From 78f8976c85c27ca8abd73d3efd6acf32bd4af1a5 Mon Sep 17 00:00:00 2001 From: mole99 Date: Thu, 13 Jul 2023 12:32:49 +0200 Subject: [PATCH 01/14] Parse port and index --- vpi/sdf_parse.y | 32 +++++++++++++++++++++++--------- vpi/sdf_parse_priv.h | 5 ----- vpi/sdf_priv.h | 10 ++++++++++ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/vpi/sdf_parse.y b/vpi/sdf_parse.y index a1fefcb81..9b652e752 100644 --- a/vpi/sdf_parse.y +++ b/vpi/sdf_parse.y @@ -42,6 +42,7 @@ char sdf_use_hchar = '.'; struct sdf_delay_s delay; struct port_with_edge_s port_with_edge; struct sdf_delval_list_s delval_list; + struct interconnect_port_s interconnect_port; }; %token K_ABSOLUTE K_CELL K_CELLTYPE K_COND K_CONDELSE K_DATE K_DELAYFILE @@ -63,7 +64,9 @@ char sdf_use_hchar = '.'; %type celltype %type cell_instance %type hierarchical_identifier -%type port port_instance port_interconnect +%type port port_instance + +%type port_interconnect %type signed_real_number %type delval rvalue_opt rvalue rtriple signed_real_number_opt @@ -338,8 +341,13 @@ del_def { if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: " "INTERCONNECT not supported.\n", sdf_parse_path, @2.first_line); - free($3); - free($4); + + vpi_printf("SDF INFO: %s:%d: " + "port1 name = %s index = %d, port2 name = %s index = %d", + sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index); + + free($3.name); + free($4.name); } | '(' K_INTERCONNECT error ')' { vpi_printf("SDF ERROR: %s:%d: Invalid/malformed INTERCONNECT\n", @@ -396,13 +404,13 @@ cond_edge_identifier timing_check_condition : port_interconnect - { free($1); } + { free($1.name); } | '~' port_interconnect - { free($2); } + { free($2.name); } | '!' port_interconnect - { free($2); } + { free($2.name); } | port_interconnect equality_operator scalar_constant - { free($1); } + { free($1.name); } ; /* This is not complete! */ @@ -458,9 +466,15 @@ port /* Since INTERCONNECT is ignored we can also ignore a vector bit. */ port_interconnect : hierarchical_identifier - { $$ = $1; } + { + struct interconnect_port_s tmp = {$1, -1}; + $$ = tmp; + } | hierarchical_identifier '[' INTEGER ']' - { $$ = $1;} + { + struct interconnect_port_s tmp = {$1, $3}; + $$ = tmp; + } ; port_edge diff --git a/vpi/sdf_parse_priv.h b/vpi/sdf_parse_priv.h index 80a9f99ec..da35f525b 100644 --- a/vpi/sdf_parse_priv.h +++ b/vpi/sdf_parse_priv.h @@ -24,11 +24,6 @@ * used to share declarations between the parse and the lexor. */ -struct port_with_edge_s { - int vpi_edge; - char*string_val; -}; - /* Path to source for error messages. */ extern const char*sdf_parse_path; diff --git a/vpi/sdf_priv.h b/vpi/sdf_priv.h index 8baa386d3..62b684d4c 100644 --- a/vpi/sdf_priv.h +++ b/vpi/sdf_priv.h @@ -48,6 +48,16 @@ struct sdf_delval_list_s { struct sdf_delay_s val[12]; }; +struct port_with_edge_s { + int vpi_edge; + char*string_val; +}; + +struct interconnect_port_s { + char* name; + int index; // -1 for whole vector +}; + extern void sdf_select_instance(const char*celltype, const char*inst, const int sdf_lineno); extern void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, From 7beadb92f8811b24e4c50e50c2bb807dea9da8d6 Mon Sep 17 00:00:00 2001 From: mole99 Date: Wed, 19 Jul 2023 15:02:20 +0200 Subject: [PATCH 02/14] Framework of the INTERCONNECT implementation --- ivtest/gold/br_gh889-vlog95.gold | 1 - ivtest/gold/br_gh889.gold | 1 - ivtest/gold/sdf_header-vvp-stdout.gold | 1 + vpi/sdf_parse.y | 19 +- vpi/sdf_priv.h | 5 + vpi/sys_sdf.c | 172 +++++++++--- vpi_user.h | 2 + vvp/delay.cc | 349 +++++++++++++++++++++++++ vvp/delay.h | 30 +++ vvp/vpi_priv.cc | 155 +++++++++++ vvp/vpi_priv.h | 61 +++++ vvp/vpi_scope.cc | 26 +- vvp/vvp.def | 1 + 13 files changed, 756 insertions(+), 67 deletions(-) diff --git a/ivtest/gold/br_gh889-vlog95.gold b/ivtest/gold/br_gh889-vlog95.gold index d914ee6c7..d9789e479 100644 --- a/ivtest/gold/br_gh889-vlog95.gold +++ b/ivtest/gold/br_gh889-vlog95.gold @@ -1,4 +1,3 @@ -SDF WARNING: ivltests/br_gh889.sdf:18: loaded from vlog95.v:17: Wildcard cell instance specification (*) currently not supported. 0 A=x, B=x, Q=x 10 A=1, B=1, Q=x 11 A=1, B=1, Q=0 diff --git a/ivtest/gold/br_gh889.gold b/ivtest/gold/br_gh889.gold index fda02b9fb..d9789e479 100644 --- a/ivtest/gold/br_gh889.gold +++ b/ivtest/gold/br_gh889.gold @@ -1,4 +1,3 @@ -SDF WARNING: ivltests/br_gh889.sdf:18: loaded from ./ivltests/br_gh889.v:21: Wildcard cell instance specification (*) currently not supported. 0 A=x, B=x, Q=x 10 A=1, B=1, Q=x 11 A=1, B=1, Q=0 diff --git a/ivtest/gold/sdf_header-vvp-stdout.gold b/ivtest/gold/sdf_header-vvp-stdout.gold index fc0185ed4..de3b4d965 100644 --- a/ivtest/gold/sdf_header-vvp-stdout.gold +++ b/ivtest/gold/sdf_header-vvp-stdout.gold @@ -1,3 +1,4 @@ +SDF INFO: Loading ivltests/sdf_header.sdf from ivltests/sdf_header.v:6 SDF INFO: ivltests/sdf_header.sdf:2: Version: 3.0 SDF INFO: ivltests/sdf_header.sdf:3: Design: test SDF INFO: ivltests/sdf_header.sdf:4: Date: Wed Mar 8 12:34:56 2023 diff --git a/vpi/sdf_parse.y b/vpi/sdf_parse.y index 9b652e752..5187a0d80 100644 --- a/vpi/sdf_parse.y +++ b/vpi/sdf_parse.y @@ -160,15 +160,15 @@ program_version hierarchy_divider : '(' K_DIVIDER '.' ')' { sdf_use_hchar = '.'; - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar); } | '(' K_DIVIDER '/' ')' { sdf_use_hchar = '/'; - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar); } | '(' K_DIVIDER HCHAR ')' { /* sdf_use_hchar no-change */ - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar); } ; @@ -198,9 +198,8 @@ process temperature : '(' K_TEMPERATURE rtriple ')' { /* The value must be defined. */ - if (! $3.defined) { - vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", sdf_parse_path, @1.first_line); - } + if (! $3.defined) vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", + sdf_parse_path, @1.first_line); else if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n", sdf_parse_path, @2.first_line, $3.value); } @@ -342,9 +341,11 @@ del_def "INTERCONNECT not supported.\n", sdf_parse_path, @2.first_line); - vpi_printf("SDF INFO: %s:%d: " - "port1 name = %s index = %d, port2 name = %s index = %d", - sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: INTERCONNECT with " + "port1 = %s index = %d, port2 = %s index = %d\n", + sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index); + + sdf_interconnect_delays($3, $4, &$5, @2.first_line); free($3.name); free($4.name); diff --git a/vpi/sdf_priv.h b/vpi/sdf_priv.h index 62b684d4c..7be638cf8 100644 --- a/vpi/sdf_priv.h +++ b/vpi/sdf_priv.h @@ -64,4 +64,9 @@ extern void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, const struct sdf_delval_list_s*delval, const int sdf_lineno); +extern void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconnect_port_s port2, + const struct sdf_delval_list_s*delval_list, + const int sdf_lineno); + #endif /* IVL_sdf_priv_h */ + diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 85bc491d7..8426f987c 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -76,8 +76,9 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf /* Test for wildcard character */ if (cellinst == NULL) { - sdf_warn_file_line(sdf_lineno); - vpi_printf("Wildcard cell instance specification (*) currently not supported.\n"); + if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: sorry: " + "Wildcard cell instance specification (*) currently not supported.\n", + sdf_fname, sdf_lineno); sdf_cur_cell = 0; return; } @@ -88,49 +89,45 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf const char*src = cellinst; const char*dp; while ( (dp=strchr(src, '.')) ) { - unsigned len = dp - src; - assert(dp >= src); - assert(len < sizeof buffer); - strncpy(buffer, src, len); - buffer[len] = 0; + unsigned len = dp - src; + assert(dp >= src); + assert(len < sizeof buffer); + strncpy(buffer, src, len); + buffer[len] = 0; - vpiHandle tmp_scope = find_scope(scope, buffer); - if (tmp_scope == 0) { - sdf_warn_file_line(sdf_lineno); - vpi_printf("Cannot find %s in scope %s.\n", - buffer, vpi_get_str(vpiFullName, scope)); - break; - } - assert(tmp_scope); - scope = tmp_scope; + vpiHandle tmp_scope = find_scope(scope, buffer); + if (tmp_scope == 0) { + vpi_printf("SDF ERROR: %s:%d: Cannot find %s in scope %s.\n", + sdf_fname, sdf_lineno, buffer, vpi_get_str(vpiFullName, scope)); + break; + } + assert(tmp_scope); + scope = tmp_scope; - src = dp + 1; + src = dp + 1; } /* Now find the cell. */ if (src[0] == 0) - sdf_cur_cell = sdf_scope; + sdf_cur_cell = sdf_scope; else - sdf_cur_cell = find_scope(scope, src); + sdf_cur_cell = find_scope(scope, src); if (sdf_cur_cell == 0) { - sdf_warn_file_line(sdf_lineno); - vpi_printf("Unable to find %s in scope %s.\n", - src, vpi_get_str(vpiFullName, scope)); - return; + vpi_printf("SDF ERROR: %s:%d: Unable to find %s in scope %s.\n", + sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope)); + return; } /* The scope that matches should be a module. */ if (vpi_get(vpiType,sdf_cur_cell) != vpiModule) { - sdf_warn_file_line(sdf_lineno); - vpi_printf("Scope %s in %s is not a module.\n", - src, vpi_get_str(vpiFullName, scope)); + vpi_printf("SDF ERROR: %s:%d: Scope %s in %s is not a module.\n", + sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope)); } /* The matching scope (a module) should have the expected type. */ if (strcmp(celltype,vpi_get_str(vpiDefName,sdf_cur_cell)) != 0) { - sdf_warn_file_line(sdf_lineno); - vpi_printf("Module %s in %s is not a %s; it is a ", src, - vpi_get_str(vpiFullName, scope), celltype); + vpi_printf("SDF ERROR: %s:%d: Module %s in %s is not a %s; it is a ", + sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope), celltype); vpi_printf("%s\n", vpi_get_str(vpiDefName, sdf_cur_cell)); } @@ -147,6 +144,110 @@ static const char*edge_str(int vpi_edge) return "edge.. "; } +vpiHandle get_port_handle(char* port_name, const int sdf_lineno) +{ + vpiHandle scope = sdf_cur_cell; + + // Get occurences of '.' in the name + int submodules = 0; + + for (int i=0; port_name[i] != '\0'; i++) + { + if (port_name[i] == '.') submodules++; + } + + // Extract the first token + char* token = strtok(port_name, ".");; + + // Change scope into submodule + while (submodules--) + { + scope = vpi_handle_by_name(token, scope); + + if (!scope) vpi_printf("SDF ERROR: %s:%d: Submodule %s in port path not found!\n", sdf_fname, sdf_lineno, token); + + // Extract next token + token = strtok(NULL, "."); + } + + // Iterate over ports + vpiHandle port_i = vpi_iterate(vpiPort, scope) ; + vpiHandle port; + vpiHandle port_handle = NULL; + + while ((port=vpi_scan(port_i)) != NULL) + { + char *port_name_ = vpi_get_str(vpiName, port) ; + + if (strcmp(port_name_, token) == 0) + { + if (port_handle != NULL) + { + if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: Found multiple matching ports for %s !\n", sdf_fname, sdf_lineno, token); + } + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Found handle for port %s!\n", sdf_fname, sdf_lineno, token); + port_handle = port; + } + } + + return port_handle; +} + + +void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconnect_port_s port2, + const struct sdf_delval_list_s*delval_list, + const int sdf_lineno) +{ + + // Get handles for both ports + // After calling get_port_handle, the name is invalid + vpiHandle port1_handle = get_port_handle(port1.name, sdf_lineno); + vpiHandle port2_handle = get_port_handle(port2.name, sdf_lineno); + + if (port1_handle && port2_handle) + { + // Get interModPath for the two ports + vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle); + + if (intermodpath) + { + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Got an vpiInterModPath!\n", sdf_fname, sdf_lineno); + + s_vpi_delay delays; + struct t_vpi_time delay_vals[12]; + + // Initialize delay structure + delays.da = delay_vals; + delays.no_of_delays = delval_list->count; + delays.time_type = vpiScaledRealTime; + delays.mtm_flag = 0; + delays.append_flag = 0; + delays.pulsere_flag = 0; + vpi_get_delays(intermodpath, &delays); + + for (int idx = 0 ; idx < delval_list->count ; idx += 1) { + delay_vals[idx].type = vpiScaledRealTime; + if (delval_list->val[idx].defined) { + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Putting delay: %f for index %d\n", + sdf_fname, sdf_lineno, delval_list->val[idx].value, idx); + delay_vals[idx].real = delval_list->val[idx].value; + } + } + + // Put the new delays + vpi_put_delays(intermodpath, &delays); + } + else + { + vpi_printf("SDF ERROR: %s:%d: Could not find intermodpath!\n", sdf_fname, sdf_lineno); + } + } + else + { + vpi_printf("SDF ERROR: %s:%d: Could not find handles for both ports!\n", sdf_fname, sdf_lineno); + } +} + void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, const struct sdf_delval_list_s*delval_list, const int sdf_lineno) @@ -214,10 +315,10 @@ void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, } if (match_count == 0) { - sdf_warn_file_line(sdf_lineno); - vpi_printf("Unable to match ModPath %s%s -> %s in %s\n", - edge_str(vpi_edge), src, dst, - vpi_get_str(vpiFullName, sdf_cur_cell)); + vpi_printf("SDF ERROR: %s:%d: Unable to match ModPath %s%s -> %s in %s\n", + sdf_fname, sdf_lineno, + edge_str(vpi_edge), src, dst, + vpi_get_str(vpiFullName, sdf_cur_cell)); } } @@ -309,6 +410,11 @@ static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } + if (sdf_flag_inform) vpi_printf("SDF INFO: Loading %s from %s:%d\n", + fname, + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + sdf_fd = fopen(fname, "r"); if (sdf_fd == 0) { vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), diff --git a/vpi_user.h b/vpi_user.h index 43e9345b5..6ac693ab4 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -277,6 +277,7 @@ typedef struct t_vpi_delay { #define vpiConstant 7 #define vpiFunction 20 #define vpiIntegerVar 25 +#define vpiInterModPath 26 #define vpiIterator 27 #define vpiMemory 29 #define vpiMemoryWord 30 @@ -534,6 +535,7 @@ extern vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref); extern vpiHandle vpi_scan(vpiHandle iter); extern vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx); extern vpiHandle vpi_handle_by_name(const char*name, vpiHandle scope); +extern vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, vpiHandle ref2); extern void vpi_get_time(vpiHandle obj, s_vpi_time*t); extern PLI_INT32 vpi_get(int property, vpiHandle ref); diff --git a/vvp/delay.cc b/vvp/delay.cc index fb79981c6..6c9aeb1cb 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -1115,3 +1115,352 @@ struct __vpiModPathSrc* vpip_make_modpath_src(struct __vpiModPath*path, return obj; } + +vvp_fun_intermodpath::vvp_fun_intermodpath(vvp_net_t*net, unsigned width) +: net_(net) +{ + for (unsigned idx = 0 ; idx < 12 ; idx += 1) + delay_[idx] = 0; + + cur_vec4_ = vvp_vector4_t(width, BIT4_X); + schedule_init_propagate(net_, cur_vec4_); // TODO is this needed? +} + +vvp_fun_intermodpath::~vvp_fun_intermodpath() +{ +} + +void vvp_fun_intermodpath::get_delay12(vvp_time64_t val[12]) const +{ + for (unsigned idx = 0 ; idx < 12 ; idx += 1) + val[idx] = delay_[idx]; +} + +void vvp_fun_intermodpath::put_delay12(const vvp_time64_t val[12]) +{ + for (unsigned idx = 0 ; idx < 12 ; idx += 1) + delay_[idx] = val[idx]; +} + +/* + * FIXME: this implementation currently only uses the maximum delay + * from all the bit changes in the vectors. If there are multiple + * changes with different delays, then the results would be + * wrong. What should happen is that if there are multiple changes, + * multiple vectors approaching the result should be scheduled. + */ +void vvp_fun_intermodpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, + vvp_context_t) +{ + /* Only the first port is used. */ + if (port.port() > 0) + return; + + if (cur_vec4_.eeq(bit)) + return; + + /* Given the scheduled output time, create an output event. */ + vvp_time64_t use_delay = delay_from_edge(cur_vec4_.value(0), + bit.value(0), + delay_); + + /* FIXME: This bases the edge delay on only the least + bit. This is WRONG! I need to find all the possible delays, + and schedule an event for each partial change. Hard! */ + for (unsigned idx = 1 ; idx < bit.size() ; idx += 1) { + vvp_time64_t tmp = delay_from_edge(cur_vec4_.value(idx), + bit.value(idx), + delay_); + /* If the current and new bit values match then no delay + * is needed for this bit. */ + if (cur_vec4_.value(idx) == bit.value(idx)) continue; + assert(tmp == use_delay); + } + + cur_vec4_ = bit; + schedule_generic(this, use_delay, false); +} + +void vvp_fun_intermodpath::run_run() +{ + net_->send_vec4(cur_vec4_, 0); +} + +/* + * All the below routines that begin with + * intermodpath_* belong the internal function + * of an vpiInterModPath object. This is used to + * make some specific delays path operations + * + */ +static int intermodpath_get(int, vpiHandle ref) +{ + struct __vpiInterModPath*obj =dynamic_cast<__vpiInterModPath*>(ref); + assert(obj); + return 0; +} + +static void intermodpath_get_value(vpiHandle ref, p_vpi_value) +{ + struct __vpiInterModPath* intermodpath = dynamic_cast<__vpiInterModPath*>(ref); + assert(intermodpath); + return; +} + +static vpiHandle intermodpath_put_value(vpiHandle ref, s_vpi_value *, int ) +{ + struct __vpiInterModPath* intermodpath = dynamic_cast<__vpiInterModPath*>(ref); + assert(intermodpath); + return 0; +} + +static vpiHandle intermodpath_get_handle(int code, vpiHandle ref) +{ + struct __vpiInterModPath*rfp = dynamic_cast<__vpiInterModPath*>(ref); + assert(rfp); + + switch (code) { + + case vpiScope: + return rfp->scope; + + case vpiModule: + { __vpiScope*scope = rfp->scope; + while (scope && scope->get_type_code() != vpiModule) + scope = scope->scope; + assert(scope); + return scope; + } + } + return 0; +} + +static vpiHandle intermodpath_iterate(int code, vpiHandle ref) +{ + struct __vpiInterModPath*rfp = dynamic_cast<__vpiInterModPath*>(ref); + assert(rfp); + + // For now intermodpaths only support exactly two ports + switch (code) { + case vpiPort: { + vpiHandle*args = (vpiHandle*)calloc(2, sizeof(vpiHandle*)); + args[0] = rfp->port1; + args[1] = rfp->port2; + return vpip_make_iterator(2, args, true); + } + } + return 0; +} + + +/* + * This routine will put specific dimension of delay[] values + * into a vpiHandle. In this case, we will put + * specific delays values in a vpiInterModPath object + * TODO code duplication + */ +static void intermodpath_put_delays (vpiHandle ref, p_vpi_delay delays) +{ + vvp_time64_t tmp[12]; + int idx; + struct __vpiInterModPath * src = dynamic_cast<__vpiInterModPath*>(ref) ; + assert(src) ; + + vvp_fun_intermodpath *fun = dynamic_cast(src->net->fun); + assert( fun ); + + typedef unsigned char map_array_t[12]; + // Only the first six entries are used for the less than twelve maps. + static const map_array_t map_1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + static const map_array_t map_2 = {0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0}; + static const map_array_t map_3 = {0, 1, 2, 0, 2, 1, 0, 0, 0, 0, 0, 0}; + static const map_array_t map_6 = {0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0}; + static const map_array_t map12 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + + const map_array_t*use_map = 0; + switch (delays->no_of_delays) { + case 1: + use_map = &map_1; + break; + case 2: + use_map = &map_2; + break; + case 3: + use_map = &map_3; + break; + case 6: + use_map = &map_6; + break; + case 12: + use_map = &map12; + break; + default: + assert(0); + break; + } + + if (delays->time_type == vpiSimTime) { + for (idx = 0 ; idx < 12 ; idx += 1) { + tmp[idx] = vpip_timestruct_to_time(delays->da+use_map[0][idx]); + } + } else { + // You cannot create a modpath with a negative delay so set it + // to zero per 1364-2005 section 14.3.1. + for (idx = 0 ; idx < delays->no_of_delays ; idx += 1) { + if (delays->da[idx].real < 0.0) delays->da[idx].real = 0.0; + } + for (idx = 0 ; idx < 12 ; idx += 1) { + tmp[idx] = vpip_scaled_real_to_time64(delays->da[use_map[0][idx]].real, + src->scope); + } + } + + /* Now define the to-from-x delays if needed. */ + if (delays->no_of_delays <= 6) { + /* 0->x is the minimum of 0->z and 0->1. */ + tmp[DELAY_EDGE_0x] = tmp[DELAY_EDGE_0z] < tmp[DELAY_EDGE_01] ? + tmp[DELAY_EDGE_0z] : tmp[DELAY_EDGE_01]; + /* x->1 is the maximum of z->1 and 0->1. */ + tmp[DELAY_EDGE_x1] = tmp[DELAY_EDGE_z1] > tmp[DELAY_EDGE_01] ? + tmp[DELAY_EDGE_z1] : tmp[DELAY_EDGE_01]; + /* 1->x is the minimum of 1->z and 1->0. */ + tmp[DELAY_EDGE_1x] = tmp[DELAY_EDGE_1z] < tmp[DELAY_EDGE_10] ? + tmp[DELAY_EDGE_1z] : tmp[DELAY_EDGE_10]; + /* x->0 is the maximum of z->0 and 1->0. */ + tmp[DELAY_EDGE_x0] = tmp[DELAY_EDGE_z0] > tmp[DELAY_EDGE_10] ? + tmp[DELAY_EDGE_z0] : tmp[DELAY_EDGE_10]; + /* x->z is the maximum of 1->z and 0->z. */ + tmp[DELAY_EDGE_xz] = tmp[DELAY_EDGE_1z] > tmp[DELAY_EDGE_0z] ? + tmp[DELAY_EDGE_1z] : tmp[DELAY_EDGE_0z]; + /* z->x is the minimum of z->1 and z->0. */ + tmp[DELAY_EDGE_zx] = tmp[DELAY_EDGE_z1] < tmp[DELAY_EDGE_z0] ? + tmp[DELAY_EDGE_z1] : tmp[DELAY_EDGE_z0]; + } + + fun->put_delay12(tmp); +} + +/* + * This routine will retrieve the delay[12] values + * of a vpiHandle. In this case, he will get an + * specific delays values from a vpiInterModPath + * object + * + */ + +static void intermodpath_get_delays ( vpiHandle ref, p_vpi_delay delays ) +{ + struct __vpiInterModPath*src = dynamic_cast<__vpiInterModPath*>(ref) ; + assert(src); + + vvp_fun_intermodpath *fun = dynamic_cast(src->net->fun); + assert(fun); + + int idx; + vvp_time64_t tmp[12]; + fun->get_delay12(tmp); + + switch (delays->no_of_delays) { + case 1: + case 2: + case 3: + case 6: + case 12: + break; + + default: + assert(0); + break; + } + + if (delays->time_type == vpiSimTime) { + for (idx = 0; idx < delays->no_of_delays; idx += 1) { + vpip_time_to_timestruct(delays->da+idx, tmp[idx]); + } + } else { + for (idx = 0; idx < delays->no_of_delays; idx += 1) { + delays->da[idx].real = vpip_time_to_scaled_real(tmp[idx], src->scope); + } + } +} + +/* +* The __vpiInterModPath class is what the VPI client sees as a +* vpiInterModPath object. +*/ +inline __vpiInterModPath::__vpiInterModPath() +{ } + +int __vpiInterModPath::get_type_code(void) const +{ return vpiInterModPath; } + +int __vpiInterModPath::vpi_get(int code) +{ return intermodpath_get(code, this); } + +void __vpiInterModPath::vpi_get_value(p_vpi_value val) +{ intermodpath_get_value(this, val); } + +vpiHandle __vpiInterModPath::vpi_put_value(p_vpi_value val, int flags) +{ return intermodpath_put_value(this, val, flags); } + +vpiHandle __vpiInterModPath::vpi_handle(int code) +{ return intermodpath_get_handle(code, this); } + +vpiHandle __vpiInterModPath::vpi_iterate(int code) +{ return intermodpath_iterate(code, this); } + +void __vpiInterModPath::vpi_get_delays(p_vpi_delay del) +{ intermodpath_get_delays(this, del); } + +void __vpiInterModPath::vpi_put_delays(p_vpi_delay del) +{ intermodpath_put_delays(this, del); } + +static int intermodpath_free_object( vpiHandle ref ) +{ + delete ref; + return 1 ; +} + +__vpiHandle::free_object_fun_t __vpiInterModPath::free_object_fun(void) +{ return &intermodpath_free_object; } + +/* + * This function will construct a vpiInterModPath Object. + * give a respective "net", and will point to his + * respective functor + */ + +#ifdef CHECK_WITH_VALGRIND +static struct __vpiInterModPath**imp_list = 0; +static unsigned imp_count = 0; +#endif + +struct __vpiInterModPath* vpip_make_intermodpath(vvp_net_t *net, vpiPortInfo* port1, vpiPortInfo* port2) +{ + struct __vpiInterModPath*obj = new __vpiInterModPath; + obj->scope = vpip_peek_current_scope ( ); + + obj->net = net; + obj->port1 = port1; + obj->port2 = port2; + +#ifdef CHECK_WITH_VALGRIND + imp_count += 1; + imp_list = (struct __vpiInterModPath **) realloc(imp_list, + imp_count*sizeof(struct __vpiInterModPath **)); + imp_list[imp_count-1] = obj; +#endif + return obj; +} + +#ifdef CHECK_WITH_VALGRIND +void intermodpath_delete() +{ + for (unsigned idx = 0; idx < mp_count; idx += 1) { + delete imp_list[idx]; + } + free(imp_list); + imp_list = 0; + imp_count = 0; +} +#endif diff --git a/vvp/delay.h b/vvp/delay.h index c495bb1e2..01c89a172 100644 --- a/vvp/delay.h +++ b/vvp/delay.h @@ -234,4 +234,34 @@ class vvp_fun_modpath_edge : public vvp_fun_modpath_src { bool negedge_; }; +/* +* The intermodpath is used to implement the SDF INTERCONNECT feature +*/ +class vvp_fun_intermodpath : public vvp_net_fun_t, private vvp_gen_event_s { + + public: + vvp_fun_intermodpath(vvp_net_t*net, unsigned width); + ~vvp_fun_intermodpath(); + + void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, + vvp_context_t); + + void get_delay12(vvp_time64_t out[12]) const; + void put_delay12(const vvp_time64_t in[12]); + + private: + virtual void run_run(); + + private: + vvp_net_t*net_; + + vvp_vector4_t cur_vec4_; + + vvp_time64_t delay_[12]; + + private: // not implemented + vvp_fun_intermodpath(const vvp_fun_intermodpath&); + vvp_fun_intermodpath& operator= (const vvp_fun_intermodpath&); +}; + #endif /* IVL_delay_H */ diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 1de770fd4..c2f694295 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -20,6 +20,7 @@ # include "version_base.h" # include "vpi_priv.h" # include "schedule.h" +# include "logic.h" #ifdef CHECK_WITH_VALGRIND # include "vvp_cleanup.h" #endif @@ -1553,6 +1554,159 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope) return out; } +// Used to get intermodpath for two ports +vpiHandle vpi_handle_multi(PLI_INT32 type, + vpiHandle ref1, + vpiHandle ref2) +{ + if (vpi_trace) { + fprintf(vpi_trace, "vpi_handle_multi(%d, %p, %p) -->\n", + type, ref1, ref2); + } + + if (type != vpiInterModPath) { + fprintf(stderr, "sorry: vpi_handle_multi currently supports" + "only vpiInterModPath\n"); + return nullptr; + } + + vpiPortInfo* port1 = dynamic_cast(ref1); + + if (!port1) { + fprintf(stderr, "sorry: second argument of vpi_handle_multi" + "must be a vpiPort\n"); + return nullptr; + } + + vpiPortInfo* port2 = dynamic_cast(ref2); + + if (!port2) { + fprintf(stderr, "sorry: third argument of vpi_handle_multi" + "must be a vpiPort\n"); + return nullptr; + } + + std::string port_name1(vpi_get_str(vpiName, ref1)); + std::string port_name2(vpi_get_str(vpiName, ref2)); + + fprintf(stderr, "port_name1: %s\n", port_name1.c_str()); + fprintf(stderr, "port_name2: %s\n", port_name2.c_str()); + + vpiHandle mod1 = vpi_handle(vpiModule, ref1); + vpiHandle mod2 = vpi_handle(vpiModule, ref2); + + if (!mod1) fprintf(stderr, "Cannot access module of port1!\n"); + if (!mod2) fprintf(stderr, "Cannot access module of port2!\n"); + + // Find net for port1 + vpiHandle net_i = vpi_iterate(vpiNet, mod1); + vpiHandle net; + vpiHandle net_handle1 = nullptr; + + while ((net=vpi_scan(net_i)) != nullptr) + { + char *net_name = vpi_get_str(vpiName, net); + + fprintf(stderr, "Comparing %s and %s\n", net_name, port_name1.c_str()); + if (port_name1 == net_name) + { + if (net_handle1 != nullptr) + { + fprintf(stderr, "Found multiple matching nets for %s !\n", port_name1.c_str()); + } + fprintf(stderr, "Found handle for net %s!\n", net_name); + net_handle1 = net; + } + } + + // Find net for port2 + net_i = vpi_iterate(vpiNet, mod2); + vpiHandle net_handle2 = nullptr; + + while ((net=vpi_scan(net_i)) != nullptr) + { + char *net_name = vpi_get_str(vpiName, net); + + fprintf(stderr, "Comparing %s and %s\n", net_name, port_name2.c_str()); + if (port_name2 == net_name) + { + if (net_handle2 != nullptr) + { + fprintf(stderr, "Found multiple matching nets for %s !\n", port_name2.c_str()); + } + fprintf(stderr, "Found handle for net %s!\n", net_name); + net_handle2 = net; + } + } + + // Try to access net/node behind it + struct __vpiSignal*node1 = dynamic_cast<__vpiSignal*>(net_handle1); + assert(node1); + struct __vpiSignal*node2 = dynamic_cast<__vpiSignal*>(net_handle2); + assert(node2); + + vvp_net_t* net1 = node1->node; + vvp_net_t* net2 = node2->node; + + // TODO don't just compare the nets, may be a problem for high fan-out nets + if (net1 == net2) + { + fprintf(stderr, "Same net!\n"); + } + else + { + fprintf(stderr, "Different net!\n"); + return nullptr; + } + + // Debug information + + for (int i=0; i<4; i++) + { + fprintf(stderr, "my_node1->port[%d].ptr() : %p\n", i, net1->port[i].ptr()); + fprintf(stderr, "my_node1->port[%d].port() : %d\n", i, net1->port[i].port()); + } + + fprintf(stderr, "my_node1->fun : %p\n", net1->fun); + fprintf(stderr, "my_node1->fil : %p\n", net1->fil); + + fprintf(stderr, "my_node1->fil->filter_size() : %d\n", net1->fil->filter_size()); + + //fprintf(stderr, "my_node1->out_.ptr() : %p\n", net1->out_.ptr()); // vvp_net_t + //fprintf(stderr, "my_node1->out_.port() : %d\n", net1->out_.port()); // input 3-0 + + + // TODO for now just replace vvp_fun_bufz with vvp_fun_intermodpath + if (dynamic_cast(net1->fun)) + { + std::cout << "Replacing with vvp_fun_intermodpath!" << std::endl; + + int width = 1; // TODO + + vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(net1, width); + net1->fun = obj; + + __vpiInterModPath*intermodpath = vpip_make_intermodpath(net1, port1, port2); + intermodpath->intermodpath = obj; + + // TODO add net to network + + /*vvp_net_t*net = new vvp_net_t; + vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(net, width, delay); + net->fun = obj; + + __vpiInterModPath*intermodpath = vpip_make_intermodpath(net, ref1, ref2); + intermodpath->intermodpath = obj;*/ + + return intermodpath; + } + else + { + std::cout << "sorry: Could not insert intermodpath!" << std::endl; + } + + return nullptr; +} /* We increment the two vpi methods to enable the @@ -1749,6 +1903,7 @@ vpip_routines_s vpi_routines = { .get_systf_info = vpi_get_systf_info, .handle_by_name = vpi_handle_by_name, .handle_by_index = vpi_handle_by_index, + .handle_multi = vpi_handle_multi, .handle = vpi_handle, .iterate = vpi_iterate, .scan = vpi_scan, diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 28f484ea8..3f2e29fb3 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -432,6 +432,30 @@ struct __vpiBit { int get_index(void) const; }; + +class vpiPortInfo : public __vpiHandle { + public: + vpiPortInfo( __vpiScope *parent, + unsigned index, + int vpi_direction, + unsigned width, + const char *name ); + ~vpiPortInfo(); + + int get_type_code(void) const { return vpiPort; } + + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_handle(int code); + + private: + __vpiScope *parent_; + unsigned index_; + int direction_; + unsigned width_; + const char *name_; +}; + /* * This is used by system calls to represent a bit/part select of * a simple variable or constant array word. @@ -520,6 +544,43 @@ extern struct __vpiModPathSrc* vpip_make_modpath_src(struct __vpiModPath*path, extern struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) ; +/* + * + * The vpiInterModPath vpiHandle will define + * a vpiInterModPath of record .intermodpath as defined + * in the IEEE 1364 + * + */ + +struct __vpiInterModPath : public __vpiHandle { + __vpiInterModPath(); + int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + void vpi_get_delays(p_vpi_delay del); + void vpi_put_delays(p_vpi_delay del); + free_object_fun_t free_object_fun(void); + + __vpiScope *scope ; + + class vvp_fun_intermodpath*intermodpath; + + vvp_net_t *net; + + vpiPortInfo* port1; + vpiPortInfo* port2; +}; + + +/* + * The Function is used to create the vpiHandle + * for vpiInterModPath + */ + +extern struct __vpiInterModPath* vpip_make_intermodpath(vvp_net_t *net, vpiPortInfo* port1, vpiPortInfo* port2); /* * These methods support the vpi creation of events. The name string diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 9d6484537..2057abbac 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -82,6 +82,9 @@ static void delete_sub_scopes(__vpiScope *scope) /* The destination ModPath is cleaned up later. */ delete item; break; + case vpiInterModPath: + delete item; + break; case vpiNamedEvent: named_event_delete(item); break; @@ -659,29 +662,6 @@ unsigned vpip_add_item_to_context(automatic_hooks_s*item, } -class vpiPortInfo : public __vpiHandle { - public: - vpiPortInfo( __vpiScope *parent, - unsigned index, - int vpi_direction, - unsigned width, - const char *name ); - ~vpiPortInfo(); - - int get_type_code(void) const { return vpiPort; } - - int vpi_get(int code); - char* vpi_get_str(int code); - vpiHandle vpi_handle(int code); - - private: - __vpiScope *parent_; - unsigned index_; - int direction_; - unsigned width_; - const char *name_; -}; - vpiPortInfo::vpiPortInfo( __vpiScope *parent, unsigned index, int vpi_direction, diff --git a/vvp/vvp.def b/vvp/vvp.def index c49f79400..7e7da212c 100644 --- a/vvp/vvp.def +++ b/vvp/vvp.def @@ -18,6 +18,7 @@ vpi_get_vlog_info vpi_handle vpi_handle_by_index vpi_handle_by_name +vpi_handle_multi vpi_iterate vpi_mcd_close vpi_mcd_flush From f6e4b6d381c54625ba5ae3106b7a7ab00b9fab25 Mon Sep 17 00:00:00 2001 From: mole99 Date: Thu, 20 Jul 2023 08:43:51 +0200 Subject: [PATCH 03/14] Add vpi_handle_multi to libvpi --- vpi/libvpi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vpi/libvpi.c b/vpi/libvpi.c index 5262d2e66..100d6f084 100644 --- a/vpi/libvpi.c +++ b/vpi/libvpi.c @@ -60,6 +60,11 @@ vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx) assert(vpip_routines); return vpip_routines->handle_by_index(ref, idx); } +vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, vpiHandle ref2) +{ + assert(vpip_routines); + return vpip_routines->handle_multi(type, ref1, ref2); +} // for traversing relationships From cf19acd8ee94312b7f3e20b2135d9c6afac0c011 Mon Sep 17 00:00:00 2001 From: mole99 Date: Thu, 20 Jul 2023 09:06:31 +0200 Subject: [PATCH 04/14] Update vpip_routines_s --- vpi_user.h | 1 + 1 file changed, 1 insertion(+) diff --git a/vpi_user.h b/vpi_user.h index 6ac693ab4..e57983a08 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -699,6 +699,7 @@ typedef struct { void (*get_systf_info)(vpiHandle, p_vpi_systf_data); vpiHandle (*handle_by_name)(const char*, vpiHandle); vpiHandle (*handle_by_index)(vpiHandle, PLI_INT32); + vpiHandle (*handle_multi)(PLI_INT32, vpiHandle, vpiHandle); vpiHandle (*handle)(PLI_INT32, vpiHandle); vpiHandle (*iterate)(PLI_INT32, vpiHandle); vpiHandle (*scan)(vpiHandle); From 3fe59b0c16557b11afd23bf417970749f3d1b3e4 Mon Sep 17 00:00:00 2001 From: mole99 Date: Thu, 20 Jul 2023 09:46:46 +0200 Subject: [PATCH 05/14] Add vpi_handle_multi to vpi_modules --- vpi_modules.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vpi_modules.cc b/vpi_modules.cc index 5d0b8c3aa..cb7b0eb9f 100644 --- a/vpi_modules.cc +++ b/vpi_modules.cc @@ -46,6 +46,7 @@ void vpi_get_systf_info(vpiHandle, p_vpi_systf_data) { } vpiHandle vpi_handle_by_name(const char*, vpiHandle) { return 0; } vpiHandle vpi_handle_by_index(vpiHandle, PLI_INT32) { return 0; } +vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, vpiHandle ref2) { return 0; } // for traversing relationships @@ -195,6 +196,7 @@ vpip_routines_s vpi_routines = { .get_systf_info = vpi_get_systf_info, .handle_by_name = vpi_handle_by_name, .handle_by_index = vpi_handle_by_index, + .handle_multi = vpi_handle_multi, .handle = vpi_handle, .iterate = vpi_iterate, .scan = vpi_scan, From adb40e75725d3a5ae6723027373dd655736ff952 Mon Sep 17 00:00:00 2001 From: mole99 Date: Tue, 25 Jul 2023 13:14:49 +0200 Subject: [PATCH 06/14] Annotate simple designs --- vvp/vpi_priv.cc | 218 ++++++++++++++++++++++++++++++++++++++++-------- vvp/vpi_priv.h | 1 + vvp/vvp_net.h | 2 +- 3 files changed, 186 insertions(+), 35 deletions(-) diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index c2f694295..115d6fe61 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -33,6 +33,16 @@ # include # include +# include "npmos.h" +# include "vvp_island.h" +# include "resolv.h" +# include "bufif.h" +# include "latch.h" +# include "dff.h" +# include "event.h" +# include "arith.h" +# include "part.h" + using namespace std; vpi_mode_t vpi_mode_flag = VPI_MODE_NONE; FILE*vpi_trace = 0; @@ -1554,6 +1564,84 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope) return out; } +void print_net_type(vvp_net_t* net1) +{ + if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_delay*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_modpath*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_modpath_src*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_pv*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_var*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_abs*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_cast_int*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_cast_real*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_cast_vec2*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_real_*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_edge*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_anyedge*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_event_or*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_named_event*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_bufif*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_dff*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_boolean_*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_bufz*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_muxz*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_muxr*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_not*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_concat*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_concat8*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_force*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_repeat*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_drive*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_extend_signed*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_wide_fun_core*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_wide_fun_t*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_vec*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_real*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_string*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_object*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_base*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "resolv_core*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "resolv_extend*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_latch*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_pmos_*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_cmos_*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_island_port*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_intermodpath*!" << std::endl; + + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_base*!" << std::endl; + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_and*!" << std::endl; + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_or*!" << std::endl; + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_xor*!" << std::endl; + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_nand*!" << std::endl; + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_nor*!" << std::endl; + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_xnor*!" << std::endl; + + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_sa*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_aa*!" << std::endl; + + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_substitute*!" << std::endl; + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_arrayport*!" << std::endl; + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_arrayport_sa*!" << std::endl; + //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_arrayport_aa*!" << std::endl; + + else std::cout << "unknown!" << std::endl; +} + +void print_port_connections(vvp_net_ptr_t* net_ptr) +{ + vvp_net_t* next_net = net_ptr->ptr(); + if (!next_net) return; + + print_net_type(next_net); + vvp_net_ptr_t* next_net_ptr = &next_net->port[net_ptr->port()]; + + print_port_connections(next_net_ptr); +} + + // Used to get intermodpath for two ports vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, @@ -1586,6 +1674,18 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; } + /*if (!(port1->get_direction() == vpiOutput || port1->get_direction() == vpiInout)) { + fprintf(stderr, "ERROR: First vpiPort must be an output" + " or bidirectional port\n"); + return nullptr; + } + + if (!(port2->get_direction() == vpiInput || port2->get_direction() == vpiInout)) { + fprintf(stderr, "ERROR: Second vpiPort must be an input" + " or bidirectional port\n"); + return nullptr; + }*/ + std::string port_name1(vpi_get_str(vpiName, ref1)); std::string port_name2(vpi_get_str(vpiName, ref2)); @@ -1648,63 +1748,113 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, vvp_net_t* net1 = node1->node; vvp_net_t* net2 = node2->node; - // TODO don't just compare the nets, may be a problem for high fan-out nets - if (net1 == net2) - { - fprintf(stderr, "Same net!\n"); - } - else - { - fprintf(stderr, "Different net!\n"); - return nullptr; - } + print_net_type(net1); + print_net_type(net2); // Debug information for (int i=0; i<4; i++) { - fprintf(stderr, "my_node1->port[%d].ptr() : %p\n", i, net1->port[i].ptr()); - fprintf(stderr, "my_node1->port[%d].port() : %d\n", i, net1->port[i].port()); + fprintf(stderr, "net1->port[%d].ptr() : %p\n", i, net1->port[i].ptr()); + fprintf(stderr, "net1->port[%d].port() : %d\n", i, net1->port[i].port()); } - fprintf(stderr, "my_node1->fun : %p\n", net1->fun); - fprintf(stderr, "my_node1->fil : %p\n", net1->fil); + fprintf(stderr, "net1->fun : %p\n", net1->fun); + fprintf(stderr, "net1->fil : %p\n", net1->fil); - fprintf(stderr, "my_node1->fil->filter_size() : %d\n", net1->fil->filter_size()); + fprintf(stderr, "net1->fil->filter_size() : %d\n", net1->fil->filter_size()); - //fprintf(stderr, "my_node1->out_.ptr() : %p\n", net1->out_.ptr()); // vvp_net_t - //fprintf(stderr, "my_node1->out_.port() : %d\n", net1->out_.port()); // input 3-0 + //fprintf(stderr, "net1->out_.ptr() : %p\n", net1->out_.ptr()); // vvp_net_t + //fprintf(stderr, "net1->out_.port() : %d\n", net1->out_.port()); // input 3-0 - - // TODO for now just replace vvp_fun_bufz with vvp_fun_intermodpath - if (dynamic_cast(net1->fun)) + // TODO don't just compare the nets, may be a problem for high fan-out nets + if (net1 == net2) { - std::cout << "Replacing with vvp_fun_intermodpath!" << std::endl; + fprintf(stderr, "Same net!\n"); + vvp_net_ptr_t* next_ptr = &net1->out_; + + fprintf(stderr, "Port connections:\n"); + + print_port_connections(next_ptr); + + fprintf(stderr, "End port connections:\n"); + + std::cout << *next_ptr << std::endl; + + vvp_net_t* next_net = next_ptr->ptr(); + //assert(next_net); + + if (!next_net) return 0; + + print_net_type(next_net); + + for (int i=0; i<4; i++) + { + fprintf(stderr, "next_net->port[%d].ptr() : %p\n", i, next_net->port[i].ptr()); + fprintf(stderr, "next_net->port[%d].port() : %d\n", i, next_net->port[i].port()); + + if (next_net->port[i].ptr()) print_net_type(next_net->port[i].ptr()); + } + + + // May be connected to both vvp_fun_modpath_src* and vvp_fun_bufz*! + //if (next_net->port[next_ptr->port()].ptr() == nullptr) + //{ + //fprintf(stderr, "next_net is the only thing connected to net1/net2!\n"); int width = 1; // TODO - vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(net1, width); - net1->fun = obj; + vvp_net_t*new_net = new vvp_net_t; + vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); + new_net->fun = obj; - __vpiInterModPath*intermodpath = vpip_make_intermodpath(net1, port1, port2); + new_net->out_= vvp_net_ptr_t(next_net,0); // point to port0 of net2 + + net1->out_ = vvp_net_ptr_t(new_net,0); // point to port0 of new_net + + __vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2); intermodpath->intermodpath = obj; - // TODO add net to network - - /*vvp_net_t*net = new vvp_net_t; - vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(net, width, delay); - net->fun = obj; - - __vpiInterModPath*intermodpath = vpip_make_intermodpath(net, ref1, ref2); - intermodpath->intermodpath = obj;*/ + fprintf(stderr, "Inserted vvp_fun_intermodpath!\n"); return intermodpath; + //} + } else { - std::cout << "sorry: Could not insert intermodpath!" << std::endl; - } + fprintf(stderr, "Different net!\n"); + vvp_net_ptr_t* net1_ptr = &net1->out_; + + // TODO follow whole linked list + if (net1_ptr->ptr() == net2) + { + fprintf(stderr, "But net1 connected to net2!\n"); + + if (net2->port[net1_ptr->port()].ptr() == nullptr) + { + fprintf(stderr, "Net2 is the only thing connected to net1!\n"); + + int width = 1; // TODO + + vvp_net_t*new_net = new vvp_net_t; + vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); + new_net->fun = obj; + + new_net->out_= vvp_net_ptr_t(net2,0); // point to port0 of net2 + net1->out_ = vvp_net_ptr_t(new_net,0); // point to port0 of new_net + + __vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2); + intermodpath->intermodpath = obj; + + fprintf(stderr, "Inserted vvp_fun_intermodpath!\n"); + + return intermodpath; + } + } + } + std::cout << "sorry: Could not insert intermodpath!" << std::endl; return nullptr; } diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 3f2e29fb3..842c2874b 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -443,6 +443,7 @@ class vpiPortInfo : public __vpiHandle { ~vpiPortInfo(); int get_type_code(void) const { return vpiPort; } + int get_direction(void) { return direction_; } int vpi_get(int code); char* vpi_get_str(int code); diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 711f1f03c..e2b9ad574 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1159,7 +1159,7 @@ class vvp_net_t { public: // Method to support $countdrivers void count_drivers(unsigned idx, unsigned counts[4]); - private: + public: vvp_net_ptr_t out_; public: // Need a better new for these objects. From 6d3e2bf3448efcdcd55ac9e0aefa6a344abc38c4 Mon Sep 17 00:00:00 2001 From: mole99 Date: Tue, 8 Aug 2023 11:42:15 +0200 Subject: [PATCH 07/14] Improve SDF interconnect support, add -ginterconnect flag --- compiler.h | 5 + driver/iverilog.man.in | 8 ++ driver/main.c | 9 ++ elaborate.cc | 51 ++++---- ivl.def | 2 + ivl_target.h | 3 + main.cc | 12 ++ net_scope.cc | 8 ++ netlist.cc | 4 +- netlist.h | 7 +- t-dll-api.cc | 11 ++ t-dll.cc | 12 ++ t-dll.h | 1 + tgt-vvp/vvp_scope.c | 11 +- vpi_modules.cc | 2 +- vvp/compile.h | 2 +- vvp/parse.y | 7 +- vvp/vpi_priv.cc | 257 +++++++++++++++++++++++------------------ vvp/vpi_priv.h | 5 +- vvp/vpi_scope.cc | 9 +- 20 files changed, 277 insertions(+), 149 deletions(-) diff --git a/compiler.h b/compiler.h index 11491baf4..307589aad 100644 --- a/compiler.h +++ b/compiler.h @@ -177,6 +177,11 @@ extern bool gn_icarus_misc_flag; is false, then skip elaboration of specify behavior. */ extern bool gn_specify_blocks_flag; +/* If this flag is true, then add input/output buffers to modules so that + VVP can insert intermodpaths inbetween. If this flag + is false, then no input/output buffers are inserted if not needed. */ +extern bool gn_interconnect_flag; + /* If this flag is true, then elaborate supported assertion statements. If this flag is false, then stub out supported assertion statements. */ extern bool gn_supported_assertions_flag; diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 74935a542..3e70a44cd 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -95,6 +95,14 @@ simulation, and in fact can hurt performance of the simulation. However, disabling specify blocks reduces accuracy of full-timing simulations. .TP 8 +.B -ginterconnect\fI|\fP-gno-interconnect +Enable or disable (default) SDF interconnect support. When enabled, +input and output buffers will be added to modules, so that VVP can +add interconnection delays. This option is commonly not needed for RTL +simulation, and in fact can hurt performance of the +simulation. However, disabling interconnection delays reduces accuracy of +full-timing simulations. +.TP 8 .B -gstd-include\fI|\fP-gno-std-include Enable (default) or disable the search of a standard installation include directory after all other explicit include directories. This diff --git a/driver/main.c b/driver/main.c index d3eba6bb0..546cd1cfc 100644 --- a/driver/main.c +++ b/driver/main.c @@ -125,6 +125,7 @@ char depmode = 'a'; const char*generation = "2005"; const char*gen_specify = "no-specify"; +const char*gen_interconnect = "no-interconnect"; const char*gen_assertions = "assertions"; const char*gen_xtypes = "xtypes"; const char*gen_icarus = "icarus-misc"; @@ -757,6 +758,12 @@ static int process_generation(const char*name) else if (strcmp(name,"no-specify") == 0) gen_specify = "no-specify"; + else if (strcmp(name,"interconnect") == 0) + gen_interconnect = "interconnect"; + + else if (strcmp(name,"no-interconnect") == 0) + gen_interconnect = "no-interconnect"; + else if (strcmp(name,"assertions") == 0) gen_assertions = "assertions"; @@ -821,6 +828,7 @@ static int process_generation(const char*name) "Other generation flags:\n" " assertions | supported-assertions | no-assertions\n" " specify | no-specify\n" + " interconnect | no-interconnect\n" " verilog-ams | no-verilog-ams\n" " std-include | no-std-include\n" " relative-include | no-relative-include\n" @@ -1368,6 +1376,7 @@ int main(int argc, char **argv) if (mtm != 0) fprintf(iconfig_file, "-T:%s\n", mtm); fprintf(iconfig_file, "generation:%s\n", generation); fprintf(iconfig_file, "generation:%s\n", gen_specify); + fprintf(iconfig_file, "generation:%s\n", gen_interconnect); fprintf(iconfig_file, "generation:%s\n", gen_assertions); fprintf(iconfig_file, "generation:%s\n", gen_xtypes); fprintf(iconfig_file, "generation:%s\n", gen_io_range_error); diff --git a/elaborate.cc b/elaborate.cc index 16c482f12..ed7bc1419 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1159,13 +1159,13 @@ static void convert_net(Design*des, const LineInfo *line, } static void isolate_and_connect(Design*des, NetScope*scope, const PGModule*mod, - NetNet*port, NetNet*sig, NetNet::PortType ptype) + NetNet*port, NetNet*sig, NetNet::PortType ptype, int idx = -1) { switch (ptype) { case NetNet::POUTPUT: { NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(), - sig->vector_width(), true); + sig->vector_width(), true, idx); tmp->set_line(*mod); des->add_node(tmp); connect(tmp->pin(1), port->pin(0)); @@ -1598,21 +1598,25 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } } - if (need_bufz_for_input_port(prts)) { - NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(), - sig->vector_width(), true); - tmp->set_line(*this); - des->add_node(tmp); - connect(tmp->pin(1), sig->pin(0)); + // Add module input buffers if needed + if (need_bufz_for_input_port(prts) || gn_interconnect_flag == true) { + // FIXME improve this for multiple module instances + NetScope* inner_scope = scope->instance_arrays[get_name()][0]; - netvector_t*tmp2_vec = new netvector_t(sig->data_type(), + NetBUFZ*tmp = new NetBUFZ(inner_scope, inner_scope->local_symbol(), + sig->vector_width(), true, gn_interconnect_flag ? idx : -1); + tmp->set_line(*this); + des->add_node(tmp); + connect(tmp->pin(1), sig->pin(0)); + + netvector_t*tmp2_vec = new netvector_t(sig->data_type(), sig->vector_width()-1,0); - NetNet*tmp2 = new NetNet(scope, scope->local_symbol(), + NetNet*tmp2 = new NetNet(inner_scope, inner_scope->local_symbol(), NetNet::WIRE, tmp2_vec); - tmp2->local_flag(true); - tmp2->set_line(*this); - connect(tmp->pin(0), tmp2->pin(0)); - sig = tmp2; + tmp2->local_flag(true); + tmp2->set_line(*this); + connect(tmp->pin(0), tmp2->pin(0)); + sig = tmp2; } // If we have a real signal driving a bit/vector port @@ -1933,10 +1937,13 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // that are a delay path destination, to avoid // the delay being applied to other drivers of // the external signal. - if (prts[0]->delay_paths() > 0) { - isolate_and_connect(des, scope, this, prts[0], sig, ptype); + if (prts[0]->delay_paths() > 0 || (gn_interconnect_flag == true && ptype == NetNet::POUTPUT)) { + // FIXME improve this for multiple module instances + NetScope* inner_scope = scope->instance_arrays[get_name()][0]; + + isolate_and_connect(des, inner_scope, this, prts[0], sig, ptype, gn_interconnect_flag ? idx : -1); } else { - connect(prts[0]->pin(0), sig->pin(0)); + connect(prts[0]->pin(0), sig->pin(0)); } } else if (sig->vector_width()==prts_vector_width/instance.size() @@ -3496,14 +3503,14 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const parm.parm); } - // Special case: Specify blocks are turned off, and this is an - // $sdf_annotate system task. There will be nothing for $sdf - // to annotate, and the user is intending to turn the behavior + // Special case: Specify blocks and interconnects are turned off, + // and this is an $sdf_annotate system task. There will be nothing for + // $sdf to annotate, and the user is intending to turn the behavior // off anyhow, so replace the system task invocation with a no-op. - if (gn_specify_blocks_flag == false && name == "$sdf_annotate") { + if (gn_specify_blocks_flag == false && gn_interconnect_flag == false && name == "$sdf_annotate") { cerr << get_fileline() << ": warning: Omitting $sdf_annotate() " - << "since specify blocks are being omitted." << endl; + << "since specify blocks and interconnects are being omitted." << endl; NetBlock*noop = new NetBlock(NetBlock::SEQU, scope); noop->set_line(*this); return noop; diff --git a/ivl.def b/ivl.def index 630a10cc1..867d832f4 100644 --- a/ivl.def +++ b/ivl.def @@ -109,6 +109,7 @@ ivl_logic_scope ivl_logic_type ivl_logic_udp ivl_logic_width +ivl_logic_port_buffer ivl_lpm_array ivl_lpm_aset_value @@ -229,6 +230,7 @@ ivl_scope_mod_module_ports ivl_scope_mod_module_port_name ivl_scope_mod_module_port_type ivl_scope_mod_module_port_width +ivl_scope_mod_module_port_buffer ivl_scope_mod_port ivl_scope_name ivl_scope_param diff --git a/ivl_target.h b/ivl_target.h index 7f551aa72..b33ea9aa4 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1112,6 +1112,7 @@ extern ivl_drive_t ivl_logic_drive0(ivl_net_logic_t net); extern ivl_drive_t ivl_logic_drive1(ivl_net_logic_t net); extern unsigned ivl_logic_width(ivl_net_logic_t net); extern unsigned ivl_logic_is_cassign(ivl_net_logic_t net); +extern unsigned ivl_logic_port_buffer(ivl_net_logic_t net); /* DEPRECATED */ extern const char* ivl_logic_attr(ivl_net_logic_t net, const char*key); @@ -1897,6 +1898,7 @@ extern unsigned ivl_scope_mod_module_ports(ivl_scope_t net); extern const char *ivl_scope_mod_module_port_name(ivl_scope_t net, unsigned idx ); extern ivl_signal_port_t ivl_scope_mod_module_port_type(ivl_scope_t net, unsigned idx ); extern unsigned ivl_scope_mod_module_port_width(ivl_scope_t net, unsigned idx ); +extern ivl_net_logic_t ivl_scope_mod_module_port_buffer(ivl_scope_t net, unsigned idx ); extern unsigned ivl_scope_ports(ivl_scope_t net); extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx); @@ -2432,3 +2434,4 @@ _END_DECL #undef ENUM_UNSIGNED_INT #endif /* IVL_ivl_target_H */ + diff --git a/main.cc b/main.cc index 057b70ac2..0f3763b28 100644 --- a/main.cc +++ b/main.cc @@ -106,6 +106,7 @@ generation_t generation_flag = GN_DEFAULT; bool gn_icarus_misc_flag = true; bool gn_cadence_types_flag = true; bool gn_specify_blocks_flag = true; +bool gn_interconnect_flag = true; bool gn_supported_assertions_flag = true; bool gn_unsupported_assertions_flag = true; bool gn_io_range_error_flag = true; @@ -334,6 +335,12 @@ static void process_generation_flag(const char*gen) } else if (strcmp(gen,"no-specify") == 0) { gn_specify_blocks_flag = false; + } else if (strcmp(gen,"interconnect") == 0) { + gn_interconnect_flag = true; + + } else if (strcmp(gen,"no-interconnect") == 0) { + gn_interconnect_flag = false; + } else if (strcmp(gen,"assertions") == 0) { gn_supported_assertions_flag = true; gn_unsupported_assertions_flag = true; @@ -1095,6 +1102,11 @@ int main(int argc, char*argv[]) else cout << ",no-specify"; + if (gn_interconnect_flag) + cout << ",interconnect"; + else + cout << ",no-interconnect"; + if (gn_cadence_types_flag) cout << ",xtypes"; else diff --git a/net_scope.cc b/net_scope.cc index ba8c3577d..9fac014e8 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -572,8 +572,15 @@ void NetScope::add_module_port_info( unsigned idx, perm_string name, PortType::E info.name = name; info.type = ptype; info.width = width; + info.buffer = nullptr; } +PortInfo* NetScope::get_module_port_info( unsigned idx ) +{ + ivl_assert(*this, type_ == MODULE); + ivl_assert(*this, ports_.size() > idx); + return &ports_[idx]; +} unsigned NetScope::module_port_nets() const { @@ -872,3 +879,4 @@ void NetScope::add_tie_lo(Design*des) connect(sig->pin(0), tie_lo_->pin(0)); } } + diff --git a/netlist.cc b/netlist.cc index 561701b32..732df78e5 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1966,8 +1966,8 @@ unsigned NetSignExtend::width() const return width_; } -NetBUFZ::NetBUFZ(NetScope*s, perm_string n, unsigned w, bool trans) -: NetNode(s, n, 2), width_(w), transparent_(trans) +NetBUFZ::NetBUFZ(NetScope*s, perm_string n, unsigned w, bool trans, int port_info_index) +: NetNode(s, n, 2), width_(w), transparent_(trans), port_info_index_(port_info_index) { pin(0).set_dir(Link::OUTPUT); pin(1).set_dir(Link::INPUT); diff --git a/netlist.h b/netlist.h index ff5854da4..04aed1699 100644 --- a/netlist.h +++ b/netlist.h @@ -660,6 +660,7 @@ struct PortInfo PortType::Enum type; unsigned long width; perm_string name; + ivl_net_logic_t buffer; }; @@ -1127,6 +1128,8 @@ class NetScope : public Definitions, public Attrib { PortType::Enum type, unsigned long width ); + PortInfo* get_module_port_info(unsigned idx); + const std::vector &module_port_info() const; /* Scopes have their own time units and time precision. The @@ -2359,11 +2362,12 @@ class NetSubstitute : public NetNode { class NetBUFZ : public NetNode { public: - explicit NetBUFZ(NetScope*s, perm_string n, unsigned wid, bool transp); + explicit NetBUFZ(NetScope*s, perm_string n, unsigned wid, bool transp, int port_info_index = -1); ~NetBUFZ(); unsigned width() const; bool transparent() const { return transparent_; } + int port_info_index() const { return port_info_index_; } virtual void dump_node(std::ostream&, unsigned ind) const; virtual bool emit_node(struct target_t*) const; @@ -2371,6 +2375,7 @@ class NetBUFZ : public NetNode { private: unsigned width_; bool transparent_; + int port_info_index_; }; /* diff --git a/t-dll-api.cc b/t-dll-api.cc index 50cb6a2eb..17ff59b3d 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -992,6 +992,12 @@ extern "C" unsigned ivl_logic_width(ivl_net_logic_t net) return net->width_; } +extern "C" unsigned ivl_logic_port_buffer(ivl_net_logic_t net) +{ + assert(net); + return net->is_port_buffer; +} + extern "C" int ivl_udp_sequ(ivl_udp_t net) { assert(net); @@ -2315,6 +2321,11 @@ extern "C" unsigned ivl_scope_mod_module_port_width(ivl_scope_t net, unsigned id return net->module_ports_info[idx].width; } +extern "C" ivl_net_logic_t ivl_scope_mod_module_port_buffer(ivl_scope_t net, unsigned idx ) +{ + assert(net); + return (ivl_net_logic_t)net->module_ports_info[idx].buffer; +} extern "C" unsigned ivl_scope_ports(ivl_scope_t net) { diff --git a/t-dll.cc b/t-dll.cc index b009f14f8..85600143e 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -856,6 +856,7 @@ bool dll_target::bufz(const NetBUFZ*net) obj->type_ = net->transparent()? IVL_LO_BUFT : IVL_LO_BUFZ; obj->width_= net->width(); obj->is_cassign = 0; + obj->is_port_buffer = net->port_info_index() >= 0; obj->npins_= 2; obj->pins_ = new ivl_nexus_t[2]; FILE_NAME(obj, net); @@ -892,6 +893,15 @@ bool dll_target::bufz(const NetBUFZ*net) scope_add_logic(scop, obj); + // Add bufz to the corresponding port_info entry, + // if it is an input / output buffer + // This is needed for the SDF interconnect feature + // to access the buffers directly from the port_info + if (obj->is_port_buffer) + { + scop->module_ports_info[net->port_info_index()].buffer = obj; + } + return true; } @@ -959,6 +969,7 @@ void dll_target::logic(const NetLogic*net) struct ivl_net_logic_s *obj = new struct ivl_net_logic_s; obj->width_ = net->width(); + obj->is_port_buffer = 0; FILE_NAME(obj, net); @@ -1427,6 +1438,7 @@ void dll_target::udp(const NetUDP*net) struct ivl_net_logic_s *obj = new struct ivl_net_logic_s; obj->type_ = IVL_LO_UDP; + obj->is_port_buffer = 0; FILE_NAME(obj, net); /* The NetUDP class hasn't learned about width yet, so we diff --git a/t-dll.h b/t-dll.h index 909ab5e94..15f727117 100644 --- a/t-dll.h +++ b/t-dll.h @@ -530,6 +530,7 @@ struct ivl_net_logic_s { ivl_logic_t type_; unsigned width_; unsigned is_cassign; + unsigned is_port_buffer; ivl_udp_t udp; perm_string name_; diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index e8e4e4ec5..9becbab24 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -308,6 +308,9 @@ int signal_is_return_value(ivl_signal_t sig) */ int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr) { + // If bufz is a module input/output buffer do not elide + if (ivl_logic_port_buffer(net)) return 0; + ivl_nexus_t in_n, out_n; unsigned idx; @@ -2405,11 +2408,14 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) const char *name = ivl_scope_mod_module_port_name(net,idx); ivl_signal_port_t ptype = ivl_scope_mod_module_port_type(net,idx); unsigned width = ivl_scope_mod_module_port_width(net,idx); + ivl_net_logic_t buffer = ivl_scope_mod_module_port_buffer(net,idx); if( name == 0 ) name = ""; - fprintf( vvp_out, " .port_info %u %s %u \"%s\";\n", + fprintf( vvp_out, " .port_info %u %s %u \"%s\"", idx, vvp_port_info_type_str(ptype), width, - vvp_mangle_name(name) ); + vvp_mangle_name(name) ); + if (buffer) fprintf( vvp_out, " L_%p;\n", buffer); + else fprintf( vvp_out, ";\n"); } } @@ -2529,3 +2535,4 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) ivl_scope_children(net, (ivl_scope_f*) draw_scope, net); return 0; } + diff --git a/vpi_modules.cc b/vpi_modules.cc index cb7b0eb9f..ab8f86f7c 100644 --- a/vpi_modules.cc +++ b/vpi_modules.cc @@ -46,7 +46,7 @@ void vpi_get_systf_info(vpiHandle, p_vpi_systf_data) { } vpiHandle vpi_handle_by_name(const char*, vpiHandle) { return 0; } vpiHandle vpi_handle_by_index(vpiHandle, PLI_INT32) { return 0; } -vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, vpiHandle ref2) { return 0; } +vpiHandle vpi_handle_multi(PLI_INT32, vpiHandle, vpiHandle) { return 0; } // for traversing relationships diff --git a/vvp/compile.h b/vvp/compile.h index 76befa6d6..57cdf3e4d 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -514,7 +514,7 @@ extern void compile_var_queue(char*label, char*name, unsigned size); * nets connected through module ports. */ -extern void compile_port_info( unsigned index, int vpi_port_type, unsigned width, const char *name ); +extern void compile_port_info( unsigned index, int vpi_port_type, unsigned width, const char *name, char* buffer ); /* diff --git a/vvp/parse.y b/vvp/parse.y index 1224fa21a..2f5ed3c95 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -713,10 +713,13 @@ statement /* Port information for scopes... currently this is just meta-data for VPI queries */ + | K_PORT_INFO T_NUMBER port_type T_NUMBER T_STRING T_SYMBOL ';' + { compile_port_info( $2 /* port_index */, $3, $4 /* width */, + $5 /*&name */, $6 /* buffer */ ); } + | K_PORT_INFO T_NUMBER port_type T_NUMBER T_STRING ';' { compile_port_info( $2 /* port_index */, $3, $4 /* width */, - $5 /*&name */ ); } - + $5 /*&name */, nullptr /* buffer */ ); } | K_TIMESCALE T_NUMBER T_NUMBER';' { compile_timescale($2, $3); } diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 115d6fe61..1cbbdae4f 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1583,9 +1583,15 @@ void print_net_type(vvp_net_t* net1) else if (dynamic_cast(net1->fun)) std::cout << "vvp_named_event*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_bufif*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_dff*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_and*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_equiv*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_impl*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_or*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_xor*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_boolean_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_buft*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_bufz*!" << std::endl; + else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_muxz*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_muxr*!" << std::endl; else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_not*!" << std::endl; @@ -1686,70 +1692,35 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; }*/ - std::string port_name1(vpi_get_str(vpiName, ref1)); - std::string port_name2(vpi_get_str(vpiName, ref2)); + vvp_net_t* net1 = port1->get_port(); + vvp_net_t* net2 = port2->get_port(); - fprintf(stderr, "port_name1: %s\n", port_name1.c_str()); - fprintf(stderr, "port_name2: %s\n", port_name2.c_str()); - - vpiHandle mod1 = vpi_handle(vpiModule, ref1); - vpiHandle mod2 = vpi_handle(vpiModule, ref2); - - if (!mod1) fprintf(stderr, "Cannot access module of port1!\n"); - if (!mod2) fprintf(stderr, "Cannot access module of port2!\n"); - - // Find net for port1 - vpiHandle net_i = vpi_iterate(vpiNet, mod1); - vpiHandle net; - vpiHandle net_handle1 = nullptr; - - while ((net=vpi_scan(net_i)) != nullptr) + if (net1 == nullptr || net2 == nullptr) { - char *net_name = vpi_get_str(vpiName, net); - - fprintf(stderr, "Comparing %s and %s\n", net_name, port_name1.c_str()); - if (port_name1 == net_name) - { - if (net_handle1 != nullptr) - { - fprintf(stderr, "Found multiple matching nets for %s !\n", port_name1.c_str()); - } - fprintf(stderr, "Found handle for net %s!\n", net_name); - net_handle1 = net; - } + fprintf(stderr, "Error: Could not find net. " + "Did you run iverilog with '-ginterconnect'?\n"); + return nullptr; } - // Find net for port2 - net_i = vpi_iterate(vpiNet, mod2); - vpiHandle net_handle2 = nullptr; - - while ((net=vpi_scan(net_i)) != nullptr) + if (!dynamic_cast(net1->fun)) { - char *net_name = vpi_get_str(vpiName, net); - - fprintf(stderr, "Comparing %s and %s\n", net_name, port_name2.c_str()); - if (port_name2 == net_name) - { - if (net_handle2 != nullptr) - { - fprintf(stderr, "Found multiple matching nets for %s !\n", port_name2.c_str()); - } - fprintf(stderr, "Found handle for net %s!\n", net_name); - net_handle2 = net; - } + fprintf(stderr, "Error: functor of net1 must be" + "vvp_fun_buft\n"); + return nullptr; } - // Try to access net/node behind it - struct __vpiSignal*node1 = dynamic_cast<__vpiSignal*>(net_handle1); - assert(node1); - struct __vpiSignal*node2 = dynamic_cast<__vpiSignal*>(net_handle2); - assert(node2); + if (!dynamic_cast(net2->fun)) + { + fprintf(stderr, "Error: functor of net2 must be" + "vvp_fun_buft\n"); + return nullptr; + } - vvp_net_t* net1 = node1->node; - vvp_net_t* net2 = node2->node; + std::cout << "net1: "; print_net_type(net1); + print_port_connections(&net1->out_); - print_net_type(net1); - print_net_type(net2); + std::cout << "net2: "; print_net_type(net2); + print_port_connections(&net2->out_); // Debug information @@ -1767,50 +1738,35 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, //fprintf(stderr, "net1->out_.ptr() : %p\n", net1->out_.ptr()); // vvp_net_t //fprintf(stderr, "net1->out_.port() : %d\n", net1->out_.port()); // input 3-0 - // TODO don't just compare the nets, may be a problem for high fan-out nets - if (net1 == net2) + // TODO don't just compare the nets, may be a problem for high fan-out nets + if (net1 == net2 )//&& port2->get_direction() == vpiOutput) { fprintf(stderr, "Same net!\n"); + return nullptr; // TODO - vvp_net_ptr_t* next_ptr = &net1->out_; + // TODO Problem: this only delays the output as viewed from outside + // because the net for output points to before inserted intermodpath + fprintf(stderr, "Output port!\n"); - fprintf(stderr, "Port connections:\n"); + // Check if there is already an intermodpath TODO - print_port_connections(next_ptr); + fprintf(stderr, "Inserting intermodpath...\n"); - fprintf(stderr, "End port connections:\n"); - - std::cout << *next_ptr << std::endl; - - vvp_net_t* next_net = next_ptr->ptr(); - //assert(next_net); - - if (!next_net) return 0; - - print_net_type(next_net); - - for (int i=0; i<4; i++) - { - fprintf(stderr, "next_net->port[%d].ptr() : %p\n", i, next_net->port[i].ptr()); - fprintf(stderr, "next_net->port[%d].port() : %d\n", i, next_net->port[i].port()); - - if (next_net->port[i].ptr()) print_net_type(next_net->port[i].ptr()); - } - - - // May be connected to both vvp_fun_modpath_src* and vvp_fun_bufz*! - //if (next_net->port[next_ptr->port()].ptr() == nullptr) - //{ - //fprintf(stderr, "next_net is the only thing connected to net1/net2!\n"); - int width = 1; // TODO + int width = 1; // TODO get width of port, check port widths are equal vvp_net_t*new_net = new vvp_net_t; vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); new_net->fun = obj; - new_net->out_= vvp_net_ptr_t(next_net,0); // point to port0 of net2 + // point to where net1/net2 was pointing + vvp_net_ptr_t net1_ptr = net1->out_; + + // net1/net2 points to intermodpath + net1->out_ = vvp_net_ptr_t(new_net,0); + + // out of new_net should point to net2 + new_net->out_= net1_ptr; // point to port0 of net2 - net1->out_ = vvp_net_ptr_t(new_net,0); // point to port0 of new_net __vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2); intermodpath->intermodpath = obj; @@ -1818,41 +1774,114 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, fprintf(stderr, "Inserted vvp_fun_intermodpath!\n"); return intermodpath; - //} - } else { fprintf(stderr, "Different net!\n"); + //vvp_fun_port* fun_port1 = dynamic_cast(net1->fun); + //vvp_fun_port* fun_port2 = dynamic_cast(net2->fun); + + //if (!fun_port1 || !fun_port2) fprintf(stderr, "Not vvp_fun_port!\n"); + vvp_net_ptr_t* net1_ptr = &net1->out_; + vvp_net_ptr_t* net2_ptr = &net2->out_; - // TODO follow whole linked list - if (net1_ptr->ptr() == net2) + fprintf(stderr, "Connected to port1:\n"); + print_port_connections(net1_ptr); + + fprintf(stderr, "Connected to port2:\n"); + print_port_connections(net2_ptr); + + // TODO first iterate over list and if functor is vvp_fun_intermodpath + // then check if output is connected to net, if so return + vvp_net_ptr_t* net_ptr = net1_ptr; + + while (net_ptr) + { + vvp_net_t* next_net = net_ptr->ptr(); + + if (!next_net) break; // End of list + + // Found a vvp_fun_intermodpath, check if port2 is connected + if (dynamic_cast(next_net->fun)) + { + if (next_net->out_.ptr() == net2) + { + fprintf(stderr, "Found already existing modpath!\n"); + + // Return the intermodpath TODO is it correct to create a new object? + // or add reference to __vpiInterModPath from vvp_fun_intermodpath + __vpiInterModPath*intermodpath = vpip_make_intermodpath(next_net, port1, port2); + + return intermodpath; + } + } + + net_ptr = &next_net->port[net_ptr->port()]; + } + + // Iterate over linked list until port2 is found + net_ptr = net1_ptr; + vvp_net_ptr_t previous_net_ptr = vvp_net_ptr_t(nullptr, 0); + vvp_net_t* previous_net = net1; + + while (net_ptr) + { + vvp_net_t* next_net = net_ptr->ptr(); + + if (!next_net) break; // End of list + if (next_net == net2) break; // Found net2 + + previous_net_ptr = *net_ptr; + net_ptr = &next_net->port[net_ptr->port()]; + } + + if (!net_ptr->ptr()) return 0; + + fprintf(stderr, "Net2 connected to net1!\n"); + + fprintf(stderr, "%p\n", previous_net); + + fprintf(stderr, "Inserting intermodpath...\n"); + + int width = 1; // TODO get width of port, check port widths are equal + + vvp_net_t*new_net = new vvp_net_t; + vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); + new_net->fun = obj; + + // point to where net2 was pointing + new_net->port[0] = net_ptr->ptr()->port[net_ptr->port()]; + + // Directly connected to port1 + if (!previous_net_ptr.ptr()) { - fprintf(stderr, "But net1 connected to net2!\n"); - - if (net2->port[net1_ptr->port()].ptr() == nullptr) - { - fprintf(stderr, "Net2 is the only thing connected to net1!\n"); - - int width = 1; // TODO - - vvp_net_t*new_net = new vvp_net_t; - vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); - new_net->fun = obj; - - new_net->out_= vvp_net_ptr_t(net2,0); // point to port0 of net2 - net1->out_ = vvp_net_ptr_t(new_net,0); // point to port0 of new_net - - __vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2); - intermodpath->intermodpath = obj; - - fprintf(stderr, "Inserted vvp_fun_intermodpath!\n"); - - return intermodpath; - } + net1->out_ = vvp_net_ptr_t(new_net,0); } + else + { + // what pointed to net2 should point to new_net + previous_net_ptr.ptr()->port[previous_net_ptr.port()] = vvp_net_ptr_t(new_net,0); + } + + // out of new_net should point to net2 + new_net->out_= vvp_net_ptr_t(net2,0); // point to port0 of net2 + + + __vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2); + intermodpath->intermodpath = obj; + + fprintf(stderr, "Inserted vvp_fun_intermodpath!\n"); + + fprintf(stderr, "Connected to port1:\n"); + print_port_connections(net1_ptr); + + fprintf(stderr, "Connected to port2:\n"); + print_port_connections(net2_ptr); + + return intermodpath; + } std::cout << "sorry: Could not insert intermodpath!" << std::endl; return nullptr; diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 842c2874b..3ebaa820e 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -439,7 +439,8 @@ class vpiPortInfo : public __vpiHandle { unsigned index, int vpi_direction, unsigned width, - const char *name ); + const char *name, + char* buffer ); ~vpiPortInfo(); int get_type_code(void) const { return vpiPort; } @@ -448,6 +449,7 @@ class vpiPortInfo : public __vpiHandle { int vpi_get(int code); char* vpi_get_str(int code); vpiHandle vpi_handle(int code); + vvp_net_t* get_port(void) const { return ref_; } private: __vpiScope *parent_; @@ -455,6 +457,7 @@ class vpiPortInfo : public __vpiHandle { int direction_; unsigned width_; const char *name_; + vvp_net_t *ref_; }; /* diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 2057abbac..5b660e486 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -666,13 +666,16 @@ vpiPortInfo::vpiPortInfo( __vpiScope *parent, unsigned index, int vpi_direction, unsigned width, - const char *name ) : + const char *name, + char* buffer) : parent_(parent), index_(index), direction_(vpi_direction), width_(width), name_(name) { + if (buffer != nullptr) functor_ref_lookup(&ref_, buffer); + else ref_ = nullptr; } vpiPortInfo::~vpiPortInfo() @@ -737,9 +740,9 @@ vpiHandle vpiPortInfo::vpi_handle(int code) * code-generators etc. There are no actual nets corresponding to instances of module ports * as elaboration directly connects nets connected through module ports. */ -void compile_port_info( unsigned index, int vpi_direction, unsigned width, const char *name ) +void compile_port_info( unsigned index, int vpi_direction, unsigned width, const char *name, char* buffer ) { vpiHandle obj = new vpiPortInfo( vpip_peek_current_scope(), - index, vpi_direction, width, name ); + index, vpi_direction, width, name, buffer ); vpip_attach_to_current_scope(obj); } From 423f88cce990692912a83cc77eb3dc5c032c6e5d Mon Sep 17 00:00:00 2001 From: mole99 Date: Wed, 16 Aug 2023 09:04:10 +0200 Subject: [PATCH 08/14] Fix annotation for special cases --- vvp/vpi_priv.cc | 98 ++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 54 deletions(-) diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 1cbbdae4f..8a7cb16a7 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1680,6 +1680,13 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; } + bool is_output = false; + if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput) + { + std::cout << "OUTPUT!!!" << std::endl; + is_output = true; + } + /*if (!(port1->get_direction() == vpiOutput || port1->get_direction() == vpiInout)) { fprintf(stderr, "ERROR: First vpiPort must be an output" " or bidirectional port\n"); @@ -1821,66 +1828,49 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, net_ptr = &next_net->port[net_ptr->port()]; } - // Iterate over linked list until port2 is found - net_ptr = net1_ptr; - vvp_net_ptr_t previous_net_ptr = vvp_net_ptr_t(nullptr, 0); - vvp_net_t* previous_net = net1; + // Verify if port2 is connected to port1 + vvp_net_t* current_net = net1_ptr->ptr(); - while (net_ptr) + while (current_net) { - vvp_net_t* next_net = net_ptr->ptr(); + if (!current_net) break; // End of list - if (!next_net) break; // End of list - if (next_net == net2) break; // Found net2 + if (current_net == net2) + { + std::cout << "Found net2!" << std::endl; - previous_net_ptr = *net_ptr; - net_ptr = &next_net->port[net_ptr->port()]; + // Ol switcheroo + vvp_net_fun_t* net2_functor = net2->fun; + + int width = 1; // TODO + vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(net2, width); + net2->fun = obj; + + vvp_net_t*new_net = new vvp_net_t; + new_net->fun = net2_functor; + //net2_functor->net = new_net; + + new_net->out_ = net2->out_; + net2->out_ = vvp_net_ptr_t(new_net, 0); + + + __vpiInterModPath*intermodpath = vpip_make_intermodpath(net2, port1, port2); + intermodpath->intermodpath = obj; + + fprintf(stderr, "Inserted vvp_fun_intermodpath!\n"); + + fprintf(stderr, "Connected to port1:\n"); + print_port_connections(net1_ptr); + + fprintf(stderr, "Connected to port2:\n"); + print_port_connections(net2_ptr); + + return intermodpath; + } + current_net = current_net->port[0].ptr(); // BUFT has only one input, index 0 } - if (!net_ptr->ptr()) return 0; - - fprintf(stderr, "Net2 connected to net1!\n"); - - fprintf(stderr, "%p\n", previous_net); - - fprintf(stderr, "Inserting intermodpath...\n"); - - int width = 1; // TODO get width of port, check port widths are equal - - vvp_net_t*new_net = new vvp_net_t; - vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); - new_net->fun = obj; - - // point to where net2 was pointing - new_net->port[0] = net_ptr->ptr()->port[net_ptr->port()]; - - // Directly connected to port1 - if (!previous_net_ptr.ptr()) - { - net1->out_ = vvp_net_ptr_t(new_net,0); - } - else - { - // what pointed to net2 should point to new_net - previous_net_ptr.ptr()->port[previous_net_ptr.port()] = vvp_net_ptr_t(new_net,0); - } - - // out of new_net should point to net2 - new_net->out_= vvp_net_ptr_t(net2,0); // point to port0 of net2 - - - __vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2); - intermodpath->intermodpath = obj; - - fprintf(stderr, "Inserted vvp_fun_intermodpath!\n"); - - fprintf(stderr, "Connected to port1:\n"); - print_port_connections(net1_ptr); - - fprintf(stderr, "Connected to port2:\n"); - print_port_connections(net2_ptr); - - return intermodpath; + std::cout << "Could not find net2!" << std::endl; } std::cout << "sorry: Could not insert intermodpath!" << std::endl; From db068aa1370027ecee89a909cd34a1a2d4c1e57b Mon Sep 17 00:00:00 2001 From: mole99 Date: Thu, 17 Aug 2023 10:18:56 +0200 Subject: [PATCH 09/14] Correctly dump the delayed signal for output ports --- vvp/vpi_priv.cc | 324 ++++++++++++------------------------------------ 1 file changed, 79 insertions(+), 245 deletions(-) diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 8a7cb16a7..39b8aee44 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1564,90 +1564,6 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope) return out; } -void print_net_type(vvp_net_t* net1) -{ - if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_delay*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_modpath*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_modpath_src*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_pv*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_var*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_abs*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_cast_int*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_cast_real*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_cast_vec2*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_arith_real_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_edge*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_anyedge*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_event_or*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_named_event*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_bufif*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_dff*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_and*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_equiv*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_impl*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_or*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_xor*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_boolean_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_buft*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_bufz*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_muxz*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_muxr*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_not*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_concat*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_concat8*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_force*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_repeat*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_drive*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_extend_signed*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_wide_fun_core*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_wide_fun_t*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_vec*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_real*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_string*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_object*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_signal_base*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "resolv_core*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "resolv_extend*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_latch*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_pmos_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_cmos_*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_island_port*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_intermodpath*!" << std::endl; - - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_base*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_and*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_or*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_xor*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_nand*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_nor*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_reduce_xnor*!" << std::endl; - - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_sa*!" << std::endl; - else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_part_aa*!" << std::endl; - - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_substitute*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_arrayport*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_arrayport_sa*!" << std::endl; - //else if (dynamic_cast(net1->fun)) std::cout << "vvp_fun_arrayport_aa*!" << std::endl; - - else std::cout << "unknown!" << std::endl; -} - -void print_port_connections(vvp_net_ptr_t* net_ptr) -{ - vvp_net_t* next_net = net_ptr->ptr(); - if (!next_net) return; - - print_net_type(next_net); - vvp_net_ptr_t* next_net_ptr = &next_net->port[net_ptr->port()]; - - print_port_connections(next_net_ptr); -} - - // Used to get intermodpath for two ports vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, @@ -1660,7 +1576,7 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, if (type != vpiInterModPath) { fprintf(stderr, "sorry: vpi_handle_multi currently supports" - "only vpiInterModPath\n"); + "only vpiInterModPath\n"); return nullptr; } @@ -1680,24 +1596,32 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; } - bool is_output = false; + // If both ports are vpiOutput, we have to reassign the __vpiSignal from port1 + // to port2 because otherwise the non-delayed version of the signal is dumped + // even tho the intermodpath is correctly inserted + __vpiSignal* output_signal = nullptr; + if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput) { - std::cout << "OUTPUT!!!" << std::endl; - is_output = true; - } + vpiHandle scope_port2 = vpi_handle(vpiScope, ref2); + assert(scope_port2); + std::string port2_name(vpi_get_str(vpiName, ref2)); - /*if (!(port1->get_direction() == vpiOutput || port1->get_direction() == vpiInout)) { - fprintf(stderr, "ERROR: First vpiPort must be an output" - " or bidirectional port\n"); - return nullptr; - } + // Iterate over nets in the scope of port2 + vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ; + vpiHandle net; - if (!(port2->get_direction() == vpiInput || port2->get_direction() == vpiInout)) { - fprintf(stderr, "ERROR: Second vpiPort must be an input" - " or bidirectional port\n"); - return nullptr; - }*/ + while ((net = vpi_scan(net_i)) != NULL) + { + std::string net_name(vpi_get_str(vpiName, net)); + + // Compare whether the net matches with the port name + if (net_name == port2_name) + { + output_signal = dynamic_cast<__vpiSignal*>(net); + } + } + } vvp_net_t* net1 = port1->get_port(); vvp_net_t* net2 = port2->get_port(); @@ -1709,6 +1633,13 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; } + if (net1 == net2) + { + fprintf(stderr, "Error: Net for both ports is the same. " + "Did you pass the same port twice?\n"); + return nullptr; + } + if (!dynamic_cast(net1->fun)) { fprintf(stderr, "Error: functor of net1 must be" @@ -1723,156 +1654,59 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; } - std::cout << "net1: "; print_net_type(net1); - print_port_connections(&net1->out_); + // Iterate over all nodes connected to port1 + vvp_net_ptr_t cur = net1->out_; + vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0); - std::cout << "net2: "; print_net_type(net2); - print_port_connections(&net2->out_); - - // Debug information - - for (int i=0; i<4; i++) + while (cur.ptr()) { - fprintf(stderr, "net1->port[%d].ptr() : %p\n", i, net1->port[i].ptr()); - fprintf(stderr, "net1->port[%d].port() : %d\n", i, net1->port[i].port()); + // Port2 is directly connected to port1 + if (cur.ptr() == net2) + { + vvp_net_t*new_net = new vvp_net_t; + + int width = 1; // TODO + vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); + new_net->fun = obj; + new_net->out_ = cur; // TODO pointer to current net + + // Port2 is in the middle of the list + // Insert intermodpath before port2 and keep everything else intact + if (prev.ptr()) + { + prev.ptr()->port[prev.port()] = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath + new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list + cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath + } + // Port2 is first in list + // Insert intermodpath before port2 and keep everything else intact + else + { + net1->out_ = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath + new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list + cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath + } + + // If both ports are vpiOutput, we have to reassign the __vpiSignal + if (output_signal) + { + net2->fil = net1->fil; + net1->fil = nullptr; + output_signal->node = net2; + } + + // Create the VPI intermodpath object + __vpiInterModPath* intermodpath = vpip_make_intermodpath(new_net, port1, port2); + intermodpath->intermodpath = obj; + + // Finally done, return the intermodpath object + return intermodpath; + } + + prev = cur; + cur = cur.ptr()->port[cur.port()]; // Next net in linked list } - fprintf(stderr, "net1->fun : %p\n", net1->fun); - fprintf(stderr, "net1->fil : %p\n", net1->fil); - - fprintf(stderr, "net1->fil->filter_size() : %d\n", net1->fil->filter_size()); - - //fprintf(stderr, "net1->out_.ptr() : %p\n", net1->out_.ptr()); // vvp_net_t - //fprintf(stderr, "net1->out_.port() : %d\n", net1->out_.port()); // input 3-0 - - // TODO don't just compare the nets, may be a problem for high fan-out nets - if (net1 == net2 )//&& port2->get_direction() == vpiOutput) - { - fprintf(stderr, "Same net!\n"); - return nullptr; // TODO - - // TODO Problem: this only delays the output as viewed from outside - // because the net for output points to before inserted intermodpath - fprintf(stderr, "Output port!\n"); - - // Check if there is already an intermodpath TODO - - fprintf(stderr, "Inserting intermodpath...\n"); - - int width = 1; // TODO get width of port, check port widths are equal - - vvp_net_t*new_net = new vvp_net_t; - vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); - new_net->fun = obj; - - // point to where net1/net2 was pointing - vvp_net_ptr_t net1_ptr = net1->out_; - - // net1/net2 points to intermodpath - net1->out_ = vvp_net_ptr_t(new_net,0); - - // out of new_net should point to net2 - new_net->out_= net1_ptr; // point to port0 of net2 - - - __vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2); - intermodpath->intermodpath = obj; - - fprintf(stderr, "Inserted vvp_fun_intermodpath!\n"); - - return intermodpath; - } - else - { - fprintf(stderr, "Different net!\n"); - - //vvp_fun_port* fun_port1 = dynamic_cast(net1->fun); - //vvp_fun_port* fun_port2 = dynamic_cast(net2->fun); - - //if (!fun_port1 || !fun_port2) fprintf(stderr, "Not vvp_fun_port!\n"); - - vvp_net_ptr_t* net1_ptr = &net1->out_; - vvp_net_ptr_t* net2_ptr = &net2->out_; - - fprintf(stderr, "Connected to port1:\n"); - print_port_connections(net1_ptr); - - fprintf(stderr, "Connected to port2:\n"); - print_port_connections(net2_ptr); - - // TODO first iterate over list and if functor is vvp_fun_intermodpath - // then check if output is connected to net, if so return - vvp_net_ptr_t* net_ptr = net1_ptr; - - while (net_ptr) - { - vvp_net_t* next_net = net_ptr->ptr(); - - if (!next_net) break; // End of list - - // Found a vvp_fun_intermodpath, check if port2 is connected - if (dynamic_cast(next_net->fun)) - { - if (next_net->out_.ptr() == net2) - { - fprintf(stderr, "Found already existing modpath!\n"); - - // Return the intermodpath TODO is it correct to create a new object? - // or add reference to __vpiInterModPath from vvp_fun_intermodpath - __vpiInterModPath*intermodpath = vpip_make_intermodpath(next_net, port1, port2); - - return intermodpath; - } - } - - net_ptr = &next_net->port[net_ptr->port()]; - } - - // Verify if port2 is connected to port1 - vvp_net_t* current_net = net1_ptr->ptr(); - - while (current_net) - { - if (!current_net) break; // End of list - - if (current_net == net2) - { - std::cout << "Found net2!" << std::endl; - - // Ol switcheroo - vvp_net_fun_t* net2_functor = net2->fun; - - int width = 1; // TODO - vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(net2, width); - net2->fun = obj; - - vvp_net_t*new_net = new vvp_net_t; - new_net->fun = net2_functor; - //net2_functor->net = new_net; - - new_net->out_ = net2->out_; - net2->out_ = vvp_net_ptr_t(new_net, 0); - - - __vpiInterModPath*intermodpath = vpip_make_intermodpath(net2, port1, port2); - intermodpath->intermodpath = obj; - - fprintf(stderr, "Inserted vvp_fun_intermodpath!\n"); - - fprintf(stderr, "Connected to port1:\n"); - print_port_connections(net1_ptr); - - fprintf(stderr, "Connected to port2:\n"); - print_port_connections(net2_ptr); - - return intermodpath; - } - current_net = current_net->port[0].ptr(); // BUFT has only one input, index 0 - } - - std::cout << "Could not find net2!" << std::endl; - - } std::cout << "sorry: Could not insert intermodpath!" << std::endl; return nullptr; } From 37119b15040a5874750498d548517616b99b4d48 Mon Sep 17 00:00:00 2001 From: mole99 Date: Thu, 17 Aug 2023 14:36:21 +0200 Subject: [PATCH 10/14] Remove some unnecessary output --- vpi/sdf_parse.y | 5 +---- vpi/sys_sdf.c | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/vpi/sdf_parse.y b/vpi/sdf_parse.y index 5187a0d80..d865aa9f1 100644 --- a/vpi/sdf_parse.y +++ b/vpi/sdf_parse.y @@ -337,10 +337,7 @@ del_def sdf_parse_path, @2.first_line); } /* | '(' K_INTERCONNECT port_instance port_instance delval_list ')' */ | '(' K_INTERCONNECT port_interconnect port_interconnect delval_list ')' - { if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: " - "INTERCONNECT not supported.\n", - sdf_parse_path, @2.first_line); - + { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: INTERCONNECT with " "port1 = %s index = %d, port2 = %s index = %d\n", sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index); diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 8426f987c..739803047 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -185,7 +185,6 @@ vpiHandle get_port_handle(char* port_name, const int sdf_lineno) { if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: Found multiple matching ports for %s !\n", sdf_fname, sdf_lineno, token); } - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Found handle for port %s!\n", sdf_fname, sdf_lineno, token); port_handle = port; } } @@ -211,7 +210,7 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne if (intermodpath) { - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Got an vpiInterModPath!\n", sdf_fname, sdf_lineno); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Created a vpiInterModPath\n", sdf_fname, sdf_lineno); s_vpi_delay delays; struct t_vpi_time delay_vals[12]; From 306e4cfa6b9438aa136af3e3f5ee681faf8adb8e Mon Sep 17 00:00:00 2001 From: mole99 Date: Thu, 17 Aug 2023 14:37:40 +0200 Subject: [PATCH 11/14] Add three tests to exercise interconnection delays in designs --- ivtest/gold/sdf_interconnect1-vvp-stdout.gold | 9 ++ ivtest/gold/sdf_interconnect2-vvp-stdout.gold | 9 ++ ivtest/gold/sdf_interconnect3-vvp-stdout.gold | 24 +++ ivtest/ivltests/sdf_interconnect1.sdf | 56 +++++++ ivtest/ivltests/sdf_interconnect1.v | 68 +++++++++ ivtest/ivltests/sdf_interconnect2.sdf | 55 +++++++ ivtest/ivltests/sdf_interconnect2.v | 70 +++++++++ ivtest/ivltests/sdf_interconnect3.sdf | 75 +++++++++ ivtest/ivltests/sdf_interconnect3.v | 143 ++++++++++++++++++ ivtest/regress-vvp.list | 3 + ivtest/vvp_tests/sdf_interconnect1.json | 6 + ivtest/vvp_tests/sdf_interconnect2.json | 6 + ivtest/vvp_tests/sdf_interconnect3.json | 6 + 13 files changed, 530 insertions(+) create mode 100644 ivtest/gold/sdf_interconnect1-vvp-stdout.gold create mode 100644 ivtest/gold/sdf_interconnect2-vvp-stdout.gold create mode 100644 ivtest/gold/sdf_interconnect3-vvp-stdout.gold create mode 100644 ivtest/ivltests/sdf_interconnect1.sdf create mode 100644 ivtest/ivltests/sdf_interconnect1.v create mode 100644 ivtest/ivltests/sdf_interconnect2.sdf create mode 100644 ivtest/ivltests/sdf_interconnect2.v create mode 100644 ivtest/ivltests/sdf_interconnect3.sdf create mode 100644 ivtest/ivltests/sdf_interconnect3.v create mode 100644 ivtest/vvp_tests/sdf_interconnect1.json create mode 100644 ivtest/vvp_tests/sdf_interconnect2.json create mode 100644 ivtest/vvp_tests/sdf_interconnect3.json diff --git a/ivtest/gold/sdf_interconnect1-vvp-stdout.gold b/ivtest/gold/sdf_interconnect1-vvp-stdout.gold new file mode 100644 index 000000000..860d290bc --- /dev/null +++ b/ivtest/gold/sdf_interconnect1-vvp-stdout.gold @@ -0,0 +1,9 @@ +SDF ERROR: ivltests/sdf_interconnect1.sdf:32: Unable to match ModPath in -> out in top.my_design_inst.buffer0 +SDF ERROR: ivltests/sdf_interconnect1.sdf:42: Unable to match ModPath in -> out in top.my_design_inst.buffer1 +SDF ERROR: ivltests/sdf_interconnect1.sdf:52: Unable to match ModPath in -> out in top.my_design_inst.buffer2 +time=0 a=x b=x +time=5000 a=0 b=x +time=5080 a=0 b=0 +time=15000 a=1 b=0 +time=15080 a=1 b=1 +ivltests/sdf_interconnect1.v:59: $finish called at 25000 (1ps) diff --git a/ivtest/gold/sdf_interconnect2-vvp-stdout.gold b/ivtest/gold/sdf_interconnect2-vvp-stdout.gold new file mode 100644 index 000000000..1f31b9428 --- /dev/null +++ b/ivtest/gold/sdf_interconnect2-vvp-stdout.gold @@ -0,0 +1,9 @@ +SDF ERROR: ivltests/sdf_interconnect2.sdf:31: Unable to match ModPath in -> out in top.my_design_inst.buffer0 +SDF ERROR: ivltests/sdf_interconnect2.sdf:41: Unable to match ModPath in -> out in top.my_design_inst.buffer1 +SDF ERROR: ivltests/sdf_interconnect2.sdf:51: Unable to match ModPath in -> out in top.my_design_inst.buffer2 +time=0 a=x b=x +time=5000 a=0 b=x +time=5010 a=0 b=0 +time=15000 a=1 b=0 +time=15030 a=1 b=1 +ivltests/sdf_interconnect2.v:61: $finish called at 25000 (1ps) diff --git a/ivtest/gold/sdf_interconnect3-vvp-stdout.gold b/ivtest/gold/sdf_interconnect3-vvp-stdout.gold new file mode 100644 index 000000000..1db8ffb91 --- /dev/null +++ b/ivtest/gold/sdf_interconnect3-vvp-stdout.gold @@ -0,0 +1,24 @@ +SDF ERROR: ivltests/sdf_interconnect3.sdf:41: Unable to match ModPath in -> out in top.my_design_inst.buffer0 +SDF ERROR: ivltests/sdf_interconnect3.sdf:51: Unable to match ModPath in -> out in top.my_design_inst.buffer1 +SDF ERROR: ivltests/sdf_interconnect3.sdf:61: Unable to match ModPath in -> out in top.my_design_inst.buffer2 +SDF ERROR: ivltests/sdf_interconnect3.sdf:71: Unable to match ModPath in -> out in top.my_design_inst.buffer3 +time=0 a=x b=x c=x d=x +time=10000 a=0 b=0 c=0 d=x +time=10060 a=0 b=0 c=0 d=0 +time=20000 a=1 b=0 c=0 d=0 +time=20060 a=1 b=0 c=0 d=1 +time=30000 a=0 b=1 c=0 d=1 +time=30050 a=0 b=1 c=0 d=0 +time=40000 a=1 b=1 c=0 d=0 +time=40060 a=1 b=1 c=0 d=1 +time=50000 a=0 b=0 c=1 d=1 +time=50040 a=0 b=0 c=1 d=0 +time=50050 a=0 b=0 c=1 d=1 +time=50060 a=0 b=0 c=1 d=0 +time=60000 a=1 b=0 c=1 d=0 +time=60060 a=1 b=0 c=1 d=1 +time=70000 a=0 b=1 c=1 d=1 +time=70050 a=0 b=1 c=1 d=0 +time=80000 a=1 b=1 c=1 d=0 +time=80060 a=1 b=1 c=1 d=1 +ivltests/sdf_interconnect3.v:132: $finish called at 90000 (1ps) diff --git a/ivtest/ivltests/sdf_interconnect1.sdf b/ivtest/ivltests/sdf_interconnect1.sdf new file mode 100644 index 000000000..914b011ef --- /dev/null +++ b/ivtest/ivltests/sdf_interconnect1.sdf @@ -0,0 +1,56 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "test") + (DATE "Wed Mar 8 12:34:56 2023") + (VENDOR "No Vendor") + (PROGRAM "Human") + (VERSION "1.0.0") + (DIVIDER .) + (VOLTAGE 5.5:5.0:4.5) + (PROCESS "best=0.65:nom=1.0:worst=1.8") + (TEMPERATURE -25.0:25.0:85.0) + (TIMESCALE 1 ns) + + (CELL + (CELLTYPE "my_design") + (INSTANCE) + (DELAY + (ABSOLUTE + (INTERCONNECT a buffer0.in (0.010:0.020:0.030) (0.010:0.020:0.030)) + (INTERCONNECT buffer0.out buffer1.in (0.010:0.020:0.030) (0.010:0.020:0.030)) + (INTERCONNECT buffer1.out buffer2.in (0.010:0.020:0.030) (0.010:0.020:0.030)) + (INTERCONNECT buffer2.out b (0.010:0.020:0.030) (0.010:0.020:0.030)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer0) + (DELAY + (ABSOLUTE + (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer1) + (DELAY + (ABSOLUTE + (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer2) + (DELAY + (ABSOLUTE + (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + ) + ) + ) +) diff --git a/ivtest/ivltests/sdf_interconnect1.v b/ivtest/ivltests/sdf_interconnect1.v new file mode 100644 index 000000000..122556220 --- /dev/null +++ b/ivtest/ivltests/sdf_interconnect1.v @@ -0,0 +1,68 @@ +`timescale 1ns/1ps + +/* + This design tests the interconnection delay + for three buffers in series +*/ + +module buffer ( + input in, + output out +); + specify + (in => out) = (0.0:0.0:0.0); + endspecify + + assign out = in; + +endmodule + +module my_design ( + input a, + output b +); + wire w1, w2; + + buffer buffer0 ( + .in (a), + .out (w1) + ); + + buffer buffer1 ( + .in (w1), + .out (w2) + ); + + buffer buffer2 ( + .in (w2), + .out (b) + ); + +endmodule + +module top; + + initial begin + $sdf_annotate("ivltests/sdf_interconnect1.sdf", my_design_inst); + $monitor("time=%0t a=%h b=%h", $realtime, a, b); + end + + reg a; + wire b; + + initial begin + #5; + a <= 1'b0; + #10; + a <= 1'b1; + #10; + $finish; + end + + my_design my_design_inst ( + .a (a), + .b (b) + ); + +endmodule + diff --git a/ivtest/ivltests/sdf_interconnect2.sdf b/ivtest/ivltests/sdf_interconnect2.sdf new file mode 100644 index 000000000..eef3b95cd --- /dev/null +++ b/ivtest/ivltests/sdf_interconnect2.sdf @@ -0,0 +1,55 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "test") + (DATE "Wed Mar 8 12:34:56 2023") + (VENDOR "No Vendor") + (PROGRAM "Human") + (VERSION "1.0.0") + (DIVIDER .) + (VOLTAGE 5.5:5.0:4.5) + (PROCESS "best=0.65:nom=1.0:worst=1.8") + (TEMPERATURE -25.0:25.0:85.0) + (TIMESCALE 1 ns) + + (CELL + (CELLTYPE "my_design") + (INSTANCE) + (DELAY + (ABSOLUTE + (INTERCONNECT a buffer0.in (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT a buffer1.in (0.000:0.020:0.000) (0.000:0.020:0.000)) + (INTERCONNECT a buffer2.in (0.000:0.030:0.000) (0.000:0.030:0.000)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer0) + (DELAY + (ABSOLUTE + (IOPATH in out (0.000:0.100:0.000) (0.000:0.100:0.000)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer1) + (DELAY + (ABSOLUTE + (IOPATH in out (0.000:0.200:0.000) (0.000:0.200:0.000)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer2) + (DELAY + (ABSOLUTE + (IOPATH in out (0.000:0.300:0.000) (0.000:0.300:0.000)) + ) + ) + ) +) diff --git a/ivtest/ivltests/sdf_interconnect2.v b/ivtest/ivltests/sdf_interconnect2.v new file mode 100644 index 000000000..296416fbd --- /dev/null +++ b/ivtest/ivltests/sdf_interconnect2.v @@ -0,0 +1,70 @@ +`timescale 1ns/1ps + +/* + This design tests the interconnection delay + for three buffers in parallel +*/ + +module buffer ( + input in, + output out +); + specify + (in => out) = (0.0:0.0:0.0); + endspecify + + assign out = in; + +endmodule + +module my_design ( + input a, + output b +); + wire w1, w2, w3; + + buffer buffer0 ( + .in (a), + .out (w1) + ); + + buffer buffer1 ( + .in (a), + .out (w2) + ); + + buffer buffer2 ( + .in (a), + .out (w3) + ); + + assign b = w1 & w2 & w3; + +endmodule + +module top; + + initial begin + $sdf_annotate("ivltests/sdf_interconnect2.sdf", my_design_inst); + $monitor("time=%0t a=%h b=%h", $realtime, a, b); + end + + reg a; + wire b; + + initial begin + #5; + a <= 1'b0; + #10; + a <= 1'b1; + #10; + $finish; + end + + my_design my_design_inst ( + .a (a), + .b (b) + ); + +endmodule + diff --git a/ivtest/ivltests/sdf_interconnect3.sdf b/ivtest/ivltests/sdf_interconnect3.sdf new file mode 100644 index 000000000..b4ebb0017 --- /dev/null +++ b/ivtest/ivltests/sdf_interconnect3.sdf @@ -0,0 +1,75 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "test") + (DATE "Wed Mar 8 12:34:56 2023") + (VENDOR "No Vendor") + (PROGRAM "Human") + (VERSION "1.0.0") + (DIVIDER .) + (VOLTAGE 5.5:5.0:4.5) + (PROCESS "best=0.65:nom=1.0:worst=1.8") + (TEMPERATURE -25.0:25.0:85.0) + (TIMESCALE 1 ns) + + (CELL + (CELLTYPE "my_design") + (INSTANCE) + (DELAY + (ABSOLUTE + (INTERCONNECT a buffer0.in (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT b my_xor0.a (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT c my_xor0.b (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT buffer0.out my_xor1.a (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT b my_xor1.b (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT my_xor0.out buffer1.in (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT my_xor1.out my_xor2.a (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT buffer1.out my_xor2.b (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT c buffer2.in (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT my_xor2.out my_xor3.a (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT buffer2.out my_xor3.b (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT my_xor3.out buffer3.in (0.000:0.010:0.000) (0.000:0.010:0.000)) + (INTERCONNECT buffer3.out d (0.000:0.010:0.000) (0.000:0.010:0.000)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer0) + (DELAY + (ABSOLUTE + (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer1) + (DELAY + (ABSOLUTE + (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer2) + (DELAY + (ABSOLUTE + (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer3) + (DELAY + (ABSOLUTE + (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + ) + ) + ) +) diff --git a/ivtest/ivltests/sdf_interconnect3.v b/ivtest/ivltests/sdf_interconnect3.v new file mode 100644 index 000000000..c62d7e8d7 --- /dev/null +++ b/ivtest/ivltests/sdf_interconnect3.v @@ -0,0 +1,143 @@ +`timescale 1ns/1ps + +/* + This design tests the interconnection delays + for a circuit of various buffers and xors +*/ + +module my_xor ( + input a, + input b, + output out +); + specify + (a => out) = (0.0:0.0:0.0); + (b => out) = (0.0:0.0:0.0); + endspecify + + assign out = a ^ b; + +endmodule + +module buffer ( + input in, + output out +); + specify + (in => out) = (0.0:0.0:0.0); + endspecify + + assign out = in; + +endmodule + +module my_design ( + input a, + input b, + input c, + output d +); + wire w1, w2, w3, w4, w5, w6, w7; + + buffer buffer0 ( + .in (a), + .out (w1) + ); + + my_xor my_xor0 ( + .a (b), + .b (c), + .out (w2) + ); + + my_xor my_xor1 ( + .a (w1), + .b (b), + .out (w3) + ); + + buffer buffer1 ( + .in (w2), + .out (w4) + ); + + my_xor my_xor2 ( + .a (w3), + .b (w4), + .out (w5) + ); + + buffer buffer2 ( + .in (c), + .out (w6) + ); + + my_xor my_xor3 ( + .a (w5), + .b (w6), + .out (w7) + ); + + buffer buffer3 ( + .in (w7), + .out (d) + ); + +endmodule + +module top; + + initial begin + $sdf_annotate("ivltests/sdf_interconnect3.sdf", my_design_inst); + $monitor("time=%0t a=%h b=%h c=%h d=%h", $realtime, a, b, c, d); + end + + reg a, b, c; + wire d; + + initial begin + #10; + a <= 1'b0; + b <= 1'b0; + c <= 1'b0; + #10; + a <= 1'b1; + b <= 1'b0; + c <= 1'b0; + #10; + a <= 1'b0; + b <= 1'b1; + c <= 1'b0; + #10; + a <= 1'b1; + b <= 1'b1; + c <= 1'b0; + #10; + a <= 1'b0; + b <= 1'b0; + c <= 1'b1; + #10; + a <= 1'b1; + b <= 1'b0; + c <= 1'b1; + #10; + a <= 1'b0; + b <= 1'b1; + c <= 1'b1; + #10; + a <= 1'b1; + b <= 1'b1; + c <= 1'b1; + #10; + $finish; + end + + my_design my_design_inst ( + .a (a), + .b (b), + .c (c), + .d (d) + ); + +endmodule + diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index b18194e48..b3dffb45f 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -94,3 +94,6 @@ task_return_fail1 vvp_tests/task_return_fail1.json task_return_fail2 vvp_tests/task_return_fail2.json timing_check_syntax vvp_tests/timing_check_syntax.json timing_check_delayed_signals vvp_tests/timing_check_delayed_signals.json +sdf_interconnect1 vvp_tests/sdf_interconnect1.json +sdf_interconnect2 vvp_tests/sdf_interconnect2.json +sdf_interconnect3 vvp_tests/sdf_interconnect3.json diff --git a/ivtest/vvp_tests/sdf_interconnect1.json b/ivtest/vvp_tests/sdf_interconnect1.json new file mode 100644 index 000000000..d9d587c3e --- /dev/null +++ b/ivtest/vvp_tests/sdf_interconnect1.json @@ -0,0 +1,6 @@ +{ + "type" : "normal", + "source" : "sdf_interconnect1.v", + "iverilog-args" : [ "-Ttyp", "-ginterconnect" ], + "gold" : "sdf_interconnect1" +} diff --git a/ivtest/vvp_tests/sdf_interconnect2.json b/ivtest/vvp_tests/sdf_interconnect2.json new file mode 100644 index 000000000..44bb83a8a --- /dev/null +++ b/ivtest/vvp_tests/sdf_interconnect2.json @@ -0,0 +1,6 @@ +{ + "type" : "normal", + "source" : "sdf_interconnect2.v", + "iverilog-args" : [ "-Ttyp", "-ginterconnect" ], + "gold" : "sdf_interconnect2" +} diff --git a/ivtest/vvp_tests/sdf_interconnect3.json b/ivtest/vvp_tests/sdf_interconnect3.json new file mode 100644 index 000000000..fa67e509b --- /dev/null +++ b/ivtest/vvp_tests/sdf_interconnect3.json @@ -0,0 +1,6 @@ +{ + "type" : "normal", + "source" : "sdf_interconnect3.v", + "iverilog-args" : [ "-Ttyp", "-ginterconnect" ], + "gold" : "sdf_interconnect3" +} From 11c944f5e9356c1405115e6a9827e143f7caf9b0 Mon Sep 17 00:00:00 2001 From: mole99 Date: Thu, 17 Aug 2023 16:09:20 +0200 Subject: [PATCH 12/14] Cleanup --- driver/main.c | 2 +- elaborate.cc | 38 ++++----- t-dll.cc | 13 ++-- tgt-vvp/vvp_scope.c | 30 +++---- vpi/sdf_parse.y | 54 +++++++------ vpi/sdf_priv.h | 8 +- vpi/sys_sdf.c | 177 ++++++++++++++++++++---------------------- vvp/delay.cc | 7 +- vvp/delay.h | 2 + vvp/vpi_priv.cc | 185 ++++++++++++++++++++------------------------ vvp/vpi_scope.cc | 6 +- vvp/vvp_net.h | 1 + 12 files changed, 253 insertions(+), 270 deletions(-) diff --git a/driver/main.c b/driver/main.c index 546cd1cfc..090d6c36a 100644 --- a/driver/main.c +++ b/driver/main.c @@ -758,7 +758,7 @@ static int process_generation(const char*name) else if (strcmp(name,"no-specify") == 0) gen_specify = "no-specify"; - else if (strcmp(name,"interconnect") == 0) + else if (strcmp(name,"interconnect") == 0) gen_interconnect = "interconnect"; else if (strcmp(name,"no-interconnect") == 0) diff --git a/elaborate.cc b/elaborate.cc index ed7bc1419..02a1fd47b 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1600,23 +1600,23 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // Add module input buffers if needed if (need_bufz_for_input_port(prts) || gn_interconnect_flag == true) { - // FIXME improve this for multiple module instances - NetScope* inner_scope = scope->instance_arrays[get_name()][0]; + // FIXME improve this for multiple module instances + NetScope* inner_scope = scope->instance_arrays[get_name()][0]; - NetBUFZ*tmp = new NetBUFZ(inner_scope, inner_scope->local_symbol(), - sig->vector_width(), true, gn_interconnect_flag ? idx : -1); - tmp->set_line(*this); - des->add_node(tmp); - connect(tmp->pin(1), sig->pin(0)); + NetBUFZ*tmp = new NetBUFZ(inner_scope, inner_scope->local_symbol(), + sig->vector_width(), true, gn_interconnect_flag ? idx : -1); + tmp->set_line(*this); + des->add_node(tmp); + connect(tmp->pin(1), sig->pin(0)); - netvector_t*tmp2_vec = new netvector_t(sig->data_type(), - sig->vector_width()-1,0); - NetNet*tmp2 = new NetNet(inner_scope, inner_scope->local_symbol(), - NetNet::WIRE, tmp2_vec); - tmp2->local_flag(true); - tmp2->set_line(*this); - connect(tmp->pin(0), tmp2->pin(0)); - sig = tmp2; + netvector_t*tmp2_vec = new netvector_t(sig->data_type(), + sig->vector_width()-1,0); + NetNet*tmp2 = new NetNet(inner_scope, inner_scope->local_symbol(), + NetNet::WIRE, tmp2_vec); + tmp2->local_flag(true); + tmp2->set_line(*this); + connect(tmp->pin(0), tmp2->pin(0)); + sig = tmp2; } // If we have a real signal driving a bit/vector port @@ -1938,12 +1938,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // the delay being applied to other drivers of // the external signal. if (prts[0]->delay_paths() > 0 || (gn_interconnect_flag == true && ptype == NetNet::POUTPUT)) { - // FIXME improve this for multiple module instances - NetScope* inner_scope = scope->instance_arrays[get_name()][0]; + // FIXME improve this for multiple module instances + NetScope* inner_scope = scope->instance_arrays[get_name()][0]; - isolate_and_connect(des, inner_scope, this, prts[0], sig, ptype, gn_interconnect_flag ? idx : -1); + isolate_and_connect(des, inner_scope, this, prts[0], sig, ptype, gn_interconnect_flag ? idx : -1); } else { - connect(prts[0]->pin(0), sig->pin(0)); + connect(prts[0]->pin(0), sig->pin(0)); } } else if (sig->vector_width()==prts_vector_width/instance.size() diff --git a/t-dll.cc b/t-dll.cc index 85600143e..feecb3d2b 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -893,13 +893,12 @@ bool dll_target::bufz(const NetBUFZ*net) scope_add_logic(scop, obj); - // Add bufz to the corresponding port_info entry, - // if it is an input / output buffer - // This is needed for the SDF interconnect feature - // to access the buffers directly from the port_info - if (obj->is_port_buffer) - { - scop->module_ports_info[net->port_info_index()].buffer = obj; + // Add bufz to the corresponding port_info entry, + // if it is an input / output buffer + // This is needed for the SDF interconnect feature + // to access the buffers directly from the port_info + if (obj->is_port_buffer) { + scop->module_ports_info[net->port_info_index()].buffer = obj; } return true; diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 9becbab24..47d9adfd7 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -308,7 +308,7 @@ int signal_is_return_value(ivl_signal_t sig) */ int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr) { - // If bufz is a module input/output buffer do not elide + // If bufz is a module input/output buffer do not elide if (ivl_logic_port_buffer(net)) return 0; ivl_nexus_t in_n, out_n; @@ -2403,20 +2403,20 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) if( ivl_scope_type(net) == IVL_SCT_MODULE ) { - // Port data for VPI: needed for vpiPorts property of vpiModule - for( idx = 0; idx < ivl_scope_mod_module_ports(net); ++idx ) { - const char *name = ivl_scope_mod_module_port_name(net,idx); - ivl_signal_port_t ptype = ivl_scope_mod_module_port_type(net,idx); - unsigned width = ivl_scope_mod_module_port_width(net,idx); - ivl_net_logic_t buffer = ivl_scope_mod_module_port_buffer(net,idx); - if( name == 0 ) - name = ""; - fprintf( vvp_out, " .port_info %u %s %u \"%s\"", - idx, vvp_port_info_type_str(ptype), width, - vvp_mangle_name(name) ); - if (buffer) fprintf( vvp_out, " L_%p;\n", buffer); - else fprintf( vvp_out, ";\n"); - } + // Port data for VPI: needed for vpiPorts property of vpiModule + for( idx = 0; idx < ivl_scope_mod_module_ports(net); ++idx ) { + const char *name = ivl_scope_mod_module_port_name(net,idx); + ivl_signal_port_t ptype = ivl_scope_mod_module_port_type(net,idx); + unsigned width = ivl_scope_mod_module_port_width(net,idx); + ivl_net_logic_t buffer = ivl_scope_mod_module_port_buffer(net,idx); + if( name == 0 ) + name = ""; + fprintf( vvp_out, " .port_info %u %s %u \"%s\"", + idx, vvp_port_info_type_str(ptype), width, + vvp_mangle_name(name) ); + if (buffer) fprintf( vvp_out, " L_%p;\n", buffer); + else fprintf( vvp_out, ";\n"); + } } for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) { diff --git a/vpi/sdf_parse.y b/vpi/sdf_parse.y index d865aa9f1..caad9b898 100644 --- a/vpi/sdf_parse.y +++ b/vpi/sdf_parse.y @@ -160,26 +160,31 @@ program_version hierarchy_divider : '(' K_DIVIDER '.' ')' { sdf_use_hchar = '.'; - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", + sdf_parse_path, @1.first_line, sdf_use_hchar); } | '(' K_DIVIDER '/' ')' { sdf_use_hchar = '/'; - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", + sdf_parse_path, @1.first_line, sdf_use_hchar); } | '(' K_DIVIDER HCHAR ')' { /* sdf_use_hchar no-change */ - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", sdf_parse_path, @1.first_line, sdf_use_hchar); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", + sdf_parse_path, @1.first_line, sdf_use_hchar); } ; voltage : '(' K_VOLTAGE rtriple ')' { /* The value must be defined. */ - if (! $3.defined) { - vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", sdf_parse_path, @1.first_line); - } - else if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Voltage: %f\n", - sdf_parse_path, @2.first_line, $3.value); + if (! $3.defined) { + vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", + sdf_parse_path, @1.first_line); + } else if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Voltage: %f\n", + sdf_parse_path, @2.first_line, $3.value); + } } | '(' K_VOLTAGE signed_real_number ')' { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Voltage: %f\n", @@ -198,10 +203,10 @@ process temperature : '(' K_TEMPERATURE rtriple ')' { /* The value must be defined. */ - if (! $3.defined) vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", - sdf_parse_path, @1.first_line); - else if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n", - sdf_parse_path, @2.first_line, $3.value); + if (! $3.defined) vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", + sdf_parse_path, @1.first_line); + else if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n", + sdf_parse_path, @2.first_line, $3.value); } | '(' K_TEMPERATURE signed_real_number ')' { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n", @@ -338,18 +343,21 @@ del_def /* | '(' K_INTERCONNECT port_instance port_instance delval_list ')' */ | '(' K_INTERCONNECT port_interconnect port_interconnect delval_list ')' { - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: INTERCONNECT with " - "port1 = %s index = %d, port2 = %s index = %d\n", - sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index); + if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: INTERCONNECT with " + "port1 = %s index = %d, port2 = %s index = %d\n", + sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index); + } - sdf_interconnect_delays($3, $4, &$5, @2.first_line); + sdf_interconnect_delays($3, $4, &$5, @2.first_line); - free($3.name); - free($4.name); + free($3.name); + free($4.name); } | '(' K_INTERCONNECT error ')' { vpi_printf("SDF ERROR: %s:%d: Invalid/malformed INTERCONNECT\n", - sdf_parse_path, @2.first_line); } + sdf_parse_path, @2.first_line); + } ; tchk_def_list @@ -465,13 +473,13 @@ port port_interconnect : hierarchical_identifier { - struct interconnect_port_s tmp = {$1, -1}; - $$ = tmp; + struct interconnect_port_s tmp = {$1, -1}; + $$ = tmp; } | hierarchical_identifier '[' INTEGER ']' { - struct interconnect_port_s tmp = {$1, $3}; - $$ = tmp; + struct interconnect_port_s tmp = {$1, $3}; + $$ = tmp; } ; diff --git a/vpi/sdf_priv.h b/vpi/sdf_priv.h index 7be638cf8..f1b9bdfb4 100644 --- a/vpi/sdf_priv.h +++ b/vpi/sdf_priv.h @@ -60,13 +60,15 @@ struct interconnect_port_s { extern void sdf_select_instance(const char*celltype, const char*inst, const int sdf_lineno); + extern void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, const struct sdf_delval_list_s*delval, const int sdf_lineno); -extern void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconnect_port_s port2, - const struct sdf_delval_list_s*delval_list, - const int sdf_lineno); +extern void sdf_interconnect_delays(struct interconnect_port_s port1, + struct interconnect_port_s port2, + const struct sdf_delval_list_s*delval_list, + const int sdf_lineno); #endif /* IVL_sdf_priv_h */ diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 739803047..54a3203fe 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -76,9 +76,11 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf /* Test for wildcard character */ if (cellinst == NULL) { - if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: sorry: " - "Wildcard cell instance specification (*) currently not supported.\n", - sdf_fname, sdf_lineno); + if (sdf_flag_warning) { + vpi_printf("SDF WARNING: %s:%d: sorry: " + "Wildcard cell instance specification (*) currently not supported.\n", + sdf_fname, sdf_lineno); + } sdf_cur_cell = 0; return; } @@ -89,45 +91,45 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf const char*src = cellinst; const char*dp; while ( (dp=strchr(src, '.')) ) { - unsigned len = dp - src; - assert(dp >= src); - assert(len < sizeof buffer); - strncpy(buffer, src, len); - buffer[len] = 0; + unsigned len = dp - src; + assert(dp >= src); + assert(len < sizeof buffer); + strncpy(buffer, src, len); + buffer[len] = 0; - vpiHandle tmp_scope = find_scope(scope, buffer); - if (tmp_scope == 0) { - vpi_printf("SDF ERROR: %s:%d: Cannot find %s in scope %s.\n", - sdf_fname, sdf_lineno, buffer, vpi_get_str(vpiFullName, scope)); - break; - } - assert(tmp_scope); - scope = tmp_scope; + vpiHandle tmp_scope = find_scope(scope, buffer); + if (tmp_scope == 0) { + vpi_printf("SDF ERROR: %s:%d: Cannot find %s in scope %s.\n", + sdf_fname, sdf_lineno, buffer, vpi_get_str(vpiFullName, scope)); + break; + } + assert(tmp_scope); + scope = tmp_scope; - src = dp + 1; + src = dp + 1; } /* Now find the cell. */ if (src[0] == 0) - sdf_cur_cell = sdf_scope; + sdf_cur_cell = sdf_scope; else - sdf_cur_cell = find_scope(scope, src); + sdf_cur_cell = find_scope(scope, src); if (sdf_cur_cell == 0) { - vpi_printf("SDF ERROR: %s:%d: Unable to find %s in scope %s.\n", - sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope)); - return; + vpi_printf("SDF ERROR: %s:%d: Unable to find %s in scope %s.\n", + sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope)); + return; } /* The scope that matches should be a module. */ if (vpi_get(vpiType,sdf_cur_cell) != vpiModule) { vpi_printf("SDF ERROR: %s:%d: Scope %s in %s is not a module.\n", - sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope)); + sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope)); } /* The matching scope (a module) should have the expected type. */ if (strcmp(celltype,vpi_get_str(vpiDefName,sdf_cur_cell)) != 0) { vpi_printf("SDF ERROR: %s:%d: Module %s in %s is not a %s; it is a ", - sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope), celltype); + sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope), celltype); vpi_printf("%s\n", vpi_get_str(vpiDefName, sdf_cur_cell)); } @@ -148,45 +150,40 @@ vpiHandle get_port_handle(char* port_name, const int sdf_lineno) { vpiHandle scope = sdf_cur_cell; - // Get occurences of '.' in the name + // Get occurences of '.' in the name int submodules = 0; - for (int i=0; port_name[i] != '\0'; i++) - { - if (port_name[i] == '.') submodules++; + for (int i=0; port_name[i] != '\0'; i++) { + if (port_name[i] == '.') submodules++; } - // Extract the first token + // Extract the first token char* token = strtok(port_name, ".");; - // Change scope into submodule - while (submodules--) - { - scope = vpi_handle_by_name(token, scope); + // Change scope into submodule + while (submodules--) { + scope = vpi_handle_by_name(token, scope); - if (!scope) vpi_printf("SDF ERROR: %s:%d: Submodule %s in port path not found!\n", sdf_fname, sdf_lineno, token); + if (!scope) vpi_printf("SDF ERROR: %s:%d: Submodule %s in port path not found!\n", sdf_fname, sdf_lineno, token); // Extract next token - token = strtok(NULL, "."); + token = strtok(NULL, "."); } - // Iterate over ports + // Iterate over ports vpiHandle port_i = vpi_iterate(vpiPort, scope) ; vpiHandle port; vpiHandle port_handle = NULL; - while ((port=vpi_scan(port_i)) != NULL) - { - char *port_name_ = vpi_get_str(vpiName, port) ; + while ((port=vpi_scan(port_i)) != NULL) { + char *port_name_ = vpi_get_str(vpiName, port) ; - if (strcmp(port_name_, token) == 0) - { - if (port_handle != NULL) - { - if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: Found multiple matching ports for %s !\n", sdf_fname, sdf_lineno, token); - } - port_handle = port; - } + if (strcmp(port_name_, token) == 0) { + if (port_handle != NULL) { + if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: Found multiple matching ports for %s !\n", sdf_fname, sdf_lineno, token); + } + port_handle = port; + } } return port_handle; @@ -198,52 +195,46 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne const int sdf_lineno) { - // Get handles for both ports - // After calling get_port_handle, the name is invalid + // Get handles for both ports + // After calling get_port_handle, the name is invalid vpiHandle port1_handle = get_port_handle(port1.name, sdf_lineno); vpiHandle port2_handle = get_port_handle(port2.name, sdf_lineno); - if (port1_handle && port2_handle) - { + if (port1_handle && port2_handle) { // Get interModPath for the two ports - vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle); + vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle); - if (intermodpath) - { - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Created a vpiInterModPath\n", sdf_fname, sdf_lineno); + if (intermodpath) { + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Created a vpiInterModPath\n", sdf_fname, sdf_lineno); - s_vpi_delay delays; - struct t_vpi_time delay_vals[12]; + s_vpi_delay delays; + struct t_vpi_time delay_vals[12]; - // Initialize delay structure - delays.da = delay_vals; - delays.no_of_delays = delval_list->count; - delays.time_type = vpiScaledRealTime; - delays.mtm_flag = 0; - delays.append_flag = 0; - delays.pulsere_flag = 0; - vpi_get_delays(intermodpath, &delays); + // Initialize delay structure + delays.da = delay_vals; + delays.no_of_delays = delval_list->count; + delays.time_type = vpiScaledRealTime; + delays.mtm_flag = 0; + delays.append_flag = 0; + delays.pulsere_flag = 0; + vpi_get_delays(intermodpath, &delays); - for (int idx = 0 ; idx < delval_list->count ; idx += 1) { - delay_vals[idx].type = vpiScaledRealTime; - if (delval_list->val[idx].defined) { - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Putting delay: %f for index %d\n", - sdf_fname, sdf_lineno, delval_list->val[idx].value, idx); - delay_vals[idx].real = delval_list->val[idx].value; - } - } + for (int idx = 0 ; idx < delval_list->count ; idx += 1) { + delay_vals[idx].type = vpiScaledRealTime; + if (delval_list->val[idx].defined) { + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Putting delay: %f for index %d\n", + sdf_fname, sdf_lineno, delval_list->val[idx].value, idx); + delay_vals[idx].real = delval_list->val[idx].value; + } + } - // Put the new delays - vpi_put_delays(intermodpath, &delays); - } - else - { - vpi_printf("SDF ERROR: %s:%d: Could not find intermodpath!\n", sdf_fname, sdf_lineno); - } - } - else - { - vpi_printf("SDF ERROR: %s:%d: Could not find handles for both ports!\n", sdf_fname, sdf_lineno); + // Put the new delays + vpi_put_delays(intermodpath, &delays); + } else { + vpi_printf("SDF ERROR: %s:%d: Could not find intermodpath!\n", sdf_fname, sdf_lineno); + } + } else { + vpi_printf("SDF ERROR: %s:%d: Could not find handles for both ports!\n", sdf_fname, sdf_lineno); } } @@ -314,10 +305,10 @@ void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, } if (match_count == 0) { - vpi_printf("SDF ERROR: %s:%d: Unable to match ModPath %s%s -> %s in %s\n", - sdf_fname, sdf_lineno, - edge_str(vpi_edge), src, dst, - vpi_get_str(vpiFullName, sdf_cur_cell)); + vpi_printf("SDF ERROR: %s:%d: Unable to match ModPath %s%s -> %s in %s\n", + sdf_fname, sdf_lineno, + edge_str(vpi_edge), src, dst, + vpi_get_str(vpiFullName, sdf_cur_cell)); } } @@ -409,10 +400,12 @@ static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) return 0; } - if (sdf_flag_inform) vpi_printf("SDF INFO: Loading %s from %s:%d\n", - fname, - vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); + if (sdf_flag_inform) { + vpi_printf("SDF INFO: Loading %s from %s:%d\n", + fname, + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + } sdf_fd = fopen(fname, "r"); if (sdf_fd == 0) { diff --git a/vvp/delay.cc b/vvp/delay.cc index 6c9aeb1cb..db243b9a8 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -1120,10 +1120,10 @@ vvp_fun_intermodpath::vvp_fun_intermodpath(vvp_net_t*net, unsigned width) : net_(net) { for (unsigned idx = 0 ; idx < 12 ; idx += 1) - delay_[idx] = 0; + delay_[idx] = 0; cur_vec4_ = vvp_vector4_t(width, BIT4_X); - schedule_init_propagate(net_, cur_vec4_); // TODO is this needed? + schedule_init_propagate(net_, cur_vec4_); } vvp_fun_intermodpath::~vvp_fun_intermodpath() @@ -1252,12 +1252,11 @@ static vpiHandle intermodpath_iterate(int code, vpiHandle ref) return 0; } - /* * This routine will put specific dimension of delay[] values * into a vpiHandle. In this case, we will put * specific delays values in a vpiInterModPath object - * TODO code duplication + * */ static void intermodpath_put_delays (vpiHandle ref, p_vpi_delay delays) { diff --git a/vvp/delay.h b/vvp/delay.h index 01c89a172..f13215102 100644 --- a/vvp/delay.h +++ b/vvp/delay.h @@ -236,6 +236,8 @@ class vvp_fun_modpath_edge : public vvp_fun_modpath_src { /* * The intermodpath is used to implement the SDF INTERCONNECT feature +* Upon a (INTERCONNECT ...) statement an intermodpath will be inserted +* between port1 and port2 and its delay can be annotated */ class vvp_fun_intermodpath : public vvp_net_fun_t, private vvp_gen_event_s { diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 39b8aee44..ac7ea6450 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2008-2022 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2023 Stephen Williams (steve@icarus.com) + * Copyright (c) 2023 Leo Moser (leo.moser@pm.me) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -33,16 +34,6 @@ # include # include -# include "npmos.h" -# include "vvp_island.h" -# include "resolv.h" -# include "bufif.h" -# include "latch.h" -# include "dff.h" -# include "event.h" -# include "arith.h" -# include "part.h" - using namespace std; vpi_mode_t vpi_mode_flag = VPI_MODE_NONE; FILE*vpi_trace = 0; @@ -1570,144 +1561,132 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref2) { if (vpi_trace) { - fprintf(vpi_trace, "vpi_handle_multi(%d, %p, %p) -->\n", - type, ref1, ref2); + fprintf(vpi_trace, "vpi_handle_multi(%d, %p, %p) -->\n", + type, ref1, ref2); } if (type != vpiInterModPath) { - fprintf(stderr, "sorry: vpi_handle_multi currently supports" - "only vpiInterModPath\n"); - return nullptr; + fprintf(stderr, "sorry: vpi_handle_multi currently supports" + "only vpiInterModPath\n"); + return nullptr; } vpiPortInfo* port1 = dynamic_cast(ref1); if (!port1) { - fprintf(stderr, "sorry: second argument of vpi_handle_multi" - "must be a vpiPort\n"); - return nullptr; + fprintf(stderr, "sorry: second argument of vpi_handle_multi" + "must be a vpiPort\n"); + return nullptr; } vpiPortInfo* port2 = dynamic_cast(ref2); if (!port2) { - fprintf(stderr, "sorry: third argument of vpi_handle_multi" - "must be a vpiPort\n"); - return nullptr; + fprintf(stderr, "sorry: third argument of vpi_handle_multi" + "must be a vpiPort\n"); + return nullptr; } - // If both ports are vpiOutput, we have to reassign the __vpiSignal from port1 - // to port2 because otherwise the non-delayed version of the signal is dumped - // even tho the intermodpath is correctly inserted + // If both ports are vpiOutput, we have to reassign the __vpiSignal from port1 + // to port2 because otherwise the non-delayed version of the signal is dumped + // even tho the intermodpath is correctly inserted __vpiSignal* output_signal = nullptr; - if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput) - { - vpiHandle scope_port2 = vpi_handle(vpiScope, ref2); - assert(scope_port2); - std::string port2_name(vpi_get_str(vpiName, ref2)); + if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput) { + vpiHandle scope_port2 = vpi_handle(vpiScope, ref2); + assert(scope_port2); + std::string port2_name(vpi_get_str(vpiName, ref2)); // Iterate over nets in the scope of port2 - vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ; - vpiHandle net; + vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ; + vpiHandle net; - while ((net = vpi_scan(net_i)) != NULL) - { - std::string net_name(vpi_get_str(vpiName, net)); + while ((net = vpi_scan(net_i)) != NULL) { + std::string net_name(vpi_get_str(vpiName, net)); - // Compare whether the net matches with the port name - if (net_name == port2_name) - { - output_signal = dynamic_cast<__vpiSignal*>(net); - } - } + // Compare whether the net matches with the port name + if (net_name == port2_name) { + output_signal = dynamic_cast<__vpiSignal*>(net); + } + } } vvp_net_t* net1 = port1->get_port(); vvp_net_t* net2 = port2->get_port(); - if (net1 == nullptr || net2 == nullptr) - { - fprintf(stderr, "Error: Could not find net. " - "Did you run iverilog with '-ginterconnect'?\n"); - return nullptr; + if (net1 == nullptr || net2 == nullptr) { + fprintf(stderr, "Error: Could not find net. " + "Did you run iverilog with '-ginterconnect'?\n"); + return nullptr; } - if (net1 == net2) - { - fprintf(stderr, "Error: Net for both ports is the same. " - "Did you pass the same port twice?\n"); - return nullptr; + if (net1 == net2) { + fprintf(stderr, "Error: Net for both ports is the same. " + "Did you pass the same port twice?\n"); + return nullptr; } - if (!dynamic_cast(net1->fun)) - { - fprintf(stderr, "Error: functor of net1 must be" - "vvp_fun_buft\n"); - return nullptr; + if (!dynamic_cast(net1->fun)) { + fprintf(stderr, "Error: functor of net1 must be" + "vvp_fun_buft\n"); + return nullptr; } - if (!dynamic_cast(net2->fun)) - { - fprintf(stderr, "Error: functor of net2 must be" - "vvp_fun_buft\n"); - return nullptr; + if (!dynamic_cast(net2->fun)) { + fprintf(stderr, "Error: functor of net2 must be" + "vvp_fun_buft\n"); + return nullptr; } - // Iterate over all nodes connected to port1 + // Iterate over all nodes connected to port1 vvp_net_ptr_t cur = net1->out_; vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0); - while (cur.ptr()) - { + while (cur.ptr()) { // Port2 is directly connected to port1 - if (cur.ptr() == net2) - { - vvp_net_t*new_net = new vvp_net_t; + if (cur.ptr() == net2) { + vvp_net_t*new_net = new vvp_net_t; - int width = 1; // TODO - vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); - new_net->fun = obj; - new_net->out_ = cur; // TODO pointer to current net + // Create new node with intermodpath and connect port2 to it + int width = 1; // TODO + vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); + new_net->fun = obj; + new_net->out_ = cur; - // Port2 is in the middle of the list - // Insert intermodpath before port2 and keep everything else intact - if (prev.ptr()) - { - prev.ptr()->port[prev.port()] = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath - new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list - cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath - } - // Port2 is first in list - // Insert intermodpath before port2 and keep everything else intact - else - { - net1->out_ = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath - new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list - cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath - } + // Port2 is in the middle of the list + // Insert intermodpath before port2 and keep everything else intact + if (prev.ptr()) { + prev.ptr()->port[prev.port()] = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath + new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list + cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath + // Port2 is first in list + // Insert intermodpath before port2 and keep everything else intact + } else { + net1->out_ = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath + new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list + cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath + } - // If both ports are vpiOutput, we have to reassign the __vpiSignal - if (output_signal) - { - net2->fil = net1->fil; - net1->fil = nullptr; - output_signal->node = net2; - } + // If both ports are vpiOutput, we have to reassign the __vpiSignal + if (output_signal) { + net2->fil = net1->fil; + net1->fil = nullptr; + output_signal->node = net2; + } - // Create the VPI intermodpath object - __vpiInterModPath* intermodpath = vpip_make_intermodpath(new_net, port1, port2); - intermodpath->intermodpath = obj; + // Create the VPI intermodpath object + __vpiInterModPath* intermodpath = vpip_make_intermodpath(new_net, port1, port2); + intermodpath->intermodpath = obj; - // Finally done, return the intermodpath object - return intermodpath; - } + // Finally done, return the intermodpath object + return intermodpath; + } - prev = cur; - cur = cur.ptr()->port[cur.port()]; // Next net in linked list + prev = cur; + cur = cur.ptr()->port[cur.port()]; // Next net in linked list } - std::cout << "sorry: Could not insert intermodpath!" << std::endl; + fprintf(stderr, "VPI error: Could not insert intermodpath!\n"); return nullptr; } diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 5b660e486..8a6f72912 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -742,7 +742,7 @@ vpiHandle vpiPortInfo::vpi_handle(int code) */ void compile_port_info( unsigned index, int vpi_direction, unsigned width, const char *name, char* buffer ) { - vpiHandle obj = new vpiPortInfo( vpip_peek_current_scope(), - index, vpi_direction, width, name, buffer ); - vpip_attach_to_current_scope(obj); + vpiHandle obj = new vpiPortInfo( vpip_peek_current_scope(), + index, vpi_direction, width, name, buffer ); + vpip_attach_to_current_scope(obj); } diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index e2b9ad574..b7e14dd7a 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1159,6 +1159,7 @@ class vvp_net_t { public: // Method to support $countdrivers void count_drivers(unsigned idx, unsigned counts[4]); + // This needs to be public so that SDF interconnects can be inserted public: vvp_net_ptr_t out_; From 665295ba007fa89fe8fcbdeb834477bc07dd69e8 Mon Sep 17 00:00:00 2001 From: mole99 Date: Wed, 30 Aug 2023 15:13:18 +0200 Subject: [PATCH 13/14] Also enable -gspecify for interconnect tests --- ivtest/gold/sdf_interconnect1-vvp-stdout.gold | 7 +-- ivtest/gold/sdf_interconnect2-vvp-stdout.gold | 7 +-- ivtest/gold/sdf_interconnect3-vvp-stdout.gold | 24 ++++----- ivtest/ivltests/sdf_interconnect3.sdf | 52 +++++++++++++++++-- ivtest/vvp_tests/sdf_interconnect1.json | 2 +- ivtest/vvp_tests/sdf_interconnect2.json | 2 +- ivtest/vvp_tests/sdf_interconnect3.json | 2 +- 7 files changed, 65 insertions(+), 31 deletions(-) diff --git a/ivtest/gold/sdf_interconnect1-vvp-stdout.gold b/ivtest/gold/sdf_interconnect1-vvp-stdout.gold index 860d290bc..c1f32d65b 100644 --- a/ivtest/gold/sdf_interconnect1-vvp-stdout.gold +++ b/ivtest/gold/sdf_interconnect1-vvp-stdout.gold @@ -1,9 +1,6 @@ -SDF ERROR: ivltests/sdf_interconnect1.sdf:32: Unable to match ModPath in -> out in top.my_design_inst.buffer0 -SDF ERROR: ivltests/sdf_interconnect1.sdf:42: Unable to match ModPath in -> out in top.my_design_inst.buffer1 -SDF ERROR: ivltests/sdf_interconnect1.sdf:52: Unable to match ModPath in -> out in top.my_design_inst.buffer2 time=0 a=x b=x time=5000 a=0 b=x -time=5080 a=0 b=0 +time=5680 a=0 b=0 time=15000 a=1 b=0 -time=15080 a=1 b=1 +time=15680 a=1 b=1 ivltests/sdf_interconnect1.v:59: $finish called at 25000 (1ps) diff --git a/ivtest/gold/sdf_interconnect2-vvp-stdout.gold b/ivtest/gold/sdf_interconnect2-vvp-stdout.gold index 1f31b9428..7722826f1 100644 --- a/ivtest/gold/sdf_interconnect2-vvp-stdout.gold +++ b/ivtest/gold/sdf_interconnect2-vvp-stdout.gold @@ -1,9 +1,6 @@ -SDF ERROR: ivltests/sdf_interconnect2.sdf:31: Unable to match ModPath in -> out in top.my_design_inst.buffer0 -SDF ERROR: ivltests/sdf_interconnect2.sdf:41: Unable to match ModPath in -> out in top.my_design_inst.buffer1 -SDF ERROR: ivltests/sdf_interconnect2.sdf:51: Unable to match ModPath in -> out in top.my_design_inst.buffer2 time=0 a=x b=x time=5000 a=0 b=x -time=5010 a=0 b=0 +time=5110 a=0 b=0 time=15000 a=1 b=0 -time=15030 a=1 b=1 +time=15330 a=1 b=1 ivltests/sdf_interconnect2.v:61: $finish called at 25000 (1ps) diff --git a/ivtest/gold/sdf_interconnect3-vvp-stdout.gold b/ivtest/gold/sdf_interconnect3-vvp-stdout.gold index 1db8ffb91..7de592d59 100644 --- a/ivtest/gold/sdf_interconnect3-vvp-stdout.gold +++ b/ivtest/gold/sdf_interconnect3-vvp-stdout.gold @@ -1,24 +1,20 @@ -SDF ERROR: ivltests/sdf_interconnect3.sdf:41: Unable to match ModPath in -> out in top.my_design_inst.buffer0 -SDF ERROR: ivltests/sdf_interconnect3.sdf:51: Unable to match ModPath in -> out in top.my_design_inst.buffer1 -SDF ERROR: ivltests/sdf_interconnect3.sdf:61: Unable to match ModPath in -> out in top.my_design_inst.buffer2 -SDF ERROR: ivltests/sdf_interconnect3.sdf:71: Unable to match ModPath in -> out in top.my_design_inst.buffer3 time=0 a=x b=x c=x d=x time=10000 a=0 b=0 c=0 d=x -time=10060 a=0 b=0 c=0 d=0 +time=10560 a=0 b=0 c=0 d=0 time=20000 a=1 b=0 c=0 d=0 -time=20060 a=1 b=0 c=0 d=1 +time=20560 a=1 b=0 c=0 d=1 time=30000 a=0 b=1 c=0 d=1 -time=30050 a=0 b=1 c=0 d=0 +time=30450 a=0 b=1 c=0 d=0 time=40000 a=1 b=1 c=0 d=0 -time=40060 a=1 b=1 c=0 d=1 +time=40560 a=1 b=1 c=0 d=1 time=50000 a=0 b=0 c=1 d=1 -time=50040 a=0 b=0 c=1 d=0 -time=50050 a=0 b=0 c=1 d=1 -time=50060 a=0 b=0 c=1 d=0 +time=50340 a=0 b=0 c=1 d=0 +time=50450 a=0 b=0 c=1 d=1 +time=50560 a=0 b=0 c=1 d=0 time=60000 a=1 b=0 c=1 d=0 -time=60060 a=1 b=0 c=1 d=1 +time=60560 a=1 b=0 c=1 d=1 time=70000 a=0 b=1 c=1 d=1 -time=70050 a=0 b=1 c=1 d=0 +time=70450 a=0 b=1 c=1 d=0 time=80000 a=1 b=1 c=1 d=0 -time=80060 a=1 b=1 c=1 d=1 +time=80560 a=1 b=1 c=1 d=1 ivltests/sdf_interconnect3.v:132: $finish called at 90000 (1ps) diff --git a/ivtest/ivltests/sdf_interconnect3.sdf b/ivtest/ivltests/sdf_interconnect3.sdf index b4ebb0017..a6fa94626 100644 --- a/ivtest/ivltests/sdf_interconnect3.sdf +++ b/ivtest/ivltests/sdf_interconnect3.sdf @@ -38,7 +38,7 @@ (INSTANCE buffer0) (DELAY (ABSOLUTE - (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + (IOPATH in out (0.0:0.1:0.0) (0.0:0.1:0.0)) ) ) ) @@ -48,7 +48,7 @@ (INSTANCE buffer1) (DELAY (ABSOLUTE - (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + (IOPATH in out (0.0:0.1:0.0) (0.0:0.1:0.0)) ) ) ) @@ -58,7 +58,7 @@ (INSTANCE buffer2) (DELAY (ABSOLUTE - (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + (IOPATH in out (0.0:0.1:0.0) (0.0:0.1:0.0)) ) ) ) @@ -68,7 +68,51 @@ (INSTANCE buffer3) (DELAY (ABSOLUTE - (IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3)) + (IOPATH in out (0.0:0.1:0.0) (0.0:0.1:0.0)) + ) + ) + ) + + (CELL + (CELLTYPE "my_xor") + (INSTANCE my_xor0) + (DELAY + (ABSOLUTE + (IOPATH a out (0.0:0.1:0.0) (0.0:0.1:0.0)) + (IOPATH b out (0.0:0.1:0.0) (0.0:0.1:0.0)) + ) + ) + ) + + (CELL + (CELLTYPE "my_xor") + (INSTANCE my_xor1) + (DELAY + (ABSOLUTE + (IOPATH a out (0.0:0.1:0.0) (0.0:0.1:0.0)) + (IOPATH b out (0.0:0.1:0.0) (0.0:0.1:0.0)) + ) + ) + ) + + (CELL + (CELLTYPE "my_xor") + (INSTANCE my_xor2) + (DELAY + (ABSOLUTE + (IOPATH a out (0.0:0.1:0.0) (0.0:0.1:0.0)) + (IOPATH b out (0.0:0.1:0.0) (0.0:0.1:0.0)) + ) + ) + ) + + (CELL + (CELLTYPE "my_xor") + (INSTANCE my_xor3) + (DELAY + (ABSOLUTE + (IOPATH a out (0.0:0.1:0.0) (0.0:0.1:0.0)) + (IOPATH b out (0.0:0.1:0.0) (0.0:0.1:0.0)) ) ) ) diff --git a/ivtest/vvp_tests/sdf_interconnect1.json b/ivtest/vvp_tests/sdf_interconnect1.json index d9d587c3e..df933cd89 100644 --- a/ivtest/vvp_tests/sdf_interconnect1.json +++ b/ivtest/vvp_tests/sdf_interconnect1.json @@ -1,6 +1,6 @@ { "type" : "normal", "source" : "sdf_interconnect1.v", - "iverilog-args" : [ "-Ttyp", "-ginterconnect" ], + "iverilog-args" : [ "-Ttyp", "-ginterconnect", "-gspecify" ], "gold" : "sdf_interconnect1" } diff --git a/ivtest/vvp_tests/sdf_interconnect2.json b/ivtest/vvp_tests/sdf_interconnect2.json index 44bb83a8a..d10bce47a 100644 --- a/ivtest/vvp_tests/sdf_interconnect2.json +++ b/ivtest/vvp_tests/sdf_interconnect2.json @@ -1,6 +1,6 @@ { "type" : "normal", "source" : "sdf_interconnect2.v", - "iverilog-args" : [ "-Ttyp", "-ginterconnect" ], + "iverilog-args" : [ "-Ttyp", "-ginterconnect", "-gspecify" ], "gold" : "sdf_interconnect2" } diff --git a/ivtest/vvp_tests/sdf_interconnect3.json b/ivtest/vvp_tests/sdf_interconnect3.json index fa67e509b..973160884 100644 --- a/ivtest/vvp_tests/sdf_interconnect3.json +++ b/ivtest/vvp_tests/sdf_interconnect3.json @@ -1,6 +1,6 @@ { "type" : "normal", "source" : "sdf_interconnect3.v", - "iverilog-args" : [ "-Ttyp", "-ginterconnect" ], + "iverilog-args" : [ "-Ttyp", "-ginterconnect", "-gspecify" ], "gold" : "sdf_interconnect3" } From 0c9549379436a6e73b1a89d2a6c1a050e76a5473 Mon Sep 17 00:00:00 2001 From: mole99 Date: Sat, 2 Sep 2023 15:57:04 +0200 Subject: [PATCH 14/14] Add has_index flag to interconnect_port_s --- vpi/sdf_parse.y | 5 ++--- vpi/sdf_priv.h | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/vpi/sdf_parse.y b/vpi/sdf_parse.y index caad9b898..70f0b6af5 100644 --- a/vpi/sdf_parse.y +++ b/vpi/sdf_parse.y @@ -469,16 +469,15 @@ port /* | hierarchical_identifier '[' INTEGER ']' */ ; - /* Since INTERCONNECT is ignored we can also ignore a vector bit. */ port_interconnect : hierarchical_identifier { - struct interconnect_port_s tmp = {$1, -1}; + struct interconnect_port_s tmp = {$1, false, 0}; $$ = tmp; } | hierarchical_identifier '[' INTEGER ']' { - struct interconnect_port_s tmp = {$1, $3}; + struct interconnect_port_s tmp = {$1, true, $3}; $$ = tmp; } ; diff --git a/vpi/sdf_priv.h b/vpi/sdf_priv.h index f1b9bdfb4..60889eb9a 100644 --- a/vpi/sdf_priv.h +++ b/vpi/sdf_priv.h @@ -20,6 +20,7 @@ */ # include +# include /* * Invoke the parser to parse the opened SDF file. The fd is the SDF @@ -55,7 +56,8 @@ struct port_with_edge_s { struct interconnect_port_s { char* name; - int index; // -1 for whole vector + bool has_index; + int index; // invalid if has_index is false }; extern void sdf_select_instance(const char*celltype, const char*inst,