Merge pull request #1065 from steveicarus/vvp-undriven-net-initialisation
vvp undriven net initialisation
This commit is contained in:
commit
8f1fcc988e
|
|
@ -0,0 +1,52 @@
|
|||
#include <vpi_user.h>
|
||||
|
||||
static PLI_INT32 start_cb(struct t_cb_data *cb)
|
||||
{
|
||||
static struct t_vpi_value val;
|
||||
vpiHandle wire;
|
||||
|
||||
(void)cb; // suppress unused parameter warning
|
||||
|
||||
wire = vpi_handle_by_name("test.w4", NULL);
|
||||
if (wire) {
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = 1;
|
||||
vpi_put_value(wire, &val, NULL, vpiNoDelay);
|
||||
} else {
|
||||
vpi_printf("Failed to get handle for w4\n");
|
||||
}
|
||||
|
||||
wire = vpi_handle_by_name("test.w8", NULL);
|
||||
if (wire) {
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = 1;
|
||||
vpi_put_value(wire, &val, NULL, vpiNoDelay);
|
||||
} else {
|
||||
vpi_printf("Failed to get handle for w8\n");
|
||||
}
|
||||
|
||||
wire = vpi_handle_by_name("test.wr", NULL);
|
||||
if (wire) {
|
||||
val.format = vpiRealVal;
|
||||
val.value.real = 1.0;
|
||||
vpi_put_value(wire, &val, NULL, vpiNoDelay);
|
||||
} else {
|
||||
vpi_printf("Failed to get handle for wr\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void register_cb(void)
|
||||
{
|
||||
struct t_cb_data cbd = {};
|
||||
|
||||
cbd.reason = cbStartOfSimulation;
|
||||
cbd.cb_rtn = start_cb;
|
||||
vpi_register_cb(&cbd);
|
||||
}
|
||||
|
||||
void (*vlog_startup_routines[])(void) = {
|
||||
register_cb,
|
||||
0
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
module test;
|
||||
wire w4;
|
||||
tri0 w8;
|
||||
wire real wr;
|
||||
|
||||
reg failed = 0;
|
||||
|
||||
initial begin
|
||||
#0;
|
||||
$display("w4 %b w8 %b wr %f", w4, w8, wr);
|
||||
if (w4 !== 1'b1) failed = 1;
|
||||
if (w8 !== 1'b1) failed = 1;
|
||||
if (wr != 1.0) failed = 1;
|
||||
|
||||
if (failed)
|
||||
$display("FAILED");
|
||||
else
|
||||
$display("PASSED");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#include <vpi_user.h>
|
||||
|
||||
static void step(void);
|
||||
|
||||
static vpiHandle w;
|
||||
|
||||
static PLI_INT32 tick_cb(struct t_cb_data *cb)
|
||||
{
|
||||
static struct t_vpi_value val = { .format = vpiIntVal };
|
||||
static int idx;
|
||||
|
||||
(void)cb;
|
||||
|
||||
++idx;
|
||||
val.value.integer = idx & 1;
|
||||
vpi_put_value(w, &val, NULL, vpiNoDelay);
|
||||
step();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Request a callback after a delay. */
|
||||
|
||||
static void step(void)
|
||||
{
|
||||
static struct t_vpi_time now = { .type = vpiSimTime, .low = 2 };
|
||||
static struct t_cb_data cbd =
|
||||
{ .reason = cbAfterDelay, .cb_rtn = tick_cb, .time = &now };
|
||||
|
||||
/* Callback after delay. */
|
||||
|
||||
vpi_register_cb(&cbd);
|
||||
}
|
||||
|
||||
/* Callback function - simulation is starting. */
|
||||
|
||||
static PLI_INT32 start_cb(struct t_cb_data *cb)
|
||||
{
|
||||
static struct t_vpi_value val = { .format = vpiIntVal };
|
||||
|
||||
(void)cb;
|
||||
|
||||
w = vpi_handle_by_name("test.w", NULL);
|
||||
if (!w)
|
||||
vpi_printf("No handle!\n");
|
||||
vpi_printf("Got handle for %s\n", vpi_get_str(vpiFullName, w));
|
||||
val.value.integer = 0;
|
||||
vpi_put_value(w, &val, NULL, vpiNoDelay);
|
||||
step();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* VPI initialisation. */
|
||||
|
||||
static void start(void)
|
||||
{
|
||||
static struct t_vpi_time now = { .type = vpiSimTime };
|
||||
static struct t_cb_data cbd = { .reason = cbStartOfSimulation,
|
||||
.time = &now, .cb_rtn = start_cb };
|
||||
|
||||
/* At this point VPI objects do not exist,
|
||||
* so request a callback once they do.
|
||||
*/
|
||||
|
||||
vpi_register_cb(&cbd);
|
||||
}
|
||||
|
||||
/* This is a table of registration functions. This table is the external
|
||||
* symbol that the VVP simulator looks for when loading this .vpi module.
|
||||
*/
|
||||
|
||||
void (*vlog_startup_routines[])(void) = {
|
||||
start,
|
||||
0
|
||||
};
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
module test(w);
|
||||
input wire w;
|
||||
wire a, b;
|
||||
|
||||
|
||||
initial begin
|
||||
#11 $finish;
|
||||
end
|
||||
|
||||
assign b = 0;
|
||||
|
||||
assign a = !w | b;
|
||||
|
||||
always @(a) begin
|
||||
$display($time, ": Wire a is now ", a);
|
||||
end
|
||||
endmodule
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Compiling vpi/br_gh1041.c...
|
||||
Making br_gh1041.vpi from br_gh1041.o...
|
||||
w4 1 w8 1 wr 1.000000
|
||||
PASSED
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
Compiling vpi/br_gh1041b.c...
|
||||
Making br_gh1041b.vpi from br_gh1041b.o...
|
||||
Got handle for test.w
|
||||
0: Wire a is now 1
|
||||
2: Wire a is now 0
|
||||
4: Wire a is now 1
|
||||
6: Wire a is now 0
|
||||
8: Wire a is now 1
|
||||
10: Wire a is now 0
|
||||
vpi/br_gh1041b.v:7: $finish called at 11 (1s)
|
||||
|
|
@ -71,6 +71,8 @@ br_gh308 normal br_gh308.c br_gh308.gold
|
|||
br_gh317 normal br_gh317.c br_gh317.gold
|
||||
br_gh496 normal,-g2009 br_gh496.c br_gh496.gold
|
||||
br_gh1037 normal,-g2009 br_gh1037.c br_gh1037.gold
|
||||
br_gh1041 normal br_gh1041.c br_gh1041.gold
|
||||
br_gh1041b normal br_gh1041b.c br_gh1041b.gold
|
||||
br_ml20191013 normal br_ml20191013.c br_ml20191013.gold
|
||||
by_index normal by_index.c by_index.gold
|
||||
by_name normal by_name.c by_name.log
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2022 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2024 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
|
||||
|
|
@ -651,18 +651,20 @@ static void draw_net_input_x(ivl_nexus_t nex,
|
|||
nex_data->flags |= nex_flags;
|
||||
|
||||
/* If the nexus has no drivers, then send a constant HiZ or
|
||||
0.0 into the net. */
|
||||
0.0 into the net. Use a lower case 'c' prefix for the
|
||||
constant to inform vvp that this is an undriven value. */
|
||||
if (ndrivers == 0) {
|
||||
unsigned wid = width_of_nexus(nex);
|
||||
int pull = (res == IVL_SIT_TRI0) || (res == IVL_SIT_TRI1);
|
||||
/* For real nets put 0.0. */
|
||||
if (signal_data_type_of_nexus(nex) == IVL_VT_REAL) {
|
||||
nex_private = draw_Cr_to_string(0.0);
|
||||
nex_private[0] = 'c';
|
||||
} else {
|
||||
unsigned jdx;
|
||||
char*tmp = malloc((pull ? 3 : 1) * wid + 5);
|
||||
nex_private = tmp;
|
||||
strcpy(tmp, pull ? "C8<" : "C4<");
|
||||
strcpy(tmp, pull ? "c8<" : "c4<");
|
||||
tmp += strlen(tmp);
|
||||
switch (res) {
|
||||
case IVL_SIT_TRI:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001-2021 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2024 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
|
||||
|
|
@ -891,9 +891,20 @@ void compile_vpi_time_precision(long pre)
|
|||
*
|
||||
* The real value is sign * (mant ** exp).
|
||||
*/
|
||||
static bool crstring_header_test(const char*str)
|
||||
{
|
||||
if ((str[0] != 'C') && (str[0] != 'c'))
|
||||
return false;
|
||||
if ((str[1] != 'r') || (str[2] != '<'))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool crstring_test(const char*str)
|
||||
{
|
||||
if (strncmp(str, "Cr<", 3) != 0) return false;
|
||||
if (!crstring_header_test(str))
|
||||
return false;
|
||||
const char*tp = strchr(str, '>');
|
||||
if (tp == 0) return false;
|
||||
if (tp[1] != 0) return false;
|
||||
|
|
@ -906,6 +917,8 @@ bool crstring_test(const char*str)
|
|||
|
||||
double crstring_to_double(const char*label)
|
||||
{
|
||||
assert(crstring_header_test(label));
|
||||
|
||||
const char*cp = label+3;
|
||||
assert(*cp == 'm');
|
||||
cp += 1;
|
||||
|
|
@ -956,14 +969,21 @@ void input_connect(vvp_net_t*fdx, unsigned port, char*label)
|
|||
|
||||
vvp_vector4_t tmp = c4string_to_vector4(label);
|
||||
|
||||
// Inputs that are constants are schedule to execute as
|
||||
// Inputs that are constants are scheduled to execute as
|
||||
// soon at the simulation starts. In Verilog, constants
|
||||
// start propagating when the simulation starts, just
|
||||
// like any other signal value. But letting the
|
||||
// scheduler distribute the constant value has the
|
||||
// additional advantage that the constant is not
|
||||
// propagated until the network is fully linked.
|
||||
schedule_set_vector(ifdx, tmp);
|
||||
// For constants that initialise an undriven net, we
|
||||
// schedule execution before time 0, to make sure it
|
||||
// occurs before any sensitive processes are started
|
||||
// or VPI callbacks are executed.
|
||||
if (label[0] == 'c')
|
||||
schedule_init_vector(ifdx, tmp);
|
||||
else
|
||||
schedule_set_vector(ifdx, tmp);
|
||||
|
||||
free(label);
|
||||
return;
|
||||
|
|
@ -973,7 +993,10 @@ void input_connect(vvp_net_t*fdx, unsigned port, char*label)
|
|||
if (c8string_test(label)) {
|
||||
|
||||
vvp_vector8_t tmp = c8string_to_vector8(label);
|
||||
schedule_set_vector(ifdx, tmp);
|
||||
if (label[0] == 'c')
|
||||
schedule_init_vector(ifdx, tmp);
|
||||
else
|
||||
schedule_set_vector(ifdx, tmp);
|
||||
|
||||
free(label);
|
||||
return;
|
||||
|
|
@ -985,7 +1008,10 @@ void input_connect(vvp_net_t*fdx, unsigned port, char*label)
|
|||
|
||||
double tmp = crstring_to_double(label);
|
||||
|
||||
schedule_set_vector(ifdx, tmp);
|
||||
if (label[0] == 'c')
|
||||
schedule_init_vector(ifdx, tmp);
|
||||
else
|
||||
schedule_set_vector(ifdx, tmp);
|
||||
free(label);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2001-2018 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2024 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
|
||||
|
|
@ -263,17 +263,17 @@ static char* strdupnew(char const *str)
|
|||
|
||||
/* Handle some specialized constant/literals as symbols. */
|
||||
|
||||
"C4<"[01xz]*">" {
|
||||
[Cc]"4<"[01xz]*">" {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
|
||||
"C8<"[01234567xz]*">" {
|
||||
[Cc]"8<"[01234567xz]*">" {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
|
||||
"Cr<m"[a-f0-9]*"g"[a-f0-9]*">" {
|
||||
[Cc]"r<m"[a-f0-9]*"g"[a-f0-9]*">" {
|
||||
yylval.text = strdup(yytext);
|
||||
assert(yylval.text);
|
||||
return T_SYMBOL; }
|
||||
|
|
|
|||
|
|
@ -1147,6 +1147,8 @@ void schedule_simulate(void)
|
|||
delete cur;
|
||||
}
|
||||
|
||||
sim_started = true;
|
||||
|
||||
if (verbose_flag) {
|
||||
vpi_mcd_printf(1, " ...execute StartOfSim callbacks\n");
|
||||
}
|
||||
|
|
@ -1154,8 +1156,6 @@ void schedule_simulate(void)
|
|||
// Execute start of simulation callbacks
|
||||
vpiStartOfSim();
|
||||
|
||||
sim_started = true;
|
||||
|
||||
signals_capture();
|
||||
|
||||
if (verbose_flag) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2004-2023 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2004-2024 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
|
||||
|
|
@ -2999,9 +2999,18 @@ vvp_vector4_t vector2_to_vector4(const vvp_vector2_t&that, unsigned wid)
|
|||
return res;
|
||||
}
|
||||
|
||||
static bool c4string_header_test(const char*str)
|
||||
{
|
||||
if ((str[0] != 'C') && (str[0] != 'c'))
|
||||
return false;
|
||||
if ((str[1] != '4') || (str[2] != '<'))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool c4string_test(const char*str)
|
||||
{
|
||||
if (strncmp(str, "C4<", 3) != 0)
|
||||
if (!c4string_header_test(str))
|
||||
return false;
|
||||
size_t value_size = strspn(str+3, "01xz");
|
||||
if (str[3+value_size] != '>')
|
||||
|
|
@ -3014,7 +3023,7 @@ bool c4string_test(const char*str)
|
|||
|
||||
vvp_vector4_t c4string_to_vector4(const char*str)
|
||||
{
|
||||
assert((str[0]=='C') && (str[1]=='4') && (str[2]=='<'));
|
||||
assert(c4string_header_test(str));
|
||||
|
||||
str += 3;
|
||||
const char*tp = str + strspn(str,"01xz");
|
||||
|
|
@ -3186,14 +3195,21 @@ vvp_vector8_t part_expand(const vvp_vector8_t&that, unsigned wid, unsigned off)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
static bool c8string_header_test(const char*str)
|
||||
{
|
||||
if ((str[0] != 'C') && (str[0] != 'c'))
|
||||
return false;
|
||||
if ((str[1] != '8') || (str[2] != '<'))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool c8string_test(const char*str)
|
||||
{
|
||||
const char*cp;
|
||||
if (str[0] != 'C') return false;
|
||||
if (str[1] != '8') return false;
|
||||
if (str[2] != '<') return false;
|
||||
if (!c8string_header_test(str))
|
||||
return false;
|
||||
|
||||
cp = str+3;
|
||||
const char*cp = str+3;
|
||||
for (;; cp += 1) {
|
||||
if (cp[0] == '>' && cp[1] == 0) return true;
|
||||
if (cp[0] >= '0' && cp[0] <= '9') continue;
|
||||
|
|
@ -3210,6 +3226,8 @@ bool c8string_test(const char*str)
|
|||
*/
|
||||
vvp_vector8_t c8string_to_vector8(const char*str)
|
||||
{
|
||||
assert(c8string_header_test(str));
|
||||
|
||||
size_t vsize = strlen(str)-4;
|
||||
assert(vsize%3 == 0);
|
||||
vsize /= 3;
|
||||
|
|
|
|||
Loading…
Reference in New Issue