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 draw_lpm_sfunc(ivl_lpm_t net) { unsigned idx; const char*dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .sfunc %u %u \"%s\"", net, dly, ivl_file_table_index(ivl_lpm_file(net)), ivl_lpm_lineno(net), ivl_lpm_string(net)); /* Print the function type descriptor string. */ fprintf(vvp_out, ", \""); draw_type_string_of_nex(ivl_lpm_q(net,0)); for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) draw_type_string_of_nex(ivl_lpm_data(net,idx)); fprintf(vvp_out, "\""); for (idx = 0 ; idx < ivl_lpm_size(net) ; idx += 1) { fprintf(vvp_out, ", %s", draw_net_input(ivl_lpm_data(net,idx))); } fprintf(vvp_out, ";\n"); }
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)); }
/* * 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; } }
// Concat lpm_data unsigned create_concat_lpm_data(ivl_lpm_t lpm) { unsigned width = ivl_lpm_width(lpm); unsigned id; unsigned i; id = id_of_nexus(ivl_lpm_data(lpm, 0), 0); for (i = 1; i < width; i++) { id = create_bit_concat(id, i, ivl_lpm_data(lpm, i)); } return id; }
static void show_lpm_arithmetic_pins(ivl_lpm_t net) { ivl_nexus_t nex; nex = ivl_lpm_q(net); fprintf(out, " Q: %p\n", ivl_lpm_q(net)); nex = ivl_lpm_data(net, 0); fprintf(out, " DataA: %p\n", nex); nex = ivl_lpm_data(net, 1); fprintf(out, " DataB: %p\n", nex); }
/* 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); }
/* 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; } }
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; } }
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; } }
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)); } }
/* * This function draws the arguments to a .const node using the * lpm inputs starting at "start" and for "cnt" inputs. This input * count must be <= 4. It is up to the caller to write the header part * of the statement, and to organize the data into multiple * statements. * * Return the width of the final concatenation. */ static unsigned lpm_concat_inputs(ivl_lpm_t net, unsigned start, unsigned cnt, const char*src_table[]) { unsigned idx; unsigned wid = 0; assert(cnt <= 4); /* First, draw the [L M N O] part of the statement, the list of widths for the .concat statement. */ fprintf(vvp_out, "["); for (idx = 0 ; idx < cnt ; idx += 1) { ivl_nexus_t nex = ivl_lpm_data(net, start+idx); unsigned nexus_width = width_of_nexus(nex); fprintf(vvp_out, " %u", nexus_width); wid += nexus_width; } for ( ; idx < 4 ; idx += 1) fprintf(vvp_out, " 0"); fprintf(vvp_out, "]"); for (idx = 0 ; idx < cnt ; idx += 1) { fprintf(vvp_out, ", %s", src_table[idx]); } fprintf(vvp_out, ";\n"); return wid; }
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))); } }
/* * Draw unary reduction devices. */ static void draw_lpm_re(ivl_lpm_t net, const char*type) { const char*dly = draw_lpm_output_delay(net); fprintf(vvp_out, "L_%p%s .reduce/%s %s;\n", net, dly, type, draw_net_input(ivl_lpm_data(net,0))); }
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 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"); }
/* * This function draws any functors needed to calculate the input to * this nexus, and leaves in the data array strings that can be used * as functor arguments. The strings are from the draw_net_input * function, which in turn returns nexus names, so the strings are * safe to pass around. */ static void draw_lpm_data_inputs(ivl_lpm_t net, unsigned base, unsigned ndata, const char**src_table) { unsigned idx; for (idx = 0 ; idx < ndata ; idx += 1) { ivl_nexus_t nex = ivl_lpm_data(net, base+idx); src_table[idx] = draw_net_input(nex); } }
/* * 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; } }
/* * 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); }
/* * Handle a PART SELECT device. This has a single input and output, * plus an optional extra input that is a non-constant base. */ static void draw_lpm_part(ivl_lpm_t net) { unsigned width, base; ivl_nexus_t sel; const char*dly = draw_lpm_output_delay(net); width = ivl_lpm_width(net); base = ivl_lpm_base(net); sel = ivl_lpm_data(net,1); if (sel == 0) { fprintf(vvp_out, "L_%p%s .part %s", net, dly, draw_net_input(ivl_lpm_data(net, 0))); fprintf(vvp_out, ", %u, %u;\n", base, width); } else { const char*sel_symbol = draw_net_input(sel); fprintf(vvp_out, "L_%p%s .part/v %s", net, dly, draw_net_input(ivl_lpm_data(net,0))); fprintf(vvp_out, ", %s", sel_symbol); fprintf(vvp_out, ", %u;\n", width); } }
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); }
int fit_logic(void) { unsigned idx; for (idx = 0 ; idx < pins ; idx += 1) { ivl_nexus_t cell; struct pal_bind_s*pin = bind_pin + idx; if (pin->sop == 0) continue; cell = pin->nexus; if (cell == 0) continue; /* If there is an enable, then this is a bufifX or a notifX. Build the expression for the enable, and guess that the input to the cell is actually the input to the enable. */ if (pin->enable) { ivl_nexus_t en_nex = ivl_logic_pin(pin->enable, 2); assert(cell == ivl_logic_pin(pin->enable, 0)); cell = ivl_logic_pin(pin->enable, 1); assert(cell); pin->enable_ex = build_expr(en_nex); dump_expr(pin->enable_ex, ivl_nexus_name(en_nex)); } /* If there is a reg, then the input to the cell is really the D input to the ff. */ if (pin->reg) { assert(cell == ivl_lpm_q(pin->reg, pin->reg_q)); cell = ivl_lpm_data(pin->reg, pin->reg_q); } assert(cell); /* Here we are. Generate the sum-of-products for the input. */ pin->sop_ex = build_expr(cell); dump_expr(pin->sop_ex, ivl_nexus_name(cell)); } return 0; }
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 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; } }
/* * 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"); }
static void generic_show_dff(ivl_lpm_t net) { char name[1024]; ivl_nexus_t nex; xnf_mangle_lpm_name(net, name, sizeof name); fprintf(xnf, "SYM, %s, DFF, LIBVER=2.0.0\n", name); nex = ivl_lpm_q(net, 0); xnf_draw_pin(nex, "Q", 'O'); nex = ivl_lpm_data(net, 0); xnf_draw_pin(nex, "D", 'I'); nex = ivl_lpm_clk(net); xnf_draw_pin(nex, "C", 'I'); if ((nex = ivl_lpm_enable(net))) xnf_draw_pin(nex, "CE", 'I'); fprintf(xnf, "END\n"); }