Fix for initial value propagation (part 1).

To match the behaviour of other simulators, delayed bit-based signals
should have the value 'x' and delayed real valued signals should have
the value 0.0 until the true initial value has propagated. This patch
provides this behaviour.
This commit is contained in:
Martin Whitaker 2010-04-08 11:48:17 +01:00 committed by Stephen Williams
parent 483afd5dc9
commit c9f0d7e28f
11 changed files with 103 additions and 62 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -47,6 +47,10 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
dly = "";
if (d_rise != 0) {
unsigned dly_width = width;
if (data_type_of_nexus(ivl_lpm_q(net)) == IVL_VT_REAL)
dly_width = 0;
dly = "/d";
if (number_is_immediate(d_rise, 64, 0) &&
number_is_immediate(d_fall, 64, 0) &&
@ -67,8 +71,9 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
exit(1);
}
fprintf(vvp_out, "L_%p .delay (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
net, get_number_immediate64(d_rise),
fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
net, dly_width,
get_number_immediate64(d_rise),
get_number_immediate64(d_fall),
get_number_immediate64(d_decay), net);
} else {
@ -80,7 +85,8 @@ static void draw_lpm_mux_ab(ivl_lpm_t net, const char*muxz)
assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL);
fprintf(vvp_out, "L_%p .delay L_%p/d", net, net);
fprintf(vvp_out, "L_%p .delay %u L_%p/d",
net, dly_width, net);
sig = ivl_expr_signal(d_rise);
assert(ivl_signal_dimensions(sig) == 0);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -355,6 +355,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
if (cptr) {
char *result = 0;
ivl_expr_t d_rise, d_fall, d_decay;
unsigned dly_width = 0;
/* Constants should have exactly 1 pin, with a literal value. */
assert(nptr_pin == 0);
@ -372,10 +373,12 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
ivl_nexus_ptr_drive0(nptr),
ivl_nexus_ptr_drive1(nptr));
}
dly_width = ivl_const_width(cptr);
break;
case IVL_VT_REAL:
result = draw_Cr_to_string(ivl_const_real(cptr));
dly_width = 0;
break;
default:
@ -403,9 +406,10 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
assert(! number_is_unknown(d_fall));
assert(! number_is_unknown(d_decay));
fprintf(vvp_out, "L_%p .delay "
fprintf(vvp_out, "L_%p .delay %u "
"(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
cptr, get_number_immediate64(d_rise),
cptr, dly_width,
get_number_immediate64(d_rise),
get_number_immediate64(d_fall),
get_number_immediate64(d_decay), cptr);
@ -418,7 +422,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
assert(ivl_expr_type(d_fall) == IVL_EX_SIGNAL);
assert(ivl_expr_type(d_decay) == IVL_EX_SIGNAL);
fprintf(vvp_out, "L_%p .delay L_%p/d", cptr, cptr);
fprintf(vvp_out, "L_%p .delay %u L_%p/d",
cptr, dly_width, cptr);
sig = ivl_expr_signal(d_rise);
assert(ivl_signal_dimensions(sig) == 0);

View File

@ -66,6 +66,8 @@ static void draw_modpath_record(const char*label, const char*driver,
ccharp*src_drivers;
ccharp*con_drivers;
unsigned width = ivl_signal_width(path_sig);
src_drivers = calloc(ivl_signal_npath(path_sig), sizeof(ccharp));
con_drivers = calloc(ivl_signal_npath(path_sig), sizeof(ccharp));
for (idx = 0 ; idx < ivl_signal_npath(path_sig) ; idx += 1) {
@ -81,7 +83,7 @@ static void draw_modpath_record(const char*label, const char*driver,
}
fprintf(vvp_out, " .scope S_%p;\n", ivl_path_scope(ivl_signal_path(path_sig,0)));
fprintf(vvp_out, "%s .modpath %s v%p_0", label, driver, path_sig);
fprintf(vvp_out, "%s .modpath %u %s v%p_0", label, width, driver, path_sig);
for (idx = 0 ; idx < ivl_signal_npath(path_sig); idx += 1) {
ivl_delaypath_t path = ivl_signal_path(path_sig, idx);

View File

@ -878,6 +878,10 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
ivl_expr_t fall_exp = ivl_logic_delay(lptr, 1);
ivl_expr_t decay_exp = ivl_logic_delay(lptr, 2);
unsigned dly_width = vector_width;
if (data_type_of_nexus(ivl_logic_pin(lptr,0)) == IVL_VT_REAL)
dly_width = 0;
if (number_is_immediate(rise_exp, 64, 0)
&& number_is_immediate(fall_exp, 64, 0)
&& number_is_immediate(decay_exp, 64, 0)) {
@ -897,8 +901,9 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
assert(0);
}
fprintf(vvp_out, "L_%p .delay (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
lptr, get_number_immediate64(rise_exp),
fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") L_%p/d;\n",
lptr, dly_width,
get_number_immediate64(rise_exp),
get_number_immediate64(fall_exp),
get_number_immediate64(decay_exp), lptr);
} else {
@ -910,7 +915,7 @@ static void draw_logic_in_scope(ivl_net_logic_t lptr)
assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
assert(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL);
fprintf(vvp_out, "L_%p .delay L_%p/d", lptr, lptr);
fprintf(vvp_out, "L_%p .delay %u L_%p/d", lptr, dly_width, lptr);
sig = ivl_expr_signal(rise_exp);
assert(ivl_signal_dimensions(sig) == 0);
@ -1091,11 +1096,15 @@ static void draw_lpm_data_inputs(ivl_lpm_t net, unsigned base,
* "" string if the node was not needed. The caller uses that string
* to modify labels that are generated.
*/
static const char* draw_lpm_output_delay(ivl_lpm_t net)
static const char* draw_lpm_output_delay(ivl_lpm_t net, ivl_variable_type_t dt)
{
ivl_expr_t d_rise = ivl_lpm_delay(net, 0);
ivl_expr_t d_fall = ivl_lpm_delay(net, 1);
ivl_expr_t d_decay = ivl_lpm_delay(net, 2);
unsigned width = ivl_lpm_width(net);
if (dt == IVL_VT_REAL)
width = 0;
const char*dly = "";
if (d_rise != 0) {
@ -1119,8 +1128,9 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net)
}
dly = "/d";
fprintf(vvp_out, "L_%p .delay (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ")"
" L_%p/d;\n", net, get_number_immediate64(d_rise),
fprintf(vvp_out, "L_%p .delay %u (%" PRIu64 ",%" PRIu64 ",%" PRIu64 ")"
" L_%p/d;\n", net, width,
get_number_immediate64(d_rise),
get_number_immediate64(d_fall),
get_number_immediate64(d_decay), net);
}
@ -1131,11 +1141,12 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net)
static void draw_lpm_abs(ivl_lpm_t net)
{
const char*src_table[1];
ivl_variable_type_t dt = data_type_of_nexus(ivl_lpm_data(net,0));
const char*dly;
draw_lpm_data_inputs(net, 0, 1, src_table);
dly = draw_lpm_output_delay(net);
dly = draw_lpm_output_delay(net, dt);
fprintf(vvp_out, "L_%p%s .abs %s;\n",
net, dly, src_table[0]);
@ -1148,7 +1159,7 @@ static void draw_lpm_cast_int(ivl_lpm_t net)
draw_lpm_data_inputs(net, 0, 1, src_table);
dly = draw_lpm_output_delay(net);
dly = draw_lpm_output_delay(net, IVL_VT_LOGIC);
fprintf(vvp_out, "L_%p%s .cast/int %u, %s;\n",
net, dly, ivl_lpm_width(net), src_table[0]);
@ -1162,7 +1173,7 @@ static void draw_lpm_cast_real(ivl_lpm_t net)
draw_lpm_data_inputs(net, 0, 1, src_table);
dly = draw_lpm_output_delay(net);
dly = draw_lpm_output_delay(net, IVL_VT_REAL);
if (ivl_lpm_signed(net)) is_signed = ".s";
@ -1234,7 +1245,7 @@ static void draw_lpm_add(ivl_lpm_t net)
draw_lpm_data_inputs(net, 0, 2, src_table);
dly = draw_lpm_output_delay(net);
dly = draw_lpm_output_delay(net, dto);
fprintf(vvp_out, "L_%p%s .arith/%s %u, %s, %s;\n",
net, dly, type, width, src_table[0], src_table[1]);
@ -1317,7 +1328,7 @@ static void draw_lpm_cmp(ivl_lpm_t net)
draw_lpm_data_inputs(net, 0, 2, src_table);
dly = draw_lpm_output_delay(net);
dly = draw_lpm_output_delay(net, dtc);
fprintf(vvp_out, "L_%p%s .cmp/%s%s %u, %s, %s;\n",
net, dly, type, signed_string, width,
@ -1375,7 +1386,7 @@ static void draw_lpm_concat(ivl_lpm_t net)
{
const char*src_table[4];
unsigned icnt = ivl_lpm_size(net);
const char*dly = draw_lpm_output_delay(net);
const char*dly = draw_lpm_output_delay(net, IVL_VT_LOGIC);
if (icnt <= 4) {
/* This is the easiest case. There are 4 or fewer input
@ -1545,7 +1556,7 @@ static void draw_lpm_shiftl(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
const char* signed_flag = ivl_lpm_signed(net)? "s" : "";
const char*dly = draw_lpm_output_delay(net);
const char*dly = draw_lpm_output_delay(net, IVL_VT_LOGIC);
if (ivl_lpm_type(net) == IVL_LPM_SHIFTR)
fprintf(vvp_out, "L_%p%s .shift/r%s %u", net, dly, signed_flag,
@ -1580,7 +1591,8 @@ static void draw_lpm_sfunc(ivl_lpm_t net)
{
unsigned idx;
const char*dly = draw_lpm_output_delay(net);
ivl_variable_type_t dt = data_type_of_nexus(ivl_lpm_q(net));
const char*dly = draw_lpm_output_delay(net, dt);
if (ivl_lpm_trigger(net))
fprintf(vvp_out, "L_%p%s .sfunc/e %u %u \"%s\", E_%p", net, dly,
@ -1616,7 +1628,8 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
const char**input_strings;
ivl_scope_t def = ivl_lpm_define(net);
const char*dly = draw_lpm_output_delay(net);
ivl_variable_type_t dt = data_type_of_nexus(ivl_lpm_q(net));
const char*dly = draw_lpm_output_delay(net, dt);
/* Get all the input labels that I will use for net signals that
connect to the inputs of the function. */
@ -1681,7 +1694,7 @@ static void draw_lpm_part(ivl_lpm_t net)
unsigned width, base;
ivl_nexus_t sel;
const char*dly = draw_lpm_output_delay(net);
const char*dly = draw_lpm_output_delay(net, IVL_VT_LOGIC);
width = ivl_lpm_width(net);
base = ivl_lpm_base(net);
@ -1722,7 +1735,7 @@ static void draw_lpm_part_pv(ivl_lpm_t net)
*/
static void draw_lpm_re(ivl_lpm_t net, const char*type)
{
const char*dly = draw_lpm_output_delay(net);
const char*dly = draw_lpm_output_delay(net, IVL_VT_LOGIC);
fprintf(vvp_out, "L_%p%s .reduce/%s %s;\n", net, dly,
type, draw_net_input(ivl_lpm_data(net,0)));
@ -1730,7 +1743,7 @@ static void draw_lpm_re(ivl_lpm_t net, const char*type)
static void draw_lpm_repeat(ivl_lpm_t net)
{
const char*dly = draw_lpm_output_delay(net);
const char*dly = draw_lpm_output_delay(net, IVL_VT_LOGIC);
fprintf(vvp_out, "L_%p%s .repeat %u, %u, %s;\n", net, dly,
ivl_lpm_width(net), ivl_lpm_size(net),
@ -1739,7 +1752,7 @@ static void draw_lpm_repeat(ivl_lpm_t net)
static void draw_lpm_sign_ext(ivl_lpm_t net)
{
const char*dly = draw_lpm_output_delay(net);
const char*dly = draw_lpm_output_delay(net, IVL_VT_LOGIC);
fprintf(vvp_out, "L_%p%s .extend/s %u, %s;\n",
net, dly, ivl_lpm_width(net),

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
*
*/
@ -375,13 +375,14 @@ delayed. The delay amount is given on the node line. Variable delay
nodes have three extra inputs to receive the rise, fall and decay
times that are used for delay.
.delay ( <rise>, <fall>, <decay> ) <input> ;
.delay <input>, <rise>, <fall>, <decay> ;
.delay <width> ( <rise>, <fall>, <decay> ) <input> ;
.delay <width> <input>, <rise>, <fall>, <decay> ;
The first form above takes three constant (64bit) numbers as the
initial delay, and takes a single input. The second form takes 4 net
inputs, with the first being the value to delay, and the remaining to
be the delay values to use.
be the delay values to use. <width> specifies the bit width of the
input net, with a width of 0 used to identify a real valued net.
MODULE PATH DELAY STATEMENTS:
@ -389,7 +390,9 @@ A module path delay takes data from its input, then a list of module
path delays. The <src> for each possible delay set is a trigger that
activates the delay.
.modpath <input> , [ <src> (<delays> [? <condition>]) ] ;
.modpath <width> <input> , [ <src> (<delays> [? <condition>]) ] ;
<width> specifies the bit width of the input net.
ARRAY INDEX STATEMENTS:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -1244,10 +1244,11 @@ void compile_cmp_gt_r(char*label, unsigned argc, struct symb_s*argv)
}
void compile_delay(char*label, vvp_delay_t*delay, struct symb_s arg)
void compile_delay(char*label, unsigned width,
vvp_delay_t*delay, struct symb_s arg)
{
vvp_net_t*net = new vvp_net_t;
vvp_fun_delay*obj = new vvp_fun_delay(net, BIT4_X, *delay);
vvp_fun_delay*obj = new vvp_fun_delay(net, width, *delay);
net->fun = obj;
delete delay;
@ -1258,11 +1259,12 @@ void compile_delay(char*label, vvp_delay_t*delay, struct symb_s arg)
free(label);
}
void compile_delay(char*label, unsigned argc, struct symb_s*argv)
void compile_delay(char*label, unsigned width,
unsigned argc, struct symb_s*argv)
{
vvp_delay_t stub (0, 0, 0);
vvp_net_t*net = new vvp_net_t;
vvp_fun_delay*obj = new vvp_fun_delay(net, BIT4_X, stub);
vvp_fun_delay*obj = new vvp_fun_delay(net, width, stub);
net->fun = obj;
inputs_connect(net, argc, argv);
@ -1289,11 +1291,11 @@ void compile_extend_signed(char*label, long wid, struct symb_s arg)
input_connect(ptr, 0, arg.text);
}
struct __vpiModPath* compile_modpath(char*label, struct symb_s drv,
struct symb_s dest)
struct __vpiModPath* compile_modpath(char*label, unsigned width,
struct symb_s drv, struct symb_s dest)
{
vvp_net_t*net = new vvp_net_t;
vvp_fun_modpath*obj = new vvp_fun_modpath(net);
vvp_fun_modpath*obj = new vvp_fun_modpath(net, width);
net->fun = obj;
input_connect(net, 0, drv.text);

View File

@ -1,7 +1,7 @@
#ifndef __compile_H
#define __compile_H
/*
* Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -128,8 +128,10 @@ extern void compile_compiletf(struct __vpiSysTaskCall*);
/*
* Compile delay nodes of various form.
*/
extern void compile_delay(char*label, vvp_delay_t*del, struct symb_s input);
extern void compile_delay(char*label, unsigned argc, struct symb_s*argv);
extern void compile_delay(char*label, unsigned width,
vvp_delay_t*del, struct symb_s input);
extern void compile_delay(char*label, unsigned width,
unsigned argc, struct symb_s*argv);
/*
* This is called by the parser to create a part select node.
@ -198,6 +200,7 @@ extern void compile_dff(char*label,
class __vpiModPath;
extern __vpiModPath* compile_modpath(char*label,
unsigned width,
struct symb_s drv,
struct symb_s dest);
extern void compile_modpath_src(__vpiModPath*dst,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005-2009 Stephen Williams <steve@icarus.com>
* Copyright (c) 2005-2010 Stephen Williams <steve@icarus.com>
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -133,12 +133,17 @@ void vvp_delay_t::set_decay(vvp_time64_t val)
calculate_min_delay_();
}
vvp_fun_delay::vvp_fun_delay(vvp_net_t*n, vvp_bit4_t init, const vvp_delay_t&d)
: net_(n), delay_(d), cur_vec4_(1)
vvp_fun_delay::vvp_fun_delay(vvp_net_t*n, unsigned width, const vvp_delay_t&d)
: net_(n), delay_(d)
{
cur_vec4_.set_bit(0, init);
cur_vec8_ = vvp_vector8_t(cur_vec4_, 6, 6);
cur_real_ = 0.0;
if (width > 0) {
cur_vec4_ = vvp_vector4_t(width, BIT4_X);
cur_vec8_ = vvp_vector8_t(cur_vec4_, 6, 6);
schedule_init_propagate(net_, cur_vec4_);
} else {
schedule_init_propagate(net_, cur_real_);
}
list_ = 0;
type_ = UNKNOWN_DELAY;
initial_ = true;
@ -468,9 +473,11 @@ void vvp_fun_delay::run_run_real_(struct vvp_fun_delay::event_*cur)
net_->send_real(cur_real_, 0);
}
vvp_fun_modpath::vvp_fun_modpath(vvp_net_t*net)
vvp_fun_modpath::vvp_fun_modpath(vvp_net_t*net, unsigned width)
: net_(net), src_list_(0), ifnone_list_(0)
{
cur_vec4_ = vvp_vector4_t(width, BIT4_X);
schedule_init_propagate(net_, cur_vec4_);
}
vvp_fun_modpath::~vvp_fun_modpath()

View File

@ -1,7 +1,7 @@
#ifndef __delay_H
#define __delay_H
/*
* Copyright 2005-2008 Stephen Williams
* Copyright 2005-2008,2010 Stephen Williams
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -83,7 +83,7 @@ class vvp_fun_delay : public vvp_net_fun_t, private vvp_gen_event_s {
};
public:
vvp_fun_delay(vvp_net_t*net, vvp_bit4_t init, const vvp_delay_t&d);
vvp_fun_delay(vvp_net_t*net, unsigned width, const vvp_delay_t&d);
~vvp_fun_delay();
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
@ -156,7 +156,7 @@ class vvp_fun_modpath_src;
class vvp_fun_modpath : public vvp_net_fun_t, private vvp_gen_event_s {
public:
vvp_fun_modpath(vvp_net_t*net);
vvp_fun_modpath(vvp_net_t*net, unsigned width);
~vvp_fun_modpath();
void add_modpath_src(vvp_fun_modpath_src*that, bool ifnone);

View File

@ -426,15 +426,15 @@ statement
node takes two form, one with an array of constants and a single
input, and another with an array of inputs. */
| T_LABEL K_DELAY delay symbol ';'
{ compile_delay($1, $3, $4); }
| T_LABEL K_DELAY symbols ';'
{ struct symbv_s obj = $3;
compile_delay($1, obj.cnt, obj.vect);
| T_LABEL K_DELAY T_NUMBER delay symbol ';'
{ compile_delay($1, $3, $4, $5); }
| T_LABEL K_DELAY T_NUMBER symbols ';'
{ struct symbv_s obj = $4;
compile_delay($1, $3, obj.cnt, obj.vect);
}
| T_LABEL K_MODPATH symbol symbol ','
{ modpath_dst = compile_modpath($1, $3, $4); }
| T_LABEL K_MODPATH T_NUMBER symbol symbol ','
{ modpath_dst = compile_modpath($1, $3, $4, $5); }
modpath_src_list ';'
{ modpath_dst = 0; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2005-2010 Stephen Williams (steve@icarus.com)
*
* (This is a rewrite of code that was ...
* Copyright (c) 2001 Stephan Boettcher <stephan@nevis.columbia.edu>)
@ -985,7 +985,7 @@ void compile_udp_functor(char*label, char*type,
if (delay != 0) {
vvp_net_t*net_drv = new vvp_net_t;
vvp_fun_delay*obj_drv = new vvp_fun_delay(net_drv, BIT4_X, *delay);
vvp_fun_delay*obj_drv = new vvp_fun_delay(net_drv, 1, *delay);
delete delay;
net_drv->fun = obj_drv;