Fix/enhance readmem/writemem routines, etc.

This patch adds compilef routines for the readmemb/h and
writememb/h system tasks. It also fixes some errors related
to arrays with negative range values. You can not specify a
negative address in the file, but arrays with negative range
values or negative start/finish argument to the tasks are
supported. It also generates an error when reading invalid
character from the input file.

A significant amount of the code is common between the two
styles of tasks so this has been grouped into common
routines.

It also adds a common routine for getting a string that will
be used as a file name. This routine is used by any task
that requires a file name value. If a filename has a
non-printable character it will be displayed as a \octal
constant to show what the character is.

Updates the dumping routines to match each other better,
improves some error messages and fixes a bug in the LXT2
dumper when dumping greater than 32 bit delays.
This commit is contained in:
Cary R 2009-02-24 16:47:46 -08:00 committed by Stephen Williams
parent fa02455f36
commit fa1160c4ab
10 changed files with 551 additions and 601 deletions

View File

@ -96,12 +96,12 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name)
int fail = 0; int fail = 0;
char *mode_string = 0; char *mode_string = 0;
unsigned idx; unsigned idx;
vpiHandle item = vpi_scan(argv); vpiHandle fileh = vpi_scan(argv);
char *fname;
vpiHandle mode = vpi_scan(argv); vpiHandle mode = vpi_scan(argv);
unsigned len;
/* Get the mode handle if it exists. */ /* Get the mode handle if it exists. */
if (mode) { if (mode) {
char *esc_md;
val.format = vpiStringVal; val.format = vpiStringVal;
vpi_get_value(mode, &val); vpi_get_value(mode, &val);
/* Verify that we have a string and that it is not NULL. */ /* Verify that we have a string and that it is not NULL. */
@ -119,8 +119,10 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name)
vpi_printf("WARNING: %s:%d: ", vpi_printf("WARNING: %s:%d: ",
vpi_get_str(vpiFile, callh), vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
esc_md = as_escaped(val.value.str);
vpi_printf("%s's mode argument (%s) is too long.\n", vpi_printf("%s's mode argument (%s) is too long.\n",
name, val.value.str); name, esc_md);
free(esc_md);
fail = 1; fail = 1;
} else { } else {
unsigned bin = 0, plus = 0; unsigned bin = 0, plus = 0;
@ -150,8 +152,10 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name)
vpi_printf("WARNING: %s:%d: ", vpi_printf("WARNING: %s:%d: ",
vpi_get_str(vpiFile, callh), vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
esc_md = as_escaped(val.value.str);
vpi_printf("%s's mode argument (%s) is invalid.\n", vpi_printf("%s's mode argument (%s) is invalid.\n",
name, val.value.str); name, esc_md);
free(esc_md);
fail = 1; fail = 1;
break; break;
} }
@ -162,49 +166,18 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name)
vpi_free_object(argv); vpi_free_object(argv);
} }
/* Get the string form of the file name from the file name fname = get_filename(callh, name, fileh);
argument. */ if (fname == 0 && mode) free(mode_string);
val.format = vpiStringVal;
vpi_get_value(item, &val);
/* Verify that we have a string and that it is not NULL. */
if (val.format != vpiStringVal || !*(val.value.str)) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's file name argument is not a valid string.\n",
name);
fail = 1;
if (mode) free(mode_string);
}
/*
* Verify that the file name is composed of only printable
* characters.
*/
len = strlen(val.value.str);
for (idx = 0; idx < len; idx++) {
if (! isprint(val.value.str[idx])) {
char msg [64];
snprintf(msg, 64, "WARNING: %s:%d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s %s's file name argument contains non-"
"printable characters.\n", msg, name);
vpi_printf("%*s \"%s\"\n", (int) strlen(msg), " ", val.value.str);
fail = 1;
if (mode) free(mode_string);
}
}
/* If either the mode or file name are not valid just return. */ /* If either the mode or file name are not valid just return. */
if (fail) return 0; if (fail || fname == 0) return 0;
val.format = vpiIntVal; val.format = vpiIntVal;
if (mode) { if (mode) {
val.value.integer = vpi_fopen(val.value.str, mode_string); val.value.integer = vpi_fopen(fname, mode_string);
free(mode_string); free(mode_string);
} else } else
val.value.integer = vpi_mcd_open(val.value.str); val.value.integer = vpi_mcd_open(fname);
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
@ -220,51 +193,23 @@ static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name)
{ {
vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle file = vpi_scan(argv);
s_vpi_value val; s_vpi_value val;
char *mode; char *mode, *fname;
unsigned idx, len;
vpi_free_object(argv);
/* Get the mode. */ /* Get the mode. */
mode = name + strlen(name) - 1; mode = name + strlen(name) - 1;
/* Get the filename. */ /* Get the file name. */
val.format = vpiStringVal; fname = get_filename(callh, name, vpi_scan(argv));
vpi_get_value(file, &val); vpi_free_object(argv);
if (fname == 0) return 0;
/* Verify that we have a string and that it is not NULL. */
if (val.format != vpiStringVal || !*(val.value.str)) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's file name argument is not a valid string.\n",
name);
return 0;
}
/*
* Verify that the file name is composed of only printable
* characters.
*/
len = strlen(val.value.str);
for (idx = 0; idx < len; idx++) {
if (! isprint(val.value.str[idx])) {
char msg [64];
snprintf(msg, 64, "WARNING: %s:%d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s %s's file name argument contains non-"
"printable characters.\n", msg, name);
vpi_printf("%*s \"%s\"\n", (int) strlen(msg), " ", val.value.str);
return 0;
}
}
/* Open the file and return the result. */ /* Open the file and return the result. */
val.format = vpiIntVal; val.format = vpiIntVal;
val.value.integer = vpi_fopen(val.value.str, mode); val.value.integer = vpi_fopen(fname, mode);
vpi_put_value(callh, &val, 0, vpiNoDelay); vpi_put_value(callh, &val, 0, vpiNoDelay);
free(fname);
return 0; return 0;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
* *
* 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
@ -168,7 +168,7 @@ static void show_this_item(struct vcd_info*info)
{ {
s_vpi_value value; s_vpi_value value;
if (vpi_get(vpiType,info->item) == vpiRealVar) { if (vpi_get(vpiType, info->item) == vpiRealVar) {
value.format = vpiRealVal; value.format = vpiRealVal;
vpi_get_value(info->item, &value); vpi_get_value(info->item, &value);
lt_emit_value_double(dump_file, info->sym, 0, value.value.real); lt_emit_value_double(dump_file, info->sym, 0, value.value.real);
@ -280,8 +280,7 @@ static PLI_INT32 variable_cb_1(p_cb_data cause)
static PLI_INT32 dumpvars_cb(p_cb_data cause) static PLI_INT32 dumpvars_cb(p_cb_data cause)
{ {
if (dumpvars_status != 1) if (dumpvars_status != 1) return 0;
return 0;
dumpvars_status = 2; dumpvars_status = 2;
@ -298,13 +297,11 @@ static PLI_INT32 dumpvars_cb(p_cb_data cause)
static PLI_INT32 finish_cb(p_cb_data cause) static PLI_INT32 finish_cb(p_cb_data cause)
{ {
if (finish_status != 0) if (finish_status != 0) return 0;
return 0;
finish_status = 1; finish_status = 1;
dumpvars_time = timerec_to_time64(cause->time); dumpvars_time = timerec_to_time64(cause->time);
if (!dump_is_off && !dump_is_full && dumpvars_time != vcd_cur_time) { if (!dump_is_off && !dump_is_full && dumpvars_time != vcd_cur_time) {
lt_set_time64(dump_file, dumpvars_time); lt_set_time64(dump_file, dumpvars_time);
} }
@ -317,8 +314,7 @@ __inline__ static int install_dumpvars_callback(void)
struct t_cb_data cb; struct t_cb_data cb;
static struct t_vpi_time now; static struct t_vpi_time now;
if (dumpvars_status == 1) if (dumpvars_status == 1) return 0;
return 0;
if (dumpvars_status == 2) { if (dumpvars_status == 2) {
vpi_printf("LXT warning: $dumpvars ignored, previously" vpi_printf("LXT warning: $dumpvars ignored, previously"
@ -412,7 +408,7 @@ static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name)
vpi_get_time(0, &now); vpi_get_time(0, &now);
now64 = timerec_to_time64(&now); now64 = timerec_to_time64(&now);
if (now64> vcd_cur_time) { if (now64 > vcd_cur_time) {
lt_set_time64(dump_file, now64); lt_set_time64(dump_file, now64);
vcd_cur_time = now64; vcd_cur_time = now64;
} }
@ -460,31 +456,33 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
{ {
vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle argv = vpi_iterate(vpiArgument, callh);
s_vpi_value value; char *path;
char*path;
/* $dumpfile must be called before $dumpvars starts! */ /* $dumpfile must be called before $dumpvars starts! */
if (dumpvars_status != 0) { if (dumpvars_status != 0) {
vpi_printf("LXT warning: %s called after $dumpvars started,\n" char msg [64];
" using existing file (%s).\n", snprintf(msg, 64, "LXT warning: %s:%d:",
name, dump_path); vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s %s called after $dumpvars started,\n", msg, name);
vpi_printf("%*s using existing file (%s).\n",
(int) strlen(msg), " ", dump_path);
vpi_free_object(argv);
return 0; return 0;
} }
assert(argv); path = get_filename(callh, name, vpi_scan(argv));
value.format = vpiStringVal; vpi_free_object(argv);
vpi_get_value(vpi_scan(argv), &value); if (! path) return 0;
path = strdup(value.value.str);
if (dump_path) { if (dump_path) {
vpi_printf("LXT warning: Overriding dump file %s with %s\n", vpi_printf("LXT warning: %s:%d: ", vpi_get_str(vpiFile, callh),
dump_path, path); (int)vpi_get(vpiLineNo, callh));
vpi_printf("Overriding dump file %s with %s.\n", dump_path, path);
free(dump_path); free(dump_path);
} }
dump_path = path; dump_path = path;
vpi_free_object(argv);
return 0; return 0;
} }
@ -500,12 +498,11 @@ static PLI_INT32 sys_dumplimit_calltf(PLI_BYTE8 *name)
{ {
vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle limit = vpi_scan(argv);
s_vpi_value val; s_vpi_value val;
/* Get the value and set the dump limit. */ /* Get the value and set the dump limit. */
val.format = vpiIntVal; val.format = vpiIntVal;
vpi_get_value(limit, &val); vpi_get_value(vpi_scan(argv), &val);
dump_limit = val.value.integer; dump_limit = val.value.integer;
vpi_free_object(argv); vpi_free_object(argv);
@ -567,7 +564,11 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
info->time.type = vpiSimTime; info->time.type = vpiSimTime;
info->item = item; info->item = item;
info->sym = lt_symbol_add(dump_file, ident, 0 /* array rows */, vpi_get(vpiLeftRange, item), vpi_get(vpiRightRange, item), LT_SYM_F_BITS); info->sym = lt_symbol_add(dump_file, ident,
0 /* array rows */,
vpi_get(vpiLeftRange, item),
vpi_get(vpiRightRange, item),
LT_SYM_F_BITS);
info->scheduled = 0; info->scheduled = 0;
cb.time = &info->time; cb.time = &info->time;
@ -604,7 +605,10 @@ static void scan_item(unsigned depth, vpiHandle item, int skip)
info->time.type = vpiSimTime; info->time.type = vpiSimTime;
info->item = item; info->item = item;
info->sym = lt_symbol_add(dump_file, ident, 0 /* array rows */, vpi_get(vpiSize, item)-1, 0, LT_SYM_F_DOUBLE); info->sym = lt_symbol_add(dump_file, ident,
0 /* array rows */,
vpi_get(vpiSize, item)-1,
0, LT_SYM_F_DOUBLE);
info->scheduled = 0; info->scheduled = 0;
cb.time = &info->time; cb.time = &info->time;
@ -675,8 +679,7 @@ static int draw_scope(vpiHandle item)
const char *name; const char *name;
vpiHandle scope = vpi_handle(vpiScope, item); vpiHandle scope = vpi_handle(vpiScope, item);
if (!scope) if (!scope) return 0;
return 0;
depth = 1 + draw_scope(scope); depth = 1 + draw_scope(scope);
name = vpi_get_str(vpiName, scope); name = vpi_get_str(vpiName, scope);
@ -696,10 +699,16 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
if (dump_file == 0) { if (dump_file == 0) {
open_dumpfile(callh); open_dumpfile(callh);
if (dump_file == 0) return 0; if (dump_file == 0) {
vpi_free_object(argv);
return 0;
}
} }
if (install_dumpvars_callback()) return 0; if (install_dumpvars_callback()) {
vpi_free_object(argv);
return 0;
}
/* Get the depth if it exists. */ /* Get the depth if it exists. */
if (argv) { if (argv) {
@ -727,7 +736,9 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
} }
/* Most effective compression. */ /* Most effective compression. */
if (lxm_optimum_mode == LXM_SPACE) lt_set_no_interlace(dump_file); if (lxm_optimum_mode == LXM_SPACE) {
lt_set_no_interlace(dump_file);
}
return 0; return 0;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2003-2009 Stephen Williams (steve@icarus.com)
* *
* 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
@ -142,7 +142,7 @@ static char *create_full_name(const char *name)
} }
static char *dump_path; static char *dump_path = 0;
static struct lxt2_wr_trace *dump_file = 0; static struct lxt2_wr_trace *dump_file = 0;
struct vcd_info { struct vcd_info {
@ -169,7 +169,7 @@ static void show_this_item(struct vcd_info*info)
{ {
s_vpi_value value; s_vpi_value value;
if (vpi_get(vpiType,info->item) == vpiRealVar) { if (vpi_get(vpiType, info->item) == vpiRealVar) {
value.format = vpiRealVal; value.format = vpiRealVal;
vpi_get_value(info->item, &value); vpi_get_value(info->item, &value);
lxt2_wr_emit_value_double(dump_file, info->sym, 0, lxt2_wr_emit_value_double(dump_file, info->sym, 0,
@ -361,7 +361,7 @@ static PLI_INT32 sys_dumpoff_calltf(PLI_BYTE8*name)
if (now64 > vcd_cur_time) { if (now64 > vcd_cur_time) {
lxt2_wr_set_time(dump_file, now64); lxt2_wr_set_time(dump_file, now64);
vcd_cur_time = now.low; vcd_cur_time = now64;
} }
lxt2_wr_set_dumpoff(dump_file); lxt2_wr_set_dumpoff(dump_file);
@ -410,9 +410,10 @@ static PLI_INT32 sys_dumpall_calltf(PLI_BYTE8*name)
vpi_get_time(0, &now); vpi_get_time(0, &now);
now64 = timerec_to_time64(&now); now64 = timerec_to_time64(&now);
if (now64 > vcd_cur_time) if (now64 > vcd_cur_time) {
lxt2_wr_set_time64(dump_file, now64); lxt2_wr_set_time64(dump_file, now64);
vcd_cur_time = now64; vcd_cur_time = now64;
}
vcd_checkpoint(); vcd_checkpoint();
@ -458,33 +459,35 @@ static void open_dumpfile(vpiHandle callh)
static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name) static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
{ {
vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle argv = vpi_iterate(vpiArgument, callh);
s_vpi_value value; char *path;
char*path;
/* $dumpfile must be called before $dumpvars starts! */ /* $dumpfile must be called before $dumpvars starts! */
if (dumpvars_status != 0) { if (dumpvars_status != 0) {
vpi_printf("LXT2 warning: %s called after $dumpvars started,\n" char msg [64];
" using existing file (%s).\n", snprintf(msg, 64, "LXT2 warning: %s:%d:",
name, dump_path); vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s %s called after $dumpvars started,\n", msg, name);
vpi_printf("%*s using existing file (%s).\n",
(int) strlen(msg), " ", dump_path);
vpi_free_object(argv);
return 0; return 0;
} }
assert(argv); path = get_filename(callh, name, vpi_scan(argv));
value.format = vpiStringVal; vpi_free_object(argv);
vpi_get_value(vpi_scan(argv), &value); if (! path) return 0;
path = strdup(value.value.str);
if (dump_path) { if (dump_path) {
vpi_printf("LXT2 warning: Overriding dump file %s with %s.\n", vpi_printf("LXT2 warning: %s:%d: ", vpi_get_str(vpiFile, callh),
dump_path, path); (int)vpi_get(vpiLineNo, callh));
vpi_printf("Overriding dump file %s with %s.\n", dump_path, path);
free(dump_path); free(dump_path);
} }
dump_path = path; dump_path = path;
vpi_free_object(argv);
return 0; return 0;
} }
@ -708,10 +711,16 @@ static PLI_INT32 sys_dumpvars_calltf(PLI_BYTE8*name)
if (dump_file == 0) { if (dump_file == 0) {
open_dumpfile(callh); open_dumpfile(callh);
if (dump_file == 0) return 0; if (dump_file == 0) {
vpi_free_object(argv);
return 0;
}
} }
if (install_dumpvars_callback()) return 0; if (install_dumpvars_callback()) {
vpi_free_object(argv);
return 0;
}
/* Get the depth if it exists. */ /* Get the depth if it exists. */
if (argv) { if (argv) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2003-2009 Stephen Williams (steve@icarus.com)
* *
* 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
@ -18,6 +18,8 @@
*/ */
#include <assert.h> #include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "sys_priv.h" #include "sys_priv.h"
@ -32,6 +34,73 @@ PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time)
return tmp; return tmp;
} }
char * as_escaped(char *arg)
{
unsigned idx, cur, cnt, len = strlen(arg);
char *res = (char *) malloc(sizeof(char *) * len);
cur = 0;
cnt = len;
for (idx = 0; idx < cnt; idx++) {
if (isprint(arg[idx])) {
res[cur] = arg[idx];
cur += 1;
} else {
len += 3;
res = (char *) realloc(res, sizeof(char *) * len);
sprintf(&(res[cur]), "\\%03o", arg[idx]);
cur += 4;
}
}
res[cur] = 0;
return res;
}
/*
* Generic routine to get the filename from the given handle.
* The result is duplicated so call free when the name is no
* longer needed. Returns 0 (NULL) for an error.
*/
char * get_filename(vpiHandle callh, char *name, vpiHandle file)
{
s_vpi_value val;
unsigned len, idx;
/* Get the filename. */
val.format = vpiStringVal;
vpi_get_value(file, &val);
/* Verify that we have a string and that it is not NULL. */
if (val.format != vpiStringVal || !*(val.value.str)) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's file name argument (%s) is not a valid string.\n",
name, vpi_get_str(vpiType, file));
return 0;
}
/*
* Verify that the file name is composed of only printable
* characters.
*/
len = strlen(val.value.str);
for (idx = 0; idx < len; idx++) {
if (! isprint(val.value.str[idx])) {
char msg [64];
char *esc_fname = as_escaped(val.value.str);
snprintf(msg, 64, "WARNING: %s:%d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s %s's file name argument contains non-"
"printable characters.\n", msg, name);
vpi_printf("%*s \"%s\"\n", (int) strlen(msg), " ", esc_fname);
free(esc_fname);
return 0;
}
}
return strdup(val.value.str);
}
/* /*
* This routine returns 1 if the argument is a constant value, * This routine returns 1 if the argument is a constant value,
* otherwise it returns 0. * otherwise it returns 0.

View File

@ -1,7 +1,7 @@
#ifndef __vpi_sys_priv_H #ifndef __vpi_sys_priv_H
#define __vpi_sys_priv_H #define __vpi_sys_priv_H
/* /*
* Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com) * Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
* *
* 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
@ -35,6 +35,9 @@ extern unsigned long genrand(struct context_s *context);
extern PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time); extern PLI_UINT64 timerec_to_time64(const struct t_vpi_time*time);
extern char * as_escaped(char *arg);
extern char * get_filename(vpiHandle callh, char *name, vpiHandle file);
struct timeformat_info_s { struct timeformat_info_s {
int units; int units;
unsigned prec; unsigned prec;

View File

@ -20,105 +20,267 @@
# include "vpi_config.h" # include "vpi_config.h"
# include "vpi_user.h" # include "vpi_user.h"
# include "sys_priv.h"
# include <ctype.h>
# include <string.h> # include <string.h>
# include <stdlib.h> # include <stdlib.h>
# include <stdio.h> # include <stdio.h>
# include <assert.h> # include <assert.h>
# include "sys_readmem_lex.h" # include "sys_readmem_lex.h"
static int check_integer_constant(char*name, vpiHandle handle) static void get_mem_params(vpiHandle argv, vpiHandle callh, char *name,
char **fname, vpiHandle *mitem,
vpiHandle *start_item, vpiHandle *stop_item)
{ {
if (vpi_get(vpiType, handle) != vpiConstant){ /* Get the first parameter (file name). */
vpi_printf("ERROR: %s parameter must be a constant (vpiType=%d)\n", *fname = get_filename(callh, name, vpi_scan(argv));
name, vpi_get(vpiType, handle));
return 0;
}
switch(vpi_get(vpiConstType, handle)){ /* Get the second parameter (memory). */
case vpiDecConst: *mitem = vpi_scan(argv);
case vpiBinaryConst:
case vpiOctConst:
case vpiHexConst:
return 1;
break;
/* We rely on vpi_get_value for reals and strings to return a correct */
/* integer value when this is requested. So only a warning is generated. */
case vpiRealConst:
vpi_printf("Warning: real supplied to %s instead of integer.\n", name);
return 1;
break;
case vpiStringConst:
vpi_printf("Warning: string supplied to %s instead of integer.\n", name);
return 1;
break;
}
/* switch statement covers all possibilities. Code should never come here... */
assert(0);
return 0;
}
/*
* This function makes sure the handle is of an object that can get a
* string value for a file name.
*/
static int check_file_name(const char*name, vpiHandle item)
{
switch (vpi_get(vpiType, item)) {
/* Get optional third parameter (start address). */
*start_item = vpi_scan(argv);
if (*start_item) {
/* Warn the user if they gave a real value for the start
* address. */
switch (vpi_get(vpiType, *start_item)) {
case vpiConstant: case vpiConstant:
if (vpi_get(vpiConstType, item) != vpiStringConst) {
vpi_printf("ERROR: %s argument 1: file name argument "
"must be a string.\n", name);
return 0;
}
break;
case vpiParameter: case vpiParameter:
if (vpi_get(vpiConstType,item) != vpiStringConst) { if (vpi_get(vpiConstType, *start_item) != vpiRealConst) break;
vpi_printf("ERROR: %s argument 1: Parameter %s is " case vpiRealVar:
"not a string in this context.\n", vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
name, vpi_get_str(vpiName,item)); (int)vpi_get(vpiLineNo, callh));
return 0; vpi_printf("%s's third argument (start address) is a real "
} "value.\n", name);
break;
case vpiReg:
break;
default:
vpi_printf("ERROR: %s argument 1: must be a string\n", name);
return 0;
} }
return 1; /* Get optional forth parameter (finish address). */
*stop_item = vpi_scan(argv);
if (*stop_item) {
/* Warn the user if they gave a real value for the finish
* address. */
switch (vpi_get(vpiType, *stop_item)) {
case vpiConstant:
case vpiParameter:
if (vpi_get(vpiConstType, *stop_item) != vpiRealConst) {
break;
}
case vpiRealVar:
vpi_printf("WARNING: %s:%d: ",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's fourth argument (finish address) is a "
"real value.\n", name);
}
vpi_free_object(argv);
}
} else {
*stop_item = 0;
}
} }
static int process_params(vpiHandle mitem,
vpiHandle start_item, vpiHandle stop_item,
vpiHandle callh, char *name,
int *start_addr, int *stop_addr, int *addr_incr,
int *min_addr, int *max_addr)
{
s_vpi_value val;
int left_addr, right_addr;
/* Get left addr of memory */
val.format = vpiIntVal;
vpi_get_value(vpi_handle(vpiLeftRange, mitem), &val);
left_addr = val.value.integer;
/* Get right addr of memory */
val.format = vpiIntVal;
vpi_get_value(vpi_handle(vpiRightRange, mitem), &val);
right_addr = val.value.integer;
/* Get start_addr, stop_addr and addr_incr */
if (! start_item) {
*start_addr = left_addr<right_addr ? left_addr : right_addr;
*stop_addr = left_addr<right_addr ? right_addr : left_addr;
*addr_incr = 1;
} else {
val.format = vpiIntVal;
vpi_get_value(start_item, &val);
*start_addr = val.value.integer;
if (! stop_item) {
*stop_addr = left_addr<right_addr ? right_addr : left_addr;
*addr_incr = 1;
} else {
val.format = vpiIntVal;
vpi_get_value(stop_item, &val);
*stop_addr = val.value.integer;
*addr_incr = *start_addr<*stop_addr ? 1 : -1;
}
}
/* Find the minimum and maximum address. */
*min_addr = *start_addr<*stop_addr ? *start_addr : *stop_addr ;
*max_addr = *start_addr<*stop_addr ? *stop_addr : *start_addr;
/* If the range is not fully specified and the left address is
* greater than the right address. Print a warning that this
* code follows 1364-2005.
*
* If we passed a generation flag we could do the correct thing
* for 1364-1995 and 1364-2001 instead of this general warning
* or we could only show the warning when using 2001/1995.
*/
if (!stop_item && (left_addr > right_addr)) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s: Standard inconsistency, following 1364-2005.\n",
name);
}
/* Check that start_addr and stop_addr are within the memory
range */
if (left_addr < right_addr) {
if (*start_addr < left_addr || *start_addr > right_addr) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s: Start address %d is out of bounds for memory "
"\'%s[%d:%d]\'!\n", name, *start_addr,
vpi_get_str(vpiFullName, mitem),
left_addr, right_addr);
return 1;
}
if (*stop_addr < left_addr || *stop_addr > right_addr) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s: Finish address %d is out of bounds for memory "
"\'%s[%d:%d]\'!\n", name, *stop_addr,
vpi_get_str(vpiFullName, mitem),
left_addr, right_addr);
return 1;
}
} else {
if (*start_addr < right_addr || *start_addr > left_addr) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s: Start address %d is out of bounds for memory "
"\'%s[%d:%d]\'!\n", name, *start_addr,
vpi_get_str(vpiFullName, mitem),
left_addr, right_addr);
return 1;
}
if (*stop_addr < right_addr || *stop_addr > left_addr) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s: Finish address %d is out of bounds for memory "
"\'%s[%d:%d]\'!\n", name, *stop_addr,
vpi_get_str(vpiFullName, mitem),
left_addr, right_addr);
return 1;
}
}
return 0;
}
static PLI_INT32 sys_mem_compiletf(PLI_BYTE8*name)
{
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle arg;
/* Check that there is 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 two arguments.\n", name);
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 first argument must be a file name (string).\n",
name);
vpi_control(vpiFinish, 1);
}
/* Check that there is a memory argument. */
arg = vpi_scan(argv);
if (! arg) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s requires a second (memory) argument.\n", name);
vpi_control(vpiFinish, 1);
return 0;
}
if (vpi_get(vpiType, arg) != vpiMemory) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's second argument must be a memory.\n", name);
vpi_control(vpiFinish, 1);
}
/* Check if there is a starting address argument. */
arg = vpi_scan(argv);
if (! arg) return 0;
if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's third argument must be a start address "
"(numeric).\n", name);
vpi_control(vpiFinish, 1);
}
/* Check if there is a finish address argument. */
arg = vpi_scan(argv);
if (! arg) return 0;
if (! is_numeric_obj(arg)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's fourth argument must be a finish address "
"(numeric).\n", name);
vpi_control(vpiFinish, 1);
}
/* Make sure there are no extra arguments. */
if (vpi_scan(argv) != 0) {
char msg [64];
unsigned argc;
snprintf(msg, 64, "ERROR: %s:%d:",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
argc = 1;
while (vpi_scan(argv)) argc += 1;
vpi_printf("%s %s takes at most four arguments.\n",
msg, name);
vpi_printf("%*s Found %u extra argument%s.\n",
(int) strlen(msg), " ", argc, argc == 1 ? "" : "s");
vpi_control(vpiFinish, 1);
}
return 0;
}
static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name) static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
{ {
int code; int code, wwid, addr;
int wwid;
char*path;
char*mem_name;
FILE*file; FILE*file;
unsigned addr; char *fname = 0;
s_vpi_value value; s_vpi_value value;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle item = vpi_scan(argv); vpiHandle mitem = 0;
vpiHandle mitem; vpiHandle start_item = 0;
vpiHandle start_item; vpiHandle stop_item = 0;
vpiHandle stop_item;
vpiHandle left_range;
vpiHandle right_range;
vpiHandle word_index;
/* These are left and right hand side parameters in the
declaration of the memory. */
int left_addr, right_addr;
/* start_addr and stop_addr are the parameters given to $readmem in the /* start_addr and stop_addr are the parameters given to $readmem in the
Verilog code. When not specified, start_addr is equal to the lower of Verilog code. When not specified, start_addr is equal to the lower of
@ -128,159 +290,37 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
/* min_addr and max_addr are equal to start_addr and stop_addr if /* min_addr and max_addr are equal to start_addr and stop_addr if
start_addr<stop_addr or vice versa if not... */ start_addr<stop_addr or vice versa if not... */
unsigned min_addr, max_addr; int min_addr, max_addr;
/* This is the number of words that we need from the memory. */ /* This is the number of words that we need from the memory. */
unsigned word_count; unsigned word_count;
/*======================================== Get parameters */ /*======================================== Get parameters */
if (item == 0) { get_mem_params(argv, callh, name,
vpi_printf("%s: file name parameter missing.\n", name); &fname, &mitem, &start_item, &stop_item);
return 0; if (fname == 0) return 0;
}
/* Check then get the first argument, the file name. It is
possible that Verilog would right-justify a name to fit a
reg value to fit the reg width, so chop off leading white
space in the process. */
if (check_file_name(name, item) == 0) {
vpi_free_object(argv);
return 0;
}
value.format = vpiStringVal;
vpi_get_value(item, &value);
path = strdup(value.value.str + strspn(value.value.str, " "));
/* Get and check the second parameter. It must be a memory. */
mitem = vpi_scan(argv);
if (mitem == 0) {
vpi_printf("%s: Missing memory parameter\n", name);
free(path);
return 0;
}
if (vpi_get(vpiType, mitem) != vpiMemory) {
vpi_printf("%s: Second parameter must be a memory.\n", name);
free(path);
vpi_free_object(argv);
return 0;
}
mem_name = vpi_get_str(vpiFullName, mitem);
/* Get optional third parameter. It must be a constant. */
start_item = vpi_scan(argv);
if (start_item!=0){
if (check_integer_constant(name, start_item) == 0){
vpi_free_object(argv);
return 0;
}
/* Get optional forth parameter. It must be a constant. */
stop_item = vpi_scan(argv);
if (stop_item!=0){
if (check_integer_constant(name, stop_item) == 0){
vpi_free_object(argv);
return 0;
}
/* Check that there is no 5th parameter */
if (vpi_scan(argv) != 0){
vpi_printf("ERROR: %s accepts maximum 4 parameters!\n", name );
vpi_free_object(argv);
return 0;
}
}
}
else{
stop_item = 0;
}
/*======================================== Process parameters */ /*======================================== Process parameters */
if (process_params(mitem, start_item, stop_item, callh, name,
&start_addr, &stop_addr, &addr_incr,
&min_addr, &max_addr)) return 0;
/* Open the data file. */ /* Open the data file. */
file = fopen(path, "r"); file = fopen(fname, "r");
if (file == 0) { if (file == 0) {
vpi_printf("%s: Unable to open %s for reading.\n", name, path); vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
free(path); (int)vpi_get(vpiLineNo, callh));
vpi_printf("%s: Unable to open %s for reading.\n", name, fname);
free(fname);
return 0; return 0;
} }
/* Get left addr of memory */
left_range = vpi_handle(vpiLeftRange, mitem);
value.format = vpiIntVal;
vpi_get_value(left_range, &value);
left_addr = value.value.integer;
/* Get right addr of memory */
right_range = vpi_handle(vpiRightRange, mitem);
value.format = vpiIntVal;
vpi_get_value(right_range, &value);
right_addr = value.value.integer;
/* Get start_addr, stop_addr and addr_incr */
if (start_item==0){
start_addr = left_addr<right_addr ? left_addr : right_addr;
stop_addr = left_addr<right_addr ? right_addr : left_addr;
addr_incr = 1;
}
else{
s_vpi_value value2;
value2.format = vpiIntVal;
vpi_get_value(start_item, &value2);
start_addr = value2.value.integer;
if (stop_item==0){
stop_addr = left_addr<right_addr ? right_addr : left_addr;
addr_incr = 1;
}
else{
s_vpi_value value3;
value3.format = vpiIntVal;
vpi_get_value(stop_item, &value3);
stop_addr = value3.value.integer;
addr_incr = start_addr<stop_addr ? 1 : -1;
}
}
min_addr = start_addr<stop_addr ? start_addr : stop_addr ;
max_addr = start_addr<stop_addr ? stop_addr : start_addr;
/* We need this many words from the file. */ /* We need this many words from the file. */
word_count = max_addr-min_addr+1; word_count = max_addr-min_addr+1;
/* Check that start_addr and stop_addr are within the memory wwid = vpi_get(vpiSize, vpi_handle_by_index(mitem, min_addr));
range */
if (left_addr<right_addr){
if (start_addr<left_addr || start_addr > right_addr) {
vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name, mem_name);
return 0;
}
if (stop_addr<left_addr || stop_addr > right_addr) {
vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name, mem_name);
return 0;
}
}
else{
if (start_addr<right_addr || start_addr > left_addr) {
vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name, mem_name);
return 0;
}
if (stop_addr<right_addr || stop_addr > left_addr) {
vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name, mem_name);
return 0;
}
}
item = vpi_handle_by_index(mitem,min_addr);
wwid = vpi_get(vpiSize, item);
/* variable that will be uses by the lexer to pass values /* variable that will be uses by the lexer to pass values
back to this code */ back to this code */
@ -293,7 +333,6 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
else else
sys_readmem_start_file(file, 0, wwid, value.value.vector); sys_readmem_start_file(file, 0, wwid, value.value.vector);
/*======================================== Read memory file */ /*======================================== Read memory file */
/* Run through the input file and store the new contents in the memory */ /* Run through the input file and store the new contents in the memory */
@ -302,44 +341,67 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
switch (code) { switch (code) {
case MEM_ADDRESS: case MEM_ADDRESS:
addr = value.value.vector->aval; addr = value.value.vector->aval;
if (addr < min_addr || addr > max_addr) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s(%s): address (0x%x) is out of range "
"[0x%x:0x%x]\n",
name, fname, addr, start_addr, stop_addr);
goto bailout;
}
/* if there is an address in the memory file, then /* if there is an address in the memory file, then
turn off any possible warnings about not having turn off any possible warnings about not having
enough words to load the memory. This is standard enough words to load the memory. This is standard
behavior. */ behavior from 1364-2005. */
word_count = 0; word_count = 0;
break; break;
case MEM_WORD: case MEM_WORD:
if (addr >= min_addr && addr <= max_addr){ if (addr >= min_addr && addr <= max_addr) {
vpiHandle word_index;
word_index = vpi_handle_by_index(mitem, addr); word_index = vpi_handle_by_index(mitem, addr);
assert(word_index); assert(word_index);
vpi_put_value(word_index, &value, 0, vpiNoDelay); vpi_put_value(word_index, &value, 0, vpiNoDelay);
if (word_count > 0) if (word_count > 0) word_count -= 1;
word_count -= 1; } else {
} vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
else{ (int)vpi_get(vpiLineNo, callh));
vpi_printf("%s(%s): address (0x%x) out of range (0x%x:0x%x)\n", vpi_printf("%s(%s): Too many words in the file for the "
name, path, addr, start_addr, stop_addr); "requested range [%d:%d].\n",
name, fname, start_addr, stop_addr);
goto bailout; goto bailout;
} }
addr += addr_incr; addr += addr_incr;
break; break;
case MEM_ERROR:
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s(%s): Invalid input character: %s\n", name,
fname, readmem_error_token);
goto bailout;
break;
default: default:
vpi_printf("Huh?! (%d)\n", code); assert(0);
break; break;
} }
} }
if (word_count > 0) /* Print a warning if there are not enough words in the data file. */
vpi_printf("%s(%s): Not enough words in the read file " if (word_count > 0) {
"for requested range.\n", name, path); vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s(%s): Not enough words in the file for the "
"requested range [%d:%d].\n", name, fname,
start_addr, stop_addr);
}
bailout: bailout:
free(value.value.vector); free(value.value.vector);
free(path); free(fname);
fclose(file); fclose(file);
destroy_readmem_lexor(file); destroy_readmem_lexor(file);
return 0; return 0;
@ -347,197 +409,53 @@ static PLI_INT32 sys_readmem_calltf(PLI_BYTE8*name)
static PLI_INT32 sys_writemem_calltf(PLI_BYTE8*name) static PLI_INT32 sys_writemem_calltf(PLI_BYTE8*name)
{ {
int wwid; int addr;
char*path;
char*mem_name;
FILE*file; FILE*file;
unsigned addr = 0; char*fname = 0;
unsigned cnt = 0; unsigned cnt;
s_vpi_value value; s_vpi_value value;
vpiHandle words; vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle sys = vpi_handle(vpiSysTfCall, 0); vpiHandle argv = vpi_iterate(vpiArgument, callh);
vpiHandle argv = vpi_iterate(vpiArgument, sys); vpiHandle mitem = 0;
vpiHandle item = vpi_scan(argv); vpiHandle start_item = 0;
vpiHandle mitem; vpiHandle stop_item = 0;
vpiHandle start_item;
vpiHandle stop_item;
vpiHandle word_index;
vpiHandle left_range;
vpiHandle right_range;
int left_addr, right_addr;
int start_addr, stop_addr, addr_incr; int start_addr, stop_addr, addr_incr;
int min_addr, max_addr; int min_addr, max_addr; // Not used in this routine.
/*======================================== Get parameters */ /*======================================== Get parameters */
if (item == 0) { get_mem_params(argv, callh, name,
vpi_printf("%s: file name parameter missing.\n", name); &fname, &mitem, &start_item, &stop_item);
return 0;
}
if (vpi_get(vpiType, item) != vpiConstant) { if (fname == 0) return 0;
vpi_printf("ERROR: %s parameter must be a constant\n", name);
vpi_free_object(argv);
return 0;
}
if (vpi_get(vpiConstType, item) != vpiStringConst) {
vpi_printf("ERROR: %s parameter must be a string\n", name);
vpi_free_object(argv);
return 0;
}
value.format = vpiStringVal;
vpi_get_value(item, &value);
path = strdup(value.value.str);
/* Get and check the second parameter. It must be a memory. */
mitem = vpi_scan(argv);
if (mitem == 0) {
vpi_printf("%s: Missing memory parameter\n", name);
free(path);
return 0;
}
if (vpi_get(vpiType, mitem) != vpiMemory) {
vpi_printf("%s: Second parameter must be a memory.\n", name);
free(path);
vpi_free_object(argv);
return 0;
}
mem_name = vpi_get_str(vpiFullName, mitem);
/* Get optional third parameter. It must be a constant. */
start_item = vpi_scan(argv);
if (start_item!=0){
if (check_integer_constant(name, start_item) == 0){
free(path);
vpi_free_object(argv);
return 0;
}
/* Get optional forth parameter. It must be a constant. */
stop_item = vpi_scan(argv);
if (stop_item!=0){
if (check_integer_constant(name, stop_item) == 0){
free(path);
vpi_free_object(argv);
return 0;
}
/* Check that there is no 5th parameter */
if (vpi_scan(argv) != 0){
vpi_printf("ERROR: %s accepts maximum 4 parameters!\n", name );
free(path);
vpi_free_object(argv);
return 0;
}
}
}
else{
stop_item = 0;
}
/*======================================== Process parameters */ /*======================================== Process parameters */
if (process_params(mitem, start_item, stop_item, callh, name,
&start_addr, &stop_addr, &addr_incr,
&min_addr, &max_addr)) return 0;
/* Open the data file. */ /* Open the data file. */
file = fopen(path, "w"); file = fopen(fname, "w");
if (file == 0) { if (file == 0) {
vpi_printf("%s: Unable to open %s for writing.\n", name, path); vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
free(path); (int)vpi_get(vpiLineNo, callh));
vpi_printf("%s: Unable to open %s for writing.\n", name, fname);
free(fname);
return 0; return 0;
} }
/* Get left addr of memory */ if (strcmp(name,"$writememb")==0) value.format = vpiBinStrVal;
left_range = vpi_handle(vpiLeftRange, mitem); else value.format = vpiHexStrVal;
value.format = vpiIntVal;
vpi_get_value(left_range, &value);
left_addr = value.value.integer;
/* Get right addr of memory */
right_range = vpi_handle(vpiRightRange, mitem);
value.format = vpiIntVal;
vpi_get_value(right_range, &value);
right_addr = value.value.integer;
/* Get start_addr, stop_addr and addr_incr */
if (start_item==0){
start_addr = left_addr<right_addr ? left_addr : right_addr;
stop_addr = left_addr<right_addr ? right_addr : left_addr;
addr_incr = 1;
}
else{
s_vpi_value value2;
value2.format = vpiIntVal;
vpi_get_value(start_item, &value2);
start_addr = value2.value.integer;
if (stop_item==0){
stop_addr = left_addr<right_addr ? right_addr : left_addr;
addr_incr = 1;
}
else{
s_vpi_value value3;
value3.format = vpiIntVal;
vpi_get_value(stop_item, &value3);
stop_addr = value3.value.integer;
addr_incr = start_addr<stop_addr ? 1 : -1;
}
}
min_addr = start_addr<stop_addr ? start_addr : stop_addr ;
max_addr = start_addr<stop_addr ? stop_addr : start_addr;
/* Check that start_addr and stop_addr are within the memory
range */
if (left_addr<right_addr){
if (start_addr<left_addr || start_addr > right_addr) {
vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name, mem_name);
return 0;
}
if (stop_addr<left_addr || stop_addr > right_addr) {
vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name, mem_name);
return 0;
}
}
else{
if (start_addr<right_addr || start_addr > left_addr) {
vpi_printf("%s: Start address is out of bounds for memory \'%s\'!\n", name, mem_name);
return 0;
}
if (stop_addr<right_addr || stop_addr > left_addr) {
vpi_printf("%s: Stop address is out of bounds for memory \'%s\'!\n", name, mem_name);
return 0;
}
}
words = vpi_iterate(vpiMemoryWord, mitem);
assert(words);
item = vpi_scan(words);
wwid = vpi_get(vpiSize, item);
vpi_free_object(words);
if (strcmp(name,"$writememb")==0){
value.format = vpiBinStrVal;
}
else{
value.format = vpiHexStrVal;
}
/*======================================== Write memory file */ /*======================================== Write memory file */
cnt=0; cnt = 0;
for(addr=start_addr; addr!=stop_addr+addr_incr; addr+=addr_incr, ++cnt){ for(addr=start_addr; addr!=stop_addr+addr_incr; addr+=addr_incr, ++cnt) {
if (cnt%16 == 0) vpiHandle word_index;
fprintf(file, "// 0x%08x\n", cnt);
if (cnt%16 == 0) fprintf(file, "// 0x%08x\n", cnt);
word_index = vpi_handle_by_index(mitem, addr); word_index = vpi_handle_by_index(mitem, addr);
assert(word_index); assert(word_index);
@ -546,7 +464,7 @@ static PLI_INT32 sys_writemem_calltf(PLI_BYTE8*name)
} }
fclose(file); fclose(file);
free(path); free(fname);
return 0; return 0;
} }
@ -557,7 +475,7 @@ void sys_readmem_register()
tf_data.type = vpiSysTask; tf_data.type = vpiSysTask;
tf_data.tfname = "$readmemh"; tf_data.tfname = "$readmemh";
tf_data.calltf = sys_readmem_calltf; tf_data.calltf = sys_readmem_calltf;
tf_data.compiletf = 0; tf_data.compiletf = sys_mem_compiletf;
tf_data.sizetf = 0; tf_data.sizetf = 0;
tf_data.user_data = "$readmemh"; tf_data.user_data = "$readmemh";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
@ -565,7 +483,7 @@ void sys_readmem_register()
tf_data.type = vpiSysTask; tf_data.type = vpiSysTask;
tf_data.tfname = "$readmemb"; tf_data.tfname = "$readmemb";
tf_data.calltf = sys_readmem_calltf; tf_data.calltf = sys_readmem_calltf;
tf_data.compiletf = 0; tf_data.compiletf = sys_mem_compiletf;
tf_data.sizetf = 0; tf_data.sizetf = 0;
tf_data.user_data = "$readmemb"; tf_data.user_data = "$readmemb";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
@ -573,7 +491,7 @@ void sys_readmem_register()
tf_data.type = vpiSysTask; tf_data.type = vpiSysTask;
tf_data.tfname = "$writememh"; tf_data.tfname = "$writememh";
tf_data.calltf = sys_writemem_calltf; tf_data.calltf = sys_writemem_calltf;
tf_data.compiletf = 0; tf_data.compiletf = sys_mem_compiletf;
tf_data.sizetf = 0; tf_data.sizetf = 0;
tf_data.user_data = "$writememh"; tf_data.user_data = "$writememh";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);
@ -581,7 +499,7 @@ void sys_readmem_register()
tf_data.type = vpiSysTask; tf_data.type = vpiSysTask;
tf_data.tfname = "$writememb"; tf_data.tfname = "$writememb";
tf_data.calltf = sys_writemem_calltf; tf_data.calltf = sys_writemem_calltf;
tf_data.compiletf = 0; tf_data.compiletf = sys_mem_compiletf;
tf_data.sizetf = 0; tf_data.sizetf = 0;
tf_data.user_data = "$writememb"; tf_data.user_data = "$writememb";
vpi_register_systf(&tf_data); vpi_register_systf(&tf_data);

