Systemverilog线程之间的通信:事件【event】,旗语以及可执行代码

event作为SV的关键词,表示事件,也用来同步多个并发的进程。比如:某个进程等待着事件,而另一个进程则触发这个事件。

1. event事件在线程中的通信

0. 最简单的例子:

program test;

  event e1;

  initial begin
    $display("[%0t]Start simulation", $time);
    fork 
      begin
        $display("[%0t]Trigger the event e1", $time);
        -> e1;
      end
    join

    fork
      begin
        $display("[%0t]Received the event e1", $time);
        @e1;
      end
    join
  end

endprogram

仿真结果:

% vcs -R -sverilog -timescale=1ns/1ps basic_event_example.sv
[0]Start simulation
[0]Trigger the event e1
[0]Received the event e1

1. 在事件的边沿阻塞:在闪电出现的时候按下快门才有效

@和->必须同时发生。
如下面的例子:

program test;

  event e1, e2;
  initial begin
    $display("@%0t: Thread 1: before trigger", $time);
    -> e1;
    @e2;
    $display("@%0t: Thread 1: after trigger", $time);
  end

  initial begin
    $display("@%0t: Thread 2: before trigger", $time);
    -> e2;
    @e1;
    $display("@%0t: Thread 2: after trigger", $time);
  end
endprogram

运行结果:

@0: Thread 1: before trigger
@0: Thread 2: before trigger
@0: Thread 1: after trigger

讲解:第一个初始化块启动,触发e1,
然后阻塞在了另一个事件上。第二个初始化块启动,触发e2,唤醒第一个块儿,然后阻塞在第一个事件上。但是因为第一个事件是一个零宽度的脉冲,所以第二个线程会因为错过第一个事件而被锁住。

1.1 补充:等待事件的触发

用电平敏感的wait(e1.triggered)来代替边沿敏感的阻塞语句@,如果时间在当前已经被触发过,则不会引起阻塞;否则还是要等到事件被触发为止。

rogram test;

  event e1, e2;

  initial begin
    $display("[%0t]Start simulation", $time);
    fork 
      begin
        $display("[%0t]before the event e1", $time);
        -> e1;
        wait(e2.triggered);
        $display("[%0t]after the event e1", $time);
      end
    join
  end  

  initial begin
    fork
      begin
        $display("[%0t]before the event e2", $time);
        -> e2;
        wait(e1.triggered);
        $display("[%0t]after the event e2", $time);        
      end
    join
  end

endprogram

执行结果:

[0]Start simulation
[0]before the event e1
[0]before the event e2
[0]after the event e2
[0]after the event e1
$finish at simulation time                    0
           V C S   S i m u l a t i o n   R e p o r t 

2. 传递事件:

SV中的event可以像被参数一样传递给子程序。如下:一个事件被generator用来作为其执行完毕的标识信号:

class Generator;

  event done;
  function new(event done);
    this.done = done;
  endfunction

  task run();
    fork
      begin
        // ... process
        -> done;
        $display("Generator triggered");
      end
    join_none
  endtask
endclass

program automatic test;

  event gen_done;
  Generator gen;
  initial begin
    gen = new(gen_done);
    gen.run();
    wait(gen_done.triggered);
    $display("Generator done");
  end
endprogram

运行结果:

Generator triggered
Generator done

关于trigger:注意wait(event_name.triggered)中的triggered不是个方法,是属性,所以这里不能在triggered后加一对括号。

wait()括号中的参数不能是事件,即不能是wait(event_name),wait()括号中的参数需要是个表达式。

3. event可以被赋值

当一个event被赋值给其它事件,这样两个事件变量(句柄)会指向同一个同步化对象,触发任意一个变量就触发这个事件, 如下所示:

 program e_event;
  event event;
  event tmp;
  
  initial begin
      tmp = eve;
      #10 -> tmp;
  end
  initial begin
       wait(event.triggered);
       $display("@%0t : event trigger",$time);
  end

endprogram

执行结果

 @10 : event trigger

4. 使用wait fork等待多个线程

使用线程计数来等待多个线程
// TODO

5. Wait order

wait_order阻塞等待多个事件的触发,并且要求这多个事件按照用户决定顺序触发。wait_order可以和else一同使用,当多个事件按顺序触发时,执行wait_order后的语句,否则执行else后的语句。

module tb;
  // Declare three events that can be triggered separately
  event a, b, c;
 
  // This block triggers each event one by one
  initial begin
    #10 -> a;
    #10 -> b;
    #10 -> c;
  end
 
  // This block waits until each event is triggered in the given order
  initial begin
 
    wait_order (a,b,c) 
      $display ("Events were executed in the correct order");
    else 
        $display ("Events were NOT executed in the correct order !");  
  end
endmodule

6. 事件的合并

module tb;
  // Declare three events that can be triggered separately
  event a, b, c;
 
  // This block triggers each event one by one
  initial begin
    #10 -> a;
    #10 -> b;
    #10 -> c;
  end
 
  // This block waits until each event is triggered in the given order
  initial begin
 
    wait_order (a,b,c) 
      $display ("Events were executed in the correct order");
    else 
        $display ("Events were NOT executed in the correct order !");  
  end
endmodule

2. 旗语 semaphore

class car;
    semaphore key; // declare a key
    function new ();
        this.key=new(1); // create one key
    endfunction
 
    task drive_car(string name);
        $display("@%0t: %s wants to drive the car",$time,name);
        key.get(); // get the key
        #1ns;
        $display("@%0t: %s gets the car key",$time,name);
        #10ns;
    endtask
 
    task return_key(string name);
        $display("@%0t: %s used the car",$time,name);
        key.put(); // put back the key
        #1ns;
        $display("@%0t: %s returned the key.",$time,name);
    endtask
endclass
 
 
program test;
    car car_handle;
    string name1="Alex";
    string name2="Bob";
    string name3="Calvin";
    string name4="Denise";
 
    initial begin
       car_handle =new();
      fork 
        begin
            car_handle.drive_car(name1);
            car_handle.return_key(name1);
        end
 
        begin
            car_handle.drive_car(name2);
            car_handle.return_key(name2);
        end
 
        begin
            car_handle.drive_car(name3);
            car_handle.return_key(name3);
        end
 
        begin
            car_handle.drive_car(name4);
            car_handle.return_key(name4);
        end

      join
    end
endprogram

用VCS来执行:

vcs -R car.sv -sverilog -timescale=1ns/1ps

执行结果:

@0: Alex wants to drive the car
@0: Bob wants to drive the car
@0: Calvin wants to drive the car
@0: Denise wants to drive the car
@1000: Alex gets the car key
@11000: Alex used the car
@12000: Alex returned the key.
@12000: Bob gets the car key
@22000: Bob used the car
@23000: Bob returned the key.
@23000: Calvin gets the car key
@33000: Calvin used the car
@34000: Calvin returned the key.
@34000: Denise gets the car key
@44000: Denise used the car
@45000: Denise returned the key.
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值