`timescale 1ns / 1ps module TB_top(); // ========================================== // 参数与信号定义 // ========================================== parameter CLK_PERIOD = 20; // 50MHz parameter BAUD = 115200; localparam BIT_TIME = 1_000_000_000 / BAUD; reg clk; reg rst_n; reg uart_rx; // 对应 DUT 的 RX wire uart_tx; // 对应 DUT 的 TX reg sig_in; // 时钟生成 initial clk = 0; always #(CLK_PERIOD/2) clk = ~clk; // ========================================== // 实例化被测设计 (DUT) // ========================================== digital_top u_digital_top( .clk (clk), .rst_n (rst_n), .uart_rx (uart_rx), .uart_tx (uart_tx), .sig_in (sig_in) ); // // ========================================== // // 流程控制:TX 驱动 (从 case.txt 读取) // // ========================================== // initial begin // int file_h; // int status; // logic [63:0] val; // // 初始化信号 // rst_n = 0; // uart_rx = 1; // #(CLK_PERIOD * 10); // rst_n = 1; // file_h = $fopen("case.txt", "r"); // if (!file_h) begin // $display("[TX ERROR] Cannot open case.txt"); // $finish; // end // $display("[TX] Starting transmission..."); // while (!$feof(file_h)) begin // // 假设文件中每行是一个 hex 数据 // status = $fscanf(file_h, "%h\n", val); // if (status == 1) begin // if (val > 64'hFFFF_FFFF) begin // $display("[%t] TX CMD: %h", $time, val); // send_data(val, 64); // end else begin // $display("[%t] TX DATA: %h", $time, val[31:0]); // send_data(val[31:0], 32); // end // #(BIT_TIME * 5); // 帧间隙 // end // end // $fclose(file_h); // $display("[TX] All cases sent."); // // 等待一段时间观察 RX 是否还有回传,然后结束 // #(BIT_TIME * 500); // $display("[SIM] Simulation finished."); // $finish; // end initial begin // 1. 初始化 rst_n = 0; uart_rx = 1; sig_in = 0; #(CLK_PERIOD * 20); rst_n = 1; #(CLK_PERIOD * 100); $display("------- Step 1: Configure Thermometer Regs -------"); send_data(64'h80000004_00000004,64); send_data(64'h80000008_00000004,64); send_data(64'h8000000c_00000004,64); send_data(64'h80000010_00000004,64); send_data(64'h80000014_00000004,64); $display("------- Step 2: Running Concurrent Tasks -------"); fork // 进程 A: 模拟输入脉冲 (代表温度变化) begin gen_pulses(400, 10); // 100kHz 持续 10ms end // 进程 B: 在上报期间,强行插口读取指令 begin #(2_000000); // 等待第一个上报包可能发出 $display("[%t] TX: Sending Read Request during active reporting...", $time); send_data(64'h80000014_00000004,64); send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32); send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32); end join #(BIT_TIME * 500); $display("Test Done."); $finish; end // ========================================== // 流程控制:RX 监听 (保存到 rx_data.txt) // ========================================== int rx_file_h; initial begin logic [7:0] rx_byte; rx_file_h = $fopen("rx_data.txt", "w"); if (!rx_file_h) begin $display("[RX ERROR] Cannot create rx_data.txt"); $finish; end forever begin logic [31:0] packet_word; // 32位数据包 logic [7:0] rx_byte; // 收集4个字节并组合成32位数据 for (int byte_idx = 0; byte_idx < 4; byte_idx++) begin // 1. 等待起始位 (下降沿) @(negedge uart_tx); // 2. 跳过起始位,采样数据中心点 #(BIT_TIME / 2); #(BIT_TIME); // 读取8个数据位 for (int i = 0; i < 8; i++) begin rx_byte[i] = uart_tx; #(BIT_TIME); end // 组合成32位数据(小端序:先收到的在低位) packet_word[24 - 8*byte_idx +: 8] = rx_byte; $display("[%t] Byte %0d: 0x%h", $time, byte_idx, rx_byte); // 等待停止位结束 if (byte_idx < 3) begin #(BIT_TIME / 2); end end // 写入文件(一行一个32位数据) $fdisplay(rx_file_h, "%08h", packet_word); $display("[%t] Packet (32-bit): 0x%08h", $time, packet_word); // 等待最后一个字节的停止位结束 #(BIT_TIME / 2); end end final begin if (rx_file_h) begin $fclose(rx_file_h); $display("[RX] File closed at %t",$time); end end // --- Pulse Generation Task --- // freq_khz: Target frequency (kHz) // duration_ms: Test duration (ms) task automatic gen_pulses(input int freq_khz, input int duration_ms); int half_period_ns; longint end_time_ns; begin if (freq_khz <= 0) begin sig_in = 0; #(duration_ms * 1000000); end else begin half_period_ns = 500000 / freq_khz; end_time_ns = $time + (longint'(duration_ms) * 1000000); $display("[%0t] Start generating signal: %0d kHz", $time, freq_khz); while ($time < end_time_ns) begin sig_in = 1; #(half_period_ns); sig_in = 0; #(half_period_ns); end end end endtask // ========================================== // 任务:发送一个字节 (Serial TX) // ========================================== task automatic send_byte(input [7:0] data); begin uart_rx = 0; // 起始位 #(BIT_TIME); for (int i = 0; i < 8; i++) begin uart_rx = data[i]; // LSB First #(BIT_TIME); end uart_rx = 1; // 停止位 #(BIT_TIME); end endtask // 任务:发送 32/64 位数据 task automatic send_data(input [63:0] data, input int len_bits); int bytes = len_bits / 8; for (int i = bytes - 1; i >= 0; i--) begin // 从最高字节往下发 send_byte(data[i*8 +: 8]); end endtask endmodule