MCDF实验4:魔龙的狂舞(从verilog到SV的入门lab4)_mcdf sv lab4

12 篇文章 0 订阅
11 篇文章 0 订阅

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

读写寄存器

  • bit(0):通道使能信号。1为打开,0位关闭。复位值为1。 bit(2:1):优先级。0为最高,3为最低。复位值为3。
  • bit(5:3):数据包长度,解码对应表为,
    0对应长度4,1对应长度8,2对应长度16,3对应长度32,其它数值(4-7)均暂时对应长度32。复位值为0。
  • bit(31:6):保留位,无法写入。复位值为0。

只读寄存器

bit(7:0):上行数据从端FIFO的可写余量,同FIFO的数据余量保持同步变化。复位值为FIFO的深度数。
bit(31:8):保留位,复位值为0。

1.12 clone、sprint、
    function reg_trans clone();
      reg_trans c = new();
      c.addr = this.addr;
      c.cmd = this.cmd;
      c.data = this.data;
      c.rsp = this.rsp;
      return c;
    endfunction

   function string sprint();
      string s;
      s = {s, $sformatf("=======================================\n")};
      s = {s, $sformatf("reg\_trans object content is as below: \n")};
      s = {s, $sformatf("addr = %2x: \n", this.addr)};
      s = {s, $sformatf("cmd = %2b: \n", this.cmd)};
      s = {s, $sformatf("data = %8x: \n", this.data)};
      s = {s, $sformatf("rsp = %0d: \n", this.rsp)};
      s = {s, $sformatf("=======================================\n")};
      return s;
    endfunction
  endclass

1.2 reg_driver

  class reg_driver;
    local string name;
    local virtual reg_intf intf;
    mailbox #(reg_trans) req_mb;
    mailbox #(reg_trans) rsp_mb;

    function new(string name = "reg\_driver");
      this.name = name;
    endfunction
  
    function void set\_interface(virtual reg_intf intf);
      if(intf == null)
        $error("interface handle is NULL, please check if target interface has been intantiated");
      else
        this.intf = intf;
    endfunction

    task run();
      fork
        this.do\_drive();
        this.do\_reset();
      join
    endtask

    task do\_reset(); //复位
      forever begin
        @(negedge intf.rstn);
        intf.cmd_addr <= 0;
        intf.cmd <= `IDLE;
        intf.cmd_data_m2s <= 0;
      end
    endtask

    task do\_drive();
      reg_trans req, rsp;
      @(posedge intf.rstn);
      forever begin
        this.req_mb.get(req);
        this.reg\_write(req);
        rsp = req.clone();
        rsp.rsp = 1;
        this.rsp_mb.put(rsp);
      end
    endtask
  
    task reg\_write(reg_trans t);//给寄存器
      @(posedge intf.clk iff intf.rstn);
      case(t.cmd)
        `WRITE: begin //如果是写操作
                  intf.drv_ck.cmd_addr <= t.addr; //地址
                  intf.drv_ck.cmd <= t.cmd; 
                  intf.drv_ck.cmd_data_m2s <= t.data; //数据
                end
        `READ:  begin 
                  intf.drv_ck.cmd_addr <= t.addr; //总线
                  intf.drv_ck.cmd <= t.cmd; 
                  repeat(2) @(negedge intf.clk);//等两个时钟的下降沿,第一个下降沿还在
                  t.data = intf.cmd_data_s2m; //采样了intf的数据
                end
        `IDLE:  begin 
                  this.reg\_idle(); //等一拍
                end
        default: $error("command %b is illegal", t.cmd);
      endcase
      $display("%0t reg driver [%s] sent addr %2x, cmd %2b, data %8x", $time, name, t.addr, t.cmd, t.data);
    endtask

