chapter7
7.4 event
event e1, e2;
initial begin
$display("@%0d: 1: before trigger", $time);
-> e1;
@e2;
$display("@%0d: 1: after trigger", $time);
end
initial begin
$display("@%0d: 2: before trigger", $time);
-> e2;
@e1;
$display("@%0d: 2: after trigger", $time);
end
In the same time-slot / the different initial block will definitely run in sequential. so you have problems when using the
verilogbut the following is correct
event e1, e2;
initial begin
$display("\n@%0d: 1: before trigger", $time);
-> e1;
wait (
e2.triggered);
$display("@%0d: 1: after trigger", $time);
end
initial begin
$display("@%0d: 2: before trigger", $time);
-> e2;
wait (
e1.triggered);
$display("@%0d: 2: after trigger", $time);
end
you can see the result in the same slot
2 see more about the
wait fork( you can wait more threads to finish using
wait fork)
3 Semaphores
mutually exclusive access,” so a semaphore is known as a
mutex and is used
to control access to a resource.
You create a
semaphore with one or more keys using the
new method, get one or more keys with
get, and
return one or more keys with
put. If you want to try to get a semaphore, but
not block, use the
try_get function. It returns 1 if there are enough keys, and
0 if there are insufficient keys.
There are two things you should watch out for with semaphores. First, you
can put
more keys back than you took out. Suddenly you may have
two keys
but only
one car! Secondly, be
very careful if your testbench needs to
get and
put multiple keys. Perhaps you have
one key left, and a thread requests
two,
causing it to block. Now a second thread requests
a single semaphore – what
should happen? In SystemVerilog the
second request is blocked because of
the
fifo ordering, even
though there are
enough keys.
If you need to let smaller requests jump in before larger ones, you can
always write your
own class
program automatic test;
semaphore sem; // Create a semaphore
initial begin
sem = new(1); // Allocate with 1 key
fork
sequencer; // Spawn two threads that both
sequencer; // do bus transactions
join
end
task sequencer;
repeat($urandom%10) // Random wait, 0-9 cycles
@bus.cb;
sendTrans; // Execute the transaction
endtask
task sendTrans;
sem.get(1); // Get the key to the bus
@bus.cb; // Drive signals onto bus
bus.cb.addr <= t.addr;
...
sem.put(1); // Put it back when done
endtask
endprogram
4 mailbox
the easiest way to think about a mailbox is that it is just a
FIFO, with a
sourceand
sink. The source puts data into the mailbox, and the sink gets values from
the mailbox. Mailboxes can have a
maximum size or can be
unlimited. When
the source puts a value into a sized mailbox that is full, it blocks until data is
removed. Likewise, if a sink tries to remove data from a mailbox that is
empty, it blocks until data is put into the mailbox.
You put data into a mailbox with the
put task, and remove it with the
gettask. A
put can
block if the mailbox is
full and a
get blocks if it is
empty.
The
peek task gets a copy of the data in the mailbox but does
not remove it.
The data can be a
single value, such as an integer, or logic of
any size. You can put a handle into a mailbox, not an object. By
default, a mailbox does not have a type, so you can put
any mixof data into it.
Don’t do it! Stick to one type per mailbox
5 The solution is to make sure your loop has all three steps of constructing the object, randomizing it, and putting it in the mailbox
6 mailbox example:
program mailbox_example(bus_if.TB bus, ...);
class Generator;
Transaction tr;
mailbox mbx;
function new(mailbox mbx);
this.mbx = mbx;
endfunction
task run;
repeat (10) begin
tr = new;
assert(tr.randomize);
mbx.put(tr); // Send out transaction
end
endtask
endclass
class Driver;
Transaction tr;
mailbox mbx;
function new(mailbox mbx);
this.mbx = mbx;
endfunction
task run;
repeat (10) begin
mbx.get(tr); // Fetch next transaction
@(posedge busif.cb.ack);
bus.cb.kind <= tr.kind;
...
end
endtask
endclass
mailbox mbx; // Mailbox connecting gen & drv
Generator gen;
Driver drv;
initial begin
mbx = new;gen = new(mbx);drv = new(mbx);fork
gen.run(); // Spawn the generator
drv.run(); // Spawn the driver
join
end
endprogram
7