Example #1
0
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)));
      }
}
Example #2
0
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));
      }
}
Example #3
0
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;
      }
}
Example #4
0
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;
      }
}
Example #5
0
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));
}
Example #6
0
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;
      }
}
Example #7
0
/*
 * 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;
      }
}
Example #8
0
/*
 * 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;
}
Example #9
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;
      }
}
Example #10
0
/*
 * 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;
      }
}
Example #11
0
/*
 * 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);
}
Example #12
0
/*
 * 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;
      }
}
Example #13
0
static void draw_type_string_of_nex(ivl_nexus_t nex)
{
      switch (data_type_of_nexus(nex)) {
	  case IVL_VT_REAL:
	    fprintf(vvp_out, "r");
	    break;
	  case IVL_VT_LOGIC:
          case IVL_VT_BOOL:
	    fprintf(vvp_out, "v%d", width_of_nexus(nex));
	    break;
	  default:
	    assert(0);
	    break;
      }
}
Example #14
0
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;
      }

}
Example #15
0
/* IVL_LPM_CONCAT
 * The concat device takes N inputs (N=ivl_lpm_size) and generates
 * a single output. The total output is known from the ivl_lpm_width
 * function. The widths of all the inputs are inferred from the widths
 * of the signals connected to the nexus of the inputs. The compiler
 * makes sure the input widths add up to the output width.
 */
