SystemVerilog - 07 (Verification) Threads and Interprocess Communication (v05!01!2013)
SystemVerilog - 07 (Verification) Threads and Interprocess Communication (v05!01!2013)
Topics
Verilog Divisor module verification task Threads join[all] join_any join_none Variables automatic Semaphores semaphore Events event Mailboxes mailbox Building an IPC Test-Bench
[email protected] 1
SystemVerilog [Verification]
Verilog Divisor
MEMORY
INPUT-OUTPUT
CONTROL
parameter S_LO = 1'd0, S_HI = 1'd1; reg reg reg reg reg reg reg state, next_state; q, next_q; t, next_t; r, next_r; p, next_p; next_quotient, next_modulus; next_done;
// // // //
DATAPATH
http://www.dragonwins.com/domains/getteched/de248/binary_division.htm
SystemVerilog [Verification]
Verilog Divisor
MEMORY
INPUT-OUTPUT
CONTROL
DATAPATH
http://www.dragonwins.com/domains/getteched/de248/binary_division.htm
SystemVerilog [Verification]
Verilog Divisor
MEMORY
INPUT-OUTPUT
CONTROL
DATAPATH
http://www.dragonwins.com/domains/getteched/de248/binary_division.htm
SystemVerilog [Verification]
Verilog Divisor
SystemVerilog [Verification]
Threads
The parent process blocks until all the processes spawned by this fork complete.
join_any
The parent process blocks until any one of the processes spawned by this fork complete.
join_none
The parent process continues to execute concurrently with all the processes spawned by the fork. The spawned processes do not start executing until the parent thread executes a blocking statement.
SystemVerilog [Verification]
Spawning Threads
Threads
fork
fork
fork
-------------
-------------
-------------
-------------
-------------
-------------
-------------
-------------
-------------
join [all]
join_any
join_none
SystemVerilog [Verification]
fork/join [all]
fork initial begin clk = 0; #5 fork #5 a = 0; #10 b = 0; join clk = 1; end
Threads
-------------
-------------
-------------
Join [all]
clk becomes 1 at t = 15
SystemVerilog [Verification]
fork/join_any
Threads
fork
-------------
-------------
-------------
initial begin clk = 0; #5 fork #5 a = 0; #10 b = 0; join_any clk = 1; end clk becomes 1 at t = 10
join_any
SystemVerilog [Verification]
fork/join_none
Threads
fork
-------------
-------------
-------------
initial begin clk = 0; #5 fork #5 a = 0; #10 b = 0; join_none clk = 1; end clk becomes 1 at $time = 5
join_none
10
SystemVerilog [Verification]
Spawning functions/tasks
task compute_div_task( input integer a, input integer b, output integer q, output integer r); begin q = 0; r = 0; //for i = n-1...0 do where n is number of bits for (int i = 31; i >= 0; i--) begin @(posedge clk); // Clock 1 ... R by 1 bit r = r << 1; // R := R << 1 left-shift ... @(posedge clk); // Clock 2 initial begin r = r + a[i]; // R(0) := A(i) for (int j = 0; j < NUM_DIV; j = j + 1) begin if (r >= b) begin // if R >= B then fork @(posedge clk); // Clock 4 begin r = r b; // R = R - B @(poesedge clk) go[i] = 1; q[i] = 1; // Q(i) := 1 a[j] = $random( ); end b[j] = $random( ); end compute_div(a[j], b[j], q[j], r[j]); end while(~done[i]) @(poesedge clk); endtask : compute_div_task ... Whats the problem here? What happens end join_none; when multiple processes are in the same end task at the same time? endprogram;
[email protected] 11
Threads
SystemVerilog [Verification]
Spawning functions/tasks
compute_div_tasks
Threads
r
... genvar i; generate for (int i = 0; i < NUM_DIV; i = i + 1) my_div_implementation i_dut (.clk (clk), .reset_n(reset_n), .a (a[i]), .b (b[i])); endgenerate i_dut[NUM_DIV-1] ... initial begin for (int j = 0; j < NUM_DIV; j = j + 1) begin fork begin @(poesedge clk) go[i] = 1; a[j] = $random( ); b[j] = $random( ); compute_div(a[j], b[j], q[j], r[j]); while(~done[i]) @(poesedge clk); ... end join_none; end endprogram;
i_dut[0]
i_dut[1]
i_dut[NUM_DIV-2]
12
SystemVerilog [Verification]
Threads
fork
If we stop the simulator after three clock cycles, we would see the following:
join_none
[email protected]
13
SystemVerilog [Verification]
Threads
1st Thread
@(posedge clk); r = r << 1;
compute_div(7, 3)
14
SystemVerilog [Verification]
Threads
compute_div(7, 3)
1st Thread
@(posedge clk); r = r + a[i]; // //
2nd Thread
@(posedge clk); r = r << 1; // //
compute_div(4, 2)
15
SystemVerilog [Verification]
Threads
compute_div(7, 3)
compute_div(4, 2)
3nd Thread
@(posedge clk); r = r << 1; // Clock 1 // R := R << 1 left-shift R by 1 bit
16
compute_div(6, 3)
SystemVerilog [Verification]
Threads
Whats the problem here? What if we want to expand this concept to a task but dont want to explicitly call ALL variables automatic (gets to be a pain)?
17
SystemVerilog [Verification]
Threads
Verilog allows tasks to be declared as automatic so that all formal arguments and local variables are stored on the stack. SystemVerilog extends this capability by allowing specific formal arguments and local variables to be declared as automatic within a static task or by declaring specific formal arguments and local variables as static within an automatic task. [SVLRM]
18
SystemVerilog [Verification]
Spawning functions/tasks
Threads
compute_div_tasks
compute_div_tasks
compute_div_tasks
compute_div_tasks
b
a
q
b
b
a
q
b
b
a
q
b
b
a
q
b
i_dut[0]
i_dut[1]
... genvar i; generate for (int i = 0; i < NUM_DIV; i = i + 1) my_div_implementation i_dut (.clk (clk), .reset_n(reset_n), .a (a[i]), .b i_dut[NUM_DIV-2] i_dut[NUM_DIV-1] (b[i])); endgenerate ... initial begin for (int j = 0; j < NUM_DIV; j = j + 1) begin fork begin @(poesedge clk) go[i] = 1; a[j] = $random( ); b[j] = $random( ); compute_div(a[j], b[j], q[j], r[j]); while(~done[i]) @(poesedge clk); ... end join_none; end endprogram;4 19
SystemVerilog [Verification]
compute_div_tasks
compute_div_tasks
compute_div_tasks
compute_div_tasks
i_dut
... my_div_implementation i_dut (.clk (clk), .reset_n(reset_n), .a (a), .b (b)); ... initial begin for (int j = 0; j < NUM_TESTS; j = j + 1) begin fork begin @(poesedge clk) go = 1; a = $random( ); b = $random( ); compute_div(a, b, q, r); while(~done) @(poesedge clk); ... end join_none; end endprogram;
20
SystemVerilog [Verification]
semaphore
Overview
21
SystemVerilog [Verification]
semaphore
22
SystemVerilog [Verification]
semaphore
SystemVerilog [Verification]
Overview
SystemVerilog events
provides a handle to a synchronization object.
have a persistent triggered state that lasts for the duration of the entire time step. can be assigned another event variable or the special value null can be passed as arguments to tasks.
event
24
SystemVerilog [Verification]
event
Upon triggering an event, all other processes waiting on that event become are blocking until event e2 is triggered.
initial : run_second; begin We miss event e1. How can we fix this? $display(run_second: before event2 triggered); run_first: before event1 triggered -> e2; // trigger event 2 run_second: before event2 triggered @e1; // start waiting for event 1 $display(run_second: after event2 triggered)run_first: after event1 triggered end
25
SystemVerilog [Verification]
event
task run_first; $display(run_first: before event1 triggered); ->> e1; // trigger event 1 @e2; // start waiting for e2 to be 1 $display(run_first: after event1 triggered); endtask : run_first task run_second; $display(run_second: before event2 triggered); ->> e2; // trigger event 2 @e1; // start waiting for e1 to be 1 $display(run_second: after event2 triggered) endtask : run_second
26
SystemVerilog [Verification]
event
class Reciever; event input_sent; event output_taken; //=================================== // Constructor //=================================== function new (event _input_sent, _output_taken); this.input_sent = _input_sent; this.output_taken = _output_taken; endfunction task start( ); while(1) begin @input_sent; takeOutput( ); ->output_taken; end endtask : start endclass : Receiver
27
SystemVerilog [Verification]
event
event e1, e2; task run_first; $display(run_first: before event1 triggered); -> e1; // trigger event 1 wait (e2.triggered); // start waiting for e2 to be 1 $display(run_first: after event1 triggered); endtask : run_first task run_second; $display(run_second: before event2 triggered); -> e2; // trigger event 2 wait (e1.triggered); // start waiting for e1 to be 1 $display(run_second: after event2 triggered) endtask : run_second
run_first: before event1 triggered run_second: before event2 triggered run_first: after event1 triggered run_second: after event2 triggered
[email protected] 28
SystemVerilog [Verification]
event
suspends the current process until the 3 events a, b, and c are triggered.
The $wait_order system task suspends the calling process until all of the specified events are triggered (similar to $wait_all), but the events must be triggered in the given order (left to right). If an event is received out of order, the process unblocks and generates a run-time error.
$wait_order( event_identifier {, event_identifier } ) $wait_order( a, b, c);
The $wait_any system tasks suspends the calling process until any of the specified events are triggered
$wait_any( event_identifier {, event_identifier } ) $wait_any( a, b, c);
[email protected]
suspends the current process until either event a, or event b, or event c is triggered.
29
SystemVerilog [Verification]
mailbox
Inter-Process-Communication (Mailboxes) How the can be used in the verification environment Examples Bounded vs. Un-Bounded Mailboxes
30
SystemVerilog [Verification]
mailbox
There are several mechanisms that this communication link can use for sending and receiving data between the processes.
- Direct Communication - Must Explicitly name the recipient - Indirect Communication - messages are sent to mailboxes or ports
- Symmetric Communication - Both Sender and Receiver must name each other to communicate - Asymmetric Communication - Only the sender names the recipient - Automatic Buffering The link has potentially an infinite number of outstanding or un-read communiqu's (default) - Explicit Buffering - The queue has a finite length, it can be zero or more. But it is fixed. - Send by Copy Send a complete copy of the data to the recipient - Send by Reference Send a pointer or handle to the recipient - Fixed Size Messages The message can only be a predefined number of bytes or structure. - Variable Size Messages The message can be of varying length (default)
31
31
SystemVerilog [Verification]
mailbox
Mailbox
Scoreboard
Mailbox
reset() cfg_dut()
32
SystemVerilog [Verification]
mailbox
Examples
Mailbox is a built-in class that provides the following methods:
Create a mailbox: new()
33
SystemVerilog [Verification]
mailbox
Examples
Mailbox is a built-in class that provides the following methods:
To take a message from the mailbox : get()
SystemVerilog [Verification]
mailbox
Note: When a process is waiting on some event to occur, it is blocked, i.e. no other statements in that process will be executed until the last call becomes un-blocked.
Try to place a message in a mailbox without blocking: try_put() Try to retrieve a message from a mailbox without blocking: try_get() or try_peek() Retrieve the number of messages in the mailbox: num()
35
SystemVerilog [Verification]
mailbox
Note: The new() function returns the mailbox handle or, if the mailbox cannot be created, null. If the bound argument is 0, then the mailbox is unbounded (the default)
Note: The type of mailbox can be fixed to only support a specific data-type. This is called a parameterized mailbox. [This is the only kind of mailbox supported by our license.]
36
SystemVerilog [Verification]
mailbox
put ( )
class Transmitter; mailbox #(int) mb; function new (); mb = new( ); // Unbounded Mail-Box endfunction task run; for (int i = 0; i < 20; i++) mb.put(i); endtask endclass
item out. If a bounded mailbox has been specified, the process waits until there is sufficient room such that the message can be placed onto the Queue.
Must use a variable in argument list to receive data. If the mailbox is empty, the process will wait until a message gets put in the mailbox. You must use the correct data-type when puting
37
SystemVerilog [Verification]
Un-Bounded Example
class Transmitter; mailbox mb;
mailbox
module tb_mailbox; // kick off the test. mailbox_test test ( ); endmodule ( ); // mailbox used for communication. // Transmitter. // Receiver.
task run; for (int i = 0; i < 20; i++) mb.put(i); endtask endclass
class Receiver; mailbox mb; int rx_val; function new (mailbox mb); this.mb = mb; endfunction task run; for(int i = 0; i < 20; i++) begin mb.get(rx_val); $display("rx val = %d", rx_val); end endtask endclass
initial begin mb = new( ); t1 = new(mb); r1 = new(mb); fork t1.run(); r1.run(); join end endprogram
38
SystemVerilog [Verification]
mailbox
try_put ( )
class Transmitter; mailbox #(int) mb; function new (); mb = new(10); // Bounded Mail-Box endfunction task run; for (int i = 0; i < 20; i++) while (mb.try_put(i) !== 0); endtask endclass : Transmitter
the queue and the method returns a 1 (for true) If the mailbox is full, the method returns a 0
type matches the type of the message variable. Returns 0 if the mailbox is empty Returns -1 if the variable type specified does not match (and a message is available)
[email protected] 39
SystemVerilog [Verification]
PacketOut
Scoreboard
Functional
Functional
Driver
Command Signal
Command Signal
Receiver
AND
40
SystemVerilog [Verification]
//================================================================================ // pack the contents into a frame of 2bits. function new (bit [ ] data); //================================================================================ function void display ( ); function bit [number_of_inputs] pack ( ); function bit [ ] pack ( ); pack = data; function void unpack (input [] data); endfunction
//================================================================================ // unpack the contents of a frame into a given Packet. //================================================================================ function void unpack (input bit [number_of_inputs] _data); this.data = _data; endfunction : unpack endclass : PacketIn [email protected] 41
SystemVerilog [Verification]
Driver
42
SystemVerilog [Verification]
PacketOut
//=============================================================================== function new (bit _c); // pack the contents into a frame of 2bits. function void display ( ); //============================================================================= function bit [ ] pack ( ); function bit pack ( ); function void unpack (input bit data); pack = this.c; endfunction : pack
//=============================================================================== // unpack the contents of a frame into a given Packet. //=============================================================================== function void unpack (input bit data); this.c = data; endfunction : unpack endclass : PacketOut [email protected]
43
SystemVerilog [Verification]
Receiver
SystemVerilog [Verification]
Scoreboard
Functional
Functional
function new (mailbox #(PacketIn #(2)) _driver_mb, mailbox #(PacketOut) _receiver_mb); this.driver_mb = _driver_mb; this.receiver_mb = _receiver_mb; endfunction : new //===================================================================== // Start Monitoring the receiver and driver mailboxes and then compare //===================================================================== task start ( ); while(1) begin this.driver_mb.get(sentPkt); this.receiver_mb.get(rcvdPkt); #5;
if ((&sentPkt.pack( )) != rcvdPkt.pack( )) $display("Scoreboard: Packet Failed"); else $display("Scoreboard: Packet Passed"); end endtask endclass : ScoreBoard [email protected]
45
SystemVerilog [Verification]
// Testbench components handles Receiver receiver_cl; Driver driver_cl; ScoreBoard scoreboard_cl; //================================================= // constructor - to assign virtual interfaces //================================================= function new (virtual and_if.IN _INif, virtual and_if.OUT _OUTif); this.INif = _INif; this.OUTif = _OUTif; endfunction
//================================================= // Run //================================================= task run (input integer NUM_OF_TESTS = 10); this.build( ); this.reset( ); fork //================================================= this.start( ); // Instantiate the Driver, Receiver, Scoreboard for (int i = 0; i < NUM_OF_TESTS; i = i++) begin // and the 2 mailboxes. driver_cl.write( ); //================================================= receiver_cl.read( ); task build ( ); // Create the driver and receiver mailbox end driver_mb = new ( ); join_any receiver_mb = new ( ); endtask receiver_cl = new (this.OUTif, this.receiver_mb); endclass : Environment driver_cl = new (this.INif, this.driver_mb); scoreboard_cl = new (this.driver_mb, this.receiver_mb); endtask : build 46 [email protected]
SystemVerilog [Verification]
47
SystemVerilog [Verification]
endmodule : tb_top
48