Add support for tracing procedural statements.

This patch adds support for tracing procedural statement execution in vvp.
This is accomplished by adding a new opcode that is inserted before the
code that represents a procedural statement. These opcodes also trigger
a message whenever time advances. By default these opcodes are not added.
To add them, pass the -pfileline=1 flag to the compiler. In the future we
may add support for turning the debug output on and off once the opcodes
have been added with a system task or from the interactive prompt.
This commit is contained in:
Cary R 2011-02-27 19:20:16 -08:00 committed by Stephen Williams
parent 312b4da46f
commit 06447817d3
20 changed files with 614 additions and 61 deletions

View File

@ -1,4 +1,4 @@
.TH iverilog 1 "January 8th, 2011" "" "Version %M.%m.%n %E"
.TH iverilog 1 "February 27th, 2011" "" "Version %M.%m.%n %E"
.SH NAME
iverilog - Icarus Verilog compiler
@ -258,7 +258,9 @@ checking the syntax of the Verilog source.
.B vvp
This is the default. The vvp target generates code for the vvp
runtime. The output is a complete program that simulates the design
but must be run by the \fBvvp\fP command.
but must be run by the \fBvvp\fP command. The -pfileline=1 option
can be used to add procedural statement debugging opcodes to the
generated code.
.TP 8
.B fpga
This is a synthesis target that supports a variety of fpga devices,

View File

