`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 // 时钟生成 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) ); // ========================================== // 任务:发送一个字节 (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 = 0; i < bytes; i++) begin // 默认小端发送:低字节在前 send_byte(data[i*8 +: 8]); end endtask // ========================================== // 流程控制: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 // ========================================== // 流程控制: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[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 endmodule