Sie sind auf Seite 1von 48

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

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
Kyle.Gilsdorf@asu.edu 1

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Example implementation Module Declaration


////////////////////////////////////////////////////////////// // William L. Bahn // // FILE: division32.v // // DESCRIPTION: This module divides one integer by another // producing an integer quotient and integer remainder. // It works with 32-bit unsigned integers. ////////////////////////////////////////////////////////////// module division32( input wire [31:0] input wire [31:0] output reg [31:0] output reg [31:0] input wire output reg input wire

Verilog Divisor

MEMORY

dividend, divisor, quotient, modulus, go, done, clk, rst);

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;

[31:0] [31:0] [62:0] [62:0] [31:0]

// // // //

Working Working Working Working

Quotient Term Remainder Product

DATAPATH

parameter S_IDLE = 1'd0, S_RUN = 1'd1; Kyle.Gilsdorf@asu.edu

http://www.dragonwins.com/domains/getteched/de248/binary_division.htm

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Example implementation - Memory


//-------------------------------------------------------// FSM Registers //-------------------------------------------------------always @(posedge clk or posedge rst) begin if (rst) begin q <= 32'd0; r <= 63'd0; p <= 63'd0; t <= 32'd0; quotient <= 32'd0; modulus <= 32'd0; done <= HI; state <= S_IDLE; end else begin q <= next_q; r <= next_r; p <= next_p; t <= next_t; quotient <= next_quotient; modulus <= next_modulus; done <= next_done; state <= next_state; end end

Verilog Divisor

MEMORY

INPUT-OUTPUT

CONTROL

DATAPATH

Kyle.Gilsdorf@asu.edu

http://www.dragonwins.com/domains/getteched/de248/binary_division.htm

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Example implementation Control and Data-Path


always @* // FSM Next State Logic begin case(state) S_IDLE: begin next_t = 32'h80000000; // t = 2^31 next_p = {divisor,31'd0 }; // p = divisor*2^31 next_q = 32'd0; // q = 0 next_r = {31'd0, dividend}; // r = dividend next_quotient = quotient; next_modulus = modulus; if (go) begin next_done = LO; next_state = S_RUN; end else begin next_done = done; next_state = S_IDLE; end end S_RUN: begin next_t = {LO,t[31:1]}; // t = t/2 next_p = {LO,p[62:1]}; // p = p/2 if (p <= r) begin next_q = q + t; next_r = r - p; end else begin next_q = q; next_r = r; end if (t[0]) begin // Term == 1 next_quotient = q + ((p <= r)? t:0); next_modulus = r - ((p <= r)? p:0); next_done = HI; next_state = S_IDLE; end else begin next_quotient = quotient; next_modulus = modulus; next_done = done; next_state = S_RUN; end end endcase end endmodule

Verilog Divisor

MEMORY

INPUT-OUTPUT

CONTROL

DATAPATH

Kyle.Gilsdorf@asu.edu

http://www.dragonwins.com/domains/getteched/de248/binary_division.htm

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

program and testbench


task compute_div_task( input integer a, input integer b, output integer q, output integer r); begin q = 0; r = 0; //for i = for (int i = 31; i >= @(posedge clk); r = r << 1; @(posedge clk); r = r + a[i]; if (r >= b) begin @(posedge clk); r = r b; q[i] = 1; end end end endtask : compute_div_task program test_pi_machine (input wire clk, reset_n); integer a, b, r_gold, q_gold, r_dut, q_dut; division i_dut (.clk (clk), // I Clock .rst (rst)), // I Reset n-1...0 do where n is number of bits .dividend (a), // I [31:00] 0; i--) begin .divisor (b), // I [31:00] // Clock 1 .quotient (q_dut), // O [31:00] // R := R << 1 left-shift R by 1 . bit modulus (r_dut), // O [31:00] // Clock 2 .go (go), // I // R(0) := A(i) .done (done)); // O // if R >= B then // Clock 4 initial begin // R = R - B for (int j = 0; j < 8; j = j + 1) begin // Q(i) := 1 a = $random( ); b = $random( ); @(poesedge clk) go = 1; @(poesedge clk) go = 0; compute_div_task(a, b, q, r); while(done) (poesedge clk); if (q_gold != q_dut) $display(Error: Result was incorrect); else if (r_gold != r_dut) $display(Error: Remainder was incorrect); end end endprogram;

Verilog Divisor

Kyle.Gilsdorf@asu.edu

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Threads

Option Description: join

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.

Kyle.Gilsdorf@asu.edu

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Spawning Threads

Threads

fork

fork

fork

-------------

-------------

-------------

-------------

-------------

