From 7beadb92f8811b24e4c50e50c2bb807dea9da8d6 Mon Sep 17 00:00:00 2001 From: mole99 Date: Wed, 19 Jul 2023 15:02:20 +0200 Subject: [PATCH] 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