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)); } } }
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; }
void draw_switch_in_scope(ivl_switch_t sw) { ivl_island_t island; ivl_nexus_t nex_a, nex_b, enable; const char*str_a, *str_b, *str_e; ivl_expr_t rise_exp = ivl_switch_delay(sw, 0); ivl_expr_t fall_exp = ivl_switch_delay(sw, 1); ivl_expr_t decay_exp= ivl_switch_delay(sw, 2); if ((rise_exp || fall_exp || decay_exp) && (!number_is_immediate(rise_exp, 64, 0) || number_is_unknown(rise_exp) || !number_is_immediate(fall_exp, 64, 0) || number_is_unknown(fall_exp) || !number_is_immediate(decay_exp, 64, 0) || number_is_unknown(decay_exp))) { fprintf(stderr, "%s:%u: error: Invalid tranif delay expression.\n", ivl_switch_file(sw), ivl_switch_lineno(sw)); vvp_errors += 1; } island = ivl_switch_island(sw); if (ivl_island_flag_test(island, 0) == 0) draw_tran_island(island); nex_a = ivl_switch_a(sw); assert(nex_a); str_a = draw_island_net_input(island, nex_a); nex_b = ivl_switch_b(sw); assert(nex_b); str_b = draw_island_net_input(island, nex_b); enable = ivl_switch_enable(sw); str_e = 0; char str_e_buf[4 + 2*sizeof(void*)]; if (enable && rise_exp) { assert(fall_exp && decay_exp); /* If the enable has a delay, then generate a .delay node to delay the input by the specified amount. Do the delay outside of the island so that the island processing doesn't have to deal with it. */ const char*raw = draw_net_input(enable); snprintf(str_e_buf, sizeof str_e_buf, "p%p", sw); str_e = str_e_buf; fprintf(vvp_out, "%s/d .delay 1 " "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n", str_e, get_number_immediate64(rise_exp), get_number_immediate64(fall_exp), get_number_immediate64(decay_exp), raw); fprintf(vvp_out, "%s .import I%p, %s/d;\n", str_e, island, str_e); } else if (enable) { str_e = draw_island_net_input(island, enable); } switch (ivl_switch_type(sw)) { case IVL_SW_TRAN: fprintf(vvp_out, " .tran"); break; case IVL_SW_TRANIF0: fprintf(vvp_out, " .tranif0"); break; case IVL_SW_TRANIF1: fprintf(vvp_out, " .tranif1"); break; case IVL_SW_TRAN_VP: fprintf(vvp_out, " .tranvp %u %u %u,", ivl_switch_width(sw), ivl_switch_part(sw), ivl_switch_offset(sw)); break; default: fprintf(stderr, "%s:%u: tgt-vvp sorry: resistive switch modeling " "is not currently supported.\n", ivl_switch_file(sw), ivl_switch_lineno(sw)); vvp_errors += 1; return; } fprintf(vvp_out, " I%p, %s %s", island, str_a, str_b); if (enable) { fprintf(vvp_out, ", %s", str_e); } fprintf(vvp_out, ";\n"); }