
module sram_tp_pcie_3072x35 #(
    parameter WIDTH = 35,
    parameter DEPTH = 3072,
    parameter IN_PIPE = 0,
    parameter OUT_PIPE = 1
)(
    input wire CLK,       // Write/Read Clock, Sync type SRAM
    input wire WEB,       // Write Enable, Active-low
    input wire [$clog2(DEPTH)-1:0] AA,  // Write Address
    input wire [WIDTH-1:0] D,           // Write Data
    input wire [WIDTH-1:0] BWEB,        // Bit mask Write Enable, Active-low
    input wire REB,                     // Read Enable, Active-low
    input wire [$clog2(DEPTH)-1:0] AB,  // Read Address
    
    input wire mem_ctrl_bus_sd,
    input wire [64 -1:0] mem_ctrl_bus,
    
    output wire [WIDTH-1:0] Q           // Read Data Output
);
    localparam ADDR_WIDTH = $clog2(DEPTH);
    
    wire sram_web;
    wire [ADDR_WIDTH-1:0] sram_waddr;
    wire [WIDTH-1:0] sram_wdata;
    wire [WIDTH-1:0] sram_bweb;
    wire sram_reb;
    wire [ADDR_WIDTH-1:0] sram_raddr;
    wire [WIDTH-1:0] sram_rdata;

    localparam ASSEMBLY_WIDTH_NUMS = 1;
    localparam ASSEMBLY_DEPTH_NUMS = 3;
    localparam COMPILE_DEPTH      = 1024;
    localparam COMPILE_WIDTH      = 35;

    localparam ADDR_COMPILE_WIDTH = $clog2(COMPILE_DEPTH);

    wire SD     = mem_ctrl_bus_sd;
    wire [2 -1:0] RTSEL  = mem_ctrl_bus[63:62];
    wire [2 -1:0] MTSEL  = mem_ctrl_bus[59:58];
    wire [2 -1:0] WTSEL  = mem_ctrl_bus[55:54];

    `ifdef USE_N12_TSMC_SRAM

    wire[ASSEMBLY_DEPTH_NUMS - 1:0] sram_web_sub;
    wire[ASSEMBLY_DEPTH_NUMS - 1:0] sram_reb_sub;
    wire[WIDTH - 1:0] sram_rdata_sub[ASSEMBLY_DEPTH_NUMS - 1:0];

    wire [ADDR_WIDTH -1:ADDR_COMPILE_WIDTH] sram_sel =  sram_raddr[ADDR_WIDTH -1:ADDR_COMPILE_WIDTH];
    assign sram_rdata = sram_rdata_sub[sram_sel];

    genvar gv_row;
    genvar gv_col;

    generate
        for (gv_row=0;gv_row<ASSEMBLY_DEPTH_NUMS;gv_row=gv_row+1 ) begin:gen_sram_row
            assign sram_web_sub[gv_row] = (WEB==1'b0 && AA[ADDR_WIDTH -1:ADDR_COMPILE_WIDTH]==gv_row) ? 1'b0 : 1'b1;
            assign sram_reb_sub[gv_row] = (REB==1'b0 && AB[ADDR_WIDTH -1:ADDR_COMPILE_WIDTH]==gv_row) ? 1'b0 : 1'b1;

            for (gv_col=0;gv_col<ASSEMBLY_WIDTH_NUMS;gv_col=gv_col+1) begin:gen_sram_col
                //== SRAM Instance
                if(DEPTH==3072 && WIDTH==35) begin : GEN_3072X35_SRAM
                    TSN12FFCLLULVTB1024x35M4WSHOCP U_TSN12FFCLLULVTB1024x35M4WSHOCP (
                        .CLK   (CLK                                 ),
                        .WEB   (sram_web_sub[gv_row]               ),
                        .AA    (sram_waddr[ADDR_COMPILE_WIDTH-1:0] ),
                        .D     (sram_wdata[gv_col*(WIDTH/ASSEMBLY_WIDTH_NUMS) +: COMPILE_WIDTH] ),
                        .BWEB  (sram_bweb[gv_col*(WIDTH/ASSEMBLY_WIDTH_NUMS) +: COMPILE_WIDTH]  ),
                        .REB   (sram_reb_sub[gv_row]                ),
                        .AB    (sram_raddr[ADDR_COMPILE_WIDTH-1:0] ),
                        .Q     (sram_rdata_sub[gv_row][gv_col*(WIDTH/ASSEMBLY_WIDTH_NUMS) +: COMPILE_WIDTH]),
                        //.BIST  (1'b0),
                        //.WEBM  (1'b0),
                        //.AMA   ({ADDR_WIDTH{1'b0}}),
                        //.DM    (0)
                        //.BWEBM (0),
                        //.REBM  (1'b0),
                        //.AMB   ({ADDR_WIDTH{1'b0}}),
                        .RTSEL (RTSEL),
                        .WTSEL (WTSEL),
                        .MTSEL (MTSEL),
                        .SLP   (1'b0),    
                        .DSLP  (1'b0),    
                        .SD    (SD),      
                        .PUDELAY (),     
                        .FADIO (9'd0),    
                        .REDENIO (1'b0)   
                    );
                end
                else begin : ILLEAGAL_SIZE_SRAM
                    //$display("\tERROR %m : Illegal SRAM size. %t\n", $realtime);
                end
            end
        end
    endgenerate

`elsif USE_N12_SNPS_SRAM