-------------

-------------

-------------

-------------

join [all]

join_any

join_none

Kyle.Gilsdorf@asu.edu

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & 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

Kyle.Gilsdorf@asu.edu

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & 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

Kyle.Gilsdorf@asu.edu

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & 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

Kyle.Gilsdorf@asu.edu

10

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & 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;
Kyle.Gilsdorf@asu.edu 11

Threads

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & 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]

Kyle.Gilsdorf@asu.edu

12

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Local Variables in Threads


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 rd @(posedge clk); // Clock 1 3 Thread r = r << 1; // R := R << 1 left-shift R by 1 bit @(posedge clk); // Clock 2 2nd Thread r = r + a[i]; // R(0) := A(i) if (r >= b) begin // if R >= B then @(posedge clk); // Clock 4 1st Thread r = r b; // R = R - B q[i] = 1; // Q(i) := 1 end end It turns out that each instance of the function call end endtask : compute_div_task doesnt get its on variables. They are really just at

Threads

fork

If we stop the simulator after three clock cycles, we would see the following:

join_none
Kyle.Gilsdorf@asu.edu

different places in the same task.

13

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Local Variables in Threads


task compute_div_task( input integer a, input integer b, a b q r output integer q, output integer r); 0 0 7 3 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 = r << 1; // R := R << 1 left-shift R by 1 bit @(posedge clk); // Clock 2 r = r + a[i]; // R(0) := A(i) if (r >= b) begin // if R >= B then @(posedge clk); // Clock 4 r = r b; // R = R - B // Clock 1 q[i] = 1; // Q(i) := 1 // R := R << 1 left-shift R by 1 bit end end end endtask : compute_div_task

Threads

1st Thread
@(posedge clk); r = r << 1;

Kyle.Gilsdorf@asu.edu

compute_div(7, 3)

14

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Local Variables in Threads


task compute_div_task( input integer a, input integer b, a b q r output integer q, output integer r); 0 2 4 2 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 = r << 1; // R := R << 1 left-shift R by 1 bit @(posedge clk); // Clock 2 r = r + a[i]; // R(0) := A(i) if (r >= b) begin // if R >= B then @(posedge clk); // Clock 4 r = r b; // R = R - B Clock 2 q[i] = 1; // Q(i) := 1 R(0) := A(i) end end end endtask : compute_div_task Clock 1 R := R << 1 left-shift R by 1 bit

Threads

Kyle.Gilsdorf@asu.edu

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 and Inter-Process Communication

Advanced Hardware Design & Verification

Local Variables in Threads


task compute_div_task( input integer a, input integer b, a b q r output integer q, output integer r); 0 4 6 3 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 = r << 1; // R := R << 1 left-shift R by 1 bit @(posedge clk); // Clock 2 r = r + a[i]; // R(0) := A(i) if (r >= b) begin // if R >= B then @(posedge clk); // Clock 4 1st Thread r = r b; // R = R - B @(posedge clk); // Clock 3 q[i] = 1; // Q(i) := 1 tmp <= r b; // negative end check end 2nd Thread end endtask : compute_div_task @(posedge clk); // Clock 2 r <= r + a[i]; // R(0) := A(i)

Threads

Kyle.Gilsdorf@asu.edu

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 and Inter-Process Communication

Advanced Hardware Design & Verification

local copy of specific variables: automatic


Data declared in an automatic task, function, or block have the lifetime of the call or activation and a local scope. This is roughly equivalent to a C automatic variable. [SVLRM]
initial for(int j = 1; j <= 3; ++j) fork automatic int k = j; // local copy, k, for each value of j #k $write("%0d", k); begin automatic int m = j; // the value of m is undetermined ... end join_none

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)?

Kyle.Gilsdorf@asu.edu

17

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

local copy of all variables: automatic


task automatic compute_div_task( input integer a, input integer b, output integer q, output integer r); begin q = 0; default lifetime is static r = 0; //for i = n-1...0 do where n is number of bits for (int i = 31; i >= 0; i--) begin SystemVerilog adds an optional qualifier @(posedge clk); // Clock 1 to specify the default lifetime of all r = r << 1; // R := R << 1 left-shift R by 1 bit variables declared in a task, function, or @(posedge clk); // Clock 2 block defined within a module, interface, r = r + a[i]; // R(0) := A(i) if (r >= b) begin // if R >= B then or program (see Clause 16). The lifetime @(posedge clk); // Clock 4 qualifier is automatic or static. The r = r b; // R = R - B default lifetime is static. [SVLRM] q[i] = 1; // Q(i) := 1 end end end endtask : compute_div_task

Threads

