diff --git a/rtl/digital_top.v b/rtl/digital_top.v index 68bb407..d42230e 100644 --- a/rtl/digital_top.v +++ b/rtl/digital_top.v @@ -21,6 +21,43 @@ module digital_top( - + input clk, + input rst_n, + input uart_rx, + output uart_tx ); + +wire [31:0] w_wrdata; // DUT -> SRAM 写数据 +wire [24:0] w_addr; // DUT -> SRAM 地址 +wire w_wren; // 写使能 +wire w_rden; // 读使能 +wire [31:0] w_rddata; // SRAM -> DUT 读数据 + + + // 例化待测模块 (DUT) +uart_ctrl_sysreg #( + .BAUD (115200), + .CLOCK_FREQ (50_000_000) +) u_uart_ctrl ( + .clk (clk), + .rst_n (rst_n), + .uart_rx (uart_rx), + .uart_tx (uart_tx), + .o_wrdata (w_wrdata), + .o_addr (w_addr), + .o_wren (w_wren), + .o_rden (w_rden), + .i_rddata (w_rddata) +); + +system_regfile u_system_regfile ( + .clk (clk), + .rst_n (rst_n), + .wrdata (w_wrdata), + .wren (w_wren), + .rwaddr (w_addr), + .rden (w_rden), + .rddata (w_rddata) +); + endmodule diff --git a/rtl/uart_ctrl_sysreg.v b/rtl/uart_ctrl_sysreg.v index cf80e30..8fa0edc 100644 --- a/rtl/uart_ctrl_sysreg.v +++ b/rtl/uart_ctrl_sysreg.v @@ -45,8 +45,9 @@ module uart_ctrl_sysreg #( localparam S_IDLE = 3'd0, S_RX_CMD_L = 3'd1, S_PARSE = 3'd2, - S_RD_DATA = 3'd3, - S_WR_DATA = 3'd4; + S_WAIT_RD = 3'd3, + S_RD_DATA = 3'd4, + S_WR_DATA = 3'd5; @@ -81,19 +82,22 @@ module uart_ctrl_sysreg #( data_bytes_len <= cmd_reg[19:0]; if(cmd_reg[63] == 1'b1) begin //读指令 o_rden <= 1'b1; - state <= S_RD_DATA; + state <= S_WAIT_RD; end else begin //写指令 state <= S_WR_DATA; end end - S_RD_DATA :begin //3 + S_WAIT_RD : begin //3 o_rden <= 1'b0; + state <= S_RD_DATA; + end + S_RD_DATA :begin //4 uart_tx_data <= i_rddata; uart_tx_go <= 1'b1; state <= S_IDLE; end - S_WR_DATA : begin //4 + S_WR_DATA : begin //5 o_wren <= 1'b0; if(data_bytes_len != 0)begin if(uart_rx_done) begin diff --git a/tb/TB_top.sv b/tb/TB_top.sv new file mode 100644 index 0000000..91f3b1c --- /dev/null +++ b/tb/TB_top.sv @@ -0,0 +1,155 @@ +`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 \ No newline at end of file diff --git a/tb/tb_diginal_top.v b/tb/tb_diginal_top.v new file mode 100644 index 0000000..3904357 --- /dev/null +++ b/tb/tb_diginal_top.v @@ -0,0 +1,123 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 2026/04/03 22:09:36 +// Design Name: +// Module Name: tb_diginal_top +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module tb_diginal_top(); + + reg clk; + reg rst_n; + wire uart_tx; + reg uart_rx; + + parameter CLK_PERIOD = 20; // 50MHz + parameter BAUD = 115200; // 提高波特率加快仿真 + localparam BIT_TIME = 1_000_000_000 / BAUD; // 计算1比特持续的ns数 + + initial clk = 0; + always #(CLK_PERIOD/2) clk = ~clk; + + digital_top u_digital_top( + .clk(clk), + .rst_n(rst_n), + .uart_rx(uart_rx), + .uart_tx(uart_tx) + ); + + // ============================================================ + // 模拟上位机:字节发送任务 (Serial UART TX) + // ============================================================ + task send_byte; + input [7:0] data; + integer i; + begin + uart_rx = 0; // 起始位 + #(BIT_TIME); + for (i = 0; i < 8; i = i + 1) begin + uart_rx = data[i]; // 数据位 (LSB first) + #(BIT_TIME); + end + uart_rx = 1; // 停止位 + #(BIT_TIME); + #(BIT_TIME); // 字节间隙 + end + endtask + + // 发送 32 位数据 (拆分为 4 个字节) + task send_32bit; + input [31:0] data; + begin + // 注意:这里发送顺序要和你的串口接收模块端序一致 + // 假设小端发送:先发 [7:0] + send_byte(data[7:0]); + send_byte(data[15:8]); + send_byte(data[23:16]); + send_byte(data[31:24]); + end + endtask + + integer file_ptr; + integer status; + reg [63:0] temp_cmd; + reg [31:0] temp_data; + + initial begin + // 初始化 + rst_n = 0; + uart_rx = 1; + #(CLK_PERIOD * 10); + rst_n = 1; + #(CLK_PERIOD * 100); + + // 打开测试文件 + file_ptr = $fopen("D:/shortname/thermometer/try/test_cases.txt", "r"); + if (file_ptr == 0) begin + $display("====Error: can not open test_cases.txt file!==="); + $finish; + end + + $display("======= Begin Send Case ======="); + + while (!$feof(file_ptr)) begin + // 尝试读取一行(先尝试按 64 位 CMD 读取) + status = $fscanf(file_ptr, "%h\n", temp_cmd); + + if (status == 1) begin + if (temp_cmd > 64'hFFFF_FFFF) begin + // 如果读到的是 64 位,认为是 CMD + $display("[%t] Send command frame: 0x%h", $time, temp_cmd); + send_32bit(temp_cmd[63:32]); // 先发高32位 + send_32bit(temp_cmd[31:0]); // 再发低32位 + end else begin + // 如果读到的是 32 位,认为是 DATA + $display("[%t] Send data stream: 0x%h", $time, temp_cmd[31:0]); + send_32bit(temp_cmd[31:0]); + end + end + #(BIT_TIME * 20); // 指令/数据组之间的间隔 + end + + $display("======= All Cases Sent ======="); + $fclose(file_ptr); + + #(BIT_TIME * 200); + $stop; + end +endmodule