MCDF实验4(3)

目录

1. 对整个 MCDF_pkg.sv 的 结构的理解

 2. mcdf_reg_t

 3. 对  mcdf_refmod 的理解

3.1 对 run() 里的 do_reset() 进行解释

3.2 对 run() 里的 do_reg_updata() 进行解释

3.3 对run() 里的do_packet()进行解释

4. 对 mcdf_checker 中的 do_compare()进行代码解释

5. 对 mcdf_env 的理解

6. 对mcdf_base_test 的理解


1. 对整个 MCDF_pkg.sv 的 结构的理解

mcdf_checker 包含了 reg_mb 实例 chnl_mb 实例 , fmt_mb 实例 ,和 mcdf_refmod 参考模型,以及 do_compare()比较功能

其中, refmod 是用来模拟 硬件的行为的, 它包括

reg_mb 句柄 :

用来接收从reg_pkg中的 monitor 监测到的寄存器的信号(cmd,addr,data) 

in_mbs[0] 句柄  in_mbs[1]  句柄  in_mbs[2] 句柄 :

用来接收 从chnl_pkg中的 monitor 监测到的 chnnel 的数据 (data)

out_mbs[0] 实例 out_mbs[1] 实例 out_mbs[2] 实例  :

用来对 in_mbs[i] 中的数据进行分别打包

以及 两个 do_reg_update()  和 do_packet():

对监测到的数据和信号 进行寄存器的内容的更新和 对 chnnel 的数据打包成 fmt_trans 形式的数据包, 并输出到 out_mbs[i] 中

refmod 模拟了硬件的行为,数据传输 和 数据打包 和 寄存器更新; 没有模拟arbiter 的仲裁 和 数据的优先级,以后可加入这些模拟。

remod 完成了它的功能了之后,在 do_cmpare() 里 与 从fmt 的 monitor 检测到的数据包进行比较。其中 fmt 最终形成了一个数据包, 而在 refmod 中形成了3个数据包,怎么比较呢? 通过得知 fmt  数据包的 id, 然后把那个 id 的 在 refmod 中 一个拿出来进行比较。

reg_mb chnl_mb fmt_mb 与 各自 agent 中的 monitor 中的 mon_mb 句柄的连接 ,在更大的 mcdf_env 类中实现

先实例化,再连接句柄

句柄与实例的连接,要在它们所在的公共层

比如 mcdf_checker 中的 reg_mb 实例 和 monitor 中的 mon_mb 句柄 就要在它们的公共顶层 mcdf_env 中 连接:this.reg_agt.monitor. mon_mb = this.chker.reg_mb;

以及它里面的一层refmod 中的 reg_mb 句柄 就要在它们的公共层 mcdf_checker 中 连接:

this.refmod.reg_mb = this.reg_mb;

其他的情况是一样的,只有refmod 中的 三个out_mbs[i] 实例, 在mcdf_checker 中也声明了三个句柄,指向这三个实例,exp_mbs[i] 

并在 mcdf_checker 中连接:

this.exp_mb[i] = this.refmod.out_mbs[i];

为了之后挑选出一个与 fmt_mbs 进行比较(比较的不是句柄 而是句柄指向的mailbox 中存放的数据)

 

 2. mcdf_reg_t

 在定义 mcdf_refmod 之前 , 先定义了 refmod 要用到的 为了模拟硬件的寄存器的

结构体 mcdf_reg_t 如下图所示

 3. 对  mcdf_refmod 的理解

mcdf_refmod() 用来 模拟硬件的功能的两个任务:do_reg_update() 更新寄存器的内容和 do_packet() 对chnl 的 数据进行打包 ,完成的对应的硬件功能如下图示意

3.1 对 run() 里的 do_reset() 进行解释

3.2 对 run() 里的 do_reg_updata() 进行解释

从monitor 检测到的寄存器的数据内容,进而对我们的参考模型里的寄存器进行实时更新,

对读写寄存器 没有必要更新读操作 因为你读到的数 就是你写进去的数 没有意义

3.3 对run() 里的do_packet()进行解释

两种写法: 其中 wait(this.in_mbs[id].num() >0)  和  this.in_mbs[id].peek(it) 