task_declaration ::= task [ lifetime ]

lifetime ::= static | automatic

Kyle.Gilsdorf@asu.edu

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]

Threads and Inter-Process Communication

Advanced Hardware Design & 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]

Kyle.Gilsdorf@asu.edu

... 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]

Multiple Tasks accessing the same DUT

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

compute_div_tasks

compute_div_tasks

compute_div_tasks

compute_div_tasks

i_dut

Kyle.Gilsdorf@asu.edu

... 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]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

semaphore
Overview

We like to visualize a semaphore as a bucket.


semaphore smTx;

Once allocated, that bucket will contain one or more keys.


smTx = new(1);

Kyle.Gilsdorf@asu.edu

21

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Basic utility functions to use semaphores

semaphore

To take a semaphore from the bucket : get()

Place the semaphore in the bucket: put()

Look into the bucket to see if there is a semaphore available: try_get()

Kyle.Gilsdorf@asu.edu

22

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Updated compute_div task


task automatic compute_div_task( input integer a, input integer b, output integer q, output integer r); begin smTx.get( ) 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 = r << 1; // R := R << 1 left-shift R by 1 bit @(posedge clk); // Clock 2 r = r + a[i]; // R(0) := A(i) if (r >= b) begin // if R >= B then @(posedge clk); // Clock 4 r = r b; // R = R - B q[i] = 1; // Q(i) := 1 end end smTx.put( ) end endtask : compute_div_task
Kyle.Gilsdorf@asu.edu 23

semaphore

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & 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

event variable_name [= initial_value];


event done; // declare a new event called done event done_too = done; // declare done_too as alias to done event empty = null; // event variable with no synchronization object
If the event is assigned null, the event becomes non-blocking, as if it were permanently triggered.

Kyle.Gilsdorf@asu.edu

24

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Triggering of Events (-> or ->>)


Named events are triggered via the -> operator.
event_trigger ::= -> hierarchical_event_identifier; | ->> [ delay_or_event_control ] hierarchical_event_identifier;

event

Non-Blocking events are triggered via the ->> operator.


The big change over Verilog events is that SystemVerilog events can remain visible for a specified duration. After triggering e1, run_first blocks and does not execute any further event e1, e2;
initial : run_first; unblocked. begin $display(run_first: before event1 triggered); -> e1; // trigger event 1 We @e2; // start waiting for e2 to be triggered $display(run_first: after event1 triggered); end

Upon triggering an event, all other processes waiting on that event become are blocking until event e2 is triggered.

Kyle.Gilsdorf@asu.edu

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]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

non-blocking after triggering of an event (->>)


Named events are triggered via the -> operator.
event_trigger ::= -> hierarchical_event_identifier; | ->> [ delay_or_event_control ] hierarchical_event_identifier;
event e1, e2;

event

Non-Blocking events are triggered via the ->> operator.

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

Events e1 and e2 will be updated in the non-blocking region of the scheduler.


run_first: before event1 triggered run_second: before event2 triggered run_first: after event1 triggered run_second: after event2 triggered

Kyle.Gilsdorf@asu.edu

26

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Variable Declaration (event)


The event data type is an enhancement over Verilog named events. SystemVerilog events provide a handle to a synchronization object. The general idea is to create a synchronization mechanism that can be passed to other tasks.
class Driver; 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); sendInput( ); ->input_sent; @output_taken; end endtask : start endclass : Driver
Kyle.Gilsdorf@asu.edu

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]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Waiting on the level of the event


This now looking at the state of the event, i.e. it is level triggered.

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
Kyle.Gilsdorf@asu.edu 28

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

event Synchronization Utilities


The $wait_all system tasks suspends the calling process until all of the specified events are triggered.
$wait_all( event_identifier {, event_identifier } ) $wait_all( a, b, c);

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);

suspends the current process until events trigger in the 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);
Kyle.Gilsdorf@asu.edu

suspends the current process until either event a, or event b, or event c is triggered.
29

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

mailbox
Inter-Process-Communication (Mailboxes) How the can be used in the verification environment Examples Bounded vs. Un-Bounded Mailboxes

Kyle.Gilsdorf@asu.edu

30

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Mailboxes as a Software Concept


In software, we use a message passing system to allow processes to communicate with each other without needing to resort to using some sort of shared data. For example, we could have two processes P and Q, who would like to send messages to each other. They do so, using a communication link as illustrated below:

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

Kyle.Gilsdorf@asu.edu

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

How to use them in Verification Environment

mailbox

Mailbox

Scoreboard

Mailbox

Generator & Driver

Device Under Test

receiver(s) receiver(s) receiver(s) receiver(s)

