diff --git a/tgt-edif/Makefile.in b/tgt-edif/Makefile.in index 59372c540..b83a7f3cf 100644 --- a/tgt-edif/Makefile.in +++ b/tgt-edif/Makefile.in @@ -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) diff --git a/tgt-edif/d-virtex.c b/tgt-edif/d-virtex.c new file mode 100644 index 000000000..4dcd03280 --- /dev/null +++ b/tgt-edif/d-virtex.c @@ -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 +# include +#ifdef HAVE_MALLOC_H +# include +#endif +# include + +/* + * 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. + * + */ + diff --git a/tgt-edif/edif.h b/tgt-edif/edif.h index e3de1faa2..79eb82414 100644 --- a/tgt-edif/edif.h +++ b/tgt-edif/edif.h @@ -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 @@ -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. * diff --git a/tgt-edif/edif_priv.h b/tgt-edif/edif_priv.h index 7599705f8..07223e8d1 100644 --- a/tgt-edif/edif_priv.h +++ b/tgt-edif/edif_priv.h @@ -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 # 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. * diff --git a/tgt-edif/tables.c b/tgt-edif/tables.c index 8985ac884..8fe7fcf6a 100644 --- a/tgt-edif/tables.c +++ b/tgt-edif/tables.c @@ -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= 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. * diff --git a/tgt-edif/xilinx.c b/tgt-edif/xilinx.c new file mode 100644 index 000000000..ccdf29543 --- /dev/null +++ b/tgt-edif/xilinx.c @@ -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 +# include +#ifdef HAVE_MALLOC_H +# include +#endif +# include + +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 columns of 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. + * + */ + diff --git a/tgt-edif/xilinx.h b/tgt-edif/xilinx.h new file mode 100644 index 000000000..931b8aa2e --- /dev/null +++ b/tgt-edif/xilinx.h @@ -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