Пример #1
0
/*
 * Scoped objects are the signals, reg and wire and what-not. What
 * this function does is draw the objects of the scope, along with a
 * fake scope context so that the hierarchical name remains
 * pertinent.
 */
static void draw_scoped_objects(ivl_design_t des)
{
      ivl_scope_t root = ivl_design_root(des);
      unsigned cnt, idx;

      cnt = ivl_scope_sigs(root);
      for (idx = 0 ;  idx < cnt ;  idx += 1) {
	    ivl_signal_t sig = ivl_scope_sig(root, idx);

	    switch (ivl_signal_type(sig)) {
		case IVL_SIT_REG:
		  if (ivl_signal_pins(sig) > 1)
			fprintf(out, "    reg [%u:0] %s;\n",
				ivl_signal_pins(sig),
				ivl_signal_basename(sig));
		  else
			fprintf(out, "    reg %s;\n",
				ivl_signal_basename(sig));
		  break;
		case IVL_SIT_TRI:
		  fprintf(out, "    wire %s;\n", ivl_signal_basename(sig));
		  break;
		default:
		  assert(0);
	    }
      }

}
static void set_to_lvariable(ivl_lval_t lval, unsigned idx,
			     unsigned bit, unsigned wid)
{
      ivl_signal_t sig  = ivl_lval_sig(lval);
      unsigned part_off = ivl_lval_part_off(lval);

      if (ivl_lval_mux(lval)) {
	    assert(wid == 1);
	    if ((ivl_signal_pins(sig)-1) <= 0xffffU) {
		  fprintf(vvp_out, "    %%set/x0 V_%s, %u, %u;\n",
			  vvp_signal_label(sig), bit, ivl_signal_pins(sig)-1);
	    } else {
		    /* If the target bound is too big for the %set/x0
		       instruction, then use the %set/x0/x instruction
		       instead. */
		  fprintf(vvp_out, "    %%ix/load 3, %u;\n",
			  ivl_signal_pins(sig)-1);
		  fprintf(vvp_out, "    %%set/x0/x V_%s, %u, 3;\n",
			  vvp_signal_label(sig), bit);
	    }
			  
      } else if (wid == 1) {
	    fprintf(vvp_out, "    %%set V_%s[%u], %u;\n",
		    vvp_signal_label(sig), idx+part_off, bit);

      } else {
	    fprintf(vvp_out, "    %%set/v V_%s[%u], %u, %u;\n",
		    vvp_signal_label(sig), idx+part_off, bit, wid);

      }
}
Пример #3
0
static void show_root_ports_xnf(ivl_scope_t root)
{
    unsigned cnt = ivl_scope_sigs(root);
    unsigned idx;

    for (idx = 0 ;  idx < cnt ;  idx += 1) {
        ivl_signal_t sig = ivl_scope_sig(root, idx);
        const char*use_name;

        if (ivl_signal_port(sig) == IVL_SIP_NONE)
            continue;

        use_name = ivl_signal_basename(sig);
        if (ivl_signal_pins(sig) == 1) {
            ivl_nexus_t nex = ivl_signal_pin(sig, 0);
            fprintf(xnf, "SIG, %s, PIN=%s\n",
                    xnf_mangle_nexus_name(nex), use_name);

        } else {
            unsigned pin;

            for (pin = 0 ; pin < ivl_signal_pins(sig); pin += 1) {
                ivl_nexus_t nex = ivl_signal_pin(sig, pin);
                fprintf(xnf, "SIG, %s, PIN=%s%u\n",
                        xnf_mangle_nexus_name(nex), use_name,
                        pin);
            }
        }
    }
}
Пример #4
0
static void show_root_ports_edif(ivl_scope_t root)
{
      char jbuf[1024];
      unsigned cnt = ivl_scope_sigs(root);
      unsigned idx;

      for (idx = 0 ;  idx < cnt ;  idx += 1) {
	    ivl_signal_t sig = ivl_scope_sig(root, idx);
	    const char*use_name;
	    const char*dir = 0;

	    if (ivl_signal_attr(sig, "PAD") != 0)
		  continue;

	    switch (ivl_signal_port(sig)) {
		case IVL_SIP_NONE:
		  continue;

		case IVL_SIP_INPUT:
		  dir = "INPUT";
		  break;

		case IVL_SIP_OUTPUT:
		  dir = "OUTPUT";
		  break;

		case IVL_SIP_INOUT:
		  dir = "INOUT";
		  break;
	    }

	    use_name = ivl_signal_basename(sig);
	    if (ivl_signal_pins(sig) == 1) {
		  fprintf(xnf, "            (port %s (direction %s))\n",
			  use_name, dir);

		  sprintf(jbuf, "(portRef %s)", use_name);
		  edif_set_nexus_joint(ivl_signal_pin(sig, 0), jbuf);

	    } else {
		  unsigned pin;

		  for (pin = 0 ; pin < ivl_signal_pins(sig); pin += 1) {
			fprintf(xnf, "            (port (rename %s_%u "
				"\"%s[%u]\") (direction %s))\n", use_name,
				pin, use_name, pin, dir);
			sprintf(jbuf, "(portRef %s_%u)", use_name, pin);
			edif_set_nexus_joint(ivl_signal_pin(sig, pin), jbuf);
		  }
	    }
      }
}
static int show_stmt_cassign(ivl_statement_t net)
{
      ivl_lval_t lval;
      ivl_signal_t lsig;
      unsigned idx;
      char*tmp_label;

      assert(ivl_stmt_lvals(net) == 1);
      lval = ivl_stmt_lval(net, 0);

      lsig = ivl_lval_sig(lval);
      assert(lsig != 0);
      assert(ivl_lval_mux(lval) == 0);
      assert(ivl_signal_pins(lsig) == ivl_stmt_nexus_count(net));
      assert(ivl_lval_part_off(lval) == 0);

      tmp_label = strdup(vvp_signal_label(lsig));
      for (idx = 0 ;  idx < ivl_stmt_nexus_count(net) ;  idx += 1) {
	    fprintf(vvp_out, "    %%cassign V_%s[%u], %s;\n",
		    tmp_label, idx,
		    draw_net_input(ivl_stmt_nexus(net, idx)));
      }
      free(tmp_label);

      return 0;
}
Пример #6
0
/*
 * This function scans the netlist for all the pin assignments that
 * are fixed by a PAD attribute. Search the scopes recursively,
 * looking for signals that may have PAD attributes.
 */
