/* * A 4-input N-wide mux can be made on Virtex devices using MUXF5 and * LUT devices. The MUXF5 selects a LUT device (and is connected to * S[1]) and the LUT devices, connected to S[0], select the input. */ static void virtex_mux4(ivl_lpm_t net) { unsigned idx; assert(ivl_lpm_selects(net) == 2); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { edif_joint_t jnt; edif_cellref_t lut01; edif_cellref_t lut23; edif_cellref_t muxf5; lut01 = edif_cellref_create(edf, xilinx_cell_lut3(xlib)); edif_cellref_pstring(lut01, "INIT", "CA"); lut23 = edif_cellref_create(edf, xilinx_cell_lut3(xlib)); edif_cellref_pstring(lut23, "INIT", "CA"); muxf5 = edif_cellref_create(edf, xilinx_cell_muxf5(xlib)); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 0, idx)); edif_add_to_joint(jnt, lut01, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 1, idx)); edif_add_to_joint(jnt, lut01, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 2, idx)); edif_add_to_joint(jnt, lut23, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, 3, idx)); edif_add_to_joint(jnt, lut23, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 0)); edif_add_to_joint(jnt, lut01, LUT_I2); edif_add_to_joint(jnt, lut23, LUT_I2); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxf5, MUXF_I0); edif_add_to_joint(jnt, lut01, LUT_O); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxf5, MUXF_I1); edif_add_to_joint(jnt, lut23, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, muxf5, MUXF_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, 1)); edif_add_to_joint(jnt, muxf5, MUXF_S); } }
static void lpm_show_constant(ivl_net_const_t net) { edif_cell_t cell0 = edif_xlibrary_findcell(xlib, "cell0"); edif_cell_t cell1 = edif_xlibrary_findcell(xlib, "cell1"); edif_cellref_t ref0 = 0, ref1 = 0; const char*bits; unsigned idx; if (cell0 == 0) { cell0 = edif_xcell_create(xlib, "cell0", 1); edif_cell_portconfig(cell0, 0, "Result0", IVL_SIP_OUTPUT); edif_cell_pstring(cell0, "LPM_Type", "LPM_CONSTANT"); edif_cell_pinteger(cell0, "LPM_Width", 1); edif_cell_pinteger(cell0, "LPM_CValue", 0); } if (cell1 == 0) { cell1 = edif_xcell_create(xlib, "cell1", 1); edif_cell_portconfig(cell1, 0, "Result0", IVL_SIP_OUTPUT); edif_cell_pstring(cell1, "LPM_Type", "LPM_CONSTANT"); edif_cell_pinteger(cell1, "LPM_Width", 1); edif_cell_pinteger(cell1, "LPM_CValue", 1); } bits = ivl_const_bits(net); for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) { if (bits[idx] == '1') { if (ref1 == 0) ref1 = edif_cellref_create(edf, cell1); } else { if (ref0 == 0) ref0 = edif_cellref_create(edf, cell0); } } for (idx = 0 ; idx < ivl_const_pins(net) ; idx += 1) { edif_joint_t jnt; jnt = edif_joint_of_nexus(edf, ivl_const_pin(net,idx)); if (bits[idx] == '1') edif_add_to_joint(jnt, ref1, 0); else edif_add_to_joint(jnt, ref0, 0); } }
static void hookup_logic_gate(ivl_net_logic_t net, edif_cell_t cell) { unsigned pin, idx; edif_joint_t jnt; edif_cellref_t ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); pin = edif_cell_port_byname(cell, "Result0"); edif_add_to_joint(jnt, ref, pin); for (idx = 1 ; idx < ivl_logic_pins(net) ; idx += 1) { char name[32]; jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx)); sprintf(name, "Data%ux0", idx-1); pin = edif_cell_port_byname(cell, name); edif_add_to_joint(jnt, ref, pin); } }
static void lpm_show_mult(ivl_lpm_t net) { char name[64]; unsigned idx; edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; sprintf(name, "mult%u", ivl_lpm_width(net)); cell = edif_xlibrary_findcell(xlib, name); if (cell == 0) { cell = edif_xcell_create(xlib, strdup(name), 3 * ivl_lpm_width(net)); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { sprintf(name, "Result%u", idx); edif_cell_portconfig(cell, idx*3+0, strdup(name), IVL_SIP_OUTPUT); sprintf(name, "DataA%u", idx); edif_cell_portconfig(cell, idx*3+1, strdup(name), IVL_SIP_INPUT); sprintf(name, "DataB%u", idx); edif_cell_portconfig(cell, idx*3+2, strdup(name), IVL_SIP_INPUT); } edif_cell_pstring(cell, "LPM_Type", "LPM_MULT"); edif_cell_pinteger(cell, "LPM_WidthP", ivl_lpm_width(net)); edif_cell_pinteger(cell, "LPM_WidthA", ivl_lpm_width(net)); edif_cell_pinteger(cell, "LPM_WidthB", ivl_lpm_width(net)); } ref = edif_cellref_create(edf, cell); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { unsigned pin; ivl_nexus_t nex; sprintf(name, "Result%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, ref, pin); if ( (nex = ivl_lpm_data(net, idx)) ) { sprintf(name, "DataA%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, nex); edif_add_to_joint(jnt, ref, pin); } if ( (nex = ivl_lpm_datab(net, idx)) ) { sprintf(name, "DataB%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, nex); edif_add_to_joint(jnt, ref, pin); } } }
static void lpm_show_add(ivl_lpm_t net) { unsigned idx; unsigned cell_width; char cellname[32]; edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; const char*type = "ADD"; if (ivl_lpm_type(net) == IVL_LPM_SUB) type = "SUB"; /* Figure out the width of the cell. Normally, it is the LPM width known by IVL. But if the top data input bits are unconnected, then we really have a width one less, and we can use the cout to fill out the output width. */ cell_width = ivl_lpm_width(net); if ( (ivl_lpm_data(net,cell_width-1) == 0) && (ivl_lpm_datab(net,cell_width-1) == 0) ) cell_width -= 1; /* Find the correct ADD/SUB device in the library, search by name. If the device is not there, then create it and put it in the library. */ sprintf(cellname, "%s%u", type, cell_width); cell = edif_xlibrary_findcell(xlib, cellname); if (cell == 0) { unsigned pins = cell_width * 3 + 1; cell = edif_xcell_create(xlib, strdup(cellname), pins); for (idx = 0 ; idx < cell_width ; idx += 1) { sprintf(cellname, "Result%u", idx); edif_cell_portconfig(cell, idx*3+0, strdup(cellname), IVL_SIP_OUTPUT); sprintf(cellname, "DataA%u", idx); edif_cell_portconfig(cell, idx*3+1, strdup(cellname), IVL_SIP_INPUT); sprintf(cellname, "DataB%u", idx); edif_cell_portconfig(cell, idx*3+2, strdup(cellname), IVL_SIP_INPUT); } edif_cell_portconfig(cell, pins-1, "Cout", IVL_SIP_OUTPUT); edif_cell_pstring(cell, "LPM_Type", "LPM_ADD_SUB"); edif_cell_pstring(cell, "LPM_Direction", type); edif_cell_pinteger(cell, "LPM_Width", ivl_lpm_width(net)); } ref = edif_cellref_create(edf, cell); /* Connect the pins of the instance to the nexa. Access the cell pins by name. */ for (idx = 0 ; idx < cell_width ; idx += 1) { unsigned pin; sprintf(cellname, "Result%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, ref, pin); sprintf(cellname, "DataA%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, ref, pin); sprintf(cellname, "DataB%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx)); edif_add_to_joint(jnt, ref, pin); } if (cell_width < ivl_lpm_width(net)) { unsigned pin = edif_cell_port_byname(cell, "Cout"); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, cell_width)); edif_add_to_joint(jnt, ref, pin); } }
static void lpm_show_mux(ivl_lpm_t net) { edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; unsigned idx, rdx; char cellname[32]; unsigned wid_r = ivl_lpm_width(net); unsigned wid_s = ivl_lpm_selects(net); unsigned wid_z = ivl_lpm_size(net); sprintf(cellname, "mux%u_%u_%u", wid_r, wid_s, wid_z); cell = edif_xlibrary_findcell(xlib, cellname); if (cell == 0) { unsigned pins = wid_r + wid_s + wid_r*wid_z; cell = edif_xcell_create(xlib, strdup(cellname), pins); /* Make the output ports. */ for (idx = 0 ; idx < wid_r ; idx += 1) { sprintf(cellname, "Result%u", idx); edif_cell_portconfig(cell, idx, strdup(cellname), IVL_SIP_OUTPUT); } /* Make the select ports. */ for (idx = 0 ; idx < wid_s ; idx += 1) { sprintf(cellname, "Sel%u", idx); edif_cell_portconfig(cell, wid_r+idx, strdup(cellname), IVL_SIP_INPUT); } for (idx = 0 ; idx < wid_z ; idx += 1) { unsigned base = wid_r + wid_s + wid_r * idx; unsigned rdx; for (rdx = 0 ; rdx < wid_r ; rdx += 1) { sprintf(cellname, "Data%ux%u", idx, rdx); edif_cell_portconfig(cell, base+rdx, strdup(cellname), IVL_SIP_INPUT); } } edif_cell_pstring(cell, "LPM_Type", "LPM_MUX"); edif_cell_pinteger(cell, "LPM_Width", wid_r); edif_cell_pinteger(cell, "LPM_WidthS", wid_s); edif_cell_pinteger(cell, "LPM_Size", wid_z); } ref = edif_cellref_create(edf, cell); /* Connect the pins of the instance to the nexa. Access the cell pins by name. */ for (idx = 0 ; idx < wid_r ; idx += 1) { unsigned pin; sprintf(cellname, "Result%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, ref, pin); } for (idx = 0 ; idx < wid_s ; idx += 1) { unsigned pin; sprintf(cellname, "Sel%u", idx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_select(net, idx)); edif_add_to_joint(jnt, ref, pin); } for (idx = 0 ; idx < wid_z ; idx += 1) { for (rdx = 0 ; rdx < wid_r ; rdx += 1) { unsigned pin; sprintf(cellname, "Data%ux%u", idx, rdx); pin = edif_cell_port_byname(cell, cellname); jnt = edif_joint_of_nexus(edf, ivl_lpm_data2(net, idx, rdx)); edif_add_to_joint(jnt, ref, pin); } } }
static void lpm_show_dff(ivl_lpm_t net) { char name[64]; edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; unsigned idx; unsigned pin, wid = ivl_lpm_width(net); sprintf(name, "fd%s%s%s%s%s%u", ivl_lpm_enable(net)? "ce" : "", ivl_lpm_async_clr(net)? "cl" : "", ivl_lpm_sync_clr(net)? "sc" : "", ivl_lpm_async_set(net)? "se" : "", ivl_lpm_sync_set(net)? "ss" : "", wid); cell = edif_xlibrary_findcell(xlib, name); if (cell == 0) { unsigned nports = 2 * wid + 1; pin = 0; if (ivl_lpm_enable(net)) nports += 1; if (ivl_lpm_async_clr(net)) nports += 1; if (ivl_lpm_sync_clr(net)) nports += 1; if (ivl_lpm_async_set(net)) nports += 1; if (ivl_lpm_sync_set(net)) nports += 1; cell = edif_xcell_create(xlib, strdup(name), nports); edif_cell_pstring(cell, "LPM_Type", "LPM_FF"); edif_cell_pinteger(cell, "LPM_Width", wid); for (idx = 0 ; idx < wid ; idx += 1) { sprintf(name, "Q%u", idx); edif_cell_portconfig(cell, idx*2+0, strdup(name), IVL_SIP_OUTPUT); sprintf(name, "Data%u", idx); edif_cell_portconfig(cell, idx*2+1, strdup(name), IVL_SIP_INPUT); } pin = wid*2; if (ivl_lpm_enable(net)) { edif_cell_portconfig(cell, pin, "Enable", IVL_SIP_INPUT); pin += 1; } if (ivl_lpm_async_clr(net)) { edif_cell_portconfig(cell, pin, "Aclr", IVL_SIP_INPUT); pin += 1; } if (ivl_lpm_sync_clr(net)) { edif_cell_portconfig(cell, pin, "Sclr", IVL_SIP_INPUT); pin += 1; } if (ivl_lpm_async_set(net)) { edif_cell_portconfig(cell, pin, "Aset", IVL_SIP_INPUT); pin += 1; } if (ivl_lpm_sync_set(net)) { edif_cell_portconfig(cell, pin, "Sset", IVL_SIP_INPUT); pin += 1; } edif_cell_portconfig(cell, pin, "Clock", IVL_SIP_INPUT); pin += 1; assert(pin == nports); } ref = edif_cellref_create(edf, cell); pin = edif_cell_port_byname(cell, "Clock"); jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net)); edif_add_to_joint(jnt, ref, pin); if (ivl_lpm_enable(net)) { pin = edif_cell_port_byname(cell, "Enable"); jnt = edif_joint_of_nexus(edf, ivl_lpm_enable(net)); edif_add_to_joint(jnt, ref, pin); } if (ivl_lpm_async_clr(net)) { pin = edif_cell_port_byname(cell, "Aclr"); jnt = edif_joint_of_nexus(edf, ivl_lpm_async_clr(net)); edif_add_to_joint(jnt, ref, pin); } if (ivl_lpm_sync_clr(net)) { pin = edif_cell_port_byname(cell, "Sclr"); jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_clr(net)); edif_add_to_joint(jnt, ref, pin); } if (ivl_lpm_async_set(net)) { pin = edif_cell_port_byname(cell, "Aset"); jnt = edif_joint_of_nexus(edf, ivl_lpm_async_set(net)); edif_add_to_joint(jnt, ref, pin); } if (ivl_lpm_sync_set(net)) { ivl_expr_t svalue = ivl_lpm_sset_value(net); pin = edif_cell_port_byname(cell, "Sset"); jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_set(net)); edif_add_to_joint(jnt, ref, pin); edif_cellref_pinteger(ref, "LPM_Svalue", ivl_expr_uvalue(svalue)); } for (idx = 0 ; idx < wid ; idx += 1) { sprintf(name, "Q%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, ref, pin); sprintf(name, "Data%u", idx); pin = edif_cell_port_byname(cell, name); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, ref, pin); } }
static void lpm_logic(ivl_net_logic_t net) { edif_cell_t cell; edif_cellref_t ref; edif_joint_t jnt; switch (ivl_logic_type(net)) { case IVL_LO_BUFZ: case IVL_LO_BUF: assert(ivl_logic_pins(net) == 2); cell = lpm_cell_buf(); ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, ref, 0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, ref, 1); break; case IVL_LO_BUFIF0: assert(ivl_logic_pins(net) == 3); cell = lpm_cell_bufif0(); ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, ref, 0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, ref, 1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); edif_add_to_joint(jnt, ref, 2); break; case IVL_LO_BUFIF1: assert(ivl_logic_pins(net) == 3); cell = lpm_cell_bufif1(); ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, ref, 0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, ref, 1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 2)); edif_add_to_joint(jnt, ref, 2); break; case IVL_LO_NOT: assert(ivl_logic_pins(net) == 2); cell = lpm_cell_inv(); ref = edif_cellref_create(edf, cell); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, ref, 0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 1)); edif_add_to_joint(jnt, ref, 1); break; case IVL_LO_OR: cell = lpm_cell_or(ivl_logic_pins(net)-1); hookup_logic_gate(net, cell); break; case IVL_LO_NOR: cell = lpm_cell_nor(ivl_logic_pins(net)-1); hookup_logic_gate(net, cell); break; case IVL_LO_AND: cell = lpm_cell_and(ivl_logic_pins(net)-1); hookup_logic_gate( net, cell); break; case IVL_LO_XOR: cell = lpm_cell_xor(ivl_logic_pins(net)-1); hookup_logic_gate( net, cell); break; default: fprintf(stderr, "UNSUPPORTED LOGIC TYPE: %u\n", ivl_logic_type(net)); break; } }
/* * This function generates ADD/SUB devices for Virtex devices, * based on the documented implementations of ADD8/ADD16, etc., from * the Libraries Guide. * * Each slice of the ADD/SUB device is made from a LUT2 device, an * XORCY device that mixes with the LUT2 to make a full adder, and a * MUXCY_L to propagate the carry. The most significant slice does not * have a carry to propagate, so has no MUXCY_L. * * If the device is a wide adder, then the LUT2 devices are configured * to implement an XOR function and a zero is pumped into the least * significant carry input. * * If the device is really an adder, then the input is turned into an * XNOR, which takes a 1-s complement of the B input. Pump a 1 into * the LSB carry input to finish converting the B input into the 2s * complement. */ void virtex_add(ivl_lpm_t net) { const char*ha_init = 0; edif_cellref_t lut, xorcy, muxcy, pad; edif_joint_t jnt; unsigned idx; if (ivl_lpm_width(net) < 2) { xilinx_add(net); return; } switch (ivl_lpm_type(net)) { case IVL_LPM_ADD: ha_init = "6"; break; case IVL_LPM_SUB: ha_init = "9"; break; default: assert(0); } assert(ivl_lpm_width(net) > 1); lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib)); muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib)); edif_cellref_pstring(lut, "INIT", ha_init); /* The bottom carry-in takes a constant that primes the add or subtract. */ switch (ivl_lpm_type(net)) { case IVL_LPM_ADD: pad = edif_cellref_create(edf, cell_0); break; case IVL_LPM_SUB: pad = edif_cellref_create(edf, cell_1); break; default: assert(0); } jnt = edif_joint_create(edf); edif_add_to_joint(jnt, pad, 0); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, xorcy, XORCY_CI); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, xorcy, XORCY_O); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, xorcy, XORCY_LI); edif_add_to_joint(jnt, muxcy, MUXCY_S); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I0); edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I1); for (idx = 1 ; idx < ivl_lpm_width(net) ; idx += 1) { edif_cellref_t muxcy0 = muxcy; lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib)); edif_cellref_pstring(lut, "INIT", ha_init); /* If this is the last bit, then there is no further propagation in the carry chain, and I can skip the carry mux MUXCY. */ if ((idx+1) < ivl_lpm_width(net)) muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib)); else muxcy = 0; jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy0, MUXCY_O); edif_add_to_joint(jnt, xorcy, XORCY_CI); if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_CI); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, xorcy, XORCY_O); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, xorcy, XORCY_LI); if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_S); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, lut, LUT_I0); if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx)); edif_add_to_joint(jnt, lut, LUT_I1); } }
static void virtex_or_wide(ivl_net_logic_t net) { edif_cell_t cell_muxcy_l = xilinx_cell_muxcy_l(xlib); edif_cell_t cell_muxcy = xilinx_cell_muxcy(xlib); edif_cell_t cell_lut4 = xilinx_cell_lut4(xlib); edif_cellref_t true_out, false_out; edif_cellref_t lut, muxcy, muxcy_down=NULL; edif_joint_t jnt; unsigned idx, inputs, lut4_cnt; if (ivl_logic_type(net) == IVL_LO_OR) { true_out = edif_cellref_create(edf, cell_1); false_out = edif_cellref_create(edf, cell_0); } else { true_out = edif_cellref_create(edf, cell_0); false_out = edif_cellref_create(edf, cell_1); } inputs = ivl_logic_pins(net) - 1; lut4_cnt = (inputs-1)/4; for (idx = 0 ; idx < lut4_cnt ; idx += 1) { muxcy = edif_cellref_create(edf, cell_muxcy_l); lut = edif_cellref_create(edf, cell_lut4); edif_cellref_pstring(lut, "INIT", "0001"); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, muxcy, MUXCY_S); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, true_out, 0); edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+1)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+2)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, idx*4+1+3)); edif_add_to_joint(jnt, lut, LUT_I3); if (idx > 0) { jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, muxcy_down, MUXCY_O); } else { jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, false_out, 0); } muxcy_down = muxcy; } muxcy = edif_cellref_create(edf, cell_muxcy); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, true_out, 0); edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, muxcy_down, MUXCY_O); switch (ivl_logic_pins(net) - 1 - lut4_cnt*4) { case 1: lut = edif_cellref_create(edf, xilinx_cell_inv(xlib)); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0)); edif_add_to_joint(jnt, lut, BUF_I); break; case 2: lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); edif_cellref_pstring(lut, "INIT", "1"); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1)); edif_add_to_joint(jnt, lut, LUT_I1); break; case 3: lut = edif_cellref_create(edf, xilinx_cell_lut3(xlib)); edif_cellref_pstring(lut, "INIT", "01"); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+2)); edif_add_to_joint(jnt, lut, LUT_I2); break; case 4: lut = edif_cellref_create(edf, cell_lut4); edif_cellref_pstring(lut, "INIT", "0001"); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+1)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+2)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, lut4_cnt*4+1+3)); edif_add_to_joint(jnt, lut, LUT_I3); break; default: assert(0); } jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, muxcy, MUXCY_S); jnt = edif_joint_of_nexus(edf, ivl_logic_pin(net, 0)); edif_add_to_joint(jnt, muxcy, MUXCY_O); }
/* * Implement hardware for the device (A >= B). We use LUT devices if * it can handle the slices, or carry chain logic if the slices must * span LUT devices. */ void virtex_ge(ivl_lpm_t net) { edif_cellref_t muxcy_prev; edif_cellref_t lut; edif_joint_t jnt; unsigned idx; if (ivl_lpm_width(net) == 1) { /* If the comparator is a single bit, then use a LUT2 with this truth table: Q A B --+---- 1 | 0 0 0 | 0 1 1 | 1 0 1 | 1 1 Connect the A value to I1 and the B value to I0. */ lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); edif_cellref_pstring(lut, "INIT", "D"); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I2); return; } /* Handle the case where the device is two slices wide. In this case, we can use a LUT4 to do all the calculation. Use this truth table: Q AA BB --+------ 1 | 00 00 0 | 00 01 0 | 00 10 0 | 00 11 1 | 01 00 1 | 01 01 0 | 01 10 0 | 01 11 1 | 10 00 1 | 10 01 1 | 10 10 0 | 10 11 1 | 11 xx The I3-I0 inputs are A1 A0 B1 B0 in that order. */ assert(ivl_lpm_width(net) >= 2); lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib)); edif_cellref_pstring(lut, "INIT", "F731"); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1)); edif_add_to_joint(jnt, lut, LUT_I3); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1)); edif_add_to_joint(jnt, lut, LUT_I1); /* There are only two slices, so this is all we need. */ if (ivl_lpm_width(net) == 2) { jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); return; } /* The general case requires that we make the >= comparator from slices. This is an iterative design. Each slice has the truth table: An Bn | A >= B ------+------- 0 0 | CI 0 1 | 0 1 0 | 1 1 1 | CI The CI for each slice is the output of the compare of the next less significant bits. We get this truth table by connecting a LUT2 to the S input of a MUXCY. When the S input is (1), it propagates its CI. This suggests that the init value for the LUT be "9" (XNOR). When the MUXCY S input is 0, it propagates a local input. We connect to that input An, and we get the desired and complete truth table for a slice. This iterative definition needs to terminate at the least significant bits. In fact, we have a non-iterative was to deal with the two least significant slices. We take the output of the LUT4 device for the least significant bits, and use that to generate the initial CI for the chain. */ muxcy_prev = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib)); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, muxcy_prev, MUXCY_S); { edif_cellref_t p0 = edif_cellref_create(edf, cell_0); edif_cellref_t p1 = edif_cellref_create(edf, cell_1); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, p0, 0); edif_add_to_joint(jnt, muxcy_prev, MUXCY_DI); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, p1, 0); edif_add_to_joint(jnt, muxcy_prev, MUXCY_CI); } for (idx = 2 ; idx < ivl_lpm_width(net) ; idx += 1) { edif_cellref_t muxcy; lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); muxcy = edif_cellref_create(edf, xilinx_cell_muxcy(xlib)); edif_cellref_pstring(lut, "INIT", "9"); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, muxcy, MUXCY_S); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, muxcy, MUXCY_CI); edif_add_to_joint(jnt, muxcy_prev, MUXCY_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, lut, LUT_I0); edif_add_to_joint(jnt, muxcy, MUXCY_DI); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx)); edif_add_to_joint(jnt, lut, LUT_I1); muxcy_prev = muxcy; } jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, muxcy_prev, MUXCY_O); }
/* * This method handles both == and != operators, the identity * comparison operators. * * If the identity compare is applied to small enough input vectors, * it is shoved into a single LUT. Otherwise, it is strung out into a * row of LUT devices chained together by carry muxes. The output of * the comparison is the output of the last mux. * * When the compare is small, a LUT is generated with the appropriate * truth table to cause an == or != result. * * When the compare is too wide for a single LUT, then it is made into * a chain connected by a string of carry mux devices. Each LUT * implements == for up to two pairs of bits, even if the final output * is supposed to be !=. The LUT output is connected to an associated * MUX select input. The CO output of each muxcy is passed up to the * next higher order bits of the compare. * * For identity == compare, a != output from the LUT selects the DI * input of the muxcy, generating a 0 output that is passed up. Since * the next higher muxcy now gets a 0 input to both DI and CI, the * output of the next higher muxcy is guaranteed to be 0, and so on to * the final output of the carry chain. If the output from a LUT is ==, * then the CI input of the muxcy is selected and the truth of this * level depends on lower order bits. The least significant muxcy is * connected to GND and VCC so that its CO follows the least * significant LUT. * * Identity != is the same as == except that the output is * inverted. To get that effect without putting an inverter on the * output of the top muxcy pin CO (which would cost a LUT) the DI * inputs are all connected to VCC instead of GND, and the CI of the * least significant muxcy is connected to GND instead of VCC. The LUT * expressions for the chained compare are configured for ==, with the * changed CI/DI inputs performing the inversion. */ void virtex_eq(ivl_lpm_t net) { edif_cellref_t lut, mux, mux_prev; edif_joint_t jnt, jnt_di; unsigned idx; /* True if I'm implementing CMP_EQ instead of CMP_NE */ int eq = 1; assert(ivl_lpm_width(net) >= 1); if (ivl_lpm_type(net) == IVL_LPM_CMP_NE) eq = 0; switch (ivl_lpm_width(net)) { case 1: lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); edif_cellref_pstring(lut, "INIT", eq? "9" : "6"); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I1); return; case 2: lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib)); edif_cellref_pstring(lut, "INIT", eq? "9009" : "6FF6"); jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, lut, LUT_O); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0)); edif_add_to_joint(jnt, lut, LUT_I1); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1)); edif_add_to_joint(jnt, lut, LUT_I3); return; default: { edif_cellref_t di; di = edif_cellref_create(edf, eq? cell_0 : cell_1); jnt_di = edif_joint_create(edf); edif_add_to_joint(jnt_di, di, 0); } mux_prev = 0; for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 2) { int subwid = 2; if ((idx + 1) == ivl_lpm_width(net)) subwid = 1; mux = edif_cellref_create(edf, xilinx_cell_muxcy(xlib)); if (subwid == 2) { lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib)); edif_cellref_pstring(lut, "INIT", "9009"); } else { lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib)); edif_cellref_pstring(lut, "INIT", "9"); } jnt = edif_joint_create(edf); edif_add_to_joint(jnt, lut, LUT_O); edif_add_to_joint(jnt, mux, MUXCY_S); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, lut, LUT_I0); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx)); edif_add_to_joint(jnt, lut, LUT_I1); if (subwid > 1) { jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx+1)); edif_add_to_joint(jnt, lut, LUT_I2); jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx+1)); edif_add_to_joint(jnt, lut, LUT_I3); } edif_add_to_joint(jnt_di, mux, MUXCY_DI); if (mux_prev) { jnt = edif_joint_create(edf); edif_add_to_joint(jnt, mux, MUXCY_CI); edif_add_to_joint(jnt, mux_prev, MUXCY_O); } else { edif_cellref_t ci; ci = edif_cellref_create(edf, eq? cell_1 : cell_0); jnt = edif_joint_create(edf); edif_add_to_joint(jnt, ci, 0); edif_add_to_joint(jnt, mux, MUXCY_CI); } mux_prev = mux; } jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0)); edif_add_to_joint(jnt, mux_prev, MUXCY_O); return; } }
void virtex_generic_dff(ivl_lpm_t net) { unsigned idx; ivl_nexus_t aclr = ivl_lpm_async_clr(net); ivl_nexus_t aset = ivl_lpm_async_set(net); ivl_nexus_t sclr = ivl_lpm_sync_clr(net); ivl_nexus_t sset = ivl_lpm_sync_set(net); const char*abits = 0; if (aset) { ivl_expr_t avalue = ivl_lpm_aset_value(net); assert(avalue); abits = ivl_expr_bits(avalue); assert(abits); } /* XXXX Can't handle both synchronous and asynchronous clear. */ assert( ! (aclr && sclr) ); /* XXXX Can't handle synchronous set at all. */ assert( ! sset ); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { edif_cellref_t obj; ivl_nexus_t nex; edif_joint_t jnt; /* If there is a preset, then select an FDCPE instead of an FDCE device. */ if (aset && (abits[idx] == '1')) { obj = edif_cellref_create(edf, xilinx_cell_fdcpe(xlib)); } else if (aclr) { obj = edif_cellref_create(edf, xilinx_cell_fdce(xlib)); } else if (sclr) { obj = edif_cellref_create(edf, xilinx_cell_fdre(xlib)); } else { obj = edif_cellref_create(edf, xilinx_cell_fdce(xlib)); } jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx)); edif_add_to_joint(jnt, obj, FDCE_Q); jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx)); edif_add_to_joint(jnt, obj, FDCE_D); jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net)); edif_add_to_joint(jnt, obj, FDCE_C); if ( (nex = ivl_lpm_enable(net)) ) { jnt = edif_joint_of_nexus(edf, nex); edif_add_to_joint(jnt, obj, FDCE_CE); } if (aclr) { jnt = edif_joint_of_nexus(edf, aclr); edif_add_to_joint(jnt, obj, FDCE_CLR); } else if (sclr) { jnt = edif_joint_of_nexus(edf, sclr); edif_add_to_joint(jnt, obj, FDCE_CLR); } if (aset) { if (abits[idx] == '1') { jnt = edif_joint_of_nexus(edf, aset); edif_add_to_joint(jnt, obj, FDCE_PRE); } else { assert(aclr == 0); jnt = edif_joint_of_nexus(edf, aset); edif_add_to_joint(jnt, obj, FDCE_CLR); } } } }