@ -2192,6 +2192,7 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
return 0;
}
st = event_->elaborate(des, scope);
st->set_line(*this);
if (st == 0) {
cerr << event_->get_fileline() << ": error: "
"unable to elaborate event expression."
@ -2217,12 +2218,15 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
// We need a repeat statement.
} else {
st = new NetRepeat(count, st);
st->set_line(*this);
}
} else {
st = new NetRepeat(count, st);
st->set_line(*this);
}
} else {
st = event_->elaborate_st(des, scope, a2);
st->set_line(*this);
if (st == 0) {
cerr << event_->get_fileline() << ": error: "
"unable to elaborate event expression."
@ -3852,7 +3856,9 @@ NetProc* PTrigger::elaborate(Design*des, NetScope*scope) const
NetProc* PWhile::elaborate(Design*des, NetScope*scope) const
{
NetExpr*tmp = elab_and_eval(des, scope, cond_, -1);
tmp->set_line(*this);
NetWhile*loop = new NetWhile(tmp, statement_->elaborate(des, scope));
loop->set_line(*this);
return loop;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2005-2011 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
@ -51,7 +51,7 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t expr)
/* ports cannot be arrays. */
assert(ivl_signal_dimensions(port) == 0);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res);
fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", port, res);
clr_word(res);
}
@ -180,9 +180,9 @@ int draw_ufunc_real(ivl_expr_t expr)
/* Call the function */
fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def)));
fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def)));
fprintf(vvp_out, ", S_%p;\n", def);
fprintf(vvp_out, " %%join;\n");
fprintf(vvp_out, " %%join;\n");
/* Return value signal cannot be an array. */
assert(ivl_signal_dimensions(retval) == 0);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2005-2011 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
@ -54,7 +54,8 @@ static int eval_bool64_logic(ivl_expr_t expr)
if (ivl_expr_signed(expr))
s_flag = "/s";
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", s_flag, res, tmp.base, tmp.wid);
fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n", s_flag, res,
tmp.base, tmp.wid);
clr_vector(tmp);
return res;
@ -75,7 +76,7 @@ static int draw_number_bool64(ivl_expr_t expr)
res = allocate_word();
low = val % UINT64_C(0x100000000);
hig = val / UINT64_C(0x100000000);
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n", res, low, hig);
fprintf(vvp_out, " %%ix/load %d, %lu, %lu;\n", res, low, hig);
return res;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -750,7 +750,7 @@ static struct vector_info draw_binary_expr_lor(ivl_expr_t expr, unsigned wid,
if (wid == 1) {
if (lv.base >= 4 && lv.base < 8) {
unsigned tmp = allocate_vector(1);
fprintf(vvp_out, " %%mov %u, %u, 1;\n", tmp, lv.base);
fprintf(vvp_out, " %%mov %u, %u, 1;\n", tmp, lv.base);
lv.base = tmp;
}
return lv;
@ -932,7 +932,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
long imm = get_number_immediate(le);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
rv.base, imm, rv.wid);
} else {
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
@ -948,7 +948,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
long imm = get_number_immediate(re);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
lv.base, imm, lv.wid);
} else {
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
@ -964,7 +964,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
long imm = get_number_immediate(re);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
lv.base, imm, lv.wid);
} else {
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
@ -979,7 +979,7 @@ static struct vector_info draw_binary_expr_le(ivl_expr_t expr,
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
long imm = get_number_immediate(le);
assert(imm >= 0);
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
fprintf(vvp_out, " %%cmpi/%c %u, %ld, %u;\n", s_flag,
rv.base, imm, rv.wid);
} else {
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
@ -1039,7 +1039,7 @@ static struct vector_info draw_logic_immediate(ivl_expr_t expr,
switch (ivl_expr_opcode(expr)) {
case '&':
fprintf(vvp_out, " %%andi %u, %lu, %u;\n", lv.base, imm, lv.wid);
fprintf(vvp_out, " %%andi %u, %lu, %u;\n", lv.base, imm, lv.wid);
break;
default:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -22,12 +22,13 @@
# include "vvp_priv.h"
# include <string.h>
# include <assert.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
static const char*version_string =
"Icarus Verilog VVP Code Generator " VERSION " (" VERSION_TAG ")\n\n"
"Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)\n\n"
"Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)\n\n"
" This program is free software; you can redistribute it and/or modify\n"
" it under the terms of the GNU General Public License as published by\n"
" the Free Software Foundation; either version 2 of the License, or\n"
@ -45,6 +46,7 @@ static const char*version_string =
FILE*vvp_out = 0;
int vvp_errors = 0;
unsigned show_file_line = 0;
__inline__ static void draw_execute_header(ivl_design_t des)
{
@ -95,8 +97,39 @@ int target_design(ivl_design_t des)
unsigned size;
unsigned idx;
const char*path = ivl_design_flag(des, "-o");
/* Use -pfileline to determine if file and line information is
* printed for procedural statements. (e.g. -pfileline=1).
* The default is no file/line information will be included. */
const char*fileline = ivl_design_flag(des, "fileline");
assert(path);
/* Check to see if file/line information should be included. */
if (strcmp(fileline, "") != 0) {
char *eptr;
long fl_value = strtol(fileline, &eptr, 0);
/* Nothing usable in the file/line string. */
if (fileline == eptr) {
fprintf(stderr, "vvp error: Unable to extract file/line "
"information from string: %s\n", fileline);
return 1;
}
/* Extra stuff at the end. */
if (*eptr != 0) {
fprintf(stderr, "vvp error: Extra characters '%s' "
"included at end of file/line string: %s\n",
eptr, fileline);
return 1;
}
/* The file/line flag must be positive. */
if (fl_value < 0) {
fprintf(stderr, "vvp error: File/line flag (%ld) must "
"be positive.\n", fl_value);
return 1;
}
show_file_line = fl_value > 0;
}
#ifdef HAVE_FOPEN64
vvp_out = fopen64(path, "w");
#else

View File

@ -1,7 +1,7 @@
#ifndef __vvp_priv_H
#define __vvp_priv_H
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -39,6 +39,12 @@ extern FILE* vvp_out;
*/
extern int vvp_errors;
/*
* Set to non-zero when the user wants to display file and line number
* information for procedural statements.
*/
extern unsigned show_file_line;
struct vector_info {
unsigned base;
unsigned wid;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -111,13 +111,13 @@ static void set_to_lvariable(ivl_lval_t lval,
unsigned skip_set = transient_id++;
if (word_ix) {
draw_eval_expr_into_integer(word_ix, 3);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
} else {
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
}
draw_eval_expr_into_integer(part_off_ex, 1);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set);
@ -128,12 +128,12 @@ static void set_to_lvariable(ivl_lval_t lval,
unsigned skip_set = transient_id++;
if (word_ix) {
draw_eval_expr_into_integer(word_ix, 3);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
} else {
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
}
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid);
if (word_ix) /* Only need this label if word_ix is set. */
fprintf(vvp_out, "t_%u ;\n", skip_set);
@ -155,9 +155,9 @@ static void set_to_lvariable(ivl_lval_t lval,
unsigned skip_set = transient_id++;
unsigned index_reg = 3;
draw_eval_expr_into_integer(word_ix, index_reg);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set);
}
@ -171,9 +171,10 @@ static void set_to_lvariable(ivl_lval_t lval,
directly to the word and save the index calculation. */
if (word_ix == 0) {
if (use_word < ivl_signal_array_count(sig)) {
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
use_word);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid);
} else {
fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u "
@ -184,9 +185,9 @@ static void set_to_lvariable(ivl_lval_t lval,
unsigned skip_set = transient_id++;
unsigned index_reg = 3;
draw_eval_expr_into_integer(word_ix, index_reg);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set);
}
@ -535,6 +536,24 @@ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res)
}
}
/*
* Routine to insert statement tracing information into the output stream
* when requested by the user (compiler).
*/
static void show_stmt_file_line(ivl_statement_t net, const char* desc)
{
if (show_file_line) {
/* If the line number is not zero then the file should also
* be set. It's safe to skip the assert during debug, but
* the assert represents missing file/line information that
* should be reported/fixed. */
unsigned lineno = ivl_stmt_lineno(net);
assert(lineno);
fprintf(vvp_out, " %%file_line %d %d \"%s\";\n",
ivl_file_table_index(ivl_stmt_file(net)), lineno, desc);
}
}
static int show_stmt_alloc(ivl_statement_t net)
{
ivl_scope_t scope = ivl_stmt_call(net);
@ -637,6 +656,8 @@ static int show_stmt_assign(ivl_statement_t net)
ivl_lval_t lval;
ivl_signal_t sig;
show_stmt_file_line(net, "Blocking assignment.");
lval = ivl_stmt_lval(net, 0);
sig = ivl_lval_sig(lval);
@ -739,6 +760,8 @@ static int show_stmt_assign_nb(ivl_statement_t net)
ivl_signal_t sig;
unsigned nevents = ivl_stmt_nevent(net);
show_stmt_file_line(net, "Nonblocking assignment.");
/* If we have an event control build the control structure. */
if (nevents) {
assert(del == 0);
@ -922,6 +945,8 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
unsigned idx, default_case;
show_stmt_file_line(net, "Case statement.");
local_count += count + 1;
/* First draw the branch table. All the non-default cases
@ -1039,8 +1064,9 @@ static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope)
unsigned idx, default_case;
local_count += count + 1;
show_stmt_file_line(net, "Case statement.");
local_count += count + 1;
/* First draw the branch table. All the non-default cases
generate a branch out of here, to the code that implements
@ -1282,6 +1308,8 @@ static int show_stmt_cassign(ivl_statement_t net)
ivl_expr_t rval;
ivl_signal_t sig;
show_stmt_file_line(net, "Assign statement.");
rval = ivl_stmt_rval(net);
assert(rval);
@ -1318,6 +1346,8 @@ static int show_stmt_deassign(ivl_statement_t net)
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
unsigned lidx;
show_stmt_file_line(net, "Deassign statement.");
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
ivl_lval_t lval;
@ -1372,8 +1402,11 @@ static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope)
int rc = 0;
unsigned lab_false, lab_out;
ivl_expr_t expr = ivl_stmt_cond_expr(net);
struct vector_info cond
= draw_eval_expr(expr, STUFF_OK_XZ|STUFF_OK_47|STUFF_OK_RO);
struct vector_info cond;
show_stmt_file_line(net, "If statement.");
cond = draw_eval_expr(expr, STUFF_OK_XZ|STUFF_OK_47|STUFF_OK_RO);
assert(cond.wid == 1);
@ -1426,6 +1459,8 @@ static int show_stmt_delay(ivl_statement_t net, ivl_scope_t sscope)
unsigned long low = delay % UINT64_C(0x100000000);
unsigned long hig = delay / UINT64_C(0x100000000);
show_stmt_file_line(net, "Delay statement.");
fprintf(vvp_out, " %%delay %lu, %lu;\n", low, hig);
/* Lots of things can happen during a delay. */
clear_expression_lookaside();
@ -1447,6 +1482,8 @@ static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
ivl_expr_t expr = ivl_stmt_delay_expr(net);
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
show_stmt_file_line(net, "Delay statement.");
switch (ivl_expr_value(expr)) {
case IVL_VT_BOOL:
@ -1480,8 +1517,10 @@ static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope)
{
int rc = 0;
ivl_scope_t target = ivl_stmt_call(net);
show_stmt_file_line(net, "Disable statement.");
fprintf(vvp_out, " %%disable S_%p;\n", target);
return rc;
@ -1492,6 +1531,8 @@ static int show_stmt_force(ivl_statement_t net)
ivl_expr_t rval;
ivl_signal_t sig;
show_stmt_file_line(net, "Force statement.");
rval = ivl_stmt_rval(net);
assert(rval);
@ -1524,6 +1565,8 @@ static int show_stmt_forever(ivl_statement_t net, ivl_scope_t sscope)
ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
unsigned lab_top = local_count++;
show_stmt_file_line(net, "Forever statement.");
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_top);
rc += show_statement(stmt, sscope);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top);
@ -1614,6 +1657,8 @@ static int show_stmt_release(ivl_statement_t net)
ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
unsigned lidx;
show_stmt_file_line(net, "Release statement.");
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
unsigned type = 0;
ivl_lval_t lval;
@ -1682,9 +1727,13 @@ static int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope)
int rc = 0;
unsigned lab_top = local_count++, lab_out = local_count++;
ivl_expr_t expr = ivl_stmt_cond_expr(net);
struct vector_info cnt = draw_eval_expr(expr, 0);
struct vector_info cnt;
const char *sign = ivl_expr_signed(expr) ? "s" : "u";
show_stmt_file_line(net, "Repeat statement.");
cnt = draw_eval_expr(expr, 0);
/* Test that 0 < expr */
fprintf(vvp_out, "T_%u.%u %%cmp/%s 0, %u, %u;\n", thread_count,
lab_top, sign, cnt.base, cnt.wid);
@ -1712,6 +1761,9 @@ static int show_stmt_trigger(ivl_statement_t net)
{
ivl_event_t ev = ivl_stmt_events(net, 0);
assert(ev);
show_stmt_file_line(net, "Event trigger statement.");
fprintf(vvp_out, " %%set/v E_%p, 0,1;\n", ev);
return 0;
}
@ -1720,6 +1772,8 @@ static int show_stmt_utask(ivl_statement_t net)
{
ivl_scope_t task = ivl_stmt_call(net);
show_stmt_file_line(net, "User task call.");
fprintf(vvp_out, " %%fork TD_%s",
vvp_mangle_id(ivl_scope_name(task)));
fprintf(vvp_out, ", S_%p;\n", task);
@ -1730,6 +1784,8 @@ static int show_stmt_utask(ivl_statement_t net)
static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
{
show_stmt_file_line(net, "Event wait (@) statement.");
if (ivl_stmt_nevent(net) == 1) {
ivl_event_t ev = ivl_stmt_events(net, 0);
fprintf(vvp_out, " %%wait E_%p;\n", ev);
@ -1793,6 +1849,8 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
unsigned top_label = local_count++;
unsigned out_label = local_count++;
show_stmt_file_line(net, "While statement.");
/* Start the loop. The top of the loop starts a basic block
because it can be entered from above or from the bottom of
the loop. */
@ -1824,6 +1882,8 @@ static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
static int show_system_task_call(ivl_statement_t net)
{
show_stmt_file_line(net, "System task call.");
draw_vpi_task_call(net);
/* VPI calls can manipulate anything, so clear the expression
@ -1833,6 +1893,361 @@ static int show_system_task_call(ivl_statement_t net)
return 0;
}
/*
* Icarus translated <var> = <delay or event> <value> into
* begin
* <tmp> = <value>;
* <delay or event> <var> = <tmp>;
* end
* This routine looks for this pattern so we only emit one %file_line opcode.
*/
static unsigned is_delayed_or_event_assign(ivl_scope_t scope,
ivl_statement_t stmt)
{
ivl_statement_t assign, delay, delayed_assign;
ivl_statement_type_t delay_type;
ivl_lval_t lval;
ivl_expr_t rval;
ivl_signal_t lsig, rsig;
/* We must have two block elements. */
if (ivl_stmt_block_count(stmt) != 2) return 0;
/* The first must be an assign. */
assign = ivl_stmt_block_stmt(stmt, 0);
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
/* The second must be a delayx. */
delay = ivl_stmt_block_stmt(stmt, 1);
delay_type = ivl_statement_type(delay);
if ((delay_type != IVL_ST_DELAYX) &&
(delay_type != IVL_ST_WAIT)) return 0;
/* The statement for the delayx must be an assign. */
delayed_assign = ivl_stmt_sub_stmt(delay);
if (ivl_statement_type(delayed_assign) != IVL_ST_ASSIGN) return 0;
/* The L-value must be a single signal. */
if (ivl_stmt_lvals(assign) != 1) return 0;
lval = ivl_stmt_lval(assign, 0);
/* It must not have an array select. */
if (ivl_lval_idx(lval)) return 0;
/* It must not have a non-zero base. */
if (ivl_lval_part_off(lval)) return 0;
lsig = ivl_lval_sig(lval);
/* It must not be part of the signal. */
if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0;
/* The R-value must be a single signal. */
rval = ivl_stmt_rval(delayed_assign);
if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return 0;
/* It must not be an array word. */
if (ivl_expr_oper1(rval)) return 0;
rsig = ivl_expr_signal(rval);
/* The two signals must be the same. */
if (lsig != rsig) return 0;
/* And finally the three statements must have the same line number
* as the block. */
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(delay)) ||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(delayed_assign))) {
return 0;
}
/* The pattern matched so this block represents a blocking
* assignment with an inter-assignment delay or event. */
if (delay_type == IVL_ST_DELAYX) {
show_stmt_file_line(stmt, "Blocking assignment (delay).");
} else {
show_stmt_file_line(stmt, "Blocking assignment (event).");
}
return 1;
}
/*
* Icarus translated <var> = repeat(<count>) <event> <value> into
* begin
* <tmp> = <value>;
* repeat(<count>) <event>;
* <var> = <tmp>;
* end
* This routine looks for this pattern so we only emit one %file_line opcode.
*/
static unsigned is_repeat_event_assign(ivl_scope_t scope,
ivl_statement_t stmt)
{
ivl_statement_t assign, event, event_assign, repeat;
ivl_lval_t lval;
ivl_expr_t rval;
ivl_signal_t lsig, rsig;
/* We must have three block elements. */
if (ivl_stmt_block_count(stmt) != 3) return 0;
/* The first must be an assign. */
assign = ivl_stmt_block_stmt(stmt, 0);
if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
/* The second must be a repeat with an event or an event. */
repeat = ivl_stmt_block_stmt(stmt, 1);
if (ivl_statement_type(repeat) != IVL_ST_REPEAT) return 0;
/* The repeat must have an event statement. */
event = ivl_stmt_sub_stmt(repeat);
if (ivl_statement_type(event) != IVL_ST_WAIT) return 0;
/* The third must be an assign. */
event_assign = ivl_stmt_block_stmt(stmt, 2);
if (ivl_statement_type(event_assign) != IVL_ST_ASSIGN) return 0;
/* The L-value must be a single signal. */
if (ivl_stmt_lvals(assign) != 1) return 0;
lval = ivl_stmt_lval(assign, 0);
/* It must not have an array select. */
if (ivl_lval_idx(lval)) return 0;
/* It must not have a non-zero base. */
if (ivl_lval_part_off(lval)) return 0;
lsig = ivl_lval_sig(lval);
/* It must not be part of the signal. */
if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0;
/* The R-value must be a single signal. */
rval = ivl_stmt_rval(event_assign);
if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return 0;
/* It must not be an array word. */
if (ivl_expr_oper1(rval)) return 0;
rsig = ivl_expr_signal(rval);
/* The two signals must be the same. */
if (lsig != rsig) return 0;
/* And finally the four statements must have the same line number
* as the block. */
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(repeat)) ||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(event)) ||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(event_assign))) {
return 0;
}
/* The pattern matched so this block represents a blocking
* assignment with an inter-assignment repeat event. */
show_stmt_file_line(stmt, "Blocking assignment (repeat event).");
return 1;
}
/*
* Icarus translated wait(<expr) <stmt> into
* begin
* while (<expr> !== 1'b1) @(<expr sensitivities>);
* <stmt>
* end
* This routine looks for this pattern and turns it back into a
* wait statement.
*/
static unsigned is_wait(ivl_scope_t scope, ivl_statement_t stmt)
{
ivl_statement_t while_wait, wait, wait_stmt;
ivl_expr_t while_expr, expr;
const char *bits;
/* We must have two block elements. */
if (ivl_stmt_block_count(stmt) != 2) return 0;
/* The first must be a while. */
while_wait = ivl_stmt_block_stmt(stmt, 0);
if (ivl_statement_type(while_wait) != IVL_ST_WHILE) return 0;
/* That has a wait with a NOOP statement. */
wait = ivl_stmt_sub_stmt(while_wait);
if (ivl_statement_type(wait) != IVL_ST_WAIT) return 0;
wait_stmt = ivl_stmt_sub_stmt(wait);
if (ivl_statement_type(wait_stmt) != IVL_ST_NOOP) return 0;
/* Check that the while condition has the correct form. */
while_expr = ivl_stmt_cond_expr(while_wait);
if (ivl_expr_type(while_expr) != IVL_EX_BINARY) return 0;
if (ivl_expr_opcode(while_expr) != 'N') return 0;
/* Has a second operator that is a constant 1'b1. */
expr = ivl_expr_oper2(while_expr);
if (ivl_expr_type(expr) != IVL_EX_NUMBER) return 0;
if (ivl_expr_width(expr) != 1) return 0;
bits = ivl_expr_bits(expr);
if (*bits != '1') return 0;
/* There is no easy way to verify that the @ sensitivity list
* matches the first expression so that is not currently checked. */
/* And finally the two statements that represent the wait must
* have the same line number as the block. */
if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_wait)) ||
(ivl_stmt_lineno(stmt) != ivl_stmt_lineno(wait))) {
return 0;
}
/* The pattern matched so this block represents a wait statement. */
show_stmt_file_line(stmt, "Wait statement.");
return 1;
}
/*
* Check to see if the statement L-value is a port in the given scope.
* If it is return the zero based port number.
*/
static unsigned utask_in_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
{
unsigned idx, ports = ivl_scope_ports(scope);
ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
ivl_signal_t lsig = ivl_lval_sig(lval);
const char *sig_name;
/* The L-value must be a single signal. */
if (ivl_stmt_lvals(stmt) != 1) return ports;
/* It must not have an array select. */
if (ivl_lval_idx(lval)) return ports;
/* It must not have a non-zero base. */
if (ivl_lval_part_off(lval)) return ports;
/* It must not be part of the signal. */
if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return ports;
/* It must have the same scope as the task. */
if (scope != ivl_signal_scope(lsig)) return ports;
/* It must be an input or inout port of the task. */
sig_name = ivl_signal_basename(lsig);
for (idx = 0; idx < ports; idx += 1) {
ivl_signal_t port = ivl_scope_port(scope, idx);
ivl_signal_port_t port_type = ivl_signal_port(port);
if ((port_type != IVL_SIP_INPUT) &&
(port_type != IVL_SIP_INOUT)) continue;
if (strcmp(sig_name, ivl_signal_basename(port)) == 0) break;
}
return idx;
}
/*
* Check to see if the statement R-value is a port in the given scope.
* If it is return the zero based port number.
*/
static unsigned utask_out_port_idx(ivl_scope_t scope, ivl_statement_t stmt)
{
unsigned idx, ports = ivl_scope_ports(scope);
ivl_expr_t rval = ivl_stmt_rval(stmt);
ivl_signal_t rsig = 0;
ivl_expr_type_t expr_type = ivl_expr_type(rval);
const char *sig_name;
/* We can have a simple signal. */
if (expr_type == IVL_EX_SIGNAL) {
rsig = ivl_expr_signal(rval);
/* Or a simple select of a simple signal. */
} else if (expr_type == IVL_EX_SELECT) {
ivl_expr_t expr = ivl_expr_oper1(rval);
/* We must have a zero select base. */
if (ivl_expr_oper2(rval)) return ports;
/* We must be selecting a signal. */
if (ivl_expr_type(expr) != IVL_EX_SIGNAL) return ports;
rsig = ivl_expr_signal(expr);
} else return ports;
/* The R-value must have the same scope as the task. */
if (scope != ivl_signal_scope(rsig)) return ports;
/* It must not be an array element. */
if (ivl_signal_dimensions(rsig)) return ports;
/* It must be an output or inout port of the task. */
sig_name = ivl_signal_basename(rsig);
for (idx = 0; idx < ports; idx += 1) {
ivl_signal_t port = ivl_scope_port(scope, idx);
ivl_signal_port_t port_type = ivl_signal_port(port);
if ((port_type != IVL_SIP_OUTPUT) &&
(port_type != IVL_SIP_INOUT)) continue;
if (strcmp(sig_name, ivl_signal_basename(port)) == 0) break;
}
return idx;
}
/*
* Structure to hold the port information as we extract it from the block.
*/
typedef struct port_expr_s {
ivl_signal_port_t type;
union {
ivl_statement_t lval;
ivl_expr_t rval;
};
} *port_expr_t;
/*
* Icarus encodes a user task call with arguments as:
* begin
* <input 1> = <arg>
* ...
* <input n> = <arg>
* <task_call>
* <arg> = <output 1>
* ...
* <arg> = <output n>
* end
* This routine looks for that pattern and translates it into the
* appropriate task call. It returns true (1) if it successfully
* translated the block to a task call, otherwise it returns false
* (0) to indicate the block needs to be emitted.
*/
static unsigned is_utask_call_with_args(ivl_scope_t scope,
ivl_statement_t stmt)
{
unsigned idx, ports, task_idx = 0;
unsigned count = ivl_stmt_block_count(stmt);
unsigned lineno = ivl_stmt_lineno(stmt);
ivl_scope_t task_scope = 0;
port_expr_t port_exprs;
/* Check to see if the block is of the basic form first. */
for (idx = 0; idx < count; idx += 1) {
ivl_statement_t tmp = ivl_stmt_block_stmt(stmt, idx);
if (ivl_statement_type(tmp) == IVL_ST_ASSIGN) continue;
if (ivl_statement_type(tmp) == IVL_ST_UTASK && !task_scope) {
task_idx = idx;
task_scope = ivl_stmt_call(tmp);
assert(ivl_scope_type(task_scope) == IVL_SCT_TASK);
continue;
}
return 0;
}
/* If there is no task call or it takes no argument then return. */
if (!task_scope) return 0;
ports = ivl_scope_ports(task_scope);
if (ports == 0) return 0;
/* Allocate space to save the port information and initialize it. */
port_exprs = (port_expr_t) malloc(sizeof(struct port_expr_s)*ports);
for (idx = 0; idx < ports; idx += 1) {
port_exprs[idx].type = IVL_SIP_NONE;
port_exprs[idx].rval = 0;
}
/* Check that the input arguments are correct. */
for (idx = 0; idx < task_idx; idx += 1) {
ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx);
unsigned port = utask_in_port_idx(task_scope, assign);
if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) {
free(port_exprs);
return 0;
}
port_exprs[port].type = IVL_SIP_INPUT;
port_exprs[port].rval = ivl_stmt_rval(assign);
}
/* Check that the output arguments are correct. */
for (idx = task_idx + 1; idx < count; idx += 1) {
ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx);
unsigned port = utask_out_port_idx(task_scope, assign);
if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) {
free(port_exprs);
return 0;
}
if (port_exprs[port].type == IVL_SIP_INPUT) {
/* We probably should verify that the current R-value
* matches the new L-value. */
port_exprs[port].type = IVL_SIP_INOUT;
} else {
port_exprs[port].type = IVL_SIP_OUTPUT;
}
port_exprs[port].lval = assign;
}
/* Check that the task call has the correct line number. */
if (lineno != ivl_stmt_lineno(ivl_stmt_block_stmt(stmt, task_idx))) {
free(port_exprs);
return 0;
}
/* Verify that all the ports were defined. */
for (idx = 0; idx < ports; idx += 1) {
if (port_exprs[idx].type == IVL_SIP_NONE) {
free(port_exprs);
return 0;
}
}
/* The pattern matched so this block represents a call to a user
* defined task with arguments. */
show_stmt_file_line(stmt, "User task call (with arguments).");
return 1;
}
/*
* This function draws a statement as vvp assembly. It basically
* switches on the statement type and draws code based on the type and
@ -1842,6 +2257,7 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
{
const ivl_statement_type_t code = ivl_statement_type(net);
int rc = 0;
unsigned saved_file_line = 0;
switch (code) {
@ -1860,8 +2276,21 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
case IVL_ST_BLOCK:
if (ivl_stmt_block_scope(net))
rc += show_stmt_block_named(net, sscope);
else
else {
/* This block could really represent a single statement.
* If so only emit a single %file_line opcode. */
if (show_file_line) {
if (is_delayed_or_event_assign(sscope, net) ||
is_repeat_event_assign(sscope, net) ||
is_wait(sscope, net) ||
is_utask_call_with_args(sscope, net)) {
saved_file_line = show_file_line;
show_file_line = 0;
}
}
rc += show_stmt_block(net, sscope);
if (saved_file_line) show_file_line = 1;
}
break;
case IVL_ST_CASE:

