/* * 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); } }
/* * This function draws N-bit wide binary mux devices. These are so * very popular because they are the result of such expressions as: * * x = sel? a : b; * * This code only supports the case where sel is a single bit. It * works by drawing for each bit of the width an EQN device that takes * as inputs I0 and I1 the alternative inputs, and I2 the select. The * select bit is common with all the generated mux devices. */ static void generic_show_mux(ivl_lpm_t net) { char name[1024]; ivl_nexus_t nex, sel; unsigned idx; xnf_mangle_lpm_name(net, name, sizeof name); /* Access the single select bit. This is common to the whole width of the mux. */ assert(ivl_lpm_selects(net) == 1); sel = ivl_lpm_select(net, 0); for (idx = 0 ; idx < ivl_lpm_width(net) ; idx += 1) { fprintf(xnf, "SYM, %s/M%u, EQN, " "EQN=((I0 * ~I2) + (I1 * I2))\n", name, idx); nex = ivl_lpm_q(net, idx); xnf_draw_pin(nex, "O", 'O'); nex = ivl_lpm_data2(net, 0, idx); xnf_draw_pin(nex, "I0", 'I'); nex = ivl_lpm_data2(net, 1, idx); xnf_draw_pin(nex, "I1", 'I'); xnf_draw_pin(sel, "I2", 'I'); fprintf(xnf, "END\n"); } }
static void show_lpm_array(ivl_lpm_t net) { ivl_nexus_t nex; unsigned width = ivl_lpm_width(net); ivl_signal_t array = ivl_lpm_array(net); fprintf(out, " LPM_ARRAY: <width=%u, signal=%s>\n", width, ivl_signal_basename(array)); nex = ivl_lpm_q(net); assert(nex); fprintf(out, " Q: %p\n", nex); nex = ivl_lpm_select(net); assert(nex); fprintf(out, " Address: %p (address width=%u)\n", nex, ivl_lpm_selects(net)); if (width_of_nexus(ivl_lpm_q(net)) != width) { fprintf(out, " ERROR: Data Q width doesn't match " "nexus width=%u\n", width_of_nexus(ivl_lpm_q(net))); stub_errors += 1; } if (ivl_signal_width(array) != width) { fprintf(out, " ERROR: Data width doesn't match " "word width=%u\n", ivl_signal_width(array)); stub_errors += 1; } }
/* * The read port to an array is generated as a single record that takes * the address as an input. */ static void draw_lpm_array(ivl_lpm_t net) { ivl_nexus_t nex; ivl_signal_t mem = ivl_lpm_array(net); const char*tmp; nex = ivl_lpm_select(net); tmp = draw_net_input(nex); fprintf(vvp_out, "L_%p .array/port v%p, %s;\n", net, mem, tmp); }
// Mux tree. unsigned create_mux(ivl_lpm_t lpm, unsigned select_width, unsigned select_number) { unsigned id; if (select_width == 0) { id = create_concat_lpm_data2(lpm, select_number); } else { unsigned width = ivl_lpm_width(lpm); unsigned select = id_of_nexus(ivl_lpm_select(lpm, select_width - 1), 0); unsigned data_0 = create_mux(lpm, select_width - 1, select_number << 1); unsigned data_1 = create_mux(lpm, select_width - 1, (select_number << 1) | 1); id = new_id(); indent(); fprintf(output, " (mux %i %i %i %i %i)\n", id, width, select, data_0, data_1); } return id; }
/* * Show an IVL_LPM_MUX. * * The compiler is supposed to make sure that the Q output and data * inputs all have the width of the device. The ivl_lpm_select input * has its own width. */ static void show_lpm_mux(ivl_lpm_t net) { ivl_nexus_t nex; unsigned idx; unsigned width = ivl_lpm_width(net); unsigned size = ivl_lpm_size(net); ivl_drive_t drive0 = ivl_lpm_drive0(net); ivl_drive_t drive1 = ivl_lpm_drive1(net); fprintf(out, " LPM_MUX %s: <width=%u, size=%u>\n", ivl_lpm_basename(net), width, size); nex = ivl_lpm_q(net); fprintf(out, " Q: %p <drive0/1 = %u/%u>\n", nex, drive0, drive1); if (width != width_of_nexus(nex)) { fprintf(out, " Q: ERROR: Nexus width is %u\n", width_of_nexus(nex)); stub_errors += 1; } /* The select input is a vector with the width from the ivl_lpm_selects function. */ nex = ivl_lpm_select(net); fprintf(out, " S: %p <width=%u>\n", nex, ivl_lpm_selects(net)); if (ivl_lpm_selects(net) != width_of_nexus(nex)) { fprintf(out, " S: ERROR: Nexus width is %u\n", width_of_nexus(nex)); stub_errors += 1; } /* The ivl_lpm_size() method give the number of inputs that can be selected from. */ for (idx = 0 ; idx < size ; idx += 1) { nex = ivl_lpm_data(net,idx); fprintf(out, " D%u: %p\n", idx, nex); if (width != width_of_nexus(nex)) { fprintf(out, " D%u: ERROR, Nexus width is %u\n", idx, width_of_nexus(nex)); stub_errors += 1; } } }
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); } } }