119 lines
3.3 KiB
Verilog
119 lines
3.3 KiB
Verilog
`timescale 1ns / 1ps
|
||
|
||
module tb_digital_top();
|
||
|
||
// 参数定义
|
||
parameter CLK_PERIOD = 10; // 100MHz 系统时钟
|
||
parameter SCLK_PERIOD = 100; // 10MHz SPI时钟 (必须比系统时钟慢)
|
||
|
||
// 信号声明
|
||
logic clk;
|
||
logic rst_n;
|
||
logic [4:0] cfgid;
|
||
|
||
logic sclk;
|
||
logic csn;
|
||
logic mosi;
|
||
logic miso;
|
||
logic oen;
|
||
|
||
|
||
// 实例化 DUT
|
||
digital_top u_digital_top (
|
||
.clk (clk ),
|
||
.rst_n (rst_n ),
|
||
.cfgid (cfgid ),
|
||
.sclk (sclk ),
|
||
.csn (csn ),
|
||
.mosi (mosi ),
|
||
.miso (miso ),
|
||
.oen (oen ),
|
||
.sig_in ( )
|
||
);
|
||
|
||
// 系统时钟产生
|
||
initial begin
|
||
clk = 0;
|
||
forever #(CLK_PERIOD/2) clk = ~clk;
|
||
end
|
||
|
||
// 初始复位与赋值
|
||
initial begin
|
||
rst_n = 0;
|
||
sclk = 0;
|
||
csn = 1;
|
||
mosi = 0;
|
||
cfgid = 5'h0A; // 设定芯片ID为 10
|
||
|
||
#(CLK_PERIOD * 10);
|
||
rst_n = 1;
|
||
#(CLK_PERIOD * 10);
|
||
|
||
// --- 开始测试 ---
|
||
|
||
// 1. 测试写操作: 写入 0x12345678 到 地址 0x100
|
||
spi_write(25'h100, 5'h0A, 32'h12345678);
|
||
|
||
#(SCLK_PERIOD * 5);
|
||
|
||
// 2. 测试读操作: 从地址 0x100 读取 (验证读使能和地址)
|
||
spi_read(25'h222, 5'h0A);
|
||
|
||
#(SCLK_PERIOD * 20);
|
||
$display("Test Bench Finished.");
|
||
$finish;
|
||
end
|
||
|
||
// ---------------------------------------------------------
|
||
// Task: SPI 发送/接收 32位数据
|
||
// ---------------------------------------------------------
|
||
task spi_xfer_32(input [31:0] data_in, output [31:0] data_out);
|
||
for (int i = 31; i >= 0; i--) begin
|
||
mosi = data_in[i]; // MSB First
|
||
#(SCLK_PERIOD/2);
|
||
sclk = 1; // 上升沿,DUT采样
|
||
#(SCLK_PERIOD/2);
|
||
data_out[i] = miso; // 采样从机发回的数据
|
||
sclk = 0;
|
||
end
|
||
endtask
|
||
|
||
// ---------------------------------------------------------
|
||
// Task: 写操作 (wnr=0)
|
||
// ---------------------------------------------------------
|
||
task spi_write(input [24:0] target_addr, input [4:0] id, input [31:0] data);
|
||
logic [31:0] header;
|
||
logic [31:0] dummy;
|
||
|
||
header = {1'b0, target_addr, id, 1'b0}; // 构造命令帧
|
||
|
||
$display("[WRITE] Addr: %h, Data: %h", target_addr, data);
|
||
|
||
csn = 0;
|
||
spi_xfer_32(header, dummy); // 发送命令
|
||
spi_xfer_32(data, dummy); // 发送数据
|
||
csn = 1;
|
||
mosi = 0;
|
||
endtask
|
||
|
||
// ---------------------------------------------------------
|
||
// Task: 读操作 (wnr=1)
|
||
// ---------------------------------------------------------
|
||
task spi_read(input [24:0] target_addr, input [4:0] id);
|
||
logic [31:0] header;
|
||
logic [31:0] read_val;
|
||
|
||
header = {1'b1, target_addr, id, 1'b0}; // 构造命令帧 (wnr=1)
|
||
|
||
$display("[READ] Addr: %h", target_addr);
|
||
|
||
csn = 0;
|
||
spi_xfer_32(header, read_val); // 发送命令帧,此时读回的可能是无用数据
|
||
spi_xfer_32(32'h0, read_val); // 发送Dummy,接收真正的读数据
|
||
csn = 1;
|
||
mosi = 0;
|
||
|
||
$display("[READ] Result: %h", read_val);
|
||
endtask
|
||
|
||
endmodule |