// On-Chip Memory: 4-Bank Double-Buffered SRAM + DMA
module onchip_mem #(parameter DW=16, AW=12, NB=4, DEPTH=4096, BURST=16)(
    input clk, rst_n,
    output reg [31:0] dma_addr, output reg dma_valid, output reg [15:0] dma_len,
    input dma_ready, input [DW*NB-1:0] dma_data, input dma_dvalid, input dma_last,
    input [AW-1:0] raddr[0:NB-1], input [NB-1:0] ren, output [DW*NB-1:0] rdata, output [NB-1:0] rvalid,
    input [AW-1:0] waddr[0:NB-1], input [NB-1:0] wen, input [DW*NB-1:0] wdata,
    input [NB-1:0] bsel, input [1:0] bufsel, output [NB*2-1:0] bstat
);
    genvar i; generate for(i=0;i<NB;i++) begin:bg
        sram_bank #(.DW(DW),.DEPTH(DEPTH)) ub0(.clk(clk),.rst_n(rst_n),.ra(raddr[i]),.re(ren[i]&&!bufsel[0]),.rd(rdata[i*DW+:DW]),.wa(waddr[i]),.we(wen[i]&&!bufsel[0]),.wd(wdata[i*DW+:DW]));
        sram_bank #(.DW(DW),.DEPTH(DEPTH)) ub1(.clk(clk),.rst_n(rst_n),.ra(raddr[i]),.re(ren[i]&&bufsel[0]),.rd(),.wa(waddr[i]),.we(wen[i]&&bufsel[0]),.wd(wdata[i*DW+:DW]));
    end endgenerate
    assign rvalid=ren&bsel; assign bstat='0;
    reg [1:0] ds; reg [15:0] dcnt; reg [31:0] dbase;
    always_ff @(posedge clk or negedge rst_n)
        if(!rst_n) begin ds<=0; dcnt<=0; dbase<=0; dma_valid<=0; dma_addr<=0; dma_len<=0; end
        else case(ds) 0: begin dma_valid<=0; if(dma_ready&&|bsel) begin ds<=1; dcnt<=0; dma_valid<=1; dma_addr<=dbase; dma_len<=BURST; end end
            1: if(dma_ready) begin dma_valid<=0; ds<=2; end
            2: if(dma_dvalid) begin dcnt<=dcnt+1; if(dma_last) begin ds<=0; dbase<=dbase+BURST; end end
        endcase
endmodule

module sram_bank #(parameter DW=16, DEPTH=4096, AW=12)(
    input clk, rst_n, input [AW-1:0] ra, input re, output reg [DW-1:0] rd, input [AW-1:0] wa, input we, input [DW-1:0] wd
);
    reg [DW-1:0] mem[0:DEPTH-1]; always_ff @(posedge clk) if(re) rd<=mem[ra]; always_ff @(posedge clk) if(we) mem[wa]<=wd;
endmodule