View File

@ -1,7 +1,7 @@
#ifndef __vpi_user_H
#define __vpi_user_H
/*
* Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2011 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
@ -373,6 +373,8 @@ typedef struct t_vpi_delay {
# define _vpiDelaySelMinimum 1
# define _vpiDelaySelTypical 2
# define _vpiDelaySelMaximum 3
/* used in vvp/vpi_priv.h 0x1000003 */
/* used in vvp/vpi_priv.h 0x1000004 */
/* DELAY MODES */
#define vpiNoDelay 1

View File

@ -67,8 +67,8 @@ V = vpi_modules.o vpi_callback.o vpi_const.o vpi_event.o vpi_iter.o vpi_mcd.o \
vpip_to_dec.o vpip_format.o vvp_vpi.o
O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
concat.o dff.o enum_type.o extend.o npmos.o part.o permaheap.o \
reduce.o resolv.o \
concat.o dff.o enum_type.o extend.o file_line.o npmos.o part.o \
permaheap.o reduce.o resolv.o \
sfunc.o stop.o symbols.o ufunc.o codes.o vthread.o schedule.o \
statistics.o tables.o udp.o vvp_island.o vvp_net.o vvp_net_sig.o \
event.o logic.o delay.o words.o island_tran.o $V

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -109,6 +109,8 @@ void codespace_delete(void)
vpi_call_delete((cur+idx)->handle);
} else if ((cur+idx)->opcode == &of_EXEC_UFUNC) {
exec_ufunc_delete((cur+idx));
} else if ((cur+idx)->opcode == &of_FILE_LINE) {
delete((cur+idx)->handle);
}
if (count_opcodes == 0) break;
}

