`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