static void draw_lpm_ufunc(ivl_lpm_t net) { unsigned idx; ivl_scope_t def = ivl_lpm_define(net); const char*dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .ufunc TD_%s, %u", net, dly, vvp_mangle_id(ivl_scope_name(def)), ivl_lpm_width(net)); /* Print all the net signals that connect to the input of the function. */ for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) { fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net, idx))); } assert((ivl_lpm_size(net)+1) == ivl_scope_ports(def)); /* Now print all the variables in the function scope that receive the input values given in the previous list. */ for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) { ivl_signal_t psig = ivl_scope_port(def, idx+1); if (idx == 0) fprintf(vvp_out, " ("); else fprintf(vvp_out, ", "); assert(ivl_signal_dimensions(psig) == 0); fprintf(vvp_out, "v%p_0", psig); } fprintf(vvp_out, ")"); /* Now print the reference to the signal from which the result is collected. */ { ivl_signal_t psig = ivl_scope_port(def, 0); assert(ivl_lpm_width(net) == ivl_signal_width(psig)); assert(ivl_signal_dimensions(psig) == 0); fprintf(vvp_out, " v%p_0", psig); } /* Finally, print the scope identifier. */ fprintf(vvp_out, " S_%p;\n", def); }
static void show_lpm_cast_real(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); ivl_nexus_t q, a; fprintf(out, " LPM_CAST_REAL %s: <width=%u>\n", ivl_lpm_basename(net), width); q = ivl_lpm_q(net); a = ivl_lpm_data(net,0); fprintf(out, " O: %p\n", ivl_lpm_q(net)); fprintf(out, " A: %p\n", ivl_lpm_data(net,0)); if (type_of_nexus(q) != IVL_VT_REAL) { fprintf(out, " ERROR: Data type of Q is %s, expecting real\n", data_type_string(type_of_nexus(q))); stub_errors += 1; } if (type_of_nexus(a) == IVL_VT_REAL) { fprintf(out, " ERROR: Data type of A is %s, expecting !real\n", data_type_string(type_of_nexus(a))); stub_errors += 1; } }
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; } }
static void show_lpm_sfunc(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); unsigned ports = ivl_lpm_size(net); ivl_variable_type_t data_type = type_of_nexus(ivl_lpm_q(net)); ivl_nexus_t nex; unsigned idx; fprintf(out, " LPM_SFUNC %s: <call=%s, width=%u, type=%s, ports=%u>\n", ivl_lpm_basename(net), ivl_lpm_string(net), width, data_type_string(data_type), ports); nex = ivl_lpm_q(net); if (width != width_of_nexus(nex)) { fprintf(out, " ERROR: Q output nexus width=%u " " does not match part width\n", width_of_nexus(nex)); stub_errors += 1; } fprintf(out, " Q: %p\n", nex); for (idx = 0 ; idx < ports ; idx += 1) { nex = ivl_lpm_data(net, idx); fprintf(out, " D%u: %p <width=%u, type=%s>\n", idx, nex, width_of_nexus(nex), data_type_string(type_of_nexus(nex))); } }
/* * The compare-like LPM nodes have input widths that match the * ivl_lpm_width() value, and an output width of 1. This function * checks that that is so, and indicates errors otherwise. */ static void check_cmp_widths(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); /* Check that the input widths are as expected. The inputs must be the width of the ivl_lpm_width() for this device, even though the output for this device is 1 bit. */ if (width != width_of_nexus(ivl_lpm_data(net,0))) { fprintf(out, " ERROR: Width of A is %u, not %u\n", width_of_nexus(ivl_lpm_data(net,0)), width); stub_errors += 1; } if (width != width_of_nexus(ivl_lpm_data(net,1))) { fprintf(out, " ERROR: Width of B is %u, not %u\n", width_of_nexus(ivl_lpm_data(net,1)), width); stub_errors += 1; } if (width_of_nexus(ivl_lpm_q(net)) != 1) { fprintf(out, " ERROR: Width of Q is %u, not 1\n", width_of_nexus(ivl_lpm_q(net))); stub_errors += 1; } }
static void show_lpm_ufunc(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); unsigned ports = ivl_lpm_size(net); ivl_scope_t def = ivl_lpm_define(net); ivl_nexus_t nex; unsigned idx; fprintf(out, " LPM_UFUNC %s: <call=%s, width=%u, ports=%u>\n", ivl_lpm_basename(net), ivl_scope_name(def), width, ports); show_lpm_delays(net); nex = ivl_lpm_q(net); if (width != width_of_nexus(nex)) { fprintf(out, " ERROR: Q output nexus width=%u " " does not match part width\n", width_of_nexus(nex)); stub_errors += 1; } fprintf(out, " Q: %p\n", nex); for (idx = 0 ; idx < ports ; idx += 1) { nex = ivl_lpm_data(net, idx); fprintf(out, " D%u: %p <width=%u>\n", idx, nex, width_of_nexus(nex)); } }
static void show_lpm_shift(ivl_lpm_t net, const char*shift_dir) { ivl_nexus_t nex; unsigned width = ivl_lpm_width(net); fprintf(out, " LPM_SHIFT%s %s: <width=%u, %ssigned>\n", shift_dir, ivl_lpm_basename(net), width, ivl_lpm_signed(net)? "" : "un"); nex = ivl_lpm_q(net); fprintf(out, " Q: %p\n", nex); if (width != width_of_nexus(nex)) { fprintf(out, " ERROR: Q output nexus width=%u " "does not match part width\n", width_of_nexus(nex)); stub_errors += 1; } nex = ivl_lpm_data(net, 0); fprintf(out, " D: %p\n", nex); if (width != width_of_nexus(nex)) { fprintf(out, " ERROR: Q output nexus width=%u " "does not match part width\n", width_of_nexus(nex)); stub_errors += 1; } nex = ivl_lpm_data(net, 1); fprintf(out, " S: %p <width=%u>\n", nex, width_of_nexus(nex)); }
static void show_lpm_abs(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); ivl_nexus_t nex; fprintf(out, " LPM_ABS %s: <width=%u>\n", ivl_lpm_basename(net), width); nex = ivl_lpm_q(net); fprintf(out, " Q: %p\n", ivl_lpm_q(net)); nex = ivl_lpm_data(net, 0); fprintf(out, " D: %p\n", nex); if (nex == 0) { fprintf(out, " ERROR: missing input\n"); stub_errors += 1; return; } if (width_of_nexus(nex) != width) { fprintf(out, " ERROR: D width (%d) is wrong\n", width_of_nexus(nex)); stub_errors += 1; } }
/* * 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_repeat(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); unsigned count = ivl_lpm_size(net); ivl_nexus_t nex_q = ivl_lpm_q(net); ivl_nexus_t nex_a = ivl_lpm_data(net,0); fprintf(out, " LPM_REPEAT %s: <width=%u, count=%u>\n", ivl_lpm_basename(net), width, count); fprintf(out, " Q: %p\n", nex_q); fprintf(out, " D: %p\n", nex_a); if (width != width_of_nexus(nex_q)) { fprintf(out, " ERROR: Width of Q is %u, expecting %u\n", width_of_nexus(nex_q), width); stub_errors += 1; } if (count == 0 || count > width || (width%count != 0)) { fprintf(out, " ERROR: Repeat count not reasonable\n"); stub_errors += 1; } else if (width/count != width_of_nexus(nex_a)) { fprintf(out, " ERROR: Width of D is %u, expecting %u\n", width_of_nexus(nex_a), width/count); stub_errors += 1; } }
// Split lpm_q void create_split_lpm_q(ivl_lpm_t lpm, unsigned id) { unsigned width = ivl_lpm_width(lpm); unsigned i; for (i = 0; i < width; i++) create_bit_select(id_of_nexus(ivl_lpm_q(lpm, i), 1), width, i, id); }
static void draw_lpm_repeat(ivl_lpm_t net) { const char*dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .repeat %u, %u, %s;\n", net, dly, ivl_lpm_width(net), ivl_lpm_size(net), draw_net_input(ivl_lpm_data(net,0))); }
static void draw_lpm_sign_ext(ivl_lpm_t net) { const char*dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .extend/s %u, %s;\n", net, dly, ivl_lpm_width(net), draw_net_input(ivl_lpm_data(net,0))); }
static void show_lpm_sub(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); fprintf(out, " LPM_SUB %s: <width=%u>\n", ivl_lpm_basename(net), width); show_lpm_arithmetic_pins(net); }
// Concat lpm_data2 unsigned create_concat_lpm_data2(ivl_lpm_t lpm, unsigned select) { unsigned width = ivl_lpm_width(lpm); unsigned id; unsigned i; id = id_of_nexus(ivl_lpm_data2(lpm, select, 0), 0); for (i = 1; i < width; i++) { id = create_bit_concat(id, i, ivl_lpm_data2(lpm, select, i)); } return id; }
/* * Handle a PART SELECT PV device. Generate a .part/pv node that * includes the part input, and the geometry of the part. */ static void draw_lpm_part_pv(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); unsigned base = ivl_lpm_base(net); unsigned signal_width = width_of_nexus(ivl_lpm_q(net,0)); fprintf(vvp_out, "L_%p .part/pv %s", net, draw_net_input(ivl_lpm_data(net, 0))); fprintf(vvp_out, ", %u, %u, %u;\n", base, width, signal_width); }
/* IVL_LPM_CMP_NE * This LPM node supports two-input compare. The output width is * actually always 1, the lpm_width is the expected width of the inputs. */ static void show_lpm_cmp_ne(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); fprintf(out, " LPM_CMP_NE %s: <width=%u>\n", ivl_lpm_basename(net), width); fprintf(out, " O: %p\n", ivl_lpm_q(net)); fprintf(out, " A: %p\n", ivl_lpm_data(net,0)); fprintf(out, " B: %p\n", ivl_lpm_data(net,1)); check_cmp_widths(net); }
static void draw_lpm_cast_int(ivl_lpm_t net) { const char*src_table[1]; const char*dly; draw_lpm_data_inputs(net, 0, 1, src_table); dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .cast/int %u, %s;\n", net, dly, ivl_lpm_width(net), src_table[0]); }
/* IVL_LPM_CMP_GT * This LPM node supports two-input compare. */ static void show_lpm_cmp_gt(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); fprintf(out, " LPM_CMP_GT %s: <width=%u %s>\n", ivl_lpm_basename(net), width, ivl_lpm_signed(net)? "signed" : "unsigned"); fprintf(out, " O: %p\n", ivl_lpm_q(net)); fprintf(out, " A: %p\n", ivl_lpm_data(net,0)); fprintf(out, " B: %p\n", ivl_lpm_data(net,1)); check_cmp_widths(net); }
/* IVL_LPM_CMP_EEQ/NEE * This LPM node supports two-input compare. The output width is * actually always 1, the lpm_width is the expected width of the inputs. */ static void show_lpm_cmp_eeq(ivl_lpm_t net) { const char*str = (ivl_lpm_type(net) == IVL_LPM_CMP_EEQ)? "EEQ" : "NEE"; unsigned width = ivl_lpm_width(net); fprintf(out, " LPM_CMP_%s %s: <width=%u>\n", str, ivl_lpm_basename(net), width); fprintf(out, " O: %p\n", ivl_lpm_q(net)); fprintf(out, " A: %p\n", ivl_lpm_data(net,0)); fprintf(out, " B: %p\n", ivl_lpm_data(net,1)); check_cmp_widths(net); }
/* * The reduction operators have similar characteristics and are * displayed here. */ static void show_lpm_re(ivl_lpm_t net) { ivl_nexus_t nex; const char*type = "?"; unsigned width = ivl_lpm_width(net); switch (ivl_lpm_type(net)) { case IVL_LPM_RE_AND: type = "AND"; break; case IVL_LPM_RE_NAND: type = "NAND"; break; case IVL_LPM_RE_OR: type = "OR"; break; case IVL_LPM_RE_NOR: type = "NOR"; case IVL_LPM_RE_XOR: type = "XOR"; break; case IVL_LPM_RE_XNOR: type = "XNOR"; default: break; } fprintf(out, " LPM_RE_%s: %s <width=%u>\n", type, ivl_lpm_name(net),width); nex = ivl_lpm_q(net); fprintf(out, " Q: %p\n", nex); nex = ivl_lpm_data(net, 0); fprintf(out, " D: %p\n", nex); nex = ivl_lpm_q(net); if (1 != width_of_nexus(nex)) { fprintf(out, " ERROR: Width of Q is %u, expecting 1\n", width_of_nexus(nex)); stub_errors += 1; } nex = ivl_lpm_data(net, 0); if (width != width_of_nexus(nex)) { fprintf(out, " ERROR: Width of input is %u, expecting %u\n", width_of_nexus(nex), width); stub_errors += 1; } }
/* * 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); } }
int syn_lat_lpm (ivl_lpm_t lpm, syn_ctx * pal) { int rc = 0; unsigned q, wid = ivl_lpm_width (lpm); debug_msg("fitting latch: %s\n", ivl_lpm_basename (lpm)); for (q = 0; q < wid; q += 1) { debug_msg("bit: %u\n", q); rc = scan_ff_q (lpm, q, pal,1); if (rc != 0) return rc; } return rc; }
// 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; }
static void show_lpm_sign_ext(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); ivl_nexus_t nex_q = ivl_lpm_q(net); ivl_nexus_t nex_a = ivl_lpm_data(net,0); fprintf(out, " LPM_SIGN_EXT %s: <width=%u>\n", ivl_lpm_basename(net), width); fprintf(out, " Q: %p\n", nex_q); fprintf(out, " D: %p <width=%u>\n", nex_a, width_of_nexus(nex_a)); if (width != width_of_nexus(nex_q)) { fprintf(out, " ERROR: Width of Q is %u, expecting %u\n", width_of_nexus(nex_q), width); stub_errors += 1; } }
static void draw_lpm_shiftl(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); const char* signed_flag = ivl_lpm_signed(net)? "s" : ""; const char*dly = draw_lpm_output_delay(net); if (ivl_lpm_type(net) == IVL_LPM_SHIFTR) fprintf(vvp_out, "L_%p%s .shift/r%s %u", net, dly, signed_flag, width); else fprintf(vvp_out, "L_%p%s .shift/l %u", net, dly, width); fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net, 0))); fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net, 1))); fprintf(vvp_out, ";\n"); }
static void show_lpm_ff(ivl_lpm_t net) { ivl_nexus_t nex; unsigned width = ivl_lpm_width(net); fprintf(out, " LPM_FF %s: <width=%u>\n", ivl_lpm_basename(net), width); nex = ivl_lpm_clk(net); fprintf(out, " clk: %p\n", nex); if (width_of_nexus(nex) != 1) { fprintf(out, " clk: ERROR: Nexus width is %u\n", width_of_nexus(nex)); stub_errors += 1; } if (ivl_lpm_enable(net)) { nex = ivl_lpm_enable(net); fprintf(out, " CE: %p\n", nex); if (width_of_nexus(nex) != 1) { fprintf(out, " CE: ERROR: Nexus width is %u\n", width_of_nexus(nex)); stub_errors += 1; } } nex = ivl_lpm_data(net,0); fprintf(out, " D: %p\n", nex); if (width_of_nexus(nex) != width) { fprintf(out, " D: ERROR: Nexus width is %u\n", width_of_nexus(nex)); stub_errors += 1; } nex = ivl_lpm_q(net); fprintf(out, " Q: %p\n", nex); if (width_of_nexus(nex) != width) { fprintf(out, " Q: ERROR: Nexus width is %u\n", width_of_nexus(nex)); stub_errors += 1; } }
/* * The LPM_MULT node has a Q output and two data inputs. The width of * the Q output must be the width of the node itself. */ static void show_lpm_mult(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); fprintf(out, " LPM_MULT %s: <width=%u>\n", ivl_lpm_basename(net), width); fprintf(out, " O: %p\n", ivl_lpm_q(net)); fprintf(out, " A: %p <width=%u>\n", ivl_lpm_data(net,0), width_of_nexus(ivl_lpm_data(net,0))); fprintf(out, " B: %p <width=%u>\n", ivl_lpm_data(net,1), width_of_nexus(ivl_lpm_data(net,1))); if (width != width_of_nexus(ivl_lpm_q(net))) { fprintf(out, " ERROR: Width of Q is %u, not %u\n", width_of_nexus(ivl_lpm_q(net)), width); stub_errors += 1; } }
/* * 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; } } }
/* * primitive FD (q, clk, ce, d); * output q; * reg q; * input clk, ce, d; * table * // clk ce d r s q q+ * r 1 0 0 0 : ? : 0; * r 1 1 0 0 : ? : 1; * f 1 ? 0 0 : ? : -; * ? 1 ? 0 0 : ? : -; * * 0 ? 0 0 : ? : -; * ? ? ? 1 ? : ? : 0; * ? ? ? 0 1 : ? : 1; * endtable * endprimitive */ static void draw_lpm_ff(ivl_lpm_t net) { ivl_expr_t aset_expr = 0; const char*aset_bits = 0; ivl_nexus_t nex; unsigned width; width = ivl_lpm_width(net); aset_expr = ivl_lpm_aset_value(net); if (aset_expr) { assert(ivl_expr_width(aset_expr) == width); aset_bits = ivl_expr_bits(aset_expr); } fprintf(vvp_out, "L_%p .dff ", net); nex = ivl_lpm_data(net,0); assert(nex); fprintf(vvp_out, "%s", draw_net_input(nex)); nex = ivl_lpm_clk(net); assert(nex); fprintf(vvp_out, ", %s", draw_net_input(nex)); nex = ivl_lpm_enable(net); if (nex) { fprintf(vvp_out, ", %s", draw_net_input(nex)); } else { fprintf(vvp_out, ", C4<1>"); } /* Stub asynchronous input for now. */ fprintf(vvp_out, ", C4<z>"); fprintf(vvp_out, ";\n"); }