Framework of the INTERCONNECT implementation
This commit is contained in:
parent
78f8976c85
commit
7beadb92f8
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
172
vpi/sys_sdf.c
172
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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
349
vvp/delay.cc
349
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<vvp_fun_intermodpath*>(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<vvp_fun_intermodpath*>(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
|
||||
|
|
|
|||
30
vvp/delay.h
30
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 */
|
||||
|
|
|
|||
155
vvp/vpi_priv.cc
155
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<vpiPortInfo*>(ref1);
|
||||
|
||||
if (!port1) {
|
||||
fprintf(stderr, "sorry: second argument of vpi_handle_multi"
|
||||
"must be a vpiPort\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vpiPortInfo* port2 = dynamic_cast<vpiPortInfo*>(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<vvp_fun_bufz*>(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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue