//+FHDR-------------------------------------------------------------------------------------------------------- // Company: //----------------------------------------------------------------------------------------------------------------- // File Name : spi_to_sram_v1.2.v // Department : // Author : ZYZ // Author's Tel : //----------------------------------------------------------------------------------------------------------------- // Relese History // Version Date Author Description // 1.2 2024-04-02 ZYZ //----------------------------------------------------------------------------------------------------------------- // Keywords : 1.replace stream mode of send 32bit data 16 times // 2.wrdata_reg address is no longer related to csn_active //----------------------------------------------------------------------------------------------------------------- // Parameter // //----------------------------------------------------------------------------------------------------------------- // Purpose : // //----------------------------------------------------------------------------------------------------------------- // Target Device: // Tool versions: //----------------------------------------------------------------------------------------------------------------- // Reuse Issues // Reset Strategy: // Clock Domains: // Critical Timing: // Asynchronous I/F: // Synthesizable (y/n): // Other: //-FHDR-------------------------------------------------------------------------------------------------------- module spi_to_sram ( //system port input clk // System Main Clock ,input spi_rstn // Spi Reset active low //spi port ,input sclk // Spi Clock ,input csn // Spi Chip Select active low ,input mosi // Spi Mosi ,output miso // Spi Miso ,output miso_oen // Spi Miso output enable ,output error_check // spi form check ,output [31:0] wrdata //write data to sram ,output [24:0] addr //sram address ,output wren //write enable sram ,output rden //rden enable sram ,input [31:0] rddata //read data from sram ); localparam L = 1'b0, H = 1'b1; //3-bits shift register for sclk's rising & falling edges reg [2 :0] sclk_reg; wire sclk_p; wire sclk_n; //3-bits shift register for csn reg [4 :0] csn_reg; wire csn_active; //2-bits shift register for mosi reg [1 :0] mosi_reg; wire mosi_data; //cmd_reg--> 0:write,1:read reg cmd_reg; //rxs_reg reg rxs_reg; //addr_reg--> initial address reg [24 :0] addr_reg; //rxd_reg --> recive data reg [31 :0] rxd_reg; //rx; reg [9 :0] rxcnt; wire add_rxcnt; wire end_rxcnt; wire wr_times; reg recv_start; reg wren_reg; reg wren_reg_1; reg [31 :0] wrdata_reg; //send data reg [31 :0] txd_reg; //tx; reg [9 :0] txcnt; wire add_txcnt; wire end_txcnt; reg trans_start; //read write address reg [24:0] rwaddr_reg; reg address_start; wire add_addr_wr; wire add_addr_rd; //read rddata to txd_reg reg rd_times; //read sram wire rd_sram; //foreread //output enable reg miso_reg; reg miso_oen_reg; //data form check reg error_check_reg ; reg [9:0] frame_len; ////////////////////////////////////////////////////////////////////////// //capture the sck ////////////////////////////////////////////////////////////////////////// //sync sclk to the main clock using a 3-bits shift register always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin sclk_reg <= 3'b000; end else begin sclk_reg <= {sclk_reg[1:0],sclk}; end end //sclk's rising edges assign sclk_p = (sclk_reg[2:1] == 2'b01); //sclk's falling edges assign sclk_n = (sclk_reg[2:1] == 2'b10); ////////////////////////////////////////////////////////////////////////// //capture the csn ////////////////////////////////////////////////////////////////////////// //sync csn to the main clock using a 3-bits shift register always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin csn_reg <= 5'b11111; end else begin csn_reg <= {csn_reg[3:0],csn}; end end // csn is active low assign csn_active = ~csn_reg[1]; ////////////////////////////////////////////////////////////////////////// //capture the mosi ////////////////////////////////////////////////////////////////////////// //sync mosi to the main clock using a 2-bits shift register always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin mosi_reg <= 2'b00; end else begin mosi_reg <= {mosi_reg[0],mosi}; end end //mosi_data assign mosi_data = mosi_reg[1]; ////////////////////////////////////////////////////////////////////////// //rxcnt ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin rxcnt <= 10'd0; end else if(end_rxcnt) begin rxcnt <= 10'd0; end else if (add_rxcnt)begin rxcnt <= rxcnt + 1'b1; end else begin rxcnt <= rxcnt; end end //add_rxcnt assign add_rxcnt = sclk_p && csn_active; assign end_rxcnt = add_rxcnt & (rxcnt == frame_len - 1'b1); assign wr_times = add_rxcnt & (rxcnt[4:0] == 5'd31) & ~cmd_reg; ////////////////////////////////////////////////////////////////////////// //cmd_reg ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin cmd_reg <= 1'b0; end else if(add_rxcnt && rxcnt == 10'd0 ) begin cmd_reg <= mosi_data; end else begin cmd_reg <= cmd_reg; end end ////////////////////////////////////////////////////////////////////////// //rxs_reg ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L ) begin rxs_reg <= 1'b0; end else if(add_rxcnt && rxcnt == 10'd1) begin rxs_reg <= mosi_data; end else begin rxs_reg <= rxs_reg; end end ////////////////////////////////////////////////////////////////////////// //addr_reg ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L ) begin addr_reg <= 25'd0; end else if(add_rxcnt && rxcnt <= 10'd26 ) begin addr_reg <= {addr_reg[23:0],mosi_data}; end else begin addr_reg <= addr_reg; end end ////////////////////////////////////////////////////////////////////////// //rxd_reg ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin rxd_reg <= 32'd0; end else if(add_rxcnt) begin rxd_reg <= {rxd_reg[30:0],mosi_data}; end else begin rxd_reg <= rxd_reg; end end ////////////////////////////////////////////////////////////////////////// //frame_len ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin frame_len <= 10'd0; end else if(add_rxcnt && rxcnt == 10'd2) begin if(rxs_reg) begin frame_len <= 10'd544; end else begin frame_len <= 10'd64; end end else begin frame_len <= frame_len; end end ////////////////////////////////////////////////////////////////////////// //recv_start ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin recv_start <= 1'b0; end else if(~csn_active )begin recv_start <= 1'b0; end else if(wr_times)begin recv_start <= 1'b1; end else begin recv_start <= recv_start; end end ////////////////////////////////////////////////////////////////////////// //wren_reg ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin wren_reg <= 1'b0; end else begin wren_reg <= recv_start & wr_times ; wren_reg_1 <= wren_reg; end end ////////////////////////////////////////////////////////////////////////// //wrdata_reg ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin wrdata_reg <= 32'b0; end else if(wren_reg)begin wrdata_reg <= rxd_reg; end end ////////////////////////////////////////////////////////////////////////// //txcnt ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin txcnt <= 10'd0; end else if(end_txcnt) begin txcnt <= 10'd0; end else if (add_txcnt)begin txcnt <= txcnt + 1'b1; end else begin txcnt <= txcnt; end end //add_txcnt assign add_txcnt = sclk_n && csn_active; //end_txcnt assign end_txcnt = add_txcnt && (txcnt == frame_len - 1'b1) ; ////////////////////////////////////////////////////////////////////////// //rd_times ////////////////////////////////////////////////////////////////////////// always@(*)begin if(rxs_reg)begin rd_times = add_txcnt & (txcnt[4:0] == 5'd31)& (txcnt != 10'd543) & cmd_reg; end else begin rd_times = add_txcnt & (txcnt[4:0] == 5'd31)& (txcnt != 10'd63) & cmd_reg; end end //rd_sram foreread //assign rd_sram = (rd_times) | (add_txcnt & (txcnt[9:0] == 5'd30) & cmd_reg) ; assign rd_sram = rd_times & cmd_reg; ////////////////////////////////////////////////////////////////////////// //trans_start ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin trans_start <= 1'b0; end else if(rd_times)begin trans_start <= 1'b1; end else if(~csn_active)begin trans_start <= 1'b0; end else begin trans_start <= trans_start; end end ////////////////////////////////////////////////////////////////////////// //txd_reg ////////////////////////////////////////////////////////////////////////// reg [2:0] rd_times_r; always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin rd_times_r <= 3'b0; end else begin rd_times_r <= {rd_times_r[1:0],rd_times}; end end always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin txd_reg <= 32'h0; end else if(rd_times_r[2]) begin txd_reg <= rddata; end else if(add_txcnt && trans_start && txcnt[4:0]!=5'd31) begin txd_reg <= {txd_reg[30:0],1'b0}; end else begin txd_reg <= txd_reg; end end ////////////////////////////////////////////////////////////////////////// //address_start ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin address_start <= 1'b0; end else if(txcnt == 10'd29)begin address_start <= 1'b1; end else if(~csn_active)begin address_start <= 1'b0; end else begin address_start <= address_start; end end ////////////////////////////////////////////////////////////////////////// //rwaddr_reg ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin rwaddr_reg <= 25'b0; end else if(address_start)begin if(add_addr_wr)begin rwaddr_reg <= rwaddr_reg + 3'd4; end else if(add_addr_rd)begin rwaddr_reg <= rwaddr_reg + 3'd4; end else begin rwaddr_reg <= rwaddr_reg; end end else begin rwaddr_reg <= addr_reg; end end assign add_addr_wr = rxs_reg & wren_reg_1 ; assign add_addr_rd = rxs_reg & rd_sram ; ////////////////////////////////////////////////////////////////////////// //miso_reg ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin miso_reg <= 1'b0; end else begin miso_reg <= txd_reg[31]; end end ////////////////////////////////////////////////////////////////////////// //miso_oen_reg ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin miso_oen_reg <= 1'b1; end else begin miso_oen_reg <= ~(trans_start & cmd_reg); end end ////////////////////////////////////////////////////////////////////////// //error_check ////////////////////////////////////////////////////////////////////////// always @(posedge clk or negedge spi_rstn) begin if(spi_rstn == L) begin error_check_reg <= 1'b0; end else if( (rxcnt != 0 || txcnt != 0)&&(~csn_active) )begin error_check_reg <= 1'b1; end end ////////////////////////////////////////////////////////////////////////// //Outputs signals ////////////////////////////////////////////////////////////////////////// //wren assign wren = wren_reg_1 ; //wrdata assign wrdata = wrdata_reg; //rden assign rden = rd_sram ; //addr assign addr = rwaddr_reg; //miso assign miso = miso_reg; //miso_oen assign miso_oen = miso_oen_reg; //error_check assign error_check = error_check_reg; endmodule