MCDF-实验3——随机约束与环境结构

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

实验内容:

本次实验需要升级实验2中的genenrator和initiator之间的数据生成和数据传输的处理。
同时将何时结束测试的主动权讲给generator而非test。
添加monitor和checker组件。


提示:以下是本篇文章正文内容,下面案例可供参考

一、随机约束——chnl_pkg1.sv、tb1.sv

验证文件独立放置,即将chnl_pkg1.sv与tb1.sv文件独立开

1.为chnl_basic_test的数据包添加约束

需要修改数据包的约束,在chnl_trans中实现,要求如下:
在这里插入图片描述
在chnl_trans中添加约束
在这里插入图片描述
在这里插入图片描述

2.在generator中结束仿真

将chnl_root_rest中的$finish移到generator中,在数据全部发送完后结束仿真。
在这里插入图片描述
仿真结果不对
在这里插入图片描述

  • 应该是1200个对象;req600个,rsp600个,每个chnl是200个对象。
  • 下图数将种子数改为随机的仿真结果,一个是req的数据包内容,另一个是rsp的。可以从pkt_id看出chnl0完整发送了ntrans = 200个packet,但是其他通道明显没有发完200个。因此obj_id没有达到1200,所以错误原因明显是因为$finish的位置放的不对,它在完成了一个通道的任务后就停止了
    vsim -novopt -solvefaildebug -sv_seed random work.tb1

在这里插入图片描述

在这里插入图片描述

  • $finish应该放在generator何处?
    在这里插入图片描述
    仿真结果是正确的,但是仅针对ntrans = 200,不够灵活。
    $finish不能直接放入generator中(我是没想出来咋样能够放入generator来控制结束),用来控制仿真结束的应该是ntrans,这是数据包发送的个数,但是三个通道都要例化所以不能在generator中结束,这样只会在完成一个通道的任务后结束,当repeat了200次后结束gen,从而结束了agent[x].run,而要满足三个通道的agent都结束才可以。(ntrans->generator->agent[0,1,2])

二、灵活的测试控制——chnl_pkg2.sv tb2.sv

我们要实现三种测试chnl_basic_test、chnl_burst_test、chnl_fifo_full_test,同时对于不同的测试需要对generator的随机变量做出不同控制,进而控制内部随机的chnl_trans对象。
即对随机化进行分层,在test层随机化generator层,依靠gen中随机化的成员变量,在进一步随机化generator中的chnl_trans对象,由此达到顶层到底层的随机化控制。
综上,我们需要将generator从agent中迁移出来,放置在test层中。

  • chnl_generator
  class chnl_generator;
    rand int pkt_id = -1;
    rand int ch_id = -1;
    rand int data_nidles = -1;
    rand int pkt_nidles = -1;
    rand int data_size = -1;
    rand int ntrans = 10;

    mailbox #(chnl_trans) req_mb;
    mailbox #(chnl_trans) rsp_mb;

    constraint cstr{
      soft ch_id == -1;
      soft pkt_id == -1;
      soft data_size == -1;
      soft data_nidles == -1;
      soft pkt_nidles == -1;
      soft ntrans == 10;
    }

    function new();
      this.req_mb = new();
      this.rsp_mb = new();
    endfunction

    task run();
      repeat(ntrans) send_trans();
    endtask

    // generate transaction and put into local mailbox
    task send_trans();
      chnl_trans req, rsp;
      req = new();
      assert(req.randomize with {local::ch_id >= 0 -> ch_id == local::ch_id; 
                                 local::pkt_id >= 0 -> pkt_id == local::pkt_id;
                                 local::data_nidles >= 0 -> data_nidles == local::data_nidles;
                                 local::pkt_nidles >= 0 -> pkt_nidles == local::pkt_nidles;
                                 local::data_size >0 -> data.size() == local::data_size; 
                               })
        else $fatal("[RNDFAIL] channel packet randomization failure!");
      this.pkt_id++;
      $display(req.sprint());
      this.req_mb.put(req);
      this.rsp_mb.get(rsp);
      $display(rsp.sprint());
      assert(rsp.rsp)
        else $error("[RSPERR] %0t error response received!", $time);
    endtask

    function string sprint();
      string s;
      s = {s, $sformatf("=======================================\n")};
      s = {s, $sformatf("chnl_generator object content is as below: \n")};
      s = {s, $sformatf("ntrans = %0d: \n", this.ntrans)};
      s = {s, $sformatf("ch_id = %0d: \n", this.ch_id)};
      s = {s, $sformatf("pkt_id = %0d: \n", this.pkt_id)};
      s = {s, $sformatf("data_nidles = %0d: \n", this.data_nidles)};
      s = {s, $sformatf("pkt_nidles = %0d: \n", this.pkt_nidles)};
      s = {s, $sformatf("data_size = %0d: \n", this.data_size)};
      s = {s, $sformatf("=======================================\n")};
      return s;
    endfunction

    function void post_randomize();
      string s;
      s = {"AFTER RANDOMIZATION \n", this.sprint()};
      $display(s);
    endfunction
  endclass: chnl_generator

