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 .SH NAME
iverilog - Icarus Verilog compiler iverilog - Icarus Verilog compiler
@ -258,7 +258,9 @@ checking the syntax of the Verilog source.
.B vvp .B vvp
This is the default. The vvp target generates code for the vvp This is the default. The vvp target generates code for the vvp
runtime. The output is a complete program that simulates the design 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 .TP 8
.B fpga .B fpga
This is a synthesis target that supports a variety of fpga devices, 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; return 0;
} }
st = event_->elaborate(des, scope); st = event_->elaborate(des, scope);
st->set_line(*this);
if (st == 0) { if (st == 0) {
cerr << event_->get_fileline() << ": error: " cerr << event_->get_fileline() << ": error: "
"unable to elaborate event expression." "unable to elaborate event expression."
@ -2217,12 +2218,15 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
// We need a repeat statement. // We need a repeat statement.
} else { } else {
st = new NetRepeat(count, st); st = new NetRepeat(count, st);
st->set_line(*this);
} }
} else { } else {
st = new NetRepeat(count, st); st = new NetRepeat(count, st);
st->set_line(*this);
} }
} else { } else {
st = event_->elaborate_st(des, scope, a2); st = event_->elaborate_st(des, scope, a2);
st->set_line(*this);
if (st == 0) { if (st == 0) {
cerr << event_->get_fileline() << ": error: " cerr << event_->get_fileline() << ": error: "
"unable to elaborate event expression." "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 NetProc* PWhile::elaborate(Design*des, NetScope*scope) const
{ {
NetExpr*tmp = elab_and_eval(des, scope, cond_, -1); NetExpr*tmp = elab_and_eval(des, scope, cond_, -1);
tmp->set_line(*this);
NetWhile*loop = new NetWhile(tmp, statement_->elaborate(des, scope)); NetWhile*loop = new NetWhile(tmp, statement_->elaborate(des, scope));
loop->set_line(*this);
return loop; 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 * 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
@ -51,7 +51,7 @@ static void function_argument_real(ivl_signal_t port, ivl_expr_t expr)
/* ports cannot be arrays. */ /* ports cannot be arrays. */
assert(ivl_signal_dimensions(port) == 0); 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); clr_word(res);
} }
@ -180,9 +180,9 @@ int draw_ufunc_real(ivl_expr_t expr)
/* Call the function */ /* 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, ", S_%p;\n", def);
fprintf(vvp_out, " %%join;\n"); fprintf(vvp_out, " %%join;\n");
/* Return value signal cannot be an array. */ /* Return value signal cannot be an array. */
assert(ivl_signal_dimensions(retval) == 0); 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 * 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
@ -54,7 +54,8 @@ static int eval_bool64_logic(ivl_expr_t expr)
if (ivl_expr_signed(expr)) if (ivl_expr_signed(expr))
s_flag = "/s"; 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); clr_vector(tmp);
return res; return res;
@ -75,7 +76,7 @@ static int draw_number_bool64(ivl_expr_t expr)
res = allocate_word(); res = allocate_word();
low = val % UINT64_C(0x100000000); low = val % UINT64_C(0x100000000);
hig = 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; 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 * 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
@ -750,7 +750,7 @@ static struct vector_info draw_binary_expr_lor(ivl_expr_t expr, unsigned wid,
if (wid == 1) { if (wid == 1) {
if (lv.base >= 4 && lv.base < 8) { if (lv.base >= 4 && lv.base < 8) {
unsigned tmp = allocate_vector(1); 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; lv.base = tmp;
} }
return lv; 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)) { if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
long imm = get_number_immediate(le); long imm = get_number_immediate(le);
assert(imm >= 0); 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); rv.base, imm, rv.wid);
} else { } else {
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); 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)) { if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
long imm = get_number_immediate(re); long imm = get_number_immediate(re);
assert(imm >= 0); 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); lv.base, imm, lv.wid);
} else { } else {
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); 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)) { if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
long imm = get_number_immediate(re); long imm = get_number_immediate(re);
assert(imm >= 0); 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); lv.base, imm, lv.wid);
} else { } else {
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ); 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)) { if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
long imm = get_number_immediate(le); long imm = get_number_immediate(le);
assert(imm >= 0); 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); rv.base, imm, rv.wid);
} else { } else {
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ); 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)) { switch (ivl_expr_opcode(expr)) {
case '&': 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; break;
default: 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 * 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
@ -22,12 +22,13 @@
# include "vvp_priv.h" # include "vvp_priv.h"
# include <string.h> # include <string.h>
# include <assert.h> # include <assert.h>
# include <stdlib.h>
# include <sys/types.h> # include <sys/types.h>
# include <sys/stat.h> # include <sys/stat.h>
static const char*version_string = static const char*version_string =
"Icarus Verilog VVP Code Generator " VERSION " (" VERSION_TAG ")\n\n" "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" " 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" " 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" " 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; FILE*vvp_out = 0;
int vvp_errors = 0; int vvp_errors = 0;
unsigned show_file_line = 0;
__inline__ static void draw_execute_header(ivl_design_t des) __inline__ static void draw_execute_header(ivl_design_t des)
{ {
@ -95,8 +97,39 @@ int target_design(ivl_design_t des)
unsigned size; unsigned size;
unsigned idx; unsigned idx;
const char*path = ivl_design_flag(des, "-o"); 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); 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 #ifdef HAVE_FOPEN64
vvp_out = fopen64(path, "w"); vvp_out = fopen64(path, "w");
#else #else

View File

@ -1,7 +1,7 @@
#ifndef __vvp_priv_H #ifndef __vvp_priv_H
#define __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 * 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
@ -39,6 +39,12 @@ extern FILE* vvp_out;
*/ */
extern int vvp_errors; 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 { struct vector_info {
unsigned base; unsigned base;
unsigned wid; 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 * 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
@ -111,13 +111,13 @@ static void set_to_lvariable(ivl_lval_t lval,
unsigned skip_set = transient_id++; unsigned skip_set = transient_id++;
if (word_ix) { if (word_ix) {
draw_eval_expr_into_integer(word_ix, 3); 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 { } 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); draw_eval_expr_into_integer(part_off_ex, 1);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid); sig, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set); 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++; unsigned skip_set = transient_id++;
if (word_ix) { if (word_ix) {
draw_eval_expr_into_integer(word_ix, 3); 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 { } 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, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid); sig, bit, wid);
if (word_ix) /* Only need this label if word_ix is set. */ if (word_ix) /* Only need this label if word_ix is set. */
fprintf(vvp_out, "t_%u ;\n", skip_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 skip_set = transient_id++;
unsigned index_reg = 3; unsigned index_reg = 3;
draw_eval_expr_into_integer(word_ix, index_reg); draw_eval_expr_into_integer(word_ix, index_reg);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); 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, " %%ix/load 1, %lu, 0;\n", part_off);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid); sig, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set); 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. */ directly to the word and save the index calculation. */
if (word_ix == 0) { if (word_ix == 0) {
if (use_word < ivl_signal_array_count(sig)) { if (use_word < ivl_signal_array_count(sig)) {
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n"); fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word); fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n",
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", use_word);
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid); sig, bit, wid);
} else { } else {
fprintf(vvp_out, " ; %%set/v v%p_%lu, %u, %u " 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 skip_set = transient_id++;
unsigned index_reg = 3; unsigned index_reg = 3;
draw_eval_expr_into_integer(word_ix, index_reg); draw_eval_expr_into_integer(word_ix, index_reg);
fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set);
fprintf(vvp_out, " %%ix/load 1, 0, 0;\n"); fprintf(vvp_out, " %%ix/load 1, 0, 0;\n");
fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", fprintf(vvp_out, " %%set/av v%p, %u, %u;\n",
sig, bit, wid); sig, bit, wid);
fprintf(vvp_out, "t_%u ;\n", skip_set); 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) static int show_stmt_alloc(ivl_statement_t net)
{ {
ivl_scope_t scope = ivl_stmt_call(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_lval_t lval;
ivl_signal_t sig; ivl_signal_t sig;
show_stmt_file_line(net, "Blocking assignment.");
lval = ivl_stmt_lval(net, 0); lval = ivl_stmt_lval(net, 0);
sig = ivl_lval_sig(lval); sig = ivl_lval_sig(lval);
@ -739,6 +760,8 @@ static int show_stmt_assign_nb(ivl_statement_t net)
ivl_signal_t sig; ivl_signal_t sig;
unsigned nevents = ivl_stmt_nevent(net); unsigned nevents = ivl_stmt_nevent(net);
show_stmt_file_line(net, "Nonblocking assignment.");
/* If we have an event control build the control structure. */ /* If we have an event control build the control structure. */
if (nevents) { if (nevents) {
assert(del == 0); assert(del == 0);
@ -922,6 +945,8 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
unsigned idx, default_case; unsigned idx, default_case;
show_stmt_file_line(net, "Case statement.");
local_count += count + 1; local_count += count + 1;
/* First draw the branch table. All the non-default cases /* 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; 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 /* First draw the branch table. All the non-default cases
generate a branch out of here, to the code that implements 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_expr_t rval;
ivl_signal_t sig; ivl_signal_t sig;
show_stmt_file_line(net, "Assign statement.");
rval = ivl_stmt_rval(net); rval = ivl_stmt_rval(net);
assert(rval); 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)); ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
unsigned lidx; unsigned lidx;
show_stmt_file_line(net, "Deassign statement.");
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) { if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
ivl_lval_t lval; ivl_lval_t lval;
@ -1372,8 +1402,11 @@ static int show_stmt_condit(ivl_statement_t net, ivl_scope_t sscope)
int rc = 0; int rc = 0;
unsigned lab_false, lab_out; unsigned lab_false, lab_out;
ivl_expr_t expr = ivl_stmt_cond_expr(net); ivl_expr_t expr = ivl_stmt_cond_expr(net);
struct vector_info cond struct vector_info cond;
= draw_eval_expr(expr, STUFF_OK_XZ|STUFF_OK_47|STUFF_OK_RO);
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); 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 low = delay % UINT64_C(0x100000000);
unsigned long hig = 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); fprintf(vvp_out, " %%delay %lu, %lu;\n", low, hig);
/* Lots of things can happen during a delay. */ /* Lots of things can happen during a delay. */
clear_expression_lookaside(); 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_expr_t expr = ivl_stmt_delay_expr(net);
ivl_statement_t stmt = ivl_stmt_sub_stmt(net); ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
show_stmt_file_line(net, "Delay statement.");
switch (ivl_expr_value(expr)) { switch (ivl_expr_value(expr)) {
case IVL_VT_BOOL: 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) static int show_stmt_disable(ivl_statement_t net, ivl_scope_t sscope)
{ {
int rc = 0; int rc = 0;
ivl_scope_t target = ivl_stmt_call(net); ivl_scope_t target = ivl_stmt_call(net);
show_stmt_file_line(net, "Disable statement.");
fprintf(vvp_out, " %%disable S_%p;\n", target); fprintf(vvp_out, " %%disable S_%p;\n", target);
return rc; return rc;
@ -1492,6 +1531,8 @@ static int show_stmt_force(ivl_statement_t net)
ivl_expr_t rval; ivl_expr_t rval;
ivl_signal_t sig; ivl_signal_t sig;
show_stmt_file_line(net, "Force statement.");
rval = ivl_stmt_rval(net); rval = ivl_stmt_rval(net);
assert(rval); 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); ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
unsigned lab_top = local_count++; unsigned lab_top = local_count++;
show_stmt_file_line(net, "Forever statement.");
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_top); fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_top);
rc += show_statement(stmt, sscope); rc += show_statement(stmt, sscope);
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_top); 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)); ivl_signal_t sig = ivl_lval_sig(ivl_stmt_lval(net, 0));
unsigned lidx; unsigned lidx;
show_stmt_file_line(net, "Release statement.");
if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) { if (sig && ivl_signal_data_type(sig) == IVL_VT_REAL) {
unsigned type = 0; unsigned type = 0;
ivl_lval_t lval; ivl_lval_t lval;
@ -1682,9 +1727,13 @@ static int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope)
int rc = 0; int rc = 0;
unsigned lab_top = local_count++, lab_out = local_count++; unsigned lab_top = local_count++, lab_out = local_count++;
ivl_expr_t expr = ivl_stmt_cond_expr(net); 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"; 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 */ /* Test that 0 < expr */
fprintf(vvp_out, "T_%u.%u %%cmp/%s 0, %u, %u;\n", thread_count, fprintf(vvp_out, "T_%u.%u %%cmp/%s 0, %u, %u;\n", thread_count,
lab_top, sign, cnt.base, cnt.wid); 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); ivl_event_t ev = ivl_stmt_events(net, 0);
assert(ev); assert(ev);
show_stmt_file_line(net, "Event trigger statement.");
fprintf(vvp_out, " %%set/v E_%p, 0,1;\n", ev); fprintf(vvp_out, " %%set/v E_%p, 0,1;\n", ev);
return 0; return 0;
} }
@ -1720,6 +1772,8 @@ static int show_stmt_utask(ivl_statement_t net)
{ {
ivl_scope_t task = ivl_stmt_call(net); ivl_scope_t task = ivl_stmt_call(net);
show_stmt_file_line(net, "User task call.");
fprintf(vvp_out, " %%fork TD_%s", fprintf(vvp_out, " %%fork TD_%s",
vvp_mangle_id(ivl_scope_name(task))); vvp_mangle_id(ivl_scope_name(task)));
fprintf(vvp_out, ", S_%p;\n", 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) 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) { if (ivl_stmt_nevent(net) == 1) {
ivl_event_t ev = ivl_stmt_events(net, 0); ivl_event_t ev = ivl_stmt_events(net, 0);
fprintf(vvp_out, " %%wait E_%p;\n", ev); 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 top_label = local_count++;
unsigned out_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 /* Start the loop. The top of the loop starts a basic block
because it can be entered from above or from the bottom of because it can be entered from above or from the bottom of
the loop. */ 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) static int show_system_task_call(ivl_statement_t net)
{ {
show_stmt_file_line(net, "System task call.");
draw_vpi_task_call(net); draw_vpi_task_call(net);
/* VPI calls can manipulate anything, so clear the expression /* 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; 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 * This function draws a statement as vvp assembly. It basically
* switches on the statement type and draws code based on the type and * 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); const ivl_statement_type_t code = ivl_statement_type(net);
int rc = 0; int rc = 0;
unsigned saved_file_line = 0;
switch (code) { switch (code) {
@ -1860,8 +2276,21 @@ static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
case IVL_ST_BLOCK: case IVL_ST_BLOCK:
if (ivl_stmt_block_scope(net)) if (ivl_stmt_block_scope(net))
rc += show_stmt_block_named(net, sscope); 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); rc += show_stmt_block(net, sscope);
if (saved_file_line) show_file_line = 1;
}
break; break;
case IVL_ST_CASE: case IVL_ST_CASE:

View File

@ -1,7 +1,7 @@
#ifndef __vpi_user_H #ifndef __vpi_user_H
#define __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 * 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
@ -373,6 +373,8 @@ typedef struct t_vpi_delay {
# define _vpiDelaySelMinimum 1 # define _vpiDelaySelMinimum 1
# define _vpiDelaySelTypical 2 # define _vpiDelaySelTypical 2
# define _vpiDelaySelMaximum 3 # define _vpiDelaySelMaximum 3
/* used in vvp/vpi_priv.h 0x1000003 */
/* used in vvp/vpi_priv.h 0x1000004 */
/* DELAY MODES */ /* DELAY MODES */
#define vpiNoDelay 1 #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 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 \ 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 \ concat.o dff.o enum_type.o extend.o file_line.o npmos.o part.o \
reduce.o resolv.o \ permaheap.o reduce.o resolv.o \
sfunc.o stop.o symbols.o ufunc.o codes.o vthread.o schedule.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 \ 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 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 * 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
@ -109,6 +109,8 @@ void codespace_delete(void)
vpi_call_delete((cur+idx)->handle); vpi_call_delete((cur+idx)->handle);
} else if ((cur+idx)->opcode == &of_EXEC_UFUNC) { } else if ((cur+idx)->opcode == &of_EXEC_UFUNC) {
exec_ufunc_delete((cur+idx)); exec_ufunc_delete((cur+idx));
} else if ((cur+idx)->opcode == &of_FILE_LINE) {
delete((cur+idx)->handle);
} }
if (count_opcodes == 0) break; if (count_opcodes == 0) break;
} }

View File

@ -1,7 +1,7 @@
#ifndef __codes_H #ifndef __codes_H
#define __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 * 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
@ -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_EVCTLC(vthread_t thr, vvp_code_t code);
extern bool of_EVCTLI(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_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_LINK(vthread_t thr, vvp_code_t code);
extern bool of_FORCE_V(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); 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 * 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
@ -1709,6 +1709,23 @@ void compile_fork(char*label, struct symb_s dest, struct symb_s scope)
compile_vpi_lookup(&code->handle, scope.text); 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, void compile_vpi_call(char*label, char*name,
bool func_as_task_err, bool func_as_task_warn, bool func_as_task_err, bool func_as_task_warn,
long file_idx, long lineno, long file_idx, long lineno,

View File

@ -1,7 +1,7 @@
#ifndef __compile_H #ifndef __compile_H
#define __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 * 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
@ -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_code(char*label, char*mnem, comp_operands_t opa);
extern void compile_disable(char*label, struct symb_s symb); 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, extern void compile_vpi_call(char*label, char*name,
bool func_as_task_err, bool func_as_task_warn, bool func_as_task_err, bool func_as_task_warn,
long file_idx, long lineno, 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 * 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
@ -204,13 +204,14 @@ static char* strdupnew(char const *str)
kind of instruction this really is. The few exceptions (that have kind of instruction this really is. The few exceptions (that have
exceptional parameter requirements) are listed first. */ 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/w" { return K_vpi_call_w; }
"%vpi_call/i" { return K_vpi_call_i; } "%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; } "%vpi_func/r" { return K_vpi_func_r; }
"%disable" { return K_disable; } "%disable" { return K_disable; }
"%fork" { return K_fork; } "%fork" { return K_fork; }
"%file_line" { return K_file_line; }
/* Handle the specialized variable access functions. */ /* 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. 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/v <label>, <bit>, <wid>
Force a constant value to the target variable. This is similar to %set 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 * 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
@ -95,7 +95,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_vpi_func K_vpi_func_r %token K_vpi_func K_vpi_func_r
%token K_disable K_fork %token K_disable K_fork
%token K_ivl_version K_ivl_delay_selection %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_INSTR
%token <text> T_LABEL %token <text> T_LABEL
@ -556,6 +556,15 @@ statement
| T_LABEL ';' | T_LABEL ';'
{ compile_codelabel($1); } { 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 /* %vpi_call statements are instructions that have unusual operand
requirements so are handled by their own rules. The %vpi_func requirements so are handled by their own rules. The %vpi_func
statement is a variant of %vpi_call that includes a thread vector 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 * 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
@ -1029,6 +1029,12 @@ void schedule_simulate(void)
if (!schedule_runnable) break; if (!schedule_runnable) break;
schedule_time += ctim->delay; 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; ctim->delay = 0;
vpiNextSimTime(); vpiNextSimTime();

View File

@ -1,7 +1,7 @@
#ifndef __vpi_priv_H #ifndef __vpi_priv_H
#define __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 * 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
@ -38,6 +38,17 @@
* header file elsewhere. * 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. * 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 * 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
@ -4487,6 +4487,18 @@ bool of_SUBI(vthread_t thr, vvp_code_t cp)
return true; 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) bool of_VPI_CALL(vthread_t thr, vvp_code_t cp)
{ {
vpip_execute_vpi_call(thr, cp->handle); vpip_execute_vpi_call(thr, cp->handle);