// ============================================================================
// prng_rule30.v - 基于规则30的硬件伪随机数生成器
// 从中心列提取随机位，支持多位并行输出
// ============================================================================
module prng_rule30 #(
    parameter WIDTH     = 64,      // CA网格宽度（建议≥32）
    parameter OUT_WIDTH = 32       // 随机数输出位宽
)(
    input  wire                  clk,
    input  wire                  rst_n,
    input  wire                  enable,      // 使能
    input  wire                  init,        // 初始化
    input  wire [WIDTH-1:0]      seed,        // 初始种子
    output wire [OUT_WIDTH-1:0]  random_out,  // 随机数输出
    output wire                  valid,       // 输出有效
    output wire [WIDTH-1:0]      state_debug  // 调试：当前CA状态
);

    // ---- CA状态寄存器 ----
    reg [WIDTH-1:0] curr;
    reg [WIDTH-1:0] nxt;

    // ---- 规则30: f(L,C,R) = L XOR (C OR R) ----
    // 优化实现：无需8:1 MUX，直接用布尔逻辑
    wire left_ext  = curr[WIDTH-1]; // 环形：左边界的左邻居
    wire right_ext = curr[0];       // 环形：右边界的右邻居

    genvar i;
    generate
        for (i = 0; i < WIDTH; i = i + 1) begin : gen_rule30
            wire L = (i == 0)        ? left_ext  : curr[i-1];
            wire C = curr[i];
            wire R = (i == WIDTH-1)  ? right_ext : curr[i+1];
            assign nxt[i] = L ^ (C | R);
        end
    endgenerate

    // ---- 状态更新 ----
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            curr <= {WIDTH{1'b0}};
        else if (init)
            curr <= seed;
        else if (enable)
            curr <= nxt;
    end

    // ---- 随机位提取 ----
    // 方法1：取中心列连续OUT_WIDTH步的值（需要OUT_WIDTH步才能输出一个数）
    // 方法2：从当前状态的多列并行提取（1步即可输出）

    // 这里采用方法2：从网格中均匀采样OUT_WIDTH个位
    // 采样间隔 = WIDTH / OUT_WIDTH
    localparam SAMPLE_GAP = WIDTH / OUT_WIDTH;

    genvar j;
    generate
        for (j = 0; j < OUT_WIDTH; j = j + 1) begin : gen_sample
            // 从右半部分采样（右半部分更混沌）
            localparam IDX = WIDTH/2 + (j * SAMPLE_GAP);
            // 确保索引在范围内
            if (IDX < WIDTH)
                assign random_out[j] = curr[IDX];
            else
                assign random_out[j] = curr[WIDTH-1];
        end
    endgenerate

    assign valid       = enable;
    assign state_debug = curr;

endmodule