1.在root_test中连接gen和agent.init的信箱

连接信箱
在这里插入图片描述

2.在root_test中对gen进行随机化配置

  • chnl_root_test

在这里插入图片描述

  • chnl_burst_test
    在这里插入图片描述

  • chnl_fifo_full_test
    要求等到每个通道的fifo余量同时全满,停止仿真,但是对发送的数据包有要求,否则无法达到要求(上个实验一样),因此随机的ntrans个数应该大一些,我们将它定在1000-2000之间。
    在这里插入图片描述

在这里插入图片描述
在root_test中定义run_stop_callback()虚方法停止仿真,这样在运行fifo_full_test时就能执行子类的同名方法。
在这里插入图片描述


3.测试

tb2.sv对于测试的选择可以通过仿真时的参数传递来完成。
系统函数 v a l u e value valueplusarges
在这里插入图片描述
在这里插入图片描述

  • basic_test
    vsim -novopt -solvefaildebug -sv_seed 0 work.tb2
    仿真波形没问题,但打印语句有问题,ch_id一直打印的是0.
    以下操作将id传递给gen[x]
    在这里插入图片描述
    在这里插入图片描述
    还是不行,因为gen[x]在new以后调用了randomize(),而gen中定义的软约束使得ch_id=0。
    所以应该在调用randomize()时的with约束块中添加约束条件 ch_id=x。后续的测试类也应该加上。
    在这里插入图片描述
  • burst_test
    vsim -novopt -solvefaildebug -sv_seed 0 +TESTNAME=chnl_burst_test work.tb2
    gen[0].ntrtans=58,gen[1].ntrtans=5a,gen[2].ntrtans=51,合计259,打印结果obj_id=518
    ch_id也是对应的。
  • fifo_full_test
    gen[0].ntrans=69b,gen[1].ntrtans=64e,gen[2].ntrtans=7b2,合计5275,打印结果obj_id=10550
    在这里插入图片描述

三、添加monitor、checker——chnl_pkg3.sv、tb3.sv

将checker置于顶层环境,思考什么不放在agent中?

1.采样数据并存入信箱

在chnl_monitor和chnl_checker中的任务mon_trans内采样正确的数据包,并且将其写入mailbox。然后将采样的数据打印出来方便调试。

1)输入端数据监测chnl_monitor

在这里插入图片描述
利用时钟块实现在mon_trans内采样

  • 在接口内新建一个时钟块mon_ck
    在这里插入图片描述
  • 采样data并写入monitor信箱
    在这里插入图片描述
    打印语句缺少参数$time

2)输出端数据监测mcdt_monitor

  • 新建接口,因为采样的信号是mcdt的输出端信号,由实验二可以知道输出端有三个信号mcdt_data_o,mcdt_val_o,mcdt_id_o,新建接口在顶层环境将这三个信号与接口连接,这有区别于tb2.sv直接将它们在端口处声明
    在这里插入图片描述
    在这里插入图片描述
  • 采样data并写入monitor信箱
    在这里插入图片描述
    不能使用非阻塞赋值

2.在agent中例化chnl_monitor,并运行run

在这里插入图片描述

3.比较数据

