2003-03-24 01:47:54 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
|
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
|
|
|
|
#ifdef HAVE_CVS_IDENT
|
2003-04-04 06:59:03 +02:00
|
|
|
#ident "$Id: d-virtex2.c,v 1.7 2003/04/04 04:59:03 steve Exp $"
|
2003-03-24 01:47:54 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# include "device.h"
|
|
|
|
|
# include "fpga_priv.h"
|
|
|
|
|
# include "edif.h"
|
|
|
|
|
# include <stdlib.h>
|
|
|
|
|
# include <string.h>
|
|
|
|
|
#ifdef HAVE_MALLOC_H
|
|
|
|
|
# include <malloc.h>
|
|
|
|
|
#endif
|
|
|
|
|
# include <assert.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static edif_t edf = 0;
|
|
|
|
|
static edif_xlibrary_t xlib = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The cell_* variables below are the various kinds of devices that
|
|
|
|
|
* this family supports as primitives. If the cell type is used at
|
|
|
|
|
* least once, then the edif_cell_t is non-zero and will also be
|
|
|
|
|
* included in the library declaration. The constants underneath are
|
|
|
|
|
* pin assignments for the cell.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static edif_cell_t cell_0 = 0;
|
|
|
|
|
static edif_cell_t cell_1 = 0;
|
|
|
|
|
|
|
|
|
|
static edif_cell_t cell_fdce = 0;
|
|
|
|
|
static edif_cell_t cell_fdcpe = 0;
|
|
|
|
|
const unsigned FDCE_Q = 0;
|
|
|
|
|
const unsigned FDCE_C = 1;
|
|
|
|
|
const unsigned FDCE_D = 2;
|
|
|
|
|
const unsigned FDCE_CE = 3;
|
|
|
|
|
const unsigned FDCE_CLR = 4;
|
|
|
|
|
const unsigned FDCE_PRE = 5;
|
|
|
|
|
|
|
|
|
|
static edif_cell_t cell_ipad = 0;
|
|
|
|
|
static edif_cell_t cell_opad = 0;
|
|
|
|
|
|
|
|
|
|
static edif_cell_t cell_buf = 0;
|
|
|
|
|
static edif_cell_t cell_inv = 0;
|
|
|
|
|
static edif_cell_t cell_ibuf = 0;
|
|
|
|
|
static edif_cell_t cell_obuf = 0;
|
|
|
|
|
const unsigned BUF_O = 0;
|
|
|
|
|
const unsigned BUF_I = 1;
|
|
|
|
|
|
|
|
|
|
static edif_cell_t cell_lut2 = 0;
|
|
|
|
|
static edif_cell_t cell_lut3 = 0;
|
|
|
|
|
static edif_cell_t cell_lut4 = 0;
|
|
|
|
|
const unsigned LUT_O = 0;
|
|
|
|
|
const unsigned LUT_I0 = 1;
|
|
|
|
|
const unsigned LUT_I1 = 2;
|
|
|
|
|
const unsigned LUT_I2 = 3;
|
|
|
|
|
const unsigned LUT_I3 = 4;
|
|
|
|
|
|
|
|
|
|
static edif_cell_t cell_muxcy = 0;
|
|
|
|
|
static edif_cell_t cell_muxcy_l = 0;
|
|
|
|
|
const unsigned MUXCY_O = 0;
|
|
|
|
|
const unsigned MUXCY_DI = 1;
|
|
|
|
|
const unsigned MUXCY_CI = 2;
|
|
|
|
|
const unsigned MUXCY_S = 3;
|
|
|
|
|
|
|
|
|
|
static edif_cell_t cell_xorcy = 0;
|
|
|
|
|
const unsigned XORCY_O = 0;
|
|
|
|
|
const unsigned XORCY_CI = 1;
|
|
|
|
|
const unsigned XORCY_LI = 2;
|
|
|
|
|
|
|
|
|
|
const unsigned MULT_AND_LO = 0;
|
|
|
|
|
const unsigned MULT_AND_I0 = 1;
|
|
|
|
|
const unsigned MULT_AND_I1 = 2;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The check_cell_* functions can be called in front of any reference
|
|
|
|
|
* to the matching cell_* variable to make sure the cell type has been
|
|
|
|
|
* created. By creating the cell type only when it is needed, we
|
|
|
|
|
* reduce the size of the library declaration, and also better support
|
|
|
|
|
* cross-family code sharing.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void check_cell_fdce(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_fdce != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_fdce = edif_xcell_create(xlib, "FDCE", 5);
|
|
|
|
|
edif_cell_portconfig(cell_fdce, FDCE_Q, "Q", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_fdce, FDCE_D, "D", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_fdce, FDCE_C, "C", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_fdce, FDCE_CE, "CE", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_fdce, FDCE_CLR,"CLR", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_fdcpe(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_fdcpe != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_fdcpe = edif_xcell_create(xlib, "FDCPE", 6);
|
|
|
|
|
edif_cell_portconfig(cell_fdcpe, FDCE_Q, "Q", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_fdcpe, FDCE_D, "D", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_fdcpe, FDCE_C, "C", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_fdcpe, FDCE_CE, "CE", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_fdcpe, FDCE_CLR,"CLR", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_fdcpe, FDCE_PRE,"PRE", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_buf(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_buf != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_buf = edif_xcell_create(xlib, "BUF", 2);
|
|
|
|
|
edif_cell_portconfig(cell_buf, BUF_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_buf, BUF_I, "I", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_inv(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_inv != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_inv = edif_xcell_create(xlib, "INV", 2);
|
|
|
|
|
edif_cell_portconfig(cell_inv, BUF_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_inv, BUF_I, "I", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_ibuf(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_ibuf != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_ibuf = edif_xcell_create(xlib, "IBUF", 2);
|
|
|
|
|
edif_cell_portconfig(cell_ibuf, BUF_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_ibuf, BUF_I, "I", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_obuf(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_obuf != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_obuf = edif_xcell_create(xlib, "OBUF", 2);
|
|
|
|
|
edif_cell_portconfig(cell_obuf, BUF_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_obuf, BUF_I, "I", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_lut2(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_lut2 != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_lut2 = edif_xcell_create(xlib, "LUT2", 3);
|
|
|
|
|
edif_cell_portconfig(cell_lut2, LUT_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_lut2, LUT_I0, "I0", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_lut2, LUT_I1, "I1", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_lut3(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_lut3 != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_lut3 = edif_xcell_create(xlib, "LUT3", 4);
|
|
|
|
|
edif_cell_portconfig(cell_lut3, LUT_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_lut3, LUT_I0, "I0", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_lut3, LUT_I1, "I1", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_lut3, LUT_I2, "I2", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_lut4(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_lut4 != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_lut4 = edif_xcell_create(xlib, "LUT4", 5);
|
|
|
|
|
edif_cell_portconfig(cell_lut4, LUT_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_lut4, LUT_I0, "I0", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_lut4, LUT_I1, "I1", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_lut4, LUT_I2, "I2", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_lut4, LUT_I3, "I3", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_muxcy(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_muxcy != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_muxcy = edif_xcell_create(xlib, "MUXCY", 4);
|
|
|
|
|
edif_cell_portconfig(cell_muxcy, MUXCY_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_muxcy, MUXCY_DI, "DI", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_muxcy, MUXCY_CI, "CI", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_muxcy, MUXCY_S, "S", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_muxcy_l(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_muxcy_l != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_muxcy_l = edif_xcell_create(xlib, "MUXCY_L", 4);
|
|
|
|
|
edif_cell_portconfig(cell_muxcy_l, MUXCY_O, "LO", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_muxcy_l, MUXCY_DI, "DI", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_muxcy_l, MUXCY_CI, "CI", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_muxcy_l, MUXCY_S, "S", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void check_cell_xorcy(void)
|
|
|
|
|
{
|
|
|
|
|
if (cell_xorcy != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cell_xorcy = edif_xcell_create(xlib, "XORCY", 3);
|
|
|
|
|
edif_cell_portconfig(cell_xorcy, XORCY_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell_xorcy, XORCY_CI, "CI", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell_xorcy, XORCY_LI, "LI", IVL_SIP_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-04 06:59:03 +02:00
|
|
|
|
|
|
|
|
static edif_cell_t celltable_mult_and(edif_xlibrary_t xlib)
|
2003-03-24 01:47:54 +01:00
|
|
|
{
|
2003-04-04 06:59:03 +02:00
|
|
|
edif_cell_t cell = edif_xcell_create(xlib, "MULT_AND", 3);
|
|
|
|
|
edif_cell_portconfig(cell, MULT_AND_LO, "LO", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell, MULT_AND_I0, "I0", IVL_SIP_INPUT);
|
|
|
|
|
edif_cell_portconfig(cell, MULT_AND_I1, "I1", IVL_SIP_INPUT);
|
|
|
|
|
return cell;
|
|
|
|
|
}
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-04-04 06:59:03 +02:00
|
|
|
static edif_cell_t celltable_bufg(edif_xlibrary_t xlib)
|
|
|
|
|
{
|
|
|
|
|
edif_cell_t cell = edif_xcell_create(xlib, "BUFG", 2);
|
|
|
|
|
edif_cell_portconfig(cell, BUF_O, "O", IVL_SIP_OUTPUT);
|
|
|
|
|
edif_cell_portconfig(cell, BUF_I, "I", IVL_SIP_INPUT);
|
|
|
|
|
return cell;
|
2003-03-24 01:47:54 +01:00
|
|
|
}
|
|
|
|
|
|
2003-04-04 06:59:03 +02:00
|
|
|
const static struct edif_xlib_celltable virtex2_celltable[] = {
|
|
|
|
|
{ "BUFG", celltable_bufg },
|
|
|
|
|
{ "MULT_AND", celltable_mult_and },
|
|
|
|
|
{ 0, 0}
|
|
|
|
|
};
|
|
|
|
|
|
2003-03-24 01:47:54 +01:00
|
|
|
/*
|
|
|
|
|
* The show_header function is called before any of the devices of the
|
|
|
|
|
* netlist are scanned.
|
|
|
|
|
*
|
|
|
|
|
* In this function, we look at the ports of the root module to decide
|
|
|
|
|
* if they are to be made into ports. Modules that have PAD attributes
|
|
|
|
|
* are *not* to be used as ports, they will be connected to special
|
|
|
|
|
* PAD devices instead.
|
|
|
|
|
*/
|
|
|
|
|
static void virtex2_show_header(ivl_design_t des)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
ivl_scope_t root = ivl_design_root(des);
|
|
|
|
|
unsigned sig_cnt = ivl_scope_sigs(root);
|
|
|
|
|
unsigned nports = 0, pidx;
|
2003-03-24 03:29:04 +01:00
|
|
|
const char*part_str = 0;
|
2003-03-24 01:47:54 +01:00
|
|
|
|
|
|
|
|
/* Count the ports I'm going to use. */
|
|
|
|
|
for (idx = 0 ; idx < sig_cnt ; idx += 1) {
|
|
|
|
|
ivl_signal_t sig = ivl_scope_sig(root, idx);
|
|
|
|
|
|
|
|
|
|
if (ivl_signal_port(sig) == IVL_SIP_NONE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (ivl_signal_attr(sig, "PAD") != 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
nports += ivl_signal_pins(sig);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edf = edif_create(ivl_scope_basename(root), nports);
|
|
|
|
|
|
|
|
|
|
pidx = 0;
|
|
|
|
|
for (idx = 0 ; idx < sig_cnt ; idx += 1) {
|
|
|
|
|
edif_joint_t jnt;
|
|
|
|
|
ivl_signal_t sig = ivl_scope_sig(root, idx);
|
|
|
|
|
|
|
|
|
|
if (ivl_signal_port(sig) == IVL_SIP_NONE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (ivl_signal_attr(sig, "PAD") != 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-03-30 05:43:44 +02:00
|
|
|
if (ivl_signal_pins(sig) == 1) {
|
|
|
|
|
edif_portconfig(edf, pidx, ivl_signal_basename(sig),
|
|
|
|
|
ivl_signal_port(sig));
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-30 05:43:44 +02:00
|
|
|
assert(ivl_signal_pins(sig) == 1);
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, 0));
|
|
|
|
|
edif_port_to_joint(jnt, edf, pidx);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
const char*name = ivl_signal_basename(sig);
|
|
|
|
|
ivl_signal_port_t dir = ivl_signal_port(sig);
|
|
|
|
|
char buf[128];
|
|
|
|
|
unsigned bit;
|
|
|
|
|
for (bit = 0 ; bit < ivl_signal_pins(sig) ; bit += 1) {
|
|
|
|
|
const char*tmp;
|
|
|
|
|
sprintf(buf, "%s[%u]", name, bit);
|
|
|
|
|
tmp = strdup(buf);
|
|
|
|
|
edif_portconfig(edf, pidx+bit, tmp, dir);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf,ivl_signal_pin(sig,bit));
|
|
|
|
|
edif_port_to_joint(jnt, edf, pidx+bit);
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-03-24 01:47:54 +01:00
|
|
|
|
|
|
|
|
pidx += ivl_signal_pins(sig);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(pidx == nports);
|
|
|
|
|
|
|
|
|
|
xlib = edif_xlibrary_create(edf, "VIRTEX2");
|
2003-04-04 06:59:03 +02:00
|
|
|
edif_xlibrary_set_celltable(xlib, virtex2_celltable);
|
|
|
|
|
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-24 03:29:04 +01:00
|
|
|
if ( (part_str = ivl_design_flag(des, "part")) && (part_str[0] != 0) ) {
|
|
|
|
|
edif_pstring(edf, "PART", part_str);
|
2003-03-24 01:47:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cell_0 = edif_xcell_create(xlib, "GND", 1);
|
|
|
|
|
edif_cell_portconfig(cell_0, 0, "GROUND", IVL_SIP_OUTPUT);
|
|
|
|
|
|
|
|
|
|
cell_1 = edif_xcell_create(xlib, "VCC", 1);
|
|
|
|
|
edif_cell_portconfig(cell_1, 0, "VCC", IVL_SIP_OUTPUT);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void virtex2_show_footer(ivl_design_t des)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < ivl_design_consts(des) ; idx += 1) {
|
|
|
|
|
unsigned pin;
|
|
|
|
|
ivl_net_const_t net = ivl_design_const(des, idx);
|
|
|
|
|
const char*val = ivl_const_bits(net);
|
|
|
|
|
|
|
|
|
|
for (pin = 0 ; pin < ivl_const_pins(net) ; pin += 1) {
|
|
|
|
|
edif_joint_t jnt;
|
|
|
|
|
edif_cellref_t pad;
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_const_pin(net, pin));
|
|
|
|
|
switch (val[pin]) {
|
|
|
|
|
case '0':
|
|
|
|
|
pad = edif_cellref_create(edf, cell_0);
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
pad = edif_cellref_create(edf, cell_1);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edif_add_to_joint(jnt, pad, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edif_print(xnf, edf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void virtex2_pad(ivl_signal_t sig, const char*str)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
unsigned*pins;
|
|
|
|
|
|
|
|
|
|
if (cell_ipad == 0) {
|
|
|
|
|
cell_ipad = edif_xcell_create(xlib, "IPAD", 1);
|
|
|
|
|
edif_cell_portconfig(cell_ipad, 0, "IPAD", IVL_SIP_OUTPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cell_opad == 0) {
|
|
|
|
|
cell_opad = edif_xcell_create(xlib, "OPAD", 1);
|
|
|
|
|
edif_cell_portconfig(cell_opad, 0, "OPAD", IVL_SIP_OUTPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Collect an array of pin assignments from the attribute
|
|
|
|
|
string passed in as str. The format is a comma separated
|
|
|
|
|
list of unsigned decimal integers. */
|
|
|
|
|
pins = calloc(ivl_signal_pins(sig), sizeof(unsigned));
|
|
|
|
|
for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) {
|
|
|
|
|
char*tmp;
|
|
|
|
|
pins[idx] = strtoul(str, &tmp, 10);
|
|
|
|
|
switch (*tmp) {
|
|
|
|
|
case ',':
|
|
|
|
|
tmp += 1;
|
|
|
|
|
break;
|
|
|
|
|
case 0:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now go through the pins of the signal, creating pads and
|
|
|
|
|
bufs and joining them to the signal nexus. */
|
|
|
|
|
for (idx = 0 ; idx < ivl_signal_pins(sig) ; idx += 1) {
|
|
|
|
|
edif_joint_t jnt;
|
|
|
|
|
edif_cellref_t pad, buf;
|
|
|
|
|
|
2003-03-24 03:29:04 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-24 01:47:54 +01:00
|
|
|
switch (ivl_signal_port(sig)) {
|
|
|
|
|
case IVL_SIP_INPUT:
|
|
|
|
|
check_cell_ibuf();
|
|
|
|
|
pad = edif_cellref_create(edf, cell_ipad);
|
|
|
|
|
buf = edif_cellref_create(edf, cell_ibuf);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_create(edf);
|
2003-03-24 03:29:04 +01:00
|
|
|
edif_joint_rename(jnt, name_str);
|
2003-03-24 01:47:54 +01:00
|
|
|
edif_add_to_joint(jnt, pad, 0);
|
|
|
|
|
edif_add_to_joint(jnt, buf, BUF_I);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx));
|
|
|
|
|
edif_add_to_joint(jnt, buf, BUF_O);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_SIP_OUTPUT:
|
|
|
|
|
check_cell_obuf();
|
|
|
|
|
pad = edif_cellref_create(edf, cell_opad);
|
|
|
|
|
buf = edif_cellref_create(edf, cell_obuf);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_create(edf);
|
2003-03-24 03:29:04 +01:00
|
|
|
edif_joint_rename(jnt, name_str);
|
2003-03-24 01:47:54 +01:00
|
|
|
edif_add_to_joint(jnt, pad, 0);
|
|
|
|
|
edif_add_to_joint(jnt, buf, BUF_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_signal_pin(sig, idx));
|
|
|
|
|
edif_add_to_joint(jnt, buf, BUF_I);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(pins);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function handles the case where the user specifies the cell to
|
|
|
|
|
* use by attribute.
|
|
|
|
|
*/
|
|
|
|
|
static void edif_cellref_logic(ivl_net_logic_t net, const char*def)
|
|
|
|
|
{
|
|
|
|
|
char*str = strdup(def);
|
|
|
|
|
char*pins;
|
|
|
|
|
edif_cell_t cell;
|
|
|
|
|
edif_cellref_t ref;
|
|
|
|
|
edif_joint_t jnt;
|
|
|
|
|
unsigned idx, port;
|
|
|
|
|
|
|
|
|
|
pins = strchr(str, ':');
|
|
|
|
|
assert(pins);
|
|
|
|
|
*pins++ = 0;
|
|
|
|
|
|
|
|
|
|
/* Locate the cell in the library, lookup by name. */
|
|
|
|
|
cell = edif_xlibrary_findcell(xlib, str);
|
|
|
|
|
assert(cell);
|
|
|
|
|
|
|
|
|
|
ref = edif_cellref_create(edf, cell);
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < ivl_logic_pins(net) ; idx += 1) {
|
|
|
|
|
char*tmp;
|
|
|
|
|
|
|
|
|
|
assert(pins);
|
|
|
|
|
tmp = strchr(pins,',');
|
|
|
|
|
if (tmp != 0)
|
|
|
|
|
*tmp++ = 0;
|
|
|
|
|
else
|
|
|
|
|
tmp = 0;
|
|
|
|
|
|
|
|
|
|
port = edif_cell_port_byname(cell, pins);
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx));
|
|
|
|
|
edif_add_to_joint(jnt, ref, port);
|
|
|
|
|
|
|
|
|
|
pins = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(str);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void virtex2_logic(ivl_net_logic_t net)
|
|
|
|
|
{
|
|
|
|
|
edif_cellref_t obj;
|
|
|
|
|
edif_joint_t jnt;
|
|
|
|
|
|
|
|
|
|
{ const char*cellref_attribute = ivl_logic_attr(net, "cellref");
|
|
|
|
|
if (cellref_attribute != 0) {
|
|
|
|
|
edif_cellref_logic(net, cellref_attribute);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (ivl_logic_type(net)) {
|
|
|
|
|
|
|
|
|
|
case IVL_LO_BUF:
|
|
|
|
|
case IVL_LO_BUFZ:
|
|
|
|
|
assert(ivl_logic_pins(net) == 2);
|
|
|
|
|
check_cell_buf();
|
|
|
|
|
|
|
|
|
|
obj = edif_cellref_create(edf, cell_buf);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, obj, BUF_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
|
|
|
|
|
edif_add_to_joint(jnt, obj, BUF_I);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_LO_OR:
|
|
|
|
|
assert(ivl_logic_pins(net) <= 5);
|
|
|
|
|
assert(ivl_logic_pins(net) >= 3);
|
|
|
|
|
|
|
|
|
|
switch (ivl_logic_pins(net)) {
|
|
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
|
check_cell_lut2();
|
|
|
|
|
obj = edif_cellref_create(edf, cell_lut2);
|
|
|
|
|
edif_cellref_pstring(obj, "INIT", "E");
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_I0);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_I1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
|
check_cell_lut3();
|
|
|
|
|
obj = edif_cellref_create(edf, cell_lut3);
|
|
|
|
|
edif_cellref_pstring(obj, "INIT", "FE");
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_I0);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_I1);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 3));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_I2);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 5:
|
|
|
|
|
check_cell_lut4();
|
|
|
|
|
obj = edif_cellref_create(edf, cell_lut4);
|
|
|
|
|
edif_cellref_pstring(obj, "INIT", "FFFE");
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_I0);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_I1);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 3));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_I2);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 4));
|
|
|
|
|
edif_add_to_joint(jnt, obj, LUT_I3);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n",
|
|
|
|
|
ivl_logic_type(net));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void virtex2_generic_dff(ivl_lpm_t net)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
|
|
ivl_nexus_t aclr = ivl_lpm_async_clr(net);
|
|
|
|
|
ivl_nexus_t aset = ivl_lpm_async_set(net);
|
|
|
|
|
const char*abits = 0;
|
|
|
|
|
|
|
|
|
|
if (aset) {
|
|
|
|
|
ivl_expr_t avalue = ivl_lpm_aset_value(net);
|
|
|
|
|
assert(avalue);
|
|
|
|
|
abits = ivl_expr_bits(avalue);
|
|
|
|
|
assert(abits);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) {
|
|
|
|
|
edif_cellref_t obj;
|
|
|
|
|
ivl_nexus_t nex;
|
|
|
|
|
edif_joint_t jnt;
|
|
|
|
|
|
|
|
|
|
/* If there is a preset, then select an FDCPE instead of
|
|
|
|
|
an FDCE device. */
|
|
|
|
|
if (aset && (abits[idx] == '1')) {
|
|
|
|
|
check_cell_fdcpe();
|
|
|
|
|
obj = edif_cellref_create(edf, cell_fdcpe);
|
|
|
|
|
} else {
|
|
|
|
|
check_cell_fdce();
|
|
|
|
|
obj = edif_cellref_create(edf, cell_fdce);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
|
|
|
|
|
edif_add_to_joint(jnt, obj, FDCE_Q);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
|
|
|
|
|
edif_add_to_joint(jnt, obj, FDCE_D);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net));
|
|
|
|
|
edif_add_to_joint(jnt, obj, FDCE_C);
|
|
|
|
|
|
|
|
|
|
if ( (nex = ivl_lpm_enable(net)) ) {
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, nex);
|
|
|
|
|
edif_add_to_joint(jnt, obj, FDCE_CE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (aclr) {
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, aclr);
|
|
|
|
|
edif_add_to_joint(jnt, obj, FDCE_CLR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (aset) {
|
|
|
|
|
if (abits[idx] == '1') {
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, aset);
|
|
|
|
|
edif_add_to_joint(jnt, obj, FDCE_PRE);
|
|
|
|
|
} else {
|
|
|
|
|
assert(aclr == 0);
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, aset);
|
|
|
|
|
edif_add_to_joint(jnt, obj, FDCE_CLR);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The left shift is implemented as a matrix of MUX2_1 devices. The
|
|
|
|
|
* matrix has as many rows as the device width, and a column for each
|
|
|
|
|
* select.
|
|
|
|
|
*/
|
|
|
|
|
static void virtex2_show_shiftl(ivl_lpm_t net)
|
|
|
|
|
{
|
|
|
|
|
unsigned width = ivl_lpm_width(net);
|
|
|
|
|
unsigned nsel = 0, swid = 0;
|
|
|
|
|
unsigned sdx, qdx;
|
|
|
|
|
|
|
|
|
|
edif_cellref_t* cells;
|
|
|
|
|
edif_cellref_t**table;
|
|
|
|
|
|
|
|
|
|
edif_cellref_t pad0_cell;
|
|
|
|
|
edif_joint_t pad0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
check_cell_lut3();
|
|
|
|
|
check_cell_lut4();
|
|
|
|
|
|
|
|
|
|
/* First, find out how many select inputs we really need. We
|
|
|
|
|
can only use the selects that are enough to shift out the
|
|
|
|
|
entire width of the device. The excess can be used as an
|
|
|
|
|
enable for the last column. When disabled, the last column
|
|
|
|
|
emits zeros. */
|
|
|
|
|
|
|
|
|
|
while (nsel < ivl_lpm_selects(net)) {
|
|
|
|
|
|
|
|
|
|
nsel += 1;
|
|
|
|
|
|
|
|
|
|
swid = 1 << nsel;
|
|
|
|
|
if (swid >= width)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(nsel > 0);
|
|
|
|
|
|
|
|
|
|
/* Allocate a matrix of edif_cellref_t variables. A devices
|
|
|
|
|
will be addressed by the expression table[sdx][qdx];
|
|
|
|
|
This should make the algorighm code easier to read. */
|
|
|
|
|
cells = calloc(nsel * width, sizeof(edif_cellref_t));
|
|
|
|
|
table = calloc(nsel, sizeof(edif_cellref_t*));
|
|
|
|
|
|
|
|
|
|
for (sdx = 0 ; sdx < nsel ; sdx += 1)
|
|
|
|
|
table[sdx] = cells + sdx*width;
|
|
|
|
|
|
|
|
|
|
/* Make a 0 valued pad bit. I wlil use this for all the shifin
|
|
|
|
|
values that are beyond the input. */
|
|
|
|
|
pad0_cell = edif_cellref_create(edf, cell_0);
|
|
|
|
|
pad0 = edif_joint_create(edf);
|
|
|
|
|
edif_add_to_joint(pad0, pad0_cell, 0);
|
|
|
|
|
|
|
|
|
|
/* The LUT matrix is <nsel> columns of <width> devices, with
|
|
|
|
|
the last column a LUT4 devices. The extra input of the
|
|
|
|
|
LUT4s in the last column are used as an enable to collect
|
|
|
|
|
all the excess select inputs. */
|
|
|
|
|
|
|
|
|
|
/* Allocate the LUT devices of the matrix, and connect the
|
|
|
|
|
select inputs to I2 of all the devices of the column. */
|
|
|
|
|
for (sdx = 0 ; sdx < nsel ; sdx += 1) {
|
|
|
|
|
const char*init_string = 0;
|
|
|
|
|
ivl_nexus_t nex = ivl_lpm_select(net,sdx);
|
|
|
|
|
edif_joint_t sdx_jnt = edif_joint_of_nexus(edf, nex);
|
|
|
|
|
|
|
|
|
|
edif_cell_t lut;
|
|
|
|
|
|
|
|
|
|
if (((sdx+1) == nsel) && (nsel < ivl_lpm_selects(net))) {
|
|
|
|
|
lut = cell_lut4;
|
|
|
|
|
init_string = "00CA";
|
|
|
|
|
} else {
|
|
|
|
|
lut = cell_lut3;
|
|
|
|
|
init_string = "CA";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (qdx = 0 ; qdx < width ; qdx += 1) {
|
|
|
|
|
table[sdx][qdx] = edif_cellref_create(edf, lut);
|
|
|
|
|
edif_add_to_joint(sdx_jnt, table[sdx][qdx], LUT_I2);
|
|
|
|
|
|
|
|
|
|
edif_cellref_pstring(table[sdx][qdx], "INIT", init_string);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Connect the inputs of the SHIFTL device to the column 0 LUT
|
|
|
|
|
inputs. The slice on the low end shifts in a 0 for a select
|
|
|
|
|
input. */
|
|
|
|
|
for (qdx = 0 ; qdx < width ; qdx += 1) {
|
|
|
|
|
ivl_nexus_t nex0, nex1;
|
|
|
|
|
edif_joint_t jnt0;
|
|
|
|
|
edif_joint_t jnt1;
|
|
|
|
|
|
|
|
|
|
nex0 = ivl_lpm_data(net,qdx);
|
|
|
|
|
jnt0 = edif_joint_of_nexus(edf, nex0);
|
|
|
|
|
|
|
|
|
|
if (qdx > 0) {
|
|
|
|
|
nex1 = ivl_lpm_data(net,qdx-1);
|
|
|
|
|
jnt1 = edif_joint_of_nexus(edf, nex1);
|
|
|
|
|
} else {
|
|
|
|
|
jnt1 = pad0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edif_add_to_joint(jnt0, table[0][qdx], LUT_I0);
|
|
|
|
|
edif_add_to_joint(jnt1, table[0][qdx], LUT_I1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make the inner connections between LUT devices. Each column
|
|
|
|
|
connects to the previous column, shifted by the power of
|
|
|
|
|
the column value. If the shifted input falls off the end,
|
|
|
|
|
then pad with zero. */
|
|
|
|
|
for (sdx = 1 ; sdx < nsel ; sdx += 1) {
|
|
|
|
|
|
|
|
|
|
for (qdx = 0 ; qdx < width ; qdx += 1) {
|
2003-03-31 03:34:19 +02:00
|
|
|
unsigned shift = 1 << sdx;
|
2003-03-24 01:47:54 +01:00
|
|
|
edif_joint_t jnt0 = edif_joint_create(edf);
|
|
|
|
|
edif_joint_t jnt1 = (qdx >= shift)
|
|
|
|
|
? edif_joint_create(edf)
|
|
|
|
|
: pad0;
|
|
|
|
|
|
|
|
|
|
edif_add_to_joint(jnt0, table[sdx][qdx], LUT_I0);
|
|
|
|
|
edif_add_to_joint(jnt1, table[sdx][qdx], LUT_I1);
|
|
|
|
|
|
|
|
|
|
edif_add_to_joint(jnt0, table[sdx-1][qdx], LUT_O);
|
|
|
|
|
if (qdx >= shift)
|
|
|
|
|
edif_add_to_joint(jnt1, table[sdx-1][qdx-shift], LUT_O);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Connect the output of the last column to the output of the
|
|
|
|
|
SHIFTL device. */
|
|
|
|
|
for (qdx = 0 ; qdx < width ; qdx += 1) {
|
|
|
|
|
ivl_nexus_t nex = ivl_lpm_q(net,qdx);
|
|
|
|
|
edif_joint_t jnt = edif_joint_of_nexus(edf, nex);
|
|
|
|
|
|
|
|
|
|
edif_add_to_joint(jnt, table[nsel-1][qdx], LUT_O);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Connect the excess select inputs to the enable inputs of
|
|
|
|
|
the LUT4 devices in the last column. */
|
|
|
|
|
if (nsel < ivl_lpm_selects(net)) {
|
|
|
|
|
edif_joint_t jnt;
|
|
|
|
|
|
|
|
|
|
/* XXXX Only support 1 excess bit for now. */
|
|
|
|
|
assert((nsel + 1) == ivl_lpm_selects(net));
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net,nsel));
|
|
|
|
|
for (qdx = 0 ; qdx < width ; qdx += 1)
|
|
|
|
|
edif_add_to_joint(jnt, table[nsel-1][qdx], LUT_I3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(cells);
|
|
|
|
|
free(table);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function generates ADD/SUB devices for Virtex-II devices,
|
|
|
|
|
* based on the documented implementations of ADD8/ADD16, etc., from
|
|
|
|
|
* the Libraries Guide.
|
|
|
|
|
*
|
|
|
|
|
* Each slice of the ADD/SUB device is made from a LUT2 device, an
|
|
|
|
|
* XORCY device that mixes with the LUT2 to make a full adder, and a
|
|
|
|
|
* MUXCY_L to propagate the carry. The most significant slice does no
|
|
|
|
|
* have a carry to propagate, so has no MUXCY_L.
|
|
|
|
|
*
|
|
|
|
|
* If the device is a wide adder, then the LUT2 devices are configured
|
|
|
|
|
* to implement an XOR function and a zero is pumped into the least
|
|
|
|
|
* significant carry input.
|
|
|
|
|
*
|
|
|
|
|
* If the device is really an adder, then the input is turned into an
|
|
|
|
|
* XNOR, which takes a 1-s complement of the B input. Pump a 1 into
|
|
|
|
|
* the LSB carry input to finish converting the B input into the 2s
|
|
|
|
|
* complement.
|
|
|
|
|
*/
|
|
|
|
|
static void virtex2_add(ivl_lpm_t net)
|
|
|
|
|
{
|
|
|
|
|
const char*ha_init = 0;
|
|
|
|
|
edif_cellref_t lut, xorcy, muxcy, pad;
|
|
|
|
|
edif_joint_t jnt;
|
|
|
|
|
|
|
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
|
|
switch (ivl_lpm_type(net)) {
|
|
|
|
|
case IVL_LPM_ADD:
|
|
|
|
|
ha_init = "6";
|
|
|
|
|
break;
|
|
|
|
|
case IVL_LPM_SUB:
|
|
|
|
|
ha_init = "9";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If this is a single bit wide, then generate only a
|
|
|
|
|
half-adder. Normally this is an XOR, but if this is a SUB
|
|
|
|
|
then it is an XNOR. */
|
|
|
|
|
if (ivl_lpm_width(net) == 1) {
|
|
|
|
|
|
|
|
|
|
check_cell_lut2();
|
|
|
|
|
lut = edif_cellref_create(edf, cell_lut2);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I0);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I1);
|
|
|
|
|
|
|
|
|
|
edif_cellref_pstring(lut, "INIT", ha_init);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(ivl_lpm_width(net) > 1);
|
|
|
|
|
|
|
|
|
|
check_cell_lut2();
|
|
|
|
|
check_cell_xorcy();
|
|
|
|
|
check_cell_muxcy_l();
|
|
|
|
|
|
|
|
|
|
lut = edif_cellref_create(edf, cell_lut2);
|
|
|
|
|
xorcy = edif_cellref_create(edf, cell_xorcy);
|
|
|
|
|
muxcy = edif_cellref_create(edf, cell_muxcy_l);
|
|
|
|
|
edif_cellref_pstring(lut, "INIT", ha_init);
|
|
|
|
|
|
|
|
|
|
/* The bottom carry-in takes a constant that primes the add or
|
|
|
|
|
subtract. */
|
|
|
|
|
switch (ivl_lpm_type(net)) {
|
|
|
|
|
case IVL_LPM_ADD:
|
|
|
|
|
pad = edif_cellref_create(edf, cell_0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_LPM_SUB:
|
|
|
|
|
pad = edif_cellref_create(edf, cell_1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_create(edf);
|
|
|
|
|
edif_add_to_joint(jnt, pad, 0);
|
|
|
|
|
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
|
|
|
|
|
edif_add_to_joint(jnt, xorcy, XORCY_CI);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, xorcy, XORCY_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_create(edf);
|
|
|
|
|
edif_add_to_joint(jnt, xorcy, XORCY_LI);
|
|
|
|
|
edif_add_to_joint(jnt, muxcy, MUXCY_S);
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I0);
|
|
|
|
|
edif_add_to_joint(jnt, muxcy, MUXCY_DI);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I1);
|
|
|
|
|
|
|
|
|
|
for (idx = 1 ; idx < ivl_lpm_width(net) ; idx += 1) {
|
|
|
|
|
edif_cellref_t muxcy0 = muxcy;
|
|
|
|
|
|
|
|
|
|
lut = edif_cellref_create(edf, cell_lut2);
|
|
|
|
|
xorcy = edif_cellref_create(edf, cell_xorcy);
|
|
|
|
|
edif_cellref_pstring(lut, "INIT", ha_init);
|
|
|
|
|
|
|
|
|
|
/* If this is the last bit, then there is no further
|
|
|
|
|
propagation in the carry chain, and I can skip the
|
|
|
|
|
carry mux MUXCY. */
|
|
|
|
|
if ((idx+1) < ivl_lpm_width(net))
|
|
|
|
|
muxcy = edif_cellref_create(edf, cell_muxcy_l);
|
|
|
|
|
else
|
|
|
|
|
muxcy = 0;
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_create(edf);
|
|
|
|
|
edif_add_to_joint(jnt, muxcy0, MUXCY_O);
|
|
|
|
|
edif_add_to_joint(jnt, xorcy, XORCY_CI);
|
|
|
|
|
if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_CI);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
|
|
|
|
|
edif_add_to_joint(jnt, xorcy, XORCY_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_create(edf);
|
|
|
|
|
edif_add_to_joint(jnt, xorcy, XORCY_LI);
|
|
|
|
|
if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_S);
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I0);
|
|
|
|
|
if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_DI);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Implement hardware for the device (A >= B). We use LUT devices if
|
|
|
|
|
* it can handle the slices, or carry chain logic if the slices must
|
|
|
|
|
* span LUT devices.
|
|
|
|
|
*/
|
|
|
|
|
static void virtex2_cmp_ge(ivl_lpm_t net)
|
|
|
|
|
{
|
|
|
|
|
edif_cellref_t muxcy_prev;
|
|
|
|
|
edif_cellref_t lut;
|
|
|
|
|
edif_joint_t jnt;
|
|
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
|
|
if (ivl_lpm_width(net) == 1) {
|
|
|
|
|
|
|
|
|
|
/* If the comparator is a single bit, then use a LUT2
|
|
|
|
|
with this truth table:
|
|
|
|
|
|
|
|
|
|
Q A B
|
|
|
|
|
--+----
|
|
|
|
|
1 | 0 0
|
|
|
|
|
0 | 0 1
|
|
|
|
|
1 | 1 0
|
|
|
|
|
1 | 1 1
|
|
|
|
|
|
|
|
|
|
Connect the A value to I1 and the B value to I0. */
|
|
|
|
|
|
|
|
|
|
check_cell_lut2();
|
|
|
|
|
lut = edif_cellref_create(edf, cell_lut2);
|
|
|
|
|
edif_cellref_pstring(lut, "INIT", "D");
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_O);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I1);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I2);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
/* 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. */
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:25:19 +02:00
|
|
|
assert(ivl_lpm_width(net) >= 2);
|
2003-03-31 02:04:21 +02:00
|
|
|
check_cell_lut4();
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
lut = edif_cellref_create(edf, cell_lut4);
|
|
|
|
|
edif_cellref_pstring(lut, "INIT", "F731");
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I2);
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I0);
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1));
|
|
|
|
|
edif_add_to_joint(jnt, lut, LUT_I3);
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
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);
|
2003-03-24 01:47:54 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
/* 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. */
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
check_cell_lut2();
|
|
|
|
|
check_cell_muxcy();
|
|
|
|
|
check_cell_muxcy_l();
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
muxcy_prev = edif_cellref_create(edf, cell_muxcy_l);
|
|
|
|
|
jnt = edif_joint_create(edf);
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
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);
|
2003-03-31 02:25:19 +02:00
|
|
|
edif_cellref_t p1 = edif_cellref_create(edf, cell_1);
|
|
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
jnt = edif_joint_create(edf);
|
|
|
|
|
edif_add_to_joint(jnt, p0, 0);
|
|
|
|
|
edif_add_to_joint(jnt, muxcy_prev, MUXCY_DI);
|
2003-03-31 02:25:19 +02:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
jnt = edif_joint_create(edf);
|
|
|
|
|
edif_add_to_joint(jnt, p1, 0);
|
|
|
|
|
edif_add_to_joint(jnt, muxcy_prev, MUXCY_CI);
|
|
|
|
|
}
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
for (idx = 2 ; idx < ivl_lpm_width(net) ; idx += 1) {
|
|
|
|
|
edif_cellref_t muxcy;
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
lut = edif_cellref_create(edf, cell_lut2);
|
2003-03-24 01:47:54 +01:00
|
|
|
muxcy = edif_cellref_create(edf, cell_muxcy);
|
2003-03-31 02:04:21 +02:00
|
|
|
edif_cellref_pstring(lut, "INIT", "9");
|
2003-03-24 01:47:54 +01:00
|
|
|
|
|
|
|
|
jnt = edif_joint_create(edf);
|
2003-03-31 02:04:21 +02:00
|
|
|
edif_add_to_joint(jnt, lut, LUT_O);
|
2003-03-24 01:47:54 +01:00
|
|
|
edif_add_to_joint(jnt, muxcy, MUXCY_S);
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_create(edf);
|
2003-03-31 02:04:21 +02:00
|
|
|
edif_add_to_joint(jnt, muxcy, MUXCY_CI);
|
|
|
|
|
edif_add_to_joint(jnt, muxcy_prev, MUXCY_O);
|
2003-03-24 01:47:54 +01:00
|
|
|
|
2003-03-31 02:04:21 +02:00
|
|
|
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);
|
2003-03-24 01:47:54 +01:00
|
|
|
|
|
|
|
|
muxcy_prev = muxcy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
|
2003-03-31 02:04:21 +02:00
|
|
|
edif_add_to_joint(jnt, muxcy_prev, MUXCY_O);
|
2003-03-24 01:47:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const struct device_s d_virtex2_edif = {
|
|
|
|
|
virtex2_show_header,
|
|
|
|
|
virtex2_show_footer,
|
|
|
|
|
virtex2_pad,
|
|
|
|
|
virtex2_logic,
|
|
|
|
|
virtex2_generic_dff,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
virtex2_cmp_ge,
|
|
|
|
|
0,
|
|
|
|
|
virtex2_add,
|
|
|
|
|
virtex2_add,
|
|
|
|
|
virtex2_show_shiftl, /* show_shiftl */
|
|
|
|
|
0 /* show_shiftr */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* $Log: d-virtex2.c,v $
|
2003-04-04 06:59:03 +02:00
|
|
|
* Revision 1.7 2003/04/04 04:59:03 steve
|
|
|
|
|
* Add xlibrary celltable.
|
|
|
|
|
*
|
2003-03-31 03:34:19 +02:00
|
|
|
* Revision 1.6 2003/03/31 01:34:19 steve
|
|
|
|
|
* Wide shift of MUX was wrong.
|
|
|
|
|
*
|
2003-03-31 02:25:19 +02:00
|
|
|
* Revision 1.5 2003/03/31 00:25:19 steve
|
|
|
|
|
* Fix wrong input constant to bottom of GE.
|
|
|
|
|
*
|
2003-03-31 02:04:21 +02:00
|
|
|
* Revision 1.4 2003/03/31 00:04:21 steve
|
|
|
|
|
* Proper sliced >= comparator.
|
|
|
|
|
*
|
2003-03-30 05:43:44 +02:00
|
|
|
* Revision 1.3 2003/03/30 03:43:44 steve
|
|
|
|
|
* Handle wide ports of macros.
|
|
|
|
|
*
|
2003-03-24 03:29:04 +01:00
|
|
|
* Revision 1.2 2003/03/24 02:29:04 steve
|
|
|
|
|
* Give proper basenames to PAD signals.
|
|
|
|
|
*
|
2003-03-24 01:47:54 +01:00
|
|
|
* Revision 1.1 2003/03/24 00:47:54 steve
|
|
|
|
|
* Add new virtex2 architecture family, and
|
|
|
|
|
* also the new edif.h EDIF management functions.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|