目录
多路数据分配器MCDT
一、前言
lab1的中的组件只有initiator。
二、验证结构框图
三、代码分析
1、tb部分
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)
);
// --------时钟的产生
initial begin
clk <= 0;
forever begin
#5 clk <= !clk;
end
end
//--------- 复位的产生
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[];
//----动态数组分配元素
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
initial begin
@(posedge rstn);
repeat(5) @(posedge clk);
//set.name方便下面执行写任务时打印 :*通道发送数据**
chnl0_init.set_name("chnl0_init");
chnl1_init.set_name("chnl1_init");
chnl2_init.set_name("chnl2_init");
foreach(chnl0_arr[i]) chnl0_init.chnl_write(chnl0_arr[i]);
foreach(chnl1_arr[i]) chnl1_init.chnl_write(chnl1_arr[i]);
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
2、initiator部分
`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
四、总结
仿真阶段:
- 激励数据的生成: 动态数组 + foreach遍历数组元素并赋值。
- 激励数据写入:task_case -> task(write)+ 调用name task + 调用idle task。
重点:
- transaction是怎么生成的:直接在TB声明动态数组
- transaction是在什么情况下写入:在write任务中,满足时序关系后先关信号赋值
- TB与各组件之间的连接:initiator和dut 分别在TB中例化,并分别与TB信号连接
- fifo是往里写数据,往外读数据
答:由于每次写完数据后都有一个chnl_idle()的空闲一个周期,而slave_fifo的chx_ready信号是在fifo不为满的情况下为拉高1状态,并且chnl_idle()空闲导致写一个读一个,导致永远fifo不为满状态,因此没有充分利用空间,chx_ready信号一直为高。因此chx_margin余量一直在32和31之间变化,读一个空间减一,空闲之后空间加一。