当case为 READ时,等待了两个时钟的下降沿。
第一个下降沿还在当前周期,第二个下降沿就在下一个周期了。此时数据已经驱动到接口cmd_data_s2m处了,这时去采样接口处的数据就一定是要读的数据。
在这里插入图片描述

  • 在控制寄存器接口上,需要在每一个时钟解析cmd。当cmd为写(WR)指令时,需要把数据cmd_data_in写入到cmd_addr对应的寄存器中;当cmd为读指令(RD)时,即需要从cmd_addr对应的寄存器中读取数据,并在下一个周期,将数据驱动至cmd_data_out接口。
    task reg\_idle();
      @(posedge intf.clk);
      intf.drv_ck.cmd_addr <= 0;
      intf.drv_ck.cmd <= `IDLE;
      intf.drv_ck.cmd_data_m2s <= 0;
    endtask
  endclass

1.3 reg_generator

  class reg_generator;
    rand bit[7:0] addr = -1;
    rand bit[1:0] cmd = -1;
    rand bit[31:0] data = -1;

    mailbox #(reg_trans) req_mb;
    mailbox #(reg_trans) rsp_mb;

    reg_trans reg_req[$];

    constraint cstr{
      soft addr == -1;
      soft cmd == -1;
      soft data == -1;
    }

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

    task start();
      send\_trans();
    endtask

    // generate transaction and put into local mailbox
    task send\_trans();
      reg_trans req, rsp;//做例化
      req = new();
      assert(req.randomize with {local::addr >= 0 -> addr == local::addr;
                                 local::cmd >= 0 -> cmd == local::cmd;
                                 local::data >= 0 -> data == local::data;
                               })
        else $fatal("[RNDFAIL] register packet randomization failure!");
      $display(req.sprint());
      this.req_mb.put(req);//放入数据
      this.rsp_mb.get(rsp);
      $display(rsp.sprint());
      if(req.cmd == `READ) 
        this.data = rsp.data;
      assert(rsp.rsp)
        else $error("[RSPERR] %0t error response received!", $time);
    endtask

    function string sprint();
      string s;
      s = {s, $sformatf("=======================================\n")};
      s = {s, $sformatf("reg\_generator object content is as below: \n")};
      s = {s, $sformatf("addr = %2x: \n", this.addr)};
      s = {s, $sformatf("cmd = %2b: \n", this.cmd)};
      s = {s, $sformatf("data = %8x: \n", this.data)};
      s = {s, $sformatf("=======================================\n")};
      return s;
    endfunction

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

  class reg_monitor;
    local string name;
    local virtual reg_intf intf;
    mailbox #(reg_trans) mon_mb;
    function new(string name="reg\_monitor");
      this.name = name;
    endfunction
    function void set\_interface(virtual reg_intf intf);
      if(intf == null)
        $error("interface handle is NULL, please check if target interface has been intantiated");
      else
        this.intf = intf;
    endfunction
    task run();
      this.mon\_trans();
    endtask

    task mon\_trans();
      reg_trans m;
      forever begin
        @(posedge intf.clk iff (intf.rstn && intf.mon_ck.cmd != `IDLE));//时钟的上升沿,并且数据合理
        m = new();//生成一个对象,把数据地址放入
        m.addr = intf.mon_ck.cmd_addr;
        m.cmd = intf.mon_ck.cmd;
        if(intf.mon_ck.cmd == `WRITE) begin//写指令,把总线上的数据放入
          m.data = intf.mon_ck.cmd_data_m2s;
        end
        else if(intf.mon_ck.cmd == `READ) begin//读指令,等下一个周期,再放入数据
          @(posedge intf.clk);
          m.data = intf.mon_ck.cmd_data_s2m;
        end
        mon_mb.put(m);//把数据交给checker
        $display("%0t %s monitored addr %2x, cmd %2b, data %8x", $time, this.name, m.addr, m.cmd, m.data);
      end
    endtask
  endclass

1.4 reg_agent


  class reg_agent;//包含了monitor,driver,让driver,monitor工作起来
    local string name;
    reg_driver driver;
    reg_monitor monitor;
    local virtual reg_intf vif;
    function new(string name = "reg\_agent");
      this.name = name;
      this.driver = new({name, ".driver"});
      this.monitor = new({name, ".monitor"});
    endfunction

    function void set\_interface(virtual reg_intf vif);
      this.vif = vif;
      driver.set\_interface(vif);
      monitor.set\_interface(vif);
    endfunction
    task run();
      fork
        driver.run();
        monitor.run();
      join
    endtask
  endclass

激励的类型、发送激励、产生激励、检测激励、agent

2. fmt_apk

chnl和reg的driver都是主动的发送数据给dut,而fmt的driver是被动的接受发送出来的数据。所以fmt像一个fifo,储存发送出来的数据。
需要设计fifo的大小宽度,来储存发送出来的数据。

package fmt\_pkg;
  import rpt\_pkg::\*;
//传出来的数据可能有不同的带宽、需要的fifo大小也不同,把可能需要的都枚举出来。
  typedef enum {SHORT_FIFO, MED_FIFO, LONG_FIFO, ULTRA_FIFO} fmt_fifo_t;
  typedef enum {LOW_WIDTH, MED_WIDTH, HIGH_WIDTH, ULTRA_WIDTH} fmt_bandwidth_t;

2.1 fmt_trans

  class fmt_trans;
    rand fmt_fifo_t fifo;
    rand fmt_bandwidth_t bandwidth;
    bit [9:0] length;
    bit [31:0] data[];
    bit [1:0] ch_id;
    bit rsp;
    constraint cstr{
      soft fifo == MED_FIFO;//fifo
      soft bandwidth == MED_WIDTH;//带宽
    };
    function fmt_trans clone();
      fmt_trans c = new();
      c.fifo = this.fifo;
      c.bandwidth = this.bandwidth;
      c.length = this.length;
      c.data = this.data;
      c.ch_id = this.ch_id;
      c.rsp = this.rsp;
      return c;
    endfunction

    function string sprint();
      string s;
      s = {s, $sformatf("=======================================\n")};
      s = {s, $sformatf("fmt\_trans object content is as below: \n")};
      s = {s, $sformatf("fifo = %s: \n", this.fifo)};
      s = {s, $sformatf("bandwidth = %s: \n", this.bandwidth)};
      s = {s, $sformatf("length = %s: \n", this.length)};
      foreach(data[i]) s = {s, $sformatf("data[%0d] = %8x \n", i, this.data[i])};
      s = {s, $sformatf("ch\_id = %0d: \n", this.ch_id)};
      s = {s, $sformatf("rsp = %0d: \n", this.rsp)};
      s = {s, $sformatf("=======================================\n")};
      return s;
    endfunction

    function bit compare(fmt_trans t);//当前的与传进来的数作比较
      string s;
      compare = 1;
      s = "\n=======================================\n";
      s = {s, $sformatf("COMPARING fmt\_trans object at time %0d \n", $time)};
      if(this.length != t.length) begin
        compare = 0;
        s = {s, $sformatf("sobj length %0d != tobj length %0d \n", this.length, t.length)};
      end
      if(this.ch_id != t.ch_id) begin
        compare = 0;
        s = {s, $sformatf("sobj ch\_id %0d != tobj ch\_id %0d\n", this.ch_id, t.ch_id)};
      end
      foreach(this.data[i]) begin
        if(this.data[i] != t.data[i]) begin
          compare = 0;
          s = {s, $sformatf("sobj data[%0d] %8x != tobj data[%0d] %8x\n", i, this.data[i], i, t.data[i])};
        end
      end
      if(compare == 1) s = {s, "COMPARED SUCCESS!\n"};
      else  s = {s, "COMPARED FAILURE!\n"};
      s = {s, "=======================================\n"};
      rpt_pkg::rpt\_msg("[CMPOBJ]", s, rpt_pkg::INFO, rpt_pkg::MEDIUM);
    endfunction
  endclass

2.2 fmt_driver

  class fmt_driver;
    local string name;
    local virtual fmt_intf intf;
    mailbox #(fmt_trans) req_mb;
    mailbox #(fmt_trans) rsp_mb;

    local mailbox #(bit[31:0]) fifo;
    local int fifo_bound;//长度
    local int data_consum_peroid;//消耗周期,侧面反应带宽,带宽越大,消耗周期越短

  
    function new(string name = "fmt\_driver");
      this.name = name;
      this.fifo = new();//fifo初始化
      this.fifo_bound = 4096;
      this.data_consum_peroid = 1;
    endfunction
  
    function void set\_interface(virtual fmt_intf intf);
      if(intf == null)
        $error("interface handle is NULL, please check if target interface has been intantiated");
      else
        this.intf = intf;
    endfunction

    task run();
      fork
        this.do\_receive();
        this.do\_consume();
        this.do\_config();
        this.do\_reset();
      join
    endtask
//配置fifo长或者短,消耗数据快还是慢
    task do\_config();//配置driver,配置完成后重新例化fifo
      fmt_trans req, rsp;
      forever begin
        this.req_mb.get(req);
        case(req.fifo)//配置为不同长度
          SHORT_FIFO: this.fifo_bound = 64;
          MED_FIFO: this.fifo_bound = 256;
          LONG_FIFO: this.fifo_bound = 512;
          ULTRA_FIFO: this.fifo_bound = 2048;
        endcase
        this.fifo = new(this.fifo_bound);//重新例化,并且规定长度
        case(req.bandwidth)
          LOW_WIDTH: this.data_consum_peroid = 8;
          MED_WIDTH: this.data_consum_peroid = 4;
          HIGH_WIDTH: this.data_consum_peroid = 2;
          ULTRA_WIDTH: this.data_consum_peroid = 1;
        endcase
        rsp = req.clone();
        rsp.rsp = 1;
        this.rsp_mb.put(rsp);
      end
    endtask

    task do\_reset(); 
      forever begin
        @(negedge intf.rstn) 
        intf.fmt_grant <= 0;
      end
    endtask

    task do\_receive();//模拟从formater接受数据
      forever begin
        @(posedge intf.fmt_req);//fmt的req拉高
        forever begin
          @(posedge intf.clk);//等待一拍
          if((this.fifo_bound-this.fifo.num()) >= intf.fmt_length)//fifo最大容量-已经存放了多少>=即将存放的数据长度
            break;
        end
        intf.drv_ck.fmt_grant <= 1;//可以存放数据,让grant为1
        @(posedge intf.fmt_start);
        fork
          begin
            @(posedge intf.clk);
            intf.drv_ck.fmt_grant <= 0;//过一拍置0
          end
        join_none
        repeat(intf.fmt_length) begin//把传进来的数据在每一拍做采样,重复采样length次。
          @(negedge intf.clk);
          this.fifo.put(intf.fmt_data);
        end
      end
    endtask

    task do\_consume();//不断的消耗数据,每过一拍拿一组数据
      bit[31:0] data;
      forever begin
        void'(this.fifo.try\_get(data));
        repeat($urandom\_range(1, this.data_consum_peroid)) @(posedge intf.clk);
      end
    endtask
  endclass

2.3 fmt_generator

  class fmt_generator;
    rand fmt_fifo_t fifo = MED_FIFO;
    rand fmt_bandwidth_t bandwidth = MED_WIDTH;

    mailbox #(fmt_trans) req_mb;
    mailbox #(fmt_trans) rsp_mb;

    constraint cstr{
      soft fifo == MED_FIFO;
      soft bandwidth == MED_WIDTH;
    }

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

    task start();
      send\_trans();
    endtask

    // generate transaction and put into local mailbox
    task send\_trans();
      fmt_trans req, rsp;
      req = new();
      assert(req.randomize with {local::fifo != MED_FIFO -> fifo == local::fifo; 
                                 local::bandwidth != MED_WIDTH -> bandwidth == local::bandwidth;
                               })
        else $fatal("[RNDFAIL] formatter packet randomization failure!");
      $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("fmt\_generator object content is as below: \n")};
      s = {s, $sformatf("fifo = %s: \n", this.fifo)};
      s = {s, $sformatf("bandwidth = %s: \n", this.bandwidth)};
      s = {s, $sformatf("=======================================\n")};
      return s;
    endfunction

    function void post\_randomize();
      string s;
      s = {"AFTER RANDOMIZATION \n", this.sprint()};
      $display(s);
    endfunction

  endclass

2.4 fmt_monitor

  class fmt_monitor;
    local string name;
    local virtual fmt_intf intf;
    mailbox #(fmt_trans) mon_mb;
    function new(string name="fmt\_monitor");
      this.name = name;
    endfunction
    function void set\_interface(virtual fmt_intf intf);
      if(intf == null)
        $error("interface handle is NULL, please check if target interface has been intantiated");
      else
        this.intf = intf;
    endfunction

    task run();
      this.mon\_trans();
    endtask

    task mon\_trans();
      fmt_trans m;
      string s;
      forever begin
        @(posedge intf.mon_ck.fmt_start);//假定协议是正常的
        m = new();
        m.length = intf.mon_ck.fmt_length;
        m.ch_id = intf.mon_ck.fmt_chid;
        m.data = new[m.length];
        foreach(m.data[i]) begin
          @(posedge intf.clk);
          m.data[i] = intf.mon_ck.fmt_data;//每一次数据来的时候,都存放在动态数组
        end
        mon_mb.put(m);//放好数据后,放入信箱
        s = $sformatf("=======================================\n");
        s = {s, $sformatf("%0t %s monitored a packet: \n", $time, this.name)};
        s = {s, $sformatf("length = %0d: \n", m.length)};
        s = {s, $sformatf("chid = %0d: \n", m.ch_id)};
        foreach(m.data[i]) s = {s, $sformatf("data[%0d] = %8x \n", i, m.data[i])};
        s = {s, $sformatf("=======================================\n")};
        $display(s);
      end
    endtask
  endclass

2.5 fmt_agent

  class fmt_agent;
    local string name;
    fmt_driver driver;
    fmt_monitor monitor;
    local virtual fmt_intf vif;
    function new(string name = "fmt\_agent");
      this.name = name;
      this.driver = new({name, ".driver"});
      this.monitor = new({name, ".monitor"});
    endfunction

    function void set\_interface(virtual fmt_intf vif);
      this.vif = vif;
      driver.set\_interface(vif);
      monitor.set\_interface(vif);
    endfunction
    task run();
      fork
        driver.run();
        monitor.run();
      join
    endtask
  endclass

endpackage

3. checker

  • 检测到的数据传到checker,3个chnl、fmt、reg的数据都会存放在checke已经例化好的信箱里。而fmt和3个chnl的数据格式是完全不同的。fmt对数据进行了打包,把数据整合成了新格式。
  • 所以比较输入输出先要把chnl、reg的数据需要先整形转化,模拟mcdf的行为。模拟打包后再进行数据的比较。
  • refmod利用句柄把数据拿出来,模拟硬件对数据打包。从chnl拿数据,按照长度的不同把数据放入三个输出端。

在这里插入图片描述
其中:

  • doreset对寄存器复位,清空信箱中的数据。
  • doregupdate更新checker中寄存器的配置。
  • dopackage对三个chnl做打包。

包含了checker、env和test。

`include "param\_def.v"

package mcdf\_pkg;

  import chnl\_pkg::\*;
  import reg\_pkg::\*;
  import arb\_pkg::\*;
  import fmt\_pkg::\*;
  import rpt\_pkg::\*;

  typedef struct packed {
    bit[2:0] len; //长度
    bit[1:0] prio;//
    bit en;//fifo使能
    bit[7:0] avail;//表示fifo可选余量 
  } mcdf_reg_t;
 
  typedef enum {RW_LEN, RW_PRIO, RW_EN, RD_AVAIL} mcdf_field_t;

3.1 mcdf_refmod

模拟mcdf的功能接受寄存器的读写行为,对检测来的数据进行打包。

  class mcdf_refmod;//模拟mcdf的功能接受寄存器的读写行为,对数据进行打包
    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;//引用regtrans里的数据
      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);//把chnl的数据打包
      fmt_trans ot; 
      mon_data_t it;
      forever begin
        this.in_mbs[id].peek(it);
        ot = new();
        ot.length = 4 << (this.get\_field\_value(id, RW_LEN) & 'b11);//拿到打包的长度
        ot.data = new[ot.length];//开辟空间
        ot.ch_id = id;
        foreach(ot.data[m]) begin//拿完数据,把ot放到对应的信箱。
          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
## 3.2 mcdf_checker
```java
  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];
        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),


![img](https://img-blog.csdnimg.cn/img_convert/a606920d3425ea089e8ad2a6756f55ac.png)
![img](https://img-blog.csdnimg.cn/img_convert/c180bca09205ac6bd613b68f78c949d5.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

: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),


[外链图片转存中...(img-zjF7WY3h-1715906443910)]
[外链图片转存中...(img-Qn2IRRKt-1715906443910)]

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618658159)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值