Synopsys system veriolog Lab学习(5)

Lab5

前面四个实验理解起来相对容易一些,Lab5相对难一些。该实验把测试平台的每个组件都封装为一个类,要考虑每个组件之间的通信,还要控制互斥资源的访问(本实验中为不同驱动器驱动数据通过router时,多个数据包对同一输出端口的竞争)。
本实验需要封装的类如下图所示,类之间的通信通过信箱实现。
在这里插入图片描述

测试平台框架如下图所示,在测试平台中,各个组件是同时开始工作的。
在这里插入图片描述
该框架和Lab4的区别之一是具有多个驱动器和接收器,同时驱动数据和接收数据。

Generator

在该类中,通过start()任务产生数据包。
通过信箱out_box与Driver通信,即信箱充当这两个类之间的数据包管道。

task Generator::start();
  if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
  fork
    for (int i=0; i<run_for_n_packets || run_for_n_packets <= 0; i++) begin
      this.gen();
      begin
        Packet pkt = new this.pkt2send;
        this.out_box[pkt.sa].put(pkt);
      end
    end
  join_none
endtask: start

Driver

接收Generator传来的数据包,把数据驱动到DUT接口上,同时,把数据发送到Scoreboard。

task Driver::start();
  //Lab 5 - Task 4, Step 1
  //
  //In the existing start() method body, add a trace statement
  //ToDo
  if (TRACE_ON) $display("[TRACE]%t $s:%m", $realtime, this.name);

  //Lab 5 - Task 4, Step 2
  //
  //After the trace statement, create a non-blocking fork-join block.
  //ToDo
  fork

    //Lab 5 - Task 4, Step 3
    //
    //Inside the fork-join construct, create a single infinite loop
    //ToDo
    forever begin

      //Lab 5 - Task 4, Step 4a
      //
      //Retrieve a Packet object (pkt2send) from in_box
      //ToDo
	  this.in_box.get(this.pkt2send);

      //Lab 5 - Task 4, Step 4b
      //
      //If the sa property in the retrieved Packet object does not match this.sa,
      //continue on to the next iteration of the loop
      //ToDo
	  if (this.pkt2send.sa != this.sa) continue;

      //Lab 5 - Task 4, Step 4c
      //
      //If the retrieved Packet sa does match this.sa, update the da and
      //payload class properties with the content of pkt2send
      //ToDo
	  this.da = this.pkt2send.da;
	  this.payload = this.pkt2send.payload;

      //Lab 5 - Task 4, Step 4d
      //
      //Use the semaphore sem[] array to arbitrate for access to the
      //output port specified by da
      //ToDo
	  this.sem[this.da].get(1);

      //Lab 5 - Task 4, Step 4e
      //
      //Once the arbitration is successful, call send() to drive the
      //packet through the DUT
      //ToDo
	  this.send();

      //Lab 5 - Task 4, Step 4f
      //
      //When send() completes, deposit Packet object into out_box
      //ToDo
	  this.out_box.put(this.pkt2send);

      //Lab 5 - Task 4, Step 4a
      //
      //Put the semaphore key back into its bin in the final step of the loop
      //ToDothis.sem[this.da].put(1);

	end
  join_none

endtask: start

start()任务从in_box中获取数据包,把数据驱动到DUT上,同时把数据包发送到Scoreboard。从in_box取出数据之后,通过旗语防止把数据驱动到正在使用的router输出口上,只有某一输出口不被其他数据包传输使用时方能驱动数据从该端口输出。

Receiver

该模块捕获router接口输出的数据包,发送给Scoreboard。

task ReceiverBase::recv();
  static int pkt_cnt = 0;
  if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
  this.get_payload();
  this.pkt2cmp.da = da;
  this.pkt2cmp.payload = this.pkt2cmp_payload;
  this.pkt2cmp.name = $psprintf("rcvdPkt[%0d]", pkt_cnt++);
endtask

Scoreboard

从driver_mbox和receiver_mbox接收数据,比较两者是否一致。

task Scoreboard::start();
  if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
  fork
    forever begin
      this.receiver_mbox.get(this.pkt2cmp);
      while (this.driver_mbox.num()) begin
        Packet pkt;
        this.driver_mbox.get(pkt);
        this.refPkt.push_back(pkt);
      end
      this.check();
    end
  join_none
endtask: start

当接收端接收到数据时,发送端已经把数据送到Scoreboard中。上面的任务先从接收端的管道取出数据,之后从驱动模块到Scoreboard的信箱中取数据包与其比较。

task Scoreboard::check();
  int    index[$];
  string message;
  static int  pkts_checked = 0;
  if (TRACE_ON) $display("[TRACE]%t %s:%m", $realtime, this.name);
  index = this.refPkt.find_first_index() with (item.da == this.pkt2cmp.da);
  if (index.size() <= 0) begin
    $display("\n%m\n[ERROR]%t %s not found in Reference Queue\n", $realtime, pkt2cmp.name);
    this.pkt2cmp.display("ERROR");
    $finish;
  end
  this.pkt2send = refPkt[index[0]];
  this.refPkt.delete(index[0]);
  if (!this.pkt2send.compare(this.pkt2cmp, message)) begin
    $display("\n%m\n[ERROR]%t Packet #%0d %s\n", $realtime, pkts_checked, message);
    this.pkt2send.display("ERROR");
    this.pkt2cmp.display("ERROR");
    $finish;
  end
  $display("[NOTE]%t Packet #%0d %s", $realtime, pkts_checked++, message);
  if (pkts_checked >= run_for_n_packets)
    ->this.DONE;
endtask: check

该任务从发送端的数据中取出第一个与接收端目的地址相同的数据包,与接收到的数据包进行比较。
在这里存在这样一个次序关系:发送端数据先于接收端数据(即发送数据包之后输出端才有数据可以接收)。在同一时间节点发送的数据(16个driver,16个数据),在Driver到Scoreboard的信箱中的顺序跟数据输出端放入Receiver到Scoreboard的信箱中的数据包顺序不一定一致。

Test

在测试环境中先声明各个组件:

  semaphore sem[];                    // prevent output port collision
  Driver drvr[];                         // driver
  Receiver rcvr[];                     // receiver
  Generator gen;                        // generator
  Scoreboard sb;                         // scoreboard

之后再创建各组件的对象

sem = new[16];
	drvr = new[16];
	rcvr = new[16];
	gen = new("gen");
	sb = new("sb");

	foreach (sem[i])
	  sem[i] = new(1);
	foreach (drvr[i])
	  drvr[i] = new($sformatf("drvr[%0d]",i), i, sem, gen.out_box[i], sb.driver_mbox, rtr_io);
	foreach (rcvr[i])
	  rcvr[i] = new($sformatf("rcvr[%0d]",i), i, sb.receiver_mbox, rtr_io);

复位之后启动各个组件,等待结束仿真的时间触发。

reset();

    //Lab 5 - Task 10, Step 9
    //
	//Start all transactors (gen, sb, drivers and receivers)
    //ToDo
	gen.start();
	sb.start();
	foreach (drvr[i]) drvr[i].start();
	foreach (rcvr[i]) rcvr[i].start();

    //Lab 5 - Task 10, Step 9
    //
	//Wait for the DONE event flag in sb to be trigerred
    //ToDo
	wait(sb.DONE.triggered);

注意,这里各个组件是同时开始工作的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值