`timescale 1ns/1ps module tb_RelayConTop; // 时钟和复位 reg i_sys_clk; reg i_rst_n; // SPI接口 reg i_sclk; reg i_mosi; reg i_cs; // wire o_miso; // 流控制接口 // wire o_rvaild; // reg i_rready; // reg i_wvaild; // wire o_wready; wire o_err; // 继电器控制输出 wire [7:0] o_RC_F; wire [15:0] o_RC_S; wire [31:0] o_RC_T; // 测试变量 reg [31:0] spi_data; integer test_pass; integer test_fail; // 实例化被测模块 RelayConTop DUT ( .i_sys_clk(i_sys_clk), .i_rst_n(i_rst_n), .i_sclk(i_sclk), .i_mosi(i_mosi), .i_cs(i_cs), // .o_miso(o_miso), // .o_rvaild(o_rvaild), // .i_rready(i_rready), // .i_wvaild(i_wvaild), // .o_wready(o_wready), .o_err(o_err), .o_RC_F(o_RC_F), .o_RC_S(o_RC_S), .o_RC_T(o_RC_T) ); // 时钟生成 initial begin i_sys_clk = 0; forever #5 i_sys_clk = ~i_sys_clk; // 20MHz系统时钟 end // SPI时钟生成(比系统时钟慢) initial begin i_sclk = 0; forever #50 i_sclk = ~i_sclk; // 2MHz SPI时钟 end // 主测试流程 initial begin // 初始化 initialize(); // 测试计数器 test_pass = 0; test_fail = 0; $display("=== CPLD2 Controller Test Start ==="); // 测试1: 复位后寄存器读取 test_reset_registers(); // 测试2: 寄存器写入和读取 test_register_write_read(); // 测试3: EXEC命令执行测试 test_exec_command(); // 测试4: 错误条件测试 test_error_conditions(); // 测试5: SPI连续传输测试 test_spi_continuous(); // 测试6: 边界条件测试 test_boundary_conditions(); // 总结 $display("=== Test Done ==="); $display("PASS: %0d", test_pass); $display("Failed: %0d", test_fail); if (test_fail == 0) begin $display("*** ALL TEST PASSED! ***"); end else begin $display("*** TEST FAILED FOUND!! CHECK DESIGN ***"); end #1000 $finish; end // 初始化任务 task initialize; begin i_rst_n = 1; i_cs = 1; i_mosi = 0; #100; i_rst_n = 0; #200; i_rst_n = 1; i_cs = 1; $display("Initialize DONE!"); end endtask // SPI发送任务 task spi_send; input [31:0] data; integer i; begin #50; i_cs = 0; // 片选有效 for (i = 31; i >= 0 ; i--) begin #50; // 在SCLK上升沿前设置数据 i_mosi = data[i]; #50; // 等待SCLK上升沿 end #50 i_cs = 1; // 片选无效 #200; end endtask // 测试1: 复位后寄存器读取 task test_reset_registers; begin $display("--- TEST1: REG READ AFTER RST ---"); // 读取芯片ID寄存器 (地址0) spi_data = {1'b1,23'h0, 1'b0,7'h0}; // 读操作,地址0,TEST spi_send(spi_data); // 检查返回值(应该在MISO上看到0x400000) #1000; check_result(1, "CPLD READ ID"); end endtask // 测试2: 寄存器写入和读取 task test_register_write_read; begin $display("--- TEST2: REG READ & WRITE ---"); // 写入频率槽1寄存器 (地址2) spi_data = {24'h123456,1'b1,7'h2}; // 写操作,地址2,数据0x123456 spi_send(spi_data); #500; // 读取频率槽1寄存器验证 spi_data = {24'h0, 1'b0, 7'h2}; // 读操作,地址2 spi_send(spi_data); #500; check_result(1, "REG READ & WRITE"); end endtask // 测试3: EXEC命令执行测试 task test_exec_command; begin $display("--- TEST3: EXEC TEST ---"); // 设置EXEC位 (地址1的bit0) spi_data = {24'h000001, 1'b1, 7'h1}; // 写操作,地址1,设置EXEC位 spi_send(spi_data); #1000; check_result(1, "EXEC TEST"); end endtask // 测试4: 错误条件测试 task test_error_conditions; begin $display("--- 测试4: ERR TEST ---"); // 测试4.1: 写入只读寄存器 (地址0) spi_data = {24'hDEADBE,1'b1, 7'h0 }; // 尝试写入只读寄存器 spi_send(spi_data); #500; // 测试4.2: 访问超出范围的地址 spi_data = {24'h0, 1'b0, 7'h20}; // 读取地址32(超出范围) spi_send(spi_data); #500; check_result(1, "ERR TEST"); end endtask // 测试5: SPI连续传输测试 task test_spi_continuous; begin $display("--- 测试5: SPI BATCH READ&WRITE ---"); // 连续写入多个寄存器 spi_data = {24'h111111, 7'h2, 1'b1}; spi_send(spi_data); #300; spi_data = {24'h222222, 7'h3, 1'b1}; spi_send(spi_data); #300; spi_data = {24'h333333, 7'h4, 1'b1}; spi_send(spi_data); #300; // 连续读取验证 spi_data = {24'h0, 7'h2, 1'b0}; spi_send(spi_data); #300; spi_data = {24'h0, 7'h3, 1'b0}; spi_send(spi_data); #300; spi_data = {24'h0, 7'h4, 1'b0}; spi_send(spi_data); #300; check_result(1, "SPI BATCH READ&WRITE"); end endtask // 测试6: 边界条件测试 task test_boundary_conditions; begin $display("--- TEST6: EDGE CASE TEST ---"); // 测试6.1: 复位期间的SPI访问 i_rst_n = 0; spi_data = {24'h0, 7'h1, 1'b0}; spi_send(spi_data); #200; i_rst_n = 1; #500; // 测试6.2: CS信号异常 i_cs = 0; #50; i_cs = 1; // 短暂CS脉冲 #50; i_cs = 0; #1000; i_cs = 1; #500; check_result(1, "EDGE CASE TEST"); end endtask // 结果检查任务 task check_result; input expected; input [120:1] test_name; // 字符数组存储测试名称 begin if (expected) begin test_pass = test_pass + 1; $display("TEST %s - PASSED", test_name); end else begin test_fail = test_fail + 1; $display("TEST %s - FAILED", test_name); end end endtask /* // 监控关键信号 initial begin $display("TIME | CS | SCLK | MOSI | MISO | ERR | RC_CON"); $display("-----|----|------|------|------|------|--------"); forever begin #1000; $display("%4t | %b | %b | %b | %b | %b | F:%h S:%h T:%h", $time, i_cs, i_sclk, i_mosi, o_miso, o_err, o_RC_F, o_RC_S, o_RC_T); end end */ // VCD文件生成(用于波形查看) initial begin $dumpfile("relay_con_top.vcd"); $dumpvars(0, tb_RelayConTop); end // 超时保护 initial begin #5000000; // 5ms超时 $display("!!! TEST TIMEOUT !!!"); $finish; end endmodule