static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { ivl_expr_t sel_expr = ivl_expr_oper2(expr); ivl_expr_t sig_expr = ivl_expr_oper1(expr); ivl_select_type_t sel_type = ivl_expr_sel_type(expr); if (sel_expr) { unsigned width = ivl_expr_width(expr); ivl_expr_type_t type = ivl_expr_type(sig_expr); assert(width > 0); /* The compiler uses selects for some shifts. */ if (type != IVL_EX_NUMBER && type != IVL_EX_SIGNAL) { fprintf(vlog_out, "(" ); emit_select_name(scope, sig_expr, wid); fprintf(vlog_out, " >> " ); emit_scaled_expr(scope, sel_expr, 1, 0); fprintf(vlog_out, ")" ); } else { /* A constant/parameter must be zero based in 1364-1995 * so keep the compiler generated normalization. This * does not always work for selects before the parameter * since 1364-1995 does not support signed math. */ int msb = 1; int lsb = 0; if (type == IVL_EX_SIGNAL) { ivl_signal_t sig = ivl_expr_signal(sig_expr); msb = ivl_signal_msb(sig); lsb = ivl_signal_lsb(sig); } /* A bit select. */ if (width == 1) { emit_select_name(scope, sig_expr, wid); fprintf(vlog_out, "["); emit_scaled_expr(scope, sel_expr, msb, lsb); fprintf(vlog_out, "]"); } else { if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) { /* A constant part select. */ emit_select_name(scope, sig_expr, wid); emit_scaled_range(scope, sel_expr, width, msb, lsb); } else { /* An indexed part select. */ assert(sel_type != IVL_SEL_OTHER); emit_expr_ips(scope, sig_expr, sel_expr, sel_type, width, msb, lsb); } } } } else { // HERE: Should this sign extend if the expression is signed? emit_expr(scope, sig_expr, wid); } }
static void emit_stmt_lval_piece(ivl_scope_t scope, ivl_lval_t lval) { ivl_signal_t sig = ivl_lval_sig(lval); ivl_expr_t sel_expr; ivl_select_type_t sel_type; unsigned width = ivl_lval_width(lval); int msb, lsb; assert(width > 0); /* If there are no selects then just print the name. */ sel_expr = ivl_lval_part_off(lval); if (! sel_expr && (width == ivl_signal_width(sig))) { emit_stmt_lval_name(scope, lval, sig); return; } /* We have some kind of select. */ lsb = ivl_signal_lsb(sig); msb = ivl_signal_msb(sig); sel_type = ivl_lval_sel_type(lval); assert(sel_expr); /* A bit select. */ if (width == 1) { emit_stmt_lval_name(scope, lval, sig); fprintf(vlog_out, "["); emit_scaled_expr(scope, sel_expr, msb, lsb); fprintf(vlog_out, "]"); } else { /* A constant part select. */ if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) { emit_stmt_lval_name(scope, lval, sig); emit_scaled_range(scope, sel_expr, width, msb, lsb); /* An indexed part select. */ } else { assert(sel_type != IVL_SEL_OTHER); emit_stmt_lval_ips(scope, lval, sig, sel_expr, sel_type, width, msb, lsb); } } }
/* * This function draws a reg/int/variable in the scope. This is a very * simple device to draw as there are no inputs to connect so no need * to scan the nexus. We do have to account for the possibility that * the device is arrayed, though, by making a node for each array element. */ static void draw_reg_in_scope(ivl_signal_t sig) { int msb = ivl_signal_msb(sig); int lsb = ivl_signal_lsb(sig); const char*datatype_flag = ivl_signal_integer(sig) ? "/i" : ivl_signal_signed(sig)? "/s" : ""; const char*local_flag = ivl_signal_local(sig)? "*" : ""; switch (ivl_signal_data_type(sig)) { case IVL_VT_REAL: datatype_flag = "/real"; break; default: break; } /* If the reg objects are collected into an array, then first write out the .array record to declare the array indices. */ if (ivl_signal_dimensions(sig) > 0) { unsigned word_count = ivl_signal_array_count(sig); int last = ivl_signal_array_base(sig)+word_count-1; int first = ivl_signal_array_base(sig); fprintf(vvp_out, "v%p .array%s \"%s\", %d %d, %d %d;\n", sig, datatype_flag, vvp_mangle_name(ivl_signal_basename(sig)), last, first, msb, lsb); } else { fprintf(vvp_out, "v%p_0 .var%s %s\"%s\", %d %d;%s\n", sig, datatype_flag, local_flag, vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb, ivl_signal_local(sig)? " Local signal" : ""); } }
/* * This function draws a net. This is a bit more complicated as we * have to find an appropriate functor to connect to the input. */ static void draw_net_in_scope(ivl_signal_t sig) { int msb = ivl_signal_msb(sig); int lsb = ivl_signal_lsb(sig); const char*datatype_flag = ivl_signal_signed(sig)? "/s" : ""; const char*local_flag = ivl_signal_local(sig)? "*" : ""; unsigned iword; switch (ivl_signal_data_type(sig)) { case IVL_VT_REAL: datatype_flag = "/real"; break; default: break; } for (iword = 0 ; iword < ivl_signal_array_count(sig); iword += 1) { unsigned word_count = ivl_signal_array_count(sig); unsigned dimensions = ivl_signal_dimensions(sig); struct vvp_nexus_data*nex_data; /* Connect the pin of the signal to something. */ ivl_nexus_t nex = ivl_signal_nex(sig, iword); const char*driver = draw_net_input(nex); nex_data = (struct vvp_nexus_data*)ivl_nexus_get_private(nex); assert(nex_data); if (nex_data->net == 0) { int strength_aware_flag = 0; const char*vec8 = ""; if (nex_data->flags&VVP_NEXUS_DATA_STR) strength_aware_flag = 1; if (nex_data->drivers_count > 1) vec8 = "8"; if (strength_aware_flag) vec8 = "8"; if (iword == 0 && dimensions > 0) { int last = ivl_signal_array_base(sig) + word_count-1; int first = ivl_signal_array_base(sig); fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n", sig, vvp_mangle_name(ivl_signal_basename(sig)), last, first); } if (dimensions > 0) { /* If this is a word of an array, then use an array reference in place of the net name. */ fprintf(vvp_out, "v%p_%u .net%s%s v%p %u, %d %d, %s;" " %u drivers%s\n", sig, iword, vec8, datatype_flag, sig, iword, msb, lsb, driver, nex_data->drivers_count, strength_aware_flag?", strength-aware":""); } else { /* If this is an isolated word, it uses its own name. */ assert(word_count == 1); fprintf(vvp_out, "v%p_%u .net%s%s %s\"%s\", %d %d, %s;" " %u drivers%s\n", sig, iword, vec8, datatype_flag, local_flag, vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb, driver, nex_data->drivers_count, strength_aware_flag?", strength-aware":""); } nex_data->net = sig; nex_data->net_word = iword; } else if (dimensions > 0) { /* In this case, we have an alias to an existing signal array. this typically is an instance of port collapsing that the elaborator combined to discover that the entire array can be collapsed, so the word count for the signal and the alias *must* match. */ if (word_count == ivl_signal_array_count(nex_data->net)) { if (iword == 0) { fprintf(vvp_out, "v%p .array \"%s\", v%p; Alias to %s\n", sig, vvp_mangle_name(ivl_signal_basename(sig)), nex_data->net, ivl_signal_basename(nex_data->net)); } /* An alias for an individual word. */ } else { if (iword == 0) { int first = ivl_signal_array_base(sig); int last = first + word_count-1; fprintf(vvp_out, "v%p .array \"%s\", %d %d;\n", sig, vvp_mangle_name(ivl_signal_basename(sig)), last, first); } fprintf(vvp_out, "v%p_%u .alias%s v%p %u, %d %d, " "v%p_%u; Alias to %s\n", sig, iword, datatype_flag, sig, iword, msb, lsb, nex_data->net, nex_data->net_word, ivl_signal_basename(nex_data->net)); } } else { /* Finally, we may have an alias that is a word connected to another word. Again, this is a case of port collapsing. */ /* For the alias, create a different kind of node that refers to the alias source data instead of holding our own data. */ fprintf(vvp_out, "v%p_%u .alias%s \"%s\", %d %d, v%p_%u;\n", sig, iword, datatype_flag, vvp_mangle_name(ivl_signal_basename(sig)), msb, lsb, nex_data->net, nex_data->net_word); } } }
static void show_signal(ivl_signal_t net) { unsigned idx; const char*type = "?"; const char*port = ""; const char*data_type = "?"; const char*sign = ivl_signal_signed(net)? "signed" : "unsigned"; switch (ivl_signal_type(net)) { case IVL_SIT_REG: type = "reg"; break; case IVL_SIT_TRI: type = "tri"; break; case IVL_SIT_TRI0: type = "tri0"; break; case IVL_SIT_TRI1: type = "tri1"; break; case IVL_SIT_UWIRE: type = "uwire"; break; default: break; } switch (ivl_signal_port(net)) { case IVL_SIP_INPUT: port = "input "; break; case IVL_SIP_OUTPUT: port = "output "; break; case IVL_SIP_INOUT: port = "inout "; break; case IVL_SIP_NONE: break; } switch (ivl_signal_data_type(net)) { case IVL_VT_BOOL: data_type = "bool"; break; case IVL_VT_LOGIC: data_type = "logic"; break; case IVL_VT_REAL: data_type = "real"; break; default: data_type = "?data?"; break; } const char*discipline_txt = "NONE"; if (ivl_signal_discipline(net)) { ivl_discipline_t dis = ivl_signal_discipline(net); discipline_txt = ivl_discipline_name(dis); } for (idx = 0 ; idx < ivl_signal_array_count(net) ; idx += 1) { ivl_nexus_t nex = ivl_signal_nex(net, idx); fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] " "<width=%u%s> <discipline=%s> ", type, sign, port, data_type, ivl_signal_msb(net), ivl_signal_lsb(net), ivl_signal_basename(net), idx, ivl_signal_array_base(net)+idx, ivl_signal_width(net), ivl_signal_local(net)? ", local":"", discipline_txt); if (nex == NULL) { fprintf(out, "nexus=<virtual>\n"); continue; } else { fprintf(out, "nexus=%p\n", nex); } show_nexus_details(net, nex); } for (idx = 0 ; idx < ivl_signal_npath(net) ; idx += 1) { ivl_delaypath_t path = ivl_signal_path(net,idx); ivl_nexus_t nex = ivl_path_source(path); ivl_nexus_t con = ivl_path_condit(path); int posedge = ivl_path_source_posedge(path); int negedge = ivl_path_source_negedge(path); fprintf(out, " path %p", nex); if (posedge) fprintf(out, " posedge"); if (negedge) fprintf(out, " negedge"); if (con) fprintf(out, " (if %p)", con); else if (ivl_path_is_condit(path)) fprintf(out, " (ifnone)"); fprintf(out, " %" PRIu64 ",%" PRIu64 ",%" PRIu64 " %" PRIu64 ",%" PRIu64 ",%" PRIu64 " %" PRIu64 ",%" PRIu64 ",%" PRIu64 " %" PRIu64 ",%" PRIu64 ",%" PRIu64, ivl_path_delay(path, IVL_PE_01), ivl_path_delay(path, IVL_PE_10), ivl_path_delay(path, IVL_PE_0z), ivl_path_delay(path, IVL_PE_z1), ivl_path_delay(path, IVL_PE_1z), ivl_path_delay(path, IVL_PE_z0), ivl_path_delay(path, IVL_PE_0x), ivl_path_delay(path, IVL_PE_x1), ivl_path_delay(path, IVL_PE_1x), ivl_path_delay(path, IVL_PE_x0), ivl_path_delay(path, IVL_PE_xz), ivl_path_delay(path, IVL_PE_zx)); fprintf(out, " scope=%s\n", ivl_scope_name(ivl_path_scope(path))); } for (idx = 0 ; idx < ivl_signal_attr_cnt(net) ; idx += 1) { ivl_attribute_t atr = ivl_signal_attr_val(net, idx); switch (atr->type) { case IVL_ATT_STR: fprintf(out, " %s = %s\n", atr->key, atr->val.str); break; case IVL_ATT_NUM: fprintf(out, " %s = %ld\n", atr->key, atr->val.num); break; case IVL_ATT_VOID: fprintf(out, " %s\n", atr->key); break; } } }