This commit is contained in:
mole99 2023-08-17 16:09:20 +02:00
parent 306e4cfa6b
commit 11c944f5e9
12 changed files with 253 additions and 270 deletions

View File

@ -897,8 +897,7 @@ bool dll_target::bufz(const NetBUFZ*net)
// if it is an input / output buffer // if it is an input / output buffer
// This is needed for the SDF interconnect feature // This is needed for the SDF interconnect feature
// to access the buffers directly from the port_info // to access the buffers directly from the port_info
if (obj->is_port_buffer) if (obj->is_port_buffer) {
{
scop->module_ports_info[net->port_info_index()].buffer = obj; scop->module_ports_info[net->port_info_index()].buffer = obj;
} }

View File

@ -160,15 +160,18 @@ program_version
hierarchy_divider hierarchy_divider
: '(' K_DIVIDER '.' ')' : '(' K_DIVIDER '.' ')'
{ sdf_use_hchar = '.'; { 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 '/' ')' | '(' K_DIVIDER '/' ')'
{ sdf_use_hchar = '/'; { 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 ')' | '(' K_DIVIDER HCHAR ')'
{ /* sdf_use_hchar no-change */ { /* 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);
} }
; ;
@ -176,11 +179,13 @@ voltage
: '(' K_VOLTAGE rtriple ')' : '(' K_VOLTAGE rtriple ')'
{ /* The value must be defined. */ { /* The value must be defined. */
if (! $3.defined) { if (! $3.defined) {
vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", sdf_parse_path, @1.first_line); 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", } else if (sdf_flag_inform) {
vpi_printf("SDF INFO: %s:%d: Voltage: %f\n",
sdf_parse_path, @2.first_line, $3.value); sdf_parse_path, @2.first_line, $3.value);
} }
}
| '(' K_VOLTAGE signed_real_number ')' | '(' K_VOLTAGE signed_real_number ')'
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Voltage: %f\n", { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Voltage: %f\n",
sdf_parse_path, @2.first_line, $3); sdf_parse_path, @2.first_line, $3);
@ -338,9 +343,11 @@ del_def
/* | '(' K_INTERCONNECT port_instance port_instance delval_list ')' */ /* | '(' K_INTERCONNECT port_instance port_instance delval_list ')' */
| '(' K_INTERCONNECT port_interconnect port_interconnect delval_list ')' | '(' K_INTERCONNECT port_interconnect port_interconnect delval_list ')'
{ {
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: INTERCONNECT with " if (sdf_flag_inform) {
vpi_printf("SDF INFO: %s:%d: INTERCONNECT with "
"port1 = %s index = %d, port2 = %s index = %d\n", "port1 = %s index = %d, port2 = %s index = %d\n",
sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index); 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);
@ -349,7 +356,8 @@ del_def
} }
| '(' K_INTERCONNECT error ')' | '(' K_INTERCONNECT error ')'
{ vpi_printf("SDF ERROR: %s:%d: Invalid/malformed INTERCONNECT\n", { 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 tchk_def_list

View File

@ -60,11 +60,13 @@ struct interconnect_port_s {
extern void sdf_select_instance(const char*celltype, const char*inst, extern void sdf_select_instance(const char*celltype, const char*inst,
const int sdf_lineno); const int sdf_lineno);
extern void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst, extern void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
const struct sdf_delval_list_s*delval, const struct sdf_delval_list_s*delval,
const int sdf_lineno); const int sdf_lineno);
extern void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconnect_port_s port2, extern void sdf_interconnect_delays(struct interconnect_port_s port1,
struct interconnect_port_s port2,
const struct sdf_delval_list_s*delval_list, const struct sdf_delval_list_s*delval_list,
const int sdf_lineno); const int sdf_lineno);

View File

@ -76,9 +76,11 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf
/* Test for wildcard character */ /* Test for wildcard character */
if (cellinst == NULL) { if (cellinst == NULL) {
if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: sorry: " if (sdf_flag_warning) {
vpi_printf("SDF WARNING: %s:%d: sorry: "
"Wildcard cell instance specification (*) currently not supported.\n", "Wildcard cell instance specification (*) currently not supported.\n",
sdf_fname, sdf_lineno); sdf_fname, sdf_lineno);
}
sdf_cur_cell = 0; sdf_cur_cell = 0;
return; return;
} }
@ -151,8 +153,7 @@ vpiHandle get_port_handle(char* port_name, const int sdf_lineno)
// Get occurences of '.' in the name // Get occurences of '.' in the name
int submodules = 0; int submodules = 0;
for (int i=0; port_name[i] != '\0'; i++) for (int i=0; port_name[i] != '\0'; i++) {
{
if (port_name[i] == '.') submodules++; if (port_name[i] == '.') submodules++;
} }
@ -160,8 +161,7 @@ vpiHandle get_port_handle(char* port_name, const int sdf_lineno)
char* token = strtok(port_name, ".");; char* token = strtok(port_name, ".");;
// Change scope into submodule // Change scope into submodule
while (submodules--) while (submodules--) {
{
scope = vpi_handle_by_name(token, scope); 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);
@ -175,14 +175,11 @@ vpiHandle get_port_handle(char* port_name, const int sdf_lineno)
vpiHandle port; vpiHandle port;
vpiHandle port_handle = NULL; vpiHandle port_handle = NULL;
while ((port=vpi_scan(port_i)) != NULL) while ((port=vpi_scan(port_i)) != NULL) {
{
char *port_name_ = vpi_get_str(vpiName, port) ; char *port_name_ = vpi_get_str(vpiName, port) ;
if (strcmp(port_name_, token) == 0) if (strcmp(port_name_, token) == 0) {
{ if (port_handle != NULL) {
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_warning) vpi_printf("SDF WARNING: %s:%d: Found multiple matching ports for %s !\n", sdf_fname, sdf_lineno, token);
} }
port_handle = port; port_handle = port;
@ -203,13 +200,11 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne
vpiHandle port1_handle = get_port_handle(port1.name, sdf_lineno); vpiHandle port1_handle = get_port_handle(port1.name, sdf_lineno);
vpiHandle port2_handle = get_port_handle(port2.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 // 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 (intermodpath) {
{
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Created a 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; s_vpi_delay delays;
@ -235,14 +230,10 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne
// Put the new delays // Put the new delays
vpi_put_delays(intermodpath, &delays); vpi_put_delays(intermodpath, &delays);
} } else {
else
{
vpi_printf("SDF ERROR: %s:%d: Could not find intermodpath!\n", sdf_fname, sdf_lineno); vpi_printf("SDF ERROR: %s:%d: Could not find intermodpath!\n", sdf_fname, sdf_lineno);
} }
} } else {
else
{
vpi_printf("SDF ERROR: %s:%d: Could not find handles for both ports!\n", sdf_fname, sdf_lineno); vpi_printf("SDF ERROR: %s:%d: Could not find handles for both ports!\n", sdf_fname, sdf_lineno);
} }
} }
@ -409,10 +400,12 @@ static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
return 0; return 0;
} }
if (sdf_flag_inform) vpi_printf("SDF INFO: Loading %s from %s:%d\n", if (sdf_flag_inform) {
vpi_printf("SDF INFO: Loading %s from %s:%d\n",
fname, fname,
vpi_get_str(vpiFile, callh), vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
}
sdf_fd = fopen(fname, "r"); sdf_fd = fopen(fname, "r");
if (sdf_fd == 0) { if (sdf_fd == 0) {

View File

@ -1123,7 +1123,7 @@ vvp_fun_intermodpath::vvp_fun_intermodpath(vvp_net_t*net, unsigned width)
delay_[idx] = 0; delay_[idx] = 0;
cur_vec4_ = vvp_vector4_t(width, BIT4_X); 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() vvp_fun_intermodpath::~vvp_fun_intermodpath()
@ -1252,12 +1252,11 @@ static vpiHandle intermodpath_iterate(int code, vpiHandle ref)
return 0; return 0;
} }
/* /*
* This routine will put specific dimension of delay[] values * This routine will put specific dimension of delay[] values
* into a vpiHandle. In this case, we will put * into a vpiHandle. In this case, we will put
* specific delays values in a vpiInterModPath object * specific delays values in a vpiInterModPath object
* TODO code duplication *
*/ */
static void intermodpath_put_delays (vpiHandle ref, p_vpi_delay delays) static void intermodpath_put_delays (vpiHandle ref, p_vpi_delay delays)
{ {

View File

@ -236,6 +236,8 @@ class vvp_fun_modpath_edge : public vvp_fun_modpath_src {
/* /*
* The intermodpath is used to implement the SDF INTERCONNECT feature * 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 { class vvp_fun_intermodpath : public vvp_net_fun_t, private vvp_gen_event_s {

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -33,16 +34,6 @@
# include <cmath> # include <cmath>
# include <iostream> # include <iostream>
# 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; using namespace std;
vpi_mode_t vpi_mode_flag = VPI_MODE_NONE; vpi_mode_t vpi_mode_flag = VPI_MODE_NONE;
FILE*vpi_trace = 0; FILE*vpi_trace = 0;
@ -1601,8 +1592,7 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
// even tho the intermodpath is correctly inserted // even tho the intermodpath is correctly inserted
__vpiSignal* output_signal = nullptr; __vpiSignal* output_signal = nullptr;
if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput) if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput) {
{
vpiHandle scope_port2 = vpi_handle(vpiScope, ref2); vpiHandle scope_port2 = vpi_handle(vpiScope, ref2);
assert(scope_port2); assert(scope_port2);
std::string port2_name(vpi_get_str(vpiName, ref2)); std::string port2_name(vpi_get_str(vpiName, ref2));
@ -1611,13 +1601,11 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ; vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ;
vpiHandle net; vpiHandle net;
while ((net = vpi_scan(net_i)) != NULL) while ((net = vpi_scan(net_i)) != NULL) {
{
std::string net_name(vpi_get_str(vpiName, net)); std::string net_name(vpi_get_str(vpiName, net));
// Compare whether the net matches with the port name // Compare whether the net matches with the port name
if (net_name == port2_name) if (net_name == port2_name) {
{
output_signal = dynamic_cast<__vpiSignal*>(net); output_signal = dynamic_cast<__vpiSignal*>(net);
} }
} }
@ -1626,29 +1614,25 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
vvp_net_t* net1 = port1->get_port(); vvp_net_t* net1 = port1->get_port();
vvp_net_t* net2 = port2->get_port(); vvp_net_t* net2 = port2->get_port();
if (net1 == nullptr || net2 == nullptr) if (net1 == nullptr || net2 == nullptr) {
{
fprintf(stderr, "Error: Could not find net. " fprintf(stderr, "Error: Could not find net. "
"Did you run iverilog with '-ginterconnect'?\n"); "Did you run iverilog with '-ginterconnect'?\n");
return nullptr; return nullptr;
} }
if (net1 == net2) if (net1 == net2) {
{
fprintf(stderr, "Error: Net for both ports is the same. " fprintf(stderr, "Error: Net for both ports is the same. "
"Did you pass the same port twice?\n"); "Did you pass the same port twice?\n");
return nullptr; return nullptr;
} }
if (!dynamic_cast<vvp_fun_buft*>(net1->fun)) if (!dynamic_cast<vvp_fun_buft*>(net1->fun)) {
{
fprintf(stderr, "Error: functor of net1 must be" fprintf(stderr, "Error: functor of net1 must be"
"vvp_fun_buft\n"); "vvp_fun_buft\n");
return nullptr; return nullptr;
} }
if (!dynamic_cast<vvp_fun_buft*>(net2->fun)) if (!dynamic_cast<vvp_fun_buft*>(net2->fun)) {
{
fprintf(stderr, "Error: functor of net2 must be" fprintf(stderr, "Error: functor of net2 must be"
"vvp_fun_buft\n"); "vvp_fun_buft\n");
return nullptr; return nullptr;
@ -1658,38 +1642,33 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
vvp_net_ptr_t cur = net1->out_; vvp_net_ptr_t cur = net1->out_;
vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0); vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0);
while (cur.ptr()) while (cur.ptr()) {
{
// Port2 is directly connected to port1 // Port2 is directly connected to port1
if (cur.ptr() == net2) if (cur.ptr() == net2) {
{
vvp_net_t*new_net = new vvp_net_t; vvp_net_t*new_net = new vvp_net_t;
// Create new node with intermodpath and connect port2 to it
int width = 1; // TODO int width = 1; // TODO
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width); vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
new_net->fun = obj; new_net->fun = obj;
new_net->out_ = cur; // TODO pointer to current net new_net->out_ = cur;
// Port2 is in the middle of the list // Port2 is in the middle of the list
// Insert intermodpath before port2 and keep everything else intact // Insert intermodpath before port2 and keep everything else intact
if (prev.ptr()) if (prev.ptr()) {
{
prev.ptr()->port[prev.port()] = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath 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 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 cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath
}
// Port2 is first in list // Port2 is first in list
// Insert intermodpath before port2 and keep everything else intact // Insert intermodpath before port2 and keep everything else intact
else } else {
{
net1->out_ = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath 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 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 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 both ports are vpiOutput, we have to reassign the __vpiSignal
if (output_signal) if (output_signal) {
{
net2->fil = net1->fil; net2->fil = net1->fil;
net1->fil = nullptr; net1->fil = nullptr;
output_signal->node = net2; output_signal->node = net2;
@ -1707,7 +1686,7 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
cur = cur.ptr()->port[cur.port()]; // Next net in linked list 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; return nullptr;
} }

View File

@ -1159,6 +1159,7 @@ class vvp_net_t {
public: // Method to support $countdrivers public: // Method to support $countdrivers
void count_drivers(unsigned idx, unsigned counts[4]); void count_drivers(unsigned idx, unsigned counts[4]);
// This needs to be public so that SDF interconnects can be inserted
public: public:
vvp_net_ptr_t out_; vvp_net_ptr_t out_;