View File

@ -1,7 +1,7 @@
#ifndef __codes_H
#define __codes_H
/*
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -94,6 +94,7 @@ extern bool of_EVCTL(vthread_t thr, vvp_code_t code);
extern bool of_EVCTLC(vthread_t thr, vvp_code_t code);
extern bool of_EVCTLI(vthread_t thr, vvp_code_t code);
extern bool of_EVCTLS(vthread_t thr, vvp_code_t code);
extern bool of_FILE_LINE(vthread_t thr, vvp_code_t code);
extern bool of_FORCE_LINK(vthread_t thr, vvp_code_t code);
extern bool of_FORCE_V(vthread_t thr, vvp_code_t code);
extern bool of_FORCE_WR(vthread_t thr, vvp_code_t code);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -1709,6 +1709,23 @@ void compile_fork(char*label, struct symb_s dest, struct symb_s scope)
compile_vpi_lookup(&code->handle, scope.text);
}
void compile_file_line(char*label, long file_idx, long lineno,
char*description)
{
if (label) compile_codelabel(label);
/* Create an instruction in the code space. */
vvp_code_t code = codespace_allocate();
code->opcode = &of_FILE_LINE;
/* Create a vpiHandle that contains the information. */
code->handle = vpip_build_file_line(description, file_idx, lineno);
assert(code->handle);
/* Done with the lexor-allocated name string. */
delete[] description;
}
void compile_vpi_call(char*label, char*name,
bool func_as_task_err, bool func_as_task_warn,
long file_idx, long lineno,

View File

@ -1,7 +1,7 @@
#ifndef __compile_H
#define __compile_H
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -404,6 +404,9 @@ typedef struct comp_operands_s*comp_operands_t;
extern void compile_code(char*label, char*mnem, comp_operands_t opa);
extern void compile_disable(char*label, struct symb_s symb);
extern void compile_file_line(char*label, long file_idx, long lineno,
char*description);
extern void compile_vpi_call(char*label, char*name,
bool func_as_task_err, bool func_as_task_warn,
long file_idx, long lineno,

View File

@ -4,7 +4,7 @@
%{
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -204,13 +204,14 @@ static char* strdupnew(char const *str)
kind of instruction this really is. The few exceptions (that have
exceptional parameter requirements) are listed first. */
"%vpi_call" { return K_vpi_call; }
"%vpi_call" { return K_vpi_call; }
"%vpi_call/w" { return K_vpi_call_w; }
"%vpi_call/i" { return K_vpi_call_i; }
"%vpi_func" { return K_vpi_func; }
"%vpi_func" { return K_vpi_func; }
"%vpi_func/r" { return K_vpi_func_r; }
"%disable" { return K_disable; }
"%fork" { return K_fork; }
"%disable" { return K_disable; }
"%fork" { return K_fork; }
"%file_line" { return K_file_line; }
/* Handle the specialized variable access functions. */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
*
*/
@ -385,6 +385,18 @@ that this information has been cleared. You can get an assert if
this information is not managed correctly.
* %file_line <file> <line> <description>
This command emits the provided file and line information along with
the description when it is executed. The output is sent to stderr and
the format of the output is:
<file>:<line>: <description>
<file> is the unsigned numeric file index.
<line> is the unsigned line number.
<description> is a string, if string is 0 then the following default
message is used: "Procedural tracing.".
* %force/v <label>, <bit>, <wid>
Force a constant value to the target variable. This is similar to %set

View File

@ -1,7 +1,7 @@
%{
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -95,7 +95,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_vpi_func K_vpi_func_r
%token K_disable K_fork
%token K_ivl_version K_ivl_delay_selection
%token K_vpi_module K_vpi_time_precision K_file_names
%token K_vpi_module K_vpi_time_precision K_file_names K_file_line
%token <text> T_INSTR
%token <text> T_LABEL
@ -556,6 +556,15 @@ statement
| T_LABEL ';'
{ compile_codelabel($1); }
/* %file_line statements are instructions that have unusual operand
requirements so are handled by their own rules. */
| label_opt K_file_line T_NUMBER T_NUMBER T_STRING ';'
{ compile_file_line($1, $3, $4, $5); }
| label_opt K_file_line T_NUMBER T_NUMBER T_NUMBER ';'
{ assert($5 == 0);
compile_file_line($1, $3, $4, 0); }
/* %vpi_call statements are instructions that have unusual operand
requirements so are handled by their own rules. The %vpi_func
statement is a variant of %vpi_call that includes a thread vector

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -1029,6 +1029,12 @@ void schedule_simulate(void)
if (!schedule_runnable) break;
schedule_time += ctim->delay;
/* When the design is being traced (we are emitting
* file/line information) also print any time changes. */
if (show_file_line) {
cerr << "Advancing to simulation time: "
<< schedule_time << endl;
}
ctim->delay = 0;
vpiNextSimTime();

View File

@ -1,7 +1,7 @@
#ifndef __vpi_priv_H
#define __vpi_priv_H
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -38,6 +38,17 @@
* header file elsewhere.
*/
/*
* Routines/definitions used to build the file/line number tracing object.
*/
#define _vpiFileLine 0x1000003
#define _vpiDescription 0x1000004
extern bool show_file_line;
extern vpiHandle vpip_build_file_line(char*description,
long file_idx, long lineno);
/*
* Private VPI properties that are only used in the cleanup code.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2011 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
@ -4487,6 +4487,18 @@ bool of_SUBI(vthread_t thr, vvp_code_t cp)
return true;
}
bool of_FILE_LINE(vthread_t, vvp_code_t cp)
{
if (show_file_line) {
vpiHandle handle = cp->handle;
cerr << vpi_get_str(vpiFile, handle) << ":"
<< vpi_get(vpiLineNo, handle) << ": ";
cerr << vpi_get_str(_vpiDescription, handle);
cerr << endl;
}
return true;
}
bool of_VPI_CALL(vthread_t thr, vvp_code_t cp)
{
vpip_execute_vpi_call(thr, cp->handle);