`timescale 1ns/1ps

module tb_array_rd();

    // 时钟和复位信号
    reg                 clk;
    reg                 rst_n;

    // 输入信号（DUT 的输入）
    reg                 array_rd_frame_valid;
    reg    [151:0]      array_rd_frame_data;
    reg                 array_rdata_vld;
    reg    [127:0]      array_rdata;
    reg    [7:0]        array_inner_tras;
    reg    [7:0]        array_inner_trp;
    reg    [7:0]        array_inner_trcd_rd;
    reg    [7:0]        array_inner_trtp;

    // 输出信号（DUT 的输出）
    wire                array_rd_frame_ready;
    wire                array_rd_done;
    wire                array_rd_csn;
    wire   [15:0]       array_rd_raddr;
    wire                array_caddr_vld_rd;
    wire   [5:0]        array_caddr_rd;
    wire                array2axi_rdata_valid;
    wire   [127:0]      array2axi_rdata;

    // 实例化被测试模块（DUT）
    array_rd u_array_rd(
        .clk                (clk),
        .rst_n              (rst_n),
        .array_rd_frame_valid(array_rd_frame_valid),
        .array_rd_frame_data(array_rd_frame_data),
        .array_rd_frame_ready(array_rd_frame_ready),
        .array_rd_done      (array_rd_done),
        .array_rd_csn       (array_rd_csn),
        .array_rd_raddr     (array_rd_raddr),
        .array_caddr_vld_rd (array_caddr_vld_rd),
        .array_caddr_rd     (array_caddr_rd),
        .array_rdata_vld    (array_rdata_vld),
        .array_rdata        (array_rdata),
        .array_inner_tras   (array_inner_tras),
        .array_inner_trp    (array_inner_trp),
        .array_inner_trcd_rd(array_inner_trcd_rd),
        .array_inner_trtp   (array_inner_trtp),
        .array2axi_rdata_valid(array2axi_rdata_valid),
        .array2axi_rdata    (array2axi_rdata)
    );

    // 生成时钟（50MHz，周期 20ns）
    initial begin
        clk = 1'b0;
        forever #10 clk = ~clk;
    end

    // 主测试流程
    initial begin
        // 初始化信号
        rst_n = 1'b0;
        array_rd_frame_valid = 1'b0;
        array_rd_frame_data = 152'd0;
        array_rdata_vld = 1'b0;
        array_rdata = 128'd0;
        array_inner_tras = 8'd3;     // 示例值：TRAS = 3 个时钟周期
        array_inner_trp = 8'd2;      // 示例值：TRP = 2 个时钟周期
        array_inner_trcd_rd = 8'd2;  // 示例值：TRCD_RD = 2 个时钟周期
        array_inner_trtp = 8'd1;     // 示例值：TRTP = 1 个时钟周期

        // 复位释放（10 个时钟周期后）
        #200;
        rst_n = 1'b1;
        #20;

        // 测试场景 1：单帧数据读取（含 SOF 和 EOF）
        $display("=== 测试场景 1：单帧数据读取 ===");
        send_frame(
            1'b1,    // 起始标志
            1'b1,    // 结束标志（单帧）
            16'h1234,// 读取地址
            6'h05,   // 列地址
            128'h0  // 读取操作的帧数据中数据段无效，填0
        );
        #20;
        drive_rdata(128'hA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5); // 返回读取数据
        wait(array_rd_done); // 等待读取完成
        #100;

        // 测试场景 2：多帧数据读取（首帧 SOF，末帧 EOF）
        $display("=== 测试场景 2：多帧数据读取 ===");
        // 第一帧（SOF=1，EOF=0）
        send_frame(
            1'b1,
            1'b0,
            16'h5678,
            6'h0A,
            128'h0  // 数据段无效
        );
        // 模拟返回第一帧数据
        drive_rdata(128'h55AA55AA55AA55AA55AA55AA55AA55AA);
        #10;
        // 第二帧（SOF=0，EOF=1）
        send_frame(
            1'b0,
            1'b1,
            16'h5678,  // 地址与前一帧相同（连续读取）
            6'h0B,
            128'h0  // 数据段无效
        );
        drive_rdata(128'hAA55AA55AA55AA55AA55AA55AA55AA55);
        wait(array_rd_done); // 等待读取完成
        #100;

        // 测试场景 3：无输入时的空闲状态
        $display("=== 测试场景 3：空闲状态验证 ===");
        array_rd_frame_valid = 1'b0;
        #200;

        // 测试结束
        $display("=== 所有测试场景完成 ===");
        $finish;
    end

    // 任务：发送一帧读取请求
    task send_frame;
        input           rsof;    // 帧起始标志
        input           reof;    // 帧结束标志
        input [15:0]    rraddr;  // 读取地址
        input [5:0]     rcaddr;  // 列地址
        input [127:0]   wdata;   // 占位（读取操作中无效）
    begin
        // 等待模块就绪（ready 信号为高）
        wait(array_rd_frame_ready);
        #10; // 延迟一小段时间

        // 驱动输入信号
        array_rd_frame_valid = 1'b1;
        array_rd_frame_data = {rsof, reof, rraddr, rcaddr, wdata}; // 拼接帧数据
        #20; // 保持一个时钟周期

        // 撤销有效信号
        array_rd_frame_valid = 1'b0;
        array_rd_frame_data = 152'd0;
    end
    endtask

    // 任务：驱动读取数据返回
    task drive_rdata;
        input [127:0] data; // 要返回的读取数据
    begin
        array_rdata_vld = 1'b1;
        array_rdata = data;
        #20; // 保持一个时钟周期
        array_rdata_vld = 1'b0;
        array_rdata = 128'd0;
    end
    endtask

    initial begin
        $fsdbDumpfile("tb.fsdb");
        $fsdbDumpvars(0,tb_array_rd,"+all");
        $vcdpluson;
        $vcdplusmemon;
    end

    // 监控关键信号变化（用于调试）
    initial begin
        $monitor(
            "Time: %0t, State: %h, CSN: %b, Ready: %b, Done: %b, CaddrVld: %b, FIFOValid: %b",
            $time, u_array_rd.cur_state, array_rd_csn, array_rd_frame_ready, 
            array_rd_done, array_caddr_vld_rd, array2axi_rdata_valid
        );
    end

endmodule