mirror of
https://github.com/verilator/verilator.git
synced 2025-01-26 00:04:05 +00:00
fcf0d03cd4
In non-static contexts like class objects or stack frames, the use of global trigger evaluation is not feasible. The concept of dynamic triggers allows for trigger evaluation in such cases. These triggers are simply local variables, and coroutines are themselves responsible for evaluating them. They await the global dynamic trigger scheduler object, which is responsible for resuming them during the trigger evaluation step in the 'act' eval region. Once the trigger is set, they await the dynamic trigger scheduler once again, and then get resumed during the resumption step in the 'act' eval region. Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
238 lines
5.8 KiB
Systemverilog
238 lines
5.8 KiB
Systemverilog
// DESCRIPTION: Verilator: Verilog Test module
|
|
//
|
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
|
// any use, without warranty, 2022 by Antmicro Ltd.
|
|
// SPDX-License-Identifier: CC0-1.0
|
|
|
|
`ifdef TEST_VERBOSE
|
|
`define WRITE_VERBOSE(args) $write args
|
|
`else
|
|
`define WRITE_VERBOSE(args)
|
|
`endif
|
|
|
|
module t;
|
|
// =============================================
|
|
// EVENTS
|
|
class EventClass;
|
|
event e;
|
|
int trig_count;
|
|
|
|
function new;
|
|
trig_count = 0;
|
|
endfunction
|
|
|
|
task inc_trig_count;
|
|
trig_count++;
|
|
endtask;
|
|
|
|
task sleep;
|
|
@e inc_trig_count;
|
|
`WRITE_VERBOSE(("Event in class triggered at time %0t!\n", $time));
|
|
endtask
|
|
|
|
task wake;
|
|
->e;
|
|
endtask
|
|
endclass
|
|
|
|
class WaitClass;
|
|
int a;
|
|
int b;
|
|
logic ok;
|
|
|
|
function new;
|
|
a = 0;
|
|
b = 0;
|
|
ok = 0;
|
|
endfunction
|
|
|
|
task await;
|
|
wait(a == 4 && b > 16) if (a != 4 || b <= 16) $stop;
|
|
ok = 1;
|
|
`WRITE_VERBOSE(("Condition in object met at time %0t!\n", $time));
|
|
endtask
|
|
endclass
|
|
|
|
class LocalWaitClass;
|
|
logic ok;
|
|
|
|
function new;
|
|
ok = 0;
|
|
endfunction
|
|
|
|
task await;
|
|
int a = 0;
|
|
int b = 100;
|
|
fork
|
|
wait(a == 42 || b != 100) if (a != 42 && b == 100) $stop;
|
|
#10 a = 42;
|
|
join
|
|
ok = 1;
|
|
`WRITE_VERBOSE(("Condition with local variables met at time %0t!\n", $time));
|
|
endtask
|
|
endclass
|
|
|
|
EventClass ec = new;
|
|
WaitClass wc = new;
|
|
LocalWaitClass lc = new;
|
|
|
|
initial begin
|
|
@ec.e;
|
|
ec.sleep;
|
|
if (wc.ok) $stop;
|
|
wc.await;
|
|
if (lc.ok) $stop;
|
|
lc.await;
|
|
end
|
|
|
|
initial #20 ec.wake;
|
|
initial #40 ->ec.e;
|
|
initial begin
|
|
wc.a = #50 4;
|
|
wc.b = #10 32;
|
|
end
|
|
|
|
always @ec.e begin
|
|
ec.inc_trig_count;
|
|
`WRITE_VERBOSE(("Event in class triggered at time %0t!\n", $time));
|
|
end
|
|
|
|
initial begin
|
|
#80
|
|
if (ec.trig_count != 3) $stop;
|
|
if (!wc.ok) $stop;
|
|
if (!lc.ok) $stop;
|
|
end
|
|
|
|
// =============================================
|
|
// DELAYS
|
|
virtual class DelayClass;
|
|
pure virtual task do_delay;
|
|
pure virtual task do_sth_else;
|
|
endclass
|
|
|
|
`ifdef TEST_VERBOSE
|
|
`define DELAY_CLASS(dt) \
|
|
class Delay``dt extends DelayClass; \
|
|
virtual task do_delay; \
|
|
$write("Starting a #%0d delay\n", dt); \
|
|
#dt \
|
|
$write("Ended a #%0d delay\n", dt); \
|
|
endtask \
|
|
virtual task do_sth_else; \
|
|
$write("Task with no delay (in Delay%0d)\n", dt); \
|
|
endtask \
|
|
endclass
|
|
`else
|
|
`define DELAY_CLASS(dt) \
|
|
class Delay``dt extends DelayClass; \
|
|
virtual task do_delay; \
|
|
#dt; \
|
|
endtask \
|
|
virtual task do_sth_else; \
|
|
endtask \
|
|
endclass
|
|
`endif
|
|
|
|
`DELAY_CLASS(10);
|
|
`DELAY_CLASS(20);
|
|
`DELAY_CLASS(40);
|
|
|
|
class NoDelay extends DelayClass;
|
|
virtual task do_delay;
|
|
`WRITE_VERBOSE(("Task with no delay\n"));
|
|
endtask
|
|
virtual task do_sth_else;
|
|
`WRITE_VERBOSE(("Task with no delay (in NoDelay)\n"));
|
|
endtask
|
|
endclass
|
|
|
|
class AssignDelayClass;
|
|
logic x;
|
|
logic y;
|
|
task do_assign;
|
|
y = #10 x;
|
|
`WRITE_VERBOSE(("Did assignment with delay\n"));
|
|
endtask
|
|
endclass
|
|
|
|
initial begin
|
|
DelayClass dc;
|
|
Delay10 d10 = new;
|
|
Delay20 d20 = new;
|
|
Delay40 d40 = new;
|
|
NoDelay dNo = new;
|
|
AssignDelayClass dAsgn = new;
|
|
`WRITE_VERBOSE(("I'm at time %0t\n", $time));
|
|
dc = d10;
|
|
dc.do_delay;
|
|
dc.do_sth_else;
|
|
`WRITE_VERBOSE(("I'm at time %0t\n", $time));
|
|
if ($time != 10) $stop;
|
|
dc = d20;
|
|
dc.do_delay;
|
|
dc.do_sth_else;
|
|
`WRITE_VERBOSE(("I'm at time %0t\n", $time));
|
|
if ($time != 30) $stop;
|
|
dc = d40;
|
|
dc.do_delay;
|
|
dc.do_sth_else;
|
|
`WRITE_VERBOSE(("I'm at time %0t\n", $time));
|
|
if ($time != 70) $stop;
|
|
dc = dNo;
|
|
dc.do_delay;
|
|
dc.do_sth_else;
|
|
`WRITE_VERBOSE(("I'm at time %0t\n", $time));
|
|
dAsgn.x = 1;
|
|
dAsgn.y = 0;
|
|
fork #5 dAsgn.x = 0; join_none
|
|
dAsgn.do_assign;
|
|
if ($time != 80) $stop;
|
|
if (dAsgn.y != 1) $stop;
|
|
// Test if the object is deleted before do_assign finishes:
|
|
fork dAsgn.do_assign; join_none
|
|
#5 dAsgn = null;
|
|
#15 $write("*-* All Finished *-*\n");
|
|
$finish;
|
|
end
|
|
|
|
// =============================================
|
|
// FORKS
|
|
class ForkDelayClass;
|
|
task do_delay; #40; endtask
|
|
endclass
|
|
|
|
class ForkClass;
|
|
int done = 0;
|
|
task do_fork();
|
|
ForkDelayClass d;
|
|
fork
|
|
begin
|
|
#10 done++;
|
|
`WRITE_VERBOSE(("Forked process %0d ending at time %0t\n", done, $time));
|
|
end
|
|
begin
|
|
#20 done++;
|
|
`WRITE_VERBOSE(("Forked process %0d ending at time %0t\n", done, $time));
|
|
d = new;
|
|
end
|
|
begin
|
|
#30 d.do_delay;
|
|
done++;
|
|
`WRITE_VERBOSE(("Forked process %0d ending at time %0t\n", done, $time));
|
|
end
|
|
join
|
|
done++;
|
|
`WRITE_VERBOSE(("All forked processes ended at time %0t\n", $time));
|
|
endtask
|
|
endclass
|
|
|
|
initial begin
|
|
ForkClass fc = new;
|
|
fc.do_fork;
|
|
if (fc.done != 4 || $time != 70) $stop;
|
|
end
|
|
|
|
initial #101 $stop; // timeout
|
|
endmodule
|