在chnl_checker的任务do_compare()中取出输入端和输出端monitor中信箱里的数据,然后进行比较。

  • 【注意】:输入端有三个agent,即有三个chnl_monitor,那么就有三个缓存的数据,取出哪一个和输出端进行比较?
    不能使用foreach来取出输入端的数据,因为do_compare中只有一个结构体im,每次.get(im)都会覆盖上一次的。
    输出端有一信号为mcdt_id_o它对应的是输入端口的id,因此输出id与输入id相同的数据进行比较,使用case语句可以实现。
    在这里插入图片描述
    少了endcase

4.在root_test测试环境中连接信箱

  • 例化mcdt_monitor,chnl_checker - 连接信箱
    -
    mon中的信箱只有一个this.agents[i].mon.mon_mb = this.chker.in_mbs[i]
  • 传递虚接口
    在这里插入图片描述
    另外在top环境内传递接口时需要加上mcdt_if
    在这里插入图片描述

5.测试

  • basic_test
    vsim -novopt -solvefaildebug -sv_seed 0 work.tb3
    报错1:
    在这里插入图片描述
    这里是因为chker的例化应该放在使用这个句柄之前
    在这里插入图片描述

报错2:
在这里插入图片描述
约束冲突,在chnl_trans的约束cstr中data.size没有声明软约束soft

仿真结果与参考代码不一致,对比波形
在这里插入图片描述
ref:
在这里插入图片描述
ready信号不匹配,chnl_write任务中缺少@(negedge intf.clk);修改后仿真如下:
可以看到ch1和ch2的ready信号有误。
在这里插入图片描述
仔细检查代码后,发现data.size设置的是6,应该是发送的数据太少,没办法使fifo到达空状态。
正确的仿真波形:
在这里插入图片描述

  • burst_test
    vsim -novopt -solvefaildebug -sv_seed 0 +TESTNAME=chnl_burst_test work.tb3
    参考代码使用了旗语来控制仿真停止,每个通道的gen.run结束后放入钥匙,在得到三把钥匙后停止仿真。
    (不用旗语也可以)

  • fifo_full_test
    vsim -novopt -solvefaildebug -sv_seed 0 +TESTNAME=chnl_fifo_full_test work.tb3
    仿真波形与参考波形不同
    原因:
    至少两个slave_fifo全满时(即chx_ready_o=0),强行停止产生数据gen[x].run线程,等待数据在initiator发送完毕(即fifo全空==>margin=20),停止仿真。
    而我是直接等待gen_threads自己结束即全部数据产生完,再等待数据发送完即余量为20,,然后停止仿真。

在这里插入图片描述


如何实现至少两个slave_fifo容量停下仿真是fifo_full_test测试的难点。

  • fifo全满从设计代码中可以看到对应与ready = 0,即要求至少两个chnl的ready = 0
    在这里插入图片描述
  • 方法get_chnl_ready,用来得到该时刻三个chnl的ready值,如何得到三个chnl?返回3bit值,每一位代表一个chnl_ready即可
    在这里插入图片描述
  • 任务gen_stop_callback用来停止generator产生数据
    得到了三个ready值后还需要判定至少两个ready都为0,然后停止gen_threads线程。

1.这个条件判定是从仿真开始就一直在进行的,因此放入forever中。
2.需要触发事件gen_stop_e以执行disable来结束线程,而事件通过满足结束条件来触发。
在这里插入图片描述

  • root_test内开辟fork…join_none线程,调用任务,等待事件执行disable
    在root_test内也需要空的virtual gen_stop_callback()任务
    在这里插入图片描述

总结

1.$finish(),没有找到如何在generator中结束仿真的办法。
2.约束块中的条件语句可以使用{staement1 -> statement2;}
3.%x格式是以16进制打印
4.使用case语句可以取出相同id的数据
5.function可以利用return返回向量
6.class内不能使用initial begin…end
7.initiator中的两个信箱没有例化,req_mb与rsp_mb仅表示句柄,通过在agent中进行句柄赋值,从而指向generator中的信箱
8.chnl_generator.send_trans中的断言处约束块内local不能换成this,local::指向gen实例,this指向req

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值