【SV练习】MDCF实验4

系统框图:

知识点:

1:void函数:不能等待,不能包括时延,不能包括事件触发

代码分析:

1:fmt_pkg.sv部分

package fmt_pkg;						//实现一个被动的响应,模拟一个fifo出来
  import rpt_pkg::*;

  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;

  class fmt_trans;

  class fmt_driver;

    task run();
      fork
        this.do_receive();				//接收数据
        this.do_consume();				//发送数据
        this.do_config();				//配置
        this.do_reset();				//复位
      join
    endtask

  class fmt_generator;

  class fmt_monitor;

  class fmt_agent;

endpackage

 fmt_driver作为responder存在的,是一个不断接受的数据的从端slave,类似一个fifo,并且位宽不定。不断地接收来自formatter的数据,按照fifo的位宽不断地发送数据。do_config配置参数,do_reset复位,do_receive和do_consume负责接收和发送数据。

do_receive不断地从从formatter里面拿数据。grant=1代表同意接收数据,grant=1也是有条件的(确保有余量存在),然后等待fmt_start被拉高,然后下个时钟周期再把fmt_grant拉低,开始接收数据,重复次数是fmt_length,不用等待前面的fmt_grant拉低。

do_consume的作用是按照我们给的fifo宽度不断地从fifo里面拿取数据,即使没有。并根据带宽决定发送数据的周期。fifo的宽度是在do_config里面配置的。

fmt_monitor把数据发送给mcdf_checker,用作比较。

2:mcdf_pkg.sv部分

硬件的输入主要是reg_agent和chnl_agent,在这两个共同作用下汇集到formatter里面。mcdf_checker模拟硬件的行为,数据进行打包在do_packet里面进行,更新寄存器模型的方法do_reg_config。打包以后放入out_mbs里面,根据in_mbs输入的不同长度进行打包,依据偿付分配到相应的out_mbs里面,所以refmod里面放置三个缓存,对应着三个chanl,无论是formatter还是refmod里面拿出来的都是数据包。

`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 {	}  //数据结构体包含长度、优先级、使能信号、余量

  typedef enum {RW_LEN, RW_PRIO, RW_EN, RD_AVAIL} mcdf_field_t;	        //表示当前域

  class mcdf_refmod;

  class mcdf_checker;

  class mcdf_env;

  class mcdf_base_test;

  class mcdf_data_consistence_basic_test extends mcdf_base_test;

endpackage

mcdf_refmod:参考上图中,主要三个功能 do_reset、do_packet和do_reg_update.

mcdf_checker:最主要的就是do_compare,cmp两组数据比较结果为1 还是为0,来打印比较的成功还是失败,并对total_count和chnl_count计数。

mcdf_env:整合环境,包含 chnl_agent chnl_agts[3]、reg_agent reg_agt、fmt_agentfmt_agt、mcdf_checker chker。

mcdf_base_test;

    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();
      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_reg,让driver配置寄存器,然后do_formatter,因为formatter需要模仿MCDF的下行,需要提前做好准备,配置好参数,再运行do_data。

cdf_data_consistence_basic_test extends mcdf_base_test:通过移动该有的位数配置数据,然后分别读取写入的数据和读回来的值进行比较,看是否出错。

3:reg_pkg部分

大体上和实验三类似

4:rpt_pkg部分

适应UVM中对于消息的管理。

测试功能点

 测试代码参考:路科验证MCDF_svlab4笔记_Hardworking_IC_boy的博客-优快云博客_路科验证

1、寄存器读写测试:

测试所有控制寄存器的读写、所有状态寄存器的读写(状态寄存器只读)。

class mcdf_reg_stability_test extends mcdf_base_test;
    function new(string name = "mcdf_data_consistence_basic_test");
      super.new(name);
    endfunction

    task do_reg();
      bit[7:0] chnl_rw_addrs[] = '{`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR};
      bit[7:0] chnl_ro_addrs[] = '{`SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR};
      int pwidth = `PAC_LEN_WIDTH + `PRIO_WIDTH + 1;							//=3+2+1=6
      bit[31:0] check_pattern[] = '{((1<<pwidth)-1), 0, ((1<<pwidth)-1)};
      bit[31:0] wr_val, rd_val;

      // RW register access and bits toggle
      foreach(chnl_rw_addrs[i]) begin
        foreach(check_pattern[i]) begin
          wr_val = check_pattern[i];
          this.write_reg(chnl_rw_addrs[i], wr_val);
          this.read_reg(chnl_rw_addrs[i], rd_val);
          void'(this.diff_value(wr_val, rd_val));
        end
      end

      // RO register read access
      foreach(chnl_ro_addrs[i]) begin
          this.read_reg(chnl_ro_addrs[i], rd_val);
      end

      // send IDLE command
      this.idle_reg();
    endtask
  endclass

check_pattern为要写入寄存器的数值,通过比较rd_val和wr_val是否一致,来验证控制寄存器的读写。

2、寄存器稳定性测试:

测试读写寄存器的bit(31:6)是否无法写入。

class mcdf_reg_illegal_access_test extends mcdf_base_test;
  function new(string name = "mcdf_reg_illegal_access_test");
    super.new(name);
  endfunction

  task do_reg();
    bit[7:0] chnl_rw_addrs[] = '{`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR};
    bit[7:0] chnl_ro_addrs[] = '{`SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR};
    int pwidth = `PAC_LEN_WIDTH + `PRIO_WIDTH + 1;  //=6
    bit[31:0] check_pattern[] = '{32'h0000_FFC0, 32'hFFFF_0000};
    bit[31:0] wr_val, rd_val;

    // RW register write reserved field and check
    foreach(chnl_rw_addrs[i]) begin
      foreach(check_pattern[j]) begin
        wr_val = check_pattern[j];
        this.write_reg(chnl_rw_addrs[i], wr_val);
        this.read_reg(chnl_rw_addrs[i], rd_val);
        void'(this.diff_value(wr_val & ((1<<pwidth)-1), rd_val));//将期望值和读出来的值对比
      end                                                       
    end

    // RO register write reserved field and check (no care readable field
    // value)
    foreach(chnl_ro_addrs[i]) begin
        wr_val = 32'hFFFF_FF00;
        this.write_reg(chnl_ro_addrs[i], wr_val);
        this.read_reg(chnl_ro_addrs[i], rd_val);
        void'(this.diff_value(0 , rd_val & 32'hFFFFFF00));
    end

    // send IDLE command
    this.idle_reg();
  endtask
endclass
wr_val &'b0111111是我们期望读回来的值,和rd_val进行比较。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值