【学习记录】MCDF实验1

本文介绍了从Verilog到SystemVerilog(SV)的转变,涉及兼容性、任务(task)与函数(function)的区别、timescale对时钟周期的影响,以及如何使用数组进行数据传输和验证设计的结构。着重讲解了任务的调用规则和数组在多通道通信中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TB1.从Verilog到SV的进场

在这里插入图片描述

  • 修改前后的仿真行为一致,这说明了SV对Verilog的兼容性。

tb.v
在这里插入图片描述

  • 将reg或wire修改为logic后,仿真行为一致。这是因为在SV中,任何使用线网类型的地方均可使用logic类型,但要求logic不能有多个结构性的驱动,及logic只能有一个驱动;当信号有多个驱动时,使用线网类型。

在这里插入图片描述

  • rstn信号的由原来的x变为0。这是因为logic是四值逻辑,而bit是二值逻辑

在这里插入图片描述

TB2. 方法task和函数function

在这里插入图片描述

  • 不正常。task没有被调用。

在这里插入图片描述

  • 恢复正常。

在这里插入图片描述

  • task需要被调用才能起作用。不可以放在一个initial块中调用,多个initial块是并行执行的,而initial块中的语句是串行执行的。

在这里插入图片描述

task clk_gen(int period);
  clk <= 0;
  forever begin
    #(period/2) clk <= !clk;
  end
endtask
initial begin
  // generate clk
  clk_gen(20);
end

要求2.5
如果将 timescale 1ns/1ps 修改为 timescale 1ps/1ps, 那么仿真中的时钟周期是否发生变化?这是为什么呢?

  • 周期由原来的20ns变为20ps。`timescale 时间单位/时间精度

TB3.数组的使用

在这里插入图片描述
要求3.2
如果先生成100个数,并对它们安装当前的数值规则进行赋值,请创建3个动态数组,分别放置要发送给3个slave的数据。接下来
要求3.3
利用之前生成的数组数据,将它们读取并发送给三个channel。

logic [31:0] chnl0_arr[];
logic [31:0] chnl1_arr[];
logic [31:0] chnl2_arr[];
// USER TODO
// generate 100 data for each dynamic array
initial begin
  chnl0_arr = new [100];
  chnl1_arr = new [100];
  chnl2_arr = new [100];
  foreach(chnl0_arr[i])begin
    chnl0_arr[i] = 'h00C0_00000 + i;
    chnl1_arr[i] = 'h00C1_00000 + i;
    chnl2_arr[i] = 'h00C2_00000 + i;
  end
end

// USER TODO
// use the dynamic array, user would send all of data
// data test
initial begin
  @(posedge rstn);
  repeat(5) @(posedge clk);
  // channel 0 test
  // TODO use chnl0_arr to send all data
  foreach(chnl0_arr[i]) chnl_write(0, chnl0_arr[i]);
  // channel 1 test
  // TODO use chnl1_arr to send all data
  foreach(chnl1_arr[i]) chnl_write(1, chnl1_arr[i]);
  // channel 2 test
  // TODO use chnl2_arr to send all data
  foreach(chnl2_arr[i]) chnl_write(2, chnl2_arr[i]);
end

TB4.验证结构

为了实现清晰的验证结构, 我们希望将 DUT 和激励发生器(stimulator) 之间划分。 因此,我们可以将激励方法 chnl_write()封装在新的模块 chnl_ initiator 中, 请同学们下载 tb4.sv, 在接下来开展实验步骤前, 同学们可以将“数组的使用” 环节中添加的代码部分移动到 tb4.sv对应的位置上。
从 tb4.sv 中同学们可以发现之前的 initil 语句块“channel_ write_task” 已经不见了, 在其位置上的变为了三个例化的 chnl_initiator 实例 chnl0_init、 chnl1_ init 和 chnl2_init。 它们的作用扮演每个 channel_slave 通道对应的 stimulator, 发送激励, 因此我们在其模块chnl_initiator 中定义了它的三个方法, 即 set_ name()、 chpl_write()和 chnl_idle()。
在这里插入图片描述
在这里插入图片描述

`timescale 1ns/1ps


module chnl_initiator(
  input               clk,
  input               rstn,
  output logic [31:0] ch_data,
  output logic        ch_valid,
  input               ch_ready,
  input        [ 5:0] ch_margin
);

string name;

function void set_name(string s);
  name = s;
endfunction

