Finish top-module(axi_slave array_ctrl apb_cfg): 2025-08-13 16:39:12
This commit is contained in:
110
tb/tb_apb_cfg.v
Normal file
110
tb/tb_apb_cfg.v
Normal file
@@ -0,0 +1,110 @@
|
||||
module tb_apb_cfg;
|
||||
reg apb_pclk;
|
||||
reg apb_prstn;
|
||||
|
||||
//from apb master
|
||||
reg apb_psel;
|
||||
reg apb_penable;
|
||||
reg apb_pwrite;
|
||||
reg [7:0] apb_paddr;
|
||||
reg [31:0] apb_wdata;
|
||||
|
||||
//to apb master
|
||||
wire [31:0] apb_rdata;
|
||||
wire apb_pready;
|
||||
|
||||
//cfg
|
||||
//mode ctrl
|
||||
wire mc_work_en;
|
||||
wire [1:0] axi_rw_priority;
|
||||
//
|
||||
wire [7:0] array_ras_cfg;
|
||||
wire [7:0] array_rp_cfg;
|
||||
wire [7:0] array_rc_cfg;
|
||||
//
|
||||
wire [7:0] array_rcd_wr_cfg;
|
||||
wire [7:0] array_wr_cfg;
|
||||
//
|
||||
wire [7:0] array_rcd_rd_cfg;
|
||||
wire [7:0] array_rtp_cfg;
|
||||
//
|
||||
wire [25:0] array_ref_period0;
|
||||
wire [25:0] array_ref_period1;
|
||||
wire array_ref_sel;
|
||||
|
||||
apb_cfg u_apb_cfg(
|
||||
.apb_pclk(apb_pclk),
|
||||
.apb_prstn(apb_prstn),
|
||||
.apb_psel(apb_psel),
|
||||
.apb_penable(apb_penable),
|
||||
.apb_pwrite(apb_pwrite),
|
||||
.apb_paddr(apb_paddr),
|
||||
.apb_wdata(apb_wdata),
|
||||
|
||||
.apb_rdata(apb_rdata),
|
||||
.apb_pready(apb_pready),
|
||||
|
||||
.mc_work_en(mc_work_en),
|
||||
.axi_rw_priority(axi_rw_priority),
|
||||
|
||||
.array_ras_cfg(array_ras_cfg),
|
||||
.array_rp_cfg(array_rp_cfg),
|
||||
.array_rc_cfg(array_rc_cfg),
|
||||
|
||||
.array_rcd_wr_cfg(array_rcd_wr_cfg),
|
||||
.array_wr_cfg(array_wr_cfg),
|
||||
|
||||
.array_rcd_rd_cfg(array_rcd_rd_cfg),
|
||||
.array_rtp_cfg(array_rtp_cfg),
|
||||
|
||||
.array_ref_period0(array_ref_period0),
|
||||
.array_ref_period1(array_ref_period1),
|
||||
.array_ref_sel(array_ref_sel)
|
||||
);
|
||||
|
||||
initial begin
|
||||
apb_pclk = 1'b0;
|
||||
apb_prstn = 1'b0;
|
||||
#20
|
||||
apb_prstn = 1'b1;
|
||||
end
|
||||
always #10 apb_pclk = ~apb_pclk;
|
||||
|
||||
initial begin
|
||||
apb_psel = 1'b0;
|
||||
apb_penable = 1'b0;
|
||||
apb_pwrite = 1'b0;
|
||||
apb_paddr = 'b0;
|
||||
apb_wdata = 'b0;
|
||||
end
|
||||
|
||||
//task wr
|
||||
task apb_wr;
|
||||
input apb_paddr_temp;
|
||||
input apb_wdata_temp;
|
||||
begin
|
||||
wait(apb_pready);
|
||||
@(negedge apb_pclk);
|
||||
apb_paddr = apb_paddr_temp;
|
||||
apb_wdata = apb_wdata_temp;
|
||||
apb_psel = 1'b1;
|
||||
apb_pwrite = 1'b1;
|
||||
apb_penable = 1'b0;
|
||||
@(posedge apb_pclk);
|
||||
#0.7
|
||||
apb_penable = 1'b1;
|
||||
wait(apb_pready);
|
||||
@(posedge apb_pclk);
|
||||
apb_psel = 1'b0;
|
||||
apb_pwrite = 1'b0;
|
||||
apb_penable = 1'b0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
#50
|
||||
apb_wr(8'h00,{31'b0,1'b1});
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
257
tb/tb_array_ctrl.v
Normal file
257
tb/tb_array_ctrl.v
Normal file
@@ -0,0 +1,257 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module tb_array_ctrl;
|
||||
|
||||
// 时钟与复位信号
|
||||
reg clk;
|
||||
reg rst_n;
|
||||
|
||||
// AXI到array的帧信号
|
||||
reg axi2array_frame_valid;
|
||||
reg [152:0] axi2array_frame_data;
|
||||
wire axi2array_frame_ready;
|
||||
|
||||
// array到AXI的读数据信号
|
||||
wire array2axi_rdata_valid;
|
||||
wire [127:0] array2axi_rdata;
|
||||
|
||||
// array接口信号
|
||||
wire array_csn;
|
||||
wire [15:0] array_raddr;
|
||||
wire array_caddr_vld_wr;
|
||||
wire [5:0] array_caddr_wr;
|
||||
wire array_wdata_vld;
|
||||
wire [127:0] array_wdata;
|
||||
wire array_caddr_vld_rd;
|
||||
wire [5:0] array_caddr_rd;
|
||||
reg array_rdata_vld;
|
||||
reg [127:0] array_rdata;
|
||||
|
||||
// APB配置信号(内存控制器时序参数)
|
||||
reg mc_work_en;
|
||||
reg [7:0] array_inner_tras; // 行预充电时间
|
||||
reg [7:0] array_inner_trp; // 预充电到激活时间
|
||||
reg [7:0] array_inner_trcd_wr;// 激活到写命令时间
|
||||
reg [7:0] array_inner_twr; // 写恢复时间
|
||||
reg [7:0] array_inner_trcd_rd;// 激活到读命令时间
|
||||
reg [7:0] array_inner_trtp; // 读预充电时间
|
||||
reg array_ref_en; // 刷新使能
|
||||
reg [24:0] array_inner_tref0; // 刷新间隔0
|
||||
reg [24:0] array_inner_tref1; // 刷新间隔1
|
||||
reg array_inner_ref_sel;// 刷新间隔选择
|
||||
|
||||
// 实例化被测模块
|
||||
array_ctrl u_array_ctrl (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.axi2array_frame_valid (axi2array_frame_valid),
|
||||
.axi2array_frame_data (axi2array_frame_data),
|
||||
.axi2array_frame_ready (axi2array_frame_ready),
|
||||
.array2axi_rdata_valid (array2axi_rdata_valid),
|
||||
.array2axi_rdata (array2axi_rdata),
|
||||
.array_csn (array_csn),
|
||||
.array_raddr (array_raddr),
|
||||
.array_caddr_vld_wr (array_caddr_vld_wr),
|
||||
.array_caddr_wr (array_caddr_wr),
|
||||
.array_wdata_vld (array_wdata_vld),
|
||||
.array_wdata (array_wdata),
|
||||
.array_caddr_vld_rd (array_caddr_vld_rd),
|
||||
.array_caddr_rd (array_caddr_rd),
|
||||
.array_rdata_vld (array_rdata_vld),
|
||||
.array_rdata (array_rdata),
|
||||
.mc_work_en (mc_work_en),
|
||||
.array_inner_tras (array_inner_tras),
|
||||
.array_inner_trp (array_inner_trp),
|
||||
.array_inner_trcd_wr (array_inner_trcd_wr),
|
||||
.array_inner_twr (array_inner_twr),
|
||||
.array_inner_trcd_rd (array_inner_trcd_rd),
|
||||
.array_inner_trtp (array_inner_trtp),
|
||||
.array_ref_en (array_ref_en),
|
||||
.array_inner_tref0 (array_inner_tref0),
|
||||
.array_inner_tref1 (array_inner_tref1),
|
||||
.array_inner_ref_sel (array_inner_ref_sel)
|
||||
);
|
||||
|
||||
// 时钟生成:50MHz(周期20ns)
|
||||
initial begin
|
||||
clk = 1'b0;
|
||||
forever #1.25 clk = ~clk;
|
||||
end
|
||||
|
||||
// 复位与初始化流程
|
||||
initial begin
|
||||
// 初始复位状态
|
||||
rst_n = 1'b0;
|
||||
axi2array_frame_valid = 1'b0;
|
||||
axi2array_frame_data = 153'd0;
|
||||
array_rdata_vld = 1'b0;
|
||||
array_rdata = 128'd0;
|
||||
mc_work_en = 1'b0;
|
||||
// 初始化时序参数(示例值,模拟真实内存时序)
|
||||
array_inner_tras = 8'd16; // 行预充电时间:2个时钟周期
|
||||
array_inner_trp = 8'd6; // 预充电到激活时间:1个时钟周期
|
||||
array_inner_trcd_wr = 8'd7; // 激活到写命令时间:1个时钟周期
|
||||
array_inner_twr = 8'd6; // 写恢复时间:3个时钟周期
|
||||
array_inner_trcd_rd = 8'd7; // 激活到读命令时间:1个时钟周期
|
||||
array_inner_trtp = 8'd3; // 读预充电时间:1个时钟周期
|
||||
array_ref_en = 1'b0; // 初始关闭刷新
|
||||
array_inner_tref0 = 25'd100; // 刷新间隔0:5个时钟周期(100ns)
|
||||
array_inner_tref1 = 25'd60; // 刷新间隔1:10个时钟周期(200ns)
|
||||
array_inner_ref_sel = 1'b0; // 默认选择刷新间隔0
|
||||
|
||||
// 释放复位并启动控制器
|
||||
#100 rst_n = 1'b1; // 100ns后释放复位
|
||||
#50 mc_work_en = 1'b1; // 50ns后使能控制器工作
|
||||
|
||||
// 测试场景1:单周期写操作(完整帧:含SOF和EOF)
|
||||
@(posedge clk);
|
||||
// 帧数据格式:[152]操作类型(1=写), [151]SOF, [150]EOF, [149:134]行地址, [133:128]列地址, [127:0]数据
|
||||
axi2array_frame_data = {1'b1, 1'b1, 1'b1, 16'h1234, 6'h0A, 128'h5A5A_5A5A_5A5A_5A5A_5A5A_5A5A_5A5A_5A5A};
|
||||
axi2array_frame_valid = 1'b1; // 发送写请求
|
||||
@(posedge axi2array_frame_ready); // 等待控制器接收
|
||||
axi2array_frame_valid = 1'b0; // 撤销请求
|
||||
#200; // 等待写操作完成(含时序延迟)
|
||||
|
||||
// 测试场景2:多周期写操作(分帧传输,SOF=首帧,EOF=尾帧)
|
||||
@(posedge clk);
|
||||
// 首帧:SOF=1,EOF=0
|
||||
axi2array_frame_data = {1'b1, 1'b1, 1'b0, 16'h5678, 6'h0B, 128'hA5A5_A5A5_A5A5_A5A5_A5A5_A5A5_A5A5_A5A5};
|
||||
axi2array_frame_valid = 1'b1;
|
||||
@(posedge axi2array_frame_ready);
|
||||
// 次帧:SOF=0,EOF=0
|
||||
axi2array_frame_data = {1'b1, 1'b0, 1'b0, 16'h5678, 6'h0C, 128'hAA55_AA55_AA55_AA55_AA55_AA55_AA55_AA55};
|
||||
@(posedge axi2array_frame_ready);
|
||||
// 尾帧:SOF=0,EOF=1
|
||||
axi2array_frame_data = {1'b1, 1'b0, 1'b1, 16'h5678, 6'h0D, 128'h55AA_55AA_55AA_55AA_55AA_55AA_55AA_55AA};
|
||||
@(posedge axi2array_frame_ready);
|
||||
axi2array_frame_valid = 1'b0;
|
||||
#300; // 等待多帧写完成
|
||||
|
||||
// 测试场景3:单周期读操作(读取场景1写入的数据)
|
||||
@(posedge clk);
|
||||
// 帧数据格式:[152]操作类型(0=读), [151]SOF, [150]EOF, [149:134]行地址, [133:128]列地址, [127:0]无效(读数据由array返回)
|
||||
axi2array_frame_data = {1'b0, 1'b1, 1'b1, 16'h1234, 6'h0A, 128'd0};
|
||||
axi2array_frame_valid = 1'b1; // 发送读请求
|
||||
@(posedge axi2array_frame_ready);
|
||||
axi2array_frame_valid = 1'b0;
|
||||
// 模拟array返回读数据(延迟1个时钟周期,符合时序)
|
||||
#20; // 等待控制器发起读命令
|
||||
array_rdata = 128'h5A5A_5A5A_5A5A_5A5A_5A5A_5A5A_5A5A_5A5A; // 预期数据(与场景1写入一致)
|
||||
array_rdata_vld = 1'b1;
|
||||
@(posedge clk);
|
||||
array_rdata_vld = 1'b0; // 撤销读数据有效
|
||||
#200; // 等待读响应返回AXI
|
||||
|
||||
// 测试场景4:读写混合操作(写后立即读,验证数据一致性)
|
||||
@(posedge clk);
|
||||
// 先写
|
||||
axi2array_frame_data = {1'b1, 1'b1, 1'b1, 16'h9ABC, 6'h0E, 128'h1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0};
|
||||
axi2array_frame_valid = 1'b1;
|
||||
@(posedge axi2array_frame_ready);
|
||||
axi2array_frame_valid = 1'b0;
|
||||
#100; // 等待写完成
|
||||
// 立即读
|
||||
axi2array_frame_data = {1'b0, 1'b1, 1'b1, 16'h9ABC, 6'h0E, 128'd0};
|
||||
axi2array_frame_valid = 1'b1;
|
||||
@(posedge axi2array_frame_ready);
|
||||
axi2array_frame_valid = 1'b0;
|
||||
#20;
|
||||
array_rdata = 128'h1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0; // 验证写后读一致性
|
||||
array_rdata_vld = 1'b1;
|
||||
@(posedge clk);
|
||||
array_rdata_vld = 1'b0;
|
||||
#200;
|
||||
|
||||
// 测试场景5:刷新操作(使能刷新,验证控制器响应)
|
||||
@(posedge clk);
|
||||
array_ref_en = 1'b1; // 开启刷新
|
||||
#(2.5*array_inner_tref0); // 等待至少1个刷新周期(根据tref0=5个时钟周期)
|
||||
array_ref_en = 1'b0; // 关闭刷新
|
||||
#100;
|
||||
|
||||
// 测试场景6:刷新与读写冲突(刷新期间发起读写,验证优先级)
|
||||
@(posedge clk);
|
||||
array_ref_en = 1'b1; // 开启刷新
|
||||
#50; // 确保刷新已启动
|
||||
// 尝试写入(预期被阻塞,直到刷新完成)
|
||||
axi2array_frame_data = {1'b1, 1'b1, 1'b1, 16'hDEF0, 6'h0F, 128'hFEDC_BA98_7654_3210_FEDC_BA98_7654_3210};
|
||||
axi2array_frame_valid = 1'b1;
|
||||
@(posedge axi2array_frame_ready); // 可能延迟,因刷新优先级更高
|
||||
axi2array_frame_valid = 1'b0;
|
||||
array_ref_en = 1'b0; // 关闭刷新
|
||||
#200;
|
||||
|
||||
// 测试场景7:边界地址读写(最大行/列地址)
|
||||
@(posedge clk);
|
||||
// 写最大地址
|
||||
axi2array_frame_data = {1'b1, 1'b1, 1'b1, 16'hFFFF, 6'h3F, 128'hFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF};
|
||||
axi2array_frame_valid = 1'b1;
|
||||
@(posedge axi2array_frame_ready);
|
||||
axi2array_frame_valid = 1'b0;
|
||||
#200;
|
||||
// 读最大地址
|
||||
axi2array_frame_data = {1'b0, 1'b1, 1'b1, 16'hFFFF, 6'h3F, 128'd0};
|
||||
axi2array_frame_valid = 1'b1;
|
||||
@(posedge axi2array_frame_ready);
|
||||
axi2array_frame_valid = 1'b0;
|
||||
#20;
|
||||
array_rdata = 128'hFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF; // 验证边界地址数据
|
||||
array_rdata_vld = 1'b1;
|
||||
@(posedge clk);
|
||||
array_rdata_vld = 1'b0;
|
||||
#200;
|
||||
|
||||
// 测试结束
|
||||
#1000;
|
||||
$display("所有测试场景完成!");
|
||||
$finish;
|
||||
end
|
||||
|
||||
// 波形记录(用于仿真后分析)
|
||||
initial begin
|
||||
$fsdbDumpfile("tb.fsdb"); // 记录FSDB格式波形
|
||||
$fsdbDumpvars(0, tb_array_ctrl, "+all"); // 记录所有信号
|
||||
$vcdpluson; // 记录VCD+格式波形
|
||||
$vcdplusmemon; // 记录内存信号
|
||||
end
|
||||
|
||||
// 信号监控与断言(验证关键功能)
|
||||
initial begin
|
||||
$monitor(
|
||||
"Time: %0t, 写有效: %b, 读有效: %b, 刷新使能: %b, CSN: %b, 行地址: %h, 列地址(写): %h, 列地址(读): %h",
|
||||
$time, array_wdata_vld, array_caddr_vld_rd, array_ref_en, array_csn, array_raddr, array_caddr_wr, array_caddr_rd
|
||||
);
|
||||
|
||||
// 断言1:复位期间片选信号CSN应为高(无效)
|
||||
@(negedge rst_n);
|
||||
if (array_csn !== 1'b1) begin
|
||||
$error("复位期间CSN应为高!Time: %0t", $time);
|
||||
end
|
||||
|
||||
// 断言2:写操作时CSN应为低(有效),且写数据有效
|
||||
@(posedge array_wdata_vld);
|
||||
if (array_csn !== 1'b0) begin
|
||||
$error("写操作时CSN应为低!Time: %0t", $time);
|
||||
end
|
||||
|
||||
// 断言3:读操作时CSN应为低(有效),且读地址有效
|
||||
@(posedge array_caddr_vld_rd);
|
||||
if (array_csn !== 1'b0) begin
|
||||
$error("读操作时CSN应为低!Time: %0t", $time);
|
||||
end
|
||||
|
||||
// 断言4:读响应数据应与写入数据一致(场景3验证)
|
||||
@(posedge array2axi_rdata_valid);
|
||||
if (array2axi_rdata !== 128'h5A5A_5A5A_5A5A_5A5A_5A5A_5A5A_5A5A_5A5A) begin
|
||||
$error("读数据与写入数据不一致!Time: %0t", $time);
|
||||
end
|
||||
|
||||
// 断言5:刷新期间不应有读写操作(CSN保持高或读写信号无效)
|
||||
@(posedge array_ref_en);
|
||||
#10; // 等待刷新启动
|
||||
if (array_wdata_vld === 1'b1 || array_caddr_vld_rd === 1'b1) begin
|
||||
$error("刷新期间不应有读写操作!Time: %0t", $time);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
100
tb/tb_array_mux.v
Normal file
100
tb/tb_array_mux.v
Normal file
@@ -0,0 +1,100 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module tb_array_mux;
|
||||
|
||||
// 输入信号定义
|
||||
reg array_wr_csn; // 写操作片选
|
||||
reg [15:0] array_wr_raddr; // 写操作地址
|
||||
reg array_rd_csn; // 读操作片选
|
||||
reg [15:0] array_rd_raddr; // 读操作地址
|
||||
reg array_ref_csn; // 刷新操作片选
|
||||
reg [15:0] array_ref_raddr; // 刷新操作地址
|
||||
reg [1:0] array_mux_sel; // 选择控制信号
|
||||
|
||||
// 输出信号定义
|
||||
wire array_csn; // 输出片选
|
||||
wire [15:0] array_raddr; // 输出地址
|
||||
|
||||
// 例化被测试模块
|
||||
array_mux uut (
|
||||
.array_wr_csn (array_wr_csn),
|
||||
.array_wr_raddr (array_wr_raddr),
|
||||
.array_rd_csn (array_rd_csn),
|
||||
.array_rd_raddr (array_rd_raddr),
|
||||
.array_ref_csn (array_ref_csn),
|
||||
.array_ref_raddr (array_ref_raddr),
|
||||
.array_mux_sel (array_mux_sel),
|
||||
.array_csn (array_csn),
|
||||
.array_raddr (array_raddr)
|
||||
);
|
||||
|
||||
// 初始化测试向量
|
||||
initial begin
|
||||
// 初始值设置
|
||||
array_wr_csn = 1'b0;
|
||||
array_wr_raddr = 16'h1234;
|
||||
array_rd_csn = 1'b1;
|
||||
array_rd_raddr = 16'h5678;
|
||||
array_ref_csn = 1'b0;
|
||||
array_ref_raddr = 16'h9ABC;
|
||||
array_mux_sel = 2'b00;
|
||||
|
||||
// 等待10ns,确保初始状态稳定
|
||||
#10;
|
||||
|
||||
// 测试场景1:选择刷新操作(2'b01)
|
||||
array_mux_sel = 2'b01;
|
||||
#10;
|
||||
$display("Test Case 1 (sel=01): csn=%b, addr=%h (Expected: csn=%b, addr=%h)",
|
||||
array_csn, array_raddr, array_ref_csn, array_ref_raddr);
|
||||
|
||||
// 测试场景2:选择写操作(2'b10)
|
||||
array_mux_sel = 2'b10;
|
||||
#10;
|
||||
$display("Test Case 2 (sel=10): csn=%b, addr=%h (Expected: csn=%b, addr=%h)",
|
||||
array_csn, array_raddr, array_wr_csn, array_wr_raddr);
|
||||
|
||||
// 测试场景3:选择读操作(2'b11)
|
||||
array_mux_sel = 2'b11;
|
||||
#10;
|
||||
$display("Test Case 3 (sel=11): csn=%b, addr=%h (Expected: csn=%b, addr=%h)",
|
||||
array_csn, array_raddr, array_rd_csn, array_rd_raddr);
|
||||
|
||||
// 测试场景4:默认情况(2'b00)
|
||||
array_mux_sel = 2'b00;
|
||||
#10;
|
||||
$display("Test Case 4 (sel=00): csn=%b, addr=%h (Expected: csn=1, addr=0000)",
|
||||
array_csn, array_raddr);
|
||||
|
||||
// 测试场景5:动态改变输入值,验证实时性
|
||||
array_ref_csn = 1'b1;
|
||||
array_ref_raddr = 16'hDEF0;
|
||||
array_mux_sel = 2'b01;
|
||||
#10;
|
||||
$display("Test Case 5 (sel=01 updated): csn=%b, addr=%h (Expected: csn=%b, addr=%h)",
|
||||
array_csn, array_raddr, array_ref_csn, array_ref_raddr);
|
||||
|
||||
// 测试场景6:覆盖所有可能的选择信号
|
||||
array_mux_sel = 2'b00; #5;
|
||||
array_mux_sel = 2'b01; #5;
|
||||
array_mux_sel = 2'b10; #5;
|
||||
array_mux_sel = 2'b11; #5;
|
||||
|
||||
// 结束仿真
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
$fsdbDumpfile("tb.fsdb");
|
||||
$fsdbDumpvars(0,tb_array_mux,"+all");
|
||||
$vcdpluson;
|
||||
$vcdplusmemon;
|
||||
end
|
||||
|
||||
// 监控信号变化(可选,用于波形分析)
|
||||
initial begin
|
||||
$monitor("Time: %0t, sel=%b, csn=%b, addr=%h",
|
||||
$time, array_mux_sel, array_csn, array_raddr);
|
||||
end
|
||||
|
||||
endmodule
|
175
tb/tb_array_rd.v
Normal file
175
tb/tb_array_rd.v
Normal file
@@ -0,0 +1,175 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module tb_array_rd();
|
||||
|
||||
// 时钟和复位信号
|
||||
reg clk;
|
||||
reg rst_n;
|
||||
|
||||
// 输入信号(DUT 的输入)
|
||||
reg array_rd_frame_valid;
|
||||
reg [151:0] array_rd_frame_data;
|
||||
reg array_rdata_vld;
|
||||
reg [127:0] array_rdata;
|
||||
reg [7:0] array_inner_tras;
|
||||
reg [7:0] array_inner_trp;
|
||||
reg [7:0] array_inner_trcd_rd;
|
||||
reg [7:0] array_inner_trtp;
|
||||
|
||||
// 输出信号(DUT 的输出)
|
||||
wire array_rd_frame_ready;
|
||||
wire array_rd_done;
|
||||
wire array_rd_csn;
|
||||
wire [15:0] array_rd_raddr;
|
||||
wire array_caddr_vld_rd;
|
||||
wire [5:0] array_caddr_rd;
|
||||
wire array2axi_rdata_valid;
|
||||
wire [127:0] array2axi_rdata;
|
||||
|
||||
// 实例化被测试模块(DUT)
|
||||
array_rd u_array_rd(
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.array_rd_frame_valid(array_rd_frame_valid),
|
||||
.array_rd_frame_data(array_rd_frame_data),
|
||||
.array_rd_frame_ready(array_rd_frame_ready),
|
||||
.array_rd_done (array_rd_done),
|
||||
.array_rd_csn (array_rd_csn),
|
||||
.array_rd_raddr (array_rd_raddr),
|
||||
.array_caddr_vld_rd (array_caddr_vld_rd),
|
||||
.array_caddr_rd (array_caddr_rd),
|
||||
.array_rdata_vld (array_rdata_vld),
|
||||
.array_rdata (array_rdata),
|
||||
.array_inner_tras (array_inner_tras),
|
||||
.array_inner_trp (array_inner_trp),
|
||||
.array_inner_trcd_rd(array_inner_trcd_rd),
|
||||
.array_inner_trtp (array_inner_trtp),
|
||||
.array2axi_rdata_valid(array2axi_rdata_valid),
|
||||
.array2axi_rdata (array2axi_rdata)
|
||||
);
|
||||
|
||||
// 生成时钟(50MHz,周期 20ns)
|
||||
initial begin
|
||||
clk = 1'b0;
|
||||
forever #10 clk = ~clk;
|
||||
end
|
||||
|
||||
// 主测试流程
|
||||
initial begin
|
||||
// 初始化信号
|
||||
rst_n = 1'b0;
|
||||
array_rd_frame_valid = 1'b0;
|
||||
array_rd_frame_data = 152'd0;
|
||||
array_rdata_vld = 1'b0;
|
||||
array_rdata = 128'd0;
|
||||
array_inner_tras = 8'd3; // 示例值:TRAS = 3 个时钟周期
|
||||
array_inner_trp = 8'd2; // 示例值:TRP = 2 个时钟周期
|
||||
array_inner_trcd_rd = 8'd2; // 示例值:TRCD_RD = 2 个时钟周期
|
||||
array_inner_trtp = 8'd1; // 示例值:TRTP = 1 个时钟周期
|
||||
|
||||
// 复位释放(10 个时钟周期后)
|
||||
#200;
|
||||
rst_n = 1'b1;
|
||||
#20;
|
||||
|
||||
// 测试场景 1:单帧数据读取(含 SOF 和 EOF)
|
||||
$display("=== 测试场景 1:单帧数据读取 ===");
|
||||
send_frame(
|
||||
1'b1, // 起始标志
|
||||
1'b1, // 结束标志(单帧)
|
||||
16'h1234,// 读取地址
|
||||
6'h05, // 列地址
|
||||
128'h0 // 读取操作的帧数据中数据段无效,填0
|
||||
);
|
||||
#20;
|
||||
drive_rdata(128'hA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5); // 返回读取数据
|
||||
wait(array_rd_done); // 等待读取完成
|
||||
#100;
|
||||
|
||||
// 测试场景 2:多帧数据读取(首帧 SOF,末帧 EOF)
|
||||
$display("=== 测试场景 2:多帧数据读取 ===");
|
||||
// 第一帧(SOF=1,EOF=0)
|
||||
send_frame(
|
||||
1'b1,
|
||||
1'b0,
|
||||
16'h5678,
|
||||
6'h0A,
|
||||
128'h0 // 数据段无效
|
||||
);
|
||||
// 模拟返回第一帧数据
|
||||
drive_rdata(128'h55AA55AA55AA55AA55AA55AA55AA55AA);
|
||||
#10;
|
||||
// 第二帧(SOF=0,EOF=1)
|
||||
send_frame(
|
||||
1'b0,
|
||||
1'b1,
|
||||
16'h5678, // 地址与前一帧相同(连续读取)
|
||||
6'h0B,
|
||||
128'h0 // 数据段无效
|
||||
);
|
||||
drive_rdata(128'hAA55AA55AA55AA55AA55AA55AA55AA55);
|
||||
wait(array_rd_done); // 等待读取完成
|
||||
#100;
|
||||
|
||||
// 测试场景 3:无输入时的空闲状态
|
||||
$display("=== 测试场景 3:空闲状态验证 ===");
|
||||
array_rd_frame_valid = 1'b0;
|
||||
#200;
|
||||
|
||||
// 测试结束
|
||||
$display("=== 所有测试场景完成 ===");
|
||||
$finish;
|
||||
end
|
||||
|
||||
// 任务:发送一帧读取请求
|
||||
task send_frame;
|
||||
input rsof; // 帧起始标志
|
||||
input reof; // 帧结束标志
|
||||
input [15:0] rraddr; // 读取地址
|
||||
input [5:0] rcaddr; // 列地址
|
||||
input [127:0] wdata; // 占位(读取操作中无效)
|
||||
begin
|
||||
// 等待模块就绪(ready 信号为高)
|
||||
wait(array_rd_frame_ready);
|
||||
#10; // 延迟一小段时间
|
||||
|
||||
// 驱动输入信号
|
||||
array_rd_frame_valid = 1'b1;
|
||||
array_rd_frame_data = {rsof, reof, rraddr, rcaddr, wdata}; // 拼接帧数据
|
||||
#20; // 保持一个时钟周期
|
||||
|
||||
// 撤销有效信号
|
||||
array_rd_frame_valid = 1'b0;
|
||||
array_rd_frame_data = 152'd0;
|
||||
end
|
||||
endtask
|
||||
|
||||
// 任务:驱动读取数据返回
|
||||
task drive_rdata;
|
||||
input [127:0] data; // 要返回的读取数据
|
||||
begin
|
||||
array_rdata_vld = 1'b1;
|
||||
array_rdata = data;
|
||||
#20; // 保持一个时钟周期
|
||||
array_rdata_vld = 1'b0;
|
||||
array_rdata = 128'd0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
$fsdbDumpfile("tb.fsdb");
|
||||
$fsdbDumpvars(0,tb_array_rd,"+all");
|
||||
$vcdpluson;
|
||||
$vcdplusmemon;
|
||||
end
|
||||
|
||||
// 监控关键信号变化(用于调试)
|
||||
initial begin
|
||||
$monitor(
|
||||
"Time: %0t, State: %h, CSN: %b, Ready: %b, Done: %b, CaddrVld: %b, FIFOValid: %b",
|
||||
$time, u_array_rd.cur_state, array_rd_csn, array_rd_frame_ready,
|
||||
array_rd_done, array_caddr_vld_rd, array2axi_rdata_valid
|
||||
);
|
||||
end
|
||||
|
||||
endmodule
|
103
tb/tb_array_ref.v
Normal file
103
tb/tb_array_ref.v
Normal file
@@ -0,0 +1,103 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module tb_array_ref();
|
||||
|
||||
// 输入信号定义
|
||||
reg clk;
|
||||
reg rst_n;
|
||||
reg array_ref_start;
|
||||
reg [7:0] array_inner_tras;
|
||||
reg [7:0] array_inner_trp;
|
||||
|
||||
// 输出信号定义
|
||||
wire array_ref_done;
|
||||
wire array_ref_csn;
|
||||
wire [15:0] array_ref_raddr;
|
||||
|
||||
// 实例化待测试模块
|
||||
array_ref uut (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.array_ref_start (array_ref_start),
|
||||
.array_ref_done (array_ref_done),
|
||||
.array_ref_csn (array_ref_csn),
|
||||
.array_ref_raddr (array_ref_raddr),
|
||||
.array_inner_tras (array_inner_tras),
|
||||
.array_inner_trp (array_inner_trp)
|
||||
);
|
||||
|
||||
// 时钟生成:10ns周期(100MHz)
|
||||
initial begin
|
||||
clk = 0;
|
||||
forever #1.25 clk = ~clk;
|
||||
end
|
||||
|
||||
// 主测试流程
|
||||
initial begin
|
||||
// 初始化信号
|
||||
rst_n = 0;
|
||||
array_ref_start = 0;
|
||||
array_inner_tras = 8'd2; // RAS周期为2个时钟
|
||||
array_inner_trp = 8'd1; // RP周期为1个时钟
|
||||
|
||||
// 复位释放
|
||||
#20;
|
||||
rst_n = 1;
|
||||
#10;
|
||||
|
||||
// 启动刷新操作
|
||||
@(posedge clk);
|
||||
array_ref_start = 1;
|
||||
@(posedge clk);
|
||||
array_ref_start = 0; // 释放启动信号
|
||||
|
||||
// 等待刷新完成(全地址遍历)
|
||||
wait(array_ref_done);
|
||||
$display("=== 第一次完整刷新完成 ===");
|
||||
#50;
|
||||
|
||||
// // 测试不同的tras和trp参数
|
||||
// array_inner_tras = 8'd3;
|
||||
// array_inner_trp = 8'd2;
|
||||
// @(posedge clk);
|
||||
// array_ref_start = 1;
|
||||
// @(posedge clk);
|
||||
// array_ref_start = 0;
|
||||
|
||||
// wait(array_ref_done);
|
||||
// $display("=== 第二次完整刷新完成 ===");
|
||||
// #50;
|
||||
|
||||
// // 测试中途复位
|
||||
// @(posedge clk);
|
||||
// array_ref_start = 1;
|
||||
// @(posedge clk);
|
||||
// array_ref_start = 0;
|
||||
// #30;
|
||||
// rst_n = 0;
|
||||
// #20;
|
||||
// rst_n = 1;
|
||||
// $display("=== 复位测试完成 ===");
|
||||
|
||||
// 结束仿真
|
||||
#100;
|
||||
$display("=== 仿真结束 ===");
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
$fsdbDumpfile("tb.fsdb");
|
||||
$fsdbDumpvars(0,tb_array_ref,"+all");
|
||||
$vcdpluson;
|
||||
$vcdplusmemon;
|
||||
end
|
||||
// 监控信号变化
|
||||
initial begin
|
||||
$monitor(
|
||||
"Time: %0t, State: %b, raddr: %h, csn: %b, done: %b, ras_cnt: %h, rp_cnt: %h",
|
||||
$time, uut.cur_state, array_ref_raddr, array_ref_csn, array_ref_done,
|
||||
uut.ref_ras_cnt, uut.ref_rp_cnt
|
||||
);
|
||||
end
|
||||
|
||||
endmodule
|
182
tb/tb_array_status_ctrl.v
Normal file
182
tb/tb_array_status_ctrl.v
Normal file
@@ -0,0 +1,182 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module tb_array_status_ctrl();
|
||||
|
||||
// 时钟与复位信号
|
||||
reg clk;
|
||||
reg rst_n;
|
||||
|
||||
// AXI 到数组的帧信号
|
||||
reg axi2array_frame_valid;
|
||||
reg [152:0] axi2array_frame_data;
|
||||
wire axi2array_frame_ready;
|
||||
|
||||
// 数组读写信号
|
||||
wire array_wr_frame_valid;
|
||||
wire [151:0] array_wr_frame_data;
|
||||
reg array_wr_frame_ready;
|
||||
reg array_wr_done;
|
||||
|
||||
wire array_rd_frame_valid;
|
||||
wire [151:0] array_rd_frame_data;
|
||||
reg array_rd_frame_ready;
|
||||
reg array_rd_done;
|
||||
|
||||
// 数组刷新信号
|
||||
wire array_ref_start;
|
||||
reg array_ref_done;
|
||||
|
||||
// 其他控制信号
|
||||
wire [1:0] array_mux_sel;
|
||||
reg mc_work_en;
|
||||
reg array_ref_en;
|
||||
reg [24:0] array_inner_tref0;
|
||||
reg [24:0] array_inner_tref1;
|
||||
reg array_inner_ref_sel;
|
||||
|
||||
// 例化被测试模块
|
||||
array_status_ctrl uut (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.axi2array_frame_valid (axi2array_frame_valid),
|
||||
.axi2array_frame_data (axi2array_frame_data),
|
||||
.axi2array_frame_ready (axi2array_frame_ready),
|
||||
.array_wr_frame_valid (array_wr_frame_valid),
|
||||
.array_wr_frame_data (array_wr_frame_data),
|
||||
.array_wr_frame_ready (array_wr_frame_ready),
|
||||
.array_wr_done (array_wr_done),
|
||||
.array_rd_frame_valid (array_rd_frame_valid),
|
||||
.array_rd_frame_data (array_rd_frame_data),
|
||||
.array_rd_frame_ready (array_rd_frame_ready),
|
||||
.array_rd_done (array_rd_done),
|
||||
.array_ref_start (array_ref_start),
|
||||
.array_ref_done (array_ref_done),
|
||||
.array_mux_sel (array_mux_sel),
|
||||
.mc_work_en (mc_work_en),
|
||||
.array_ref_en (array_ref_en),
|
||||
.array_inner_tref0 (array_inner_tref0),
|
||||
.array_inner_tref1 (array_inner_tref1),
|
||||
.array_inner_ref_sel (array_inner_ref_sel)
|
||||
);
|
||||
|
||||
// 生成时钟(50MHz,周期20ns)
|
||||
initial begin
|
||||
clk = 0;
|
||||
forever #10 clk = ~clk;
|
||||
end
|
||||
|
||||
// 主测试流程
|
||||
initial begin
|
||||
// 初始化信号
|
||||
rst_n = 0;
|
||||
axi2array_frame_valid = 0;
|
||||
axi2array_frame_data = 0;
|
||||
array_wr_frame_ready = 0;
|
||||
array_wr_done = 0;
|
||||
array_rd_frame_ready = 0;
|
||||
array_rd_done = 0;
|
||||
array_ref_done = 0;
|
||||
mc_work_en = 0;
|
||||
array_ref_en = 0;
|
||||
array_inner_tref0 = 25'd5; // 刷新计数阈值
|
||||
array_inner_tref1 = 25'd10;
|
||||
array_inner_ref_sel = 0;
|
||||
|
||||
// 释放复位
|
||||
#100 rst_n = 1;
|
||||
#20;
|
||||
|
||||
// 测试场景1:写操作
|
||||
$display("Test Case 1: Write Operation");
|
||||
mc_work_en = 1; // 使能工作模式
|
||||
#20;
|
||||
// 发送写请求(bit152=1)
|
||||
axi2array_frame_data = {1'b1, 152'h123456}; // 写数据
|
||||
axi2array_frame_valid = 1;
|
||||
array_wr_frame_ready = 1; // 准备接收写数据
|
||||
#20;
|
||||
array_wr_done = 1; // 写完成
|
||||
#20;
|
||||
axi2array_frame_valid = 0;
|
||||
array_wr_done = 0;
|
||||
#100;
|
||||
|
||||
// 测试场景2:读操作
|
||||
$display("Test Case 2: Read Operation");
|
||||
// 发送读请求(bit152=0)
|
||||
axi2array_frame_data = {1'b0, 152'hABCDEF}; // 读数据
|
||||
axi2array_frame_valid = 1;
|
||||
array_rd_frame_ready = 1; // 准备接收读数据
|
||||
#20;
|
||||
array_rd_done = 1; // 读完成
|
||||
#20;
|
||||
axi2array_frame_valid = 0;
|
||||
array_rd_done = 0;
|
||||
#100;
|
||||
|
||||
// 测试场景3:刷新操作(达到计数阈值)
|
||||
$display("Test Case 3: Refresh Operation (by counter)");
|
||||
array_ref_en = 1; // 使能刷新
|
||||
#200; // 等待刷新计数器达到阈值(tref0=5,约100ns后触发)
|
||||
array_ref_done = 1; // 刷新完成
|
||||
#20;
|
||||
array_ref_done = 0;
|
||||
array_ref_en = 0;
|
||||
#100;
|
||||
|
||||
// 测试场景4:状态优先级(刷新 > 写 > 读)
|
||||
$display("Test Case 4: State Priority (Refresh > Write > Read)");
|
||||
array_ref_en = 1;
|
||||
mc_work_en = 1;
|
||||
// 同时触发刷新请求、写请求和读请求
|
||||
axi2array_frame_data = {1'b1, 152'hFEDCBA}; // 写请求
|
||||
axi2array_frame_valid = 1;
|
||||
#20;
|
||||
array_ref_done = 1; // 先完成刷新
|
||||
#20;
|
||||
array_ref_done = 0;
|
||||
#20;
|
||||
array_wr_done = 1; // 再完成写操作
|
||||
#20;
|
||||
axi2array_frame_valid = 0;
|
||||
array_wr_done = 0;
|
||||
#100;
|
||||
|
||||
// 结束测试
|
||||
$display("All Test Cases Completed!");
|
||||
$finish;
|
||||
end
|
||||
|
||||
// 监控状态变化
|
||||
always @(posedge clk) begin
|
||||
if (rst_n) begin
|
||||
case (uut.cur_state)
|
||||
2'b00: $display("[%0t] State: IDLE", $time);
|
||||
2'b01: $display("[%0t] State: WRITE", $time);
|
||||
2'b10: $display("[%0t] State: READ", $time);
|
||||
2'b11: $display("[%0t] State: REFRESH", $time);
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
initial begin
|
||||
$fsdbDumpfile("tb.fsdb");
|
||||
$fsdbDumpvars(0,tb_array_status_ctrl,"+all");
|
||||
$vcdpluson;
|
||||
$vcdplusmemon;
|
||||
end
|
||||
|
||||
// 监控关键信号
|
||||
always @(posedge clk) begin
|
||||
if (array_ref_start) begin
|
||||
$display("[%0t] Refresh Start Triggered", $time);
|
||||
end
|
||||
if (array_wr_frame_valid && array_wr_frame_ready) begin
|
||||
$display("[%0t] Write Data Transferred: %h", $time, array_wr_frame_data);
|
||||
end
|
||||
if (array_rd_frame_valid && array_rd_frame_ready) begin
|
||||
$display("[%0t] Read Data Transferred: %h", $time, array_rd_frame_data);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
151
tb/tb_array_wr.v
Normal file
151
tb/tb_array_wr.v
Normal file
@@ -0,0 +1,151 @@
|
||||
`timescale 1ns/1ps
|
||||
|
||||
module tb_array_wr();
|
||||
|
||||
// 时钟和复位信号
|
||||
reg clk;
|
||||
reg rst_n;
|
||||
|
||||
// 输入信号(DUT 的输入)
|
||||
reg array_wr_frame_valid;
|
||||
reg [151:0] array_wr_frame_data;
|
||||
reg [7:0] array_inner_tras;
|
||||
reg [7:0] array_inner_trp;
|
||||
reg [7:0] array_inner_trcd_wr;
|
||||
reg [7:0] array_inner_twr;
|
||||
|
||||
// 输出信号(DUT 的输出)
|
||||
wire array_wr_frame_ready;
|
||||
wire array_wr_done;
|
||||
wire array_wr_csn;
|
||||
wire [15:0] array_wr_raddr;
|
||||
wire array_caddr_vld_wr;
|
||||
wire [5:0] array_caddr_wr;
|
||||
wire array_wdata_vld;
|
||||
wire [127:0] array_wdata;
|
||||
|
||||
// 实例化被测试模块(DUT)
|
||||
array_wr u_array_wr(
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.array_wr_frame_valid(array_wr_frame_valid),
|
||||
.array_wr_frame_data(array_wr_frame_data),
|
||||
.array_wr_frame_ready(array_wr_frame_ready),
|
||||
.array_wr_done (array_wr_done),
|
||||
.array_wr_csn (array_wr_csn),
|
||||
.array_wr_raddr (array_wr_raddr),
|
||||
.array_caddr_vld_wr (array_caddr_vld_wr),
|
||||
.array_caddr_wr (array_caddr_wr),
|
||||
.array_wdata_vld (array_wdata_vld),
|
||||
.array_wdata (array_wdata),
|
||||
.array_inner_tras (array_inner_tras),
|
||||
.array_inner_trp (array_inner_trp),
|
||||
.array_inner_trcd_wr(array_inner_trcd_wr),
|
||||
.array_inner_twr (array_inner_twr)
|
||||
);
|
||||
|
||||
// 生成时钟(50MHz,周期 20ns)
|
||||
initial begin
|
||||
clk = 1'b0;
|
||||
forever #10 clk = ~clk;
|
||||
end
|
||||
|
||||
// 主测试流程
|
||||
initial begin
|
||||
// 初始化信号
|
||||
rst_n = 1'b0;
|
||||
array_wr_frame_valid = 1'b0;
|
||||
array_wr_frame_data = 152'd0;
|
||||
array_inner_tras = 8'd3; // 示例值:TRAS = 3 个时钟周期
|
||||
array_inner_trp = 8'd2; // 示例值:TRP = 2 个时钟周期
|
||||
array_inner_trcd_wr = 8'd2; // 示例值:TRCD_WR = 2 个时钟周期
|
||||
array_inner_twr = 8'd2; // 示例值:TWR = 2 个时钟周期
|
||||
|
||||
// 复位释放(10 个时钟周期后)
|
||||
#200;
|
||||
rst_n = 1'b1;
|
||||
#20;
|
||||
|
||||
// 测试场景 1:单帧数据写入(含 SOF 和 EOF)
|
||||
$display("=== 测试场景 1:单帧数据写入 ===");
|
||||
send_frame(
|
||||
1'b1, // 起始标志
|
||||
1'b1, // 结束标志(单帧)
|
||||
16'h1234,// 地址
|
||||
6'h05, // 列地址
|
||||
128'hA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5 // 数据
|
||||
);
|
||||
wait(array_wr_done); // 等待写入完成
|
||||
#100;
|
||||
|
||||
// 测试场景 2:多帧数据写入(首帧 SOF,末帧 EOF)
|
||||
$display("=== 测试场景 2:多帧数据写入 ===");
|
||||
// 第一帧(SOF=1,EOF=0)
|
||||
send_frame(
|
||||
1'b1,
|
||||
1'b0,
|
||||
16'h5678,
|
||||
6'h0A,
|
||||
128'h55AA55AA55AA55AA55AA55AA55AA55AA
|
||||
);
|
||||
#20;
|
||||
// 第二帧(SOF=0,EOF=1)
|
||||
send_frame(
|
||||
1'b0,
|
||||
1'b1,
|
||||
16'h5678, // 地址与前一帧相同(连续写入)
|
||||
6'h0B,
|
||||
128'hAA55AA55AA55AA55AA55AA55AA55AA55
|
||||
);
|
||||
wait(array_wr_done); // 等待写入完成
|
||||
#100;
|
||||
|
||||
// 测试场景 3:无输入时的空闲状态
|
||||
$display("=== 测试场景 3:空闲状态验证 ===");
|
||||
array_wr_frame_valid = 1'b0;
|
||||
#200;
|
||||
|
||||
// 测试结束
|
||||
$display("=== 所有测试场景完成 ===");
|
||||
$finish;
|
||||
end
|
||||
|
||||
// 任务:发送一帧数据(封装输入信号逻辑)
|
||||
task send_frame;
|
||||
input wsof; // 帧起始标志
|
||||
input weof; // 帧结束标志
|
||||
input [15:0] wraddr; // 写入地址
|
||||
input [5:0] wcaddr; // 列地址
|
||||
input [127:0] wdata; // 写入数据
|
||||
begin
|
||||
// 等待模块就绪(ready 信号为高)
|
||||
wait(array_wr_frame_ready);
|
||||
#10; // 延迟一小段时间
|
||||
|
||||
// 驱动输入信号
|
||||
array_wr_frame_valid = 1'b1;
|
||||
array_wr_frame_data = {wsof, weof, wraddr, wcaddr, wdata}; // 拼接帧数据
|
||||
#20; // 保持一个时钟周期
|
||||
|
||||
// 撤销有效信号
|
||||
array_wr_frame_valid = 1'b0;
|
||||
array_wr_frame_data = 152'd0;
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
$fsdbDumpfile("tb.fsdb");
|
||||
$fsdbDumpvars(0,tb_array_wr,"+all");
|
||||
$vcdpluson;
|
||||
$vcdplusmemon;
|
||||
end
|
||||
|
||||
// 监控关键信号变化(可选,用于调试)
|
||||
initial begin
|
||||
$monitor(
|
||||
"Time: %0t, State: %h, CSN: %b, Ready: %b, Done: %b, Valid: %b",
|
||||
$time, u_array_wr.cur_state, array_wr_csn, array_wr_frame_ready, array_wr_done, array_wdata_vld
|
||||
);
|
||||
end
|
||||
|
||||
endmodule
|
197
tb/tb_axi_slv.v
Normal file
197
tb/tb_axi_slv.v
Normal file
@@ -0,0 +1,197 @@
|
||||
module tb_axi_slv;
|
||||
reg clk;
|
||||
reg rst_n;
|
||||
|
||||
reg axi_s_awvalid;
|
||||
reg [7:0] axi_s_awlen;
|
||||
reg [25:0] axi_s_awaddr;
|
||||
wire axi_s_awready;
|
||||
|
||||
reg axi_s_wvalid;
|
||||
reg axi_s_wlast;
|
||||
reg [63:0] axi_s_wdata;
|
||||
wire axi_s_wready;
|
||||
|
||||
reg axi_s_arvalid;
|
||||
reg [7:0] axi_s_arlen;
|
||||
reg [25:0] axi_s_araddr;
|
||||
wire axi_s_arready;
|
||||
|
||||
wire axi_s_rvalid;
|
||||
wire axi_s_rlast;
|
||||
wire [63:0] axi_s_rdata;
|
||||
|
||||
wire axi2array_frame_valid;
|
||||
wire [152:0] axi2array_frame_data;
|
||||
reg axi2array_frame_ready;
|
||||
|
||||
reg array2axi_rdata_valid;
|
||||
reg [127:0] array2axi_rdata;
|
||||
|
||||
reg [1:0] axi_bus_rw_priority;
|
||||
reg mc_work_en;
|
||||
|
||||
axi_slv u_axi_slv(
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
|
||||
.axi_s_awvalid (axi_s_awvalid),
|
||||
.axi_s_awlen (axi_s_awlen),
|
||||
.axi_s_awaddr (axi_s_awaddr),
|
||||
.axi_s_awready (axi_s_awready),
|
||||
|
||||
.axi_s_wvalid (axi_s_wvalid),
|
||||
.axi_s_wlast (axi_s_wlast),
|
||||
.axi_s_wdata (axi_s_wdata),
|
||||
.axi_s_wready (axi_s_wready),
|
||||
|
||||
.axi_s_arvalid (axi_s_arvalid),
|
||||
.axi_s_arlen (axi_s_arlen),
|
||||
.axi_s_araddr (axi_s_araddr),
|
||||
.axi_s_arready (axi_s_arready),
|
||||
|
||||
.axi_s_rvalid (axi_s_rvalid),
|
||||
.axi_s_rlast (axi_s_rlast),
|
||||
.axi_s_rdata (axi_s_rdata),
|
||||
|
||||
.axi2array_frame_valid (axi2array_frame_valid),
|
||||
.axi2array_frame_data (axi2array_frame_data),
|
||||
.axi2array_frame_ready (axi2array_frame_ready),
|
||||
|
||||
.array2axi_rdata_valid (array2axi_rdata_valid),
|
||||
.array2axi_rdata (array2axi_rdata),
|
||||
|
||||
.axi_bus_rw_priority (axi_bus_rw_priority),
|
||||
.mc_work_en (mc_work_en)
|
||||
);
|
||||
|
||||
task aw;
|
||||
input [7:0] awlen;
|
||||
input [25:0] awaddr;
|
||||
begin
|
||||
@(posedge clk) begin
|
||||
axi_s_awvalid <= 1'b1;
|
||||
axi_s_awaddr <= awaddr;
|
||||
axi_s_awlen <= awlen;
|
||||
end
|
||||
#1;
|
||||
wait(axi_s_awready);
|
||||
@(posedge clk) begin
|
||||
axi_s_awvalid <= 1'b0;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task w;
|
||||
input [63:0] wdata;
|
||||
input wlast;
|
||||
begin
|
||||
@(posedge clk) begin
|
||||
axi_s_wvalid <= 1'b1;
|
||||
axi_s_wdata <= wdata;
|
||||
axi_s_wlast <= wlast;
|
||||
end
|
||||
#0.1;
|
||||
wait(axi_s_wready);
|
||||
@(posedge clk) begin
|
||||
axi_s_wvalid <= 1'b0;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task ar;
|
||||
input [25:0] araddr;
|
||||
input [7:0] arlen;
|
||||
begin
|
||||
@(posedge clk) begin
|
||||
axi_s_arvalid <= 1'b1;
|
||||
axi_s_araddr <= araddr;
|
||||
axi_s_arlen <= arlen;
|
||||
end
|
||||
#1;
|
||||
wait(axi_s_arready);
|
||||
@(posedge clk) begin
|
||||
axi_s_arvalid <= 1'b0;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task arrayrdata;
|
||||
input [127:0] rdata;
|
||||
begin
|
||||
@(posedge clk) begin
|
||||
array2axi_rdata_valid <= 1'b1;
|
||||
array2axi_rdata <= rdata;
|
||||
end
|
||||
@(posedge clk) begin
|
||||
array2axi_rdata_valid <= 1'b0;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
clk = 0;
|
||||
forever begin
|
||||
#1.25 clk = ~clk;
|
||||
end
|
||||
end
|
||||
|
||||
initial begin
|
||||
rst_n = 'd0;
|
||||
axi_s_awvalid = 'd0;
|
||||
axi_s_awlen ='d0;
|
||||
axi_s_awaddr ='d0;
|
||||
|
||||
axi_s_wvalid = 'd0;
|
||||
axi_s_wdata = 'd0;
|
||||
axi_s_wlast = 'd0;
|
||||
axi_s_arvalid = 'd0;
|
||||
axi_s_araddr = 'd0;
|
||||
axi_s_arlen = 'd0;
|
||||
|
||||
array2axi_rdata ='d0;
|
||||
array2axi_rdata_valid = 'd0;
|
||||
axi2array_frame_ready = 1'd1;
|
||||
mc_work_en = 1'b1;
|
||||
axi_bus_rw_priority = 2'b10;
|
||||
@(posedge clk) begin
|
||||
rst_n = 1'b1;
|
||||
end
|
||||
aw(8'd5,{16'h0,6'h3f,4'h0});
|
||||
w(64'd1,0);
|
||||
w(64'd2,0);
|
||||
w(64'd3,0);
|
||||
w(64'd4,0);
|
||||
w(64'd5,0);
|
||||
w(64'd6,1);
|
||||
@(posedge clk) begin
|
||||
axi_s_wvalid <= 1'b0;
|
||||
end
|
||||
ar({16'h1,6'h3f,4'h0},8'd9);
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
@(posedge clk);
|
||||
arrayrdata({64'h2,64'h1});
|
||||
arrayrdata({64'h4,64'h3});
|
||||
arrayrdata({64'h6,64'h5});
|
||||
arrayrdata({64'h8,64'h7});
|
||||
arrayrdata({64'ha,64'h9});
|
||||
#15;
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin
|
||||
$fsdbDumpfile("tb.fsdb");
|
||||
$fsdbDumpvars(0,tb_axi_slv,"+all");
|
||||
$vcdpluson;
|
||||
$vcdplusmemon;
|
||||
end
|
||||
|
||||
endmodule
|
Reference in New Issue
Block a user