`timescale 1ns/1ps

module tb_array_wr();

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

    // 输入信号（DUT 的输入）
    reg                 array_wr_frame_valid;
    reg    [151:0]      array_wr_frame_data;
    reg    [7:0]        array_inner_tras;
    reg    [7:0]        array_inner_trp;
    reg    [7:0]        array_inner_trcd_wr;
    reg    [7:0]        array_inner_twr;

    // 输出信号（DUT 的输出）
    wire                array_wr_frame_ready;
    wire                array_wr_done;
    wire                array_wr_csn;
    wire   [15:0]       array_wr_raddr;
    wire                array_caddr_vld_wr;
    wire   [5:0]        array_caddr_wr;
    wire                array_wdata_vld;
    wire   [127:0]      array_wdata;

    // 实例化被测试模块（DUT）
    array_wr u_array_wr(
        .clk                (clk),
        .rst_n              (rst_n),
        .array_wr_frame_valid(array_wr_frame_valid),
        .array_wr_frame_data(array_wr_frame_data),
        .array_wr_frame_ready(array_wr_frame_ready),
        .array_wr_done      (array_wr_done),
        .array_wr_csn       (array_wr_csn),
        .array_wr_raddr     (array_wr_raddr),
        .array_caddr_vld_wr (array_caddr_vld_wr),
        .array_caddr_wr     (array_caddr_wr),
        .array_wdata_vld    (array_wdata_vld),
        .array_wdata        (array_wdata),
        .array_inner_tras   (array_inner_tras),
        .array_inner_trp    (array_inner_trp),
        .array_inner_trcd_wr(array_inner_trcd_wr),
        .array_inner_twr    (array_inner_twr)
    );

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

    // 主测试流程
    initial begin
        // 初始化信号
        rst_n = 1'b0;
        array_wr_frame_valid = 1'b0;
        array_wr_frame_data = 152'd0;
        array_inner_tras = 8'd3;    // 示例值：TRAS = 3 个时钟周期
        array_inner_trp = 8'd2;     // 示例值：TRP = 2 个时钟周期
        array_inner_trcd_wr = 8'd2; // 示例值：TRCD_WR = 2 个时钟周期
        array_inner_twr = 8'd2;     // 示例值：TWR = 2 个时钟周期

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

        // 测试场景 1：单帧数据写入（含 SOF 和 EOF）
        $display("=== 测试场景 1：单帧数据写入 ===");
        send_frame(
            1'b1,    // 起始标志
            1'b1,    // 结束标志（单帧）
            16'h1234,// 地址
            6'h05,   // 列地址
            128'hA5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5 // 数据
        );
        wait(array_wr_done); // 等待写入完成
        #100;

        // 测试场景 2：多帧数据写入（首帧 SOF，末帧 EOF）
        $display("=== 测试场景 2：多帧数据写入 ===");
        // 第一帧（SOF=1，EOF=0）
        send_frame(
            1'b1,
            1'b0,
            16'h5678,
            6'h0A,
            128'h55AA55AA55AA55AA55AA55AA55AA55AA
        );
        #20;
        // 第二帧（SOF=0，EOF=1）
        send_frame(
            1'b0,
            1'b1,
            16'h5678,  // 地址与前一帧相同（连续写入）
            6'h0B,
            128'hAA55AA55AA55AA55AA55AA55AA55AA55
        );
        wait(array_wr_done); // 等待写入完成
        #100;

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

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

    // 任务：发送一帧数据（封装输入信号逻辑）
    task send_frame;
        input           wsof;    // 帧起始标志
        input           weof;    // 帧结束标志
        input [15:0]    wraddr;  // 写入地址
        input [5:0]     wcaddr;  // 列地址
        input [127:0]   wdata;   // 写入数据
    begin
        // 等待模块就绪（ready 信号为高）
        wait(array_wr_frame_ready);
        #10; // 延迟一小段时间

        // 驱动输入信号
        array_wr_frame_valid = 1'b1;
        array_wr_frame_data = {wsof, weof, wraddr, wcaddr, wdata}; // 拼接帧数据
        #20; // 保持一个时钟周期

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

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

    // 监控关键信号变化（可选，用于调试）
    initial begin
        $monitor(
            "Time: %0t, State: %h, CSN: %b, Ready: %b, Done: %b, Valid: %b",
            $time, u_array_wr.cur_state, array_wr_csn, array_wr_frame_ready, array_wr_done, array_wdata_vld
        );
    end

endmodule