
event e1,e2;
initial begin
$display("@%0t: 1:before trigger", $time);
-> e1;
@e2;
$display("@%0t: 1:after trigger", $time);
end
initial begin
$display("@%0t: 2:before trigger", $time);
->e2;
@e1;
$display("@%0t: 2:after trigger", $time);
endevent创建了两个对象,不需要new。触发e1时等待e2,触发e2时等待e1。打印结果为:
@0:1:before trigger
@0:2:before trigger
@0:1:after triggere1和e2在同一时刻被触发,但是由于delta cycle的时间 差是的两个 初始化块可能无法等到e1或者e2。
更加安全的方式使用event的方法triggered()。
event e1,e2;
initial begin
$display("@%0t: 1:before trigger", $time);
-> e1;
wait (e2.tregger);
$display("@%0t: 1:after trigger", $time);
end
initial begin
$display("@%0t: 2:before trigger", $time);
->e2;
wait (e1.tregger);
$display("@%0t: 2:after trigger", $time);
end此时的打印结果为:
@0:1:before trigger
@0:2:before trigger
@0:1:after trigger
@0:2:after trigger使用wait(e1.trigger())电平敏感来代替 边沿敏感的 阻塞语句@e1。留言功能
module road;
initial begin
sutomatic begin
byd.drive();
end
endmodule
class car;
bit static = 0;
task launch();
start = 1;
$display("car is launched");
endtask
task move();
wait(start == 1);
$display("car is moving");
endtask
task drive();
fork
this.launch();
this.move();
join
endtask
endclass输出的结果car is launched
car is moving,并行 线程变为顺序触发信号。
尽管在ar::drive中同时启动了两个线程,通过共享信号car::start来判断什么时候可以行使。
如果将上述公共变量修改为event,那么通过事件的触发和判断也可以实现一样的需求。
class car;
event e_start;
task launch();
-> e_start;
$display("car is launched");
endtask
task move();
wait(e_start.triggered());
$display("car is moving");
endtask
task drive();
fork
this.launch();
this.move();
join
endtask
endclass如果汽车需要 加速的话,速度仪表盘的信息是如何显示的呢?
class car;
event e_start;
event e_speedup;
int speed = 0;
...
task speedup();
#10ns;
->e_speedup;
endtask
task display();
forever begin
@e_speedup;
speed++;
$display("speed is %0d",speed);
end
endtask
task drive();
fork
this.launch();
this.move();
this.display();
join_none
endtask
endclass
module road;
initial begin
automatic car byd = new();
byd.drive();
byd.speeduo();
byd.speeduo();
byd.speeduo();
end
endmodule
program automatic test(bus_ifc.TB.bus);
semaphore sem; //创建一个semaphore
initial begin
sem = new(1); //分配一个钥匙
fork
sequencer(); //产生两个总线实物线程
sequencer();
join
end
task sequencer;
repeat($urandom%10) //随机等待0-9个周期
@bus.cb;
sendTrans(); //执行总线事务
endTask
task sendTrans;
sem.get(1); //获取总线钥匙
@bus.cb; //把信号驱动到总线上
bus.cb.addr <= t.addr;
...
sem.put(1); //处理完成时把钥匙返回
endtask
endprogram拿了钥匙的人要还钥匙,对于线程之间 共享资源的使用方式,应该遵循互斥访问(multex access)原则。
控制线程的原因在于,如果不对其进行访问 控制,可能会 出现多个线程对同一资源的 访问,进而导致不可 预测的数据损坏和线程的异常,这种现象称之为“线程不安全”。
class car;
semaphore key;
function new();
key = new(1);
endfunction
task get_on(string p);
$display("%s is waiting for the key", p);
key.get();
#1ns;
$display("%s got on zhe car", p);
endtask
task get_off(string p);
$display("%s is got off the car", p);
key.put();
#1ns;
$display("%s return the key", p);
endtask
endlass
module family;
car byd = new();
string p1 = "husband";
string p2 = "wife";
initial begin
fork
begin // 丈夫开车
byd.get_on(p1);
byd.get_off(p1);
end
begin // 妻子开车
byd.get_on(p2);
byd.get_off(p2);
end
jion
end
endmodule
一开始给车子配置一把钥匙new(1)。虽然 丈夫和妻子在同一时间想要开这辆车子,然而只允许以为家庭成员 来驾驶。直到丈夫归还了钥匙,妻子才可以上车。
对于semaphore key使用,key在使用 前必须做初始化,即要告诉用户它原生自带几把钥匙。semaphore初始化可以初始化0,即new()无参数,可以不停的换钥匙。
semaphore::get()/put()函数中没有传递参数,即 默认他们在等待和归还钥匙的数量为1。semaphore可以被初始化为多个钥匙,也可以支持每归还多把钥匙来控制资源访问。
class carkeep;
int key = 1;
string q[$]; //队列
string user;
task keep_car();
fork
forever begin //管理钥匙和分发
wait(q.size() != 0 && key != 0);
user = q.pop_front(); //等待
key--;
end
join_none;
endtask
task get_key(string p); //拿钥匙
q.push_back(p); //把名字告诉
wait(user == p); //等待了
endtask
task put_key(string p); //还钥匙
if(user == p) begin //拿钥匙的和还钥匙的是一个人
user = "none";
key++;
end
endtask
endclass
class car;
carkeep keep;
function new();
keep = new();
endfunction
task drive();
keep.keep_car();
endtask
task get_on(string p);
$display("%s is waiting for the key", p);
keep.get_key(p);
#1ns;
$display("%s got on the car", p);
endtask
task get_off(string p);
$display("%s got off the car",p);
keep.put_key(p);
1ns;
$display("%s return the key", p);
endtask
endclass 
program automatic bounded;
mailbox mbx;
initial begin
mbx = new(1); //容量为1
fork
//线程1
for(int i =1; i<4 ; i++) begin
$display("Producer: before put(%0d)", i);
mbx.put(i);
$display("Producer: after put(%0d)", i);
end
//Consumer线程
repeat(4) begin
int j;
#1ns mbx.get(j);
$display("Consumer: after put(%0d)", j);
end
join
end
endprogram打印输出的结果为:
Producer: before put(1)
Producer: after put(1)
Producer: before put(2)
Consumer: after get(1)
Producer: after put(2)
Producer: before put(3)
Consumer: after get(2)
Producer: after put(3)
Consumer: after get(3)信箱的容量只有1,当传递进去参数 之后,需要把信箱 中内容取出,再放入新的数据。
信箱设置为1的好处是,对于动态内存不占用资源。
数据通信需求
使用mailbox通信,满足各个线程之间通信实现具体的功能
class car;
mailbox tmp_mb, spd_mb, fuel_mb;
int sample_period;
function new();
sample_period = 10; //采样
tmp_mb = new();
spd_mb = new();
fuel_mb = new();
endfunction
task sensor_tmp;
int tmp;
forever begin
std::randomize(tmp) with (tmp >= 80 && tmp <= 100;);
tmp_mb.put(tmp);
#sample_period;
end
endtask
task sensor_spd;
int spd;
forever begin
std::randomize(spd) with (spd >=50 && spd <= 60;);
spd_mb.put(spd);
#sample_period;
end
endtask
task sensor_fuel
int fuel;
forever begin
std::randomize(fuel) with (fuel >=30 && fule <=35;);
fuel_mb.put(fuel);
#sample_period;
end
endtask
task drive();
fork
sensor_tmp();
sensor_spd();
semsor_fuel();
display(tmp_mb,"temperature");
display(spd_mb,"speed");
display(fuel_mb,"feul");
join_none
endtask
task display(mailbox mb, string name="mb");
int val;
forever begin
mb.get(val);
$display("car::%s is % 0d", name ,val);
end
endtask
endclass
module road;
car byd = new();
initial begin
byd.drive();
end
endmodule
对于mailbox的用法,与FIFO使用相似。 如果我们将上述的mailbox来代替用队列
的话,则可以 修改为下面的例码。
class car;
int tmp_q[$],spd_q[$],fuel_q[$];
int sample_period;
function new();
sample_period = 10; //采样
tmp_mb = new();
spd_mb = new();
fuel_mb = new();
endfunction
task sensor_tmp;
int tmp;
forever begin
std::randomize(tmp) with (tmp >= 80 && tmp <= 100;);
tmp_q.push_back(tmp);
#sample_period;
end
endtask
task sensor_spd;
int spd;
forever begin
std::randomize(spd) with (spd >=50 && spd <= 60;);
spd_q.push_back(spd);
#sample_period;
end
endtask
task drive();
fork
sensor_tmp();
sensor_spd();
semsor_fuel();
display(tmp_mb,"temperature");
display(spd_mb,"speed");
display(fuel_mb,"feul");
join_none
endtask
task display(string name, ref int q[$]); //
int val;
forever begin
wait (q.size()>0); //只有数据不为空时
val = q.pop_front();
$display("car::%s is % 0d", name ,val);
end
endtask
endclass
module road;
car byd = new();
initial begin
byd.drive();
end
endmodule
进程间的同步需求(event同步)
class car;
event e_stall;
event e_park;
task stall;
$dsiplay("car::stall started");
#1ns;
->e_stall;
@e_park;
$display("car::stall finished");
endtask
task park;
@e_stall;
$dsiplay("car:; park started");
#1ns;
->e_park;
$display("ccar::park finished");
endtask
task drive();
fork
this.stall();
this.park();
join_none
endtask
endclass