static void show_lpm_concat(ivl_lpm_t net)
{
      unsigned idx;

      unsigned width_sum = 0;
      unsigned width = ivl_lpm_width(net);

      fprintf(out, "  LPM_CONCAT %s: <width=%u, inputs=%u>\n",
	      ivl_lpm_basename(net), width, ivl_lpm_size(net));
      fprintf(out, "    O: %p\n", ivl_lpm_q(net));

      for (idx = 0 ;  idx < ivl_lpm_size(net) ;  idx += 1) {
	    ivl_nexus_t nex = ivl_lpm_data(net, idx);
	    unsigned signal_width = width_of_nexus(nex);

	    fprintf(out, "    I%u: %p (width=%u)\n", idx, nex, signal_width);
	    width_sum += signal_width;
      }

      if (width_sum != width) {
	    fprintf(out, "    ERROR! Got %u bits input, expecting %u!\n",
		    width_sum, width);
      }
}
Example #16
0
/*
 * 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;
	    }
      }
}
Example #17
0
static void draw_logic_in_scope(ivl_net_logic_t lptr)
{
      unsigned pdx;
      const char*ltype = "?";
      const char*lcasc = 0;
      char identity_val = '0';

      int need_delay_flag = ivl_logic_delay(lptr,0)? 1 : 0;

      unsigned vector_width = width_of_nexus(ivl_logic_pin(lptr, 0));

      ivl_drive_t str0, str1;

      int level;
      int ninp = ivl_logic_pins(lptr) - 1;
      typedef const char*const_charp;
      const_charp*input_strings = calloc(ninp, sizeof(const_charp));

      for (pdx = 0 ;  pdx < ninp ;  pdx += 1) {
	    ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1);
	    if (nex == 0) {
		    /* Only UDPs can have unconnected inputs. */
		  assert(ivl_logic_type(lptr) == IVL_LO_UDP);
		  input_strings[pdx] = 0;
	    } else {
		  input_strings[pdx] = draw_net_input(nex);
	    }
      }

      switch (ivl_logic_type(lptr)) {

          case IVL_LO_UDP:
	    free(input_strings);
	    draw_udp_in_scope(lptr);
	    return;

          case IVL_LO_BUFZ: {
		  /* Draw bufz objects, but only if the gate cannot
		     be elided. If I can elide it, then the
		     draw_nex_input will take care of it for me. */
		ivl_nexus_ptr_t nptr = ivl_logic_pin_ptr(lptr,0);

		ltype = "BUFZ";

		if (can_elide_bufz(lptr, nptr))
		      return;

		break;
	  }

	  case IVL_LO_PULLDOWN:
	  case IVL_LO_PULLUP:
	      /* Skip pullup and pulldown objects. Things that have
		 pull objects as inputs will instead generate the
		 appropriate C<?> symbol. */
	    free(input_strings);
	    return;

	  case IVL_LO_AND:
	    ltype = "AND";
	    identity_val = '1';
	    break;

	  case IVL_LO_BUF:
	    ltype = "BUF";
	    break;

	  case IVL_LO_BUFIF0:
	    ltype = "BUFIF0";
	    break;

	  case IVL_LO_BUFIF1:
	    ltype = "BUFIF1";
	    break;

	  case IVL_LO_NAND:
	    ltype = "NAND";
	    lcasc = "AND";
	    identity_val = '1';
	    break;

	  case IVL_LO_NOR:
	    ltype = "NOR";
	    lcasc = "OR";
	    break;

	  case IVL_LO_NOT:
	    ltype = "NOT";
	    break;

	  case IVL_LO_OR:
	    ltype = "OR";
	    break;

	  case IVL_LO_XNOR:
	    ltype = "XNOR";
	    lcasc = "XOR";
	    break;

	  case IVL_LO_XOR:
	    ltype = "XOR";
	    break;

	  case IVL_LO_CMOS:
	    ltype = "CMOS";
	    break;

	  case IVL_LO_PMOS:
	    ltype = "PMOS";
	    break;

	  case IVL_LO_NMOS:
	    ltype = "NMOS";
	    break;

	  case IVL_LO_RCMOS:
	    ltype = "RCMOS";
	    break;

	  case IVL_LO_RPMOS:
	    ltype = "RPMOS";
	    break;

	  case IVL_LO_RNMOS:
	    ltype = "RNMOS";
	    break;

	  case IVL_LO_NOTIF0:
	    ltype = "NOTIF0";
	    break;

	  case IVL_LO_NOTIF1:
	    ltype = "NOTIF1";
	    break;

	  default:
	    fprintf(stderr, "vvp.tgt: error: Unhandled logic type: %u\n",
		    ivl_logic_type(lptr));
	    ltype = "?";
	    break;
      }

      { ivl_nexus_t nex = ivl_logic_pin(lptr, 0);
        ivl_nexus_ptr_t nptr = 0;
        unsigned idx;
	for (idx = 0 ;  idx < ivl_nexus_ptrs(nex) ;  idx += 1) {
	      nptr = ivl_nexus_ptr(nex,idx);
	      if (ivl_nexus_ptr_log(nptr) != lptr)
		    continue;
	      if (ivl_nexus_ptr_pin(nptr) != 0)
		    continue;
	      break;
	}
        str0 = ivl_nexus_ptr_drive0(nptr);
	str1 = ivl_nexus_ptr_drive1(nptr);
      }

      if (!lcasc)
	lcasc = ltype;

	/* Get all the input label that I will use for parameters to
	   the functor that I create later. */
      ninp = ivl_logic_pins(lptr) - 1;
      input_strings = calloc(ninp, sizeof(char*));
      for (pdx = 0 ;  pdx < ninp ;  pdx += 1)
	    input_strings[pdx] = draw_net_input(ivl_logic_pin(lptr, pdx+1));

      level = 0;
      ninp = ivl_logic_pins(lptr) - 1;
      while (ninp) {
	    int inst;
	    for (inst = 0; inst < ninp; inst += 4) {
		  if (ninp > 4)
			fprintf(vvp_out, "L_%p/%d/%d .functor %s %u",
				lptr, level, inst, lcasc, vector_width);
		  else {
			fprintf(vvp_out, "L_%p%s .functor %s %u",
				lptr, need_delay_flag? "/d" : "",
				ltype, vector_width);

			if (str0 != IVL_DR_STRONG || str1 != IVL_DR_STRONG)
			      fprintf(vvp_out, " [%u %u]", str0, str1);

		  }
		  for (pdx = inst; pdx < ninp && pdx < inst+4 ; pdx += 1) {
			if (level) {
			      fprintf(vvp_out, ", L_%p/%d/%d",
				      lptr, level - 1, pdx*4);
			} else {
			      fprintf(vvp_out, ", %s", input_strings[pdx]);
			}
		  }
		  for ( ;  pdx < inst+4 ;  pdx += 1) {
			unsigned wdx;
			fprintf(vvp_out, ", C4<");
			for (wdx = 0 ; wdx < vector_width ;  wdx += 1)
			      fprintf(vvp_out, "%c", identity_val);
			fprintf(vvp_out, ">");
		  }

		  fprintf(vvp_out, ";\n");
	    }
	    if (ninp > 4)
		  ninp = (ninp+3) / 4;
	    else
		  ninp = 0;
	    level += 1;
      }

	/* Free the array of char*. The strings themselves are
	   persistent, held by the ivl_nexus_t objects. */
      free(input_strings);

	/* If there are delays, then draw the delay functor to carry
	   that delay. This is the final output. */
      if (need_delay_flag) {
	    ivl_expr_t rise_exp  = ivl_logic_delay(lptr,0);
	    ivl_expr_t fall_exp  = ivl_logic_delay(lptr,1);
	    ivl_expr_t decay_exp = ivl_logic_delay(lptr,2);

	    if (number_is_immediate(rise_exp,64,0)
		&& number_is_immediate(fall_exp,64,0)
		&& number_is_immediate(decay_exp,64,0)) {

		  fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
			  lptr, get_number_immediate(rise_exp),
			  get_number_immediate(rise_exp),
			  get_number_immediate(rise_exp), lptr);
	    } else {
		  ivl_signal_t sig;
		  assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL);
		  assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
		  assert(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL);

		  fprintf(vvp_out, "L_%p .delay  L_%p/d", lptr, lptr);

		  sig = ivl_expr_signal(rise_exp);
		  assert(ivl_signal_dimensions(sig) == 0);
		  fprintf(vvp_out, ", v%p_0", sig);

		  sig = ivl_expr_signal(fall_exp);
		  assert(ivl_signal_dimensions(sig) == 0);
		  fprintf(vvp_out, ", v%p_0", sig);

		  sig = ivl_expr_signal(decay_exp);
		  assert(ivl_signal_dimensions(sig) == 0);
		  fprintf(vvp_out, ", v%p_0;\n", sig);
	    }
      }
}
Example #18
0
void show_switch(ivl_switch_t net)
{
      const char*name = ivl_switch_basename(net);
      int has_enable = 0;
      ivl_nexus_t nexa, nexb;
      ivl_variable_type_t nex_type_a, nex_type_b;

      switch (ivl_switch_type(net)) {
	  case IVL_SW_TRAN:
	    fprintf(out, "  tran %s", name);
	    break;
	  case IVL_SW_RTRAN:
	    fprintf(out, "  rtran %s", name);
	    break;
	  case IVL_SW_TRANIF0:
	    fprintf(out, "  tranif0 %s", name);
	    has_enable = 1;
	    break;
	  case IVL_SW_RTRANIF0:
	    fprintf(out, "  rtranif0 %s", name);
	    has_enable = 1;
	    break;
	  case IVL_SW_TRANIF1:
	    fprintf(out, "  tranif1 %s", name);
	    has_enable = 1;
	    break;
	  case IVL_SW_RTRANIF1:
	    fprintf(out, "  rtranif1 %s", name);
	    has_enable = 1;
	    break;
	  case IVL_SW_TRAN_VP:
	    fprintf(out, "  tran(VP wid=%u, part=%u, off=%u) %s",
		    ivl_switch_width(net), ivl_switch_part(net),
		    ivl_switch_offset(net), name);
	    break;
      }

      fprintf(out, " island=%p\n", ivl_switch_island(net));

      nexa = ivl_switch_a(net);
      nex_type_a = nexa? type_of_nexus(nexa) : IVL_VT_NO_TYPE;
      fprintf(out, "    A: %p <type=%s>\n", nexa, data_type_string(nex_type_a));

      nexb = ivl_switch_b(net);
      nex_type_b = nexb? type_of_nexus(nexb) : IVL_VT_NO_TYPE;
      fprintf(out, "    B: %p <type=%s>\n", nexb, data_type_string(nex_type_b));

	/* The A/B pins of the switch must be present, and must match. */
      if (nex_type_a == IVL_VT_NO_TYPE) {
	    fprintf(out, "    A: ERROR: Type missing for pin A\n");
	    stub_errors += 1;
      }
      if (nex_type_b == IVL_VT_NO_TYPE) {
	    fprintf(out, "    B: ERROR: Type missing for pin B\n");
	    stub_errors += 1;
      }
      if (nex_type_a != nex_type_b) {
	    fprintf(out, "    A/B: ERROR: Type mismatch between pins A and B\n");
	    stub_errors += 1;
      }

      if (ivl_switch_type(net) == IVL_SW_TRAN_VP) {
	      /* The TRAN_VP nodes are special in that the specific
		 width matters for each port and should be exactly
		 right for both. */
	    if (width_of_nexus(nexa) != ivl_switch_width(net)) {
		  fprintf(out, "    A: ERROR: part vector nexus "
			  "width=%u, expecting width=%u\n",
			  width_of_nexus(nexa), ivl_switch_width(net));
		  stub_errors += 1;
	    }
	    if (width_of_nexus(nexb) != ivl_switch_part(net)) {
		  fprintf(out, "    B: ERROR: part select nexus "
			  "width=%u, expecting width=%u\n",
			  width_of_nexus(nexb), ivl_switch_part(net));
		  stub_errors += 1;
	    }
      } else {
	      /* All other TRAN nodes will have matching vector
		 widths, but the actual value doesn't matter. */
	    if (width_of_nexus(nexa) != width_of_nexus(nexb)) {
		  fprintf(out, "    A/B: ERROR: Width of ports don't match"
			  ": A=%u, B=%u\n",
			  width_of_nexus(nexa), width_of_nexus(nexb));
		  stub_errors += 1;
	    }
      }

      if (has_enable) {
	    ivl_nexus_t nexe = ivl_switch_enable(net);
	    ivl_variable_type_t nexe_type = type_of_nexus(nexe);
	    fprintf(out, "    E: %p <type=%s>\n", nexe, data_type_string(nexe_type));
	    if (width_of_nexus(nexe) != 1) {
		  fprintf(out, "    E: ERROR: Nexus width is %u\n",
			  width_of_nexus(nexe));
	    }
      }
}
Example #19
0
static void show_lpm_part(ivl_lpm_t net)
{
      unsigned width = ivl_lpm_width(net);
      unsigned base  = ivl_lpm_base(net);
      ivl_nexus_t sel = ivl_lpm_data(net,1);
      const char*part_type_string = "";

      switch (ivl_lpm_type(net)) {
	  case IVL_LPM_PART_VP:
	    part_type_string = "VP";
	    break;
	  case IVL_LPM_PART_PV:
	    part_type_string = "PV";
	    break;
	  default:
	    break;
      }

      fprintf(out, "  LPM_PART_%s %s: <width=%u, base=%u, signed=%d>\n",
	      part_type_string, ivl_lpm_basename(net),
	      width, base, ivl_lpm_signed(net));
      fprintf(out, "    O: %p\n", ivl_lpm_q(net));
      fprintf(out, "    I: %p\n", ivl_lpm_data(net,0));

      if (sel != 0) {
	    fprintf(out, "    S: %p\n", sel);
	    if (base != 0) {
		  fprintf(out, "   ERROR: Part select has base AND selector\n");
		  stub_errors += 1;
	    }
      }

	/* The compiler must assure that the base plus the part select
	   width fits within the input to the part select. */
      switch (ivl_lpm_type(net)) {

	  case IVL_LPM_PART_VP:
	    if (width_of_nexus(ivl_lpm_data(net,0)) < (width+base)) {
		  fprintf(out, "    ERROR: Part select is out of range."
			  " Data nexus width=%u, width+base=%u\n",
			  width_of_nexus(ivl_lpm_data(net,0)), width+base);
		  stub_errors += 1;
	    }

	    if (width_of_nexus(ivl_lpm_q(net)) != width) {
		  fprintf(out, "    ERROR: Part select input mismatch."
			  " Nexus width=%u, expect width=%u\n",
			  width_of_nexus(ivl_lpm_q(net)), width);
		  stub_errors += 1;
	    }
	    break;

	  case IVL_LPM_PART_PV:
	    if (width_of_nexus(ivl_lpm_q(net)) < (width+base)) {
		  fprintf(out, "    ERROR: Part select is out of range."
			  " Target nexus width=%u, width+base=%u\n",
			  width_of_nexus(ivl_lpm_q(net)), width+base);
		  stub_errors += 1;
	    }

	    if (width_of_nexus(ivl_lpm_data(net,0)) != width) {
		  fprintf(out, "    ERROR: Part select input mismatch."
			  " Nexus width=%u, expect width=%u\n",
			  width_of_nexus(ivl_lpm_data(net,0)), width);
		  stub_errors += 1;
	    }
	    break;

	  default:
	    assert(0);
      }
}
Example #20
0
static void draw_net_input_x(ivl_nexus_t nex,
			     struct vvp_nexus_data*nex_data)
{
      ivl_island_t island = 0;
      int island_input_flag = -1;
      ivl_signal_type_t res;
      char result[512];
      unsigned idx;
      char**driver_labels;
      unsigned ndrivers = 0;

