Beispiel #1
0
/* 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);
}
Beispiel #2
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;
      }
}
Beispiel #3
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");
}
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
{
      unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
      ivl_net_const_t cptr;
      ivl_net_logic_t lptr;
      ivl_signal_t sptr;
      ivl_lpm_t lpm;

      lptr = ivl_nexus_ptr_log(nptr);
      if (lptr
	  && ((ivl_logic_type(lptr)==IVL_LO_BUFZ)||(ivl_logic_type(lptr)==IVL_LO_BUFT))
	  && (nptr_pin == 0))
	    do {
		  if (! can_elide_bufz(lptr, nptr))
			break;

		  return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
	    } while(0);

	/* If this is a pulldown device, then there is a single pin
	   that drives a constant value to the entire width of the
	   vector. The driver normally drives a pull0 value, so a C8<>
	   constant is appropriate, but if the drive is really strong,
	   then we can draw a C4<> constant instead. */
      if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
	    if (ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG) {
		  size_t result_len = ivl_logic_width(lptr) + 5;
		  char*result = malloc(result_len);
		  char*dp = result;
		  strcpy(dp, "C4<");
		  dp += strlen(dp);
		  str_repeat(dp, "0", ivl_logic_width(lptr));
		  dp += ivl_logic_width(lptr);
		  *dp++ = '>';
		  *dp = 0;
		  assert(dp >= result);
		  assert((unsigned)(dp - result) <= result_len);
		  return result;
	    } else {
		  char val[4];
		  size_t result_len = 3*ivl_logic_width(lptr) + 5;
		  char*result = malloc(result_len);
		  char*dp = result;

		  val[0] = "01234567"[ivl_nexus_ptr_drive0(nptr)];
		  val[1] = val[0];
		  val[2] = '0';
		  val[3] = 0;

		  strcpy(dp, "C8<");
		  dp += strlen(dp);
		  str_repeat(dp, val, ivl_logic_width(lptr));
		  dp += 3*ivl_logic_width(lptr);
		  *dp++ = '>';
		  *dp = 0;
		  assert(dp >= result);
		  assert((unsigned)(dp - result) <= result_len);
		  return result;
	    }
      }

      if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
	    char*result;
	    char tmp[32];
	    if (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG) {
		  size_t result_len = 5 + ivl_logic_width(lptr);
		  result = malloc(result_len);
		  char*dp = result;
		  strcpy(dp, "C4<");
		  dp += strlen(dp);
		  str_repeat(dp, "1", ivl_logic_width(lptr));
		  dp += ivl_logic_width(lptr);
		  *dp++ = '>';
		  *dp = 0;
		  assert(dp >= result);
		  assert((unsigned)(dp - result) <= result_len);

	    } else {
		  char val[4];
		  size_t result_len = 5 + 3*ivl_logic_width(lptr);
		  result = malloc(result_len);
		  char*dp = result;

		  val[0] = "01234567"[ivl_nexus_ptr_drive1(nptr)];
		  val[1] = val[0];
		  val[2] = '1';
		  val[3] = 0;

		  strcpy(dp, "C8<");
		  dp += strlen(dp);
		  str_repeat(dp, val, ivl_logic_width(lptr));
		  dp += 3*ivl_logic_width(lptr);
		  *dp++ = '>';
		  *dp = 0;
		  assert(dp >= result);
		  assert((unsigned)(dp - result) <= result_len);

	    }

	      /* Make the constant an argument to a BUFZ, which is
		 what we use to drive the PULLed value. */
	    fprintf(vvp_out, "L_%p .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n",
		    lptr, result);
	    snprintf(tmp, sizeof tmp, "L_%p", lptr);
	    result = realloc(result, strlen(tmp)+1);
	    strcpy(result, tmp);
	    return result;
      }

      if (lptr && (nptr_pin == 0)) {
	    char tmp[128];
	    snprintf(tmp, sizeof tmp, "L_%p", lptr);
	    return strdup(tmp);
      }

      sptr = ivl_nexus_ptr_sig(nptr);
      if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
	    char tmp[128];
	      /* Input is a .var. This device may be a non-zero pin
	         because it may be an array of reg vectors. */
	    snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);

	    if (ivl_signal_dimensions(sptr) > 0) {
		  fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
			  sptr, nptr_pin, sptr, nptr_pin);
	    }

	    return strdup(tmp);
      }

      cptr = ivl_nexus_ptr_con(nptr);
      if (cptr) {
	    char *result = 0;
	    ivl_expr_t d_rise, d_fall, d_decay;
            unsigned dly_width = 0;

	      /* Constants should have exactly 1 pin, with a literal value. */
	    assert(nptr_pin == 0);

	    switch (ivl_const_type(cptr)) {
		case IVL_VT_LOGIC:
		case IVL_VT_BOOL:
		case IVL_VT_STRING:
		  if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
		      && (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {

			result = draw_C4_to_string(cptr);

		  } else {
			result = draw_C8_to_string(cptr,
						   ivl_nexus_ptr_drive0(nptr),
						   ivl_nexus_ptr_drive1(nptr));
		  }
                  dly_width = ivl_const_width(cptr);
		  break;

		case IVL_VT_REAL:
		  result = draw_Cr_to_string(ivl_const_real(cptr));
                  dly_width = 0;
		  break;

		default:
		  assert(0);
		  break;
	    }

	    d_rise = ivl_const_delay(cptr, 0);
	    d_fall = ivl_const_delay(cptr, 1);
	    d_decay = ivl_const_delay(cptr, 2);

	      /* We have a delayed constant, so we need to build some code. */
	    if (d_rise != 0) {
		  char tmp[128];
		  fprintf(vvp_out, "L_%p/d .functor BUFT 1, %s, "
		                   "C4<0>, C4<0>, C4<0>;\n", cptr, result);
		  free(result);

		    /* Is this a fixed or variable delay? */
		  if (number_is_immediate(d_rise, 64, 0) &&
		      number_is_immediate(d_fall, 64, 0) &&
		      number_is_immediate(d_decay, 64, 0)) {

			assert(! number_is_unknown(d_rise));
			assert(! number_is_unknown(d_fall));
			assert(! number_is_unknown(d_decay));

			fprintf(vvp_out, "L_%p .delay %u "
				"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
			                 cptr, dly_width,
			                 get_number_immediate64(d_rise),
			                 get_number_immediate64(d_fall),
			                 get_number_immediate64(d_decay), cptr);

		  } else {
			ivl_signal_t sig;
			// We do not currently support calculating the decay
			// from the rise and fall variable delays.
			assert(d_decay != 0);
			assert(ivl_expr_type(d_rise) == IVL_EX_SIGNAL);
			assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL);
			assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL);

			fprintf(vvp_out, "L_%p .delay %u L_%p/d",
                                cptr, dly_width, cptr);

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

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

			sig = ivl_expr_signal(d_decay);
			assert(ivl_signal_dimensions(sig) == 0);
			fprintf(vvp_out, ", v%p_0;\n", sig);
		  }

		  snprintf(tmp, sizeof tmp, "L_%p", cptr);
		  result = strdup(tmp);

	    } else {
		  char tmp[64];
		  fprintf(vvp_out, "L_%p .functor BUFT 1, %s, "
			  "C4<0>, C4<0>, C4<0>;\n", cptr, result);
		  free(result);

		  snprintf(tmp, sizeof tmp, "L_%p", cptr);
		  result = strdup(tmp);
	    }

	    return result;
      }

      lpm = ivl_nexus_ptr_lpm(nptr);
      if (lpm) switch (ivl_lpm_type(lpm)) {

	  case IVL_LPM_FF:
	  case IVL_LPM_ABS:
	  case IVL_LPM_ADD:
	  case IVL_LPM_ARRAY:
	  case IVL_LPM_CAST_INT2:
	  case IVL_LPM_CAST_INT:
	  case IVL_LPM_CAST_REAL:
	  case IVL_LPM_CONCAT:
	  case IVL_LPM_CONCATZ:
	  case IVL_LPM_CMP_EEQ:
	  case IVL_LPM_CMP_EQ:
	  case IVL_LPM_CMP_GE:
	  case IVL_LPM_CMP_GT:
	  case IVL_LPM_CMP_NE:
	  case IVL_LPM_CMP_NEE:
	  case IVL_LPM_RE_AND:
	  case IVL_LPM_RE_OR:
	  case IVL_LPM_RE_XOR:
	  case IVL_LPM_RE_NAND:
	  case IVL_LPM_RE_NOR:
	  case IVL_LPM_RE_XNOR:
	  case IVL_LPM_SFUNC:
	  case IVL_LPM_SHIFTL:
	  case IVL_LPM_SHIFTR:
	  case IVL_LPM_SIGN_EXT:
	  case IVL_LPM_SUB:
	  case IVL_LPM_MULT:
	  case IVL_LPM_MUX:
	  case IVL_LPM_POW:
	  case IVL_LPM_DIVIDE:
	  case IVL_LPM_MOD:
	  case IVL_LPM_UFUNC:
	  case IVL_LPM_PART_VP:
	  case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
	  case IVL_LPM_REPEAT:
	    if (ivl_lpm_q(lpm) == nex) {
		  char tmp[128];
		  snprintf(tmp, sizeof tmp, "L_%p", lpm);
		  return strdup(tmp);
	    }
	    break;

      }

      fprintf(stderr, "vvp.tgt error: no input to nexus.\n");
      assert(0);
      return strdup("C<z>");
}
Beispiel #5
0
static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
{
      unsigned nptr_pin = ivl_nexus_ptr_pin(nptr);
      ivl_net_const_t cptr;
      ivl_net_logic_t lptr;
      ivl_signal_t sptr;
      ivl_lpm_t lpm;

      lptr = ivl_nexus_ptr_log(nptr);
      if (lptr
	  && ((ivl_logic_type(lptr)==IVL_LO_BUFZ)||(ivl_logic_type(lptr)==IVL_LO_BUFT))
	  && (nptr_pin == 0))
	    do {
		  if (! can_elide_bufz(lptr, nptr))
			break;

		  return strdup(draw_net_input(ivl_logic_pin(lptr, 1)));
	    } while(0);

      if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLDOWN)) {
	    return draw_net_pull(lptr, ivl_nexus_ptr_drive0(nptr), "0");
      }

      if (lptr && (ivl_logic_type(lptr) == IVL_LO_PULLUP)) {
	    return draw_net_pull(lptr, ivl_nexus_ptr_drive1(nptr), "1");
      }

      if (lptr && (nptr_pin == 0)) {
	    char tmp[128];
	    snprintf(tmp, sizeof tmp, "L_%p", lptr);
	    return strdup(tmp);
      }

      sptr = ivl_nexus_ptr_sig(nptr);
      if (sptr && (ivl_signal_type(sptr) == IVL_SIT_REG)) {
	    char tmp[128];
	      /* Input is a .var. This device may be a non-zero pin
	         because it may be an array of reg vectors. */
	    snprintf(tmp, sizeof tmp, "v%p_%u", sptr, nptr_pin);

	    if (ivl_signal_dimensions(sptr) > 0) {
		  fprintf(vvp_out, "v%p_%u .array/port v%p, %u;\n",
			  sptr, nptr_pin, sptr, nptr_pin);
	    }

	    return strdup(tmp);
      }

      cptr = ivl_nexus_ptr_con(nptr);
      if (cptr) {
	    char tmp[64];
	    char *result = 0;
	    ivl_expr_t d_rise, d_fall, d_decay;
            unsigned dly_width = 0;
	    char *dly;

	      /* Constants should have exactly 1 pin, with a literal value. */
	    assert(nptr_pin == 0);

	    switch (ivl_const_type(cptr)) {
		case IVL_VT_LOGIC:
		case IVL_VT_BOOL:
		case IVL_VT_STRING:
		  if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_STRONG)
		      && (ivl_nexus_ptr_drive1(nptr) == IVL_DR_STRONG)) {

			result = draw_C4_to_string(cptr);

		  } else {
			result = draw_C8_to_string(cptr,
						   ivl_nexus_ptr_drive0(nptr),
						   ivl_nexus_ptr_drive1(nptr));
		  }
                  dly_width = ivl_const_width(cptr);
		  break;

		case IVL_VT_REAL:
		  result = draw_Cr_to_string(ivl_const_real(cptr));
                  dly_width = 0;
		  break;

		default:
		  assert(0);
		  break;
	    }

	    d_rise = ivl_const_delay(cptr, 0);
	    d_fall = ivl_const_delay(cptr, 1);
	    d_decay = ivl_const_delay(cptr, 2);

	    dly = "";
	    if (d_rise != 0) {
		  draw_delay(cptr, dly_width, 0, d_rise, d_fall, d_decay);
		  dly = "/d";
	    }
	    fprintf(vvp_out, "L_%p%s .functor BUFT 1, %s, C4<0>, C4<0>, C4<0>;\n",
		    cptr, dly, result);
	    free(result);

	    snprintf(tmp, sizeof tmp, "L_%p", cptr);
	    return strdup(tmp);
      }

      lpm = ivl_nexus_ptr_lpm(nptr);
      if (lpm) switch (ivl_lpm_type(lpm)) {

	  case IVL_LPM_FF:
	  case IVL_LPM_LATCH:
	  case IVL_LPM_ABS:
	  case IVL_LPM_ADD:
	  case IVL_LPM_ARRAY:
	  case IVL_LPM_CAST_INT2:
	  case IVL_LPM_CAST_INT:
	  case IVL_LPM_CAST_REAL:
	  case IVL_LPM_CONCAT:
	  case IVL_LPM_CONCATZ:
	  case IVL_LPM_CMP_EEQ:
	  case IVL_LPM_CMP_EQ:
	  case IVL_LPM_CMP_WEQ:
	  case IVL_LPM_CMP_WNE:
	  case IVL_LPM_CMP_EQX:
	  case IVL_LPM_CMP_EQZ:
	  case IVL_LPM_CMP_GE:
	  case IVL_LPM_CMP_GT:
	  case IVL_LPM_CMP_NE:
	  case IVL_LPM_CMP_NEE:
	  case IVL_LPM_RE_AND:
	  case IVL_LPM_RE_OR:
	  case IVL_LPM_RE_XOR:
	  case IVL_LPM_RE_NAND:
	  case IVL_LPM_RE_NOR:
	  case IVL_LPM_RE_XNOR:
	  case IVL_LPM_SFUNC:
	  case IVL_LPM_SHIFTL:
	  case IVL_LPM_SHIFTR:
	  case IVL_LPM_SIGN_EXT:
	  case IVL_LPM_SUB:
	  case IVL_LPM_MULT:
	  case IVL_LPM_MUX:
	  case IVL_LPM_POW:
	  case IVL_LPM_DIVIDE:
	  case IVL_LPM_MOD:
	  case IVL_LPM_UFUNC:
	  case IVL_LPM_PART_VP:
	  case IVL_LPM_PART_PV: /* NOTE: This is only a partial driver. */
	  case IVL_LPM_REPEAT:
	  case IVL_LPM_SUBSTITUTE:
	    if (ivl_lpm_q(lpm) == nex) {
		  char tmp[128];
		  snprintf(tmp, sizeof tmp, "L_%p", lpm);
		  return strdup(tmp);
	    }
	    break;

      }

      fprintf(stderr, "vvp.tgt error: no input to nexus.\n");
      assert(0);
      return strdup("C<z>");
}
Beispiel #6
0
static void lpm_show_add(ivl_lpm_t net)
{
      unsigned idx;
      unsigned cell_width;
      char cellname[32];
      edif_cell_t cell;
      edif_cellref_t ref;
      edif_joint_t jnt;

      const char*type = "ADD";

      if (ivl_lpm_type(net) == IVL_LPM_SUB)
	    type = "SUB";

	/* Figure out the width of the cell. Normally, it is the LPM
	   width known by IVL. But if the top data input bits are
	   unconnected, then we really have a width one less, and we
	   can use the cout to fill out the output width. */
      cell_width = ivl_lpm_width(net);
      if ( (ivl_lpm_data(net,cell_width-1) == 0)
	   && (ivl_lpm_datab(net,cell_width-1) == 0) )
	    cell_width -= 1;

	/* Find the correct ADD/SUB device in the library, search by
	   name. If the device is not there, then create it and put it
	   in the library. */
      sprintf(cellname, "%s%u", type, cell_width);
      cell = edif_xlibrary_findcell(xlib, cellname);

      if (cell == 0) {
	    unsigned pins = cell_width * 3 + 1;

	    cell = edif_xcell_create(xlib, strdup(cellname), pins);

	    for (idx = 0 ;  idx < cell_width ;  idx += 1) {

		  sprintf(cellname, "Result%u", idx);
		  edif_cell_portconfig(cell, idx*3+0, strdup(cellname),
				       IVL_SIP_OUTPUT);

		  sprintf(cellname, "DataA%u", idx);
		  edif_cell_portconfig(cell, idx*3+1, strdup(cellname),
				       IVL_SIP_INPUT);

		  sprintf(cellname, "DataB%u", idx);
		  edif_cell_portconfig(cell, idx*3+2, strdup(cellname),
				       IVL_SIP_INPUT);
	    }

	    edif_cell_portconfig(cell, pins-1, "Cout", IVL_SIP_OUTPUT);

	    edif_cell_pstring(cell,  "LPM_Type",      "LPM_ADD_SUB");
	    edif_cell_pstring(cell,  "LPM_Direction", type);
	    edif_cell_pinteger(cell, "LPM_Width",     ivl_lpm_width(net));
      }

      ref = edif_cellref_create(edf, cell);

	/* Connect the pins of the instance to the nexa. Access the
	   cell pins by name. */
      for (idx = 0 ;  idx < cell_width ;  idx += 1) {
	    unsigned pin;

	    sprintf(cellname, "Result%u", idx);
	    pin = edif_cell_port_byname(cell, cellname);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
	    edif_add_to_joint(jnt, ref, pin);

	    sprintf(cellname, "DataA%u", idx);
	    pin = edif_cell_port_byname(cell, cellname);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
	    edif_add_to_joint(jnt, ref, pin);

	    sprintf(cellname, "DataB%u", idx);
	    pin = edif_cell_port_byname(cell, cellname);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
	    edif_add_to_joint(jnt, ref, pin);
      }

      if (cell_width < ivl_lpm_width(net)) {
	    unsigned pin = edif_cell_port_byname(cell, "Cout");

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, cell_width));
	    edif_add_to_joint(jnt, ref, pin);
      }
}
Beispiel #7
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;
}
Beispiel #8
0
/*
 * This function generates ADD/SUB devices for Virtex devices,
 * based on the documented implementations of ADD8/ADD16, etc., from
 * the Libraries Guide.
 *
 * Each slice of the ADD/SUB device is made from a LUT2 device, an
 * XORCY device that mixes with the LUT2 to make a full adder, and a
 * MUXCY_L to propagate the carry. The most significant slice does not
 * have a carry to propagate, so has no MUXCY_L.
 *
 * If the device is a wide adder, then the LUT2 devices are configured
 * to implement an XOR function and a zero is pumped into the least
 * significant carry input.
 *
 * If the device is really an adder, then the input is turned into an
 * XNOR, which takes a 1-s complement of the B input. Pump a 1 into
 * the LSB carry input to finish converting the B input into the 2s
 * complement.
 */
