2007-11-19 02:36:03 +01:00
|
|
|
/*
|
2025-10-13 02:35:15 +02:00
|
|
|
* Copyright (c) 2007-2025 Stephen Williams (steve@icarus.com)
|
2007-11-19 02:36:03 +01:00
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2007-11-19 02:36:03 +01:00
|
|
|
*/
|
|
|
|
|
|
2009-02-05 22:24:58 +01:00
|
|
|
# include "sys_priv.h"
|
2010-05-17 18:38:23 +02:00
|
|
|
# include "sdf_priv.h"
|
2007-11-19 02:36:03 +01:00
|
|
|
# include <stdlib.h>
|
|
|
|
|
# include <string.h>
|
|
|
|
|
# include <assert.h>
|
|
|
|
|
|
2007-11-21 07:20:22 +01:00
|
|
|
/*
|
|
|
|
|
* These are static context
|
|
|
|
|
*/
|
|
|
|
|
|
2007-11-28 06:44:25 +01:00
|
|
|
int sdf_flag_warning = 0;
|
2007-11-23 03:22:46 +01:00
|
|
|
int sdf_flag_inform = 0;
|
2010-03-18 02:48:11 +01:00
|
|
|
int sdf_min_typ_max;
|
2007-11-23 03:22:46 +01:00
|
|
|
|
2007-11-21 07:20:22 +01:00
|
|
|
/* Scope of the $sdf_annotate call. Annotation starts here. */
|
|
|
|
|
static vpiHandle sdf_scope;
|
2009-02-05 22:24:58 +01:00
|
|
|
static vpiHandle sdf_callh = 0;
|
2007-11-21 07:20:22 +01:00
|
|
|
/* The cell in process. */
|
|
|
|
|
static vpiHandle sdf_cur_cell;
|
2023-06-26 05:11:38 +02:00
|
|
|
static char* sdf_fname = NULL;
|
2007-11-21 07:20:22 +01:00
|
|
|
|
2007-11-28 06:44:25 +01:00
|
|
|
static vpiHandle find_scope(vpiHandle scope, const char*name)
|
|
|
|
|
{
|
|
|
|
|
vpiHandle idx = vpi_iterate(vpiModule, scope);
|
2009-02-05 22:24:58 +01:00
|
|
|
/* If this scope has no modules then it can't have the one we
|
|
|
|
|
* are looking for so just return 0. */
|
|
|
|
|
if (idx == 0) return 0;
|
2007-11-28 06:44:25 +01:00
|
|
|
|
|
|
|
|
vpiHandle cur;
|
|
|
|
|
while ( (cur = vpi_scan(idx)) ) {
|
|
|
|
|
|
|
|
|
|
if ( strcmp(name, vpi_get_str(vpiName,cur)) == 0) {
|
|
|
|
|
vpi_free_object(idx);
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-26 05:11:38 +02:00
|
|
|
void sdf_warn_file_line(const int sdf_lineno)
|
|
|
|
|
{
|
|
|
|
|
vpi_printf("SDF WARNING: %s:%d: loaded from %s:%d: ",
|
|
|
|
|
sdf_fname, sdf_lineno,
|
|
|
|
|
vpi_get_str(vpiFile, sdf_callh),
|
|
|
|
|
(int)vpi_get(vpiLineNo, sdf_callh));
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-21 07:20:22 +01:00
|
|
|
/*
|
|
|
|
|
* These functions are called by the SDF parser during parsing to
|
|
|
|
|
* handling items discovered in the parse.
|
|
|
|
|
*/
|
2007-11-28 06:44:25 +01:00
|
|
|
|
2023-06-26 05:11:38 +02:00
|
|
|
void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf_lineno)
|
2007-11-21 07:20:22 +01:00
|
|
|
{
|
2007-11-28 06:44:25 +01:00
|
|
|
char buffer[128];
|
|
|
|
|
|
2023-06-15 10:27:20 +02:00
|
|
|
/* Test for wildcard character */
|
|
|
|
|
if (cellinst == NULL) {
|
2023-08-17 16:09:20 +02:00
|
|
|
if (sdf_flag_warning) {
|
|
|
|
|
vpi_printf("SDF WARNING: %s:%d: sorry: "
|
|
|
|
|
"Wildcard cell instance specification (*) currently not supported.\n",
|
|
|
|
|
sdf_fname, sdf_lineno);
|
|
|
|
|
}
|
2023-06-26 05:11:38 +02:00
|
|
|
sdf_cur_cell = 0;
|
|
|
|
|
return;
|
2023-06-15 10:27:20 +02:00
|
|
|
}
|
|
|
|
|
|
2007-11-28 06:44:25 +01:00
|
|
|
/* First follow the hierarchical parts of the cellinst name to
|
|
|
|
|
get to the cell that I'm looking for. */
|
|
|
|
|
vpiHandle scope = sdf_scope;
|
|
|
|
|
const char*src = cellinst;
|
|
|
|
|
const char*dp;
|
|
|
|
|
while ( (dp=strchr(src, '.')) ) {
|
2023-08-17 16:09:20 +02:00
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
src = dp + 1;
|
2007-11-28 06:44:25 +01:00
|
|
|
}
|
2007-11-21 07:20:22 +01:00
|
|
|
|
2007-11-28 06:44:25 +01:00
|
|
|
/* Now find the cell. */
|
2007-11-29 03:17:01 +01:00
|
|
|
if (src[0] == 0)
|
2023-08-17 16:09:20 +02:00
|
|
|
sdf_cur_cell = sdf_scope;
|
2007-11-29 03:17:01 +01:00
|
|
|
else
|
2023-08-17 16:09:20 +02:00
|
|
|
sdf_cur_cell = find_scope(scope, src);
|
2007-11-28 06:44:25 +01:00
|
|
|
if (sdf_cur_cell == 0) {
|
2023-08-17 16:09:20 +02:00
|
|
|
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;
|
2007-11-28 06:44:25 +01:00
|
|
|
}
|
2007-11-21 07:20:22 +01:00
|
|
|
|
2007-11-28 06:44:25 +01:00
|
|
|
/* The scope that matches should be a module. */
|
|
|
|
|
if (vpi_get(vpiType,sdf_cur_cell) != vpiModule) {
|
2023-07-19 15:02:20 +02:00
|
|
|
vpi_printf("SDF ERROR: %s:%d: Scope %s in %s is not a module.\n",
|
2023-08-17 16:09:20 +02:00
|
|
|
sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope));
|
2007-11-28 06:44:25 +01:00
|
|
|
}
|
2007-11-21 07:20:22 +01:00
|
|
|
|
2007-11-28 06:44:25 +01:00
|
|
|
/* The matching scope (a module) should have the expected type. */
|
|
|
|
|
if (strcmp(celltype,vpi_get_str(vpiDefName,sdf_cur_cell)) != 0) {
|
2023-07-19 15:02:20 +02:00
|
|
|
vpi_printf("SDF ERROR: %s:%d: Module %s in %s is not a %s; it is a ",
|
2023-08-17 16:09:20 +02:00
|
|
|
sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope), celltype);
|
2014-04-25 22:49:11 +02:00
|
|
|
vpi_printf("%s\n", vpi_get_str(vpiDefName, sdf_cur_cell));
|
2007-11-21 07:20:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-14 05:42:06 +01:00
|
|
|
static const char*edge_str(int vpi_edge)
|
|
|
|
|
{
|
|
|
|
|
if (vpi_edge == vpiNoEdge)
|
|
|
|
|
return "";
|
|
|
|
|
if (vpi_edge == vpiPosedge)
|
|
|
|
|
return "posedge ";
|
|
|
|
|
if (vpi_edge == vpiNegedge)
|
|
|
|
|
return "negedge ";
|
|
|
|
|
return "edge.. ";
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-13 02:35:15 +02:00
|
|
|
static vpiHandle get_port_handle(char* port_name, const int sdf_lineno)
|
2023-07-19 15:02:20 +02:00
|
|
|
{
|
|
|
|
|
vpiHandle scope = sdf_cur_cell;
|
|
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
// Get occurences of '.' in the name
|
2023-07-19 15:02:20 +02:00
|
|
|
int submodules = 0;
|
|
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
for (int i=0; port_name[i] != '\0'; i++) {
|
|
|
|
|
if (port_name[i] == '.') submodules++;
|
2023-07-19 15:02:20 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
// Extract the first token
|
2023-07-19 15:02:20 +02:00
|
|
|
char* token = strtok(port_name, ".");;
|
|
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
// Change scope into submodule
|
|
|
|
|
while (submodules--) {
|
|
|
|
|
scope = vpi_handle_by_name(token, scope);
|
2023-07-19 15:02:20 +02:00
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
if (!scope) vpi_printf("SDF ERROR: %s:%d: Submodule %s in port path not found!\n", sdf_fname, sdf_lineno, token);
|
2023-07-19 15:02:20 +02:00
|
|
|
|
|
|
|
|
// Extract next token
|
2023-08-17 16:09:20 +02:00
|
|
|
token = strtok(NULL, ".");
|
2023-07-19 15:02:20 +02:00
|
|
|
}
|
|
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
// Iterate over ports
|
2023-07-19 15:02:20 +02:00
|
|
|
vpiHandle port_i = vpi_iterate(vpiPort, scope) ;
|
|
|
|
|
vpiHandle port;
|
|
|
|
|
vpiHandle port_handle = NULL;
|
|
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
while ((port=vpi_scan(port_i)) != NULL) {
|
2025-10-13 02:35:15 +02:00
|
|
|
const char *port_name_ = vpi_get_str(vpiName, port) ;
|
2023-08-17 16:09:20 +02:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
2023-07-19 15:02:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
// Get handles for both ports
|
|
|
|
|
// After calling get_port_handle, the name is invalid
|
2023-07-19 15:02:20 +02:00
|
|
|
vpiHandle port1_handle = get_port_handle(port1.name, sdf_lineno);
|
|
|
|
|
vpiHandle port2_handle = get_port_handle(port2.name, sdf_lineno);
|
|
|
|
|
|
2023-08-30 09:50:00 +02:00
|
|
|
// Check whether we have a single bit of a port for port1
|
2023-09-04 11:31:35 +02:00
|
|
|
if (port1.has_index) {
|
2023-08-30 09:50:00 +02:00
|
|
|
vpiHandle iter, vpi_port_bit;
|
|
|
|
|
iter = vpi_iterate(vpiBit, port1_handle);
|
|
|
|
|
|
|
|
|
|
if (!iter) {
|
|
|
|
|
vpi_printf("SDF ERROR: %s:%d: Could not find vpiBit iterator for port1!\n", sdf_fname, sdf_lineno);
|
2023-09-04 15:20:31 +02:00
|
|
|
return;
|
2023-08-30 09:50:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ((vpi_port_bit = vpi_scan(iter))) {
|
|
|
|
|
int bit = vpi_get(vpiBit, vpi_port_bit);
|
|
|
|
|
|
|
|
|
|
// If we found the correct vpiPortBit, replace the port with it
|
|
|
|
|
if (port1.index == bit) {
|
|
|
|
|
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Substituting vpiPort with vpiPortBit for port1\n", sdf_fname, sdf_lineno);
|
|
|
|
|
port1_handle = vpi_port_bit;
|
2023-09-04 15:20:31 +02:00
|
|
|
vpi_release_handle(iter); // Free the iterator
|
2023-08-30 09:50:00 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check whether we have a single bit of a port for port2
|
2023-09-04 11:31:35 +02:00
|
|
|
if (port2.has_index) {
|
2023-08-30 09:50:00 +02:00
|
|
|
vpiHandle iter, vpi_port_bit;
|
|
|
|
|
iter = vpi_iterate(vpiBit, port2_handle);
|
|
|
|
|
|
|
|
|
|
if (!iter) {
|
|
|
|
|
vpi_printf("SDF ERROR: %s:%d: Could not find vpiBit iterator for port2!\n", sdf_fname, sdf_lineno);
|
2023-09-04 15:20:31 +02:00
|
|
|
return;
|
2023-08-30 09:50:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ((vpi_port_bit = vpi_scan(iter))) {
|
|
|
|
|
int bit = vpi_get(vpiBit, vpi_port_bit);
|
|
|
|
|
|
|
|
|
|
// If we found the correct vpiPortBit, replace the port with it
|
|
|
|
|
if (port2.index == bit) {
|
|
|
|
|
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Substituting vpiPort with vpiPortBit for port2\n", sdf_fname, sdf_lineno);
|
|
|
|
|
port2_handle = vpi_port_bit;
|
2023-09-04 15:20:31 +02:00
|
|
|
vpi_release_handle(iter); // Free the iterator
|
2023-08-30 09:50:00 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
if (port1_handle && port2_handle) {
|
2023-07-19 15:02:20 +02:00
|
|
|
// Get interModPath for the two ports
|
2023-08-17 16:09:20 +02:00
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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);
|
2023-07-19 15:02:20 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-14 05:42:06 +01:00
|
|
|
void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
|
2023-06-26 05:11:38 +02:00
|
|
|
const struct sdf_delval_list_s*delval_list,
|
|
|
|
|
const int sdf_lineno)
|
2007-11-21 07:20:22 +01:00
|
|
|
{
|
2009-02-10 04:21:50 +01:00
|
|
|
vpiHandle iter, path;
|
|
|
|
|
int match_count = 0;
|
|
|
|
|
|
2007-11-28 06:44:25 +01:00
|
|
|
if (sdf_cur_cell == 0)
|
|
|
|
|
return;
|
2007-11-21 07:20:22 +01:00
|
|
|
|
2009-02-10 04:21:50 +01:00
|
|
|
iter = vpi_iterate(vpiModPath, sdf_cur_cell);
|
2007-12-15 06:04:20 +01:00
|
|
|
|
2007-11-21 07:20:22 +01:00
|
|
|
/* Search for the modpath that matches the IOPATH by looking
|
|
|
|
|
for the modpath that uses the same ports as the ports that
|
|
|
|
|
the parser has found. */
|
2009-01-29 05:44:15 +01:00
|
|
|
if (iter) while ( (path = vpi_scan(iter)) ) {
|
2009-02-10 04:21:50 +01:00
|
|
|
s_vpi_delay delays;
|
|
|
|
|
struct t_vpi_time delay_vals[12];
|
|
|
|
|
int idx;
|
|
|
|
|
|
2007-12-14 05:42:06 +01:00
|
|
|
vpiHandle path_t_in = vpi_handle(vpiModPathIn,path);
|
|
|
|
|
vpiHandle path_t_out = vpi_handle(vpiModPathOut,path);
|
2007-11-21 07:20:22 +01:00
|
|
|
|
2007-12-14 05:42:06 +01:00
|
|
|
vpiHandle path_in = vpi_handle(vpiExpr,path_t_in);
|
|
|
|
|
vpiHandle path_out = vpi_handle(vpiExpr,path_t_out);
|
|
|
|
|
|
|
|
|
|
/* The expressions for the path terms must be signals,
|
|
|
|
|
vpiNet or vpiReg. */
|
2007-11-21 07:20:22 +01:00
|
|
|
assert(vpi_get(vpiType,path_in) == vpiNet);
|
2007-12-14 05:42:06 +01:00
|
|
|
assert(vpi_get(vpiType,path_out) == vpiNet
|
|
|
|
|
|| vpi_get(vpiType,path_out) == vpiReg);
|
2007-11-21 07:20:22 +01:00
|
|
|
|
|
|
|
|
/* If the src name doesn't match, go on. */
|
|
|
|
|
if (strcmp(src,vpi_get_str(vpiName,path_in)) != 0)
|
|
|
|
|
continue;
|
2007-12-15 06:04:20 +01:00
|
|
|
/* The edge type must match too. But note that if this
|
|
|
|
|
IOPATH has no edge, then it matches with all edges of
|
|
|
|
|
the modpath object. */
|
2009-02-10 05:13:05 +01:00
|
|
|
/* --> Is this correct in the context of the 10, 01, etc. edges? */
|
2007-12-15 06:04:20 +01:00
|
|
|
if (vpi_edge != vpiNoEdge && vpi_get(vpiEdge,path_t_in) != vpi_edge)
|
2007-12-14 05:42:06 +01:00
|
|
|
continue;
|
2007-11-21 07:20:22 +01:00
|
|
|
|
|
|
|
|
/* If the dst name doesn't match, go on. */
|
|
|
|
|
if (strcmp(dst,vpi_get_str(vpiName,path_out)) != 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Ah, this must be a match! */
|
2009-02-10 04:21:50 +01:00
|
|
|
delays.da = delay_vals;
|
|
|
|
|
delays.no_of_delays = delval_list->count;
|
|
|
|
|
delays.time_type = vpiScaledRealTime;
|
|
|
|
|
delays.mtm_flag = 0;
|
|
|
|
|
delays.append_flag = 0;
|
2019-11-12 18:58:19 +01:00
|
|
|
delays.pulsere_flag = 0;
|
2009-02-10 04:21:50 +01:00
|
|
|
vpi_get_delays(path, &delays);
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < delval_list->count ; idx += 1) {
|
|
|
|
|
delay_vals[idx].type = vpiScaledRealTime;
|
|
|
|
|
if (delval_list->val[idx].defined) {
|
|
|
|
|
delay_vals[idx].real = delval_list->val[idx].value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-15 06:04:20 +01:00
|
|
|
vpi_put_delays(path, &delays);
|
|
|
|
|
match_count += 1;
|
2007-11-21 07:20:22 +01:00
|
|
|
}
|
|
|
|
|
|
2007-12-15 06:04:20 +01:00
|
|
|
if (match_count == 0) {
|
2023-08-17 16:09:20 +02:00
|
|
|
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));
|
2007-11-21 07:20:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-23 03:22:46 +01:00
|
|
|
static void check_command_line_args(void)
|
|
|
|
|
{
|
|
|
|
|
struct t_vpi_vlog_info vlog_info;
|
|
|
|
|
int idx;
|
|
|
|
|
|
|
|
|
|
static int sdf_command_line_done = 0;
|
|
|
|
|
if (sdf_command_line_done)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
vpi_get_vlog_info(&vlog_info);
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < vlog_info.argc ; idx += 1) {
|
|
|
|
|
if (strcmp(vlog_info.argv[idx],"-sdf-warn") == 0) {
|
2007-11-28 06:44:25 +01:00
|
|
|
sdf_flag_warning = 1;
|
2007-11-23 03:22:46 +01:00
|
|
|
|
|
|
|
|
} else if (strcmp(vlog_info.argv[idx],"-sdf-info") == 0) {
|
|
|
|
|
sdf_flag_inform = 1;
|
|
|
|
|
|
|
|
|
|
} else if (strcmp(vlog_info.argv[idx],"-sdf-verbose") == 0) {
|
2007-11-28 06:44:25 +01:00
|
|
|
sdf_flag_warning = 1;
|
2007-11-23 03:22:46 +01:00
|
|
|
sdf_flag_inform = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sdf_command_line_done = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-04 18:31:01 +02:00
|
|
|
static PLI_INT32 sys_sdf_annotate_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
2007-11-19 02:36:03 +01:00
|
|
|
{
|
2009-02-05 22:24:58 +01:00
|
|
|
vpiHandle callh = vpi_handle(vpiSysTfCall,0);
|
|
|
|
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
|
|
|
|
vpiHandle module;
|
2007-12-01 06:57:38 +01:00
|
|
|
|
2009-02-05 22:24:58 +01:00
|
|
|
check_command_line_args();
|
2007-12-01 06:57:38 +01:00
|
|
|
|
2009-02-05 22:24:58 +01:00
|
|
|
/* Check that we have a file name argument. */
|
|
|
|
|
if (argv == 0) {
|
2023-06-15 10:27:20 +02:00
|
|
|
vpi_printf("SDF ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
2009-02-05 22:24:58 +01:00
|
|
|
(int)vpi_get(vpiLineNo, callh));
|
|
|
|
|
vpi_printf("%s requires a file name argument.\n", name);
|
2021-01-21 08:50:06 +01:00
|
|
|
vpip_set_return_value(1);
|
2007-12-16 00:25:25 +01:00
|
|
|
vpi_control(vpiFinish, 1);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2009-02-05 22:24:58 +01:00
|
|
|
if (! is_string_obj(vpi_scan(argv))) {
|
2023-06-15 10:27:20 +02:00
|
|
|
vpi_printf("SDF ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
2009-02-05 22:24:58 +01:00
|
|
|
(int)vpi_get(vpiLineNo, callh));
|
|
|
|
|
vpi_printf("%s's file name must be a string.\n", name);
|
2021-01-21 08:50:06 +01:00
|
|
|
vpip_set_return_value(1);
|
2009-02-05 22:24:58 +01:00
|
|
|
vpi_control(vpiFinish, 1);
|
|
|
|
|
}
|
2007-12-16 00:25:25 +01:00
|
|
|
|
2009-02-05 22:24:58 +01:00
|
|
|
/* The module argument is optional. */
|
|
|
|
|
module = vpi_scan(argv);
|
|
|
|
|
if (module == 0) return 0;
|
|
|
|
|
if (vpi_get(vpiType, module) != vpiModule) {
|
2023-06-15 10:27:20 +02:00
|
|
|
vpi_printf("SDF ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
2009-02-05 22:24:58 +01:00
|
|
|
(int)vpi_get(vpiLineNo, callh));
|
|
|
|
|
vpi_printf("%s's second argument must be a module instance.\n",
|
|
|
|
|
name);
|
2021-01-21 08:50:06 +01:00
|
|
|
vpip_set_return_value(1);
|
2007-12-16 00:25:25 +01:00
|
|
|
vpi_control(vpiFinish, 1);
|
|
|
|
|
}
|
2007-12-01 06:57:38 +01:00
|
|
|
|
2009-02-05 22:24:58 +01:00
|
|
|
/* Warn the user that we only use the first two arguments. */
|
|
|
|
|
if (vpi_scan(argv) != 0) {
|
2023-06-15 10:27:20 +02:00
|
|
|
vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
2009-02-05 22:24:58 +01:00
|
|
|
(int)vpi_get(vpiLineNo, callh));
|
|
|
|
|
vpi_printf("%s currently only uses the first two argument.\n",
|
|
|
|
|
name);
|
|
|
|
|
vpi_free_object(argv);
|
|
|
|
|
}
|
2007-12-01 06:57:38 +01:00
|
|
|
|
2007-11-19 02:36:03 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-04 18:31:01 +02:00
|
|
|
static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
2007-11-19 02:36:03 +01:00
|
|
|
{
|
2010-03-18 02:48:11 +01:00
|
|
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
2009-02-05 22:24:58 +01:00
|
|
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
2009-02-25 01:47:46 +01:00
|
|
|
FILE *sdf_fd;
|
|
|
|
|
char *fname = get_filename(callh, name, vpi_scan(argv));
|
2007-11-19 02:36:03 +01:00
|
|
|
|
2017-11-17 04:40:09 +01:00
|
|
|
if (fname == 0) {
|
|
|
|
|
vpi_free_object(argv);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2007-11-19 02:36:03 +01:00
|
|
|
|
2023-08-17 16:09:20 +02:00
|
|
|
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));
|
|
|
|
|
}
|
2023-07-19 15:02:20 +02:00
|
|
|
|
2009-02-25 01:47:46 +01:00
|
|
|
sdf_fd = fopen(fname, "r");
|
2007-12-16 00:25:25 +01:00
|
|
|
if (sdf_fd == 0) {
|
2023-06-15 10:27:20 +02:00
|
|
|
vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
2009-02-05 22:24:58 +01:00
|
|
|
(int)vpi_get(vpiLineNo, callh));
|
|
|
|
|
vpi_printf("Unable to open SDF file \"%s\"."
|
2009-02-25 01:47:46 +01:00
|
|
|
" Skipping this annotation.\n", fname);
|
2017-11-17 04:40:09 +01:00
|
|
|
vpi_free_object(argv);
|
|
|
|
|
free(fname);
|
2007-12-16 00:25:25 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-06-26 05:11:38 +02:00
|
|
|
sdf_fname = fname;
|
2007-11-19 02:36:03 +01:00
|
|
|
|
2007-12-01 06:57:38 +01:00
|
|
|
/* The optional second argument is the scope to annotate. */
|
|
|
|
|
sdf_scope = vpi_scan(argv);
|
2009-02-05 22:24:58 +01:00
|
|
|
if (sdf_scope) vpi_free_object(argv);
|
|
|
|
|
else sdf_scope = vpi_handle(vpiScope, callh);
|
2007-12-01 06:57:38 +01:00
|
|
|
|
2010-03-18 02:48:11 +01:00
|
|
|
/* Select which delay to use. */
|
|
|
|
|
sdf_min_typ_max = vpi_get(_vpiDelaySelection, 0);
|
|
|
|
|
|
2007-11-21 07:20:22 +01:00
|
|
|
sdf_cur_cell = 0;
|
2009-02-05 22:24:58 +01:00
|
|
|
sdf_callh = callh;
|
2009-02-25 01:47:46 +01:00
|
|
|
sdf_process_file(sdf_fd, fname);
|
2009-02-05 22:24:58 +01:00
|
|
|
sdf_callh = 0;
|
2007-11-19 02:36:03 +01:00
|
|
|
|
|
|
|
|
fclose(sdf_fd);
|
2023-06-26 05:11:38 +02:00
|
|
|
sdf_fname = NULL;
|
2009-02-25 01:47:46 +01:00
|
|
|
free(fname);
|
2007-11-19 02:36:03 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-08 21:12:54 +02:00
|
|
|
void sys_sdf_register(void)
|
2007-11-19 02:36:03 +01:00
|
|
|
{
|
|
|
|
|
s_vpi_systf_data tf_data;
|
2010-04-12 08:39:08 +02:00
|
|
|
vpiHandle res;
|
2007-11-19 02:36:03 +01:00
|
|
|
|
|
|
|
|
tf_data.type = vpiSysTask;
|
|
|
|
|
tf_data.tfname = "$sdf_annotate";
|
|
|
|
|
tf_data.calltf = sys_sdf_annotate_calltf;
|
|
|
|
|
tf_data.compiletf = sys_sdf_annotate_compiletf;
|
|
|
|
|
tf_data.sizetf = 0;
|
|
|
|
|
tf_data.user_data = "$sdf_annotate";
|
2010-04-12 08:39:08 +02:00
|
|
|
res = vpi_register_systf(&tf_data);
|
|
|
|
|
vpip_make_systf_system_defined(res);
|
2007-11-19 02:36:03 +01:00
|
|
|
}
|