      const char*resolv_type;

      char*nex_private = 0;

	/* Accumulate nex_data flags. */
      int nex_flags = 0;

      res = signal_type_of_nexus(nex);
      switch (res) {
	  case IVL_SIT_TRI:
	  case IVL_SIT_UWIRE:
	    resolv_type = "tri";
	    break;
	  case IVL_SIT_TRI0:
	    resolv_type = "tri0";
	    nex_flags |= VVP_NEXUS_DATA_STR;
	    break;
	  case IVL_SIT_TRI1:
	    resolv_type = "tri1";
	    nex_flags |= VVP_NEXUS_DATA_STR;
	    break;
	  case IVL_SIT_TRIAND:
	    resolv_type = "triand";
	    break;
	  case IVL_SIT_TRIOR:
	    resolv_type = "trior";
	    break;
	  default:
	    fprintf(stderr, "vvp.tgt: Unsupported signal type: %d\n", res);
	    assert(0);
	    resolv_type = "tri";
	    break;
      }


      for (idx = 0 ;  idx < ivl_nexus_ptrs(nex) ;  idx += 1) {
	    ivl_switch_t sw = 0;
	    ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);

	      /* If this object is part of an island, then we'll be
	         making a port. If this nexus is an output from any
	         switches in the island, then set island_input_flag to
	         false. Save the island cookie. */
	    if ( (sw = ivl_nexus_ptr_switch(nptr)) ) {
		  assert(island == 0 || island == ivl_switch_island(sw));
		  island = ivl_switch_island(sw);
		  if (nex == ivl_switch_a(sw)) {
			nex_flags |= VVP_NEXUS_DATA_STR;
			island_input_flag = 0;
		  } else if (nex == ivl_switch_b(sw)) {
			nex_flags |= VVP_NEXUS_DATA_STR;
			island_input_flag = 0;
		  } else if (island_input_flag == -1) {
			assert(nex == ivl_switch_enable(sw));
			island_input_flag = 1;
		  }
	    }