View File

@ -24,6 +24,9 @@
# define MEM_ADDRESS 257 # define MEM_ADDRESS 257
# define MEM_WORD 258 # define MEM_WORD 258
# define MEM_ERROR 259
extern char *readmem_error_token;
extern void sys_readmem_start_file(FILE*in, int bin_flag, extern void sys_readmem_start_file(FILE*in, int bin_flag,
unsigned width, struct t_vpi_vecval*val); unsigned width, struct t_vpi_vecval*val);

View File

@ -30,6 +30,8 @@ static void make_bin_value();
static int save_state; static int save_state;
char *readmem_error_token = 0;
%} %}
%x BIN %x BIN
@ -51,6 +53,9 @@ static int save_state;
<CCOMMENT>"*" { ; } <CCOMMENT>"*" { ; }
<CCOMMENT>"*"+"/" { BEGIN(save_state); } <CCOMMENT>"*"+"/" { BEGIN(save_state); }
/* Catch any invalid tokens and flagged them as an error. */
<HEX,BIN>. { readmem_error_token = yytext; return MEM_ERROR; }
%% %%
static unsigned word_width = 0; static unsigned word_width = 0;
static struct t_vpi_vecval*vecval = 0; static struct t_vpi_vecval*vecval = 0;

View File

@ -286,34 +286,19 @@ static PLI_INT32 sys_sdf_annotate_compiletf(PLI_BYTE8*name)
static PLI_INT32 sys_sdf_annotate_calltf(PLI_BYTE8*name) static PLI_INT32 sys_sdf_annotate_calltf(PLI_BYTE8*name)
{ {
s_vpi_value value;
vpiHandle callh = vpi_handle(vpiSysTfCall,0); vpiHandle callh = vpi_handle(vpiSysTfCall,0);
vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle argv = vpi_iterate(vpiArgument, callh);
FILE *sdf_fd;
char *fname = get_filename(callh, name, vpi_scan(argv));
/* The first argument is the path to the SDF file. */ if (fname == 0) return 0;
vpiHandle path = vpi_scan(argv);
assert(path);
value.format = vpiStringVal; sdf_fd = fopen(fname, "r");
vpi_get_value(path, &value);
if ((value.format != vpiStringVal) || !*(value.value.str)) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s's file name argument (type=%s)"
" does not have a string value.\n",
name, vpi_get_str(vpiType, path));
vpi_control(vpiFinish, 1);
return 0;
}
char*path_str = strdup(value.value.str);
FILE*sdf_fd = fopen(path_str, "r");
if (sdf_fd == 0) { if (sdf_fd == 0) {
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh)); (int)vpi_get(vpiLineNo, callh));
vpi_printf("Unable to open SDF file \"%s\"." vpi_printf("Unable to open SDF file \"%s\"."
" Skipping this annotation.\n", path_str); " Skipping this annotation.\n", fname);
return 0; return 0;
} }
@ -324,11 +309,11 @@ static PLI_INT32 sys_sdf_annotate_calltf(PLI_BYTE8*name)
sdf_cur_cell = 0; sdf_cur_cell = 0;
sdf_callh = callh; sdf_callh = callh;
sdf_process_file(sdf_fd, path_str); sdf_process_file(sdf_fd, fname);
sdf_callh = 0; sdf_callh = 0;
fclose(sdf_fd); fclose(sdf_fd);
free(path_str); free(fname);
return 0; return 0;
} }

