Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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.
  • Loading branch information...
commit 06447817d3e8848e052a59be320b2711ac996dcc 1 parent 312b4da
@caryr caryr authored steveicarus committed
View
6 driver/iverilog.man.in
@@ -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
6 elaborate.cc
@@ -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
8 tgt-vvp/draw_ufunc.c
@@ -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
7 tgt-vvp/eval_bool.c
@@ -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
14 tgt-vvp/eval_expr.c
@@ -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
37 tgt-vvp/vvp.c
@@ -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
8 tgt-vvp/vvp_priv.h
@@ -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
477 tgt-vvp/vvp_process.c
@@ -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
@@ -1834,6 +1894,361 @@ static int show_system_task_call(ivl_statement_t net)
}
/*
+ * 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
* further specifics.
@@ -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
4 vpi_user.h
@@ -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
4 vvp/Makefile.in
@@ -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
4 vvp/codes.cc
@@ -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
3  vvp/codes.h
@@ -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
19 vvp/compile.cc
@@ -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
5 vvp/compile.h
@@ -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
11 vvp/lexor.lex
@@ -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
14 vvp/opcodes.txt
@@ -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
13 vvp/parse.y
@@ -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
8 vvp/schedule.cc
@@ -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
13 vvp/vpi_priv.h
@@ -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
@@ -39,6 +39,17 @@
*/
/*
+ * 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.
*/
#ifdef CHECK_WITH_VALGRIND
View
14 vvp/vthread.cc
@@ -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);
Please sign in to comment.
Something went wrong with that request. Please try again.