MCDF--lab01

写在前面

具体实验code可通过以下链接下载:

链接:https://pan.baidu.com/s/1E731af2LgIZzyOzlYZi94Q?pwd=qkxu 
提取码:qkxu

code:

`timescale 1ns/1ps

module tb1;
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

// data test
initial begin 
  @(posedge rstn);
  repeat(5) @(posedge clk);
  // channel 0 test
  chnl_write(0, 'h00C0_0000);
  chnl_write(0, 'h00C0_0001);
  chnl_write(0, 'h00C0_0002);
  chnl_write(0, 'h00C0_0003);
  chnl_write(0, 'h00C0_0004);
  chnl_write(0, 'h00C0_0005);
  chnl_write(0, 'h00C0_0006);
  chnl_write(0, 'h00C0_0007);
  chnl_write(0, 'h00C0_0008);
  chnl_write(0, 'h00C0_0009);
  // channel 1 test
  chnl_write(1, 'h00C1_0000);
  chnl_write(1, 'h00C1_0001);
  chnl_write(1, 'h00C1_0002);
  chnl_write(1, 'h00C1_0003);
  chnl_write(1, 'h00C1_0004);
  chnl_write(1, 'h00C1_0005);
  chnl_write(1, 'h00C1_0006);
  chnl_write(1, 'h00C1_0007);
  chnl_write(1, 'h00C1_0008);
  chnl_write(1, 'h00C1_0009);
  // channel 2 test
  chnl_write(2, 'h00C2_0000);
  chnl_write(2, 'h00C2_0001);
  chnl_write(2, 'h00C2_0002);
  chnl_write(2, 'h00C2_0003);
  chnl_write(2, 'h00C2_0004);
  chnl_write(2, 'h00C2_0005);
  chnl_write(2, 'h00C2_0006);
  chnl_write(2, 'h00C2_0007);
  chnl_write(2, 'h00C2_0008);
  chnl_write(2, 'h00C2_0009);
end

// channel write task
task chnl_write(input logic[1:0] id, input logic[31:0] data); 
  case(id)
    0: begin
      @(posedge clk);
      ch0_valid <= 1;
      ch0_data <= data;
      @(posedge clk);
      ch0_valid <= 0;
      ch0_data <= 0;
    end
    1: begin
      @(posedge clk);
      ch1_valid <= 1;
      ch1_data <= data;
      @(posedge clk);
      ch1_valid <= 0;
      ch1_data <= 0;
    end
    2: begin
      @(posedge clk);
      ch2_valid <= 1;
      ch2_data <= data;
      @(posedge clk);
      ch2_valid <= 0;
      ch2_data <= 0;
    end
    default: $error("channel id %0d is invalid", id);
  endcase
endtask

endmodule

方法task和函数function的练习 

tb1之前产生时钟和发起复位的两个initial 过程块语句都被tb2两个task即clk_gen()和rstn_gen()取代了。 以下为对比代码:

 数组的使用

使用tb1的赋值方法太过于繁琐,如果写入数据较少还可以接受,但是例如要写入100,200个较多的数据时,这样重复性的操作会使代码量增大,所以这部分赋值可以采用动态数组,需要写入多少数据就为其开辟相应的空间,并对开辟的空间进行赋值,最后通过chnl_write方法写入channel。

 tb3波形:

验证结构

为了实现清晰的验证结构, 我们希望将DUT 和激励发生器(stimulator)之间划分。 因此, 我们可
以将激励方法chnl_write()封装在新的模块chnl_initiator中,如下:

 可以发现之前的 initial语句块"channel write task"已经不见了, 在其位置上的变为了三个例化的chnl_initiator实例chnl0_init 、chnl1_init 和chnl2_init。 它们的作用扮演每个channel slave通道对应的 stimulator, 发送激励 , 因此我们在其模块chnl_initiator中定义了它的三个方法 , set_name() 、chnl_write()和chnl_idle()。

完整code:

`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_ref;
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("chnl0_init");
  chnl2_init.set_name("chnl0_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

 波形:

从仿真波形可以看出,chnl_ready信号一直是拉高的状态, 也就是说FIFO一直有空间可以写入数据,处于未满状态。那有没有什么方法可以让ready拉低,换言之,只有写入的数据比读出的数据快就可能出现ready拉低的情况,分析以上代码,我们发现:1.在每次写入数据之后紧跟一个write_idle(),这样实际上两拍才会写入一个数据;2.一共有3个slave,但是他们的chnl_write()在initial块中是顺序执行的,每次只有一个slave在往FIFO写入数据,如果换成并行执行,是不是也可以使chnl_ready拉低。

结合以上分析,我们对刚才的代码进行修改,如下:

`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 == 1); 
  $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
  // ...
  fork
  begin
  chnl0_init.set_name("chnl0_init");
  foreach(chnl0_arr[i]) chnl0_init.chnl_write(chnl0_arr[i]);
  chnl0_init.chnl_idle();
  end
  // channel 1 test
  // TODO use chnl1_arr to send all data
  begin 
   chnl1_init.set_name("chnl1_init");
   foreach(chnl1_arr[i]) chnl1_init.chnl_write(chnl1_arr[i]);
    chnl1_init.chnl_idle();
  end
  // channel 2 test
  // TODO use chnl2_arr to send all datsa
  begin 
  chnl2_init.set_name("chnl2_init");
  foreach(chnl2_arr[i]) chnl2_init.chnl_write(chnl2_arr[i]);
   chnl2_init.chnl_idle();
  end
  join
  // channel 0 test
  // TODO use chnl0_arr to send all data
  /*chnl0_init.chnl_write('h00C0_0000);
  chnl0_init.chnl_write('h00C0_0001);
  chnl0_init.chnl_write('h00C0_0002);
  chnl0_init.chnl_write('h00C0_0003);

  // channel 1 test
  // TODO use chnl1_arr to send all data
  chnl1_init.chnl_write('h00C1_0000);
  chnl1_init.chnl_write('h00C1_0001);
  chnl1_init.chnl_write('h00C1_0002);
  chnl1_init.chnl_write('h00C1_0003);

  // channel 2 test
  // TODO use chnl2_arr to send all data
  chnl2_init.chnl_write('h00C2_0000);
  chnl2_init.chnl_write('h00C2_0001);
  chnl2_init.chnl_write('h00C2_0002);
  chnl2_init.chnl_write('h00C2_0003);*/
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

 波形:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

创芯人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值