reset() cfg_dut()

Kyle.Gilsdorf@asu.edu

32

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

mailbox
Examples
Mailbox is a built-in class that provides the following methods:
Create a mailbox: new()

Place a message in a mailbox: put()

What happens when our mailbox is full?

Kyle.Gilsdorf@asu.edu

33

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

mailbox
Examples
Mailbox is a built-in class that provides the following methods:
To take a message from the mailbox : get()

To look at a message in the mailbox without taking it out: peek()

What happens when our mailbox is empty?


Kyle.Gilsdorf@asu.edu 34

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

How does it work when I ...?


Question: What happens when our mailbox is empty and we try to get or peek? Answer: We stand around waiting for a the mailbox to become a little less full or have at least one message. Question: What happens when our mailbox is full and we try to put?

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()

Kyle.Gilsdorf@asu.edu

35

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Instantiation Mailboxes are created with the new() method.


Un-Bounded Mail-Box Example
mailbox mb; // mailbox used for communication. initial begin mb = new ( ); // Unbounded Mailbox end

mailbox

Bounded Mail-Box Example


mailbox mb; // mailbox used for communication. initial begin mb = new (32); // 32-Element Deep MB end

Parameterized Mail-Box Example


class bus_trans; enum {READ, WRITE} kind; endclass : bus_trans;

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)

class bus_master; ... mailbox #(bus_trans) inbox;


function new(..., bux_trans_mbox inbox); ... this.inbox = inbox ...

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.]

Kyle.Gilsdorf@asu.edu

36

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

(Putin and Getin in a UnBounded World)


get ( )
class Reciever; mailbox #(int) mb; function new (); mb = new( ); // Unbounded Mail-Box endfunction task run; int i = 0; begin while(1) begin mb.get(i); $display(Item %i, i); i++; end end endtask endclass

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

A mailbox is a Queue, i.e. the first item in is the first

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

message into the mailbox, or your simulation will die.


Kyle.Gilsdorf@asu.edu

37

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Un-Bounded Example
class Transmitter; mailbox mb;

mailbox

Reminder: Objects are passed by reference, e.g. a mailbox is an object.

function new (mailbox mb); this.mb = mb; endfunction

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

program mailbox_test mailbox mb; Transmitter t1; Receiver r1;

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

// Create new objects.

// Fork off the processes.

Kyle.Gilsdorf@asu.edu

38

SystemVerilog [Verification]

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

(Putin and Getin in a Bounded World)


try_get ( )
class Receiver; mailbox #(int) mb; function new (); mb = new(10); // Unbounded Mail-Box endfunction task run; int i; begin while(1) begin while(~mb.try_get(i)) #10; $display(Item %i, i); end end endtask endclass : Reciever

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

If the mailbox is not full, the message is placed on

the queue and the method returns a 1 (for true) If the mailbox is full, the method returns a 0

Returns 1 if the mailbox is not empty and the message

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)
Kyle.Gilsdorf@asu.edu 39

SystemVerilog [Verification]

A complete Example (and gate)


The big picture
PacketIn (int Number of Inputs)
bit [ ] data; function new function void display function bit [ ] pack function void unpack (bit [ ] data); ( ); ( ); (input [] data); bit c; function function void function bit function void new display pack unpack (bit _c); ( ); ( ); (input bit data);

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

PacketOut

Scoreboard

Functional

Functional

Driver

Command Signal

Command Signal

Receiver

AND

Kyle.Gilsdorf@asu.edu

40

SystemVerilog [Verification]

A complete Example (and gate)


test.sv PacketIn class
class PacketIn #(parameter number_of_inputs = 2); bit [number_of_inputs] data; //================================================================================ // new( ) Objects Allocated and Initialized via call to the new // Constructor Method. Set the fields to values passed from argument default = 0. //================================================================================ function new (bit [number_of_inputs] _data = 0); this.data = _data; endfunction //================================================================================ // display( ) - Display the contents of the packet in a formatted way. //================================================================================ function void display ( ); endfunction : display

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

PacketIn (int Number of Inputs)


bit [ ] data;

//================================================================================ // 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 Kyle.Gilsdorf@asu.edu 41

SystemVerilog [Verification]

A complete Example (and gate)


