// Relese History // Version Date Author Description // 0.3 2024-05-29 ZYZ //----------------------------------------------------------------------------------------------------------------- // Keywords : connect spi-master // //----------------------------------------------------------------------------------------------------------------- // Parameter : // cmd[31:0] form: // form-v0.2 {WR ,RSV ,ID ,ADDR} // [31] [30] [29:25] [24:0] // // form-v0.3 {WR ,ADDR ,ID ,RSV} // [31] [30:6] [5:1] [0] // // form-v0.2 is defined by design , it has len[31:0]; // form-v0.3 is produced by spi interface ,it doesn't have len[31:0]; // // size : 256K //----------------------------------------------------------------------------------------------------------------- // Purpose : // //----------------------------------------------------------------------------------------------------------------- // Target Device: // Tool versions: //----------------------------------------------------------------------------------------------------------------- // Reuse Issues // Reset Strategy: // Clock Domains: // Critical Timing: // Asynchronous I/F: // Synthesizable (y/n): // Other: //-FHDR-------------------------------------------------------------------------------------------------------- module tx_sram( input clk, input rstn, (* mark_debug="true" *)input [31:0] dina, (* mark_debug="true" *)input [15:0] data_length, output [31:0] Nlen, output [4 :0] chip_ID, output [24:0] address, output [31:0] data_out, (* mark_debug="true" *)output wr_en, (* mark_debug="true" *)output rd_en, (* mark_debug="true" *)input WREADY, (* mark_debug="true" *)input RREADY, output data_done_all, output data_out_per ); parameter width = 32 ; parameter depth = 65536 ; //================================================= function integer clog2(input integer depth); begin for(clog2=0;depth>0;clog2=clog2+1) depth =depth>>1; end endfunction //================================================= localparam aw = clog2(depth-1); //================================================= //wr&rd address (* mark_debug="true" *) reg [aw-1:0]cnta ; (* mark_debug="true" *) reg [aw-1:0]cntb ; (* mark_debug="true" *) wire ena ; (* mark_debug="true" *) wire enb ; (* mark_debug="true" *) wire full ; (* mark_debug="true" *) wire [31:0] doutb; //current len of data ,initial value is 0 (* mark_debug="true" *) reg [31:0]len_current ; //cmd (* mark_debug="true" *) reg cmd_s ; (* mark_debug="true" *) reg [4:0] chip_ID_reg ; (* mark_debug="true" *)reg [24:0]address_reg ; always@(posedge clk or negedge rstn)begin if(!rstn)begin cmd_s <= 1'b0; chip_ID_reg <= 5'b0; address_reg <= 25'b0; end else if(cntb == len_current + 2'd1)begin cmd_s <= doutb[31]; chip_ID_reg <= doutb[5:1]; address_reg <= doutb[30:6]; end else begin cmd_s <= cmd_s; chip_ID_reg <= chip_ID_reg; address_reg <= address_reg; end end assign chip_ID = chip_ID_reg; assign address = address_reg; //len of data_out (* mark_debug="true" *) reg [31:0]len_reg ; always@(posedge clk or negedge rstn)begin if(!rstn)begin len_reg <= 32'b0; end else if(cntb == len_current + 2'd2)begin len_reg <= doutb ; end else begin len_reg <= len_reg; end end assign Nlen = len_reg; //data_out (* mark_debug="true" *) reg [31:0]data_out_reg ; (* mark_debug="true" *) wire data_out_en ; always@(posedge clk or negedge rstn)begin if(!rstn)begin data_out_reg <= 32'b0; end else if(data_out_en)begin data_out_reg <= doutb ; end else begin data_out_reg <= 32'b0; end end reg data_out_en_r1; always@(posedge clk or negedge rstn)begin if(!rstn)begin data_out_en_r1 <= 1'b0; end else begin data_out_en_r1 <= data_out_en; end end assign data_out = data_out_reg; assign data_out_en = (cntb >= len_current + 2'd3) & (cntb <= len_current + len_reg + 2'd2); //signal send to spi_master assign wr_en = !cmd_s & data_out_en_r1; assign rd_en = cmd_s & data_out_en_r1; //signal send to PC assign data_out_per = (cntb == len_current + 3'd3 ) ? 1'b1 : 1'b0; assign data_done_all = (cntb == data_length-1'b1 | cnta == data_length - 1'b1) ? 1'b1 : 1'b0; //the time ready for writing data and updata len_current reg [2:0] wready_reg; always @(posedge clk or negedge rstn) begin if(!rstn ) begin wready_reg <= 3'b0; end else begin wready_reg <= {wready_reg[1:0],WREADY}; end end assign wready_posedge = wready_reg[1:0] == 2'b01 ? 1'b1 : 1'b0; //updata len_current and cntb always@(posedge clk or negedge rstn)begin if(!rstn)begin len_current <= 32'b0; end else if( wready_posedge & len_reg != 0)begin len_current <= len_current + len_reg + 2'd2 ; end else begin len_current <= len_current; end end //write address: addra //read address: addrb always @(posedge clk or negedge rstn) begin if(!rstn) begin cnta <= 'hffff; end else if(ena) begin cnta <= cnta + 1'b1; end else cnta <= cnta ; end always @(posedge clk or negedge rstn) begin if(!rstn ) begin cntb <= 'h0 ; end else if(enb) begin cntb <= cntb + 1'b1; end else if(wready_posedge & len_reg != 0) begin cntb <= cntb - 1'b1 ; // better solution? end else begin cntb <= cntb; end end assign full = (cnta+1'b1 <= data_length )? 1'b0 : 1'b1 ; assign ena = !full; assign enb = full & (cntb <= data_length ) & WREADY & (cntb <= len_current + len_reg + 2'd2); /* blk_mem_gen_0 blk_mem_gen_0_inst( .clka(clk), .ena(1'b1), .wea(ena), .dina(dina), .addra(cnta), .clkb(clk), .enb(enb), .doutb(doutb), .addrb(cntb) ); */ spram_model #( .width(width), .depth(depth) )spram_inst( .clka(clk), .ena(~ena), .dina(dina), .addra(cnta), .clkb(clk), .enb(~enb), .doutb(doutb), .addrb(cntb) ); endmodule