void virtex_add(ivl_lpm_t net)
{
      const char*ha_init = 0;
      edif_cellref_t lut, xorcy, muxcy, pad;
      edif_joint_t jnt;

      unsigned idx;

      if (ivl_lpm_width(net) < 2) {
	    xilinx_add(net);
	    return;
      }

      switch (ivl_lpm_type(net)) {
	    case IVL_LPM_ADD:
	    ha_init = "6";
	    break;
	  case IVL_LPM_SUB:
	    ha_init = "9";
	    break;
	  default:
	    assert(0);
      }

      assert(ivl_lpm_width(net) > 1);

      lut   = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
      xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib));
      muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib));
      edif_cellref_pstring(lut, "INIT", ha_init);

	/* The bottom carry-in takes a constant that primes the add or
	   subtract. */
      switch (ivl_lpm_type(net)) {
	  case IVL_LPM_ADD:
	    pad = edif_cellref_create(edf, cell_0);
	    break;

	  case IVL_LPM_SUB:
	    pad = edif_cellref_create(edf, cell_1);
	    break;

	  default:
	    assert(0);
      }

      jnt = edif_joint_create(edf);
      edif_add_to_joint(jnt, pad, 0);
      edif_add_to_joint(jnt, muxcy, MUXCY_CI);
      edif_add_to_joint(jnt, xorcy, XORCY_CI);

      jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
      edif_add_to_joint(jnt, xorcy, XORCY_O);

      jnt = edif_joint_create(edf);
      edif_add_to_joint(jnt, xorcy, XORCY_LI);
      edif_add_to_joint(jnt, muxcy, MUXCY_S);
      edif_add_to_joint(jnt, lut,   LUT_O);

      jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
      edif_add_to_joint(jnt, lut,   LUT_I0);
      edif_add_to_joint(jnt, muxcy, MUXCY_DI);

      jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
      edif_add_to_joint(jnt, lut, LUT_I1);

      for (idx = 1 ;  idx < ivl_lpm_width(net) ;  idx += 1) {
	    edif_cellref_t muxcy0 = muxcy;

	    lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
	    xorcy = edif_cellref_create(edf, xilinx_cell_xorcy(xlib));
	    edif_cellref_pstring(lut, "INIT", ha_init);

	      /* If this is the last bit, then there is no further
		 propagation in the carry chain, and I can skip the
		 carry mux MUXCY. */
	    if ((idx+1) < ivl_lpm_width(net))
		  muxcy = edif_cellref_create(edf, xilinx_cell_muxcy_l(xlib));
	    else
		  muxcy = 0;

	    jnt = edif_joint_create(edf);
	    edif_add_to_joint(jnt, muxcy0, MUXCY_O);
	    edif_add_to_joint(jnt, xorcy, XORCY_CI);
	    if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_CI);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
	    edif_add_to_joint(jnt, xorcy, XORCY_O);

	    jnt = edif_joint_create(edf);
	    edif_add_to_joint(jnt, xorcy, XORCY_LI);
	    if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_S);
	    edif_add_to_joint(jnt, lut,   LUT_O);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
	    edif_add_to_joint(jnt, lut,   LUT_I0);
	    if (muxcy) edif_add_to_joint(jnt, muxcy, MUXCY_DI);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
	    edif_add_to_joint(jnt, lut, LUT_I1);
      }

}
Beispiel #9
0
/*
 * This method handles both == and != operators, the identity
 * comparison operators.
 *
 * If the identity compare is applied to small enough input vectors,
 * it is shoved into a single LUT. Otherwise, it is strung out into a
 * row of LUT devices chained together by carry muxes. The output of
 * the comparison is the output of the last mux.
 *
 * When the compare is small, a LUT is generated with the appropriate
 * truth table to cause an == or != result.
 *
 * When the compare is too wide for a single LUT, then it is made into
 * a chain connected by a string of carry mux devices. Each LUT
 * implements == for up to two pairs of bits, even if the final output
 * is supposed to be !=. The LUT output is connected to an associated
 * MUX select input. The CO output of each muxcy is passed up to the
 * next higher order bits of the compare.
 *
 * For identity == compare, a != output from the LUT selects the DI
 * input of the muxcy, generating a 0 output that is passed up. Since
 * the next higher muxcy now gets a 0 input to both DI and CI, the
 * output of the next higher muxcy is guaranteed to be 0, and so on to
 * the final output of the carry chain. If the output from a LUT is ==,
 * then the CI input of the muxcy is selected and the truth of this
 * level depends on lower order bits. The least significant muxcy is
 * connected to GND and VCC so that its CO follows the least
 * significant LUT.
 *
 * Identity != is the same as == except that the output is
 * inverted. To get that effect without putting an inverter on the
 * output of the top muxcy pin CO (which would cost a LUT) the DI
 * inputs are all connected to VCC instead of GND, and the CI of the
 * least significant muxcy is connected to GND instead of VCC. The LUT
 * expressions for the chained compare are configured for ==, with the
 * changed CI/DI inputs performing the inversion.
 */