	      /* Skip input only pins. */
	    if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
		&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
		  continue;

	      /* Mark the strength-aware flag if the driver can
		 generate values other than the standard "6"
		 strength. */
	    if (nexus_drive_is_strength_aware(nptr))
		  nex_flags |= VVP_NEXUS_DATA_STR;

	      /* Save this driver. */
	    if (ndrivers >= adrivers) {
		  adrivers += 4;
		  drivers = realloc(drivers, adrivers*sizeof(ivl_nexus_ptr_t));
	    }
	    drivers[ndrivers] = nptr;
	    ndrivers += 1;
      }

      if (island_input_flag < 0)
	    island_input_flag = 0;

	/* Save the nexus driver count in the nex_data. */
      assert(nex_data);
      nex_data->drivers_count = ndrivers;
      nex_data->flags |= nex_flags;

	/* If the nexus has no drivers, then send a constant HiZ or
	   0.0 into the net. */
      if (ndrivers == 0) {
	      /* For real nets put 0.0. */
	    if (signal_data_type_of_nexus(nex) == IVL_VT_REAL) {
		  nex_private = draw_Cr_to_string(0.0);
	    } else {
		  unsigned jdx, wid = width_of_nexus(nex);
		  char*tmp = malloc(wid + 5);
		  nex_private = tmp;
		  strcpy(tmp, "C4<");
		  tmp += strlen(tmp);
		  switch (res) {
		      case IVL_SIT_TRI:
		      case IVL_SIT_UWIRE:
			for (jdx = 0 ;  jdx < wid ;  jdx += 1)
			      *tmp++ = 'z';
			break;
		      case IVL_SIT_TRI0:
			for (jdx = 0 ;  jdx < wid ;  jdx += 1)
			      *tmp++ = '0';
			break;
		      case IVL_SIT_TRI1:
			for (jdx = 0 ;  jdx < wid ;  jdx += 1)
			      *tmp++ = '1';
			break;
		      default:
			assert(0);
		  }
		  *tmp++ = '>';
		  *tmp = 0;

		    /* Create an "open" driver to hold the HiZ. We
		       need to do this so that .nets have something to
		       hang onto. */
		  char buf[64];
		  snprintf(buf, sizeof buf, "o%p", nex);
		  fprintf(vvp_out, "%s .functor BUFZ %u, %s; HiZ drive\n",
			  buf, wid, nex_private);
		  nex_private = realloc(nex_private, strlen(buf)+1);
		  strcpy(nex_private, buf);
	    }

	    if (island) {
		  char*tmp2 = draw_island_port(island, island_input_flag, nex, nex_data, nex_private);
		  free(nex_private);
		  nex_private = tmp2;
	    }
	    assert(nex_data->net_input == 0);
	    nex_data->net_input = nex_private;
	    return;
      }

	/* A uwire is a tri with only one driver. */
      if (res == IVL_SIT_UWIRE) {
	    if (ndrivers > 1) {
		  display_multi_driver_error(nex, ndrivers, MDRV_UWIRE);
	    }
	    res = IVL_SIT_TRI;
      }

	/* If the nexus has exactly one driver, then simply draw
	   it. Note that this will *not* work if the nexus is not a
	   TRI type nexus. */
      if (ndrivers == 1 && res == IVL_SIT_TRI) {
	    ivl_signal_t path_sig = find_modpath(nex);
	    if (path_sig) {
		  char*nex_str = draw_net_input_drive(nex, drivers[0]);
		  char modpath_label[64];
		  snprintf(modpath_label, sizeof modpath_label,
			   "V_%p/m", path_sig);
		  nex_private = strdup(modpath_label);
		  draw_modpath(path_sig, nex_str);

	    } else {
		  nex_private = draw_net_input_drive(nex, drivers[0]);
	    }
	    if (island) {
		  char*tmp = draw_island_port(island, island_input_flag, nex, nex_data, nex_private);
		  free(nex_private);
		  nex_private = tmp;
	    }
	    assert(nex_data->net_input == 0);
	    nex_data->net_input = nex_private;
	    return;
      }

	/* We currently only support one driver on real nets. */
      if (ndrivers > 1 && signal_data_type_of_nexus(nex) == IVL_VT_REAL) {
	    display_multi_driver_error(nex, ndrivers, MDRV_REAL);
      }

      driver_labels = malloc(ndrivers * sizeof(char*));
      for (idx = 0; idx < ndrivers; idx += 1) {
            driver_labels[idx] = draw_net_input_drive(nex, drivers[idx]);
      }
      fprintf(vvp_out, "RS_%p .resolv %s", nex, resolv_type);
      for (idx = 0; idx < ndrivers; idx += 1) {
            fprintf(vvp_out, ", %s", driver_labels[idx]);
	    free(driver_labels[idx]);
      }
      fprintf(vvp_out, ";\n");
      free(driver_labels);

      snprintf(result, sizeof result, "RS_%p", nex);

      if (island)
	    nex_private = draw_island_port(island, island_input_flag, nex, nex_data, result);
      else
	    nex_private = strdup(result);

      assert(nex_data->net_input == 0);
      nex_data->net_input = nex_private;
}
Example #21
0
/*
 * All logic gates have inputs and outputs that match exactly in
 * width. For example, and AND gate with 4 bit inputs generates a 4
 * bit output, and all the inputs are 4 bits.
 */
