//+FHDR-------------------------------------------------------------------------------------------------------- // Company: //----------------------------------------------------------------------------------------------------------------- // File Name : spi_sys.v // Department : // Author : PWY // Author's Tel : //----------------------------------------------------------------------------------------------------------------- // Relese History // Version Date Author Description // 0.1 2024-04-13 PWY SPI BUS for System //----------------------------------------------------------------------------------------------------------------- // Keywords : // //----------------------------------------------------------------------------------------------------------------- // Parameter // //----------------------------------------------------------------------------------------------------------------- // Purpose : // //----------------------------------------------------------------------------------------------------------------- // Target Device: // Tool versions: //----------------------------------------------------------------------------------------------------------------- // Reuse Issues // Reset Strategy: // Clock Domains: // Critical Timing: // Asynchronous I/F: // Synthesizable (y/n): // Other: //-FHDR-------------------------------------------------------------------------------------------------------- //-----------------------------Spi Frame------------------------------------------------------------------------------------- ////MSB------------->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>..............................................>>>>>>>>------->LSB ///|<-----------MSB 32 bits------------------->||<---------Second 32-bit---->||<-------x 32-bit---->||<-------n 32-bit---->| // +-----++----------------------++------------++-----++---------------------++---------------------++---------------------+ // | 31 || 30:6 || 5:1 || 0 || 31:0 || ...... || 31:0 | // +-----++----------------------++------------++-----++---------------------++---------------------++---------------------+ // +-----++----------------------++------------++-----++---------------------++---------------------++---------------------+ // | wnr || addr[24:0] || CHIPID ||resv || data[31:0] || ...... || data[31:0] | // +-----++----------------------++------------++-----++---------------------++---------------------++---------------------+ //-----------------------------Spi Frame------------------------------------------------------------------------------------- module spi_sys ( //system port input clk // System Main Clock ,input rst_n // Spi Reset active low //cfg ID ,input [4 :0] cfgid //ID number for the entire chip //spi port ,input sclk // Spi Clock ,input csn // Spi Chip Select active low ,input mosi // Spi Mosi ,output miso // Spi Miso ,output oen // Spi Miso output enable ,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 IDLE = 2'b00, RECVCMD = 2'b01, WRITE = 2'b10, READ = 2'b11; //----------------------------------------------------------------------- //SPI module reset processing //----------------------------------------------------------------------- //spi_rstn //wire spi_rstn; //assign spi_rstn = rst_n & (~csn); ////////////////////////////////////////////////////////////////////////// //capture the sck ////////////////////////////////////////////////////////////////////////// wire [2:0] sclk_reg; //sync sclk to the main clock using a 3-bits shift register sirv_gnrl_dffrs #(3) sclk_reg_dffrs ({sclk_reg[1:0],sclk}, sclk_reg, clk, rst_n); //sclk's rising edges wire sclk_p = (sclk_reg[2:1] == 2'b01); //sclk's falling edges //assign sclk_n = (sclk_reg[2:1] == 2'b10); ////////////////////////////////////////////////////////////////////////// //capture the csn ////////////////////////////////////////////////////////////////////////// wire [2:0] csn_reg; //sync csn to the main clock using a 2-bits shift register sirv_gnrl_dffrs #(3) csn_reg_dffrs ({csn_reg[1:0],csn}, csn_reg, clk, rst_n); // csn is active low wire csn_active = ~csn_reg[1]; //csn's rising edges wire csn_p = (csn_reg[2:1] == 2'b01); //csn's falling edges wire csn_n = (csn_reg[2:1] == 2'b10); ////////////////////////////////////////////////////////////////////////// //capture the mosi ////////////////////////////////////////////////////////////////////////// wire [1:0] mosi_reg; //sync mosi to the main clock using a 2-bits shift register sirv_gnrl_dffr #(2) mosi_reg_dffr ({mosi_reg[0],mosi}, mosi_reg, clk, rst_n); //mosi_data wire mosi_data = mosi_reg[1]; ////////////////////////////////////////////////////////////////////////// //cnt ////////////////////////////////////////////////////////////////////////// wire [4:0] cnt_c; //add_cnt assign add_cnt = sclk_p && csn_active; //end_cnt assign end_cnt = (add_cnt && (cnt_c == 5'd31)) | csn_p; wire [4:0] cnt_n = end_cnt ? 5'h0 : add_cnt ? cnt_c + 5'b1 : cnt_c ; sirv_gnrl_dffr #(5) cnt_c_dffr (cnt_n, cnt_c, clk, rst_n); /////////////////////////////////////////////////////////////////////// //SPI data sample /////////////////////////////////////////////////////////////////////// generate genvar i; wire [31:0] recv_vld ; wire [31:0] spi_din ; for(i=0;i<32;i=i+1) begin: spi_sys_recv assign recv_vld[i] = add_cnt & (cnt_c == i ); sirv_gnrl_dfflr #(1) spi_din_dfflr (recv_vld[i], mosi_data, spi_din[31-i], clk, rst_n); end endgenerate wire [1:0] state_c; wire [1:0] state_n; /////////////////////////////////////////////////////////////////////// //init_addr capture /////////////////////////////////////////////////////////////////////// wire [24:0] initaddr; wire initaddr_vld = (state_c == RECVCMD ) & add_cnt && (cnt_c == 5'd26); wire [1:0] initaddr_vld_r; sirv_gnrl_dffr #(2) initaddr_vld_r_dffr ({initaddr_vld_r[0],initaddr_vld}, initaddr_vld_r, clk, rst_n); sirv_gnrl_dfflr #(25) initaddr_dfflr (initaddr_vld_r[0], spi_din[30:6], initaddr, clk, rst_n); /////////////////////////////////////////////////////////////////////// //CMD capture /////////////////////////////////////////////////////////////////////// wire cmd ; sirv_gnrl_dfflr #(1) cmd_dfflr ( initaddr_vld_r[0], spi_din[31], cmd, clk, rst_n); /////////////////////////////////////////////////////////////////////// //CHIPID capture /////////////////////////////////////////////////////////////////////// wire [4:0] chipid; wire [1:0] chipid_vld_r; wire chipid_vld = (state_c == RECVCMD ) & add_cnt & (cnt_c == 5'd30); //register cmd_vld to align it with cmd sirv_gnrl_dffr #(2) chipid_vld_r_dffr ({chipid_vld_r[0],chipid_vld}, chipid_vld_r, clk, rst_n); sirv_gnrl_dfflr #(5) chipid_dfflr (chipid_vld_r[0], spi_din[5:1], chipid, clk, rst_n); /////////////////////////////////////////////////////////////////////// //ID matching determination /////////////////////////////////////////////////////////////////////// wire chipid_match = (chipid == cfgid); wire chipid_dismatch = (chipid != cfgid); /////////////////////////////////////////////////////////////////////// //SPI Module State Machine /////////////////////////////////////////////////////////////////////// //Generating jump conditions for state machines wire ilde2recvcmd = (state_c == IDLE ) && csn_active && csn_n ; wire recvcmd2ilde = (state_c == RECVCMD ) && chipid_dismatch & end_cnt; wire recvcmd2write = (state_c == RECVCMD ) && chipid_match && ~cmd & end_cnt; wire recvcmd2read = (state_c == RECVCMD ) && chipid_match && cmd & end_cnt; wire write2idle = (state_c == WRITE ) && csn_p; wire read2idle = (state_c == READ ) && csn_p; //The first section of the state machine //state_c sirv_gnrl_dffr #(2) state_c_dffr (state_n, state_c, clk, rst_n); //state_n assign state_n = ((state_c == IDLE ) && ilde2recvcmd ) ? RECVCMD : ((state_c == RECVCMD ) && recvcmd2ilde ) ? IDLE : ((state_c == RECVCMD ) && recvcmd2write ) ? WRITE : ((state_c == RECVCMD ) && recvcmd2read ) ? READ : ((state_c == WRITE ) && write2idle ) ? IDLE : ((state_c == READ ) && read2idle ) ? IDLE : state_c ; /////////////////////////////////////////////////////////////////////////////////////////////////////// //Address generation for read and write operations //The address to be used for updating in the next //27 clock cycles in the read-write state /////////////////////////////////////////////////////////////////////////////////////////////////////// wire second_falling; wire second_falling_w = (state_c == WRITE); sirv_gnrl_dfflr #(1) second_falling_dfflr (end_cnt ,second_falling_w, second_falling, clk, rst_n); wire addr_update = ((state_c == READ) | ((state_c == WRITE) & second_falling)) & add_cnt & (cnt_c == 5'd27); wire [24:0] addr_c; wire [24:0] addr_n = ilde2recvcmd ? 25'd0 : initaddr_vld_r[1] ? initaddr : addr_update ? addr_c + 25'd4 : addr_c ; sirv_gnrl_dffr #(25) addr_c_dffr (addr_n, addr_c, clk, rst_n); assign addr = addr_c; /////////////////////////////////////////////////////////////////////////////////////////////////////// //Write data and write signals generation /////////////////////////////////////////////////////////////////////////////////////////////////////// wire wren_r; wire wren_w = (state_c == WRITE) & add_cnt & (cnt_c == 5'd31); //wdata sirv_gnrl_dfflr #(32) wrdata_dfflr (wren_r, spi_din[31:0], wrdata, clk, rst_n); //wren_r sirv_gnrl_dffr #(1) wren_r_dffr (wren_w, wren_r, clk, rst_n); //wren sirv_gnrl_dffr #(1) wren_dffr (wren_r, wren, clk, rst_n); /////////////////////////////////////////////////////////////////////////////////////////////////////// //read signals generation /////////////////////////////////////////////////////////////////////////////////////////////////////// wire rden_w = cmd & add_cnt & (cnt_c == 5'd28); sirv_gnrl_dffr #(1) rden_dffr (rden_w, rden, clk, rst_n); //Read data register wire rddata_vld = cmd & add_cnt & (cnt_c == 5'd30); wire [31:0] rddata_reg; sirv_gnrl_dfflr #(32) rddata_reg_dfflr (rddata_vld, rddata[31:0], rddata_reg, clk, rst_n); /////////////////////////////////////////////////////////////////////////////////////////////////////// //SPI send data update /////////////////////////////////////////////////////////////////////////////////////////////////////// wire [31:0] spi_dout ; wire update_flag = cmd & add_cnt & (cnt_c == 5'd31); wire [31:0] rddata_sr = update_flag ? rddata_reg[31:0] : ((state_c == READ) & add_cnt) ? {spi_dout[31:0],1'b0} : spi_dout ; sirv_gnrl_dffr #(32) spi_dout_dffr (rddata_sr, spi_dout, clk, rst_n); /////////////////////////////////////////////////////////////////////////////////////////////////////// //SPI send data /////////////////////////////////////////////////////////////////////////////////////////////////////// assign miso = spi_dout[31]; /////////////////////////////////////////////////////////////////////////////////////////////////////// //SPI output enable /////////////////////////////////////////////////////////////////////////////////////////////////////// sirv_gnrl_dffrs #(1) oen_dffr (~(state_c == READ), oen, clk, rst_n); endmodule