功能是一样的, 目的就是在打包之前 确保 in_mbs[id] 不为空, wait 会一直等待,peek()是复制mailbox的内容,为空的话就阻塞。

 

class mcdf_refmod 完整代码如下:

class mcdf_refmod;
    local virtual mcdf_intf intf;
    local string name;
    mcdf_reg_t regs[3];   // 只声明了三个寄存器,因为把 只读 和 读写 放在了一起
    mailbox #(reg_trans) reg_mb;
    mailbox #(mon_data_t) in_mbs[3];
    mailbox #(fmt_trans) out_mbs[3];

    function new(string name="mcdf_refmod");
      this.name = name;
      foreach(this.out_mbs[i]) this.out_mbs[i] = new();
    endfunction

    task run();
      fork
        do_reset();
        this.do_reg_update();
        do_packet(0);
        do_packet(1);
        do_packet(2);
      join
    endtask

    task do_reg_update();
      reg_trans t;
      forever begin
        this.reg_mb.get(t); 
        if(t.addr[7:4] == 0 && t.cmd == `WRITE) begin
          this.regs[t.addr[3:2]].en = t.data[0];
          this.regs[t.addr[3:2]].prio = t.data[2:1];
          this.regs[t.addr[3:2]].len = t.data[5:3];
        end
        else if(t.addr[7:4] == 1 && t.cmd == `READ) begin
          this.regs[t.addr[3:2]].avail = t.data[7:0];
        end
      end
    endtask

    task do_packet(int id); // id = 0,1,2
      fmt_trans ot;
      mon_data_t it;
	  bit[2:0] len;
      forever begin
        this.in_mbs[id].peek(it);  // 
        ot = new();
        len = this.get_field_value(id, RW_LEN); // 返回对应寄存器的对应的内容 也称域
        ot.length = len > 3 ? 32 : 4 << len;   // 对应的就是 len = 0 length = 4;  len = 1 length = 8;  len = 2 length = 16;  len = 3 length = 32;
        ot.data = new[ot.length];              // 4左移0位是4  4左移1位是8  4左移2位是16  4左移3位是32
        ot.ch_id = id;  
        foreach(ot.data[m]) begin
          this.in_mbs[id].get(it);  // 
          ot.data[m] = it.data;
        end
        this.out_mbs[id].put(ot);
      end
    endtask

    function int get_field_value(int id, mcdf_field_t f);
      case(f)
        RW_LEN: return regs[id].len;
        RW_PRIO: return regs[id].prio;
        RW_EN: return regs[id].en;
        RD_AVAIL: return regs[id].avail;
      endcase
    endfunction 

    task do_reset();
      forever begin
        @(negedge intf.rstn); 
        foreach(regs[i]) begin
          regs[i].len = 'h0;
          regs[i].prio = 'h3;
          regs[i].en = 'h1;
          regs[i].avail = 'h20;
        end
      end
    endtask

    function void set_interface(virtual mcdf_intf intf);
      if(intf == null)
        $error("interface handle is NULL, please check if target interface has been intantiated");
      else
        this.intf = intf;
    endfunction
    
  endclass