static void show_logic(ivl_net_logic_t net)
{
      unsigned npins, idx;
      const char*name = ivl_logic_basename(net);
      ivl_drive_t drive0 = ivl_logic_drive0(net);
      ivl_drive_t drive1 = ivl_logic_drive1(net);

      switch (ivl_logic_type(net)) {
	  case IVL_LO_AND:
	    fprintf(out, "  and %s", name);
	    break;
	  case IVL_LO_BUF:
	    fprintf(out, "  buf %s", name);
	    break;
	  case IVL_LO_BUFIF0:
	    fprintf(out, "  bufif0 %s", name);
	    break;
	  case IVL_LO_BUFIF1:
	    fprintf(out, "  bufif1 %s", name);
	    break;
	  case IVL_LO_BUFT:
	    fprintf(out, "  buft %s", name);
	    break;
	  case IVL_LO_BUFZ:
	    fprintf(out, "  bufz %s", name);
	    break;
	  case IVL_LO_CMOS:
	    fprintf(out, "  cmos %s", name);
	    break;
	  case IVL_LO_NAND:
	    fprintf(out, "  nand %s", name);
	    break;
	  case IVL_LO_NMOS:
	    fprintf(out, "  nmos %s", name);
	    break;
	  case IVL_LO_NOR:
	    fprintf(out, "  nor %s", name);
	    break;
	  case IVL_LO_NOT:
	    fprintf(out, "  not %s", name);
	    break;
	  case IVL_LO_NOTIF0:
	    fprintf(out, "  notif0 %s", name);
	    break;
	  case IVL_LO_NOTIF1:
	    fprintf(out, "  notif1 %s", name);
	    break;
	  case IVL_LO_OR:
	    fprintf(out, "  or %s", name);
	    break;
	  case IVL_LO_PMOS:
	    fprintf(out, "  pmos %s", name);
	    break;
	  case IVL_LO_PULLDOWN:
	    fprintf(out, "  pulldown %s", name);
	    break;
	  case IVL_LO_PULLUP:
	    fprintf(out, "  pullup %s", name);
	    break;
	  case IVL_LO_RCMOS:
	    fprintf(out, "  rcmos %s", name);
	    break;
	  case IVL_LO_RNMOS:
	    fprintf(out, "  rnmos %s", name);
	    break;
	  case IVL_LO_RPMOS:
	    fprintf(out, "  rpmos %s", name);
	    break;
	  case IVL_LO_XNOR:
	    fprintf(out, "  xnor %s", name);
	    break;
	  case IVL_LO_XOR:
	    fprintf(out, "  xor %s", name);
	    break;

	  case IVL_LO_UDP:
	    fprintf(out, "  primitive<%s> %s",
		    ivl_udp_name(ivl_logic_udp(net)), name);
	    break;

	  default:
	    fprintf(out, "  unsupported gate<type=%d> %s", ivl_logic_type(net), name);
	    break;
      }

      fprintf(out, " <width=%u>\n", ivl_logic_width(net));

      fprintf(out, "    <Delays...>\n");
      if (ivl_logic_delay(net,0)) {
	    test_expr_is_delay(ivl_logic_delay(net,0));
	    show_expression(ivl_logic_delay(net,0), 6);
      }
      if (ivl_logic_delay(net,1)) {
	    test_expr_is_delay(ivl_logic_delay(net,1));
	    show_expression(ivl_logic_delay(net,1), 6);
      }
      if (ivl_logic_delay(net,2)) {
	    test_expr_is_delay(ivl_logic_delay(net,2));
	    show_expression(ivl_logic_delay(net,2), 6);
      }

      npins = ivl_logic_pins(net);

	/* Show the pins of the gate. Pin-0 is always the output, and
	   the remaining pins are the inputs. Inputs may be
	   unconnected, but if connected the nexus width must exactly
	   match the gate width. */
      for (idx = 0 ;  idx < npins ;  idx += 1) {
	    ivl_nexus_t nex = ivl_logic_pin(net, idx);

	    fprintf(out, "    %d: %p", idx, nex);
	    if (idx == 0)
		  fprintf(out, " <drive0/1 = %u/%u>", drive0, drive1);
	    fprintf(out, "\n");

	    if (nex == 0) {
		  if (idx == 0) {
			fprintf(out, "    0: ERROR: Pin 0 must not "
				"be unconnected\n");
			stub_errors += 1;
		  }
		  continue;
	    }

	    if (ivl_logic_width(net) != width_of_nexus(nex)) {
		  fprintf(out, "    %d: ERROR: Nexus width is %u\n",
			  idx, width_of_nexus(nex));
		  stub_errors += 1;
	    }
      }

	/* If this is an instance of a UDP, then check that the
	   instantiation is consistent with the definition. */
      if (ivl_logic_type(net) == IVL_LO_UDP) {
	    ivl_udp_t udp = ivl_logic_udp(net);
	    if (npins != 1+ivl_udp_nin(udp)) {
		  fprintf(out, "    ERROR: UDP %s expects %u inputs\n",
			  ivl_udp_name(udp), ivl_udp_nin(udp));
		  stub_errors += 1;
	    }

	      /* Add a reference to this udp definition. */
	    reference_udp_definition(udp);
      }

      npins = ivl_logic_attr_cnt(net);
      for (idx = 0 ;  idx < npins ;  idx += 1) {
	    ivl_attribute_t cur = ivl_logic_attr_val(net,idx);
	    switch (cur->type) {
		case IVL_ATT_VOID:
		  fprintf(out, "    %s\n", cur->key);
		  break;
		case IVL_ATT_NUM:
		  fprintf(out, "    %s = %ld\n", cur->key, cur->val.num);
		  break;
		case IVL_ATT_STR:
		  fprintf(out, "    %s = %s\n", cur->key, cur->val.str);
		  break;
	    }
      }
}