`timescale 1ns/1ps module Sdram_Tester #( parameter TEST_LENGTH = 24'd1048576 )( input wire clk, input wire rst_n, // --- 连接到 SDRAM 控制器的用户接口 --- output reg cmd_valid, input wire cmd_ready, output reg is_write, output reg [23:0] address, output wire [15:0] write_data, input wire rsp_valid, input wire [15:0] rsp_data, // --- 外部 LED 状态指示灯 --- output reg test_pass, // 绿色 LED,成功后闪烁 output reg test_fail // 红色 LED,发生错误时常亮 ); // ========================================== // 状态机定义 // ========================================== localparam S_INIT = 3'd0; // 等待 SDRAM 初始化 localparam S_WRITE = 3'd1; // 发起单次写命令 localparam S_READ = 3'd2; // 发起单次读命令 (交替操作) localparam S_WAIT_RSP = 3'd3; // 等待读响应并比对 localparam S_DONE = 3'd4; // 测试成功完成 localparam S_ERROR = 3'd5; // 数据校验错误 reg [2:0] state; reg [15:0] init_cnt; // 用于上电延时计数 reg [23:0] test_addr; // 当前正在测试的地址 // 新增:用于控制 LED 闪烁的 26 位计数器 reg [25:0] blink_cnt; // ========================================== // 测试数据生成器 // ========================================== // 地址低16位 异或 0x5A5A,保证每个地址的数据唯一且具有翻转特性 wire [15:0] expected_data = test_addr[15:0] ^ 16'h5A5A; assign write_data = expected_data; // ========================================== // 主状态机控制逻辑 // ========================================== always @(posedge clk or negedge rst_n) begin if (!rst_n) begin state <= S_INIT; init_cnt <= 16'd0; test_addr <= 24'd0; blink_cnt <= 26'd0; // 复位闪烁计数器 cmd_valid <= 1'b0; is_write <= 1'b0; address <= 24'd0; test_pass <= 1'b0; test_fail <= 1'b0; end else begin case (state) // 1. 等待初始化 (200us @ 100MHz) S_INIT: begin if (init_cnt < 16'd20000) begin init_cnt <= init_cnt + 1'b1; end else begin state <= S_WRITE; end end // 2. 写操作 S_WRITE: begin cmd_valid <= 1'b1; is_write <= 1'b1; address <= test_addr; if (cmd_valid && cmd_ready) begin cmd_valid <= 1'b0; state <= S_READ; end end // 3. 读操作 S_READ: begin cmd_valid <= 1'b1; is_write <= 1'b0; address <= test_addr; if (cmd_valid && cmd_ready) begin cmd_valid <= 1'b0; state <= S_WAIT_RSP; end end // 4. 数据比对 S_WAIT_RSP: begin if (rsp_valid) begin if (rsp_data == expected_data) begin if (test_addr == TEST_LENGTH - 1) begin state <= S_DONE; end else begin test_addr <= test_addr + 2'b11; state <= S_WRITE; end end else begin state <= S_ERROR; end end end // 5. 测试通过:LED 闪烁逻辑 S_DONE: begin // 计数器不断累加 blink_cnt <= blink_cnt + 1'b1; test_pass <= blink_cnt[25]; test_fail <= 1'b0; end // 6. 测试失败:红灯常亮 S_ERROR: begin test_pass <= 1'b0; test_fail <= 1'b1; end default: state <= S_INIT; endcase end end endmodule