int get_pad_bindings(ivl_scope_t net, void*x)
{
      unsigned idx;

      int rc = ivl_scope_children(net, get_pad_bindings, 0);
      if (rc)
	    return rc;

      for (idx = 0 ;  idx < ivl_scope_sigs(net) ;  idx += 1) {

	    ivl_signal_t sig;
	    const char*pad;
	    int pin;

	    sig = ivl_scope_sig(net, idx);
	    pad = ivl_signal_attr(sig, "PAD");
	    if (pad == 0)
		  continue;

	    pin = strtol(pad+1, 0, 10);
	    if ((pin == 0) || (pin > pins)) {
		  printf("%s: Invalid PAD assignment: %s\n",
			 ivl_signal_name(sig), pad);
		  error_count += 1;
		  continue;
	    }

	    assert(ivl_signal_pins(sig) == 1);

	    if (bind_pin[pin-1].nexus) {

		  if (bind_pin[pin-1].nexus != ivl_signal_pin(sig, 0)) {

			printf("%s: Unconnected signals share pin %d\n",
			       ivl_signal_name(sig), pin);
			error_count += 1;
		  }

		  continue;
	    }

	    bind_pin[pin-1].nexus = ivl_signal_pin(sig, 0);
      }

      return 0;
}
Пример #7
0
/*
 * An assignment is one of a possible list of l-values to a behavioral
 * assignment. Each l-value is either a part select of a signal or a
 * non-constant bit select.
 */
