MCDF实验4(2)

目录

给出 class fmt_driver 的完整代码

fmt_generator

fmt_monitor


接着上篇的 MCDF实验4(1)MCDF实验4(1)

给出 class fmt_driver 的完整代码

class fmt_driver;  //  fmt 的 driver 类似于一个 fifo 故 接收 do_receive() 并发送 do_consume() 
    local string name; 
    local virtual fmt_intf intf;
    mailbox #(fmt_trans) req_mb;
    mailbox #(fmt_trans) rsp_mb;

    local mailbox #(bit[31:0]) fifo; // 让 driver 模拟 fifo
    local int fifo_bound;  // fifo 的 最大深度
    local int data_consum_peroid;   // 消耗 周期 也就是侧面反映了 带宽 

  
    function new(string name = "fmt_driver");
      this.name = name;
      this.fifo = new();  // 后面的 do_config 已经 new() 过 fifo 在这还有没有必要 new()  为什么 给它的 容量是无穷大4096 不是小的数?
      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();  // do_reveice() 和 do_consume() 并行 是因为 这些行为就类似硬件的行为 它们随时都可以进行
        this.do_consume();
        this.do_config();  // 对 driver 进行配置, 为了配置它的行为,让它的行为表现的更像一个 buffer
        this.do_reset();
      join
    endtask

    task do_config();  // 相当于 别的模块的 do_drive()
      fmt_trans req, rsp;
      forever begin
        this.req_mb.get(req);
        case(req.fifo)    // 下面的两个case 相当于别的模块的 reg_write()
          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();  // 模仿 formatter 的 时序 接收数据
      forever begin
        @(posedge intf.fmt_req);
        forever begin
          @(posedge intf.clk);
          if((this.fifo_bound-this.fifo.num()) >= intf.fmt_length) // 括号里的表示agent(fifo)的余量
            break;
        end
        intf.drv_ck.fmt_grant <= 1;  
        @(posedge intf.fmt_start); // start 开始数据发送 对于 fifo 也就是接收数据 
        fork
          begin
            @(posedge intf.clk);
            intf.drv_ck.fmt_grant <= 0; 
          end
        join_none
        repeat(intf.fmt_length) begin  // repeat  是 接收数据 不用等待上面的 grant 信号
          @(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));  // 从 fifo 中 不管有没有数据 都尝试拿一个数据,并经过 data_consum_peroid 次周期 一直拿
        repeat($urandom_range(1, this.data_consum_peroid)) @(posedge intf.clk);
      end
    endtask
  endclass

fmt_generator

它和其他的 chnl_generator , reg_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;  // 创建与 driver 通信的 mailbox

    constraint cstr{
      soft fifo == MED_FIFO;
      soft bandwidth == MED_WIDTH; // 数据的约束
    }

    function new();
      this.req_mb = new();
      this.rsp_mb = new();  // mailbox的 实例化
    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

主要的步骤都一样:

 

主要的就是数据不同,fmt_generator 有两个数据:  fmt_fifo_t       fmt_bandwidth_t

这两个数据都是对 fmt_driver 模拟 fifo 而配置的,一个深度,一个带宽,由我们在顶层调用时,传进来它的配置。

fmt_monitor

在 monitor 中,创建一个 mailbox, 但mailbox的例化, 在chnl_chenker 中,监测 来自 fmt 的数据,假定协议是正确的,然后接收来自总线的 数据,数据id, chnl_id。

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]; // 为 data 开辟 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

fmt_agent 

fmt_agent 里面包含了两个组件 fmt_driver 和 fmt_monitor , 故内容也简单,就是对这两个组件的例化,以及接口的传递,最后让 fmt_driver 和 fmt_monitor 运行,同时运行run()。

class fmt_agent;
    local string name;
    fmt_driver driver;
    fmt_monitor monitor;
    local virtual fmt_intf vif;  // 这个接口 为啥是 local virtual
    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

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值