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:
parent
312b4da46f
commit
06447817d3
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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. */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
13
vvp/parse.y
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
|
* 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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue