Add Xilinx virtex as a reference EDIF device.

This commit is contained in:
steve 2005-09-25 16:35:36 +00:00
parent 4a3f1a3641
commit bfabeab6b9
7 changed files with 2027 additions and 9 deletions

View File

@ -24,7 +24,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#ident "$Id: Makefile.in,v 1.1.2.1 2005/08/17 01:17:28 steve Exp $"
#ident "$Id: Makefile.in,v 1.1.2.2 2005/09/25 16:35:36 steve Exp $"
#
#
SHELL = /bin/sh
@ -61,7 +61,7 @@ dep:
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
D = d-lpm.o
D = d-lpm.o d-virtex.o xilinx.o
O = edif.o device.o target.o gates.o generic.o $D
ifeq (@WIN32@,yes)

872
tgt-edif/d-virtex.c Normal file
View File

@ -0,0 +1,872 @@
/*
* Copyright (c) 2005 Stephen Williams (steve@icarus.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: d-virtex.c,v 1.1.2.1 2005/09/25 16:35:36 steve Exp $"
#endif
/*
* This is the driver for Xilinx Virtex style FPGA devices. The device
* table structure at the bottom of this file lists all the various
* functions that are used to generate code for virtex devices. In
* some cases this table uses entries that are common to all Xilinx
* devices, and in some cases Virtex specific entries are used. The
* Virtex specific functions are given here, the xilinx_* common
* functions are in the xilinx.{hc} source files.
*/
# include "device.h"
# include "edif.h"
# include "generic.h"
# include "xilinx.h"
# include <stdlib.h>
# include <string.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <assert.h>
/*
* This is a table of cell types that are accessible via the cellref
* attribute to a gate.
*/
const static struct edif_xlib_celltable virtex_celltable[] = {
{ "BUFG", xilinx_cell_bufg },
{ "MULT_AND", xilinx_cell_mult_and },
{ 0, 0}
};
/*
* The show_header function is called before any of the devices of the
* netlist are scanned.
*
* In this function, we look at the ports of the root module to decide
* if they are to be made into ports. Modules that have PAD attributes
* are *not* to be used as ports, they will be connected to special
* PAD devices instead.
*/
static void virtex_show_header(ivl_design_t des)
{
const char*part_str = 0;
xilinx_common_header(des);
xlib = edif_xlibrary_create(edf, "VIRTEX");
edif_xlibrary_set_celltable(xlib, virtex_celltable);
if ( (part_str = ivl_design_flag(des, "part")) && (part_str[0] != 0) ) {
edif_pstring(edf, "PART", part_str);
}
cell_0 = edif_xcell_create(xlib, "GND", 1);
edif_cell_portconfig(cell_0, 0, "GROUND", IVL_SIP_OUTPUT);
cell_1 = edif_xcell_create(xlib, "VCC", 1);
edif_cell_portconfig(cell_1, 0, "VCC", IVL_SIP_OUTPUT);
}
static void virtex_or_wide(ivl_net_logic_t net)
{
edif_cell_t cell_muxcy_l = xilinx_cell_muxcy_l(xlib);
edif_cell_t cell_muxcy = xilinx_cell_muxcy(xlib);
edif_cell_t cell_lut4 = xilinx_cell_lut4(xlib);
edif_cellref_t true_out, false_out;
edif_cellref_t lut, muxcy, muxcy_down=NULL;
edif_joint_t jnt;
unsigned idx, inputs, lut4_cnt;
if (ivl_logic_type(net) == IVL_LO_OR) {
true_out = edif_cellref_create(edf, cell_1);
false_out = edif_cellref_create(edf, cell_0);
} else {
true_out = edif_cellref_create(edf, cell_0);
false_out = edif_cellref_create(edf, cell_1);
}
inputs = ivl_logic_pins(net) - 1;
lut4_cnt = (inputs-1)/4;
for (idx = 0 ; idx < lut4_cnt ; idx += 1) {
muxcy = edif_cellref_create(edf, cell_muxcy_l);
lut = edif_cellref_create(edf, cell_lut4);
edif_cellref_pstring(lut, "INIT", "0001");
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, muxcy, MUXCY_S);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, true_out, 0);
edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+1));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+2));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+3));
edif_add_to_joint(jnt, lut, LUT_I3);
if (idx > 0) {
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, muxcy_down, MUXCY_O);
} else {
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, false_out, 0);
}
muxcy_down = muxcy;
}
muxcy = edif_cellref_create(edf, cell_muxcy);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, true_out, 0);
edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, muxcy_down, MUXCY_O);
switch (ivl_logic_pins(net) - 1 - lut4_cnt*4) {
case 1:
lut = edif_cellref_create(edf, xilinx_cell_inv(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0));
edif_add_to_joint(jnt, lut, BUF_I);
break;
case 2:
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
edif_cellref_pstring(lut, "INIT", "1");
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1));
edif_add_to_joint(jnt, lut, LUT_I1);
break;
case 3:
lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
edif_cellref_pstring(lut, "INIT", "01");
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+2));
edif_add_to_joint(jnt, lut, LUT_I2);
break;
case 4:
lut = edif_cellref_create(edf, cell_lut4);
edif_cellref_pstring(lut, "INIT", "0001");
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+2));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+3));
edif_add_to_joint(jnt, lut, LUT_I3);
break;
default:
assert(0);
}
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, muxcy, MUXCY_S);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, muxcy, MUXCY_O);
}
/*
* Pick off the cases where there is a Virtex specific implementation
* that is better then the generic Xilinx implementation. Route the
* remaining to the base xilinx_logic implementation.
*/
void virtex_logic(ivl_net_logic_t net)
{
/* Nothing I can do if the user expresses a specific
opinion. The cellref attribute forces me to let the base
xilinx_logic take care of it. */
if (ivl_logic_attr(net, "cellref")) {
xilinx_logic(net);
return;
}
switch (ivl_logic_type(net)) {
case IVL_LO_OR:
case IVL_LO_NOR:
if (ivl_logic_pins(net) <= 5) {
xilinx_logic(net);
} else {
virtex_or_wide(net);
}
break;
default:
xilinx_logic(net);
break;
}
}
void virtex_generic_dff(ivl_lpm_t net)
{
unsigned idx;
ivl_nexus_t aclr = ivl_lpm_async_clr(net);
ivl_nexus_t aset = ivl_lpm_async_set(net);
ivl_nexus_t sclr = ivl_lpm_sync_clr(net);
ivl_nexus_t sset = ivl_lpm_sync_set(net);
const char*abits = 0;
if (aset) {
ivl_expr_t avalue = ivl_lpm_aset_value(net);
assert(avalue);
abits = ivl_expr_bits(avalue);
assert(abits);
}
/* XXXX Can't handle both synchronous and asynchronous clear. */
assert( ! (aclr && sclr) );
/* XXXX Can't handle synchronous set at all. */
assert( ! sset );
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
edif_cellref_t obj;
ivl_nexus_t nex;
edif_joint_t jnt;
/* If there is a preset, then select an FDCPE instead of
an FDCE device. */
if (aset && (abits[idx] == '1')) {
obj = edif_cellref_create(edf, xilinx_cell_fdcpe(xlib));
} else if (aclr) {
obj = edif_cellref_create(edf, xilinx_cell_fdce(xlib));
} else if (sclr) {
obj = edif_cellref_create(edf, xilinx_cell_fdre(xlib));
} else {
obj = edif_cellref_create(edf, xilinx_cell_fdce(xlib));
}
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, obj, FDCE_Q);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, obj, FDCE_D);
jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net));
edif_add_to_joint(jnt, obj, FDCE_C);
if ( (nex = ivl_lpm_enable(net)) ) {
jnt = edif_joint_of_nexus(edf, nex);
edif_add_to_joint(jnt, obj, FDCE_CE);
}
if (aclr) {
jnt = edif_joint_of_nexus(edf, aclr);
edif_add_to_joint(jnt, obj, FDCE_CLR);
} else if (sclr) {
jnt = edif_joint_of_nexus(edf, sclr);
edif_add_to_joint(jnt, obj, FDCE_CLR);
}
if (aset) {
if (abits[idx] == '1') {
jnt = edif_joint_of_nexus(edf, aset);
edif_add_to_joint(jnt, obj, FDCE_PRE);
} else {
assert(aclr == 0);
jnt = edif_joint_of_nexus(edf, aset);
edif_add_to_joint(jnt, obj, FDCE_CLR);
}
}
}
}
/*
* This method handles both == and != operators, the identity
* comparison operators.
*
* If the identity compare is applied to small enough input vectors,
* it is shoved into a single LUT. Otherwise, it is strung out into a
* row of LUT devices chained together by carry muxes. The output of
* the comparison is the output of the last mux.
*
* When the compare is small, a LUT is generated with the appropriate
* truth table to cause an == or != result.
*
* When the compare is too wide for a single LUT, then it is made into
* a chain connected by a string of carry mux devices. Each LUT
* implements == for up to two pairs of bits, even if the final output
* is supposed to be !=. The LUT output is connected to an associated
* MUX select input. The CO output of each muxcy is passed up to the
* next higher order bits of the compare.
*
* For identity == compare, a != output from the LUT selects the DI
* input of the muxcy, generating a 0 output that is passed up. Since
* the next higher muxcy now gets a 0 input to both DI and CI, the
* output of the next higher muxcy is guaranteed to be 0, and so on to
* the final output of the carry chain. If the output from a LUT is ==,
* then the CI input of the muxcy is selected and the truth of this
* level depends on lower order bits. The least significant muxcy is
* connected to GND and VCC so that its CO follows the least
* significant LUT.
*
* Identity != is the same as == except that the output is
* inverted. To get that effect without putting an inverter on the
* output of the top muxcy pin CO (which would cost a LUT) the DI
* inputs are all connected to VCC instead of GND, and the CI of the
* least significant muxcy is connected to GND instead of VCC. The LUT
* expressions for the chained compare are configured for ==, with the
* changed CI/DI inputs performing the inversion.
*/
void virtex_eq(ivl_lpm_t net)
{
edif_cellref_t lut, mux, mux_prev;
edif_joint_t jnt, jnt_di;
unsigned idx;
/* True if I'm implementing CMP_EQ instead of CMP_NE */
int eq = 1;
assert(ivl_lpm_width(net) >= 1);
if (ivl_lpm_type(net) == IVL_LPM_CMP_NE)
eq = 0;
switch (ivl_lpm_width(net)) {
case 1:
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
edif_cellref_pstring(lut, "INIT", eq? "9" : "6");
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
return;
case 2:
lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
edif_cellref_pstring(lut, "INIT", eq? "9009" : "6FF6");
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1));
edif_add_to_joint(jnt, lut, LUT_I3);
return;
default:
{ edif_cellref_t di;
di = edif_cellref_create(edf, eq? cell_0 : cell_1);
jnt_di = edif_joint_create(edf);
edif_add_to_joint(jnt_di, di, 0);
}
mux_prev = 0;
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 2) {
int subwid = 2;
if ((idx + 1) == ivl_lpm_width(net))
subwid = 1;
mux = edif_cellref_create(edf, xilinx_cell_muxcy(xlib));
if (subwid == 2) {
lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
edif_cellref_pstring(lut, "INIT", "9009");
} else {
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
edif_cellref_pstring(lut, "INIT", "9");
}
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, mux, MUXCY_S);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
edif_add_to_joint(jnt, lut, LUT_I1);
if (subwid > 1) {
jnt = edif_joint_of_nexus(edf,
ivl_lpm_data(net, idx+1));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf,
ivl_lpm_datab(net, idx+1));
edif_add_to_joint(jnt, lut, LUT_I3);
}
edif_add_to_joint(jnt_di, mux, MUXCY_DI);
if (mux_prev) {
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, mux, MUXCY_CI);
edif_add_to_joint(jnt, mux_prev, MUXCY_O);
} else {
edif_cellref_t ci;
ci = edif_cellref_create(edf, eq? cell_1 : cell_0);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, ci, 0);
edif_add_to_joint(jnt, mux, MUXCY_CI);
}
mux_prev = mux;
}
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, mux_prev, MUXCY_O);
return;
}
}
/*
* Implement hardware for the device (A >= B). We use LUT devices if
* it can handle the slices, or carry chain logic if the slices must
* span LUT devices.
*/
void virtex_ge(ivl_lpm_t net)
{
edif_cellref_t muxcy_prev;
edif_cellref_t lut;
edif_joint_t jnt;
unsigned idx;
if (ivl_lpm_width(net) == 1) {
/* If the comparator is a single bit, then use a LUT2
with this truth table:
Q A B
--+----
1 | 0 0
0 | 0 1
1 | 1 0
1 | 1 1
Connect the A value to I1 and the B value to I0. */
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
edif_cellref_pstring(lut, "INIT", "D");
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I2);
return;
}
/* Handle the case where the device is two slices
wide. In this case, we can use a LUT4 to do all
the calculation. Use this truth table:
Q AA BB
--+------
1 | 00 00
0 | 00 01
0 | 00 10
0 | 00 11
1 | 01 00
1 | 01 01
0 | 01 10
0 | 01 11
1 | 10 00
1 | 10 01
1 | 10 10
0 | 10 11
1 | 11 xx
The I3-I0 inputs are A1 A0 B1 B0 in that order. */
assert(ivl_lpm_width(net) >= 2);
lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
edif_cellref_pstring(lut, "INIT", "F731");
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I2);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1));
edif_add_to_joint(jnt, lut, LUT_I3);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1));
edif_add_to_joint(jnt, lut, LUT_I1);
/* There are only two slices, so this is all we need. */
if (ivl_lpm_width(net) == 2) {
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
return;
}
/* The general case requires that we make the >= comparator
from slices. This is an iterative design. Each slice has
the truth table:
An Bn | A >= B
------+-------
0 0 | CI
0 1 | 0
1 0 | 1
1 1 | CI
The CI for each slice is the output of the compare of the
next less significant bits. We get this truth table by
connecting a LUT2 to the S input of a MUXCY. When the S
input is (1), it propagates its CI. This suggests that the
init value for the LUT be "9" (XNOR).
When the MUXCY S input is 0, it propagates a local
input. We connect to that input An, and we get the desired
and complete truth table for a slice.
This iterative definition needs to terminate at the least
significant bits. In fact, we have a non-iterative was to
deal with the two least significant slices. We take the
output of the LUT4 device for the least significant bits,
and use that to generate the initial CI for the chain. */
muxcy_prev = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib));
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, muxcy_prev, MUXCY_S);
{ edif_cellref_t p0 = edif_cellref_create(edf, cell_0);
edif_cellref_t p1 = edif_cellref_create(edf, cell_1);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, p0, 0);
edif_add_to_joint(jnt, muxcy_prev, MUXCY_DI);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, p1, 0);
edif_add_to_joint(jnt, muxcy_prev, MUXCY_CI);
}
for (idx = 2 ; idx < ivl_lpm_width(net) ; idx += 1) {
edif_cellref_t muxcy;
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
muxcy = edif_cellref_create(edf, xilinx_cell_muxcy(xlib));
edif_cellref_pstring(lut, "INIT", "9");
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, lut, LUT_O);
edif_add_to_joint(jnt, muxcy, MUXCY_S);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, muxcy_prev, MUXCY_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, lut, LUT_I0);
edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
edif_add_to_joint(jnt, lut, LUT_I1);
muxcy_prev = muxcy;
}
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, muxcy_prev, MUXCY_O);
}
/*
* A 4-input N-wide mux can be made on Virtex devices using MUXF5 and
* LUT devices. The MUXF5 selects a LUT device (and is connected to
* S[1]) and the LUT devices, connected to S[0], select the input.
*/
static void virtex_mux4(ivl_lpm_t net)
{
unsigned idx;
assert(ivl_lpm_selects(net) == 2);
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
edif_joint_t jnt;
edif_cellref_t lut01;
edif_cellref_t lut23;
edif_cellref_t muxf5;
lut01 = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
edif_cellref_pstring(lut01, "INIT", "CA");
lut23 = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
edif_cellref_pstring(lut23, "INIT", "CA");
muxf5 = edif_cellref_create(edf, xilinx_cell_muxf5(xlib));
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 0, idx));
edif_add_to_joint(jnt, lut01, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 1, idx));
edif_add_to_joint(jnt, lut01, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 2, idx));
edif_add_to_joint(jnt, lut23, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 3, idx));
edif_add_to_joint(jnt, lut23, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 0));
edif_add_to_joint(jnt, lut01, LUT_I2);
edif_add_to_joint(jnt, lut23, LUT_I2);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxf5, MUXF_I0);
edif_add_to_joint(jnt, lut01, LUT_O);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxf5, MUXF_I1);
edif_add_to_joint(jnt, lut23, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, muxf5, MUXF_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 1));
edif_add_to_joint(jnt, muxf5, MUXF_S);
}
}
void virtex_mux(ivl_lpm_t net)
{
switch (ivl_lpm_selects(net)) {
case 2:
virtex_mux4(net);
break;
default:
xilinx_mux(net);
break;
}
}
/*
* This function generates ADD/SUB devices for Virtex devices,
* based on the documented implementations of ADD8/ADD16, etc., from
* the Libraries Guide.
*
* Each slice of the ADD/SUB device is made from a LUT2 device, an
* XORCY device that mixes with the LUT2 to make a full adder, and a
* MUXCY_L to propagate the carry. The most significant slice does not
* have a carry to propagate, so has no MUXCY_L.
*
* If the device is a wide adder, then the LUT2 devices are configured
* to implement an XOR function and a zero is pumped into the least
* significant carry input.
*
* If the device is really an adder, then the input is turned into an
* XNOR, which takes a 1-s complement of the B input. Pump a 1 into
* the LSB carry input to finish converting the B input into the 2s
* complement.
*/
void virtex_add(ivl_lpm_t net)
{
const char*ha_init = 0;
edif_cellref_t lut, xorcy, muxcy, pad;
edif_joint_t jnt;
unsigned idx;
if (ivl_lpm_width(net) < 2) {
xilinx_add(net);
return;
}
switch (ivl_lpm_type(net)) {
case IVL_LPM_ADD:
ha_init = "6";
break;
case IVL_LPM_SUB:
ha_init = "9";
break;
default:
assert(0);
}
assert(ivl_lpm_width(net) > 1);
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib));
muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib));
edif_cellref_pstring(lut, "INIT", ha_init);
/* The bottom carry-in takes a constant that primes the add or
subtract. */
switch (ivl_lpm_type(net)) {
case IVL_LPM_ADD:
pad = edif_cellref_create(edf, cell_0);
break;
case IVL_LPM_SUB:
pad = edif_cellref_create(edf, cell_1);
break;
default:
assert(0);
}
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, pad, 0);
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
edif_add_to_joint(jnt, xorcy, XORCY_CI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, xorcy, XORCY_O);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, xorcy, XORCY_LI);
edif_add_to_joint(jnt, muxcy, MUXCY_S);
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
for (idx = 1 ; idx < ivl_lpm_width(net) ; idx += 1) {
edif_cellref_t muxcy0 = muxcy;
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib));
edif_cellref_pstring(lut, "INIT", ha_init);
/* If this is the last bit, then there is no further
propagation in the carry chain, and I can skip the
carry mux MUXCY. */
if ((idx+1) < ivl_lpm_width(net))
muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib));
else
muxcy = 0;
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, muxcy0, MUXCY_O);
edif_add_to_joint(jnt, xorcy, XORCY_CI);
if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_CI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, xorcy, XORCY_O);
jnt = edif_joint_create(edf);
edif_add_to_joint(jnt, xorcy, XORCY_LI);
if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_S);
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
edif_add_to_joint(jnt, lut, LUT_I0);
if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_DI);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
edif_add_to_joint(jnt, lut, LUT_I1);
}
}
const struct device_s d_virtex_edif = {
virtex_show_header,
xilinx_show_footer,
xilinx_show_scope,
xilinx_pad,
virtex_logic,
virtex_generic_dff,
virtex_eq,
virtex_eq,
virtex_ge,
0, /* show_cmp_gt */
virtex_mux,
virtex_add,
virtex_add,
xilinx_shiftl,
0, /* show_shiftr */
0, /* show_mult */
0 /* show_constant */
};
/*
* $Log: d-virtex.c,v $
* Revision 1.1.2.1 2005/09/25 16:35:36 steve
* Add Xilinx virtex as a reference EDIF device.
*
*/

