From 0e797dc7bc216b3f9a004482ff398bf6835f9295 Mon Sep 17 00:00:00 2001 From: steve Date: Wed, 25 Jun 2003 02:55:57 +0000 Subject: [PATCH] Virtex and Virtex2 share much code. --- tgt-fpga/Makefile.in | 4 +- tgt-fpga/d-virtex.c | 2348 ++++++++++-------------------------------- tgt-fpga/d-virtex2.c | 1045 +------------------ tgt-fpga/generic.c | 41 + tgt-fpga/generic.h | 51 + tgt-fpga/xilinx.c | 485 ++++++++- tgt-fpga/xilinx.h | 19 +- 7 files changed, 1134 insertions(+), 2859 deletions(-) create mode 100644 tgt-fpga/generic.c create mode 100644 tgt-fpga/generic.h diff --git a/tgt-fpga/Makefile.in b/tgt-fpga/Makefile.in index eb6238751..df3d9ac32 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.9 2003/04/05 05:53:34 steve Exp $" +#ident "$Id: Makefile.in,v 1.10 2003/06/25 02:55:57 steve Exp $" # # SHELL = /bin/sh @@ -53,7 +53,7 @@ dep: mv $*.d dep 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 xilinx.o $D +O = edif.o fpga.o gates.o mangle.o tables.o generic.o xilinx.o $D ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-fpga/d-virtex.c b/tgt-fpga/d-virtex.c index 36e6937a0..f3dda88ca 100644 --- a/tgt-fpga/d-virtex.c +++ b/tgt-fpga/d-virtex.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001 Stephen Williams (steve@icarus.com) + * 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 @@ -17,11 +17,14 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: d-virtex.c,v 1.24 2003/06/25 01:49:06 steve Exp $" +#ident "$Id: d-virtex.c,v 1.25 2003/06/25 02:55:57 steve Exp $" #endif # include "device.h" # include "fpga_priv.h" +# include "edif.h" +# include "generic.h" +# include "xilinx.h" # include # include #ifdef HAVE_MALLOC_H @@ -30,856 +33,194 @@ # include /* - * This is the EDIF code generator for VIRTEX style parts. It uses the - * following VIRTEX primitives from the unified library. - * - * BUF O, I - * non-inverting buffer. This device is typically removed by the - * place-and-route step, as it is not normally needed within an - * FPGA net. - * - * BUFT O, I, T - * - * INV O, I - * Inverting buffer. - * - * LUT2 O, I0, I1 - * LUT3 O, I0, I1, I2 - * LUT4 O, I0, I1, I2, I3 - * These are look-up tables. They represent the LUT sub-devices - * that live in the CLBs, 2 per slice. The logic value of the - * device itself is given by an INIT property. - * - * The INIT property is a string of hex digits. The binary value - * that the digits represents is the outputs addressed by the - * inputs. For example, to get an AND2 from LUT2, INIT=8. - * - * MUXCY_L LO, S, DI, CI - * - * MUXF5 O, S, I0, I1 - * MUXF6 O, S, I0, I1 - * - * XORCY O, LI, CI + * This is a table of cell types that are accessible via the cellref + * attribute to a gate. */ - -static const char*virtex_library_text = -" (external VIRTEX (edifLevel 0) (technology (numberDefinition))\n" -" (cell BUF (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port I (direction INPUT)))))\n" -" (cell BUFG (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port I (direction INPUT)))))\n" -" (cell BUFT (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port I (direction OUTPUT))\n" -" (port T (direction INPUT)))))\n" -" (cell FDCE (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port Q (direction OUTPUT))\n" -" (port D (direction INPUT))\n" -" (port C (direction INPUT))\n" -" (port CE (direction INPUT))\n" -" (port CLR (direction INPUT)))))\n" -" (cell FDCPE (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port Q (direction OUTPUT))\n" -" (port D (direction INPUT))\n" -" (port C (direction INPUT))\n" -" (port CE (direction INPUT))\n" -" (port PRE (direction INPUT))\n" -" (port CLR (direction INPUT)))))\n" -" (cell GND (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface (port GROUND (direction OUTPUT)))))\n" -" (cell INV (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port I (direction INPUT)))))\n" -" (cell IBUF (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port I (direction INPUT)))))\n" -" (cell IPAD (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port IPAD (direction OUTPUT)))))\n" -" (cell LUT2 (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port I0 (direction INPUT))\n" -" (port I1 (direction INPUT)))))\n" -" (cell LUT3 (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port I0 (direction INPUT))\n" -" (port I1 (direction INPUT))\n" -" (port I2 (direction INPUT)))))\n" -" (cell LUT4 (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port I0 (direction INPUT))\n" -" (port I1 (direction INPUT))\n" -" (port I2 (direction INPUT))\n" -" (port I3 (direction INPUT)))))\n" -" (cell MUXCY (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port S (direction INPUT))\n" -" (port DI (direction INPUT))\n" -" (port CI (direction INPUT)))))\n" -" (cell MUXCY_L (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port LO (direction OUTPUT))\n" -" (port S (direction INPUT))\n" -" (port DI (direction INPUT))\n" -" (port CI (direction INPUT)))))\n" -" (cell MUXF5 (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port S (direction INPUT))\n" -" (port I0 (direction INPUT))\n" -" (port I1 (direction INPUT)))))\n" -" (cell MUXF6 (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port S (direction INPUT))\n" -" (port I0 (direction INPUT))\n" -" (port I1 (direction INPUT)))))\n" -" (cell OBUF (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port I (direction INPUT)))))\n" -" (cell OPAD (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port OPAD (direction INPUT)))))\n" -" (cell VCC (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface (port VCC (direction OUTPUT)))))\n" -" (cell XORCY (cellType GENERIC)\n" -" (view net\n" -" (viewType NETLIST)\n" -" (interface\n" -" (port O (direction OUTPUT))\n" -" (port LI (direction INPUT))\n" -" (port CI (direction INPUT)))))\n" -" )\n" -; - - -static void edif_show_header(ivl_design_t des) -{ - edif_show_header_generic(des, virtex_library_text); -} - -static void edif_show_virtex_pad(ivl_signal_t sig, const char*str) -{ - unsigned idx; - unsigned*pins; - char jbuf[1024]; - - 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; - } - - for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) { - char port_name[256]; - edif_uref += 1; - - /* Calculate the name of the net that connects the - pad to the I/OBUF. This leads to more humane - names in the mapped netlist. */ - if (ivl_signal_pins(sig) == 1) - sprintf(port_name, "(rename U%uN \"%s\")", - edif_uref, ivl_signal_basename(sig)); - else - sprintf(port_name, "(rename U%uN \"%s[%u]\")", - edif_uref, ivl_signal_basename(sig), idx); - - - /* Draw the PAD and the I/O BUF, and connect the buffer - to the logic that we are generating. */ - - switch (ivl_signal_port(sig)) { - case IVL_SIP_INPUT: - fprintf(xnf, "(instance U%uPAD" - " (viewRef net (cellRef IPAD (libraryRef VIRTEX)))", - edif_uref); - if (pins[idx] != 0) - fprintf(xnf, " (property LOC (string \"P%u\"))", - pins[idx]); - fprintf(xnf, ")\n"); - - fprintf(xnf, "(instance U%u" - " (viewRef net " - " (cellRef IBUF (libraryRef VIRTEX))))\n", - edif_uref); - - fprintf(xnf, "(net %s (joined" - " (portRef IPAD (instanceRef U%uPAD))" - " (portRef I (instanceRef U%u))))\n", - port_name, edif_uref, edif_uref); - - sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(ivl_signal_pin(sig, idx), jbuf); - break; - - case IVL_SIP_OUTPUT: - fprintf(xnf, "(instance U%uPAD" - " (viewRef net (cellRef OPAD (libraryRef VIRTEX)))", - edif_uref); - if (pins[idx] != 0) - fprintf(xnf, " (property LOC (string \"P%u\"))", - pins[idx]); - fprintf(xnf, ")\n"); - - fprintf(xnf, "(instance U%u" - " (viewRef net " - " (cellRef OBUF (libraryRef VIRTEX))))\n", - edif_uref); - - fprintf(xnf, "(net %s (joined" - " (portRef OPAD (instanceRef U%uPAD))" - " (portRef O (instanceRef U%u))))\n", - port_name, edif_uref, edif_uref); - - sprintf(jbuf, "(portRef I (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(ivl_signal_pin(sig, idx), jbuf); - break; - - default: - assert(0); - } - } - - free(pins); -} - -static void edif_show_lut2(const char*scope, const char*name, unsigned uref, - ivl_nexus_t O, ivl_nexus_t I0, ivl_nexus_t I1, - const char*truth_table) -{ - char jbuf[1024]; - - fprintf(xnf, "(instance (rename U%u \"%s.%s\")" - " (viewRef net" - " (cellRef LUT2 (libraryRef VIRTEX)))" - " (property INIT (string \"%s\")))\n", - uref, scope, name, truth_table); - - sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(O, jbuf); - - sprintf(jbuf, "(portRef I0 (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(I0, jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(I1, jbuf); -} - -static void edif_show_lut3(const char*scope, const char*name, unsigned uref, - ivl_nexus_t O, - ivl_nexus_t I0, - ivl_nexus_t I1, - ivl_nexus_t I2, - const char*truth_table) -{ - char jbuf[1024]; - - fprintf(xnf, "(instance (rename U%u \"%s.%s\")" - " (viewRef net" - " (cellRef LUT3 (libraryRef VIRTEX)))" - " (property INIT (string \"%s\")))\n", - uref, scope, name, truth_table); - - sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(O, jbuf); - - sprintf(jbuf, "(portRef I0 (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(I0, jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(I1, jbuf); - - sprintf(jbuf, "(portRef I2 (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(I2, jbuf); -} - -static void edif_show_lut4(const char*scope, const char*name, unsigned uref, - ivl_nexus_t O, - ivl_nexus_t I0, ivl_nexus_t I1, - ivl_nexus_t I2, ivl_nexus_t I3, - const char*truth_table) -{ - char jbuf[1024]; - - fprintf(xnf, "(instance (rename U%u \"%s.%s\")" - " (viewRef net" - " (cellRef LUT4 (libraryRef VIRTEX)))" - " (property INIT (string \"%s\")))\n", - uref, scope, name, truth_table); - - sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(O, jbuf); - - sprintf(jbuf, "(portRef I0 (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(I0, jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(I1, jbuf); - - sprintf(jbuf, "(portRef I2 (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(I2, jbuf); - - sprintf(jbuf, "(portRef I3 (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(I3, jbuf); -} - -void edif_show_cellref_logic(ivl_net_logic_t net, const char*cellref) -{ - char jbuf[1024]; - unsigned idx; - const char*cp; - char*tmpname; - - edif_uref += 1; - - cp = strchr(cellref, ':'); - assert(cp); - - tmpname = malloc(cp - cellref + 1); - strncpy(tmpname, cellref, cp-cellref); - tmpname[cp-cellref] = 0; - - fprintf(xnf, "(instance (rename U%u \"%s\")" - " (viewRef net (cellRef %s (libraryRef VIRTEX))))\n", - edif_uref, ivl_logic_name(net), tmpname); - - free(tmpname); - - cellref = cp + 1; - - for (idx = 0 ; idx < ivl_logic_pins(net) ; idx += 1) { - ivl_nexus_t nex = ivl_logic_pin(net, idx); - - cp = strchr(cellref, ','); - if (cp == 0) - cp = cellref+strlen(cellref); - - tmpname = malloc(cp - cellref + 1); - strncpy(tmpname, cellref, cp-cellref); - tmpname[cp-cellref] = 0; - - sprintf(jbuf, "(portRef %s (instanceRef U%u))", - tmpname, edif_uref); - edif_set_nexus_joint(nex, jbuf); - - free(tmpname); - cellref = *cp? cp+1 : cp; - } -} - +const static struct edif_xlib_celltable virtex_celltable[] = { + { "BUFG", xilinx_cell_bufg }, + { "MULT_AND", xilinx_cell_mult_and }, + { 0, 0} +}; + /* - * This function draw wide AND-like devices. The input must have at - * least 5 bits. + * 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 wide_AND_logic(ivl_net_logic_t net, unsigned edif_uref) +static void virtex_show_header(ivl_design_t des) { - char jbuf[1024]; + unsigned idx; + ivl_scope_t root = ivl_design_root(des); + unsigned sig_cnt = ivl_scope_sigs(root); + unsigned nports = 0, pidx; + const char*part_str = 0; - /* This is the number of input bits left to connect. */ - unsigned ibits = ivl_logic_pins(net) - 1; - /* Index to the next input bit. */ - unsigned idx = 1; - unsigned slice = 0; + /* 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); - const char*lut4_init; - const char*lut3_init; - const char*lut2_init; - const char*lut1_dev; + if (ivl_signal_port(sig) == IVL_SIP_NONE) + continue; - switch (ivl_logic_type(net)) { - case IVL_LO_AND: - lut4_init = "\"8000\""; - lut3_init = "\"80\""; - lut2_init = "\"8\""; - lut1_dev = "BUF"; - break; - case IVL_LO_NOR: - lut4_init = "\"0001\""; - lut3_init = "\"01\""; - lut2_init = "\"1\""; - lut1_dev = "INV"; - break; - default: - assert(0); + if (ivl_signal_attr(sig, "PAD") != 0) + continue; + + nports += ivl_signal_pins(sig); } - assert(ibits > 4); + edf = edif_create(ivl_scope_basename(root), nports); - while (ibits >= 4) { + pidx = 0; + for (idx = 0 ; idx < sig_cnt ; idx += 1) { + edif_joint_t jnt; + ivl_signal_t sig = ivl_scope_sig(root, idx); - /* The least significant bits are ANDed together 4 at a - time with LUT4 devices. The output of the LUT4 device - connects to a MUXCY device that passes its output - up to the next stage. + if (ivl_signal_port(sig) == IVL_SIP_NONE) + continue; - The DI input of the MUXCY (S==0) is connected to - ground, so that the ouput of the chain is pinned to 0 - if this slice does not AND to 1. + if (ivl_signal_attr(sig, "PAD") != 0) + continue; - If the LUT emits 1, S==1 and this slice passes the - compare from below. So the CI of the MUXCY gets the O - of the MUXCY one slice back. */ + if (ivl_signal_pins(sig) == 1) { + edif_portconfig(edf, pidx, ivl_signal_basename(sig), + ivl_signal_port(sig)); - fprintf(xnf, "(instance U%uL%u" - " (viewRef net" - " (cellRef LUT4 (libraryRef VIRTEX)))" - " (property INIT (string %s)))\n", - edif_uref, slice, lut4_init); + assert(ivl_signal_pins(sig) == 1); + jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0)); + edif_port_to_joint(jnt, edf, pidx); - fprintf(xnf, "(instance U%uM%u" - " (viewRef net" - " (cellRef MUXCY (libraryRef VIRTEX))))\n", - edif_uref, slice); - - fprintf(xnf, "(instance U%uG%u" - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref, slice); - - fprintf(xnf, "(net U%uLM%u (joined" - " (portRef O (instanceRef U%uL%u))" - " (portRef S (instanceRef U%uM%u))))\n", - edif_uref, slice, - edif_uref, slice, - edif_uref, slice); - - fprintf(xnf, "(net U%uGM%u (joined" - " (portRef GROUND (instanceRef U%uG%u))" - " (portRef DI (instanceRef U%uM%u))))\n", - edif_uref, slice, - edif_uref, slice, - edif_uref, slice); - - if (slice == 0) { - fprintf(xnf, "(instance U%uV%u" - " (viewRef net" - " (cellRef VCC (libraryRef VIRTEX))))\n", - edif_uref, slice); - - fprintf(xnf, "(net U%uMM%u (joined" - " (portRef VCC (instanceRef U%uG%u))" - " (portRef CI (instanceRef U%uM%u))))\n", - edif_uref, slice, - edif_uref, slice, - edif_uref, slice); } else { - fprintf(xnf, "(net U%uMM%u (joined" - " (portRef O (instanceRef U%uM%u))" - " (portReg CI (instanceRef U%uM%u))))\n", - edif_uref, slice, - edif_uref, slice-1, - edif_uref, slice); + 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); + } } - sprintf(jbuf, "(portRef I0 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+0), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+1), jbuf); - - sprintf(jbuf, "(portRef I2 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+2), jbuf); - - sprintf(jbuf, "(portRef I3 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+3), jbuf); - - ibits -= 4; - idx += 4; - slice += 1; + pidx += ivl_signal_pins(sig); } - if (ibits == 0) { - sprintf(jbuf, "(portRef O (instanceRef U%uM%u))", - edif_uref, slice-1); - edif_set_nexus_joint(ivl_logic_pin(net, 0), jbuf); - return; + assert(pidx == nports); + + 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); } - switch (ibits) { + cell_0 = edif_xcell_create(xlib, "GND", 1); + edif_cell_portconfig(cell_0, 0, "GROUND", IVL_SIP_OUTPUT); - case 1: - fprintf(xnf, "(instance U%uL%u" - " (viewRef net" - " (cellRef %s (libraryRef VIRTEX))))\n", - edif_uref, slice, lut1_dev); + cell_1 = edif_xcell_create(xlib, "VCC", 1); + edif_cell_portconfig(cell_1, 0, "VCC", IVL_SIP_OUTPUT); - sprintf(jbuf, "(portRef I0 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+0), jbuf); - break; - - case 2: - fprintf(xnf, "(instance U%uL%u" - " (viewRef net" - " (cellRef LUT2 (libraryRef VIRTEX)))" - " (property INIT (string %s)))\n", - edif_uref, slice, lut2_init); - - sprintf(jbuf, "(portRef I0 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+0), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+1), jbuf); - break; - - case 3: - fprintf(xnf, "(instance U%uL%u" - " (viewRef net" - " (cellRef LUT3 (libraryRef VIRTEX)))" - " (property INIT (string %s)))\n", - edif_uref, slice, lut3_init); - - sprintf(jbuf, "(portRef I0 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+0), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+1), jbuf); - - sprintf(jbuf, "(portRef I2 (instanceRef U%uL%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, idx+2), jbuf); - break; - - default: - assert(0); - } - - fprintf(xnf, "(instance U%uM%u" - " (viewRef net" - " (cellRef MUXCY (libraryRef VIRTEX))))\n", - edif_uref, slice); - - fprintf(xnf, "(instance U%uG%u" - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref, slice); - - fprintf(xnf, "(net U%uLM%u (joined" - " (portRef O (instanceRef U%uL%u))" - " (portRef S (instanceRef U%uM%u))))\n", - edif_uref, slice, - edif_uref, slice, - edif_uref, slice); - - fprintf(xnf, "(net U%uGM%u (joined" - " (portRef GROUND (instanceRef U%uG%u))" - " (portRef DI (instanceRef U%uM%u))))\n", - edif_uref, slice, - edif_uref, slice, - edif_uref, slice); - - fprintf(xnf, "(net U%uMM%u (joined" - " (portRef O (instanceRef U%uM%u))" - " (portReg CI (instanceRef U%uM%u))))\n", - edif_uref, slice, - edif_uref, slice-1, - edif_uref, slice); - - sprintf(jbuf, "(portRef O (instanceRef U%uM%u))", - edif_uref, slice); - edif_set_nexus_joint(ivl_logic_pin(net, 0), jbuf); } -static void edif_show_virtex_logic(ivl_net_logic_t net) +void virtex_show_footer(ivl_design_t des) { - char jbuf[1024]; + unsigned idx; - { const char*dev = ivl_logic_attr(net, "cellref"); - if (dev != 0) { - edif_show_cellref_logic(net, dev); - return; - } + 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_uref += 1; + edif_print(xnf, edf); +} - switch (ivl_logic_type(net)) { +void virtex_generic_dff(ivl_lpm_t net) +{ + unsigned idx; - case IVL_LO_AND: - assert(ivl_logic_pins(net) >= 3); + ivl_nexus_t aclr = ivl_lpm_async_clr(net); + ivl_nexus_t aset = ivl_lpm_async_set(net); + const char*abits = 0; - switch (ivl_logic_pins(net)) { - case 3: - edif_show_lut2(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), "8"); - break; - case 4: - edif_show_lut3(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), "80"); - break; - case 5: - edif_show_lut4(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), - ivl_logic_pin(net, 4), "8000"); - break; - default: - wide_AND_logic(net, edif_uref); - break; + 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')) { + obj = edif_cellref_create(edf, xilinx_cell_fdcpe(xlib)); + } else { + obj = edif_cellref_create(edf, xilinx_cell_fdce(xlib)); } - break; - case IVL_LO_BUF: - case IVL_LO_BUFZ: - assert(ivl_logic_pins(net) == 2); - fprintf(xnf, "(instance (rename U%u \"%s\")", - edif_uref, ivl_logic_name(net)); - fprintf(xnf, " (viewRef net" - " (cellRef BUF (libraryRef VIRTEX))))\n"); + jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); + edif_add_to_joint(jnt, obj, FDCE_Q); - sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(ivl_logic_pin(net, 0), jbuf); + jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); + edif_add_to_joint(jnt, obj, FDCE_D); - sprintf(jbuf, "(portRef I (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(ivl_logic_pin(net, 1), jbuf); - break; + jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net)); + edif_add_to_joint(jnt, obj, FDCE_C); - case IVL_LO_BUFIF1: - assert(ivl_logic_pins(net) == 3); - fprintf(xnf, "(instance (rename U%u \"%s\")", - edif_uref, ivl_logic_name(net)); - fprintf(xnf, " (viewRef net" - " (cellRef TBUF (libraryRef VIRTEX))))\n"); - - sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(ivl_logic_pin(net, 0), jbuf); - - sprintf(jbuf, "(portRef I (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(ivl_logic_pin(net, 1), jbuf); - - sprintf(jbuf, "(portRef T (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(ivl_logic_pin(net, 2), jbuf); - break; - - case IVL_LO_NOR: - assert(ivl_logic_pins(net) >= 3); - - switch (ivl_logic_pins(net)) { - case 3: - edif_show_lut2(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), "1"); - break; - case 4: - edif_show_lut3(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), "01"); - break; - case 5: - edif_show_lut4(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), - ivl_logic_pin(net, 4), "0001"); - break; - default: - wide_AND_logic(net, edif_uref); - break; + if ( (nex = ivl_lpm_enable(net)) ) { + jnt = edif_joint_of_nexus(edf, nex); + edif_add_to_joint(jnt, obj, FDCE_CE); } - break; - case IVL_LO_NOT: - assert(ivl_logic_pins(net) == 2); - fprintf(xnf, "(instance (rename U%u \"%s\")", - edif_uref, ivl_logic_name(net)); - fprintf(xnf, " (viewRef net" - " (cellRef INV (libraryRef VIRTEX))))\n"); - - sprintf(jbuf, "(portRef O (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(ivl_logic_pin(net, 0), jbuf); - - sprintf(jbuf, "(portRef I (instanceRef U%u))", edif_uref); - edif_set_nexus_joint(ivl_logic_pin(net, 1), jbuf); - break; - - case IVL_LO_OR: - assert(ivl_logic_pins(net) <= 5); - assert(ivl_logic_pins(net) >= 3); - - switch (ivl_logic_pins(net)) { - case 3: - edif_show_lut2(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), "E"); - break; - case 4: - edif_show_lut3(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), "FE"); - break; - case 5: - edif_show_lut4(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), - ivl_logic_pin(net, 4), "FFFE"); - break; + if (aclr) { + jnt = edif_joint_of_nexus(edf, aclr); + edif_add_to_joint(jnt, obj, FDCE_CLR); } - break; - case IVL_LO_XNOR: - assert(ivl_logic_pins(net) <= 5); - assert(ivl_logic_pins(net) >= 3); - - switch (ivl_logic_pins(net)) { - case 3: - edif_show_lut2(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), "9"); - break; - case 4: - edif_show_lut3(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), "69"); - break; - case 5: - edif_show_lut4(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), - ivl_logic_pin(net, 4), "9669"); - break; + 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); + } } - break; - - case IVL_LO_XOR: - assert(ivl_logic_pins(net) <= 5); - assert(ivl_logic_pins(net) >= 3); - - switch (ivl_logic_pins(net)) { - case 3: - edif_show_lut2(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), "6"); - break; - case 4: - edif_show_lut3(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), "96"); - break; - case 5: - edif_show_lut4(ivl_scope_name(ivl_logic_scope(net)), - ivl_logic_basename(net), edif_uref, - ivl_logic_pin(net, 0), - ivl_logic_pin(net, 1), - ivl_logic_pin(net, 2), - ivl_logic_pin(net, 3), - ivl_logic_pin(net, 4), "6996"); - break; - } - break; - - default: - fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n", - ivl_logic_type(net)); } } @@ -916,1031 +257,432 @@ static void edif_show_virtex_logic(ivl_net_logic_t net) * 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. + * 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. */ -static void edif_show_virtex_eq(ivl_lpm_t net) +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; - edif_uref += 1; - switch (ivl_lpm_width(net)) { + case 1: - edif_show_lut2(ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net), edif_uref, - ivl_lpm_q(net, 0), - ivl_lpm_data(net, 0), - ivl_lpm_datab(net, 0), eq? "9" : "6"); - break; + 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: - edif_show_lut4(ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net), edif_uref, - ivl_lpm_q(net, 0), - ivl_lpm_data(net, 0), ivl_lpm_datab(net, 0), - ivl_lpm_data(net, 1), ivl_lpm_datab(net, 1), - eq? "9009" : "6FF6"); - break; + lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib)); + edif_cellref_pstring(lut, "INIT", eq? "9009" : "6FF6"); - default: { - char jbuf[1024]; - unsigned idx; - unsigned pairs = ivl_lpm_width(net) / 2; - unsigned tail = ivl_lpm_width(net) % 2; + 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); - if (tail == 0) { - tail = 2; - pairs -= 1; - } + jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); + edif_add_to_joint(jnt, lut, LUT_I1); - fprintf(xnf, "(instance U%uL0" - " (viewRef net" - " (cellRef LUT4 (libraryRef VIRTEX)))" - " (property INIT (string \"9009\")))\n", - edif_uref); - fprintf(xnf, "(instance U%uM0" - " (viewRef net" - " (cellRef MUXCY_L (libraryRef VIRTEX))))\n", - edif_uref); - fprintf(xnf, "(instance U%uG0" - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref); + jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1)); + edif_add_to_joint(jnt, lut, LUT_I2); - fprintf(xnf, "(instance U%uV0" - " (viewRef net" - " (cellRef VCC (libraryRef VIRTEX))))\n", - edif_uref); - - if (eq) { - fprintf(xnf, "(net U%uVM0 (joined" - " (portRef VCC (instanceRef U%uV0))" - " (portRef CI (instanceRef U%uM0))))\n", - edif_uref, edif_uref, edif_uref); - fprintf(xnf, "(net U%uGM0 (joined" - " (portRef GROUND (instanceRef U%uG0))" - " (portRef DI (instanceRef U%uM0))))\n", - edif_uref, edif_uref, edif_uref); - } else { - fprintf(xnf, "(net U%uVM0 (joined" - " (portRef VCC (instanceRef U%uV0))" - " (portRef DI (instanceRef U%uM0))))\n", - edif_uref, edif_uref, edif_uref); - fprintf(xnf, "(net U%uGM0 (joined" - " (portRef GROUND (instanceRef U%uG0))" - " (portRef CI (instanceRef U%uM0))))\n", - edif_uref, edif_uref, edif_uref); - } - - fprintf(xnf, "(net U%uLM0 (joined" - " (portRef O (instanceRef U%uL0))" - " (portRef S (instanceRef U%uM0))))\n", - edif_uref, edif_uref, edif_uref); - - sprintf(jbuf, "(portRef I0 (instanceRef U%uL0))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data(net, 0), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%uL0))", edif_uref); - edif_set_nexus_joint(ivl_lpm_datab(net, 0), jbuf); - - sprintf(jbuf, "(portRef I2 (instanceRef U%uL0))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data(net, 1), jbuf); - - sprintf(jbuf, "(portRef I3 (instanceRef U%uL0))", edif_uref); - edif_set_nexus_joint(ivl_lpm_datab(net, 1), jbuf); - - - for (idx = 1 ; idx < pairs ; idx += 1) { - fprintf(xnf, "(instance U%uL%u" - " (viewRef net" - " (cellRef LUT4 (libraryRef VIRTEX)))" - " (property INIT (string \"9009\")))\n", - edif_uref, idx); - fprintf(xnf, "(instance U%uM%u" - " (viewRef net" - " (cellRef MUXCY_L (libraryRef VIRTEX))))\n", - edif_uref, idx); - - fprintf(xnf, "(net U%uVM%u (joined" - " (portRef LO (instanceRef U%uM%u))" - " (portRef CI (instanceRef U%uM%u))))\n", - edif_uref, idx, edif_uref, idx-1, - edif_uref, idx); - if (eq) { - fprintf(xnf, "(instance U%uG%u" - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref, idx); - fprintf(xnf, "(net U%uGM%u (joined" - " (portRef GROUND (instanceRef U%uG%u))" - " (portRef DI (instanceRef U%uM%u))))\n", - edif_uref, idx, edif_uref, idx, - edif_uref, idx); - } else { - fprintf(xnf, "(instance U%uG%u" - " (viewRef net" - " (cellRef VCC (libraryRef VIRTEX))))\n", - edif_uref, idx); - fprintf(xnf, "(net U%uGM%u (joined" - " (portRef VCC (instanceRef U%uG%u))" - " (portRef DI (instanceRef U%uM%u))))\n", - edif_uref, idx, edif_uref, idx, - edif_uref, idx); - } - fprintf(xnf, "(net U%uLM%u (joined" - " (portRef O (instanceRef U%uL%u))" - " (portRef S (instanceRef U%uM%u))))\n", - edif_uref, idx, edif_uref, idx, - edif_uref, idx); - - sprintf(jbuf, "(portRef I0 (instanceRef U%uL%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_data(net, idx*2), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%uL%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_datab(net, idx*2), jbuf); - - sprintf(jbuf, "(portRef I2 (instanceRef U%uL%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_data(net, idx*2+1), jbuf); - - sprintf(jbuf, "(portRef I3 (instanceRef U%uL%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_datab(net, idx*2+1), jbuf); - - } - - if (tail == 2) { - fprintf(xnf, "(instance U%uL%u" - " (viewRef net" - " (cellRef LUT4 (libraryRef VIRTEX)))" - " (property INIT (string \"9009\")))\n", - edif_uref, pairs); - fprintf(xnf, "(instance (rename U%uM%u \"%s.%s\")" - " (viewRef net" - " (cellRef MUXCY (libraryRef VIRTEX))))\n", - edif_uref, pairs, - ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net)); - - if (eq) { - fprintf(xnf, "(instance U%uG%u" - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref, pairs); - fprintf(xnf, "(net U%uGM%u (joined" - " (portRef GROUND (instanceRef U%uG%u))" - " (portRef DI (instanceRef U%uM%u))))\n", - edif_uref, pairs, edif_uref, pairs, - edif_uref, pairs); - } else { - fprintf(xnf, "(instance U%uG%u" - " (viewRef net" - " (cellRef VCC (libraryRef VIRTEX))))\n", - edif_uref, pairs); - fprintf(xnf, "(net U%uGM%u (joined" - " (portRef VCC (instanceRef U%uG%u))" - " (portRef DI (instanceRef U%uM%u))))\n", - edif_uref, pairs, edif_uref, pairs, - edif_uref, pairs); - } - - fprintf(xnf, "(net U%uVM%u (joined" - " (portRef LO (instanceRef U%uM%u))" - " (portRef CI (instanceRef U%uM%u))))\n", - edif_uref, pairs, edif_uref, pairs-1, - edif_uref, pairs); - fprintf(xnf, "(net U%uLM%u (joined" - " (portRef O (instanceRef U%uL%u))" - " (portRef S (instanceRef U%uM%u))))\n", - edif_uref, pairs, edif_uref, pairs, - edif_uref, pairs); - - sprintf(jbuf, "(portRef I0 (instanceRef U%uL%u))", - edif_uref, pairs); - edif_set_nexus_joint(ivl_lpm_data(net, pairs*2), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%uL%u))", - edif_uref, pairs); - edif_set_nexus_joint(ivl_lpm_datab(net, pairs*2), jbuf); - - sprintf(jbuf, "(portRef I2 (instanceRef U%uL%u))", - edif_uref, pairs); - edif_set_nexus_joint(ivl_lpm_data(net, pairs*2+1), jbuf); - - sprintf(jbuf, "(portRef I3 (instanceRef U%uL%u))", - edif_uref, pairs); - edif_set_nexus_joint(ivl_lpm_datab(net, pairs*2+1), jbuf); - - } else { - assert(tail == 1); - - fprintf(xnf, "(instance (rename U%uL%u \"%s.%s\")" - " (viewRef net" - " (cellRef LUT2 (libraryRef VIRTEX)))" - " (property INIT (string \"9\")))\n", - edif_uref, pairs, - ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net)); - fprintf(xnf, "(instance U%uM%u" - " (viewRef net" - " (cellRef MUXCY (libraryRef VIRTEX))))\n", - edif_uref, pairs); - - if (eq) { - fprintf(xnf, "(instance U%uG%u" - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref, pairs); - fprintf(xnf, "(net U%uGM%u (joined" - " (portRef GROUND (instanceRef U%uG%u))" - " (portRef DI (instanceRef U%uM%u))))\n", - edif_uref, pairs, edif_uref, pairs, - edif_uref, pairs); - } else { - fprintf(xnf, "(instance U%uG%u" - " (viewRef net" - " (cellRef VCC (libraryRef VIRTEX))))\n", - edif_uref, pairs); - fprintf(xnf, "(net U%uGM%u (joined" - " (portRef VCC (instanceRef U%uG%u))" - " (portRef DI (instanceRef U%uM%u))))\n", - edif_uref, pairs, edif_uref, pairs, - edif_uref, pairs); - } - - fprintf(xnf, "(net U%uVM%u (joined" - " (portRef LO (instanceRef U%uM%u))" - " (portRef CI (instanceRef U%uM%u))))\n", - edif_uref, pairs, edif_uref, pairs-1, - edif_uref, pairs); - fprintf(xnf, "(net U%uLM%u (joined" - " (portRef O (instanceRef U%uL%u))" - " (portRef S (instanceRef U%uM%u))))\n", - edif_uref, pairs, edif_uref, pairs, - edif_uref, pairs); - - sprintf(jbuf, "(portRef I0 (instanceRef U%uL%u))", - edif_uref, pairs); - edif_set_nexus_joint(ivl_lpm_data(net, pairs*2), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%uL%u))", - edif_uref, pairs); - edif_set_nexus_joint(ivl_lpm_datab(net, pairs*2), jbuf); - - } - - sprintf(jbuf, "(portRef O (instanceRef U%uM%u))", - edif_uref, pairs); - edif_set_nexus_joint(ivl_lpm_q(net, 0), jbuf); - - break; - } - } -} - -/* - * This supports the general MUX with a single select input. The - * output is selected from one of two inputs. - * - * This implements the mux a bit slice at a time. Each slice is a - * 1-bit mux implemented with a three input LUT: I0 and I1 are the - * alternative inputs, and I2 is the select. - * - * FIXME: In the long run, it would be cool to detect that the inputs - * of the mux are themselves LUT devices and generate MUXF5 devices in - * those cases. This currently does *not* do that. - */ -static void edif_show_virtex_muxs1(ivl_lpm_t net) -{ - unsigned idx; - assert(ivl_lpm_width(net) >= 1); - assert(ivl_lpm_selects(net) == 1); - - for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { - char tmp_name[1024]; - - edif_uref += 1; - sprintf(tmp_name, "%s<%u>", ivl_lpm_basename(net), idx); - - edif_show_lut3(ivl_scope_name(ivl_lpm_scope(net)), - tmp_name, edif_uref, - ivl_lpm_q(net, idx), - ivl_lpm_data2(net, 0, idx), - ivl_lpm_data2(net, 1, idx), - ivl_lpm_select(net, 0), - "CA"); - } -} - -/* - * This supports the general mux with two select inputs. This is a 4:1 - * mux. Use two LUT3 devices and a MUXF5 to form each bit slice of the - * full mux. By using a MUXF5, we pretty much confine the bit slice to - * a Virtex CLB slice. - */ -static void edif_show_virtex_muxs2(ivl_lpm_t net) -{ - unsigned idx; - - assert(ivl_lpm_width(net) >= 1); - assert(ivl_lpm_selects(net) == 2); - - for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { - char tmp_name[1024]; - - edif_uref += 1; - sprintf(tmp_name, "%s.%s<%u>", - ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net), idx); - - fprintf(xnf, "(instance U%uA" - " (viewRef net" - " (cellRef LUT3 (libraryRef VIRTEX)))" - " (property INIT (string \"CA\")))\n", edif_uref); - - fprintf(xnf, "(instance U%uB" - " (viewRef net" - " (cellRef LUT3 (libraryRef VIRTEX)))" - " (property INIT (string \"CA\")))\n", edif_uref); - - fprintf(xnf, "(instance (rename U%uF \"%s\")" - " (viewRef net" - " (cellRef MUXF5 (libraryRef VIRTEX))))\n", - edif_uref, tmp_name); - - fprintf(xnf, "(net U%uAF (joined" - " (portRef O (instanceRef U%uA))" - " (portRef I0 (instanceRef U%uF))))\n", - edif_uref, edif_uref, edif_uref); - fprintf(xnf, "(net U%uBF (joined" - " (portRef O (instanceRef U%uB))" - " (portRef I1 (instanceRef U%uF))))\n", - edif_uref, edif_uref, edif_uref); - - sprintf(tmp_name, "(portRef I0 (instanceRef U%uA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 0, idx), tmp_name); - - sprintf(tmp_name, "(portRef I1 (instanceRef U%uA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 1, idx), tmp_name); - - sprintf(tmp_name, "(portRef I0 (instanceRef U%uB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 2, idx), tmp_name); - - sprintf(tmp_name, "(portRef I1 (instanceRef U%uB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 3, idx), tmp_name); - - sprintf(tmp_name, "(portRef I2 (instanceRef U%uA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 0), tmp_name); - - sprintf(tmp_name, "(portRef I2 (instanceRef U%uB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 0), tmp_name); - - sprintf(tmp_name, "(portRef S (instanceRef U%uF))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 1), tmp_name); - - sprintf(tmp_name, "(portRef O (instanceRef U%uF))", edif_uref); - edif_set_nexus_joint(ivl_lpm_q(net, idx), tmp_name); - } -} -static void edif_show_virtex_muxs3(ivl_lpm_t net) -{ - unsigned idx; - - assert(ivl_lpm_width(net) >= 1); - assert(ivl_lpm_selects(net) == 3); - for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { - char tmp_name[1024]; - - edif_uref += 1; - sprintf(tmp_name, "%s.%s<%u>", - ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net), idx); - - fprintf(xnf, "(instance U%uAA" - " (viewRef net" - " (cellRef LUT3 (libraryRef VIRTEX)))" - " (property INIT (string \"CA\")))\n", edif_uref); - - fprintf(xnf, "(instance U%uBA" - " (viewRef net" - " (cellRef LUT3 (libraryRef VIRTEX)))" - " (property INIT (string \"CA\")))\n", edif_uref); - - fprintf(xnf, "(instance U%uFA" - " (viewRef net" - " (cellRef MUXF5 (libraryRef VIRTEX))))\n", - edif_uref); - - fprintf(xnf, "(net U%uAFA (joined" - " (portRef O (instanceRef U%uAA))" - " (portRef I0 (instanceRef U%uFA))))\n", - edif_uref, edif_uref, edif_uref); - fprintf(xnf, "(net U%uBFA (joined" - " (portRef O (instanceRef U%uBA))" - " (portRef I1 (instanceRef U%uFA))))\n", - edif_uref, edif_uref, edif_uref); - - fprintf(xnf, "(instance U%uAB" - " (viewRef net" - " (cellRef LUT3 (libraryRef VIRTEX)))" - " (property INIT (string \"CA\")))\n", edif_uref); - - fprintf(xnf, "(instance U%uBB" - " (viewRef net" - " (cellRef LUT3 (libraryRef VIRTEX)))" - " (property INIT (string \"CA\")))\n", edif_uref); - - fprintf(xnf, "(instance U%uFB" - " (viewRef net" - " (cellRef MUXF5 (libraryRef VIRTEX))))\n", - edif_uref); - - fprintf(xnf, "(net U%uAFB (joined" - " (portRef O (instanceRef U%uAB))" - " (portRef I0 (instanceRef U%uFB))))\n", - edif_uref, edif_uref, edif_uref); - fprintf(xnf, "(net U%uBFB (joined" - " (portRef O (instanceRef U%uBB))" - " (portRef I1 (instanceRef U%uFB))))\n", - edif_uref, edif_uref, edif_uref); - - - /* Connect the two MUXF5 devices to the MUXF6. */ - - fprintf(xnf, "(instance (rename U%uF \"%s\")" - " (viewRef net" - " (cellRef MUXF6 (libraryRef VIRTEX))))\n", - edif_uref, tmp_name); - - fprintf(xnf, "(net U%uFA (joined" - " (portRef O (instanceRef U%uFA))" - " (portRef I0 (instanceRef U%uF))))\n", - edif_uref, edif_uref, edif_uref); - fprintf(xnf, "(net U%uFB (joined" - " (portRef O (instanceRef U%uFB))" - " (portRef I1 (instanceRef U%uF))))\n", - edif_uref, edif_uref, edif_uref); - - sprintf(tmp_name, "(portRef I0 (instanceRef U%uAA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 0, idx), tmp_name); - - sprintf(tmp_name, "(portRef I1 (instanceRef U%uAA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 1, idx), tmp_name); - - sprintf(tmp_name, "(portRef I0 (instanceRef U%uBA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 2, idx), tmp_name); - - sprintf(tmp_name, "(portRef I1 (instanceRef U%uBA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 3, idx), tmp_name); - - sprintf(tmp_name, "(portRef I0 (instanceRef U%uAB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 4, idx), tmp_name); - - sprintf(tmp_name, "(portRef I1 (instanceRef U%uAB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 5, idx), tmp_name); - - sprintf(tmp_name, "(portRef I0 (instanceRef U%uBB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 6, idx), tmp_name); - - sprintf(tmp_name, "(portRef I1 (instanceRef U%uBB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data2(net, 7, idx), tmp_name); - - sprintf(tmp_name, "(portRef I2 (instanceRef U%uAA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 0), tmp_name); - - sprintf(tmp_name, "(portRef I2 (instanceRef U%uBA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 0), tmp_name); - - sprintf(tmp_name, "(portRef I2 (instanceRef U%uAB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 0), tmp_name); - - sprintf(tmp_name, "(portRef I2 (instanceRef U%uBB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 0), tmp_name); - - sprintf(tmp_name, "(portRef S (instanceRef U%uFA))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 1), tmp_name); - - sprintf(tmp_name, "(portRef S (instanceRef U%uFB))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 1), tmp_name); - - sprintf(tmp_name, "(portRef S (instanceRef U%uF))", edif_uref); - edif_set_nexus_joint(ivl_lpm_select(net, 2), tmp_name); - - sprintf(tmp_name, "(portRef O (instanceRef U%uF))", edif_uref); - edif_set_nexus_joint(ivl_lpm_q(net, idx), tmp_name); - } -} - - -static void edif_show_virtex_mux(ivl_lpm_t net) -{ - switch (ivl_lpm_selects(net)) { - case 1: - edif_show_virtex_muxs1(net); - break; - case 2: - edif_show_virtex_muxs2(net); - break; - case 3: - edif_show_virtex_muxs3(net); - break; - default: - assert(0); - break; - } -} - -static void edif_show_virtex_add(ivl_lpm_t net) -{ - char jbuf [1024]; - unsigned idx; - unsigned nref = 0; - unsigned ha_init = 6; - - edif_uref += 1; - - switch (ivl_lpm_type(net)) { - case IVL_LPM_ADD: - ha_init = 6; - fprintf(xnf, "(comment \"U%u implements %u bit ADD.\")\n", - edif_uref, ivl_lpm_width(net)); - break; - case IVL_LPM_SUB: - ha_init = 9; - fprintf(xnf, "(comment \"U%u implements %u bit SUB.\")\n", - edif_uref, ivl_lpm_width(net)); - break; - default: - assert(0); - } - - /* Handle the special case that the adder is only one bit - wide. Generate an XOR gate to perform the half-add. */ - if (ivl_lpm_width(net) == 1) { - - edif_show_lut2(ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net), edif_uref, - ivl_lpm_q(net, 0), - ivl_lpm_data(net, 0), - ivl_lpm_datab(net, 0), - (ha_init == 6) ? "6" : "9"); + jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1)); + edif_add_to_joint(jnt, lut, LUT_I3); return; - } - - assert(ivl_lpm_width(net) > 1); - - /* First, draw the bottom bit slice of the adder. This - includes the LUT2 device to perform the addition, a - MUXCY_L device to send the carry up to the next bit, - and an XORCY to make the output bit[0]. The latter is not - always needed, but it is free, because the XORCY is this - slice cannot otherwise be used anyhow. */ - fprintf(xnf, "(instance U%u_L0" - " (viewRef net (cellRef LUT2 (libraryRef VIRTEX)))" - " (property INIT (string \"%u\")))\n", - edif_uref, ha_init); - - fprintf(xnf, "(instance (rename U%u_X0 \"%s.%s[0]\")" - " (viewRef net" - " (cellRef XORCY (libraryRef VIRTEX))))\n", - edif_uref, ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net)); - - fprintf(xnf, "(instance U%u_M0", edif_uref); - fprintf(xnf, " (viewRef net" - " (cellRef MUXCY_L (libraryRef VIRTEX))))\n"); - - /* If the device is an ADD, then the CI is set to 0. If the - device is really a SUB, then tie the CI to 1. This adds in - the (+1) of the two's complement. */ - switch (ivl_lpm_type(net)) { - case IVL_LPM_ADD: - fprintf(xnf, "(instance U%u_FILL" - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref); - fprintf(xnf, "(net U%u_FILLN (joined" - " (portRef GROUND (instanceRef U%u_FILL))" - " (portRef CI (instanceRef U%u_M0))" - " (portRef CI (instanceRef U%u_X0))))\n", - edif_uref, edif_uref, edif_uref, edif_uref); - break; - - case IVL_LPM_SUB: - fprintf(xnf, "(instance U%u_FILL" - " (viewRef net" - " (cellRef VCC (libraryRef VIRTEX))))\n", - edif_uref); - fprintf(xnf, "(net U%u_FILLN (joined" - " (portRef VCC (instanceRef U%u_FILL))" - " (portRef CI (instanceRef U%u_M0))" - " (portRef CI (instanceRef U%u_X0))))\n", - edif_uref, edif_uref, edif_uref, edif_uref); - break; default: - assert(0); - } + { 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); + } - sprintf(jbuf, "(portRef I0 (instanceRef U%u_L0))" - " (portRef DI (instanceRef U%u_M0))", - edif_uref, edif_uref); - edif_set_nexus_joint(ivl_lpm_data(net, 0), jbuf); + 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; - sprintf(jbuf, "(portRef I1 (instanceRef U%u_L0))", edif_uref); - edif_set_nexus_joint(ivl_lpm_datab(net, 0), jbuf); - - fprintf(xnf, "(net U%uN%u (joined" - " (portRef O (instanceRef U%u_L0))" - " (portRef S (instanceRef U%u_M0))" - " (portRef LI (instanceRef U%u_X0))))\n", - edif_uref, nref++, edif_uref, edif_uref, edif_uref); - - sprintf(jbuf, "(portRef O (instanceRef U%u_X0))", edif_uref); - edif_set_nexus_joint(ivl_lpm_q(net, 0), jbuf); - - /* Now draw all the inside bit slices. These include the LUT2 - device for the basic add, the MUXCY_L device to propagate - the carry, and an XORCY device to generate the real - output. The XORCY device carries the name of the LPM - device, the other devices have local names. */ - for (idx = 1 ; idx < (ivl_lpm_width(net)-1) ; idx += 1) { - - fprintf(xnf, "(instance U%u_L%u" - " (viewRef net" - " (cellRef LUT2 (libraryRef VIRTEX)))" - " (property INIT (string \"%u\")))\n", - edif_uref, idx, ha_init); - - fprintf(xnf, "(instance U%u_M%u", edif_uref, idx); - fprintf(xnf, " (viewRef net" - " (cellRef MUXCY_L (libraryRef VIRTEX))))\n"); - - fprintf(xnf, "(instance (rename U%u_X%u \"%s.%s[%u]\")" - " (viewRef net" - " (cellRef XORCY (libraryRef VIRTEX))))\n", - edif_uref, idx, - ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net), idx); - - fprintf(xnf, "(net U%uN%u (joined" - " (portRef O (instanceRef U%u_L%u))" - " (portRef S (instanceRef U%u_M%u))" - " (portRef LI (instanceRef U%u_X%u))))\n", - edif_uref, nref++, edif_uref, idx, edif_uref, idx, - edif_uref, idx); - - fprintf(xnf, "(net U%uN%u (joined" - " (portRef CI (instanceRef U%u_M%u))" - " (portRef CI (instanceRef U%u_X%u))" - " (portRef LO (instanceRef U%u_M%u))))\n", - edif_uref, nref++, edif_uref, idx, edif_uref, idx, - edif_uref, idx-1); - - sprintf(jbuf, "(portRef I0 (instanceRef U%u_L%u))" - " (portRef DI (instanceRef U%u_M%u))", - edif_uref, idx, edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_data(net, idx), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%u_L%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_datab(net, idx), jbuf); - - sprintf(jbuf, "(portRef O (instanceRef U%u_X%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_q(net, idx), jbuf); - } - - - fprintf(xnf, "(instance U%u_L%u" - " (viewRef net" - " (cellRef LUT2 (libraryRef VIRTEX)))" - " (property INIT (string \"%u\")))\n", - edif_uref, idx, ha_init); - - fprintf(xnf, "(instance (rename U%u_X%u \"%s.%s[%u]\")", - edif_uref, idx, ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net), idx); - fprintf(xnf, " (viewRef net" - " (cellRef XORCY (libraryRef VIRTEX))))\n"); - - fprintf(xnf, "(net U%uN%u (joined" - " (portRef O (instanceRef U%u_L%u))" - " (portRef LI (instanceRef U%u_X%u))))\n", - edif_uref, nref++, edif_uref, idx, edif_uref, idx); - - fprintf(xnf, "(net U%uN%u (joined" - " (portRef CI (instanceRef U%u_X%u))" - " (portRef LO (instanceRef U%u_M%u))))\n", - edif_uref, nref++, edif_uref, idx, edif_uref, idx-1); - - sprintf(jbuf, "(portRef I0 (instanceRef U%u_L%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_data(net, idx), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%u_L%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_datab(net, idx), jbuf); - - sprintf(jbuf, "(portRef O (instanceRef U%u_X%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_q(net, idx), jbuf); -} - -static void virtex_show_cmp_ge(ivl_lpm_t net) -{ - char jbuf [1024]; - unsigned idx; - unsigned nref = 0; - - /* Handle the special case that the adder is only one bit - wide. Generate an XOR gate to perform the half-add. */ - if (ivl_lpm_width(net) == 1) { - edif_uref += 1; - - edif_show_lut2(ivl_scope_name(ivl_lpm_scope(net)), - ivl_lpm_basename(net), edif_uref, - ivl_lpm_q(net, 0), - ivl_lpm_data(net, 0), - ivl_lpm_datab(net, 0), - "D"); - return; - } - - assert(ivl_lpm_width(net) > 1); - edif_uref += 1; - - /* First, draw the bottom bit slice of the comparator. This - includes the LUT2 device to perform the addition, and a - MUXCY_L device to send the carry up to the next bit. */ - fprintf(xnf, "(instance (rename U%u_L0 \"%s.%s[0]\")" - " (viewRef net" - " (cellRef LUT2 (libraryRef VIRTEX)))" - " (property INIT (string \"9\")))\n", edif_uref, - ivl_scope_name(ivl_lpm_scope(net)), ivl_lpm_basename(net)); - fprintf(xnf, "(instance U%u_M0", edif_uref); - fprintf(xnf, " (viewRef net" - " (cellRef MUXCY_L (libraryRef VIRTEX))))\n"); - - fprintf(xnf, "(net U%uN%u (joined" - " (portRef O (instanceRef U%u_L0))" - " (portRef S (instanceRef U%u_M0))))\n", - edif_uref, nref++, edif_uref, edif_uref); - - sprintf(jbuf, "(portRef I0 (instanceRef U%u_L0))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data(net, 0), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%u_L0))", edif_uref); - edif_set_nexus_joint(ivl_lpm_datab(net, 0), jbuf); - - sprintf(jbuf, "(portRef DI (instanceRef U%u_M0))", edif_uref); - edif_set_nexus_joint(ivl_lpm_data(net, 0), jbuf); - - switch (ivl_lpm_type(net)) { - case IVL_LPM_CMP_GT: - fprintf(xnf, "(instance U%u_FILL " - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref); - fprintf(xnf, "(net U%u_FILLN (joined" - " (portRef GROUND (instanceRef U%u_FILL))" - " (portRef CI (instanceRef U%u_M0))))\n", - edif_uref, edif_uref, edif_uref); - break; - - case IVL_LPM_CMP_GE: - fprintf(xnf, "(instance U%u_FILL " - " (viewRef net" - " (cellRef VCC (libraryRef VIRTEX))))\n", - edif_uref); - fprintf(xnf, "(net U%u_FILLN (joined" - " (portRef VCC (instanceRef U%u_FILL))" - " (portRef CI (instanceRef U%u_M0))))\n", - edif_uref, edif_uref, edif_uref); - break; - - default: - assert(0); - } - - /* Now draw all the inside bit slices. These include the LUT2 - device for the NOR2 and the MUXCY_L device to propagate - the result. */ - for (idx = 1 ; idx < (ivl_lpm_width(net)) ; idx += 1) { - - fprintf(xnf, "(instance U%u_L%u" - " (viewRef net" - " (cellRef LUT2 (libraryRef VIRTEX)))" - " (property INIT (string \"9\")))\n", - edif_uref, idx); - - fprintf(xnf, "(instance U%u_M%u", edif_uref, idx); - fprintf(xnf, " (viewRef net" - " (cellRef MUXCY_L (libraryRef VIRTEX))))\n"); - - fprintf(xnf, "(net U%uN%u (joined" - " (portRef O (instanceRef U%u_L%u))" - " (portRef S (instanceRef U%u_M%u))))\n", - edif_uref, nref++, edif_uref, idx, edif_uref, idx); - - fprintf(xnf, "(net U%uN%u (joined" - " (portRef CI (instanceRef U%u_M%u))" - " (portRef LO (instanceRef U%u_M%u))))\n", - edif_uref, nref++, edif_uref, idx, edif_uref, idx-1); - - sprintf(jbuf, "(portRef I0 (instanceRef U%u_L%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_data(net, idx), jbuf); - - sprintf(jbuf, "(portRef I1 (instanceRef U%u_L%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_datab(net, idx), jbuf); - - sprintf(jbuf, "(portRef DI (instanceRef U%u_M%u))", - edif_uref, idx); - edif_set_nexus_joint(ivl_lpm_data(net, idx), jbuf); - - } - - - sprintf(jbuf, "(portRef LO (instanceRef U%u_M%u))", - edif_uref, idx-1); - edif_set_nexus_joint(ivl_lpm_q(net, 0), jbuf); -} - -/* - * 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 virtex_show_shiftl(ivl_lpm_t net) -{ - char jbuf[64]; - unsigned width = ivl_lpm_width(net); - unsigned nsel = 0, swid = 0; - unsigned sdx, qdx; - - edif_uref += 1; - - /* 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); - - /* Draw the gates of the matrix, and connect the select inputs - up the columns. Column 0 is the first to see the input - data, so it gets select[0], and so on. */ - for (sdx = 0 ; sdx < nsel ; sdx += 1) { - unsigned lutn = 3; - - if ( (sdx == (nsel-1)) && (nsel < ivl_lpm_selects(net))) - lutn = 4; - - for (qdx = 0 ; qdx < width ; qdx += 1) { - - fprintf(xnf, "(instance U%uC%uR%u" - " (viewRef net" - " (cellRef LUT%u (libraryRef VIRTEX)))" - " (property INIT (string \"CA\")))\n", - edif_uref, sdx, qdx, lutn); - - sprintf(jbuf, "(portRef I2 (instanceRef U%uC%uR%u))", - edif_uref, sdx, qdx); - - edif_set_nexus_joint(ivl_lpm_select(net, sdx), jbuf); - - /* If this is the last column, and there are - excess selects to account for, then connect the - I3 inputs of the LUT4 devices to the excess - select, to act as an enable. */ - if (lutn == 4) { - assert((nsel + 1) == ivl_lpm_selects(net)); - sprintf(jbuf, "(portRef I3 (instanceRef U%uC%uR%u))", - edif_uref, sdx, qdx); - edif_set_nexus_joint(ivl_lpm_select(net, nsel), jbuf); + 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; } - /* Connect the output of the matrix to the outputs of the - shiftl. */ - for (qdx = 0 ; qdx < width ; qdx += 1) { + /* 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: - sprintf(jbuf, "(portRef O (instanceRef U%uC%uR%u))", - edif_uref, nsel-1, qdx); + 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 - edif_set_nexus_joint(ivl_lpm_q(net, qdx), jbuf); + 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; } - /* Connect the input of the matrix to the inputs of the - shiftl. The B inputs of the input column MUXes also get the - inputs shifted up 1. */ - for (qdx = 0 ; qdx < width ; qdx += 1) { + /* The general case requires that we make the >= comparator + from slices. This is an iterative design. Each slice has + the truth table: - sprintf(jbuf, "(portRef I0 (instanceRef U%uC%uR%u))", - edif_uref, 0, qdx); + An Bn | A >= B + ------+------- + 0 0 | CI + 0 1 | 0 + 1 0 | 1 + 1 1 | CI - edif_set_nexus_joint(ivl_lpm_data(net, qdx), jbuf); + 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). - if (qdx < (width-1)) { - sprintf(jbuf, "(portRef I1 (instanceRef U%uC%uR%u))", - edif_uref, 0, qdx+1); - edif_set_nexus_joint(ivl_lpm_data(net, qdx), jbuf); - } + 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); } - /* Connect the B side 0 padding to the input column. */ - fprintf(xnf, "(instance U%uC%uP" - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref, 0); - fprintf(xnf, "(net U%uC0PN (joined" - " (portRef I1 (instanceRef U%uC0R0))" - " (portRef GROUND (instanceRef U%uC0P))))\n", - edif_uref, edif_uref, edif_uref); + for (idx = 2 ; idx < ivl_lpm_width(net) ; idx += 1) { + edif_cellref_t muxcy; - /* Connect the sdx column outputs to the sdx+1 column - inputs. This includes the A side which is straight - through, and the B side which is shifted based on the - selector identity. */ - for (sdx = 0 ; sdx < (nsel-1) ; sdx += 1) { - unsigned shift = 2 << sdx; + lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); + muxcy = edif_cellref_create(edf, xilinx_cell_muxcy(xlib)); + edif_cellref_pstring(lut, "INIT", "9"); - for (qdx = 0 ; qdx < (width-shift) ; qdx += 1) { - fprintf(xnf, "(net U%uC%uR%uN (joined" - " (portRef O (instanceRef U%uC%uR%u))" - " (portRef I0 (instanceRef U%uC%uR%u))" - " (portRef I1 (instanceRef U%uC%uR%u))))\n", - edif_uref, sdx, qdx, - edif_uref, sdx, qdx, - edif_uref, sdx+1, qdx, - edif_uref, sdx+1, qdx + shift); - } + jnt = edif_joint_create(edf); + edif_add_to_joint(jnt, lut, LUT_O); + edif_add_to_joint(jnt, muxcy, MUXCY_S); - for (qdx = (width-shift) ; qdx < width ; qdx += 1) { - fprintf(xnf, "(net U%uC%uR%uN (joined" - " (portRef O (instanceRef U%uC%uR%u))" - " (portRef I0 (instanceRef U%uC%uR%u))))\n", - edif_uref, sdx, qdx, - edif_uref, sdx, qdx, - edif_uref, sdx+1, qdx); + jnt = edif_joint_create(edf); + edif_add_to_joint(jnt, muxcy, MUXCY_CI); + edif_add_to_joint(jnt, muxcy_prev, MUXCY_O); - fprintf(xnf, "(instance U%uC%uR%uG" - " (viewRef net" - " (cellRef GND (libraryRef VIRTEX))))\n", - edif_uref, sdx+1, qdx); + 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); - fprintf(xnf, "(net U%uC%uR%uGN (joined" - " (portRef I1 (instanceRef U%uC%uR%u))" - " (portRef GROUND (instanceRef U%uC%uR%uG))))\n", - edif_uref, sdx+1, qdx, - edif_uref, sdx+1, (qdx+shift)%width, - edif_uref, sdx+1, qdx); - } + 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); +} + +/* + * 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 = { - edif_show_header, - edif_show_footer, - 0, /* show_scope not implemented */ - edif_show_virtex_pad, - edif_show_virtex_logic, - edif_show_generic_dff, - edif_show_virtex_eq, - edif_show_virtex_eq, - virtex_show_cmp_ge, - edif_show_virtex_mux, - edif_show_virtex_add, - edif_show_virtex_add, - virtex_show_shiftl, + virtex_show_header, + virtex_show_footer, + xilinx_show_scope, + xilinx_pad, + xilinx_logic, + virtex_generic_dff, + virtex_eq, + virtex_eq, + virtex_ge, + 0, + virtex_add, + virtex_add, + xilinx_shiftl, 0 /* show_shiftr */ }; /* * $Log: d-virtex.c,v $ + * Revision 1.25 2003/06/25 02:55:57 steve + * Virtex and Virtex2 share much code. + * * Revision 1.24 2003/06/25 01:49:06 steve * Spelling fixes. * @@ -1949,47 +691,5 @@ const struct device_s d_virtex_edif = { * * Revision 1.22 2003/02/26 01:24:42 steve * ivl_lpm_name is obsolete. - * - * Revision 1.21 2002/11/24 02:26:14 steve - * Fix instanceRef spelling. - * - * Revision 1.20 2002/11/22 05:46:06 steve - * Handle wide AND/NOR devices with Virtex carry logic. - * - * Revision 1.19 2002/11/22 01:45:40 steve - * Implement bufif1 as BUFT - * - * Revision 1.18 2002/11/01 02:36:34 steve - * Fix bottom bit of ADD/SUB device. - * - * Revision 1.17 2002/10/30 03:58:45 steve - * Fix up left shift to pass compile, - * fix up ADD/SUB to generate missing pieces, - * Add the asynch set/reset to DFF devices. - * - * Revision 1.16 2002/10/28 02:05:56 steve - * Add Virtex code generators for left shift, - * subtraction, and GE comparators. - * - * Revision 1.15 2002/09/15 21:52:19 steve - * Generate code for 8:1 muxes msing F5 and F6 muxes. - * - * Revision 1.14 2002/09/14 05:19:19 steve - * Generate Virtex code for 4:1 mux slices. - * - * Revision 1.13 2002/08/12 01:35:02 steve - * conditional ident string using autoconfig. - * - * Revision 1.12 2002/08/11 23:47:04 steve - * Add missing Log and Ident strings. - * - * Revision 1.11 2001/10/11 00:12:28 steve - * Generate BUF devices for bufz logic. - * - * Revision 1.10 2001/09/16 22:26:47 steve - * Support the cellref attribute. - * - * Revision 1.9 2001/09/16 01:48:16 steve - * Suppor the PAD attribute on signals. */ diff --git a/tgt-fpga/d-virtex2.c b/tgt-fpga/d-virtex2.c index dcf031472..932e0775d 100644 --- a/tgt-fpga/d-virtex2.c +++ b/tgt-fpga/d-virtex2.c @@ -17,12 +17,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: d-virtex2.c,v 1.13 2003/06/25 01:49:06 steve Exp $" +#ident "$Id: d-virtex2.c,v 1.14 2003/06/25 02:55:57 steve Exp $" #endif # include "device.h" # include "fpga_priv.h" # include "edif.h" +# include "generic.h" # include "xilinx.h" # include # include @@ -32,23 +33,6 @@ # 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_ipad = 0; -static edif_cell_t cell_opad = 0; - /* * This is a table of cell types that are accessible via the cellref * attribute to a gate. @@ -147,998 +131,29 @@ static void virtex2_show_header(ivl_design_t des) } -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); -} - -/* - * Make (or retrieve) a cell in the external library that reflects the - * scope with its ports. - */ -static void virtex2_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); - } -} - -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; - - 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; - - 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 lut_logic(ivl_net_logic_t net, const char*init3, - const char*init4, const char*init5) -{ - edif_cellref_t lut; - edif_joint_t jnt; - const char* init; - - 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); -} - -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); - - 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_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; - } -} - -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')) { - obj = edif_cellref_create(edf, xilinx_cell_fdcpe(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); - } - - 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; - - - /* 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); -} - -/* - * 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) { - - 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(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); - } - -} - -/* - * 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. - */ -static 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. - */ -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. */ - - 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); -} - const struct device_s d_virtex2_edif = { virtex2_show_header, - virtex2_show_footer, - virtex2_show_scope, - virtex2_pad, - virtex2_logic, - virtex2_generic_dff, + virtex_show_footer, + xilinx_show_scope, + xilinx_pad, + xilinx_logic, + virtex_generic_dff, virtex_eq, virtex_eq, - virtex2_cmp_ge, + virtex_ge, 0, - virtex2_add, - virtex2_add, - virtex2_show_shiftl, /* show_shiftl */ + virtex_add, + virtex_add, + xilinx_shiftl, /* show_shiftl */ 0 /* show_shiftr */ }; /* * $Log: d-virtex2.c,v $ + * Revision 1.14 2003/06/25 02:55:57 steve + * Virtex and Virtex2 share much code. + * * Revision 1.13 2003/06/25 01:49:06 steve * Spelling fixes. * @@ -1147,37 +162,5 @@ const struct device_s d_virtex2_edif = { * * Revision 1.11 2003/06/24 03:55:00 steve * Add ivl_synthesis_cell support for virtex2. - * - * Revision 1.10 2003/04/05 05:53:34 steve - * Move library cell management to common file. - * - * Revision 1.9 2003/04/05 01:35:40 steve - * Fix LUT function for chained NE. - * - * Revision 1.8 2003/04/04 06:20:29 steve - * Add == and some lut logic. - * - * Revision 1.7 2003/04/04 04:59:03 steve - * Add xlibrary celltable. - * - * Revision 1.6 2003/03/31 01:34:19 steve - * Wide shift of MUX was wrong. - * - * Revision 1.5 2003/03/31 00:25:19 steve - * Fix wrong input constant to bottom of GE. - * - * Revision 1.4 2003/03/31 00:04:21 steve - * Proper sliced >= comparator. - * - * Revision 1.3 2003/03/30 03:43:44 steve - * Handle wide ports of macros. - * - * Revision 1.2 2003/03/24 02:29:04 steve - * Give proper basenames to PAD signals. - * - * 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/generic.c b/tgt-fpga/generic.c new file mode 100644 index 000000000..75e54e992 --- /dev/null +++ b/tgt-fpga/generic.c @@ -0,0 +1,41 @@ +/* + * 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 + */ +#ifndef HAVE_CVS_IDENT +#ident "$Id: generic.c,v 1.1 2003/06/25 02:55:57 steve Exp $" +#endif + +# include "generic.h" + +edif_t edf = 0; +edif_xlibrary_t xlib = 0; + +edif_cell_t cell_0 = 0; +edif_cell_t cell_1 = 0; + +edif_cell_t cell_ipad = 0; +edif_cell_t cell_opad = 0; + + +/* + * $Log: generic.c,v $ + * Revision 1.1 2003/06/25 02:55:57 steve + * Virtex and Virtex2 share much code. + * + */ + diff --git a/tgt-fpga/generic.h b/tgt-fpga/generic.h new file mode 100644 index 000000000..d0fd12447 --- /dev/null +++ b/tgt-fpga/generic.h @@ -0,0 +1,51 @@ +#ifndef __generic_H +#define __generic_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 + */ +#ifndef HAVE_CVS_IDENT +#ident "$Id: generic.h,v 1.1 2003/06/25 02:55:57 steve Exp $" +#endif + +# include "edif.h" + +extern edif_t edf; +extern edif_xlibrary_t xlib; + +/* + * 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. + */ + +extern edif_cell_t cell_0; +extern edif_cell_t cell_1; + +extern edif_cell_t cell_ipad; +extern edif_cell_t cell_opad; + + +/* + * $Log: generic.h,v $ + * Revision 1.1 2003/06/25 02:55:57 steve + * Virtex and Virtex2 share much code. + * + */ +#endif diff --git a/tgt-fpga/xilinx.c b/tgt-fpga/xilinx.c index e45635cf1..3219c0a19 100644 --- a/tgt-fpga/xilinx.c +++ b/tgt-fpga/xilinx.c @@ -17,10 +17,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: xilinx.c,v 1.1 2003/04/05 05:53:34 steve Exp $" +#ident "$Id: xilinx.c,v 1.2 2003/06/25 02:55:57 steve Exp $" #endif +# 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) { @@ -198,10 +206,485 @@ edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib) return cell; } +/* + * 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; + 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; + + 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; + + 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 lut_logic(ivl_net_logic_t net, const char*init3, + const char*init4, const char*init5) +{ + edif_cellref_t lut; + edif_joint_t jnt; + const char* init; + + 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_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; + } +} + +/* + * 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.2 2003/06/25 02:55:57 steve + * Virtex and Virtex2 share much code. + * * Revision 1.1 2003/04/05 05:53:34 steve * Move library cell management to common file. * diff --git a/tgt-fpga/xilinx.h b/tgt-fpga/xilinx.h index 8fd48fac9..04fb29dee 100644 --- a/tgt-fpga/xilinx.h +++ b/tgt-fpga/xilinx.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: xilinx.h,v 1.1 2003/04/05 05:53:34 steve Exp $" +#ident "$Id: xilinx.h,v 1.2 2003/06/25 02:55:57 steve Exp $" #endif /* @@ -93,8 +93,25 @@ extern edif_cell_t xilinx_cell_xorcy(edif_xlibrary_t xlib); #define XORCY_CI 1 #define XORCY_LI 2 +/* === Inheritable Methods === */ + +extern void virtex_show_footer(ivl_design_t des); +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_add(ivl_lpm_t net); + +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_add(ivl_lpm_t net); +extern void xilinx_shiftl(ivl_lpm_t net); + /* * $Log: xilinx.h,v $ + * Revision 1.2 2003/06/25 02:55:57 steve + * Virtex and Virtex2 share much code. + * * Revision 1.1 2003/04/05 05:53:34 steve * Move library cell management to common file. *