Vengineerの妄想(準備期間)

人生は短いけど、長いです。人生を楽しみましょう!

Layered Stimulusの例題、その3

Verification Engineerの戯言

今回は、scenarioAクラスmy_driverクラスについてです。

scenarioAクラスは、次のようにbodyタスクpre_applyタスクを定義しています。
    `define num_loops 10

    class scenarioA #(type REQ = ovm_sequence_item,
                      type RSP = ovm_sequence_item) extends ovm_scenario #(REQ, RSP);

      function new(string name);
        super.new(name);
      endfunction

      task body();
        string prstring;
        int  ret_data;
        REQ  req;
        RSP  rsp;

        ovm_report_message("scenarioA", "Starting scenario");
        $display(" scenario %0d", get_id());
    
        for(int unsigned i = 0; i < `num_loops; i++) begin
          req = new();
          req.addr = (get_id() * `num_loops) + i;
          req.data = get_id() + i + 55;
          req.op   = BUS_WRITE;

          $display("scen issue op: %s", req.convert2string());
          apply(req,rsp);
      
          req = new();
          req.addr = (get_id() * `num_loops) + i;
          req.data = 0;
          req.op   = BUS_READ;

          $display("scen issue op: %s", req.convert2string());
          apply(req,rsp);
      
          if (rsp.data != (get_id() + i + 55)) begin
	    $sformat(prstring, "Error, addr: %0d, expected data: %0d, actual data: %0d",
		     req.addr, req.data, rsp.data);
            ovm_report_error("ScenarioA", prstring);
          end
        end
        ovm_report_message("scenarioA", "Finishing scenario");
      endtask // body

      task pre_apply();
        $display("In Pre-apply of scenario %0d", get_id());
      endtask

    endclass
pre_applyタスクは、メッセージを表示しているだけですが、
bodyタスクnum_loops回(実際には10回BUS_WRITE->BUS_READをシナリオコントローラに送っています。
ここで定義したbodyタスクは、ovm_scenario_base::startタスクで説明したようにstartタスク内で呼び出されます。

my_driverクラスは、次のようにrunタスクを定義しています。
    class my_driver #(type REQ = ovm_sequence_item, 
	              type RSP = ovm_sequence_item)  extends ovm_scenario_driver #(REQ, RSP);

      int data_array[511:0];

      function new(string name, ovm_component parent);
        super.new(name, parent);
      endfunction

      task run();
 
        REQ req;
        RSP rsp;

        forever begin
          get_next_item(req);
          #1;
          rsp = new();
          rsp.copy_req(req);

          // Actually do the read or write here
          if (req.op == BUS_READ) begin
	    rsp.data = data_array[req.addr[8:0]];
	    $display("Driver Read, addr: %0d, rdata: %0d",
		     req.addr, rsp.data);
          end else begin
            data_array[req.addr[8:0]] = req.data;
	    $display("Driver Write, addr: %0d, data: %0d",
	             req.addr, req.data);
          end
          $display("Driver about to call put rsp");
          put_rsp.put(rsp);
          $display("Driver called put rsp");
        end
      endtask
    endclass
runタスクでは、get_next_itemタスクでシナリオコントローラからREQ(req)を受け取り、
req.opの値でBUS_READ/BUS_WRITEの処理を行い、put_rsp.put(rsp)でシナリオコントローラに応答しています。

検証、Verification、SystemVerilog、OVM、Open Verification Methodology