View File

@ -27,7 +27,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: edif.h,v 1.1.2.1 2005/08/17 01:17:29 steve Exp $"
#ident "$Id: edif.h,v 1.1.2.2 2005/09/25 16:35:36 steve Exp $"
#endif
# include <stdio.h>
@ -239,8 +239,21 @@ extern void edif_nexus_to_joint(edif_t edf, edif_joint_t jnt, ivl_nexus_t nex);
*/
extern void edif_print(FILE*fd, edif_t design);
/*
* This is the fd that should be passed to the edif_print
* function. The name "xnf" is historical. This function is opened and
* closed automatically by the edif core (the target_design function)
* so generally there is no other use then the edif_print for this
* exposed fd.
*/
extern FILE*xnf;
/*
* $Log: edif.h,v $
* Revision 1.1.2.2 2005/09/25 16:35:36 steve
* Add Xilinx virtex as a reference EDIF device.
*
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*

View File

@ -27,16 +27,12 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: edif_priv.h,v 1.1.2.1 2005/08/17 01:17:29 steve Exp $"
#ident "$Id: edif_priv.h,v 1.1.2.2 2005/09/25 16:35:36 steve Exp $"
#endif
# include <stdio.h>
# include "device.h"
/* This is the opened xnf file descriptor. It is the output that this
code generator writes to, whether the format is XNF or EDIF. */
extern FILE*xnf;
extern int show_scope_gates(ivl_scope_t net, void*x);
@ -61,6 +57,9 @@ extern const char*xnf_mangle_nexus_name(ivl_nexus_t net);
/*
* $Log: edif_priv.h,v $
* Revision 1.1.2.2 2005/09/25 16:35:36 steve
* Add Xilinx virtex as a reference EDIF device.
*
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*

View File

@ -25,7 +25,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: tables.c,v 1.1.2.1 2005/08/17 01:17:29 steve Exp $"
#ident "$Id: tables.c,v 1.1.2.2 2005/09/25 16:35:37 steve Exp $"
#endif
# include "device.h"
@ -39,14 +39,19 @@
* it via the -parch=<foo> command line switch.
*/
extern const struct device_s d_lpm_edif;
extern const struct device_s d_virtex_edif;
const struct device_table_s edif_device_table[] = {
{ "lpm", &d_lpm_edif },
{ "virtex",&d_virtex_edif },
{ 0, 0 }
};
/*
* $Log: tables.c,v $
* Revision 1.1.2.2 2005/09/25 16:35:37 steve
* Add Xilinx virtex as a reference EDIF device.
*
* Revision 1.1.2.1 2005/08/17 01:17:29 steve
* Add the tgt-edif target.
*

980
tgt-edif/xilinx.c Normal file
View File

@ -0,0 +1,980 @@
/*
* Copyright (c) 2005 Stephen Williams (steve at icarus.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: xilinx.c,v 1.1.2.1 2005/09/25 16:35:37 steve Exp $"
#endif
/*
* This source file contains common functions used by Xilinx
* devices. The functions here do not support any specific Xilinx part
* fimily, but instead provide some core functions that are used by
* specific devices.
*
* For example, some xilinx_* functions are suitable for placing
* directly in a device_s table, but there is no "xilinx"
* device. These functions can be placed in the tables for devices
* that have no better way to handle the device_s function, or these
* functions can be called by device specific device_s functions that
* fall back on the generic handling in certain cases. For an example
* of both cases, see d-virtex.c.
*/
# include "edif.h"
# include "generic.h"
# include "xilinx.h"
# include <stdlib.h>
# include <string.h>
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
# include <assert.h>
edif_cell_t xilinx_cell_buf(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "BUF", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "BUFE", 3);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
edif_cell_portconfig(cell, BUF_T, "E", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "BUFG", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "BUFT", 3);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
edif_cell_portconfig(cell, BUF_T, "T", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "IBUF", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_inv(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "INV", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "MUXF5", 4);
edif_cell_portconfig(cell, MUXF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MUXF_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXF_I1, "I1", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXF_S, "S", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "MUXF6", 4);
edif_cell_portconfig(cell, MUXF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MUXF_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXF_I1, "I1", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXF_S, "S", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell) return cell;
cell = edif_xcell_create(xlib, "OBUF", 2);
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "LUT2", 3);
edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "LUT3", 4);
edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I2, "I2", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "LUT4", 5);
edif_cell_portconfig(cell, LUT_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, LUT_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I1, "I1", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I2, "I2", IVL_SIP_INPUT);
edif_cell_portconfig(cell, LUT_I3, "I3", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "FDCE", 5);
edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CE, "CE", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CLR,"CLR", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "FDCPE", 6);
edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CE, "CE", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CLR,"CLR", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_PRE,"PRE", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "FDRE", 5);
edif_cell_portconfig(cell, FDCE_Q, "Q", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, FDCE_D, "D", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_C, "C", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CE, "CE", IVL_SIP_INPUT);
edif_cell_portconfig(cell, FDCE_CLR,"R", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "MULT_AND", 3);
edif_cell_portconfig(cell, MULT_AND_LO, "LO", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MULT_AND_I0, "I0", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MULT_AND_I1, "I1", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "MUXCY", 4);
edif_cell_portconfig(cell, MUXCY_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MUXCY_DI, "DI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXCY_CI, "CI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXCY_S, "S", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "MUXCY_L", 4);
edif_cell_portconfig(cell, MUXCY_O, "LO", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, MUXCY_DI, "DI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXCY_CI, "CI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, MUXCY_S, "S", IVL_SIP_INPUT);
return cell;
}
edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib)
{
static edif_cell_t cell = 0;
if (cell != 0) return cell;
cell = edif_xcell_create(xlib, "XORCY", 3);
edif_cell_portconfig(cell, XORCY_O, "O", IVL_SIP_OUTPUT);
edif_cell_portconfig(cell, XORCY_CI, "CI", IVL_SIP_INPUT);
edif_cell_portconfig(cell, XORCY_LI, "LI", IVL_SIP_INPUT);
return cell;
}
/*
* This function does a lot of the stuff common to the header
* functions of various Xilinx familes. This includes creating the edf
* object that holds the netlist.
*/
void xilinx_common_header(ivl_design_t des)
{
unsigned idx;
ivl_scope_t root = ivl_design_root(des);
unsigned sig_cnt = ivl_scope_sigs(root);
unsigned nports = 0, pidx;
/* Count the ports I'm going to use. */
for (idx = 0 ; idx < sig_cnt ; idx += 1) {
ivl_signal_t sig = ivl_scope_sig(root, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
if (ivl_signal_attr(sig, "PAD") != 0)
continue;
nports += ivl_signal_pins(sig);
}
edf = edif_create(ivl_scope_basename(root), nports);
pidx = 0;
for (idx = 0 ; idx < sig_cnt ; idx += 1) {
edif_joint_t jnt;
ivl_signal_t sig = ivl_scope_sig(root, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
if (ivl_signal_attr(sig, "PAD") != 0)
continue;
if (ivl_signal_pins(sig) == 1) {
edif_portconfig(edf, pidx, ivl_signal_basename(sig),
ivl_signal_port(sig));
assert(ivl_signal_pins(sig) == 1);
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0));
edif_port_to_joint(jnt, edf, pidx);
} else {
const char*name = ivl_signal_basename(sig);
ivl_signal_port_t dir = ivl_signal_port(sig);
char buf[128];
unsigned bit;
for (bit = 0 ; bit < ivl_signal_pins(sig) ; bit += 1) {
const char*tmp;
sprintf(buf, "%s[%u]", name, bit);
tmp = strdup(buf);
edif_portconfig(edf, pidx+bit, tmp, dir);
jnt = edif_joint_of_nexus(edf,ivl_signal_pin(sig,bit));
edif_port_to_joint(jnt, edf, pidx+bit);
}
}
pidx += ivl_signal_pins(sig);
}
assert(pidx == nports);
}
void xilinx_show_footer(ivl_design_t des)
{
unsigned idx;
for (idx = 0 ; idx < ivl_design_consts(des) ; idx += 1) {
unsigned pin;
ivl_net_const_t net = ivl_design_const(des, idx);
const char*val = ivl_const_bits(net);
for (pin = 0 ; pin < ivl_const_pins(net) ; pin += 1) {
edif_joint_t jnt;
edif_cellref_t pad;
jnt = edif_joint_of_nexus(edf, ivl_const_pin(net, pin));
switch (val[pin]) {
case '0':
pad = edif_cellref_create(edf, cell_0);
break;
case '1':
pad = edif_cellref_create(edf, cell_1);
break;
default:
assert(0);
break;
}
edif_add_to_joint(jnt, pad, 0);
}
}
edif_print(xnf, edf);
}
/*
* Make (or retrieve) a cell in the external library that reflects the
* scope with its ports.
*/
void xilinx_show_scope(ivl_scope_t scope)
{
edif_cell_t cell;
edif_cellref_t ref;
unsigned port, idx;
cell = edif_xlibrary_scope_cell(xlib, scope);
ref = edif_cellref_create(edf, cell);
for (idx = 0 ; idx < ivl_scope_sigs(scope) ; idx += 1) {
edif_joint_t jnt;
ivl_signal_t sig = ivl_scope_sig(scope, idx);
if (ivl_signal_port(sig) == IVL_SIP_NONE)
continue;
port = edif_cell_port_byname(cell, ivl_signal_basename(sig));
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0));
edif_add_to_joint(jnt, ref, port);
}
}
void xilinx_pad(ivl_signal_t sig, const char*str)
{
unsigned idx;
char**pins;
if (cell_ipad == 0) {
cell_ipad = edif_xcell_create(xlib, "IPAD", 1);
edif_cell_portconfig(cell_ipad, 0, "IPAD", IVL_SIP_OUTPUT);
}
if (cell_opad == 0) {
cell_opad = edif_xcell_create(xlib, "OPAD", 1);
edif_cell_portconfig(cell_opad, 0, "OPAD", IVL_SIP_INPUT);
}
if (cell_iopad == 0) {
cell_iopad = edif_xcell_create(xlib, "IOPAD", 1);
edif_cell_portconfig(cell_iopad, 0, "IOPAD", IVL_SIP_INOUT);
}
/* Collect an array of pin assignments from the attribute
string passed in as str. The format is a comma separated
list of location names. */
pins = calloc(ivl_signal_pins(sig), sizeof(char*));
for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) {
const char*tmp = strchr(str, ',');
if (tmp == 0) tmp = str+strlen(str);
pins[idx] = malloc(tmp-str+1);
strncpy(pins[idx], str, tmp-str);
pins[idx][tmp-str] = 0;
if (*tmp != 0)
tmp += 1;
str = tmp;
}
/* Now go through the pins of the signal, creating pads and
bufs and joining them to the signal nexus. */
for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) {
edif_joint_t jnt;
edif_cellref_t pad, buf;
const char*name_str = ivl_signal_basename(sig);
if (ivl_signal_pins(sig) > 1) {
char name_buf[128];
sprintf(name_buf, "%s[%u]", name_str, idx);
name_str = strdup(name_buf);
}
switch (ivl_signal_port(sig)) {
case IVL_SIP_INPUT:
pad = edif_cellref_create(edf, cell_ipad);
buf = edif_cellref_create(edf, xilinx_cell_ibuf(xlib));
jnt = edif_joint_create(edf);
edif_joint_rename(jnt, name_str);
edif_add_to_joint(jnt, pad, 0);
edif_add_to_joint(jnt, buf, BUF_I);
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx));
edif_add_to_joint(jnt, buf, BUF_O);
break;
case IVL_SIP_OUTPUT:
pad = edif_cellref_create(edf, cell_opad);
buf = edif_cellref_create(edf, xilinx_cell_obuf(xlib));
jnt = edif_joint_create(edf);
edif_joint_rename(jnt, name_str);
edif_add_to_joint(jnt, pad, 0);
edif_add_to_joint(jnt, buf, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx));
edif_add_to_joint(jnt, buf, BUF_I);
break;
case IVL_SIP_INOUT:
pad = edif_cellref_create(edf, cell_iopad);
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx));
edif_add_to_joint(jnt, pad, 0);
break;
default:
assert(0);
}
if (pins[idx])
edif_cellref_pstring(pad, "LOC", pins[idx]);
}
/* Don't free the allocated pad name strings. The
edif_cellref_pstring function attached the string to the
LOC attribute, so the reference is permanent. */
free(pins);
}
/*
* This function handles the case where the user specifies the cell to
* use by attribute.
*/
static void edif_cellref_logic(ivl_net_logic_t net, const char*def)
{
char*str = strdup(def);
char*pins;
edif_cell_t cell;
edif_cellref_t ref;
edif_joint_t jnt;
unsigned idx, port;
pins = strchr(str, ':');
assert(pins);
*pins++ = 0;
/* Locate the cell in the library, lookup by name. */
cell = edif_xlibrary_findcell(xlib, str);
assert(cell);
ref = edif_cellref_create(edf, cell);
for (idx = 0 ; idx < ivl_logic_pins(net) ; idx += 1) {
char*tmp;
assert(pins);
tmp = strchr(pins,',');
if (tmp != 0)
*tmp++ = 0;
else
tmp = 0;
port = edif_cell_port_byname(cell, pins);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx));
edif_add_to_joint(jnt, ref, port);
pins = tmp;
}
free(str);
}
static void lut_logic(ivl_net_logic_t net, const char*init3,
const char*init4, const char*init5)
{
edif_cellref_t lut = NULL; /* initialization shuts up gcc -Wall */
edif_joint_t jnt;
const char* init = NULL; /* ditto */
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
switch (ivl_logic_pins(net)) {
case 3:
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
init = init3;
break;
case 4:
lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
init = init4;
break;
case 5:
lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
init = init5;
break;
}
edif_cellref_pstring(lut, "INIT", init);
switch (ivl_logic_pins(net)) {
case 5:
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 4));
edif_add_to_joint(jnt, lut, LUT_I3);
case 4:
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 3));
edif_add_to_joint(jnt, lut, LUT_I2);
case 3:
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
edif_add_to_joint(jnt, lut, LUT_I1);
}
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
}
void xilinx_logic(ivl_net_logic_t net)
{
edif_cellref_t obj;
edif_joint_t jnt;
{ const char*cellref_attribute = ivl_logic_attr(net, "cellref");
if (cellref_attribute != 0) {
edif_cellref_logic(net, cellref_attribute);
return;
}
}
switch (ivl_logic_type(net)) {
case IVL_LO_BUF:
case IVL_LO_BUFZ:
assert(ivl_logic_pins(net) == 2);
obj = edif_cellref_create(edf, xilinx_cell_buf(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, obj, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, obj, BUF_I);
break;
case IVL_LO_BUFIF0:
/* The Xilinx BUFT devices is a BUF that adds a T
input. The output is tri-stated if the T input is
1. In other words, it acts just like bufif0. */
assert(ivl_logic_pins(net) == 3);
obj = edif_cellref_create(edf, xilinx_cell_buft(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, obj, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, obj, BUF_I);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
edif_add_to_joint(jnt, obj, BUF_T);
break;
case IVL_LO_BUFIF1:
/* The Xilinx BUFE devices is a BUF that adds an enable
input. The output is tri-stated if the E input is 0.
In other words, it acts just like bufif1. */
assert(ivl_logic_pins(net) == 3);
obj = edif_cellref_create(edf, xilinx_cell_bufe(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, obj, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, obj, BUF_I);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
edif_add_to_joint(jnt, obj, BUF_T);
break;
case IVL_LO_NOT:
assert(ivl_logic_pins(net) == 2);
obj = edif_cellref_create(edf, xilinx_cell_inv(xlib));
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
edif_add_to_joint(jnt, obj, BUF_O);
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
edif_add_to_joint(jnt, obj, BUF_I);
break;
case IVL_LO_AND:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "8", "80", "8000");
break;
case IVL_LO_NOR:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "1", "01", "0001");
break;
case IVL_LO_OR:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "E", "FE", "FFFE");
break;
case IVL_LO_XNOR:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "9", "69", "9669");
break;
case IVL_LO_XOR:
assert(ivl_logic_pins(net) <= 5);
assert(ivl_logic_pins(net) >= 3);
lut_logic(net, "6", "96", "6996");
break;
default:
fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n",
ivl_logic_type(net));
break;
}
}
/*
* A fully generic Xilinx MUX is implemented entirely from LUT
* devices.
*/
void xilinx_mux(ivl_lpm_t net)
{
unsigned idx;
edif_cellref_t lut;
edif_joint_t jnt;
assert(ivl_lpm_selects(net) == 1);
/* A/B Mux devices are made from LUT3 devices. I0 is connected
to A, I1 to B, and I2 to the Select input. Create as many
as are needed to implement the requested width.
S B A | Q
------+--
0 0 0 | 0
0 0 1 | 1
0 1 0 | 0
0 1 1 | 1
1 0 0 | 0
1 0 1 | 0
1 1 0 | 1
1 1 1 | 1
INIT = "CA" */
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib));
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 0, idx));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 1, idx));
edif_add_to_joint(jnt, lut, LUT_I1);
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 0));
edif_add_to_joint(jnt, lut, LUT_I2);
edif_cellref_pstring(lut, "INIT", "CA");
}
}
/*
* Any Xilinx device works with this adder.
* Generic Xilinx add only works for single bit slices.
*/
void xilinx_add(ivl_lpm_t net)
{
const char*ha_init = 0;
edif_cellref_t lut;
edif_joint_t jnt;
switch (ivl_lpm_type(net)) {
case IVL_LPM_ADD:
ha_init = "6";
break;
case IVL_LPM_SUB:
ha_init = "9";
break;
default:
assert(0);
}
/* If this is a single bit wide, then generate only a
half-adder. Normally this is an XOR, but if this is a SUB
then it is an XNOR. */
if (ivl_lpm_width(net) == 1) {
lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
edif_add_to_joint(jnt, lut, LUT_O);
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
edif_add_to_joint(jnt, lut, LUT_I0);
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
edif_add_to_joint(jnt, lut, LUT_I1);
edif_cellref_pstring(lut, "INIT", ha_init);
return;
}
assert(0);
}
/*
* The left shift is implemented as a matrix of MUX2_1 devices. The
* matrix has as many rows as the device width, and a column for each
* select.
*/
void xilinx_shiftl(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
unsigned nsel = 0, swid = 0;
unsigned sdx, qdx;
edif_cellref_t* cells;
edif_cellref_t**table;
edif_cellref_t pad0_cell;
edif_joint_t pad0;
/* First, find out how many select inputs we really need. We
can only use the selects that are enough to shift out the
entire width of the device. The excess can be used as an
enable for the last column. When disabled, the last column
emits zeros. */
while (nsel < ivl_lpm_selects(net)) {
nsel += 1;
swid = 1 << nsel;
if (swid >= width)
break;
}
assert(nsel > 0);
/* Allocate a matrix of edif_cellref_t variables. A devices
will be addressed by the expression table[sdx][qdx];
This should make the algorighm code easier to read. */
cells = calloc(nsel * width, sizeof(edif_cellref_t));
table = calloc(nsel, sizeof(edif_cellref_t*));
for (sdx = 0 ; sdx < nsel ; sdx += 1)
table[sdx] = cells + sdx*width;
/* Make a 0 valued pad bit. I wlil use this for all the shifin
values that are beyond the input. */
pad0_cell = edif_cellref_create(edf, cell_0);
pad0 = edif_joint_create(edf);
edif_add_to_joint(pad0, pad0_cell, 0);
/* The LUT matrix is <nsel> columns of <width> devices, with
the last column a LUT4 devices. The extra input of the
LUT4s in the last column are used as an enable to collect
all the excess select inputs. */
/* Allocate the LUT devices of the matrix, and connect the
select inputs to I2 of all the devices of the column. */
for (sdx = 0 ; sdx < nsel ; sdx += 1) {
const char*init_string = 0;
ivl_nexus_t nex = ivl_lpm_select(net,sdx);
edif_joint_t sdx_jnt = edif_joint_of_nexus(edf, nex);
edif_cell_t lut;
if (((sdx+1) == nsel) && (nsel < ivl_lpm_selects(net))) {
lut = xilinx_cell_lut4(xlib);
init_string = "00CA";
} else {
lut = xilinx_cell_lut3(xlib);
init_string = "CA";
}
for (qdx = 0 ; qdx < width ; qdx += 1) {
table[sdx][qdx] = edif_cellref_create(edf, lut);
edif_add_to_joint(sdx_jnt, table[sdx][qdx], LUT_I2);
edif_cellref_pstring(table[sdx][qdx], "INIT", init_string);
}
}
/* Connect the inputs of the SHIFTL device to the column 0 LUT
inputs. The slice on the low end shifts in a 0 for a select
input. */
for (qdx = 0 ; qdx < width ; qdx += 1) {
ivl_nexus_t nex0, nex1;
edif_joint_t jnt0;
edif_joint_t jnt1;
nex0 = ivl_lpm_data(net,qdx);
jnt0 = edif_joint_of_nexus(edf, nex0);
if (qdx > 0) {
nex1 = ivl_lpm_data(net,qdx-1);
jnt1 = edif_joint_of_nexus(edf, nex1);
} else {
jnt1 = pad0;
}
edif_add_to_joint(jnt0, table[0][qdx], LUT_I0);
edif_add_to_joint(jnt1, table[0][qdx], LUT_I1);
}
/* Make the inner connections between LUT devices. Each column
connects to the previous column, shifted by the power of
the column value. If the shifted input falls off the end,
then pad with zero. */
for (sdx = 1 ; sdx < nsel ; sdx += 1) {
for (qdx = 0 ; qdx < width ; qdx += 1) {
unsigned shift = 1 << sdx;
edif_joint_t jnt0 = edif_joint_create(edf);
edif_joint_t jnt1 = (qdx >= shift)
? edif_joint_create(edf)
: pad0;
edif_add_to_joint(jnt0, table[sdx][qdx], LUT_I0);
edif_add_to_joint(jnt1, table[sdx][qdx], LUT_I1);
edif_add_to_joint(jnt0, table[sdx-1][qdx], LUT_O);
if (qdx >= shift)
edif_add_to_joint(jnt1, table[sdx-1][qdx-shift], LUT_O);
}
}
/* Connect the output of the last column to the output of the
SHIFTL device. */
for (qdx = 0 ; qdx < width ; qdx += 1) {
ivl_nexus_t nex = ivl_lpm_q(net,qdx);
edif_joint_t jnt = edif_joint_of_nexus(edf, nex);
edif_add_to_joint(jnt, table[nsel-1][qdx], LUT_O);
}
/* Connect the excess select inputs to the enable inputs of
the LUT4 devices in the last column. */
if (nsel < ivl_lpm_selects(net)) {
edif_joint_t jnt;
/* XXXX Only support 1 excess bit for now. */
assert((nsel + 1) == ivl_lpm_selects(net));
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net,nsel));
for (qdx = 0 ; qdx < width ; qdx += 1)
edif_add_to_joint(jnt, table[nsel-1][qdx], LUT_I3);
}
free(cells);
free(table);
}
/*
* $Log: xilinx.c,v $
* Revision 1.1.2.1 2005/09/25 16:35:37 steve
* Add Xilinx virtex as a reference EDIF device.
*
*/

