
/*
// module dmux
module sram_dmux_m #(
    parameter ADDR_WIDTH_I = 11,  // input port addr width
    parameter ADDR_WIDTH_O = 10,  // output port addr width
    parameter DATA_WIDTH   = 64   // in/output port data width 
)(
    input logic clk,
    input logic rst_n,
    sram_if.slave port_in,
    sram_if.master port_out[2**(ADDR_WIDTH_I-ADDR_WIDTH_O)-1:0]
);
    localparam ASEL_WIDTH = ADDR_WIDTH_I-ADDR_WIDTH_O;
    logic [ASEL_WIDTH-1:0] data_sel, data_out_sel;
    assign data_sel = port_in.addr[ADDR_WIDTH_I-1 : ADDR_WIDTH_O];
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            data_out_sel <= 0;
        end else begin
            data_out_sel <= data_sel;
        end
    end

    logic [DATA_WIDTH-1:0] dout_data[2**(ASEL_WIDTH)-1:0];
    genvar i;
    generate
        for (i = 0; i < 2**ASEL_WIDTH; i++) begin 
            assign port_out[i].addr = (i == data_sel) ? port_in.addr[ADDR_WIDTH_O-1:0] : 0;            
            assign port_out[i].wren = (i == data_sel) ? port_in.wren : 0;
            assign port_out[i].rden = (i == data_sel) ? port_in.rden : 0;            
            assign port_out[i].din  = (i == data_sel) ? port_in.din : 0;
            assign port_out[i].wben = (i == data_sel) ? port_in.wben : 0;
            assign dout_data[i]= port_out[i].dout;
        end
    endgenerate
    assign port_in.dout = dout_data[data_out_sel];
    
endmodule
*/

// word dmux
module sram_dmux_w #(
    parameter ADDR_WIDTH   = 11,  // input port addr width
    parameter DATA_WIDTH_I = 32,  // input port data width 
    parameter DATA_WIDTH_O = 64   // output port data width 
)(
    input logic clk,
    input logic rst_n,
    sram_if.slave   port_in,
    sram_if.master  port_out
);

    // calculate and buffer word select bit
    localparam DL = $clog2(DATA_WIDTH_I/8);
    localparam DH = $clog2(DATA_WIDTH_O/8);
    localparam WSEL_WIDTH = DH - DL;
    logic [WSEL_WIDTH-1:0] data_sel, data_out_sel;
    assign data_sel = port_in.addr[DH-1:DL];
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            data_out_sel <= 0;
        end else begin
            data_out_sel <= data_sel;
        end
    end
    // 
    assign port_out.addr = port_in.addr;
    assign port_out.wren = port_in.wren;
    assign port_out.rden = port_in.rden;
    genvar i;
    generate
        for (i = 0; i < 2**(WSEL_WIDTH); i++) begin
            assign port_out.din[DATA_WIDTH_I*i +: DATA_WIDTH_I]  =  (i == data_sel) ? port_in.din : 0;
            assign port_out.wben[DATA_WIDTH_I/8*i +: DATA_WIDTH_I/8] =  (i == data_sel) ? port_in.wben : 0;
        end      
    endgenerate
    assign port_in.dout  = port_out.dout[DATA_WIDTH_I*data_out_sel +: DATA_WIDTH_I];

endmodule

/*
// data split
module sram_split #(
    parameter ADDR_WIDTH   = 11,  // input port addr width
    parameter DATA_WIDTH_I = 64,  // input port data width 
    parameter DATA_WIDTH_O = 32   // output port data width 
)(
    sram_if.slave port_in,
    sram_if.master  port_out[DATA_WIDTH_I/DATA_WIDTH_O-1:0]
);
    localparam DH = $clog2(DATA_WIDTH_I/8);
    localparam DL = $clog2(DATA_WIDTH_O/8);
    genvar i;
    generate
        for (i = 0; i < DATA_WIDTH_I/DATA_WIDTH_O; i++) begin
            assign port_out[i].addr = {port_in.addr[ADDR_WIDTH-1:DH], {DL{1'b0}}};
            assign port_out[i].rden = port_in.rden;
            assign port_out[i].wren = port_in.wren;
            assign port_out[i].din  = port_in.din[i*DATA_WIDTH_O +: DATA_WIDTH_O];
            assign port_out[i].wben = port_in.wben[i*DATA_WIDTH_O/8 +: DATA_WIDTH_O/8];
            assign port_in.dout[i*DATA_WIDTH_O +: DATA_WIDTH_O] = port_out[i].dout;
        end      
    endgenerate
endmodule
*/