| ////////////////////////////////////////////////////////////////////// | |
| //// //// | |
| //// Single SPI Master Interface Module //// | |
| //// //// | |
| //// This file is part of the riscduino cores project //// | |
| //// https://github.com/dineshannayya/riscduino.git //// | |
| //// //// | |
| //// Description //// | |
| //// SPI Control module //// | |
| //// //// | |
| //// To Do: //// | |
| //// nothing //// | |
| //// //// | |
| //// Author(s): //// | |
| //// - Dinesh Annayya, dinesha@opencores.org //// | |
| //// //// | |
| //// Revision : //// | |
| //// V.0 - 06 Oct 2021 //// | |
| //// Initial SpI Module picked from //// | |
| //// http://www.opencores.org/cores/turbo8051/ //// | |
| //// //// | |
| ////////////////////////////////////////////////////////////////////// | |
| //// //// | |
| //// Copyright (C) 2000 Authors and OPENCORES.ORG //// | |
| //// //// | |
| //// This source file may be used and distributed without //// | |
| //// restriction provided that this copyright statement is not //// | |
| //// removed from the file and that any derivative work contains //// | |
| //// the original copyright notice and the associated disclaimer. //// | |
| //// //// | |
| //// This source file is free software; you can redistribute it //// | |
| //// and/or modify it under the terms of the GNU Lesser General //// | |
| //// Public License as published by the Free Software Foundation; //// | |
| //// either version 2.1 of the License, or (at your option) any //// | |
| //// later version. //// | |
| //// //// | |
| //// This source is distributed in the hope that it will be //// | |
| //// useful, but WITHOUT ANY WARRANTY; without even the implied //// | |
| //// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// | |
| //// PURPOSE. See the GNU Lesser General Public License for more //// | |
| //// details. //// | |
| //// //// | |
| //// You should have received a copy of the GNU Lesser General //// | |
| //// Public License along with this source; if not, download it //// | |
| //// from http://www.opencores.org/lgpl.shtml //// | |
| //// //// | |
| ////////////////////////////////////////////////////////////////////// | |
| module sspim_ctl | |
| ( | |
| input logic clk, | |
| input logic reset_n, | |
| input logic cfg_cpol, | |
| input logic cfg_op_req, | |
| input logic cfg_endian, | |
| input logic [1:0] cfg_op_type, | |
| input logic [1:0] cfg_transfer_size, | |
| input logic [4:0] cfg_sck_cs_period, | |
| input logic [7:0] cfg_cs_byte, | |
| input logic [31:0] cfg_datain, | |
| output logic [31:0] cfg_dataout, | |
| output logic [7:0] byte_out, // Byte out for Serial Shifting out | |
| input logic [7:0] byte_in, // Serial Received Byte | |
| output logic cs_int_n, | |
| input logic shift, | |
| input logic sample, | |
| output logic sck_active, | |
| output logic load_byte, | |
| output logic op_done | |
| ); | |
| //************************************************************************* | |
| parameter LITTLE_ENDIAN = 1'b0; | |
| parameter BIG_ENDIAN = 1'b1; | |
| parameter SPI_WR = 2'b00; | |
| parameter SPI_RD = 2'b01; | |
| parameter SPI_WR_RD = 2'b10; | |
| logic [5:0] sck_cnt; | |
| logic [3:0] spiif_cs; | |
| logic [2:0] byte_cnt; | |
| `define SPI_IDLE 4'b0000 | |
| `define SPI_CS_SU 4'b0001 | |
| `define SPI_DATA 4'b0010 | |
| `define SPI_CS_HLD 4'b0011 | |
| `define SPI_WAIT 4'b0100 | |
| wire [1:0] cs_data = (byte_cnt == 2'b00) ? cfg_cs_byte[7:6] : | |
| (byte_cnt == 2'b01) ? cfg_cs_byte[5:4] : | |
| (byte_cnt == 2'b10) ? cfg_cs_byte[3:2] : cfg_cs_byte[1:0] ; | |
| assign byte_out = (cfg_endian == LITTLE_ENDIAN) ? | |
| ((byte_cnt == 2'b00) ? cfg_datain[7:0] : | |
| (byte_cnt == 2'b01) ? cfg_datain[15:8] : | |
| (byte_cnt == 2'b10) ? cfg_datain[23:16] : cfg_datain[31:24]) : | |
| ((byte_cnt == 2'b00) ? cfg_datain[31:24] : | |
| (byte_cnt == 2'b01) ? cfg_datain[23:16] : | |
| (byte_cnt == 2'b10) ? cfg_datain[15:8] : cfg_datain[7:0]) ; | |
| always @(posedge clk or negedge reset_n) begin | |
| if(!reset_n) begin | |
| spiif_cs <= `SPI_IDLE; | |
| sck_cnt <= 6'h0; | |
| byte_cnt <= 2'b00; | |
| cs_int_n <= 1'b1; | |
| cfg_dataout <= 32'h0; | |
| load_byte <= 1'b0; | |
| sck_active <= 1'b0; | |
| end | |
| else begin | |
| case(spiif_cs) | |
| `SPI_IDLE : | |
| begin | |
| sck_active <= 1'b0; | |
| load_byte <= 1'b0; | |
| op_done <= 0; | |
| if(cfg_op_req) | |
| begin | |
| cfg_dataout <= 32'h0; | |
| spiif_cs <= `SPI_CS_SU; | |
| end else begin | |
| spiif_cs <= `SPI_IDLE; | |
| end | |
| end | |
| `SPI_CS_SU : | |
| begin | |
| if(shift) begin | |
| cs_int_n <= cs_data[1]; | |
| if(sck_cnt == cfg_sck_cs_period) begin | |
| sck_cnt <= 'h0; | |
| if((cfg_op_type == SPI_WR) || (cfg_op_type == SPI_WR_RD )) begin // Write Mode | |
| load_byte <= 1'b1; | |
| end | |
| spiif_cs <= `SPI_DATA; | |
| end else begin | |
| sck_cnt <= sck_cnt + 1 ; | |
| end | |
| end | |
| end | |
| `SPI_DATA : | |
| begin | |
| load_byte <= 1'b0; | |
| if((shift && (cfg_cpol == 1)) || (sample && (cfg_cpol == 0)) ) begin | |
| sck_active <= 1'b1; | |
| end else if((sample && (cfg_cpol == 1)) || (shift && (cfg_cpol == 0)) ) begin | |
| if(sck_cnt == 4'h8 )begin | |
| sck_active <= 1'b0; | |
| sck_cnt <= 'h0; | |
| spiif_cs <= `SPI_CS_HLD; | |
| end | |
| else begin | |
| sck_active <= 1'b1; | |
| sck_cnt <= sck_cnt + 1 ; | |
| end | |
| end | |
| end | |
| `SPI_CS_HLD : begin | |
| if(shift) begin | |
| cs_int_n <= cs_data[0]; | |
| if(sck_cnt == cfg_sck_cs_period) begin | |
| if((cfg_op_type == SPI_RD) || (cfg_op_type == SPI_WR_RD)) begin // Read Mode | |
| cfg_dataout <= (cfg_endian == LITTLE_ENDIAN) ? | |
| ((byte_cnt[1:0] == 2'b00) ? { cfg_dataout[31:8],byte_in } : | |
| (byte_cnt[1:0] == 2'b01) ? { cfg_dataout[31:16], byte_in, cfg_dataout[7:0] } : | |
| (byte_cnt[1:0] == 2'b10) ? { cfg_dataout[31:24], byte_in, cfg_dataout[15:0] } : | |
| { byte_in,cfg_dataout[23:0]}) : | |
| ((byte_cnt[1:0] == 2'b00) ? { byte_in,cfg_dataout[23:0] } : | |
| (byte_cnt[1:0] == 2'b01) ? { cfg_dataout[31:24], byte_in, cfg_dataout[15:0] } : | |
| (byte_cnt[1:0] == 2'b10) ? { cfg_dataout[31:16], byte_in, cfg_dataout[7:0] } : | |
| { cfg_dataout[31:8],byte_in}) ; | |
| end | |
| sck_cnt <= 'h0; | |
| if(byte_cnt == cfg_transfer_size) begin | |
| spiif_cs <= `SPI_WAIT; | |
| byte_cnt <= 0; | |
| op_done <= 1; | |
| end else begin | |
| byte_cnt <= byte_cnt +1; | |
| spiif_cs <= `SPI_CS_SU; | |
| end | |
| end | |
| else begin | |
| sck_cnt <= sck_cnt + 1 ; | |
| end | |
| end | |
| end // case: `SPI_CS_HLD | |
| `SPI_WAIT : begin | |
| if(!cfg_op_req) // Wait for Request de-assertion | |
| spiif_cs <= `SPI_IDLE; | |
| end | |
| endcase // casex(spiif_cs) | |
| end | |
| end // always @(sck_ne | |
| endmodule |