void virtex_eq(ivl_lpm_t net)
{
      edif_cellref_t lut, mux, mux_prev;
      edif_joint_t jnt, jnt_di;
      unsigned idx;

	/* True if I'm implementing CMP_EQ instead of CMP_NE */
      int eq = 1;

      assert(ivl_lpm_width(net) >= 1);

      if (ivl_lpm_type(net) == IVL_LPM_CMP_NE)
	    eq = 0;

      switch (ivl_lpm_width(net)) {

	  case 1:
	    lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
	    edif_cellref_pstring(lut, "INIT", eq? "9" : "6");

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
	    edif_add_to_joint(jnt, lut, LUT_O);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
	    edif_add_to_joint(jnt, lut, LUT_I0);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
	    edif_add_to_joint(jnt, lut, LUT_I1);
	    return;

	  case 2:
	    lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
	    edif_cellref_pstring(lut, "INIT", eq? "9009" : "6FF6");

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
	    edif_add_to_joint(jnt, lut, LUT_O);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 0));
	    edif_add_to_joint(jnt, lut, LUT_I0);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 0));
	    edif_add_to_joint(jnt, lut, LUT_I1);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, 1));
	    edif_add_to_joint(jnt, lut, LUT_I2);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, 1));
	    edif_add_to_joint(jnt, lut, LUT_I3);
	    return;

	  default:
	    { edif_cellref_t di;
	      di = edif_cellref_create(edf, eq? cell_0 : cell_1);
	      jnt_di = edif_joint_create(edf);
	      edif_add_to_joint(jnt_di, di, 0);
	    }

	    mux_prev = 0;
	    for (idx = 0 ;  idx < ivl_lpm_width(net) ;  idx += 2) {
		  int subwid = 2;
		  if ((idx + 1) == ivl_lpm_width(net))
			subwid = 1;

		  mux = edif_cellref_create(edf, xilinx_cell_muxcy(xlib));
		  if (subwid == 2) {
			lut = edif_cellref_create(edf, xilinx_cell_lut4(xlib));
			edif_cellref_pstring(lut, "INIT", "9009");
		  } else {
			lut = edif_cellref_create(edf, xilinx_cell_lut2(xlib));
			edif_cellref_pstring(lut, "INIT", "9");
		  }

		  jnt = edif_joint_create(edf);
		  edif_add_to_joint(jnt, lut, LUT_O);
		  edif_add_to_joint(jnt, mux, MUXCY_S);

		  jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
		  edif_add_to_joint(jnt, lut, LUT_I0);

		  jnt = edif_joint_of_nexus(edf, ivl_lpm_datab(net, idx));
		  edif_add_to_joint(jnt, lut, LUT_I1);

		  if (subwid > 1) {
			jnt = edif_joint_of_nexus(edf,
					       ivl_lpm_data(net, idx+1));
			edif_add_to_joint(jnt, lut, LUT_I2);

			jnt = edif_joint_of_nexus(edf,
					       ivl_lpm_datab(net, idx+1));
			edif_add_to_joint(jnt, lut, LUT_I3);
		  }

		  edif_add_to_joint(jnt_di, mux, MUXCY_DI);

		  if (mux_prev) {
			jnt = edif_joint_create(edf);
			edif_add_to_joint(jnt, mux, MUXCY_CI);
			edif_add_to_joint(jnt, mux_prev, MUXCY_O);
		  } else {
			edif_cellref_t ci;
			ci = edif_cellref_create(edf, eq? cell_1 : cell_0);
			jnt = edif_joint_create(edf);
			edif_add_to_joint(jnt, ci, 0);
			edif_add_to_joint(jnt, mux, MUXCY_CI);
		  }

		  mux_prev = mux;
	    }

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, 0));
	    edif_add_to_joint(jnt, mux_prev, MUXCY_O);
	    return;
      }
}
Beispiel #10
0
/*
 * The generic == comparator uses EQN records to generate 2-bit
 * comparators, that are then connected together by a wide AND gate.
 */