149
tgt-edif/xilinx.h Normal file
View File

@ -0,0 +1,149 @@
#ifndef __xilinx_H
#define __xilinx_H
/*
* Copyright (c) 2005 Stephen Williams (steve at icarus.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: xilinx.h,v 1.1.2.1 2005/09/25 16:35:37 steve Exp $"
#endif
/*
* This header file includes XILINX library support functions. They
* manage the creation and reference of cells from the library. Use
* the xililx_cell_* functions to get an edif_cell_t from the
* library. The function will create the cell in the library if
* needed, or will return the existing cell if it was already called.
*
* Note that these functions are *not* part of the baseline EDIF. They
* are intended to be Xilinx specific and sometimes do things that
* would be flat-out wrong for non-xilinx devices.
*/
# include "edif.h"
/* === BUF Devices === */
/* Buffer types of devices have the BUF_O and BUF_I pin
assignments. The BUF, INV, and certain specialized devices fit in
this category. */
extern edif_cell_t xilinx_cell_buf (edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_bufe(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_bufg(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_buft(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_inv (edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_ibuf(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_obuf(edif_xlibrary_t xlib);
#define BUF_O 0
#define BUF_I 1
/* Only bufe and buft buffers have this input. */
#define BUF_T 2
/* === LUT Devices === */
/* Most Xilinx devices have LUT2/3/4 devices that take, respectively,
2, 3 or 4 inputs. All forms have a single bit output. Also, the
real behavior of the device will need to be specified by an INIT
parameter string. */
extern edif_cell_t xilinx_cell_lut2(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_lut3(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_lut4(edif_xlibrary_t xlib);
#define LUT_O 0
#define LUT_I0 1
#define LUT_I1 2
#define LUT_I2 3
#define LUT_I3 4
/* === Flip-Flop Devices === */
/*
* These are flip-flops of various sort, but similar pinouts.
*/
extern edif_cell_t xilinx_cell_fdce(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_fdcpe(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_fdre(edif_xlibrary_t xlib);
#define FDCE_Q 0
#define FDCE_C 1
#define FDCE_D 2
#define FDCE_CE 3
#define FDCE_CLR 4
#define FDCE_PRE 5
/* === Virtex/Virtex2 Carry Chain Logic === */
extern edif_cell_t xilinx_cell_mult_and(edif_xlibrary_t xlib);
#define MULT_AND_LO 0
#define MULT_AND_I0 1
#define MULT_AND_I1 2
extern edif_cell_t xilinx_cell_muxcy(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_muxcy_l(edif_xlibrary_t xlib);
#define MUXCY_O 0
#define MUXCY_DI 1
#define MUXCY_CI 2
#define MUXCY_S 3
extern edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib);
#define XORCY_O 0
#define XORCY_CI 1
#define XORCY_LI 2
/* === Virtex/Virtex2 MUX devices */
extern edif_cell_t xilinx_cell_muxf5(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_muxf6(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_muxf7(edif_xlibrary_t xlib);
extern edif_cell_t xilinx_cell_muxf8(edif_xlibrary_t xlib);
#define MUXF_O 0
#define MUXF_I0 1
#define MUXF_I1 2
#define MUXF_S 3
/* === Inheritable Methods === */
extern void virtex_logic(ivl_net_logic_t net);
extern void virtex_generic_dff(ivl_lpm_t net);
extern void virtex_eq(ivl_lpm_t net);
extern void virtex_ge(ivl_lpm_t net);
extern void virtex_mux(ivl_lpm_t net);
extern void virtex_add(ivl_lpm_t net);
extern void xilinx_common_header(ivl_design_t des);
extern void xilinx_show_footer(ivl_design_t des);
extern void xilinx_show_scope(ivl_scope_t scope);
extern void xilinx_pad(ivl_signal_t, const char*str);
extern void xilinx_logic(ivl_net_logic_t net);
extern void xilinx_mux(ivl_lpm_t net);
extern void xilinx_add(ivl_lpm_t net);
extern void xilinx_shiftl(ivl_lpm_t net);
/*
* $Log: xilinx.h,v $
* Revision 1.1.2.1 2005/09/25 16:35:37 steve
* Add Xilinx virtex as a reference EDIF device.
*
*/
#endif