[Edit of Image1]
Introduction
Hey it's a me again @drifter1!
Today we continue with the Logic Design series on SystemVerilog in order to cover Processes.
So, without further ado, let's dive straight into it!
Processes / Threads
Processes and threads are pieces of code that are executed separately from each other. In Verilog, such threads are created (or spawned) in-parallel at time zero for each initial
and always
block.
Fork - Join in Verilog
Additionally, Verilog also provides a fork
- join
mechanic, which is quite limited though. Basically, new threads are spawned at a fork
within some existing initial or always block, and then the main thread / process waits for all the spawned threads to finish at the next join
.
always | initial begin
// code before fork-join
fork
// thread code
join
// code after fork-join
end
Multiple Threads
It's also quite straightforward to specify multiple threads, as any block of code within the begin
and end
keywords is considered as a separate thread. For example, three separate threads can be spawned as follows:
always | initial begin
// code before fork-join
fork
// thread 1 code
begin
// thread 2 code
end
// thread 3 code
join
// code after fork-join
end
Nested Fork - Join
A fork
- join
can also be nested within another fork
- join
, allowing child threads to spawn additional child threads, taking the role of the parent thread.
always | initial begin
fork
fork
// Thread 1_0 code
begin
// Thread 1_1 code
end
join
// Thread 2 code
join
end
Fork - Join in SystemVerilog
SystemVerilog extends on the fork-join mechanic allowing two more join behaviors:
join_any
: Execute after any of the child threads finish.join_none
: Execute directly after the threads have been spawned.
That way SystemVerilog basically introduces dynamic processes, which are built using fork
- join_any
and fork
- join_none
, whilst Verilog's initial
, always
and fork
- join
could only specify static processes.
Process Control
In order to be able to control these more dynamic processes, SystemVerilog provides us with two more statements:
wait fork
: Waits for all child processes that have been called / spawned by the calling process to complete.disable fork
: Terminates all child processes (and their child processes) of the calling process.
When join_any
or join_none
has been used, then waiting for all the child processes to finish can be achieved by using the wait fork
statement as follows:
always | initial begin
fork
// spawn threads
join_any | join_none
wait fork;
end
Similarly, the spawned child processes can be killed by using the disable fork
statement:
always | initial begin
fork
fork
// Thread 1_0 code
begin
// Thread 1_1 code
end
join
// Thread 2 code
join_any | join_none
disable fork;
end
Of course, this statement also takes care of the nested child threads 1_0 and 1_1 of thread 1!
RESOURCES:
References
- https://www.chipverify.com/systemverilog/systemverilog-tutorial
- https://www.asic-world.com/systemverilog/tutorial.html
Images
Block diagrams and other visualizations were made using draw.io
Previous articles of the series
Verilog
- Introduction → Basic Syntax, Data Types, Operators, Modules
- Combinational Logic → Assign Statement, Always Block, Control Blocks, Gate-Level Modeling and Primitives, User-Defined Primitives
- Combinational Logic Examples → One Circuit - Four Implementations, Encoder, Decoder, Multiplexer
- Sequential Logic → Procedural Blocks (Initial, Always), Blocking and Non-Blocking Assignments, Statement Groups
- Sequential Logic Examples → Flip Flops (DFF, TFF, JKFF, SRFF), N-bit Counter, Single-Port RAM
- Finite-State Machines → Finite-State Machine (FSM), FSM Types, State Encoding, Modeling FSMs in Verilog
- Finite-State Machine Examples → Moore FSM Example (1 and 2 always blocks), Mealy FSM Example (1, 2 and 3 always blocks)
- Testbenches and Simulation → Testbenches (DUT / UUT, Syntax, Test Cases), System Tasks, Simulation Tools
- Combinational Logic Testbench Example → Half Adder Implementation, Testbench and Simulation
- Sequential Logic Testbench Example → Sequence Detector FSM Implementation, Testbench and Simulation
- Functions and Tasks → Function and Task Syntax, Calling, Rules, Examples
- Module Parameters and Generate Block → Parameterized Module (Parameters, Instantiation and Overriding Parameters), Generate Blocks (For, If, Case)
- Compiler Directives → Summary of Verilog's Compiler Directives (Include, Macros, Timescale, Conditional Compilation, etc.)
- Switch Level Modeling → Transistors, Switch Primitives (NMOS, PMOS, CMOS, Bidirectional, Resistive), Signal Strengths
SystemVerilog
- From Verilog To SystemVerilog → Data Types, Arrays, Structures, Operators and Expressions
- Control Flow → Additional Procedural Blocks, Loops, Conditional Statements, Functions and Task Features
Final words | Next up
And this is actually it for today's post!
Next time we will start covering interprocess communication, which is achieved using SystemVerilog Events, Semaphores and Mailboxes...
See Ya!
Keep on drifting!