static void show_assign_lval(ivl_lval_t lval)
{
      ivl_nexus_t nex;
      ivl_signal_t sig=NULL;

      unsigned idx;
      unsigned lsb=0;

      assert(ivl_lval_mux(lval) == 0);
      assert(ivl_lval_mem(lval) == 0);

      nex = ivl_lval_pin(lval, 0);

      for (idx = 0 ;  idx < ivl_nexus_ptrs(nex) ;  idx += 1) {
	    unsigned pin;
	    ivl_nexus_ptr_t ptr;

	    ptr = ivl_nexus_ptr(nex, idx);
	    sig = ivl_nexus_ptr_sig(ptr);
	    if (sig == 0)
		  continue;

	    lsb = ivl_nexus_ptr_pin(ptr);

	    for (pin = 1 ;  pin < ivl_lval_pins(lval) ;  pin += 1) {
		  if (ivl_signal_pin(sig, lsb+pin) != ivl_lval_pin(lval,pin))
			break;
	    }

	    if (pin < ivl_lval_pins(lval))
		  continue;

	    break;
      }

      assert(sig);

      if ((lsb > 0) || (lsb + ivl_lval_pins(lval)) < ivl_signal_pins(sig)) {
	    fprintf(out, "%s[%u:%u]", ivl_signal_name(sig),
		    lsb+ivl_lval_pins(lval)-1, lsb);

      } else {
	    fprintf(out, "%s", ivl_signal_name(sig));

      }
}
Пример #8
0
/*
 * Given a nexus, this function draws a signal reference. We don't
 * care really whether the signal is a reg or wire, because this may
 * be an input or output of a gate. Just print it. And if this is a
 * bit of a vector, draw the bit select needed to get at the right bit.
 */