4. 对 mcdf_checker 中的 do_compare()进行代码解释

 class mcdf_checker 完整代码如下:

  class mcdf_checker;
    local string name;
    local int err_count;
    local int total_count;
    local int chnl_count[3];
    local virtual mcdf_intf intf;
    local mcdf_refmod refmod;
    mailbox #(mon_data_t) chnl_mbs[3];
    mailbox #(fmt_trans) fmt_mb;
    mailbox #(reg_trans) reg_mb;
    mailbox #(fmt_trans) exp_mbs[3];

    function new(string name="mcdf_checker");
      this.name = name;
      foreach(this.chnl_mbs[i]) this.chnl_mbs[i] = new();
      this.fmt_mb = new();
      this.reg_mb = new();
      this.refmod = new();
      foreach(this.refmod.in_mbs[i]) begin
        this.refmod.in_mbs[i] = this.chnl_mbs[i]; // 把 checker 中实例化过的 句柄 chnl_mbs 赋值给 refmod 中的 in_mbs
        this.exp_mbs[i] = this.refmod.out_mbs[i];
      end
      this.refmod.reg_mb = this.reg_mb;
      this.err_count = 0;
      this.total_count = 0;
      foreach(this.chnl_count[i]) this.chnl_count[i] = 0;
    endfunction

    function void set_interface(virtual mcdf_intf intf);
      if(intf == null)
        $error("interface handle is NULL, please check if target interface has been intantiated");
      else
        this.intf = intf;
        this.refmod.set_interface(intf);
    endfunction

    task run();
      fork
        this.do_compare();
        this.refmod.run();
      join
    endtask

    task do_compare();
      fmt_trans expt, mont;
      bit cmp;
      forever begin
        this.fmt_mb.get(mont);
        this.exp_mbs[mont.ch_id].get(expt);
        cmp = mont.compare(expt);   
        this.total_count++;
        this.chnl_count[mont.ch_id]++;
        if(cmp == 0) begin
          this.err_count++;
          rpt_pkg::rpt_msg("[CMPFAIL]", 
            $sformatf("%0t %0dth times comparing but failed! MCDF monitored output packet is different with reference model output", $time, this.total_count),
            rpt_pkg::ERROR,
            rpt_pkg::TOP,
            rpt_pkg::LOG);
        end
        else begin
          rpt_pkg::rpt_msg("[CMPSUCD]",
            $sformatf("%0t %0dth times comparing and succeeded! MCDF monitored output packet is the same with reference model output", $time, this.total_count),
            rpt_pkg::INFO,
            rpt_pkg::HIGH);
        end
      end
    endtask

5. 对 mcdf_env 的理解

1)声明chnl_agent , reg_agent, fmt_agent, 以及 mcdf_checker 的句柄,并在构造函数中将其实例化,

2)在实例化后,将 monitor 中的 mon_mb 这个mailbox 句柄 赋值给 checker 中对应的句柄,使其指向监测到的对象

3)先调用进行配置的do_config(),  然后调用各个组件的 run(),使其运行 

4)并且把 do_config() 和 run() 都声明为 虚函数virtual, 为实现动态绑定,do_config() 的内容也为空,在具体的 test 中,在进行配置

5)do_report() 也就是调用 checker 中的 do_report(),  进行比较之后的打印 

class mcdf_env;
    chnl_agent chnl_agts[3];  
    reg_agent reg_agt;
    fmt_agent fmt_agt;
    mcdf_checker chker;
    protected string name;

    function new(string name = "mcdf_env");
      this.name = name;
      this.chker = new();
      foreach(chnl_agts[i]) begin
        this.chnl_agts[i] = new($sformatf("chnl_agts[%0d]",i));
        this.chnl_agts[i].monitor.mon_mb = this.chker.chnl_mbs[i];
      end
      this.reg_agt = new("reg_agt");
      this.reg_agt.monitor.mon_mb = this.chker.reg_mb;
      this.fmt_agt = new("fmt_agt");
      this.fmt_agt.monitor.mon_mb = this.chker.fmt_mb;
      $display("%s instantiated and connected objects", this.name);
    endfunction

    virtual task run();
      $display($sformatf("*****************%s started********************", this.name));
      this.do_config(); // 这个 do_config 在 mcdf_base_test 中 再配置 generator
      fork
        this.chnl_agts[0].run();
        this.chnl_agts[1].run();
        this.chnl_agts[2].run();
        this.reg_agt.run();
        this.fmt_agt.run();
        this.chker.run();
      join
    endtask

    // virtual function void do_config();
    // endfunction

    virtual function void do_report();
      this.chker.do_report();
    endfunction

  endclass

6. 对mcdf_base_test 的理解

