/*
 * mailbox_wb.v
 *
 * vim: ts=4 sw=4
 *
 * Copyright (C) 2025 Krzysztof Skrzynecki, Jakub Duchniewicz <j.duchniewicz@gmail.com>
 * SPDX-License-Identifier: TODO:
 */

`default_nettype none

module mailbox_wb #(
    parameter AW = 4,  // Address width for 16 registers (4 bits)
    parameter DW = 32   // Data width for the Wishbone interface (32 bits)
)(
    input  wire             clk,
    input  wire             rst,
    // Wishbone Interface
    input  wire [AW-1:0]    wb_addr,
    input  wire [DW-1:0]    wb_wdata,
    output reg  [DW-1:0]    wb_rdata,
    input  wire             wb_we,
    input  wire             wb_cyc,
    output reg              wb_ack,

    // Flattened custom hardware side (RTL)
    output wire [16*16-1:0]     registers_flat  // Flattened register array (16 registers of 16 bits each)
);

    // Internal registers (16 registers, each 16 bits wide)
    reg [15:0] registers_array[15:0];

    // Always reset the registers on reset signal
    integer i;
    always @(posedge clk or posedge rst) begin
        if (rst) begin
            wb_ack <= 1'b0;
            for (i = 0; i < 16; i = i + 1) begin
                registers_array[i] <= 16'h0; // Reset all registers to 0
            end
        end else begin
            // Default no ack
            wb_ack <= 1'b0;

            if (wb_cyc) begin
                // Write operation (if write enable is active) // wb_stb would
                // help here
                if (wb_we) begin
                    case (wb_addr)
                        4'b0000: registers_array[0] <= wb_wdata[15:0]; // Only use lower 16 bits
                        4'b0001: registers_array[1] <= wb_wdata[15:0];
                        4'b0010: registers_array[2] <= wb_wdata[15:0];
                        4'b0011: registers_array[3] <= wb_wdata[15:0];
                        4'b0100: registers_array[4] <= wb_wdata[15:0];
                        4'b0101: registers_array[5] <= wb_wdata[15:0];
                        4'b0110: registers_array[6] <= wb_wdata[15:0];
                        4'b0111: registers_array[7] <= wb_wdata[15:0];
                        4'b1000: registers_array[8] <= wb_wdata[15:0];
                        4'b1001: registers_array[9] <= wb_wdata[15:0];
                        4'b1010: registers_array[10] <= wb_wdata[15:0];
                        4'b1011: registers_array[11] <= wb_wdata[15:0];
                        4'b1100: registers_array[12] <= wb_wdata[15:0];
                        4'b1101: registers_array[13] <= wb_wdata[15:0];
                        4'b1110: registers_array[14] <= wb_wdata[15:0];
                        4'b1111: registers_array[15] <= wb_wdata[15:0];
                    endcase
                end

                // Read operation (read the correct register based on address)
                case (wb_addr)
                    4'b0000: wb_rdata <= {16'h0, registers_array[0]}; // Place 16-bit value in lower half of 32-bit bus
                    4'b0001: wb_rdata <= {16'h0, registers_array[1]};
                    4'b0010: wb_rdata <= {16'h0, registers_array[2]};
                    4'b0011: wb_rdata <= {16'h0, registers_array[3]};
                    4'b0100: wb_rdata <= {16'h0, registers_array[4]};
                    4'b0101: wb_rdata <= {16'h0, registers_array[5]};
                    4'b0110: wb_rdata <= {16'h0, registers_array[6]};
                    4'b0111: wb_rdata <= {16'h0, registers_array[7]};
                    4'b1000: wb_rdata <= {16'h0, registers_array[8]};
                    4'b1001: wb_rdata <= {16'h0, registers_array[9]};
                    4'b1010: wb_rdata <= {16'h0, registers_array[10]};
                    4'b1011: wb_rdata <= {16'h0, registers_array[11]};
                    4'b1100: wb_rdata <= {16'h0, registers_array[12]};
                    4'b1101: wb_rdata <= {16'h0, registers_array[13]};
                    4'b1110: wb_rdata <= {16'h0, registers_array[14]};
                    4'b1111: wb_rdata <= {16'h0, registers_array[15]};
                    default: wb_rdata <= 32'hDEAD_BEEF; // Default error value
                endcase

                // Acknowledge for exactly 1 cycle
                wb_ack <= 1'b1;
            end
        end
    end

    // Flatten the registers array to the output port (registers_flat)
    generate
        genvar j;
        for (j = 0; j < 16; j = j + 1) begin : flatten
            assign registers_flat[16*(j+1)-1:16*j] = registers_array[j];
        end
    endgenerate

endmodule