1. Semaphore
If the process execution is regarded as the behavior of "driving", a key is required for driving, and the semaphore is similar to "key". A thread must first apply for a key (semaphore) to execute. If there is only one key (semaphore) and it is applied for by other threads, then this thread is blocked. When that thread finishes executing, the key (semaphore) is returned, and the blocked thread can apply for the key (semaphore) again.
Semaphores can be used when multiple processes share resources.
-
The new method creates one or more semaphores
-
get gets one or more semaphores, if the get fails to block
-
put returns one or more semaphores
-
try_get() tries to get the semaphore, but does not block. A return of 1 indicates that there are enough semaphores, and a return of 0 indicates that there are not enough semaphores.
program automatic test; semaphore sem; //create a semaphore initial begin sem = new(1); //allocate a key run(); end task run(); sem.get(1); //apply for a key ; At this time, if other processes apply for the key of this semaphore, they will be blocked. .... // Use resource sem.put(1); // Execution ends, return key endtask endprogram
2. Mailbox mailbox
Mailboxes are used to pass transactions between multiple threads, such as between generators and drivers.
The mailbox is similar to a FIFO, first in first out.
Adding an object to a fixed-capacity full mailbox will block; fetching an object from an empty mailbox will also block.
A letterbox is an object and needs to be instantiated.
get, put, peak (peek takes a copy of the object's data, but does not delete it).
It is best to put only one type of data in the mailbox. (Although it is not wrong to put different data syntax).
The mailbox is actually a parameter class, which can specify the type of data in the mailbox.
The handle (pointer) is stored in the mailbox. If only one object is new, but it is randomized many times, then the object stored in the mailbox is one.
initial begin
mailbox mlb#(Transaction); //指定类型
Transaction tr,tmp;
repeat(10) begin
tr = new(); // 在循环内创建对象
assert(tr.randomize());
mlb.put(tr); //存入mlb
end
repeat(10) begin
mlb.get(tmp); //从mlb取
tmp.show();
end
end
2.1 Synchronize using fixed-volume mailboxes
class Transaction;
rand bit[7:0] data;
rand bit[7:0] addr;
endclass
class Generator;
mailbox mlb;
Transaction tr;
function new(mailbox m);
this.mlb= m;
endfunction
task run();
repeat(5) begin
tr=new();
assert(tr.randomize());
mlb.put(tr);
$display("@ %0t [gen] put a tr",$time);
end
endtask
endclass
class Driver;
mailbox mlb;
Transaction tr;
function new(mailbox m);
this.mlb= m;
endfunction
task run();
forever begin
#10; //每延迟10ns,driver取一个数据,也可以同步到时钟沿@(posedge clk);
mlb.get(tr);
$display("@ %0t [drv] get a tr",$time);
end
endtask
endclass
program automatic tb;
Generator gen;
Driver drv;
mailbox mlb;
initial begin
mlb=new(1);//定容信箱,容量1,如果参数为空,则mailbox不限容量
gen=new(mlb);
drv=new(mlb);
fork // 并发执行
gen.run();
drv.run();
join
end
endprogram
// output
@ 0 [gen] put a tr
@ 10 [drv] get a tr
@ 10 [gen] put a tr
@ 20 [drv] get a tr
@ 20 [gen] put a tr
@ 30 [drv] get a tr
@ 30 [gen] put a tr
@ 40 [drv] get a tr
@ 40 [gen] put a tr
@ 50 [drv] get a tr
As can be seen from the output, put a tr, block the put operation, then get a tr, and then put and so on.
2.2 Using Mailboxes and Events to Synchronize
program automatic tb;
event handshake; // 事件
mailbox mlb;
class Generator;
...
task run();
repeat(5) begin
...
mlb.put(tr);
$display("@ %0t [gen] put a tr",$time);
@handshake; //生成完一个tr后阻塞。
end
endtask
endclass
class Driver;
...
task run();
forever begin
#10;
mlb.get(tr);
$display("@ %0t [drv] get a tr",$time);
->handshake; //获取完一个tr后触发事件
end
endtask
endclass
Generator gen;
Driver drv;
initial begin
mlb=new(); //无限容量
gen=new(mlb);
drv=new(mlb);
fork ... join_none
end
endprogram
@ 0 [gen] put a tr
@ 10 [drv] get a tr
@ 10 [gen] put a tr
@ 20 [drv] get a tr
@ 20 [gen] put a tr
@ 30 [drv] get a tr
@ 30 [gen] put a tr
@ 40 [drv] get a tr
@ 40 [gen] put a tr
@ 50 [drv] get a tr
2.3 Synchronize using two mailboxes
program automatic tb;
mailbox#(Transaction) mlb;
mailbox#(int) m; // 定义两个信箱
class Generator;
Transaction tr;
int i;
task run();
repeat(5) begin
tr=new();
assert(tr.randomize());
mlb.put(tr);
$display("@ %0t [gen] put a tr",$time);
m.get(i); //m为空,阻塞
end
endtask
endclass
class Driver;
Transaction tr;
int i;
task run();
forever begin
#10;
mlb.get(tr);
$display("@ %0t [drv] get a tr",$time);
m.put(i); // m不为空,触发了Generator中的语句。
end
endtask
endclass
Generator gen;
Driver drv;
initial begin
mlb=new();
m=new(); //新建信箱
gen=new();
drv=new();
fork
gen.run();
drv.run();
join
end
endprogram
@ 0 [gen] put a tr
@ 10 [drv] get a tr
@ 10 [gen] put a tr
@ 20 [drv] get a tr
@ 20 [gen] put a tr
@ 30 [drv] get a tr
@ 30 [gen] put a tr
@ 40 [drv] get a tr
@ 40 [gen] put a tr
@ 50 [drv] get a tr