// ============================================================================
// diffusion_ca.v - 扩散过程CA引擎
// 使用定点数表示浓度，Moore邻域Laplacian
// 支持多种边界条件和源项
// ============================================================================
module diffusion_ca #(
    parameter WIDTH  = 64,
    parameter HEIGHT = 64,
    parameter FRAC_W = 8,           // 小数部分位宽
    parameter [15:0] DIFF_COEFF = 16'h0100  // 扩散系数 D (8.8定点)
)(
    input  wire                     clk,
    input  wire                     rst_n,
    input  wire                     enable,
    input  wire                     init,
    // 浓度输入（8位整数+8位小数 = 16位/元胞）
    output wire [WIDTH*HEIGHT*16-1:0] concentration,
    output wire [31:0]              step_count,
    output wire [15:0]              total_mass    // 总质量守恒验证
);

    // 每格点16位浓度（8.8定点）
    reg [15:0] conc [0:WIDTH*HEIGHT-1];
    reg [15:0] conc_nxt [0:WIDTH*HEIGHT-1];
    reg [31:0] steps;

    integer idx, x, y;
    reg signed [19:0] laplacian;  // 20位有符号，足够容纳累加

    always @(*) begin
        for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1) begin
            x = idx % WIDTH;
            y = idx / WIDTH;

            // 计算Laplacian: Σ(c_neighbor - c_center)
            laplacian = 0;
            // 8个Moore邻居
            if (y > 0) begin
                laplacian = laplacian + $signed({1'b0, conc[(y-1)*WIDTH+x]}) - $signed({1'b0, conc[idx]});
                if (x > 0)  laplacian = laplacian + $signed({1'b0, conc[(y-1)*WIDTH+x-1]}) - $signed({1'b0, conc[idx]});
                if (x < WIDTH-1) laplacian = laplacian + $signed({1'b0, conc[(y-1)*WIDTH+x+1]}) - $signed({1'b0, conc[idx]});
            end
            if (y < HEIGHT-1) begin
                laplacian = laplacian + $signed({1'b0, conc[(y+1)*WIDTH+x]}) - $signed({1'b0, conc[idx]});
                if (x > 0)  laplacian = laplacian + $signed({1'b0, conc[(y+1)*WIDTH+x-1]}) - $signed({1'b0, conc[idx]});
                if (x < WIDTH-1) laplacian = laplacian + $signed({1'b0, conc[(y+1)*WIDTH+x+1]}) - $signed({1'b0, conc[idx]});
            end
            if (x > 0)  laplacian = laplacian + $signed({1'b0, conc[y*WIDTH+x-1]}) - $signed({1'b0, conc[idx]});
            if (x < WIDTH-1) laplacian = laplacian + $signed({1'b0, conc[y*WIDTH+x+1]}) - $signed({1'b0, conc[idx]});

            // 扩散更新: c_new = c + D * laplacian
            // D是8.8定点，laplacian是~16位
            conc_nxt[idx] = conc[idx] + (laplacian >>> FRAC_W);
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            steps <= 32'd0;
            for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1)
                conc[idx] <= 16'd0;
        end else if (init) begin
            steps <= 32'd0;
            for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1)
                conc[idx] <= 16'd0;
        end else if (enable) begin
            for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1)
                conc[idx] <= conc_nxt[idx];
            steps <= steps + 32'd1;
        end
    end

    genvar gi;
    generate
        for (gi = 0; gi < WIDTH*HEIGHT; gi = gi + 1)
            assign concentration[gi*16 +: 16] = conc[gi];
    endgenerate

    reg [31:0] mass;
    always @(*) begin
        mass = 0;
        for (idx = 0; idx < WIDTH*HEIGHT; idx = idx + 1)
            mass = mass + conc[idx];
    end
    assign step_count = steps;
    assign total_mass = mass[15:0];

endmodule