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

img
img

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

需要这份系统化的资料的朋友,可以添加戳这里获取

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

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拿数据,按照长度的不同把数据放入三个输出端。


![在这里插入图片描述](https://img-blog.csdnimg.cn/3078ef04dbae4754b0d4afc9e6b7c1f3.png#pic_center)  
 其中:


* 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

  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),
            rpt_pkg::INFO,
            rpt_pkg::HIGH);
        end
      end
    endtask

    function void do\_report();
      string s;
      s = "\n---------------------------------------------------------------\n";
      s = {s, "CHECKER SUMMARY \n"}; 
      s = {s, $sformatf("total comparison count: %0d \n", this.total_count)}; 
      foreach(this.chnl_count[i]) s = {s, $sformatf(" channel[%0d] comparison count: %0d \n", i, this.chnl_count[i])};
      s = {s, $sformatf("total error count: %0d \n", this.err_count)}; 
      foreach(this.chnl_mbs[i]) begin
        if(this.chnl_mbs[i].num() != 0)
          s = {s, $sformatf("WARNING:: chnl\_mbs[%0d] is not empty! size = %0d \n", i, this.chnl_mbs[i].num())}; 
      end
      if(this.fmt_mb.num() != 0)
          s = {s, $sformatf("WARNING:: fmt\_mb is not empty! size = %0d \n", this.fmt_mb.num())}; 
      s = {s, "---------------------------------------------------------------\n"};
      rpt_pkg::rpt\_msg($sformatf("[%s]",this.name), s, rpt_pkg::INFO, rpt_pkg::TOP);
    endfunction
  endclass

3.2 mcdf_env

  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();
      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

3.3 test

  class mcdf_base_test;
    chnl_generator chnl_gens[3];
    reg_generator reg_gen;
    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();//先配置fmt的fifo
      this.do\_data();
      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;
    endtask
  endclass

3.5 子类test

3.51 完整性测试
  class mcdf_data_consistence_basic_test extends mcdf_base_test;
    function new(string name = "mcdf\_data\_consistence\_basic\_test");
      super.new(name);
    endfunction

    task do\_reg();
      bit[31:0] wr_val, rd_val;
      //寄存器规定了第三位为1、2、3时对应8、16、32。
      // slv0 with len=8, prio=0, en=1
      wr_val = (1<<3)+(0<<1)+1;
      this.write\_reg(`SLV0_RW_ADDR, wr_val);	// 把值写进去
      this.read\_reg(`SLV0_RW_ADDR, rd_val);//再把写进去的值读回来
      void'(this.diff\_value(wr_val, rd_val, "SLV0\_WR\_REG"));//作比较

      // slv1 with len=16, prio=1, en=1
      wr_val = (2<<3)+(1<<1)+1;
      this.write\_reg(`SLV1_RW_ADDR, wr_val);
      this.read\_reg(`SLV1_RW_ADDR, rd_val);
      void'(this.diff\_value(wr_val, rd_val, "SLV1\_WR\_REG"));

      // slv2 with len=32, prio=2, en=1
      wr_val = (3<<3)+(2<<1)+1;
      this.write\_reg(`SLV2_RW_ADDR, wr_val);
      this.read\_reg(`SLV2_RW_ADDR, rd_val);
      void'(this.diff\_value(wr_val, rd_val, "SLV2\_WR\_REG"));

      // send IDLE command
      this.idle\_reg();
    endtask

    task do\_formatter();	//定义了fmt的fifo为LONG\_FIFO, HIGH\_WIDTH
      void'(fmt_gen.randomize() with {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;});
      fmt_gen.start();
    endtask

    task do\_data();//发送数据
      void'(chnl_gens[0].randomize() with {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; });
      void'(chnl_gens[1].randomize() with {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;});
      void'(chnl_gens[2].randomize() with {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;});
      fork
        chnl_gens[0].start();
        chnl_gens[1].start();
        chnl_gens[2].start();


![img](https://img-blog.csdnimg.cn/img_convert/3846e30d42eb11ab8294f7af2006c1cc.png)
![img](https://img-blog.csdnimg.cn/img_convert/ec20bb12b34cfd80db6839fb7d8f01b5.png)
![img](https://img-blog.csdnimg.cn/img_convert/dafa679965c6280a4fdf23a43463505f.png)

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

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

**[如果你需要这些资料,可以戳这里获取](https://bbs.youkuaiyun.com/topics/618658159)**

   endtask

    task do\_data();//发送数据
      void'(chnl_gens[0].randomize() with {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; });
      void'(chnl_gens[1].randomize() with {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;});
      void'(chnl_gens[2].randomize() with {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;});
      fork
        chnl_gens[0].start();
        chnl_gens[1].start();
        chnl_gens[2].start();


[外链图片转存中...(img-3Ca5sNAj-1715906401075)]
[外链图片转存中...(img-ZE3DNtOl-1715906401075)]
[外链图片转存中...(img-jnPHjmYV-1715906401075)]

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

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

**[如果你需要这些资料,可以戳这里获取](https://bbs.youkuaiyun.com/topics/618658159)**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值