forked from github/verilator
9c2ead90d5
This change introduces a custom reference-counting pointer class that allows creating such pointers from 'this'. This lets us keep the receiver object around even if all references to it outside of a class method no longer exist. Useful for coroutine methods, which may outlive all external references to the object. The deletion of objects is deferred until the next time slot. This is to make clearing the triggered flag on named events in classes safe (otherwise freed memory could be accessed).
171 lines
4.5 KiB
Systemverilog
171 lines
4.5 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;
|
|
|
|
task sleep; /* @e; */ endtask // Unsupported
|
|
task wake; ->e; endtask
|
|
endclass
|
|
|
|
EventClass ec = new;
|
|
int event_trig_count = 0;
|
|
|
|
initial begin
|
|
@ec.e;
|
|
ec.sleep;
|
|
end
|
|
|
|
initial #25 ec.wake;
|
|
initial #50 ->ec.e;
|
|
|
|
always @ec.e begin
|
|
event_trig_count++;
|
|
`WRITE_VERBOSE(("Event in class triggered at time %0t!\n", $time));
|
|
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 (event_trig_count != 2) $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
|