1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
|
/*
* Copyright (c) 2007-2021 Stephen Williams (steve@icarus.com)
*
* 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "sys_priv.h"
# include "sdf_priv.h"
# include <stdlib.h>
# include <string.h>
# include <assert.h>
/*
* These are static context
*/
int sdf_flag_warning = 0;
int sdf_flag_inform = 0;
int sdf_min_typ_max;
/* Scope of the $sdf_annotate call. Annotation starts here. */
static vpiHandle sdf_scope;
static vpiHandle sdf_callh = 0;
/* The cell in process. */
static vpiHandle sdf_cur_cell;
static vpiHandle find_scope(vpiHandle scope, const char*name)
{
vpiHandle idx = vpi_iterate(vpiModule, scope);
/* 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;
vpiHandle cur;
while ( (cur = vpi_scan(idx)) ) {
if ( strcmp(name, vpi_get_str(vpiName,cur)) == 0) {
vpi_free_object(idx);
return cur;
}
}
return 0;
}
/*
* These functions are called by the SDF parser during parsing to
* handling items discovered in the parse.
*/
void sdf_select_instance(const char*celltype, const char*cellinst)
{
char buffer[128];
/* 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, '.')) ) {
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 WARNING: %s:%d: ",
vpi_get_str(vpiFile, sdf_callh),
(int)vpi_get(vpiLineNo, sdf_callh));
vpi_printf("Cannot find %s in scope %s.\n",
buffer, vpi_get_str(vpiFullName, scope));
break;
}
assert(tmp_scope);
scope = tmp_scope;
src = dp + 1;
}
/* Now find the cell. */
if (src[0] == 0)
sdf_cur_cell = sdf_scope;
else
sdf_cur_cell = find_scope(scope, src);
if (sdf_cur_cell == 0) {
vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, sdf_callh),
(int)vpi_get(vpiLineNo, sdf_callh));
vpi_printf("Unable to find %s in scope %s.\n",
src, vpi_get_str(vpiFullName, scope));
return;
}
/* The scope that matches should be a module. */
if (vpi_get(vpiType,sdf_cur_cell) != vpiModule) {
vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, sdf_callh),
(int)vpi_get(vpiLineNo, sdf_callh));
vpi_printf("Scope %s in %s is not a module.\n",
src, vpi_get_str(vpiFullName, scope));
}
/* The matching scope (a module) should have the expected type. */
if (strcmp(celltype,vpi_get_str(vpiDefName,sdf_cur_cell)) != 0) {
vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, sdf_callh),
(int)vpi_get(vpiLineNo, sdf_callh));
vpi_printf("Module %s in %s is not a %s; it is a ", src,
vpi_get_str(vpiFullName, scope), celltype);
vpi_printf("%s\n", vpi_get_str(vpiDefName, sdf_cur_cell));
}
}
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.. ";
}
void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
const struct sdf_delval_list_s*delval_list)
{
vpiHandle iter, path;
int match_count = 0;
if (sdf_cur_cell == 0)
return;
iter = vpi_iterate(vpiModPath, sdf_cur_cell);
/* 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. */
if (iter) while ( (path = vpi_scan(iter)) ) {
s_vpi_delay delays;
struct t_vpi_time delay_vals[12];
int idx;
vpiHandle path_t_in = vpi_handle(vpiModPathIn,path);
vpiHandle path_t_out = vpi_handle(vpiModPathOut,path);
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. */
assert(vpi_get(vpiType,path_in) == vpiNet);
assert(vpi_get(vpiType,path_out) == vpiNet
|| vpi_get(vpiType,path_out) == vpiReg);
/* If the src name doesn't match, go on. */
if (strcmp(src,vpi_get_str(vpiName,path_in)) != 0)
continue;
/* 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. */
/* --> Is this correct in the context of the 10, 01, etc. edges? */
if (vpi_edge != vpiNoEdge && vpi_get(vpiEdge,path_t_in) != vpi_edge)
continue;
/* 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! */
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(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;
}
}
vpi_put_delays(path, &delays);
match_count += 1;
}
if (match_count == 0) {
vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, sdf_callh),
(int)vpi_get(vpiLineNo, sdf_callh));
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));
}
}
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) {
sdf_flag_warning = 1;
} else if (strcmp(vlog_info.argv[idx],"-sdf-info") == 0) {
sdf_flag_inform = 1;
} else if (strcmp(vlog_info.argv[idx],"-sdf-verbose") == 0) {
sdf_flag_warning = 1;
sdf_flag_inform = 1;
}
}
sdf_command_line_done = 1;
}
static PLI_INT32 sys_sdf_annotate_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall,0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle module;
check_command_line_args();
/* Check that we have a file name argument. */
if (argv == 0) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a file name argument.\n", name);
vpip_set_return_value(1);
vpi_control(vpiFinish, 1);
return 0;
}
if (! is_string_obj(vpi_scan(argv))) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's file name must be a string.\n", name);
vpip_set_return_value(1);
vpi_control(vpiFinish, 1);
}
/* The module argument is optional. */
module = vpi_scan(argv);
if (module == 0) return 0;
if (vpi_get(vpiType, module) != vpiModule) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must be a module instance.\n",
name);
vpip_set_return_value(1);
vpi_control(vpiFinish, 1);
}
/* Warn the user that we only use the first two arguments. */
if (vpi_scan(argv) != 0) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s currently only uses the first two argument.\n",
name);
vpi_free_object(argv);
}
return 0;
}
static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
FILE *sdf_fd;
char *fname = get_filename(callh, name, vpi_scan(argv));
if (fname == 0) {
vpi_free_object(argv);
return 0;
}
sdf_fd = fopen(fname, "r");
if (sdf_fd == 0) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("Unable to open SDF file \"%s\"."
" Skipping this annotation.\n", fname);
vpi_free_object(argv);
free(fname);
return 0;
}
/* The optional second argument is the scope to annotate. */
sdf_scope = vpi_scan(argv);
if (sdf_scope) vpi_free_object(argv);
else sdf_scope = vpi_handle(vpiScope, callh);
/* Select which delay to use. */
sdf_min_typ_max = vpi_get(_vpiDelaySelection, 0);
sdf_cur_cell = 0;
sdf_callh = callh;
sdf_process_file(sdf_fd, fname);
sdf_callh = 0;
fclose(sdf_fd);
free(fname);
return 0;
}
void sys_sdf_register(void)
{
s_vpi_systf_data tf_data;
vpiHandle res;
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";
res = vpi_register_systf(&tf_data);
vpip_make_systf_system_defined(res);
}
|