class mcdf_base_test;  // 从顶层开始 逐渐往下例化 从外往里 例化   base_test 例化 generator 和  mcdf_env
    chnl_generator chnl_gens[3];  // mcdf_env 例化了 agent 和 checker 
    reg_generator reg_gen;        // agent 例化了 driver 和 monitor  checker 例化了 refmod 
    fmt_generator fmt_gen;
    mcdf_env env;
    protected string name;

    function new(string name = "mcdf_base_test");
      this.name = name;
      this.env = new("env");

      foreach(this.chnl_gens[i]) begin
        this.chnl_gens[i] = new();
        this.env.chnl_agts[i].driver.req_mb = this.chnl_gens[i].req_mb;
        this.env.chnl_agts[i].driver.rsp_mb = this.chnl_gens[i].rsp_mb;
      end

      this.reg_gen = new();
      this.env.reg_agt.driver.req_mb = this.reg_gen.req_mb;
      this.env.reg_agt.driver.rsp_mb = this.reg_gen.rsp_mb;

      this.fmt_gen = new();
      this.env.fmt_agt.driver.req_mb = this.fmt_gen.req_mb;
      this.env.fmt_agt.driver.rsp_mb = this.fmt_gen.rsp_mb;

      rpt_pkg::logname = {this.name, "_check.log"};
      rpt_pkg::clean_log();
      $display("%s instantiated and connected objects", this.name);
    endfunction

    virtual task run();
      fork
        env.run();
      join_none
      rpt_pkg::rpt_msg("[TEST]",
        $sformatf("=====================%s AT TIME %0t STARTED=====================", this.name, $time),
        rpt_pkg::INFO,
        rpt_pkg::HIGH);
      this.do_reg();
      this.do_formatter();
      this.do_data();  // 这三个 顺序不能变 因为要在 发送数据之前先配置好寄存器,然后配置好接收来自fmt的数据 的下行通道 fmt_agent, 最后发送数据
      rpt_pkg::rpt_msg("[TEST]",
        $sformatf("=====================%s AT TIME %0t FINISHED=====================", this.name, $time),
        rpt_pkg::INFO,
        rpt_pkg::HIGH);
      this.do_report();
      $finish();
    endtask

    // do register configuration
    virtual task do_reg();
    endtask

    // do external formatter down stream slave configuration
    virtual task do_formatter();
    endtask

    // do data transition from 3 channel slaves
    virtual task do_data();
    endtask

    // do simulation summary
    virtual function void do_report();
      this.env.do_report();
      rpt_pkg::do_report();
    endfunction

    virtual function void set_interface(virtual chnl_intf ch0_vif 
                                        ,virtual chnl_intf ch1_vif 
                                        ,virtual chnl_intf ch2_vif 
                                        ,virtual reg_intf reg_vif
                                        ,virtual fmt_intf fmt_vif
                                        ,virtual mcdf_intf mcdf_vif
                                      );
      this.env.chnl_agts[0].set_interface(ch0_vif);
      this.env.chnl_agts[1].set_interface(ch1_vif);
      this.env.chnl_agts[2].set_interface(ch2_vif);
      this.env.reg_agt.set_interface(reg_vif);
      this.env.fmt_agt.set_interface(fmt_vif);
      this.env.chker.set_interface(mcdf_vif);
    endfunction

    virtual function bit diff_value(int val1, int val2, string id = "value_compare");
      if(val1 != val2) begin
        rpt_pkg::rpt_msg("[CMPERR]", 
          $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2), 
          rpt_pkg::ERROR, 
          rpt_pkg::TOP);
        return 0;
      end
      else begin
        rpt_pkg::rpt_msg("[CMPSUC]", 
          $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2),
          rpt_pkg::INFO,
          rpt_pkg::HIGH);
        return 1;
      end
    endfunction

    virtual task idle_reg();
      void'(reg_gen.randomize() with {cmd == `IDLE; addr == 0; data == 0;});
      reg_gen.start();
    endtask

    virtual task write_reg(bit[7:0] addr, bit[31:0] data);
      void'(reg_gen.randomize() with {cmd == `WRITE; addr == local::addr; data == local::data;});
      reg_gen.start();
    endtask

    virtual task read_reg(bit[7:0] addr, output bit[31:0] data);
      void'(reg_gen.randomize() with {cmd == `READ; addr == local::addr;});
      reg_gen.start();
      data = reg_gen.data; // 这个 data 是怎么获得的? 同过 与 driver 的 握手通信 this.rsp_mb.get(rsp); 而且在generator 定义了 data
    endtask
  endclass

  • 12
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值