`elsif USE_N7_TSMC_SRAM

`elsif USE_N7_SNPS_SRAM

`else
    reg [WIDTH-1:0] ram [DEPTH-1:0];
    reg [WIDTH-1:0] rdata_ff;
    integer i;

    always @(posedge CLK) begin
        if (WEB == 1'b0) begin // write
            for (i = 0; i < WIDTH; i = i + 1) begin
                if (BWEB[i] == 1'b0) 
                    ram[AA][i] <= D[i]; 
            end
        end
    end

    always @(posedge CLK) begin
        if (REB == 1'b0) begin // read
            rdata_ff <= ram[AB];  
        end
    end
    assign sram_rdata = rdata_ff;
`endif

// Input PIPE
generate
    if(IN_PIPE==1) begin : GEN_IN_PIPE_1
        reg          web_ff;
        reg [WIDTH-1:0]  bweb_ff;
        reg [ADDR_WIDTH-1:0] aa_ff;
        reg [ADDR_WIDTH-1:0] ab_ff;
        reg [WIDTH-1:0]  d_ff;
        reg          reb_ff;
        
        always @(posedge CLK) begin
            if(WEB==1'b0) begin
                web_ff  <= 1'b0;
                bweb_ff <= BWEB;
                aa_ff   <= AA;
                d_ff    <= D;
            end
            else begin
                web_ff  <= 1'b1;
            end
        end
        
        always @(posedge CLK) begin
            if(REB==1'b0) begin
                reb_ff  <= 1'b0;
                ab_ff   <= AB;
            end
            else begin
                reb_ff  <= 1'b1;
            end
        end
        
        assign sram_web   = web_ff;
        assign sram_waddr = aa_ff;
        assign sram_wdata = d_ff;
        assign sram_bweb  = bweb_ff;
        assign sram_reb   = reb_ff;
        assign sram_raddr = ab_ff;
    end
    else begin : GEN_IN_PIPE_0
        assign sram_web   = WEB;
        assign sram_waddr = AA;
        assign sram_wdata = D;
        assign sram_bweb  = BWEB;
        assign sram_reb   = REB;
        assign sram_raddr = AB;
    end
endgenerate

generate
    if(OUT_PIPE==1) begin : GEN_OUT_PIPE_1
        reg          sram_ren_ff;
        reg [WIDTH-1:0] sram_rdata_ff;
        
        always @(posedge CLK) begin
            if(REB == 1'b0) begin
                sram_ren_ff <= 1'b1;  
            end
            else begin
                sram_ren_ff <= 1'b0;  
            end
        end

        always @(posedge CLK) begin
            if(sram_ren_ff == 1'b1) begin
                sram_rdata_ff <= sram_rdata; 
            end
            else begin
                sram_rdata_ff <= sram_rdata_ff;
            end
        end
        assign Q = sram_rdata_ff; 
    end
    else begin : GEN_OUT_PIPE_0
        assign Q = sram_rdata; 
    end
endgenerate

endmodule