URL
https://opencores.org/ocsvn/yifive/yifive/trunk
Subversion Repositories yifive
[/] [yifive/] [trunk/] [caravel_yifive/] [verilog/] [rtl/] [spi_master/] [src/] [spim_ctrl.sv] - Rev 18
Go to most recent revision | Compare with Previous | Blame | View Log
////////////////////////////////////////////////////////////////////////// //////// SPI CTRL I/F Module //////// //////// This file is part of the YIFive cores project //////// http://www.opencores.org/cores/yifive/ //////// //////// Description //////// //////// To Do: //////// nothing //////// //////// Author(s): //////// - Dinesh Annayya, dinesha@opencores.org //////// //////// Revision : //////// V.0 - June 8, 2021 //////// ////////////////////////////////////////////////////////////////////////////// //////// 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 spim_ctrl(input logic clk,input logic rstn,output logic eot,input logic [7:0] spi_clk_div,input logic spi_clk_div_valid,output logic [7:0] spi_status,input logic spi_req,input logic [31:0] spi_addr,input logic [5:0] spi_addr_len,input logic [7:0] spi_cmd,input logic [5:0] spi_cmd_len,input logic [7:0] spi_mode_cmd,input logic spi_mode_cmd_enb,input logic [3:0] spi_csreg,input logic [15:0] spi_data_len,input logic [15:0] spi_dummy_rd_len,input logic [15:0] spi_dummy_wr_len,input logic spi_swrst, //FIXME Not used at allinput logic spi_rd,input logic spi_wr,input logic spi_qrd,input logic spi_qwr,input logic [31:0] spi_wdata,output logic [31:0] spi_rdata,output logic spi_ack,output logic spi_clk,output logic spi_csn0,output logic spi_csn1,output logic spi_csn2,output logic spi_csn3,output logic [1:0] spi_mode,output logic spi_sdo0,output logic spi_sdo1,output logic spi_sdo2,output logic spi_sdo3,input logic spi_sdi0,input logic spi_sdi1,input logic spi_sdi2,input logic spi_sdi3,output logic spi_en_tx // Spi Direction control);parameter SPI_STD = 2'b00;parameter SPI_QUAD_TX = 2'b01;parameter SPI_QUAD_RX = 2'b10;logic spi_rise;logic spi_fall;logic spi_clock_en;logic spi_en_rx;logic [15:0] counter_tx;logic counter_tx_valid;logic [15:0] counter_rx;logic counter_rx_valid;logic [31:0] data_to_tx;logic data_to_tx_valid;logic data_to_tx_ready;logic en_quad;logic en_quad_int;logic do_tx; //FIXME NOT USED at all!!logic do_rx;logic tx_done;logic rx_done;logic [1:0] s_spi_mode;logic ctrl_data_valid;logic spi_cs;logic tx_clk_en;logic rx_clk_en;logic en_quad_in;enum logic [2:0] {DATA_NULL,DATA_EMPTY,DATA_CMD,DATA_ADDR,DATA_MODE,DATA_FIFO} ctrl_data_mux;enum logic [4:0] {IDLE,CMD,ADDR,MODE,DUMMY,DATA_TX,DATA_RX,WAIT_EDGE} state,state_next;assign en_quad = spi_qrd | spi_qwr | en_quad_int;assign en_quad_in = (s_spi_mode == SPI_STD) ? 1'b0 : 1'b1;spim_clkgen u_clkgen(.clk ( clk ),.rstn ( rstn ),.en ( spi_clock_en ),.cfg_sck_period( spi_clk_div ),.spi_clk ( spi_clk ),.spi_fall ( spi_fall ),.spi_rise ( spi_rise ));spim_tx u_txreg(.clk ( clk ),.rstn ( rstn ),.en ( spi_en_tx ),.tx_edge ( spi_fall ),.tx_done ( tx_done ),.sdo0 ( spi_sdo0 ),.sdo1 ( spi_sdo1 ),.sdo2 ( spi_sdo2 ),.sdo3 ( spi_sdo3 ),.en_quad_in ( en_quad_in ),.counter_in ( counter_tx ),.txdata ( data_to_tx ),.data_valid ( data_to_tx_valid ),.data_ready ( ),.clk_en_o ( tx_clk_en ));spim_rx u_rxreg(.clk ( clk ),.rstn ( rstn ),.en ( spi_en_rx ),.rx_edge ( spi_rise ),.rx_done ( rx_done ),.sdi0 ( spi_sdi0 ),.sdi1 ( spi_sdi1 ),.sdi2 ( spi_sdi2 ),.sdi3 ( spi_sdi3 ),.en_quad_in ( en_quad_in ),.counter_in ( counter_rx ),.counter_in_upd ( counter_rx_valid ),.data ( spi_rdata ),.data_valid ( ),.data_ready ( 1'b1 ),.clk_en_o ( rx_clk_en ));always_combbegindata_to_tx = 'h0;data_to_tx_valid = 1'b0;case(ctrl_data_mux)DATA_NULL:begindata_to_tx = '0;data_to_tx_valid = 1'b0;endDATA_EMPTY:begindata_to_tx = '0;data_to_tx_valid = 1'b1;endDATA_CMD:begindata_to_tx = {spi_cmd,24'h0};data_to_tx_valid = ctrl_data_valid;endDATA_MODE:begindata_to_tx = {spi_mode_cmd,24'h0};data_to_tx_valid = ctrl_data_valid;endDATA_ADDR:begindata_to_tx = spi_addr;data_to_tx_valid = ctrl_data_valid;endDATA_FIFO:begindata_to_tx = spi_wdata;data_to_tx_valid = ctrl_data_valid;endendcaseendalways_combbeginspi_cs = 1'b1;spi_clock_en = 1'b0;counter_tx = '0;counter_tx_valid = 1'b0;counter_rx = '0;counter_rx_valid = 1'b0;state_next = state;ctrl_data_mux = DATA_NULL;ctrl_data_valid = 1'b0;spi_en_rx = 1'b0;spi_en_tx = 1'b0;spi_status = '0;s_spi_mode = SPI_QUAD_RX;eot = 1'b0;case(state)IDLE:beginspi_status[0] = 1'b1;s_spi_mode = SPI_QUAD_RX;if (spi_req)beginspi_cs = 1'b0;spi_clock_en = 1'b1;if (spi_cmd_len != 0)begin// s_spi_mode = (spi_qrd | spi_qwr) ? `SPI_QUAD_TX : `SPI_STD;s_spi_mode = SPI_STD; // COMMAND is always Standard Mode ?counter_tx = {8'h0,spi_cmd_len};counter_tx_valid = 1'b1;ctrl_data_mux = DATA_CMD;ctrl_data_valid = 1'b1;spi_en_tx = 1'b1;state_next = CMD;endelse if (spi_addr_len != 0)begins_spi_mode = (spi_qrd | spi_qwr) ? SPI_QUAD_TX : SPI_STD;counter_tx = {8'h0,spi_addr_len};counter_tx_valid = 1'b1;ctrl_data_mux = DATA_ADDR;ctrl_data_valid = 1'b1;spi_en_tx = 1'b1;state_next = ADDR;endelse if (spi_mode_cmd_enb != 0)begins_spi_mode = (spi_qrd | spi_qwr) ? SPI_QUAD_TX : SPI_STD;counter_tx = {8'h0,8'h8};counter_tx_valid = 1'b1;ctrl_data_mux = DATA_MODE;ctrl_data_valid = 1'b1;spi_en_tx = 1'b1;state_next = MODE;endelse if (spi_data_len != 0)beginif (spi_rd || spi_qrd)begins_spi_mode = (spi_qrd) ? SPI_QUAD_RX : SPI_STD;if(spi_dummy_rd_len != 0)begincounter_tx = en_quad ? {2'b00,spi_dummy_rd_len[13:0]} : spi_dummy_rd_len;counter_tx_valid = 1'b1;spi_en_tx = 1'b1;ctrl_data_mux = DATA_EMPTY;state_next = DUMMY;endelsebegincounter_rx = spi_data_len;counter_rx_valid = 1'b1;spi_en_rx = 1'b1;state_next = DATA_RX;endendelsebegins_spi_mode = (spi_qwr) ? SPI_QUAD_TX : SPI_STD;if(spi_dummy_wr_len != 0)begincounter_tx = en_quad ? {2'b00,spi_dummy_wr_len[13:0]} : spi_dummy_wr_len;counter_tx_valid = 1'b1;ctrl_data_mux = DATA_EMPTY;spi_en_tx = 1'b1;state_next = DUMMY;endelsebegincounter_tx = spi_data_len;counter_tx_valid = 1'b1;ctrl_data_mux = DATA_FIFO;ctrl_data_valid = 1'b0;spi_en_tx = 1'b1;state_next = DATA_TX;endendendendelsebeginspi_cs = 1'b1;state_next = IDLE;endendCMD:beginspi_status[1] = 1'b1;spi_cs = 1'b0;spi_clock_en = 1'b1;// s_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;s_spi_mode = SPI_STD; // Command is always Standard Mode ?if (tx_done)beginif (spi_addr_len != 0)begins_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;counter_tx = {8'h0,spi_addr_len};counter_tx_valid = 1'b1;ctrl_data_mux = DATA_ADDR;ctrl_data_valid = 1'b1;spi_en_tx = 1'b1;state_next = ADDR;endelse if (spi_mode_cmd_enb != 0)begins_spi_mode = (spi_qrd | spi_qwr) ? SPI_QUAD_TX : SPI_STD;counter_tx = {8'h0,8'h8};counter_tx_valid = 1'b1;ctrl_data_mux = DATA_MODE;ctrl_data_valid = 1'b1;spi_en_tx = 1'b1;state_next = MODE;endelse if (spi_data_len != 0)beginif (do_rx)begins_spi_mode = (en_quad) ? SPI_QUAD_RX : SPI_STD;if(spi_dummy_rd_len != 0)begincounter_tx = en_quad ? {2'b00,spi_dummy_rd_len[13:0]} : spi_dummy_rd_len;counter_tx_valid = 1'b1;spi_en_tx = 1'b1;ctrl_data_mux = DATA_EMPTY;state_next = DUMMY;endelsebegincounter_rx = spi_data_len;counter_rx_valid = 1'b1;spi_en_rx = 1'b1;state_next = DATA_RX;endendelsebegins_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;if(spi_dummy_wr_len != 0)begincounter_tx = en_quad ? {2'b00,spi_dummy_wr_len[13:0]} : spi_dummy_wr_len;counter_tx_valid = 1'b1;ctrl_data_mux = DATA_EMPTY;spi_en_tx = 1'b1;state_next = DUMMY;endelsebegincounter_tx = spi_data_len;counter_tx_valid = 1'b1;ctrl_data_mux = DATA_FIFO;ctrl_data_valid = 1'b1;spi_en_tx = 1'b1;state_next = DATA_TX;endendendelsebeginspi_en_tx = 1'b1;state_next = WAIT_EDGE;endendelsebeginspi_en_tx = 1'b1;state_next = CMD;endendADDR:beginspi_en_tx = 1'b1;spi_status[2] = 1'b1;spi_cs = 1'b0;spi_clock_en = 1'b1;s_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;if (tx_done)beginif (spi_mode_cmd_enb != 0)begins_spi_mode = (spi_qrd | spi_qwr) ? SPI_QUAD_TX : SPI_STD;counter_tx = {8'h0,8'h8};counter_tx_valid = 1'b1;ctrl_data_mux = DATA_MODE;ctrl_data_valid = 1'b1;spi_en_tx = 1'b1;state_next = MODE;endelse if (spi_data_len != 0)beginif (do_rx)begins_spi_mode = (en_quad) ? SPI_QUAD_RX : SPI_STD;if(spi_dummy_rd_len != 0)begincounter_tx = en_quad ? {2'b00,spi_dummy_rd_len[13:0]} : spi_dummy_rd_len;counter_tx_valid = 1'b1;spi_en_tx = 1'b1;ctrl_data_mux = DATA_EMPTY;state_next = DUMMY;endelsebegincounter_rx = spi_data_len;counter_rx_valid = 1'b1;spi_en_rx = 1'b1;state_next = DATA_RX;endendelsebegins_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;spi_en_tx = 1'b1;if(spi_dummy_wr_len != 0) begincounter_tx = en_quad ? {2'b00,spi_dummy_wr_len[13:0]} : spi_dummy_wr_len;counter_tx_valid = 1'b1;ctrl_data_mux = DATA_EMPTY;state_next = DUMMY;end else begincounter_tx = spi_data_len;counter_tx_valid = 1'b1;ctrl_data_mux = DATA_FIFO;ctrl_data_valid = 1'b1;state_next = DATA_TX;endendendelsebeginstate_next = WAIT_EDGE;endendendMODE:beginspi_en_tx = 1'b1;spi_status[3] = 1'b1;spi_cs = 1'b0;spi_clock_en = 1'b1;s_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;if (tx_done)beginif (spi_data_len != 0)beginif (do_rx)begins_spi_mode = (en_quad) ? SPI_QUAD_RX : SPI_STD;if(spi_dummy_rd_len != 0)begincounter_tx = en_quad ? {2'b00,spi_dummy_rd_len[13:0]} : spi_dummy_rd_len;counter_tx_valid = 1'b1;spi_en_tx = 1'b1;ctrl_data_mux = DATA_EMPTY;state_next = DUMMY;endelsebegincounter_rx = spi_data_len;counter_rx_valid = 1'b1;spi_en_rx = 1'b1;state_next = DATA_RX;endendelsebegins_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;spi_en_tx = 1'b1;if(spi_dummy_wr_len != 0) begincounter_tx = en_quad ? {2'b00,spi_dummy_wr_len[13:0]} : spi_dummy_wr_len;counter_tx_valid = 1'b1;ctrl_data_mux = DATA_EMPTY;state_next = DUMMY;end else begincounter_tx = spi_data_len;counter_tx_valid = 1'b1;ctrl_data_mux = DATA_FIFO;ctrl_data_valid = 1'b1;state_next = DATA_TX;endendendelsebeginstate_next = WAIT_EDGE;endendendDUMMY:beginspi_en_tx = 1'b1;spi_status[4] = 1'b1;spi_cs = 1'b0;spi_clock_en = 1'b1;s_spi_mode = (en_quad) ? SPI_QUAD_RX : SPI_STD;if (tx_done) beginif (spi_data_len != 0) beginif (do_rx) begincounter_rx = spi_data_len;counter_rx_valid = 1'b1;spi_en_rx = 1'b1;state_next = DATA_RX;end else begincounter_tx = spi_data_len;counter_tx_valid = 1'b1;s_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;spi_clock_en = tx_clk_en;spi_en_tx = 1'b1;state_next = DATA_TX;endendelsebegineot = 1'b1;state_next = WAIT_EDGE;endendelsebeginctrl_data_mux = DATA_EMPTY;spi_en_tx = 1'b1;state_next = DUMMY;endendDATA_TX:beginspi_status[5] = 1'b1;spi_cs = 1'b0;spi_clock_en = tx_clk_en;ctrl_data_mux = DATA_FIFO;ctrl_data_valid = 1'b1;spi_en_tx = 1'b1;s_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;if (tx_done) begineot = 1'b1;state_next = WAIT_EDGE;spi_clock_en = 1'b0;end else beginstate_next = DATA_TX;endendDATA_RX:beginspi_status[6] = 1'b1;spi_cs = 1'b0;spi_clock_en = rx_clk_en;s_spi_mode = (en_quad) ? SPI_QUAD_RX : SPI_STD;if (rx_done) beginstate_next = WAIT_EDGE;end else beginspi_en_rx = 1'b1;state_next = DATA_RX;endendWAIT_EDGE:beginspi_status[7] = 1'b1;spi_cs = 1'b0;spi_clock_en = 1'b0;s_spi_mode = (en_quad) ? SPI_QUAD_RX : SPI_STD;eot = 1'b1;state_next = IDLE;endendcaseendassign spi_ack = ((spi_req ==1) && (state_next == WAIT_EDGE)) ? 1'b1 : 1'b0;always_ff @(posedge clk, negedge rstn)beginif (rstn == 1'b0)beginstate <= IDLE;en_quad_int <= 1'b0;do_rx <= 1'b0;do_tx <= 1'b0;spi_mode <= SPI_QUAD_RX;endelsebeginstate <= state_next;spi_mode <= s_spi_mode;if (spi_qrd || spi_qwr)en_quad_int <= 1'b1;else if (state_next == IDLE)en_quad_int <= 1'b0;if (spi_rd || spi_qrd)begindo_rx <= 1'b1;do_tx <= 1'b0;endelse if (spi_wr || spi_qwr)begindo_rx <= 1'b0;do_tx <= 1'b1;endelse if (state_next == IDLE)begindo_rx <= 1'b0;do_tx <= 1'b0;endendendassign spi_csn0 = ~spi_csreg[0] | spi_cs;assign spi_csn1 = ~spi_csreg[1] | spi_cs;assign spi_csn2 = ~spi_csreg[2] | spi_cs;assign spi_csn3 = ~spi_csreg[3] | spi_cs;endmodule
Go to most recent revision | Compare with Previous | Blame | View Log