View File

@ -404,7 +404,8 @@ static void open_dumpfile(vpiHandle callh)
unsigned udx = 0; unsigned udx = 0;
time_t walltime; time_t walltime;
vpi_printf("VCD info: dumpfile %s opened for output.\n", dump_path); vpi_printf("VCD info: dumpfile %s opened for output.\n",
dump_path);
time(&walltime); time(&walltime);
@ -434,32 +435,33 @@ static PLI_INT32 sys_dumpfile_calltf(PLI_BYTE8*name)
{ {
vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle argv = vpi_iterate(vpiArgument, callh);
s_vpi_value value; char *path;
char*path;
/* $dumpfile must be called before $dumpvars starts! */ /* $dumpfile must be called before $dumpvars starts! */
if (dumpvars_status != 0) { if (dumpvars_status != 0) {
vpi_printf("VCD warning: %s called after $dumpvars started,\n" char msg [64];
" using existing file (%s).\n", snprintf(msg, 64, "VCD warning: %s:%d:",
name, dump_path); vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s %s called after $dumpvars started,\n", msg, name);
vpi_printf("%*s using existing file (%s).\n",
(int) strlen(msg), " ", dump_path);
vpi_free_object(argv); vpi_free_object(argv);
return 0; return 0;
} }
assert(argv); path = get_filename(callh, name, vpi_scan(argv));
value.format = vpiStringVal; vpi_free_object(argv);
vpi_get_value(vpi_scan(argv), &value); if (! path) return 0;
path = strdup(value.value.str);
if (dump_path) { if (dump_path) {
vpi_printf("VCD warning: Overriding dump file %s with %s\n", vpi_printf("VCD warning: %s:%d: ", vpi_get_str(vpiFile, callh),
dump_path, path); (int)vpi_get(vpiLineNo, callh));
vpi_printf("Overriding dump file %s with %s.\n", dump_path, path);
free(dump_path); free(dump_path);
} }
dump_path = path; dump_path = path;
vpi_free_object(argv);
return 0; return 0;
} }