static void draw_nexus(ivl_nexus_t nex)
{
      ivl_signal_t sig=NULL;
      ivl_nexus_ptr_t ptr=NULL;
      unsigned idx;

      for (idx = 0 ;  idx < ivl_nexus_ptrs(nex) ;  idx += 1) {
	    ptr = ivl_nexus_ptr(nex, idx);
	    sig = ivl_nexus_ptr_sig(ptr);
	    if (sig)
		  break;
      }

      assert(sig);

      if (ivl_signal_pins(sig) == 1) {
	    fprintf(out, "%s", ivl_signal_name(sig));

      } else {
	    fprintf(out, "%s[%u]", ivl_signal_name(sig),
		    ivl_nexus_ptr_pin(ptr));
      }
}
Пример #9
0
static void lpm_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;

	/* 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);
      }

	/* Create the base edf object. */
      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;

	    if (ivl_signal_pins(sig) == 1) {
		  edif_portconfig(edf, pidx, ivl_signal_basename(sig),
				  ivl_signal_port(sig));

		  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);
		  }
	    }

	    pidx += ivl_signal_pins(sig);
      }

      assert(pidx == nports);

      xlib = edif_xlibrary_create(edf, "LPM_LIBRARY");
}
static void draw_vpi_taskfunc_args(const char*call_string,
				   ivl_statement_t tnet,
				   ivl_expr_t fnet)
{
      unsigned idx;
      unsigned parm_count = tnet
	    ? ivl_stmt_parm_count(tnet)
	    : ivl_expr_parms(fnet);
      struct vector_info *vec = 0x0;
      unsigned int vecs= 0;
      unsigned int veci= 0;

      ivl_parameter_t par;

	/* Figure out how many expressions are going to be evaluated
	   for this task call. I won't need to evaluate expressions
	   for items that are VPI objects directly. */
      for (idx = 0 ;  idx < parm_count ;  idx += 1) {
	    ivl_expr_t expr = tnet
		  ? ivl_stmt_parm(tnet, idx)
		  : ivl_expr_parm(fnet, idx);
	    
	    switch (ivl_expr_type(expr)) {

		    /* These expression types can be handled directly,
		       with VPI handles of their own. Therefore, skip
		       them in the process of evaluating expressions. */
		case IVL_EX_NONE:
		case IVL_EX_NUMBER:
		case IVL_EX_STRING:
		case IVL_EX_EVENT:
		case IVL_EX_SCOPE:
		case IVL_EX_VARIABLE:
		  continue;

		case IVL_EX_SFUNC:
		  if (is_magic_sfunc(ivl_expr_name(expr)))
			continue;

		  break;

		case IVL_EX_SIGNAL:
		    /* If the signal node is narrower then the signal
		       itself, then this is a part select so I'm going
		       to need to evaluate the expression.

		       Also, if the signedness of the expression is
		       different from the signedness of the
		       signal. This could be caused by a $signed or
		       $unsigned system function.

		       If I don't need to do any evaluating, then skip
		       it as I'll be passing the handle to the signal
		       itself. */
		  if (ivl_expr_width(expr) !=
		      ivl_signal_pins(ivl_expr_signal(expr))) {
			break;

		  } else if (ivl_expr_signed(expr) !=
			     ivl_signal_signed(ivl_expr_signal(expr))) {
			break;

		  } else {
			continue;
		  }


		case IVL_EX_MEMORY:
		  if (!ivl_expr_oper1(expr)) {
			continue;
		  }

		    /* Everything else will need to be evaluated and
		       passed as a constant to the vpi task. */
		default:
		  break;
	    }

	    vec = (struct vector_info *)
		  realloc(vec, (vecs+1)*sizeof(struct vector_info));

	    switch (ivl_expr_value(expr)) {
		case IVL_VT_VECTOR:
		  vec[vecs] = draw_eval_expr(expr, 0);
		  break;
		case IVL_VT_REAL:
		  vec[vecs].base = draw_eval_real(expr);
		  vec[vecs].wid = 0;
		  break;
		default:
		  assert(0);
	    }
	    vecs++;
      }

      fprintf(vvp_out, "%s", call_string);

      for (idx = 0 ;  idx < parm_count ;  idx += 1) {
	    ivl_expr_t expr = tnet
		  ? ivl_stmt_parm(tnet, idx)
		  : ivl_expr_parm(fnet, idx);
	    
	    switch (ivl_expr_type(expr)) {
		case IVL_EX_NONE:
		  fprintf(vvp_out, ", \" \"");
		  continue;

		case IVL_EX_NUMBER: {
		      unsigned bit, wid = ivl_expr_width(expr);
		      const char*bits = ivl_expr_bits(expr);

		      fprintf(vvp_out, ", %u'%sb", wid,
			      ivl_expr_signed(expr)? "s" : "");
		      for (bit = wid ;  bit > 0 ;  bit -= 1)
			    fputc(bits[bit-1], vvp_out);
		      continue;
		}

		case IVL_EX_SIGNAL:
		    /* If this is a part select, then the value was
		       calculated above. Otherwise, just pass the
		       signal. */
		  if (ivl_expr_width(expr) !=
		      ivl_signal_pins(ivl_expr_signal(expr))) {
			break;

		  } else if (ivl_expr_signed(expr) !=
			     ivl_signal_signed(ivl_expr_signal(expr))) {
			break;

		  } else {
			fprintf(vvp_out, ", V_%s", 
				vvp_signal_label(ivl_expr_signal(expr)));
			continue;
		  }

		case IVL_EX_VARIABLE: {
		      ivl_variable_t var = ivl_expr_variable(expr);
		      fprintf(vvp_out, ", W_%s", vvp_word_label(var));
		      continue;
		}

		case IVL_EX_STRING:
		  if (( par = ivl_expr_parameter(expr) )) {
			fprintf(vvp_out, ", P_%p", par);

		  } else {
			fprintf(vvp_out, ", \"%s\"", 
				ivl_expr_string(expr));
		  }
		  continue;

		case IVL_EX_EVENT:
		  fprintf(vvp_out, ", E_%p", ivl_expr_event(expr));
		  continue;

		case IVL_EX_SCOPE:
		  fprintf(vvp_out, ", S_%p", ivl_expr_scope(expr));
		  continue;

		case IVL_EX_SFUNC:
		  if (is_magic_sfunc(ivl_expr_name(expr))) {
			fprintf(vvp_out, ", %s", ivl_expr_name(expr));
			continue;
		  }
		  break;
		  
		case IVL_EX_MEMORY:
		  if (!ivl_expr_oper1(expr)) {
			fprintf(vvp_out, ", M_%s", 
				vvp_memory_label(ivl_expr_memory(expr)));
			continue;
		  }
		  break;

		default:
		  break;
	    }
	    assert(veci < vecs);

	    switch (ivl_expr_value(expr)) {

		case IVL_VT_VECTOR:
		  fprintf(vvp_out, ", T<%u,%u,%s>", vec[veci].base,
			  vec[veci].wid, ivl_expr_signed(expr)? "s" : "u");
		  break;

		case IVL_VT_REAL:
		  fprintf(vvp_out, ", W<%u,r>", vec[veci].base);
		  break;

		default:
		  assert(0);
	    }
	    veci++;
      }
      
      assert(veci == vecs);

      if (vecs) {
	    for (idx = 0; idx < vecs; idx++) {
		  if (vec[idx].wid > 0)
			clr_vector(vec[idx]);
		  else if (vec[idx].wid == 0)
			clr_word(vec[idx].base);
	    }
	    free(vec);
      }

      fprintf(vvp_out, ";\n");
}
Пример #11
0
// Build the design hierarchy.
int build_hierarchy(ivl_scope_t scope, void* cd)
{
  int return_code;
  unsigned i, j;

  indent();
  fprintf(output, "(scope ");
  quoted_string(ivl_scope_tname(scope));
  fprintf(output, " ");
  quoted_string(ivl_scope_basename(scope));
  fprintf(output, " (\n");

  // Constants (root scope only)
  if (! level)
    for (i = 0; i < ivl_design_consts(design); i++) {
      ivl_net_const_t constant = ivl_design_const(design, i);
      const char* bits = ivl_const_bits(constant);
      unsigned pins = ivl_const_pins(constant);
      unsigned id = new_id();
      indent();
      fprintf(output, "  (const  %i \"", id);
      for (j = pins - 1; j < pins; j--)
        fprintf(output, "%c", bits[j]);
      fprintf(output, "\")\n");
      for (j = 0; j < pins; j++)
        create_bit_select(id_of_nexus(ivl_const_pin(constant, j), 1), pins, j, id);
    }

  // Parameters
  for (i = 0; i < ivl_scope_params(scope); i++) {
    ivl_parameter_t param = ivl_scope_param(scope, i);
    ivl_expr_t param_value = ivl_parameter_expr(param);
    unsigned width = ivl_expr_width(param_value);
    const char* bits;
    unsigned id = new_id();
    indent();
    fprintf(output, "  (const  %i \"", id);
    switch (ivl_expr_type(param_value)) {
      case IVL_EX_STRING : bits = ivl_expr_string(param_value); break;
      case IVL_EX_NUMBER : bits = ivl_expr_bits(param_value);   break;
      default            : fprintf(output, "** ERROR: Unknown parameter type."); return -1;
    }
    for (j = width - 1; j < width; j--)
      fprintf(output, "%c", bits[j]);
    fprintf(output, "\")\n");
    indent();
    fprintf(output, "  (name   %i ", new_id());
    quoted_string(ivl_parameter_basename(param));
    fprintf(output, " %i %i)\n", width, id);
  }

  // Signals
  for (i = 0; i < ivl_scope_sigs(scope); i++) {
    ivl_signal_t sig = ivl_scope_sig(scope, i);
    unsigned pins = ivl_signal_pins(sig);
    ivl_signal_port_t type = ivl_signal_port(sig);
    const char* name = ivl_signal_basename(sig);
    unsigned id;
    if (! level && type == IVL_SIP_INPUT) {
      id = new_id();
      fprintf(output, "  (input  %i \"%s\" %i)\n", id, name, pins);
      for (j = 0; j < pins; j++)
        create_bit_select(id_of_nexus(ivl_signal_pin(sig, j), 1), pins, j, id);
    }
    else if (! level && type == IVL_SIP_INOUT) {
      printf("** ERROR: Inout ports not supported.\n");
    }
    else if (! level && type == IVL_SIP_OUTPUT) {
      id = id_of_nexus(ivl_signal_pin(sig, 0), 0);
      for (j = 1; j < pins; j++) {
        id = create_bit_concat(id, j, ivl_signal_pin(sig, j));
      }
      fprintf(output, "  (output %i \"%s\" %i %i)\n", new_id(), name, pins, id);
    }
    else {
      id = id_of_nexus(ivl_signal_pin(sig, 0), 0);
      for (j = 1; j < pins; j++) {
        id = create_bit_concat(id, j, ivl_signal_pin(sig, j));
      }
      indent();
      fprintf(output, "  (name   %i ", new_id());  //XXX Why is "_s22" getting named?
      quoted_string(name);
      fprintf(output, " %i %i)\n", pins, id);
    }
  }

  // Logic
  for (i = 0; i < ivl_scope_logs(scope); i++) {
    unsigned id;
    ivl_net_logic_t log = ivl_scope_log(scope, i);
    switch (ivl_logic_type(log)) {
      case IVL_LO_BUF:
        indent();
        fprintf(output, "  (buf    %i 1 %i)\n", id_of_nexus(ivl_logic_pin(log, 0), 1), id_of_nexus(ivl_logic_pin(log, 1), 0));
        break;

      case IVL_LO_NOT:
        indent();
        fprintf(output, "  (not    %i 1 %i)\n", id_of_nexus(ivl_logic_pin(log, 0), 1), id_of_nexus(ivl_logic_pin(log, 1), 0));
        break;

      case IVL_LO_AND:
        indent();
        create_multi_gate("and ", id_of_nexus(ivl_logic_pin(log, 0), 1), log);
        break;
      
      case IVL_LO_NAND:
        id = new_id();
        indent();
        create_multi_gate("and ", id, log);
        indent();
        fprintf(output, "  (not    %i 1 %i)\n", id_of_nexus(ivl_logic_pin(log, 0), 1), id);
        break;
      
      case IVL_LO_XOR:
        indent();
        create_multi_gate("xor ", id_of_nexus(ivl_logic_pin(log, 0), 1), log);
        break;
      
      case IVL_LO_XNOR:
        id = new_id();
        indent();
        create_multi_gate("xor ", id, log);
        indent();
        fprintf(output, "  (not    %i 1 %i)\n", id_of_nexus(ivl_logic_pin(log, 0), 1), id);
        break;
      
      case IVL_LO_OR:
        indent();
        create_multi_gate("or  ", id_of_nexus(ivl_logic_pin(log, 0), 1), log);
        break;
      
      case IVL_LO_NOR:
        id = new_id();
        indent();
        create_multi_gate("or  ", id, log);
        indent();
        fprintf(output, "  (not    %i 1 %i)\n", id_of_nexus(ivl_logic_pin(log, 0), 1), id);
        break;

      default:
        printf("** ERROR: Unsupported logic type: %i.\n", ivl_logic_type(log));
        return -1;
    }
  }
  
  // LPMs
  for (i = 0; i < ivl_scope_lpms(scope); i++) {
    ivl_lpm_t lpm = ivl_scope_lpm(scope, i);
    ivl_lpm_type_t lpm_t = ivl_lpm_type(lpm);
    unsigned width   = ivl_lpm_width(lpm);
    unsigned selects;
    unsigned size;
    unsigned id, id1, id2, id3;
    switch (lpm_t) {
      case IVL_LPM_ADD:
        id  = new_id();
        id1 = create_concat_lpm_data(lpm);
        id2 = create_concat_lpm_datab(lpm);
        indent();
        fprintf(output, "  (add    %i %i %i %i)\n", id, width, id1, id2);
        create_split_lpm_q(lpm, id);
        break;

      case IVL_LPM_SUB:
        id  = new_id();
        id1 = create_concat_lpm_data(lpm);
        id2 = create_concat_lpm_datab(lpm);
        indent();
        fprintf(output, "  (sub    %i %i %i %i)\n", id, width, id1, id2);
        create_split_lpm_q(lpm, id);
        break;

      case IVL_LPM_MULT:
        id  = new_id();
        id1 = create_concat_lpm_data(lpm);
        id2 = create_concat_lpm_datab(lpm);
        indent();
        fprintf(output, "  (mul    %i %i %i %i)\n", id, width, id1, id2);
        create_split_lpm_q(lpm, id);
        break;

      case IVL_LPM_CMP_EQ:
        id1 = create_concat_lpm_data(lpm);
        id2 = create_concat_lpm_datab(lpm);
        indent();
        fprintf(output, "  (eq     %i %i %i %i)\n", id_of_nexus(ivl_lpm_q(lpm, 0), 1), width, id1, id2);
        break;

      case IVL_LPM_CMP_NE:
        id1 = create_concat_lpm_data(lpm);
        id2 = create_concat_lpm_datab(lpm);
        id  = new_id();
        indent();
        fprintf(output, "  (eq     %i %i %i %i)\n", id, width, id1, id2);
        indent();
        fprintf(output, "  (not    %i 1 %i)\n", id_of_nexus(ivl_lpm_q(lpm, 0), 1), id);
        break;

      case IVL_LPM_CMP_GT:
        // XXX Check for signed.
        id1 = create_concat_lpm_data(lpm);
        id2 = create_concat_lpm_datab(lpm);
        indent();
        fprintf(output, "  (lt     %i %i %i %i)\n", id_of_nexus(ivl_lpm_q(lpm, 0), 1), width, id2, id1);
        break;

      case IVL_LPM_CMP_GE:
        // XXX Check for signed.
        id1 = create_concat_lpm_data(lpm);
        id2 = create_concat_lpm_datab(lpm);
        id  = new_id();
        indent();
        fprintf(output, "  (lt     %i %i %i %i)\n", id, width, id1, id2);
        indent();
        fprintf(output, "  (not    %i 1 %i)\n", id_of_nexus(ivl_lpm_q(lpm, 0), 1), id);
        break;

      case IVL_LPM_FF:
        {
          ivl_nexus_t async_clr = ivl_lpm_async_clr(lpm);
          ivl_nexus_t async_set = ivl_lpm_async_set(lpm);
          ivl_nexus_t sync_clr = ivl_lpm_sync_clr(lpm);
          ivl_nexus_t sync_set = ivl_lpm_sync_set(lpm);
          ivl_nexus_t clk = ivl_lpm_clk(lpm);
          ivl_nexus_t enable = ivl_lpm_enable(lpm);
          if (async_set || sync_set) { perror("** ERROR: Does not support registers with async or sync sets.\n"); return -1; }
          id = new_id();
          id1 = create_concat_lpm_data(lpm);
          if (enable) {
            id2 = new_id();
            indent();
            fprintf(output, "  (mux    %i %i %i %i %i)\n", id2, width, id_of_nexus(enable, 0), id, id1);
            id1 = id2;
          }
          if (sync_clr) {
            id2 = new_id();
            id3 = new_id();
            indent();
            fprintf(output, "  (const  %i \"", id3);
            for (j = 0; j < width; j++)
              fprintf(output, "0");
            fprintf(output, "\")\n");
            indent();
            fprintf(output, "  (mux    %i %i %i %i %i)\n", id2, width, id_of_nexus(sync_clr, 0), id1, id3);
            id1 = id2;
          }
          // XXX Default to posedge sensitivity.
          if (async_clr) {
            indent();
            fprintf(output, "  (ffc    %i %i %i %i %i)\n", id, width, id_of_nexus(async_clr, 0), id_of_nexus(clk, 0), id1);
          }
          else {
            indent();
            fprintf(output, "  (ff     %i %i %i %i)\n", id, width, id_of_nexus(clk, 0), id1);
          }
          create_split_lpm_q(lpm, id);
        }
        break;

      case IVL_LPM_MUX:
        {
          unsigned t = 1;
          selects = ivl_lpm_selects(lpm);
          size    = ivl_lpm_size(lpm);
          for (j = 0; j < selects; j++)
            t = t * 2;
          assert(t == size); // General case.
          id = create_mux(lpm, selects, 0);
          create_split_lpm_q(lpm, id);
        }
        break;

      default:
        perror("** ERROR: Unsupported LPM type.\n");
        return -1;
    }
  }
  level = level + 1;
  return_code = ivl_scope_children(scope, build_hierarchy, 0);
  level = level - 1;
  if (! level)
    delete_nexus_table(nexus_table);
  indent();
  fprintf(output, "))\n");
  return return_code;
}