static void generic_show_cmp_eq(ivl_lpm_t net)
{
    ivl_nexus_t nex;
    unsigned idx;
    char name[1024];
    /* Make this many dual pair comparators, and */
    unsigned deqn = ivl_lpm_width(net) / 2;
    /* Make this many single pair comparators. */
    unsigned seqn = ivl_lpm_width(net) % 2;

    xnf_mangle_lpm_name(net, name, sizeof name);

    for (idx = 0 ;  idx < deqn ;  idx += 1) {
        fprintf(xnf, "SYM, %s/CD%u, EQN, "
                "EQN=(~((I0 @ I1) + (I2 @ I3)))\n",
                name, idx);

        fprintf(xnf, "    PIN, O, O, %s/CDO%u\n", name, idx);

        nex = ivl_lpm_data(net, 2*idx);
        xnf_draw_pin(nex, "I0", 'I');
        nex = ivl_lpm_datab(net, 2*idx);
        xnf_draw_pin(nex, "I1", 'I');

        nex = ivl_lpm_data(net, 2*idx+1);
        xnf_draw_pin(nex, "I2", 'I');
        nex = ivl_lpm_datab(net, 2*idx+1);
        xnf_draw_pin(nex, "I3", 'I');

        fprintf(xnf, "END\n");
    }

    if (seqn != 0) {
        fprintf(xnf, "SYM, %s/CT, XNOR, LIBVER=2.0.0\n", name);

        fprintf(xnf, "    PIN, O, O, %s/CTO\n", name);

        nex = ivl_lpm_data(net, 2*deqn);
        xnf_draw_pin(nex, "I0", 'I');

        nex = ivl_lpm_datab(net, 2*deqn);
        xnf_draw_pin(nex, "I1", 'I');

        fprintf(xnf, "END\n");
    }

    if (ivl_lpm_type(net) == IVL_LPM_CMP_EQ)
        fprintf(xnf, "SYM, %s/OUT, AND, LIBVER=2.0.0\n", name);
    else
        fprintf(xnf, "SYM, %s/OUT, NAND, LIBVER=2.0.0\n", name);

    nex = ivl_lpm_q(net, 0);
    xnf_draw_pin(nex, "O", 'O');

    for (idx = 0 ;  idx < deqn ;  idx += 1)
        fprintf(xnf, "    PIN, I%u, I, %s/CDO%u\n", idx, name, idx);

    for (idx = 0 ;  idx < seqn ;  idx += 1)
        fprintf(xnf, "    PIN, I%u, I, %s/CTO\n", deqn+idx, name);

    fprintf(xnf, "END\n");
}
Beispiel #11
0
static void draw_lpm_in_scope(ivl_lpm_t net)
{
      switch (ivl_lpm_type(net)) {

	  case IVL_LPM_ABS:
	    draw_lpm_abs(net);
	    return;

	  case IVL_LPM_CAST_INT:
	    draw_lpm_cast_int(net);
	    return;

	  case IVL_LPM_CAST_REAL:
	    draw_lpm_cast_real(net);
	    return;

	  case IVL_LPM_ADD:
	  case IVL_LPM_SUB:
	  case IVL_LPM_MULT:
	  case IVL_LPM_DIVIDE:
	  case IVL_LPM_MOD:
	  case IVL_LPM_POW:
	    draw_lpm_add(net);
	    return;

	  case IVL_LPM_ARRAY:
	    draw_lpm_array(net);
	    return;

	  case IVL_LPM_PART_VP:
	    draw_lpm_part(net);
	    return;

	  case IVL_LPM_PART_PV:
	    draw_lpm_part_pv(net);
	    return;

	  case IVL_LPM_CONCAT:
	    draw_lpm_concat(net);
	    return;

	  case IVL_LPM_FF:
	    draw_lpm_ff(net);
	    return;

	  case IVL_LPM_CMP_EEQ:
	  case IVL_LPM_CMP_EQ:
	  case IVL_LPM_CMP_GE:
	  case IVL_LPM_CMP_GT:
	  case IVL_LPM_CMP_NE:
	  case IVL_LPM_CMP_NEE:
	    draw_lpm_cmp(net);
	    return;

	  case IVL_LPM_MUX:
	    draw_lpm_mux(net);
	    return;

	  case IVL_LPM_RE_AND:
	    draw_lpm_re(net, "and");
	    return;
	  case IVL_LPM_RE_OR:
	    draw_lpm_re(net, "or");
	    return;
	  case IVL_LPM_RE_XOR:
	    draw_lpm_re(net, "xor");
	    return;
	  case IVL_LPM_RE_NAND:
	    draw_lpm_re(net, "nand");
	    return;
	  case IVL_LPM_RE_NOR:
	    draw_lpm_re(net, "nor");
	    return;
	  case IVL_LPM_RE_XNOR:
	    draw_lpm_re(net, "xnor");
	    return;

	  case IVL_LPM_REPEAT:
	    draw_lpm_repeat(net);
	    return;

	  case IVL_LPM_SHIFTL:
	  case IVL_LPM_SHIFTR:
	    draw_lpm_shiftl(net);
	    return;

	  case IVL_LPM_SIGN_EXT:
	    draw_lpm_sign_ext(net);
	    return;

	  case IVL_LPM_SFUNC:
	    draw_lpm_sfunc(net);
	    return;

	  case IVL_LPM_UFUNC:
	    draw_lpm_ufunc(net);
	    return;

	  default:
	    fprintf(stderr, "XXXX LPM not supported: %s.%s\n",
		    ivl_scope_name(ivl_lpm_scope(net)), ivl_lpm_basename(net));
      }
}
Beispiel #12
0
static void draw_lpm_cmp(ivl_lpm_t net)
{
      const char*src_table[2];
      unsigned width;
      const char*type = "";
      const char*signed_string = ivl_lpm_signed(net)? ".s" : "";
      ivl_variable_type_t dta = data_type_of_nexus(ivl_lpm_data(net,0));
      ivl_variable_type_t dtb = data_type_of_nexus(ivl_lpm_data(net,1));
      ivl_variable_type_t dtc = IVL_VT_LOGIC;
      const char*dly;

      if (dta == IVL_VT_REAL || dtb == IVL_VT_REAL)
	    dtc = IVL_VT_REAL;

      width = ivl_lpm_width(net);

      switch (ivl_lpm_type(net)) {
	  case IVL_LPM_CMP_EEQ:
	    assert(dtc != IVL_VT_REAL); /* Should never get here! */
	    type = "eeq";
	    signed_string = "";
	    break;
	  case IVL_LPM_CMP_EQ:
	    if (dtc == IVL_VT_REAL)
		  type = "eq.r";
	    else
		  type = "eq";
	    signed_string = "";
	    break;
	  case IVL_LPM_CMP_GE:
	    if (dtc == IVL_VT_REAL) {
		  type = "ge.r";
		  signed_string = "";
	    } else
		  type = "ge";
	    break;
	  case IVL_LPM_CMP_GT:
	    if (dtc == IVL_VT_REAL) {
		  type = "gt.r";
		  signed_string = "";
	    } else
		  type = "gt";
	    break;
	  case IVL_LPM_CMP_NE:
	    if (dtc == IVL_VT_REAL)
		  type = "ne.r";
	    else
		  type = "ne";
	    signed_string = "";
	    break;
	  case IVL_LPM_CMP_NEE:
	    assert(dtc != IVL_VT_REAL); /* Should never get here! */
	    type = "nee";
	    signed_string = "";
	    break;
	  default:
	    assert(0);
      }

      draw_lpm_data_inputs(net, 0, 2, src_table);

      dly = draw_lpm_output_delay(net);

      fprintf(vvp_out, "L_%p%s .cmp/%s%s %u, %s, %s;\n",
	      net, dly, type, signed_string, width,
	      src_table[0], src_table[1]);
}
Beispiel #13
0
static void draw_lpm_add(ivl_lpm_t net)
{
      const char*src_table[2];
      unsigned width;
      const char*type = "";
      ivl_variable_type_t dta = data_type_of_nexus(ivl_lpm_data(net,0));
      ivl_variable_type_t dtb = data_type_of_nexus(ivl_lpm_data(net,1));
      ivl_variable_type_t dto = IVL_VT_LOGIC;
      const char*dly;

      if (dta == IVL_VT_REAL || dtb == IVL_VT_REAL)
	    dto = IVL_VT_REAL;

      width = ivl_lpm_width(net);

      switch (ivl_lpm_type(net)) {
	  case IVL_LPM_ADD:
	    if (dto == IVL_VT_REAL)
		  type = "sum.r";
	    else
		  type = "sum";
	    break;
	  case IVL_LPM_SUB:
	    if (dto == IVL_VT_REAL)
		  type = "sub.r";
	    else
		  type = "sub";
	    break;
	  case IVL_LPM_MULT:
	    if (dto == IVL_VT_REAL)
		  type = "mult.r";
	    else
		  type = "mult";
	    break;
	  case IVL_LPM_DIVIDE:
	    if (dto == IVL_VT_REAL)
		  type = "div.r";
	    else if (ivl_lpm_signed(net))
		  type = "div.s";
	    else
		  type = "div";
	    break;
	  case IVL_LPM_MOD:
	    if (dto == IVL_VT_REAL)
		  type = "mod.r";
	    else if (ivl_lpm_signed(net))
		  type = "mod.s";
	    else
		  type = "mod";
	    break;
	  case IVL_LPM_POW:
	    if (dto == IVL_VT_REAL)
		  type = "pow.r";
	    else if (ivl_lpm_signed(net))
		  type = "pow.s";
	    else
		  type = "pow";
	    break;
	  default:
	    assert(0);
      }

      draw_lpm_data_inputs(net, 0, 2, src_table);

      dly = draw_lpm_output_delay(net);

      fprintf(vvp_out, "L_%p%s .arith/%s %u, %s, %s;\n",
	      net, dly, type, width, src_table[0], src_table[1]);
}
Beispiel #14
0
static void show_lpm(ivl_lpm_t net)
{

      switch (ivl_lpm_type(net)) {

	  case IVL_LPM_ABS:
	    show_lpm_abs(net);
	    break;

	  case IVL_LPM_ADD:
	    show_lpm_add(net);
	    break;

	  case IVL_LPM_ARRAY:
	    show_lpm_array(net);
	    break;

	  case IVL_LPM_CAST_INT:
	    show_lpm_cast_int(net);
	    break;

	  case IVL_LPM_CAST_REAL:
	    show_lpm_cast_real(net);
	    break;

	  case IVL_LPM_DIVIDE:
	    show_lpm_divide(net);
	    break;

	  case IVL_LPM_CMP_EEQ:
	  case IVL_LPM_CMP_NEE:
	    show_lpm_cmp_eeq(net);
	    break;

	  case IVL_LPM_FF:
	    show_lpm_ff(net);
	    break;

	  case IVL_LPM_CMP_GE:
	    show_lpm_cmp_ge(net);
	    break;

	  case IVL_LPM_CMP_GT:
	    show_lpm_cmp_gt(net);
	    break;

	  case IVL_LPM_CMP_NE:
	    show_lpm_cmp_ne(net);
	    break;

	  case IVL_LPM_CONCAT:
	    show_lpm_concat(net);
	    break;

	  case IVL_LPM_RE_AND:
	  case IVL_LPM_RE_NAND:
	  case IVL_LPM_RE_NOR:
	  case IVL_LPM_RE_OR:
	  case IVL_LPM_RE_XOR:
	  case IVL_LPM_RE_XNOR:
	    show_lpm_re(net);
	    break;

	  case IVL_LPM_SHIFTL:
	    show_lpm_shift(net, "L");
	    break;

	  case IVL_LPM_SIGN_EXT:
	    show_lpm_sign_ext(net);
	    break;

	  case IVL_LPM_SHIFTR:
	    show_lpm_shift(net, "R");
	    break;

	  case IVL_LPM_SUB:
	    show_lpm_sub(net);
	    break;

	  case IVL_LPM_MOD:
	    show_lpm_mod(net);
	    break;

	  case IVL_LPM_MULT:
	    show_lpm_mult(net);
	    break;

	  case IVL_LPM_MUX:
	    show_lpm_mux(net);
	    break;

	  case IVL_LPM_PART_VP:
	  case IVL_LPM_PART_PV:
	    show_lpm_part(net);
	    break;

	  case IVL_LPM_REPEAT:
	    show_lpm_repeat(net);
	    break;

	  case IVL_LPM_SFUNC:
	    show_lpm_sfunc(net);
	    break;

	  case IVL_LPM_UFUNC:
	    show_lpm_ufunc(net);
	    break;

	  default:
	    fprintf(out, "  LPM(%d) %s: <width=%u, signed=%d>\n",
		    ivl_lpm_type(net),
		    ivl_lpm_basename(net),
		    ivl_lpm_width(net),
		    ivl_lpm_signed(net));
      }
}
Beispiel #15
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);
      }
}