From ff032fa18c6f82bc7f03c31e29f40ebb85d1d474 Mon Sep 17 00:00:00 2001 From: steve Date: Mon, 24 Mar 2003 00:47:54 +0000 Subject: [PATCH] Add new virtex2 architecture family, and also the new edif.h EDIF management functions. --- tgt-fpga/Makefile.in | 6 +- tgt-fpga/d-virtex2.c | 1139 ++++++++++++++++++++++++++++++++++++++++++ tgt-fpga/edif.c | 435 ++++++++++++++++ tgt-fpga/edif.h | 201 ++++++++ tgt-fpga/fpga.txt | 11 +- tgt-fpga/tables.c | 8 +- 6 files changed, 1795 insertions(+), 5 deletions(-) create mode 100644 tgt-fpga/d-virtex2.c create mode 100644 tgt-fpga/edif.c create mode 100644 tgt-fpga/edif.h diff --git a/tgt-fpga/Makefile.in b/tgt-fpga/Makefile.in index 91c74b4e4..4f384e5e6 100644 --- a/tgt-fpga/Makefile.in +++ b/tgt-fpga/Makefile.in @@ -16,7 +16,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.7 2003/02/27 22:13:22 steve Exp $" +#ident "$Id: Makefile.in,v 1.8 2003/03/24 00:47:54 steve Exp $" # # SHELL = /bin/sh @@ -52,8 +52,8 @@ dep: $(CC) -Wall @ident_support@ -I$(srcdir)/.. $(CPPFLAGS) -MD -c $< -o $*.o mv $*.d dep -D = d-generic.o d-generic-edif.o d-virtex.o -O = fpga.o gates.o mangle.o tables.o $D +D = d-generic.o d-generic-edif.o d-virtex.o d-virtex2.o +O = edif.o fpga.o gates.o mangle.o tables.o $D ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-fpga/d-virtex2.c b/tgt-fpga/d-virtex2.c new file mode 100644 index 000000000..0a6ecd40b --- /dev/null +++ b/tgt-fpga/d-virtex2.c @@ -0,0 +1,1139 @@ +/* + * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifdef HAVE_CVS_IDENT +#ident "$Id: d-virtex2.c,v 1.1 2003/03/24 00:47:54 steve Exp $" +#endif + +# include "device.h" +# include "fpga_priv.h" +# include "edif.h" +# include +# include +#ifdef HAVE_MALLOC_H +# include +#endif +# include + + +static edif_t edf = 0; +static edif_xlibrary_t xlib = 0; + +/* + * The cell_* variables below are the various kinds of devices that + * this family supports as primitives. If the cell type is used at + * least once, then the edif_cell_t is non-zero and will also be + * included in the library declaration. The constants underneath are + * pin assignments for the cell. + */ + +static edif_cell_t cell_0 = 0; +static edif_cell_t cell_1 = 0; + +static edif_cell_t cell_fdce = 0; +static edif_cell_t cell_fdcpe = 0; +const unsigned FDCE_Q = 0; +const unsigned FDCE_C = 1; +const unsigned FDCE_D = 2; +const unsigned FDCE_CE = 3; +const unsigned FDCE_CLR = 4; +const unsigned FDCE_PRE = 5; + +static edif_cell_t cell_ipad = 0; +static edif_cell_t cell_opad = 0; + +static edif_cell_t cell_buf = 0; +static edif_cell_t cell_inv = 0; +static edif_cell_t cell_bufg = 0; +static edif_cell_t cell_ibuf = 0; +static edif_cell_t cell_obuf = 0; +const unsigned BUF_O = 0; +const unsigned BUF_I = 1; + +static edif_cell_t cell_lut2 = 0; +static edif_cell_t cell_lut3 = 0; +static edif_cell_t cell_lut4 = 0; +const unsigned LUT_O = 0; +const unsigned LUT_I0 = 1; +const unsigned LUT_I1 = 2; +const unsigned LUT_I2 = 3; +const unsigned LUT_I3 = 4; + +static edif_cell_t cell_muxcy = 0; +static edif_cell_t cell_muxcy_l = 0; +const unsigned MUXCY_O = 0; +const unsigned MUXCY_DI = 1; +const unsigned MUXCY_CI = 2; +const unsigned MUXCY_S = 3; + +static edif_cell_t cell_xorcy = 0; +const unsigned XORCY_O = 0; +const unsigned XORCY_CI = 1; +const unsigned XORCY_LI = 2; + +static edif_cell_t cell_mult_and = 0; +const unsigned MULT_AND_LO = 0; +const unsigned MULT_AND_I0 = 1; +const unsigned MULT_AND_I1 = 2; + +/* + * The check_cell_* functions can be called in front of any reference + * to the matching cell_* variable to make sure the cell type has been + * created. By creating the cell type only when it is needed, we + * reduce the size of the library declaration, and also better support + * cross-family code sharing. + */ + +static void check_cell_fdce(void) +{ + if (cell_fdce != 0) + return; + + cell_fdce = edif_xcell_create(xlib, "FDCE", 5); + edif_cell_portconfig(cell_fdce, FDCE_Q, "Q", IVL_SIP_INPUT); + edif_cell_portconfig(cell_fdce, FDCE_D, "D", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_fdce, FDCE_C, "C", IVL_SIP_INPUT); + edif_cell_portconfig(cell_fdce, FDCE_CE, "CE", IVL_SIP_INPUT); + edif_cell_portconfig(cell_fdce, FDCE_CLR,"CLR", IVL_SIP_INPUT); +} + +static void check_cell_fdcpe(void) +{ + if (cell_fdcpe != 0) + return; + + cell_fdcpe = edif_xcell_create(xlib, "FDCPE", 6); + edif_cell_portconfig(cell_fdcpe, FDCE_Q, "Q", IVL_SIP_INPUT); + edif_cell_portconfig(cell_fdcpe, FDCE_D, "D", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_fdcpe, FDCE_C, "C", IVL_SIP_INPUT); + edif_cell_portconfig(cell_fdcpe, FDCE_CE, "CE", IVL_SIP_INPUT); + edif_cell_portconfig(cell_fdcpe, FDCE_CLR,"CLR", IVL_SIP_INPUT); + edif_cell_portconfig(cell_fdcpe, FDCE_PRE,"PRE", IVL_SIP_INPUT); +} + +static void check_cell_buf(void) +{ + if (cell_buf != 0) + return; + + cell_buf = edif_xcell_create(xlib, "BUF", 2); + edif_cell_portconfig(cell_buf, BUF_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_buf, BUF_I, "I", IVL_SIP_INPUT); +} + +static void check_cell_inv(void) +{ + if (cell_inv != 0) + return; + + cell_inv = edif_xcell_create(xlib, "INV", 2); + edif_cell_portconfig(cell_inv, BUF_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_inv, BUF_I, "I", IVL_SIP_INPUT); +} + +static void check_cell_ibuf(void) +{ + if (cell_ibuf != 0) + return; + + cell_ibuf = edif_xcell_create(xlib, "IBUF", 2); + edif_cell_portconfig(cell_ibuf, BUF_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_ibuf, BUF_I, "I", IVL_SIP_INPUT); +} + +static void check_cell_obuf(void) +{ + if (cell_obuf != 0) + return; + + cell_obuf = edif_xcell_create(xlib, "OBUF", 2); + edif_cell_portconfig(cell_obuf, BUF_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_obuf, BUF_I, "I", IVL_SIP_INPUT); +} + +static void check_cell_lut2(void) +{ + if (cell_lut2 != 0) + return; + + cell_lut2 = edif_xcell_create(xlib, "LUT2", 3); + edif_cell_portconfig(cell_lut2, LUT_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_lut2, LUT_I0, "I0", IVL_SIP_INPUT); + edif_cell_portconfig(cell_lut2, LUT_I1, "I1", IVL_SIP_INPUT); +} + +static void check_cell_lut3(void) +{ + if (cell_lut3 != 0) + return; + + cell_lut3 = edif_xcell_create(xlib, "LUT3", 4); + edif_cell_portconfig(cell_lut3, LUT_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_lut3, LUT_I0, "I0", IVL_SIP_INPUT); + edif_cell_portconfig(cell_lut3, LUT_I1, "I1", IVL_SIP_INPUT); + edif_cell_portconfig(cell_lut3, LUT_I2, "I2", IVL_SIP_INPUT); +} + +static void check_cell_lut4(void) +{ + if (cell_lut4 != 0) + return; + + cell_lut4 = edif_xcell_create(xlib, "LUT4", 5); + edif_cell_portconfig(cell_lut4, LUT_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_lut4, LUT_I0, "I0", IVL_SIP_INPUT); + edif_cell_portconfig(cell_lut4, LUT_I1, "I1", IVL_SIP_INPUT); + edif_cell_portconfig(cell_lut4, LUT_I2, "I2", IVL_SIP_INPUT); + edif_cell_portconfig(cell_lut4, LUT_I3, "I3", IVL_SIP_INPUT); +} + +static void check_cell_muxcy(void) +{ + if (cell_muxcy != 0) + return; + + cell_muxcy = edif_xcell_create(xlib, "MUXCY", 4); + edif_cell_portconfig(cell_muxcy, MUXCY_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_muxcy, MUXCY_DI, "DI", IVL_SIP_INPUT); + edif_cell_portconfig(cell_muxcy, MUXCY_CI, "CI", IVL_SIP_INPUT); + edif_cell_portconfig(cell_muxcy, MUXCY_S, "S", IVL_SIP_INPUT); +} + +static void check_cell_muxcy_l(void) +{ + if (cell_muxcy_l != 0) + return; + + cell_muxcy_l = edif_xcell_create(xlib, "MUXCY_L", 4); + edif_cell_portconfig(cell_muxcy_l, MUXCY_O, "LO", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_muxcy_l, MUXCY_DI, "DI", IVL_SIP_INPUT); + edif_cell_portconfig(cell_muxcy_l, MUXCY_CI, "CI", IVL_SIP_INPUT); + edif_cell_portconfig(cell_muxcy_l, MUXCY_S, "S", IVL_SIP_INPUT); +} + +static void check_cell_xorcy(void) +{ + if (cell_xorcy != 0) + return; + + cell_xorcy = edif_xcell_create(xlib, "XORCY", 3); + edif_cell_portconfig(cell_xorcy, XORCY_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_xorcy, XORCY_CI, "CI", IVL_SIP_INPUT); + edif_cell_portconfig(cell_xorcy, XORCY_LI, "LI", IVL_SIP_INPUT); +} + +static void check_cell_mult_and(void) +{ + if (cell_mult_and != 0) + return; + + cell_mult_and = edif_xcell_create(xlib, "MULT_AND", 3); + edif_cell_portconfig(cell_mult_and, MULT_AND_LO, "LO", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_mult_and, MULT_AND_I0, "I0", IVL_SIP_INPUT); + edif_cell_portconfig(cell_mult_and, MULT_AND_I1, "I1", IVL_SIP_INPUT); +} + +/* + * 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 virtex2_show_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; + + 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); + + pidx += ivl_signal_pins(sig); + } + + assert(pidx == nports); + + xlib = edif_xlibrary_create(edf, "VIRTEX2"); + + if (ivl_design_flag(des, "part")) { + edif_pstring(edf, "PART", ivl_design_flag(des, "part")); + } + + 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); + + cell_bufg = edif_xcell_create(xlib, "BUFG", 2); + edif_cell_portconfig(cell_bufg, BUF_O, "O", IVL_SIP_OUTPUT); + edif_cell_portconfig(cell_bufg, BUF_I, "I", IVL_SIP_INPUT); +} + +static void virtex2_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); +} + +static void virtex2_pad(ivl_signal_t sig, const char*str) +{ + unsigned idx; + unsigned*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_OUTPUT); + } + + /* Collect an array of pin assignments from the attribute + string passed in as str. The format is a comma separated + list of unsigned decimal integers. */ + pins = calloc(ivl_signal_pins(sig), sizeof(unsigned)); + for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) { + char*tmp; + pins[idx] = strtoul(str, &tmp, 10); + switch (*tmp) { + case ',': + tmp += 1; + break; + case 0: + break; + default: + assert(0); + } + + 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; + + switch (ivl_signal_port(sig)) { + case IVL_SIP_INPUT: + check_cell_ibuf(); + pad = edif_cellref_create(edf, cell_ipad); + buf = edif_cellref_create(edf, cell_ibuf); + + jnt = edif_joint_create(edf); + 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: + check_cell_obuf(); + pad = edif_cellref_create(edf, cell_opad); + buf = edif_cellref_create(edf, cell_obuf); + + jnt = edif_joint_create(edf); + 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; + + default: + assert(0); + } + + } + + 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 virtex2_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); + check_cell_buf(); + + obj = edif_cellref_create(edf, cell_buf); + + 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_OR: + assert(ivl_logic_pins(net) <= 5); + assert(ivl_logic_pins(net) >= 3); + + switch (ivl_logic_pins(net)) { + + case 3: + check_cell_lut2(); + obj = edif_cellref_create(edf, cell_lut2); + edif_cellref_pstring(obj, "INIT", "E"); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); + edif_add_to_joint(jnt, obj, LUT_O); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); + edif_add_to_joint(jnt, obj, LUT_I0); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); + edif_add_to_joint(jnt, obj, LUT_I1); + break; + + case 4: + check_cell_lut3(); + obj = edif_cellref_create(edf, cell_lut3); + edif_cellref_pstring(obj, "INIT", "FE"); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); + edif_add_to_joint(jnt, obj, LUT_O); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); + edif_add_to_joint(jnt, obj, LUT_I0); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); + edif_add_to_joint(jnt, obj, LUT_I1); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 3)); + edif_add_to_joint(jnt, obj, LUT_I2); + break; + + case 5: + check_cell_lut4(); + obj = edif_cellref_create(edf, cell_lut4); + edif_cellref_pstring(obj, "INIT", "FFFE"); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); + edif_add_to_joint(jnt, obj, LUT_O); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); + edif_add_to_joint(jnt, obj, LUT_I0); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); + edif_add_to_joint(jnt, obj, LUT_I1); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 3)); + edif_add_to_joint(jnt, obj, LUT_I2); + + jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 4)); + edif_add_to_joint(jnt, obj, LUT_I3); + break; + + default: + assert(0); + } + break; + + default: + fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n", + ivl_logic_type(net)); + break; + } +} + +static void virtex2_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); + const char*abits = 0; + + if (aset) { + ivl_expr_t avalue = ivl_lpm_aset_value(net); + assert(avalue); + abits = ivl_expr_bits(avalue); + assert(abits); + } + + + 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')) { + check_cell_fdcpe(); + obj = edif_cellref_create(edf, cell_fdcpe); + } else { + check_cell_fdce(); + obj = edif_cellref_create(edf, cell_fdce); + } + + 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); + } + + 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); + } + } + } +} + +/* + * 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. + */ +static void virtex2_show_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; + + + check_cell_lut3(); + check_cell_lut4(); + + /* 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 = cell_lut4; + init_string = "00CA"; + } else { + lut = cell_lut3; + 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 - 1); + 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); +} + +/* + * This function generates ADD/SUB devices for Virtex-II 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 no + * 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. + */ +static void virtex2_add(ivl_lpm_t net) +{ + const char*ha_init = 0; + edif_cellref_t lut, xorcy, muxcy, pad; + edif_joint_t jnt; + + unsigned idx; + + 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) { + + check_cell_lut2(); + lut = edif_cellref_create(edf, cell_lut2); + + 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(ivl_lpm_width(net) > 1); + + check_cell_lut2(); + check_cell_xorcy(); + check_cell_muxcy_l(); + + lut = edif_cellref_create(edf, cell_lut2); + xorcy = edif_cellref_create(edf, cell_xorcy); + muxcy = edif_cellref_create(edf, cell_muxcy_l); + 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, cell_lut2); + xorcy = edif_cellref_create(edf, cell_xorcy); + 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, cell_muxcy_l); + 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); + } + +} + +/* + * 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. + */ +static void virtex2_cmp_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. */ + + check_cell_lut2(); + lut = edif_cellref_create(edf, cell_lut2); + 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; + } + + if (ivl_lpm_width(net) == 2) { + + /* 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. */ + + check_cell_lut4(); + + lut = edif_cellref_create(edf, cell_lut4); + edif_cellref_pstring(lut, "INIT", "F731"); + + 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_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); + return; + } + + /* The general case is more complicated, but we can take + advantage of the MULTAND and MUXCY devices to pack two bit + slices of input into each LUT4 device. The logic works like + this: + + The goal is to calculate: + + A >= B. + + This is the same as the expression: + + ~(A < B) + + so the problem is changed to calculating A < B an inverting + the result. In fact, A 0 + + This can in fact be implemented using carry chain + arithmetic. Each bit slice of a normal subtractor uses a + LUT2, a MUXCY and an XORCY. However, since we do not care + about the result of the subtract (only whether it + overflows) then we can skip the XORCY. + + Furthermore, pairs of LUT2 and MUXCY devices can be reduced + to a single LUT4, MUXCY and MULTAND device. */ + + /* For now, only support even widths. */ + assert(ivl_lpm_width(net)%2 == 0); + + muxcy_prev = 0; + for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 2) { + edif_cellref_t muxcy, multand; + + check_cell_lut4(); + check_cell_muxcy(); + check_cell_mult_and(); + + lut = edif_cellref_create(edf, cell_lut4); + muxcy = edif_cellref_create(edf, cell_muxcy); + multand = edif_cellref_create(edf, cell_mult_and); + edif_cellref_pstring(lut, "INIT", "8421"); + + jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx+0)); + edif_add_to_joint(jnt, lut, LUT_I2); + + jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx+1)); + edif_add_to_joint(jnt, lut, LUT_I3); + + jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx+0)); + edif_add_to_joint(jnt, lut, LUT_I0); + edif_add_to_joint(jnt, multand, MULT_AND_I0); + + jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx+1)); + edif_add_to_joint(jnt, lut, LUT_I1); + edif_add_to_joint(jnt, multand, MULT_AND_I1); + + 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, multand, MULT_AND_LO); + edif_add_to_joint(jnt, muxcy, MUXCY_DI); + + if (idx == 0) { + muxcy_prev = edif_cellref_create(edf, cell_1); + jnt = edif_joint_create(edf); + edif_add_to_joint(jnt, muxcy_prev, 0); + edif_add_to_joint(jnt, muxcy, MUXCY_CI); + } else { + jnt = edif_joint_create(edf); + edif_add_to_joint(jnt, muxcy_prev, MUXCY_O); + edif_add_to_joint(jnt, muxcy, MUXCY_CI); + } + + muxcy_prev = muxcy; + } + + /* At this point, muxcy_prev[MUXCY_O] in the truth of the + expression B-A > 0. Connect an inverter to this and we get + our desired result. */ + + check_cell_inv(); + lut = edif_cellref_create(edf, cell_inv); + jnt = edif_joint_create(edf); + edif_add_to_joint(jnt, muxcy_prev, MUXCY_O); + edif_add_to_joint(jnt, lut, BUF_I); + + jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); + edif_add_to_joint(jnt, lut, BUF_O); +} + +const struct device_s d_virtex2_edif = { + virtex2_show_header, + virtex2_show_footer, + virtex2_pad, + virtex2_logic, + virtex2_generic_dff, + 0, + 0, + virtex2_cmp_ge, + 0, + virtex2_add, + virtex2_add, + virtex2_show_shiftl, /* show_shiftl */ + 0 /* show_shiftr */ +}; + + +/* + * $Log: d-virtex2.c,v $ + * Revision 1.1 2003/03/24 00:47:54 steve + * Add new virtex2 architecture family, and + * also the new edif.h EDIF management functions. + * + */ + diff --git a/tgt-fpga/edif.c b/tgt-fpga/edif.c new file mode 100644 index 000000000..03e48b3ec --- /dev/null +++ b/tgt-fpga/edif.c @@ -0,0 +1,435 @@ +/* + * Copyright (c) 200Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifdef HAVE_CVS_IDENT +#ident "$Id: edif.c,v 1.1 2003/03/24 00:47:54 steve Exp $" +#endif + +# include "edif.h" +# include +# include +#ifdef HAVE_MALLOC_H +# include +#endif +# include + +struct cellref_property_ { + const char*name; + const char*value; + struct cellref_property_*next; +}; + +struct edif_s { + const char*name; + /* List the ports of the design. */ + unsigned nports; + struct __cell_port*ports; + /* All the external libraries attached to me. */ + edif_xlibrary_t xlibs; + /* list the cellref instances. */ + edif_cellref_t celref; + /* The root instance has cellref properties as well. */ + struct cellref_property_*property; + /* Keep a list of all the nexa */ + struct edif_joint_s*nexa; +}; + +struct edif_xlibrary_s { + /* Name of this library. */ + const char*name; + /* The cells that are contained in this library. */ + struct edif_cell_s*cells; + + /* used to list libraries in an edif_t. */ + struct edif_xlibrary_s*next; +}; + + +struct __cell_port { + const char*name; + ivl_signal_port_t dir; +}; + +struct edif_cell_s { + const char*name; + edif_xlibrary_t xlib; + + unsigned nports; + struct __cell_port*ports; + + struct edif_cell_s*next; +}; + +struct edif_cellref_s { + struct edif_cell_s* cell; + unsigned u; + struct cellref_property_*property; + struct edif_cellref_s* next; +}; + +struct joint_cell_ { + struct edif_cellref_s*cell; + unsigned port; + struct joint_cell_*next; +}; + +struct edif_joint_s { + struct joint_cell_*links; + struct edif_joint_s*next; +}; + +edif_t edif_create(const char*design_name, unsigned nports) +{ + edif_t edf = malloc(sizeof(struct edif_s)); + + edf->name = design_name; + edf->nports= nports; + edf->ports = nports? calloc(nports, sizeof(struct __cell_port)) : 0; + edf->celref= 0; + edf->xlibs = 0; + edf->property = 0; + edf->nexa = 0; + + return edf; +} + +void edif_portconfig(edif_t edf, unsigned idx, + const char*name, ivl_signal_port_t dir) +{ + assert(idx < edf->nports); + + edf->ports[idx].name = name; + edf->ports[idx].dir = dir; +} + +void edif_port_to_joint(edif_joint_t jnt, edif_t edf, unsigned port) +{ + struct joint_cell_* jc = malloc(sizeof(struct joint_cell_)); + + jc->cell = 0; + jc->port = port; + jc->next = jnt->links; + jnt->links = jc; +} + +void edif_pstring(edif_t edf, const char*name, const char*value) +{ + struct cellref_property_*prp = malloc(sizeof(struct cellref_property_)); + prp->name = name; + prp->value = value; + prp->next = edf->property; + edf->property = prp; +} + +edif_xlibrary_t edif_xlibrary_create(edif_t edf, const char*name) +{ + edif_xlibrary_t xlib = malloc(sizeof(struct edif_xlibrary_s)); + + xlib->name = name; + xlib->cells= 0; + xlib->next = edf->xlibs; + edf->xlibs = xlib; + + return xlib; +} + +edif_cell_t edif_xlibrary_findcell(edif_xlibrary_t xlib, + const char*cell_name) +{ + edif_cell_t cur; + for (cur = xlib->cells ; cur ; cur = cur->next) { + if (strcmp(cell_name, cur->name) == 0) + return cur; + } + + return 0; +} + +edif_cell_t edif_xcell_create(edif_xlibrary_t xlib, const char*name, + unsigned nports) +{ + unsigned idx; + edif_cell_t cell = malloc(sizeof(struct edif_cell_s)); + + cell->name = name; + cell->xlib = xlib; + cell->nports = nports; + cell->ports = calloc(nports, sizeof(struct __cell_port)); + + for (idx = 0 ; idx < nports ; idx += 1) { + cell->ports[idx].name = "?"; + cell->ports[idx].dir = IVL_SIP_NONE; + } + + cell->next = xlib->cells; + xlib->cells = cell; + + return cell; +} + +void edif_cell_portconfig(edif_cell_t cell, unsigned idx, + const char*name, ivl_signal_port_t dir) +{ + assert(idx < cell->nports); + + cell->ports[idx].name = name; + cell->ports[idx].dir = dir; +} + +unsigned edif_cell_port_byname(edif_cell_t cell, const char*name) +{ + unsigned idx = 0; + for (idx = 0 ; idx < cell->nports ; idx += 1) + if (strcmp(name, cell->ports[idx].name) == 0) + break; + + return idx; +} + +edif_cellref_t edif_cellref_create(edif_t edf, edif_cell_t cell) +{ + static unsigned u_number = 0; + edif_cellref_t ref = malloc(sizeof(struct edif_cellref_s)); + + u_number += 1; + + assert(cell); + assert(edf); + + ref->u = u_number; + ref->cell = cell; + ref->property = 0; + ref->next = edf->celref; + edf->celref = ref; + + return ref; +} + +void edif_cellref_pstring(edif_cellref_t ref, const char*name, + const char*value) +{ + struct cellref_property_*prp = malloc(sizeof(struct cellref_property_)); + prp->name = name; + prp->value = value; + prp->next = ref->property; + ref->property = prp; +} + +edif_joint_t edif_joint_create(edif_t edf) +{ + edif_joint_t jnt = malloc(sizeof(struct edif_joint_s)); + + jnt->links = 0; + jnt->next = edf->nexa; + edf->nexa = jnt; + return jnt; +} + +edif_joint_t edif_joint_of_nexus(edif_t edf, ivl_nexus_t nex) +{ + void*tmp = ivl_nexus_get_private(nex); + edif_joint_t jnt; + + if (tmp == 0) { + jnt = edif_joint_create(edf); + ivl_nexus_set_private(nex, jnt); + return jnt; + } + + jnt = (edif_joint_t) tmp; + return jnt; +} + +void edif_add_to_joint(edif_joint_t jnt, edif_cellref_t cell, unsigned port) +{ + struct joint_cell_* jc = malloc(sizeof(struct joint_cell_)); + + jc->cell = cell; + jc->port = port; + jc->next = jnt->links; + jnt->links = jc; +} + + +/* + * This function takes all the data structures that have been + * assembled by the code generator, and writes them into an EDIF + * formatted file. + */ +void edif_print(FILE*fd, edif_t edf) +{ + edif_xlibrary_t xlib; + edif_cell_t cell; + edif_cellref_t ref; + edif_joint_t jnt; + struct cellref_property_*prp; + unsigned idx; + + fprintf(fd, "(edif %s\n", edf->name); + fprintf(fd, " (edifVersion 2 0 0)\n"); + fprintf(fd, " (edifLevel 0)\n"); + fprintf(fd, " (keywordMap (keywordLevel 0))\n"); + fprintf(fd, " (status\n"); + fprintf(fd, " (written\n"); + fprintf(fd, " (timeStamp 0 0 0 0 0 0)\n"); + fprintf(fd, " (author \"unknown\")\n"); + fprintf(fd, " (program \"Icarus Verilog/fpga.tgt\")))\n"); + fflush(fd); + + for (xlib = edf->xlibs ; xlib ; xlib = xlib->next) { + + fprintf(fd, " (external %s " + "(edifLevel 0) " + "(technology (numberDefinition))\n", + xlib->name); + + for (cell = xlib->cells ; cell ; cell = cell->next) { + fprintf(fd, " (cell %s (cellType GENERIC)\n", + cell->name); + fprintf(fd, " (view net\n" + " (viewType NETLIST)\n" + " (interface"); + + for (idx = 0 ; idx < cell->nports ; idx += 1) { + struct __cell_port*pp = cell->ports + idx; + fprintf(fd, "\n (port %s", pp->name); + switch (pp->dir) { + case IVL_SIP_INPUT: + fprintf(fd, " (direction INPUT)"); + break; + case IVL_SIP_OUTPUT: + fprintf(fd, " (direction OUTPUT)"); + break; + case IVL_SIP_INOUT: + fprintf(fd, " (direction INOUT)"); + break; + default: + break; + } + fprintf(fd, ")"); + } + + fprintf(fd, ")))\n"); + } + + fprintf(fd, " )\n"); /* terminate (external ...) sexp */ + } + fflush(fd); + + /* Write out the library header */ + fprintf(fd, " (library DESIGN\n"); + fprintf(fd, " (edifLevel 0)\n"); + fprintf(fd, " (technology (numberDefinition))\n"); + + /* The root module is a cell in the library. */ + fprintf(fd, " (cell %s\n", edf->name); + fprintf(fd, " (cellType GENERIC)\n"); + fprintf(fd, " (view net\n"); + fprintf(fd, " (viewType NETLIST)\n"); + fprintf(fd, " (interface\n"); + + for (idx = 0 ; idx < edf->nports ; idx += 1) { + fprintf(fd, " (port %s ", edf->ports[idx].name); + switch (edf->ports[idx].dir) { + case IVL_SIP_INPUT: + fprintf(fd, "(direction INPUT)"); + break; + case IVL_SIP_OUTPUT: + fprintf(fd, "(direction OUTPUT)"); + break; + case IVL_SIP_INOUT: + fprintf(fd, "(direction INOUT)"); + break; + default: + break; + } + fprintf(fd, ")\n"); + } + + fprintf(fd, " )\n"); /* end the (interface ) sexp */ + fflush(fd); + + fprintf(fd, " (contents\n"); + + /* Display all the instances. */ + for (ref = edf->celref ; ref ; ref = ref->next) { + + assert(ref->cell); + + fprintf(fd, "(instance U%u (viewRef net " + "(cellRef %s (libraryRef %s)))", + ref->u, ref->cell->name, ref->cell->xlib->name); + + for (prp = ref->property ; prp ; prp = prp->next) + fprintf(fd, " (property %s (string \"%s\"))", + prp->name, prp->value); + + fprintf(fd, ")\n"); + } + + fflush(fd); + + /* Display all the joints. */ + idx = 0; + for (jnt = edf->nexa ; jnt ; jnt = jnt->next, idx += 1) { + struct joint_cell_*jc; + fprintf(fd, "(net N%u (joined", idx); + + for (jc = jnt->links ; jc ; jc = jc->next) { + if (jc->cell) + fprintf(fd, " (portRef %s (instanceRef U%u))", + jc->cell->cell->ports[jc->port].name, + jc->cell->u); + else + fprintf(fd, " (portRef %s)", + edf->ports[jc->port].name); + } + fprintf(fd, "))\n"); + } + + fprintf(fd, " )\n"); /* end the (contents...) sexp */ + + fprintf(fd, " )\n"); /* end the (view ) sexp */ + fprintf(fd, " )\n"); /* end the (cell ) sexp */ + fprintf(fd, " )\n"); /* end the (library DESIGN) sexp */ + + /* Make an instance of the defined object */ + fprintf(fd, " (design %s\n", edf->name); + fprintf(fd, " (cellRef %s (libraryRef DESIGN))\n", edf->name); + + for (prp = edf->property ; prp ; prp = prp->next) { + fprintf(fd, " (property %s (string \"%s\"))\n", + prp->name, prp->value); + } + + fprintf(fd, " )\n"); + + + + fprintf(fd, ")\n"); + fflush(fd); +} + +/* + * $Log: edif.c,v $ + * Revision 1.1 2003/03/24 00:47:54 steve + * Add new virtex2 architecture family, and + * also the new edif.h EDIF management functions. + * + */ + diff --git a/tgt-fpga/edif.h b/tgt-fpga/edif.h new file mode 100644 index 000000000..446b89baa --- /dev/null +++ b/tgt-fpga/edif.h @@ -0,0 +1,201 @@ +#ifndef __edif_H +#define __edif_H +/* + * Copyright (c) 2003 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifdef HAVE_CVS_IDENT +#ident "$Id: edif.h,v 1.1 2003/03/24 00:47:54 steve Exp $" +#endif + +# include +# include + +/* + * These types and functions support the task of generating and + * writing out an EDIF 2 0 0 netlist. These functions work by + * supporting the creation of an in-core netlist of the design, then + * writing the netlist out all at once. The library manages cells with + * ports, but does not otherwise interpret cells. They have no + * contents. + * + * The general structure of netlist creation is as follows: + * + * Create a netlist with edif_create(); + * This creates an edif object that represents the design. The + * design is given a name, and that name becomes the name of the + * single cell that this netlist handles. + * + * Add ports to the root with edif_portconfig + * The design may, if it is a macro to be included in a larger + * design, include ports. These are discovered by looking for port + * signals in the root module. + * + * Declare external libraries with edif_xlibrary_create + * Normally, this is the single technology library that contains + * the primitive cells that the code generator intendes to + * use. The library is given a name, such as VIRTEX or whatever + * the implementation tools expect. Cells are attached to the + * library later. An edif netlist may include multiple external + * references. + * + * Declare primitives with edif_xcell_create and edif_cell_portconfig. + * These functions create CELL TYPES that are attached to an + * external library. The libraries are created by + * edif_xlibrary_create. + * + * Cells can be created at any time before their first use. It + * therefore makes the most sense to not create the cell until it + * is certain that they are needed by the design. + * + * Create instances and join them up + * The edif_cellref_t objects represent instances of cells, and + * are the devices of the generated netlist. These cellrefs are + * connected together by the use of edif_joint_t joints. The + * joints can be created from ivl_nexus_t objects, or from their + * own ether. This instantiating of cells and joining them + * together that is the most fun. It is the technology specific + * stuff that the code generator does. + * + * Finally, print the result with edif_print(fd); + * This function writes the netlist in memory to an EDIF file on + * the stdio stream specified. + * + * This library is intended to be used once, to build up a netlist and + * print it. All the names that are taken as const char* should be + * somehow made permanent by the caller. Either they are constant + * strings, or they are strduped as necessary to make them + * permanent. The library will not duplicate them. + */ + +/* TYPE DECLARATIONS */ + +/* This represents the entire EDIF design. You only need one of these + to hold everything. */ +typedef struct edif_s* edif_t; + +/* Each external library of the design gets one of these. */ +typedef struct edif_xlibrary_s* edif_xlibrary_t; + +/* This represents a type of cell. */ +typedef struct edif_cell_s* edif_cell_t; + +/* A cellref is an *instance* of a cell. */ +typedef struct edif_cellref_s* edif_cellref_t; + +/* This represents a generic joint. Cell ports are connected by being + associated with a joint. These can be bound to an ivl_nexus_t + object, of stand along. */ +typedef struct edif_joint_s* edif_joint_t; + + +/* FUNCTIONS */ + + +/* Start a new EDIF design. The design_name will be used as the name + of the top-mode module of the design. */ +extern edif_t edif_create(const char*design_name, unsigned nports); + +/* macro ports to the design are handled by this library similar to + cells. The user creates ports with this function. This function + configures the sole "port" of the cell with the name and dir passed + in. The direction, in this case, is the *interface* direction. */ +extern void edif_portconfig(edif_t edf, unsigned idx, + const char*name, ivl_signal_port_t dir); + +/* This is like edif_add_to_joint, but works with the edif port. */ +extern void edif_port_to_joint(edif_joint_t jnt, edif_t edf, unsigned port); + +/* The design may have properties attached to it. These properties + will be attached to the instance declared in the footer of the EDIF + file. */ +extern void edif_pstring(edif_t edf, const char*name, const char*value); + +/* Create an external library and attach it to the edif design. This + will lead to a (external ...) declaration of cells that can be used + by the design. */ +extern edif_xlibrary_t edif_xlibrary_create(edif_t edf, const char*name); + +/* External libraries can be searched for existing cells, given a + string name. This function searches for the cell by name, and + returns it. */ +extern edif_cell_t edif_xlibrary_findcell(edif_xlibrary_t lib, + const char*cell_name); + +/* Create a new cell, attached to the external library. Specify the + number of ports that the cell has. The edif_cell_portconfig + function is then used to assign name and direction to each of the + ports. + + The cell has a number of pins that are referenced by their number + from 0 to nports-1. You need to remember the pin numbers for the + named ports for use when joining that pin to an edif_joint_t. + + Cellrefs get their port characteristics from the cell that they are + created from. So the pinouts of cellrefs match the pinout of the + associated cell. */ +extern edif_cell_t edif_xcell_create(edif_xlibrary_t, const char*name, + unsigned nports); +extern void edif_cell_portconfig(edif_cell_t cell, unsigned idx, + const char*name, ivl_signal_port_t dir); + +/* Ports of cells are normally referenced by their port number. If you + forget what that number is, this function can look it up by name. */ +extern unsigned edif_cell_port_byname(edif_cell_t cell, const char*name); + + +/* Create and instance from a cell. The instance refers to the cell, + which is a type, and contains pips for pins. */ +extern edif_cellref_t edif_cellref_create(edif_t edf, edif_cell_t cell); + +/* Instances can have properties attached to them. The name and value + given here are turned into a (property (string "val")) + sexpression attached to the instance. + + Examples of string properties commonly attached to cellref devices + include such things as the INIT= to initialize LUT cells in + FPGA devices. */ +extern void edif_cellref_pstring(edif_cellref_t ref, const char*name, + const char*value); + +/* This function gets the joint associated with a nexus. This will + create a joint if necessary. */ +extern edif_joint_t edif_joint_of_nexus(edif_t edf, ivl_nexus_t nex); + +/* For linking cells outside the ivl netlist, this function creates an + anonymous joint. */ +extern edif_joint_t edif_joint_create(edif_t edf); + +/* Given a joint, this function adds the cell reference. */ +extern void edif_add_to_joint(edif_joint_t jnt, + edif_cellref_t cell, + unsigned port); + +/* + * Print the entire design. This should only be done after the design + * is completely assembled. + */ +extern void edif_print(FILE*fd, edif_t design); + +/* + * $Log: edif.h,v $ + * Revision 1.1 2003/03/24 00:47:54 steve + * Add new virtex2 architecture family, and + * also the new edif.h EDIF management functions. + * + */ +#endif diff --git a/tgt-fpga/fpga.txt b/tgt-fpga/fpga.txt index 921405a94..d0ae25da4 100644 --- a/tgt-fpga/fpga.txt +++ b/tgt-fpga/fpga.txt @@ -2,7 +2,7 @@ FPGA LOADABLE CODE GENERATOR FOR Icarus Verilog Copyright 2001 Stephen Williams - $Id: fpga.txt,v 1.5 2002/04/30 04:26:42 steve Exp $ + $Id: fpga.txt,v 1.6 2003/03/24 00:47:54 steve Exp $ The FPGA code generator supports a variety of FPGA devices, writing XNF or EDIF depending on the target. You can select the architecture @@ -51,6 +51,11 @@ should work properly for any Virtex part. XNF ROOT PORTS + NOTE: As parts are moved over to EDIF format, XNF support will be + phased out. Current Xilinx implementation tools will accept EDIF + format files even for the older parts, and non-Xilinx implementation + tools accept nothing else. + When the output format is XNF, the code generator will generate "SIG" records for the signals that are ports of the root module. The name is declared as an external pin that this macro makes available. @@ -169,6 +174,10 @@ Compile a single-file design with command line tools like so: --- $Log: fpga.txt,v $ +Revision 1.6 2003/03/24 00:47:54 steve + Add new virtex2 architecture family, and + also the new edif.h EDIF management functions. + Revision 1.5 2002/04/30 04:26:42 steve Spelling errors. diff --git a/tgt-fpga/tables.c b/tgt-fpga/tables.c index 3f83d42cf..c45f0ee31 100644 --- a/tgt-fpga/tables.c +++ b/tgt-fpga/tables.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: tables.c,v 1.4 2002/08/12 01:35:03 steve Exp $" +#ident "$Id: tables.c,v 1.5 2003/03/24 00:47:54 steve Exp $" #endif # include "fpga_priv.h" @@ -27,6 +27,7 @@ extern const struct device_s d_generic; extern const struct device_s d_generic_edif; extern const struct device_s d_virtex_edif; +extern const struct device_s d_virtex2_edif; const struct device_table_s { @@ -36,6 +37,7 @@ const struct device_table_s { { "generic-edif", &d_generic_edif }, { "generic-xnf", &d_generic }, { "virtex", &d_virtex_edif }, + { "virtex2", &d_virtex2_edif }, { 0, 0 } }; @@ -56,6 +58,10 @@ device_t device_from_arch(const char*arch) /* * $Log: tables.c,v $ + * Revision 1.5 2003/03/24 00:47:54 steve + * Add new virtex2 architecture family, and + * also the new edif.h EDIF management functions. + * * Revision 1.4 2002/08/12 01:35:03 steve * conditional ident string using autoconfig. *