• SV--线程(一)


    1线程的使用

    1.1程序和模块

    •    module (模块)作为SV从Verilog继承过来的概念,自然地保持了它的特点除了作为RTL模型的外壳包装和实现硬件行为, 在更高层的集成层面,模块之间也需要通信和同步。
    •    对于硬件的过程块,它们之间的通信可理解为不同逻辑/时序块之间的通信或者同步,是通过信号的变化来完成的。
    •    从硬件实现的角度来看,Verilog通过always,initial过程语句块和信号数据连接实现进程间通信。
    •    我们可以将不同的module作为独立的程序块,他们之间的同步通过信号的变化(event触发)、等待特定事件(时钟周期)或者时间(固定延时)来完成。

    如果按照软件的思维理解硬件仿真,仿真中的各个模块首先是独立运行的线程(thread)。 

    模块(线程)在仿真一开始便并行执行, 除了每个线程会依照自身内部产生的事件来触发过程语句块之外, 也同时依靠相邻模块间的信号变化来完成模块之间的线程同步。

    •    线程即独立运行的程序。
    •    线程需要被触发, 可以结束或者不结束。
    •    在module中的initial和always,都可以看做独立的线程,它们会在仿真0时刻开始,而选择结束或者不结束。
    •    硬件模型中由于都是always语句块 , 所以可以看成是多个独立运行的线程, 而这些线程会一直占用仿真资源, 因为它们并不会结束。
    •    软件测试平台中的验证环境都需要由initial语句块去创建, 而在仿真过程中, 验证环境中的对象可以创建和销毁, 因此软件测试端的资源占用是动态的。 

    软件环境中的initial块对语句有两种分组方式 , 使用begin ... end或fork... join。

    begin ... end的语句以顺序的方式执行,而fork...join中的语句则以并发方式执行。

    与fork... join类似的并行方式语句还包括fork...join_any,fork...join_none.

    •    线程的执行轨迹是呈树状结构的, 即任何的线程都应该有父线程。
    •    父线程可以开辟若干个子线程, 父线程可以暂停或者终止子线程。
    •    当子线程终止时, 父线程可以继续执行。
    •    当父线程终止时, 其所开辟的所有子线程都应当会终止。

    2.线程的控制 

    2.1 fork.... join

    1. //fork...join
    2. initial
    3. begin
    4. $display("@%0t: start fork... join example", $time);
    5. #10 $display("@%0t: sequential after #10", $time);
    6. fork
    7. $display("@%Ot: parallel start", $time);
    8. #50 $display("@%0t:parallel after #50", $time);
    9. #10 $display("@%0t: parallel after #lO", $time);
    10. begin
    11. #30 $display("@%0t: sequential after #30", $time);
    12. #10 $display("@%0t: sequential after #10", $time);
    13. end
    14. join
    15. $display ("@%0t: after join", $time);
    16. #80 $display("@%0t: finish after #80", $time);
    17. end

    打印代码:

    @0: start fork... join example 
    @10: sequential after #10 
    @10: parallel start 
    @20: parallel after #10 
    @40: sequential after #30 
    @50: sequential after #10 
    @60: parallel after #50 
    @60: after join 
    @140: finish after #80 

    2.2 fork...join_any 

    1. //fork...join_any
    2. initial
    3. begin
    4. $display("@%0t: start fork... join_any example", $time);
    5. #10 $display("@%0t: sequential after #10", $time);
    6. fork
    7. $display("@%Ot: parallel start", $time);
    8. #50 $display("@%0t:parallel after #50", $time);
    9. #10 $display("@%0t: parallel after #lO", $time);
    10. begin
    11. #30 $display("@%0t: sequential after #30", $time);
    12. #10 $display("@%0t: sequential after #10", $time);
    13. end
    14. join_any
    15. $display ("@%0t: after join", $time);
    16. #80 $display("@%0t: finish after #80", $time);
    17. end

    打印代码:

    @0: start fork... join_any example 
    @10: sequential after #10 
    @10: parallel start 
    @10: after join_any
    @20: parallel after #10 
    @40: sequential after #30 
    @50: sequential after #10 
    @60: parallel after #50 
    @90: finish after #80 

    2.3 fork...join_none 

    1. //fork...join_none
    2. initial
    3. begin
    4. $display("@%0t: start fork... none example", $time);
    5. #10 $display("@%0t: sequential after #10", $time);
    6. fork
    7. $display("@%Ot: parallel start", $time);
    8. #50 $display("@%0t:parallel after #50", $time);
    9. #10 $display("@%0t: parallel after #lO", $time);
    10. begin
    11. #30 $display("@%0t: sequential after #30", $time);
    12. #10 $display("@%0t: sequential after #10", $time);
    13. end
    14. join_none
    15. $display ("@%0t: after join_none", $time);
    16. #80 $display("@%0t: finish after #80", $time);
    17. end

    打印代码:

    @0: start fork... join_none example 
    @10: sequential after #10 
    @10: after join_none

    @10: parallel start 
    @20: parallel after #10 
    @40: sequential after #30 
    @50: sequential after #10 
    @60: parallel after #50 
    @90: finish after #80 

    2.4 等待所有衍生线程 

    •    在SV中, 当程序中的initial块全部执行完毕, 仿真器就退出了。
    •    如果我们希望等待fork块中的所有线程执行完毕再退出结束initial块, 我们可以使用wait fork语句来等待所有子线程结束。

    1. task run_threads;
    2. ...
    3. fork
    4. check_trans(trl); //线程1
    5. check_trans(tr2); //线程2
    6. check_trans(tr3); //线程3
    7. join_none
    8. ...
    9. //等待所有fork中的线程结束再退出task
    10. wait fork;
    11. endtask

    2.5 停止单个线程

    在使用了fork.. join_any或者fork... join_none以后,我们可以使用disable来指定需要停止的线程。

    1. parameter TIME_OUT = 1000;
    2. task check_trans{Transaction tr);
    3. fork
    4. begin
    5. //等待回应,或者达到某个最大时延
    6. fork: timeout_block
    7. begin
    8. wait(bus.cb.addr == tr.addr);
    9. $display("@%0t: Addr match %d", $time, tr.addr);
    10. end
    11. #TIME_ OUT $display ("@%0t: Error: timeout, $time);
    12. join_any
    13. disable timeout_block;
    14. end
    15. join_none
    16. endtask

     2.6 停止多个线程

    disable fork可以停止从当前线程中衍生出来的所有子线程。 

    1. initial begin
    2. check_trans(trO); //线程0
    3. //创建一个线程来限制disable fork的作用范围
    4. fork//线程1
    5. begin
    6. check_trans(trl); //线程2
    7. fork//线程3
    8. check_trans(tr2); / /线程4
    9. join
    10. //停止线程1-4, 单独保留线程0
    11. #(TIME_OUT/2) disable fork
    12. end
    13. join
    14. end

     2.7 停止被多次调用的任务

    如果你给某—个任务或者线程指明标号, 那么当这个线程被调用多次以后 , 如果通过disable去禁止这个线程标号, 所有衍生的同名线程都将被禁止。

    1. task wait_for_time_out(int id);
    2. if (id == 0)
    3. fork
    4. begin
    5. #2;
    6. $display("@%0t: disable wait_for_time_out"' $time);
    7. disable wait_for_time_out;
    8. end
    9. join_none
    10. fork : just_a_little
    11. begin
    12. $display ("@%0t: %m: %0d entering thread", $time, id);
    13. #TIME_OUT;
    14. $display("@%0t: %m: %0d done", $0ime, id);
    15. end
    16. join_none
    17. endtask
    18. initial begin
    19. wait_for_time_out(0); // Spawn thread 0
    20. wait_for_time_out(1); // Spawn thread 1
    21. wait_for_time_out(2); // Spawn thread 2
    22. #(TIME_OUT*2) $display("@%0t: All done", $time);
    23. end

    •    任务wait_for_time_out被调用了三次, 从而衍生了三个线程。
    •    线程0在#2延时之后禁止了该任务,而由于三个线程均是“ 同名”线程, 因此这些线程都被禁止了, 最终也都没有完成。

  • 相关阅读:
    教育培训机构寒暑假班学校公众号小程序
    23种设计模式之创建型模式篇
    前端开发流程
    C++ - map 和 set 使用介绍
    利用nginx发布静态服务
    Python实战项目:打地鼠(源码分享)(文章较短,直接上代码)
    数据机构----线性表之单向链表
    在虚拟机中新安装的Linux无法联网解决办法
    【ECMAScript6】Symbol及其相关使用
    【容器网络】跨主通信网络实现方法之VXLAN实现原理
  • 原文地址:https://blog.csdn.net/weixin_45680021/article/details/126003463