task chnl_write(input logic[31:0] data);
  // USER TODO
  // drive valid data
  // ...
  @(posedge clk);
  ch_valid <= 1;
  ch_data  <= data;
  @(negedge clk);
  wait(ch_ready == 'b1);

  $display("%t channel initial [%s] sent data %x", $time, name, data);
  chnl_idle();
endtask

task chnl_idle();
  // USER TODO
  // drive idle data
  // ..
  @(posedge clk);
  ch_valid <= 0;
  ch_data  <= 0;

endtask

endmodule

module tb4;
logic         clk;
logic         rstn;
logic [31:0]  ch0_data;
logic         ch0_valid;
logic         ch0_ready;
logic [ 5:0]  ch0_margin;
logic [31:0]  ch1_data;
logic         ch1_valid;
logic         ch1_ready;
logic [ 5:0]  ch1_margin;
logic [31:0]  ch2_data;
logic         ch2_valid;
logic         ch2_ready;
logic [ 5:0]  ch2_margin;
logic [31:0]  mcdt_data;
logic         mcdt_val;
logic [ 1:0]  mcdt_id;

mcdt dut(
   .clk_i(clk)
  ,.rstn_i(rstn)
  ,.ch0_data_i(ch0_data)
  ,.ch0_valid_i(ch0_valid)
  ,.ch0_ready_o(ch0_ready)
  ,.ch0_margin_o(ch0_margin)
  ,.ch1_data_i(ch1_data)
  ,.ch1_valid_i(ch1_valid)
  ,.ch1_ready_o(ch1_ready)
  ,.ch1_margin_o(ch1_margin)
  ,.ch2_data_i(ch2_data)
  ,.ch2_valid_i(ch2_valid)
  ,.ch2_ready_o(ch2_ready)
  ,.ch2_margin_o(ch2_margin)
  ,.mcdt_data_o(mcdt_data)
  ,.mcdt_val_o(mcdt_val)
  ,.mcdt_id_o(mcdt_id)
);

// clock generation
initial begin 
  clk <= 0;
  forever begin
    #5 clk <= !clk;
  end
end

// reset trigger
initial begin 
  #10 rstn <= 0;
  repeat(10) @(posedge clk);
  rstn <= 1;
end

logic [31:0] chnl0_arr[];
logic [31:0] chnl1_arr[];
logic [31:0] chnl2_arr[];
// USER TODO
// generate 100 data for each dynamic array
initial begin
  chnl0_arr = new [100];
  chnl1_arr = new [100];
  chnl2_arr = new [100];
  foreach(chnl0_arr[i])begin
    chnl0_arr[i] = 'h00C0_00000 + i;
    chnl1_arr[i] = 'h00C1_00000 + i;
    chnl2_arr[i] = 'h00C2_00000 + i;
  end
end

// USER TODO
// use the dynamic array, user would send all of data
// data test
initial begin 
  @(posedge rstn);
  repeat(5) @(posedge clk);
  // USER TODO
  // Give unique names to each channel initiator
  // ...
  chnl0_init.set_name("chnl0_init");
  chnl1_init.set_name("chnl1_init");
  chnl2_init.set_name("chnl2_init");

  // channel 0 test
  // TODO use chnl0_arr to send all data
  foreach(chnl0_arr[i]) chnl0_init.chnl_write(chnl0_arr[i]);

  // channel 1 test
  // TODO use chnl1_arr to send all data
  foreach(chnl1_arr[i]) chnl1_init.chnl_write(chnl1_arr[i]);


  // channel 2 test
  // TODO use chnl2_arr to send all data
  foreach(chnl2_arr[i]) chnl2_init.chnl_write(chnl2_arr[i]);

end

chnl_initiator chnl0_init(
  .clk      (clk),
  .rstn     (rstn),
  .ch_data  (ch0_data),
  .ch_valid (ch0_valid),
  .ch_ready (ch0_ready),
  .ch_margin(ch0_margin) 
);

chnl_initiator chnl1_init(
  .clk      (clk),
  .rstn     (rstn),
  .ch_data  (ch1_data),
  .ch_valid (ch1_valid),
  .ch_ready (ch1_ready),
  .ch_margin(ch1_margin) 
);

chnl_initiator chnl2_init(
  .clk      (clk),
  .rstn     (rstn),
  .ch_data  (ch2_data),
  .ch_valid (ch2_valid),
  .ch_ready (ch2_ready),
  .ch_margin(ch2_margin) 
);

endmodule


如何发送更快更紧密的数据?

initial begin 
  @(posedge rstn);
  repeat(5) @(posedge clk);
  chnl0_init.set_name("chnl0_init");
  foreach(chnl0_arr[i]) chnl0_init.chnl_write(chnl0_arr[i]);
end
initial begin 
  @(posedge rstn);
  repeat(5) @(posedge clk);
  chnl1_init.set_name("chnl1_init");
  foreach(chnl1_arr[i]) chnl1_init.chnl_write(chnl1_arr[i]);
end
initial begin 
  @(posedge rstn);
  repeat(5) @(posedge clk);
  chnl2_init.set_name("chnl2_init");
  foreach(chnl2_arr[i]) chnl2_init.chnl_write(chnl2_arr[i]);
end
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绫韵枫汐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值