verilator/test_regress/t/t_timing_class.v
Krzysztof Bieganski 43fa6858f6
Fix VlForkSync redeclaration (#4277)
Given nested forks, if the inner fork had a `join` or `join_any` at the end,
`V3Sched::transformForks()` would decide that the fork's `VlForkSync` variable
should be passed in from the outside. This resulted in the `VlForkSync` getting
redeclared as a function argument. Ultimately, it led to C++ compilation errors
due to variable redeclaration.

Fixed by rearranging the `if`s that decide whether a variable should be passed
in or left as-is.
2023-06-15 07:49:50 -04:00

248 lines
6.0 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
class BaseClass;
virtual task sleep;
endtask
virtual task await;
endtask
endclass
module t;
// =============================================
// EVENTS
class EventClass extends BaseClass;
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 extends BaseClass;
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 extends BaseClass;
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
fork
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
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