class.sv Driver class
class Driver; //========================================== // Attributes //========================================== virtual and_if.IN INif; // Packet to be written PacketIn #(2) sentPkt; // mailbox handle mailbox #(PacketIn #(2)) driver_mb; //========================================== // Constructor //========================================== function new (virtual and_if.IN _INif, mailbox #(PacketIn #(2)) _driver_mb); $display("%t [Driver] new( )", $time); this.INif = _INif; this.driver_mb = _driver_mb; endfunction task write ( ); sentPkt = new($random( )); $display("%t [Driver] write(%b)", $time, sentPkt.data); // Apply the randomly generated packet to the interface this.INif.in = sentPkt.pack( ); // Send a copy of the packet, just sent, to the score-board this.driver_mb.put(sentPkt); #10; endtask : write endclass : Driver Kyle.Gilsdorf@asu.edu

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Driver

42

SystemVerilog [Verification]

A complete Example (and gate)


class.sv PacketOut class
class PacketOut; bit c; //================================================================================ // new( ) Objects Allocated and Initialized via call to the new // Constructor Method. Set the fields to values passed from argument default = 0. //================================================================================ function new (bit _c = 1'b0); this.c = _c; endfunction //=============================================================================== // display the contents of the packet in a formatted way. //=============================================================================== function void display ( ); $display("C[%b]", c); endfunction : display bit c;

Threads and Inter-Process Communication

Advanced Hardware Design & 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 Kyle.Gilsdorf@asu.edu
43

SystemVerilog [Verification]

A complete Example (and gate)


class.sv Receiver class
class Receiver; // Interfaces virtual and_if.OUT OUTif; PacketOut rcvdPkt; // mailbox handle mailbox #(PacketOut) receiver_mb; function new (virtual and_if.OUT _OUTif, mailbox #(PacketOut) _receiver_mb); $display("%t [Receiver] new( )", $time); this.OUTif = _OUTif; this.receiver_mb = _receiver_mb; endfunction
task read ( ); // Create a new packet that will be filled with the results from the // device under test rcvdPkt = new ( ); // Take the data from the output interface of the device under test $display("%t [Receiver] read(%b)", $time, this.OUTif.out); rcvdPkt.unpack(this.OUTif.out); // Push the packet to the Scoreboard's receiver mailbox this.receiver_mb.put(rcvdPkt); #10; endtask : read endclass : Receiver
Kyle.Gilsdorf@asu.edu 44

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

Receiver

SystemVerilog [Verification]

A complete Example (and gate)


class.sv Scoreboard class
class ScoreBoard; //===================================================================== // mailbox instantiations //==================================================================== mailbox #(PacketIn #(2)) driver_mb; mailbox #(PacketOut) receiver_mb; PacketOut rcvdPkt; PacketIn #(2) sentPkt;

Threads and Inter-Process Communication

Advanced Hardware Design & 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 Kyle.Gilsdorf@asu.edu

45

SystemVerilog [Verification]

A complete Example (and gate)


class.sv Environment class
class Environment; // Mailbox Instantiation mailbox #(PacketIn #(2))driver_mb; mailbox #(PacketOut )receiver_mb; virtual and_if.IN virtual and_if.OUT INif; OUTif; //==================================================== // Reset the DUT by driving all input signals low // for 10 clocks and de-assert reset signal. //==================================================== task reset ( ); this.INif.in = 0; endtask : reset //========================================== // Start the Scoreboard. //========================================== task start ( ); scoreboard_cl.start( ); endtask

Threads and Inter-Process Communication

Advanced Hardware Design & 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 Kyle.Gilsdorf@asu.edu

SystemVerilog [Verification]

A complete Example (and gate)


test.sv and interface.sv
program automatic test(and_if.IN _INif, and_if.OUT _OUTif); Environment env; initial begin env = new(_INif, _OUTif); env.run(20); $finish; end endprogram : test

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

interface and_if #(NUM_INPUTS = 2); logic [NUM_INPUTS-1: 0] in; wire out;


modport IN (output in); modport OUT (input out); endinterface

Kyle.Gilsdorf@asu.edu

47

SystemVerilog [Verification]

A complete Example (and gate)


tb_top.sv
module tb_top ( ); // Testbench parameters assets parameter NUM_OF_INPUTS_FOR_AND_GATE = 2; //=========================================================== // We instantiate the and_if interface without clock (why?) //=========================================================== and_if #(2) AndIfInst( ); //============================================================ // This is our test that creates all of the objects necessary // for driving and receiving data from our DUT. //============================================================ test i_test (AndIfInst.IN, AndIfInst.OUT); //============================================================ // Module being tested //============================================================ my_and #(NUM_OF_INPUTS_FOR_AND_GATE) i_dut (.a(AndIfInst.IN.in), .c(AndIfInst.OUT.out));
Kyle.Gilsdorf@asu.edu

Threads and Inter-Process Communication

Advanced Hardware Design & Verification

endmodule : tb_top

48

Das könnte Ihnen auch gefallen