电力电子转战数字IC20220825day69——MCDF更新APB总线

 MCDF更新APB总线

原来的寄存器做总线换成了APB总线,通道数量加了1。所有的接口几乎都发生了改变。

 channel更新为slave node

 data和valid接口保留,新增了parity和wait和error,wait接口就是原来的ready接口,表示fifo空满、是否准备好接收新的data。数据校验位parity是data的异或!(return^data;)

时序图:

 作为item的chnl_trans类不变,没有变化。传送的信号还是原来的那些。

时序图发生变化,所以驱动item的chnl_driver发生了变化:重置任务中多了ch_data_p这个信号(parity);chnl_write任务也需要多这个信号,并定义一个获取校验位的函数get_parity,就是data异或。

    task chnl_write(input chnl_trans t);
      foreach(t.data[i]) begin
        @(posedge intf.clk);
        intf.drv_ck.ch_valid <= 1;
        intf.drv_ck.ch_data <= t.data[i];
        intf.drv_ck.ch_data_p <= get_parity(t.data[i]);
        @(negedge intf.clk);
        wait(intf.ch_wait === 'b0);
        `uvm_info(get_type_name(), $sformatf("sent data 'h%8x", t.data[i]), UVM_HIGH)
        repeat(t.data_nidles) chnl_idle();
      end
      repeat(t.pkt_nidles) chnl_idle();
    endtask
    
    task chnl_idle();
      @(posedge intf.clk);
      intf.drv_ck.ch_valid <= 0;
      intf.drv_ck.ch_data <= 0;
      intf.drv_ck.ch_data_p <= 0;
    endtask

    function get_parity(bit[31:0] data);
      return ^data;
    endfunction

sequencer只有注册和new函数,无需更新。

sequence,成员变量多了动态数组data[],暂时还不知道为什么?

并对所有成员变量增加了约束。

  class chnl_data_sequence extends uvm_sequence #(chnl_trans);
    rand int pkt_id = 0;
    rand int ch_id = -1;
    rand int data_nidles = -1;
    rand int pkt_nidles = -1;
    rand int data_size = -1;
    rand int ntrans = 10;
    rand int data[];
    constraint cstr{
      soft pkt_id == 0;
      soft ch_id == -1;
      soft data_nidles == -1;
      soft pkt_nidles == -1;
      soft data_size == -1;
      soft ntrans == 10;
      soft data.size() == data_size;
      foreach(data[i]) soft data[i] == -1;
    };
    `uvm_object_utils_begin(chnl_data_sequence)
      `uvm_field_int(pkt_id, UVM_ALL_ON)
      `uvm_field_int(ch_id, UVM_ALL_ON)
      `uvm_field_int(data_nidles, UVM_ALL_ON)
      `uvm_field_int(pkt_nidles, UVM_ALL_ON)
      `uvm_field_int(data_size, UVM_ALL_ON)
      `uvm_field_int(ntrans, UVM_ALL_ON)
    `uvm_object_utils_end
    `uvm_declare_p_sequencer(chnl_sequencer)
    function new (string name = "chnl_data_sequence");
      super.new(name);
    endfunction

monitor的PORT从uvm_blocking_put_port变成了uvm_analysis_port,为什么?对应调用的方法也从put变成了write,ready信号更新为wait

agent的变化也稍微大了点,build_phase中调用uvm_config_db配置了接口,connect_phase调用了set_interface连接了接口。之前的接口是从顶层拿到接口指针后调用这里的set_interface

对比的文件是还没更新MCDF前的uvm入门实验5的文件。

tb中接口的更新:多了parity,ready改成wait,多了parity error,对应的时钟块信号发生变化,error作为input,parity作为output

interface chnl_intf(input clk, input rstn);
  logic [31:0] ch_data;
  logic        ch_data_p;
  logic        ch_valid;
  logic        ch_wait;
  logic        ch_parity_err;
  clocking drv_ck @(posedge clk);
    default input #1ps output #1ps;
    output ch_data, ch_valid, ch_data_p;
    input ch_wait, ch_parity_err;
  endclocking
  clocking mon_ck @(posedge clk);
    default input #1ps output #1ps;
    input ch_data, ch_valid, ch_data_p, ch_wait, ch_parity_err;
  endclocking
endinterface

module中的接口分别连接四个node,并且更新到dut的连接

  chnl_intf chnl0_if(.*);
  chnl_intf chnl1_if(.*);
  chnl_intf chnl2_if(.*);
  chnl_intf chnl3_if(.*);
    .slv0_data_i         (chnl0_if.ch_data        ) , // 
    .slv0_data_p_i       (chnl0_if.ch_data_p      ) , // one bit parity of data_i
    .slv0_valid_i        (chnl0_if.ch_valid       ) , // 
    .slv0_wait_o         (chnl0_if.ch_wait        ) , //
    .slv0_parity_err_o   (chnl0_if.ch_parity_err  ) , //
    .slv1_data_i         (chnl1_if.ch_data        ) , // 
    .slv1_data_p_i       (chnl1_if.ch_data_p      ) , // one bit parity of data_i
    .slv1_valid_i        (chnl1_if.ch_valid       ) , // 
    .slv1_wait_o         (chnl1_if.ch_wait        ) , //
    .slv1_parity_err_o   (chnl1_if.ch_parity_err  ) , //
    .slv2_data_i         (chnl2_if.ch_data        ) , // 
    .slv2_data_p_i       (chnl2_if.ch_data_p      ) , // one bit parity of data_i
    .slv2_valid_i        (chnl2_if.ch_valid       ) , // 
    .slv2_wait_o         (chnl2_if.ch_wait        ) , //
    .slv2_parity_err_o   (chnl2_if.ch_parity_err  ) , //
    .slv3_data_i         (chnl3_if.ch_data        ) , // 
    .slv3_data_p_i       (chnl3_if.ch_data_p      ) , // one bit parity of data_i
    .slv3_valid_i        (chnl3_if.ch_valid       ) , // 
    .slv3_wait_o         (chnl3_if.ch_wait        ) , //
    .slv3_parity_err_o   (chnl3_if.ch_parity_err  ) , //

initial块中自上而下配置接口到各个层次:top-env-agent;top-env

    uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.chnl_agts[0]",  "vif",          chnl0_if);
    uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.chnl_agts[1]",  "vif",          chnl1_if);
    uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.chnl_agts[2]",  "vif",          chnl2_if);
    uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.chnl_agts[3]",  "vif",          chnl3_if);


    uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.*",             "chnl_vifs[0]", chnl0_if);
    uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.*",             "chnl_vifs[1]", chnl1_if);
    uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.*",             "chnl_vifs[2]", chnl2_if);
    uvm_config_db#(virtual chnl_intf)::set(uvm_root::get(), "uvm_test_top.env.*",             "chnl_vifs[3]", chnl3_if);

formatter的更新

 len从0-255表示1-256个payload

 时序图如下:

fmt_trans多了校验parity。

先看接口的更新,接口变为5个,ready其实就是原来的grant

interface fmt_intf(input clk, input rstn);
  logic        fmt_ready;
  logic        fmt_valid;
  logic [31:0] fmt_data;
  logic        fmt_first;
  logic        fmt_last;
  clocking drv_ck @(posedge clk);
    default input #1ps output #1ps;
    input fmt_valid, fmt_data, fmt_first, fmt_last;
    output fmt_ready;
  endclocking
  clocking mon_ck @(posedge clk);
    default input #1ps output #1ps;
    input fmt_ready, fmt_valid, fmt_data, fmt_first, fmt_last;
  endclocking
endinterface

连接到dut的接口对应更新

    .rev_rdy_i           (fmt_if.fmt_ready        ) , // receiver rdy
    .pkg_vld_o           (fmt_if.fmt_valid        ) , // data is valid
    .pkg_dat_o           (fmt_if.fmt_data         ) , // data/payload
    .pkg_fst_o           (fmt_if.fmt_first        ) , // header indicator
    .pkg_lst_o           (fmt_if.fmt_last         )   // parirty data

driver更新了do_receive,一开始的思路是,看剩余的空间是否比item的长度还长,也就是余量是否充足,如果余量不足就停止了。

更新后的逻辑是,不管里面是不是装满了,放不下的时候ready拉低即可

    task do_receive();
      forever begin
        @(posedge intf.fmt_req);
        forever begin
          @(posedge intf.clk);
          if((this.fifo_bound-this.fifo.num()) >= intf.fmt_length)
            break;
        end
        intf.drv_ck.fmt_grant <= 1;
        @(posedge intf.fmt_start);
        fork
          begin
            @(posedge intf.clk);
            intf.drv_ck.fmt_grant <= 0;
          end
        join_none
        repeat(intf.fmt_length) begin
          @(negedge intf.clk);
          this.fifo.put(intf.fmt_data);
        end
      end
    endtask   


task do_receive();
      forever begin
        @(intf.drv_ck); #10ps;
        if(intf.fmt_valid === 1'b1) begin
          forever begin
            if((this.fifo_bound-this.fifo.num()) >= 1)
              break;
            @(intf.drv_ck); #10ps;//不行就再等多一拍
          end
          this.fifo.put(intf.fmt_data);
          #1ps; intf.fmt_ready <= 1;
        end
        else begin
          #1ps; intf.fmt_ready <= 0;
        end
      end
    endtask

monitor端口同样变为ap。原来的只看start是否拉高,现在是一个一个data进行记录,条件变多,信息集成度更高,将id、长度等集成在fmt_data的后16位

task mon_trans();
      fmt_trans m;
      string s;
      forever begin
        @(intf.mon_ck iff intf.mon_ck.fmt_first && intf.mon_ck.fmt_valid && intf.mon_ck.fmt_ready);
        m = new();
//例化后将拿到的数据包写进这个一模一样的trans对象中
        m.length = intf.mon_ck.fmt_data[23:16];//包头的len
        m.ch_id = intf.mon_ck.fmt_data[31:24];//最前面的ID
        m.data = new[m.length + 3];//为什么加3?这里的new是创建动态数组(trans里面已经有声明随机变量的32位动态数组data),length+3表示动态数组的长度
//len+1=(payload的数量),包头first和包尾last分别占1个payload
        foreach(m.data[i]) begin
          m.data[i] = intf.mon_ck.fmt_data;
          if(i == m.data.size()-1) m.parity = m.data[i];
          if(i < m.data.size()-1) @(intf.mon_ck iff intf.mon_ck.fmt_valid && intf.mon_ck.fmt_ready);
        end
        mon_ana_port.write(m);

agent也做了接口的配置和连接

顶层环境有哪些?

chnl、reg、fmt的agent,mcdf的checker、coverage、rgm,mcdf_virtual_sequencer

mcdf中rgm的更新

run_phase中无需do_reg_update(模拟硬件寄存器数组更新),现在更新后用的是rgm

 

由于通道数加了1,do_packet多了一个;packet的方式变化了,现在是调用rgm的函数来获得id和长度等信息

  class mcdf_refmod extends uvm_component;
    mcdf_rgm rgm;

    uvm_blocking_get_port #(apb_transfer) reg_bg_port;
    uvm_blocking_get_peek_port #(mon_data_t) in_bgpk_ports[4];
    uvm_tlm_analysis_fifo #(fmt_trans) out_tlm_fifos[4];

    `uvm_component_utils(mcdf_refmod)

    function new (string name = "mcdf_refmod", uvm_component parent);
      super.new(name, parent);
      reg_bg_port = new("reg_bg_port", this);
      foreach(in_bgpk_ports[i]) in_bgpk_ports[i] = new($sformatf("in_bgpk_ports[%0d]", i), this);
      foreach(out_tlm_fifos[i]) out_tlm_fifos[i] = new($sformatf("out_tlm_fifos[%0d]", i), this);
    endfunction

    function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      if(!uvm_config_db#(mcdf_rgm)::get(this,"","rgm", rgm)) begin
        `uvm_fatal("GETRGM","cannot get RGM handle from config DB")
      end
    endfunction

    task run_phase(uvm_phase phase);
      fork
        do_packet(0);
        do_packet(1);
        do_packet(2);
        do_packet(3);
      join
    endtask

    task do_packet(int ch);
      fmt_trans ot;
      mon_data_t it;
      forever begin
        this.in_bgpk_ports[ch].peek(it);
        ot = new();
        ot.length = rgm.get_reg_field_length(ch);
        ot.ch_id = rgm.get_reg_field_id(ch);
        ot.data = new[ot.length+3];
        foreach(ot.data[m]) begin
          if(m == 0) begin//包头
            ot.data[m] = (ot.ch_id<<24) + (ot.length<<16);
            ot.parity = ot.data[m];
          end 
          else if(m == ot.data.size()-1) begin//包尾
            ot.data[m] = ot.parity;
          end
          else begin //中间数据payload
            this.in_bgpk_ports[ch].get(it);
            ot.data[m] = it.data;
            ot.parity ^= it.data;
          end
        end
        this.out_tlm_fifos[ch].put(ot);
      end
    endtask
  endclass: mcdf_refmod

checker的更新

大量的PORT和mailbox被TLM analysis fifo替代,

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值