目录
1.2 用idle_cycles表示相邻两个有效数据之间的周期
实验2
首先是要用接口来封装信号
1.0 接口的使用
`timescale 1ns/1ps
//定义一个接口chnl_intf,其输入是clk和rstn
interface chnl_intf(input clk, input rstn);
//定义四个变量,这些在实验1时是作为initiator的输入和输出来处理的,接口的作用就是来封装这些信号
logic [31:0] ch_data;
logic ch_valid;
logic ch_ready;
logic [ 5:0] ch_margin;
//定义时钟块进行采样和输出,防止竞争
clocking drv_ck @(posedge clk);
default input #1ns output #1ns;
//采样的是ready和margin,要准备好且有剩余空间才可以驱动data
//驱动data和valid
output ch_data, ch_valid;
input ch_ready, ch_margin;
endclocking
endinterface
//定义initiator,输入是上面定义的interface。intf表示什么?????
module chnl_initiator(chnl_intf intf);
string name;
int idle_cycles = 1;//表示相邻有效数据之间的间隔
//输入n,将idle_cycles设置为n,初始值是1
function automatic void set_idle_cycles(int n);
idle_cycles = n;
endfunction
//输入字符串s,将name设置为s
function automatic void set_name(string s);
name = s;
endfunction
1.1 用接口中的时钟块来实现数据的采样和驱动
时钟块的定义如上面的代码,以下是应用
task automatic chnl_write(input logic[31:0] data);
@(posedge intf.clk);
//用interface中的时钟块drv_ck取代之前的clk
//上升沿到了就把data送到接口对应的logic中
intf.drv_ck.ch_valid <= 1;
intf.drv_ck.ch_data <= data;
@(negedge intf.clk);
wait(intf.ch_ready === 'b1);
$display("%t channel initiator [%s] sent data %x", $time, name, data);
repeat(idle_cycles) chnl_idle();//两个有效数据之间有多少间隔就执行多少次下面的任务chnl_idle()
endtask
task automatic chnl_idle();
@(posedge intf.clk);
intf.drv_ck.ch_valid <= 0;
intf.drv_ck.ch_data <= 0;
endtask
endmodule
1.2 用idle_cycles表示相邻两个有效数据之间的周期
上面是接口,接下来是generator
//generator的代码
module chnl_generator;
int chnl_arr[$];//定义一个队列,队列元素的标号从0到$,一开始空间为0
int num;
int id;
//初始化的函数,输入id且num清0
function automatic void initialize(int n);
id = n;
num = 0;
endfunction
//这里发现了实验1中偷懒没搞明白的地方,为什么data是这样算,为什么有c?
//回去看了对应的部分,这里是给出数据流
function automatic int get_data();
int data;
data = 'h00C0_0000 + (id<<16) + num;
num++;
chnl_arr.push_back(data);//从队列尾部写入一个data
return data;
endfunction
endmodule
然后是tb的主体部分了,这里还是先用module。
三个通道一共12个信号都被封装到接口中。
//先给出的是实验1中没有接口时的变量和例化
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上
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)
);
//————————————————————————————————————————————————————————————
//然后是实验2用接口封装了这些信号后的tb例化
module tb1_ref;
logic clk;
logic rstn;
logic [31:0] mcdt_data;
logic mcdt_val;
logic [ 1:0] mcdt_id;
mcdt dut(
.clk_i (clk )
,.rstn_i (rstn )
,.ch0_data_i (chnl0_if.ch_data )
,.ch0_valid_i (chnl0_if.ch_valid )
,.ch0_ready_o (chnl0_if.ch_ready )
,.ch0_margin_o(chnl0_if.ch_margin )
,.ch1_data_i (chnl1_if.ch_data )
,.ch1_valid_i (chnl1_if.ch_valid )
,.ch1_ready_o (chnl1_if.ch_ready )
,.ch1_margin_o(chnl1_if.ch_margin )
,.ch2_data_i (chnl2_if.ch_data )
,.ch2_valid_i (chnl2_if.ch_valid )
,.ch2_ready_o (chnl2_if.ch_ready )
,.ch2_margin_o(chnl2_if.ch_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