Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
// 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;
|
2022-10-22 14:05:39 +00:00
|
|
|
int trig_count;
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
|
2022-10-22 14:05:39 +00:00
|
|
|
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
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
endclass
|
|
|
|
|
|
|
|
EventClass ec = new;
|
2022-10-22 14:05:39 +00:00
|
|
|
WaitClass wc = new;
|
|
|
|
LocalWaitClass lc = new;
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
|
|
|
|
initial begin
|
|
|
|
@ec.e;
|
|
|
|
ec.sleep;
|
2022-10-22 14:05:39 +00:00
|
|
|
if (wc.ok) $stop;
|
|
|
|
wc.await;
|
|
|
|
if (lc.ok) $stop;
|
|
|
|
lc.await;
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
end
|
|
|
|
|
2022-10-22 14:05:39 +00:00
|
|
|
initial #20 ec.wake;
|
|
|
|
initial #40 ->ec.e;
|
|
|
|
initial begin
|
|
|
|
wc.a = #50 4;
|
|
|
|
wc.b = #10 32;
|
|
|
|
end
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
|
|
|
|
always @ec.e begin
|
2022-10-22 14:05:39 +00:00
|
|
|
ec.inc_trig_count;
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
`WRITE_VERBOSE(("Event in class triggered at time %0t!\n", $time));
|
|
|
|
end
|
|
|
|
|
2022-10-22 14:05:39 +00:00
|
|
|
initial begin
|
|
|
|
#80
|
|
|
|
if (ec.trig_count != 3) $stop;
|
|
|
|
if (!wc.ok) $stop;
|
|
|
|
if (!lc.ok) $stop;
|
|
|
|
end
|
|
|
|
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
// =============================================
|
|
|
|
// 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;
|
2022-09-28 22:54:18 +00:00
|
|
|
`WRITE_VERBOSE(("Did assignment with delay\n"));
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
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;
|
2022-09-28 22:54:18 +00:00
|
|
|
// Test if the object is deleted before do_assign finishes:
|
|
|
|
fork dAsgn.do_assign; join_none
|
|
|
|
#5 dAsgn = null;
|
|
|
|
#15 $write("*-* All Finished *-*\n");
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
$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
|
|
|
|
|
2022-09-28 22:54:18 +00:00
|
|
|
initial #101 $stop; // timeout
|
Timing support (#3363)
Adds timing support to Verilator. It makes it possible to use delays,
event controls within processes (not just at the start), wait
statements, and forks.
Building a design with those constructs requires a compiler that
supports C++20 coroutines (GCC 10, Clang 5).
The basic idea is to have processes and tasks with delays/event controls
implemented as C++20 coroutines. This allows us to suspend and resume
them at any time.
There are five main runtime classes responsible for managing suspended
coroutines:
* `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle`
with move semantics and automatic cleanup.
* `VlDelayScheduler`, for coroutines suspended by delays. It resumes
them at a proper simulation time.
* `VlTriggerScheduler`, for coroutines suspended by event controls. It
resumes them if its corresponding trigger was set.
* `VlForkSync`, used for syncing `fork..join` and `fork..join_any`
blocks.
* `VlCoroutine`, the return type of all verilated coroutines. It allows
for suspending a stack of coroutines (normally, C++ coroutines are
stackless).
There is a new visitor in `V3Timing.cpp` which:
* scales delays according to the timescale,
* simplifies intra-assignment timing controls and net delays into
regular timing controls and assignments,
* simplifies wait statements into loops with event controls,
* marks processes and tasks with timing controls in them as
suspendable,
* creates delay, trigger scheduler, and fork sync variables,
* transforms timing controls and fork joins into C++ awaits
There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`)
that integrate static scheduling with timing. This involves providing
external domains for variables, so that the necessary combinational
logic gets triggered after coroutine resumption, as well as statements
that need to be injected into the design eval function to perform this
resumption at the correct time.
There is also a function that transforms forked processes into separate
functions.
See the comments in `verilated_timing.h`, `verilated_timing.cpp`,
`V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals
documentation for more details.
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
2022-08-22 12:26:32 +00:00
|
|
|
endmodule
|