巧用fork—join_none启用后台进程


前言

聊一聊最近遇到的一个问题,巧妙的利用fork——join_none启动后台进程,实现了进程之间的并行处理。


1 问题描述

问题是要写一个监控模块的run_phase实现数据包的收集工作,收集完后,再将数据包发送给scoreboard。

DUT如下图所示。
1)输入信号包括vld_in、id_in[3:0]、src1[63:0]、src2[63:0],输出信号包括vld_out、id_out、sum。
2)接口时序是,当vld_in有效时,id_in和src1有效,src2要第3个时钟周期才有效。
3)ap.write(trans_pkt),virtual interface = vif。
在这里插入图片描述

2 问题分析

通过对上述问题的分析,主要的问题在于src2的收集。因为src2要在vld_in有效后,第3个时钟周期才有效,那么会造成第一个数据包还没收集完成,第二个数据包就来了。

这个时候,我们首先会想到通过fork——join的方式,开启多个进程来进行数据的收集。但是,仔细一想又不行,fork——join要等所有的进程都处理完成后,才会往下继续,而这里的需求是,第一个数据包收集工作开启后,就要将这个进程一直挂着,直到全部数据的收集完成,而且还不能阻塞对下一个数据包的收集工作。

这么一分析,自然就想到了fork——join_none,具体思路是,将每一个数据包的收集工作,单独作为一个进程,利用fork——join_none将进程放入后台直至其完成,同时也不影响前台对新来数据包的收集工作。

3 解决方案

3.1 monitor

编写monitor run_phase的代码如下,在monitor的run_phase中,通过forever进行循环,执行前台进程,当时钟上升沿vld_in为1时,则说明有一个数据包需要收集,那么就通过fork——join_none启用一个后台进程。

在这个后台进程中,先构造一个数据包,将id_in和src1的数据收集起来,然后再等待3个时钟上升沿,在第3个时钟上升沿的地方,收集src2的数据,完成整个数据包的收集,最后再将收集好的数据通过ap.write(pkt)发送出去。

在后台进程执行过程中,前台进程也在执行,从而保证不丢掉数据包。

同时注意到,由于src2有效晚于vld_in有效3个时钟周期,所以这里最大的后台进程深度是3。

//monitor run_phase:
task run_phase(phase)
   trans_pkt pkt;
   forever begin
       @posedge vif.clk;
       if(vif.vld_in == 1)
       fork 
           pkt = new();
           pkt.id_in = vif.id_in;
           pkt.src1 = vif.src1;
           repeat(3) @posedge vif.clk;
           pkt.src2 = vif.src2;
           ap.write(pkt);
       join_none
   end
endtask : run_phase

3.2 driver

为了测试上述的monitor代码的可行性,同时编写了driver的代码供参考。同样用到了fork——join_none启动后台进程进行发送。

要注意的是,这里将vld_in作为数据包中的一个控制字段,当发送无效包时,需要将该字段约束为0。

//driver run_phase:
task run_phase(phase)
forever begin
    trans_pkt pkt;
    seq_item_port.get_next_item(pkt);
    // write send task in here 
    fork
        send(pkt);
    join_none
    seq_item_port.item_done();
end
endtask : run_phase

task driver::send(trans_pkt pkt);
 begin
    // send id_in and src1
    @(posedge vif.clk);
    vif.vld_in <= pkt.vld_in;
    vif.id_in <= pkt.id_in;
    vif.src1 <= pkt.src1;
    //clear id_in and src1
    @(posedge vif.clk);
    vif.vld_in <= 0;
    vif.id_in <= 0;
    vif.src1 <= 0;

    //send src2
    repeat(2) @(posedge vif.clk);
    vif.src2 <= pkt.src2;
    //clear src2
    @(posedge vif.clk);
    vif.src2 <= 0;
end
endtask : send



总结

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值