spi master added
diff --git a/openlane/spi_master/config.tcl b/openlane/spi_master/config.tcl
new file mode 100755
index 0000000..b69e7cf
--- /dev/null
+++ b/openlane/spi_master/config.tcl
@@ -0,0 +1,118 @@
+# Global
+# ------
+
+set script_dir [file dirname [file normalize [info script]]]
+# Name
+set ::env(DESIGN_NAME) spim_top
+
+# This is macro
+set ::env(DESIGN_IS_CORE) 0
+
+# Diode insertion
+ # Spray
+set ::env(DIODE_INSERTION_STRATEGY) 0
+
+ # Smart-"ish"
+#set ::env(DIODE_INSERTION_STRATEGY) 3
+#set ::env(GLB_RT_MAX_DIODE_INS_ITERS) 10
+
+# Timing configuration
+set ::env(CLOCK_PERIOD) "10"
+set ::env(CLOCK_PORT) "mclk"
+
+
+# Sources
+# -------
+
+# Local sources + no2usb sources
+set ::env(VERILOG_FILES) "\
+ $script_dir/../../verilog/rtl/spi_master/src/spim_top.sv \
+ $script_dir/../../verilog/rtl/spi_master/src/spim_regs.sv \
+ $script_dir/../../verilog/rtl/spi_master/src/spim_clkgen.sv \
+ $script_dir/../../verilog/rtl/spi_master/src/spim_ctrl.sv \
+ $script_dir/../../verilog/rtl/spi_master/src/spim_rx.sv \
+ $script_dir/../../verilog/rtl/spi_master/src/spim_tx.sv "
+
+#set ::env(VERILOG_INCLUDE_DIRS) [glob $script_dir/../../verilog/rtl/syntacore/scr1/src/includes ]
+
+#set ::env(SYNTH_DEFINES) [list SCR1_DBG_EN ]
+
+
+# Need blackbox for cells
+set ::env(SYNTH_READ_BLACKBOX_LIB) 0
+
+
+# Floorplanning
+# -------------
+
+# Fixed area and pin position
+set ::env(FP_SIZING) "absolute"
+#actual die area is 0 0 2920 3520, given 500 micron extra margin
+set ::env(DIE_AREA) [list 0.0 0.0 300.0 300.0]
+set ::env(FP_PIN_ORDER_CFG) $::env(DESIGN_DIR)/pin_order.cfg
+
+# Halo around the Macros
+set ::env(FP_HORIZONTAL_HALO) 25
+set ::env(FP_VERTICAL_HALO) 20
+
+#set ::env(PDN_CFG) $::env(DESIGN_DIR)/pdn.tcl
+
+
+
+# Placement
+# ---------
+
+set ::env(PL_TARGET_DENSITY) 0.40
+
+#set ::env(MACRO_PLACEMENT_CFG) $::env(DESIGN_DIR)/macro_placement.cfg
+
+
+# Routing
+# -------
+
+#| `ROUTING_CORES` | Specifies the number of threads to be used in TritonRoute. <br> (Default: `4`) |
+set ::env(ROUTING_CORES) 4
+
+#| `GLB_RT_ALLOW_CONGESTION` | Allow congestion in the resultign guides. 0 = false, 1 = true <br> (Default: `0`) |
+set ::env(GLB_RT_ALLOW_CONGESTION) 0
+
+# | `GLB_RT_MINLAYER` | The number of lowest layer to be used in routing. <br> (Default: `1`)|
+set ::env(GLB_RT_MINLAYER) 1
+
+# | `GLB_RT_MAXLAYER` | The number of highest layer to be used in routing. <br> (Default: `6`)|
+set ::env(GLB_RT_MAXLAYER) 6
+
+# Obstructions
+ # li1 over the SRAM areas
+ # met5 over the whole design
+#set ::env(GLB_RT_OBS) "li1 0.00 22.68 1748.00 486.24, li1 0.00 851.08 1748.00 486.24, met5 0.0 0.0 1748.0 1360.0"
+
+#| `ROUTING_OPT_ITERS` | Specifies the maximum number of optimization iterations during Detailed Routing in TritonRoute. <br> (Default: `64`) |
+set ::env(ROUTING_OPT_ITERS) "64"
+
+#| `GLOBAL_ROUTER` | Specifies which global router to use. Values: `fastroute` or `cugr`. <br> (Default: `fastroute`) |
+set ::env(GLOBAL_ROUTER) "fastroute"
+
+#| `DETAILED_ROUTER` | Specifies which detailed router to use. Values: `tritonroute`, `tritonroute_or`, or `drcu`. <br> (Default: `tritonroute`) |
+set ::env(DETAILED_ROUTER) "tritonroute"
+
+# DRC
+# ---
+
+
+set ::env(MAGIC_DRC_USE_GDS) 1
+
+
+# Tape Out
+# --------
+
+set ::env(MAGIC_ZEROIZE_ORIGIN) 0
+
+
+# Cell library specific config
+# ----------------------------
+
+set filename $::env(DESIGN_DIR)/$::env(PDK)_$::env(STD_CELL_LIBRARY)_config.tcl
+if { [file exists $filename] == 1} {
+ source $filename
+}
diff --git a/openlane/spi_master/pin_order.cfg b/openlane/spi_master/pin_order.cfg
new file mode 100644
index 0000000..9691d54
--- /dev/null
+++ b/openlane/spi_master/pin_order.cfg
@@ -0,0 +1,36 @@
+#BUS_SORT
+
+#E
+mclk
+rst_n
+events_o.*
+
+
+#N
+spi_mode.*
+spi_clk
+spi_csn0
+spi_csn1
+spi_csn2
+spi_csn3
+spi_en_tx
+spi_sdi0
+spi_sdi1
+spi_sdi2
+spi_sdi3
+spi_sdo0
+spi_sdo1
+spi_sdo2
+spi_sdo3
+
+
+#N
+wbd_ack_o
+wbd_err_o
+wbd_stb_i
+wbd_we_i
+wbd_adr_i.*
+wbd_dat_i.*
+wbd_dat_o.*
+wbd_sel_i.*
+
diff --git a/openlane/syntacore/config.tcl b/openlane/syntacore/config.tcl
index f1d6458..766f736 100755
--- a/openlane/syntacore/config.tcl
+++ b/openlane/syntacore/config.tcl
@@ -3,7 +3,7 @@
set script_dir [file dirname [file normalize [info script]]]
# Name
-set ::env(DESIGN_NAME) scr1_top_axi
+set ::env(DESIGN_NAME) scr1_top_wb
# This is macro
set ::env(DESIGN_IS_CORE) 0
@@ -26,34 +26,36 @@
# Local sources + no2usb sources
set ::env(VERILOG_FILES) "\
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_top.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/scr1_core_top.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/scr1_dm.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/scr1_tapc_synchronizer.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/scr1_clk_ctrl.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/scr1_scu.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/scr1_tapc.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/scr1_tapc_shift_reg.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/scr1_dmi.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/primitives/scr1_reset_cells.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_ifu.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_idu.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_exu.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_mprf.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_csr.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_ialu.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_lsu.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_hdu.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_pipe_tdu.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/core/pipeline/scr1_ipic.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/top/scr1_dmem_router.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/top/scr1_imem_router.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/top/scr1_tcm.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/top/scr1_timer.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/top/scr1_top_axi.sv \
- $script_dir/../../verilog/rtl/syntacore_scr1/src/top/scr1_mem_axi.sv "
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_top.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/scr1_core_top.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/scr1_dm.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/scr1_tapc_synchronizer.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/scr1_clk_ctrl.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/scr1_scu.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/scr1_tapc.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/scr1_tapc_shift_reg.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/scr1_dmi.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/primitives/scr1_reset_cells.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_ifu.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_idu.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_exu.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_mprf.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_csr.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_ialu.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_lsu.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_hdu.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_pipe_tdu.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/core/pipeline/scr1_ipic.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/top/scr1_dmem_router.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/top/scr1_imem_router.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/top/scr1_tcm.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/top/scr1_timer.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/top/scr1_top_wb.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/top/scr1_dmem_wb.sv \
+ $script_dir/../../verilog/rtl/syntacore/scr1/src/top/scr1_imem_wb.sv \
+ $script_dir/../../verilog/rtl/lib/sync_fifo.sv "
-set ::env(VERILOG_INCLUDE_DIRS) [glob $script_dir/../../verilog/rtl/syntacore_scr1/src/includes ]
+set ::env(VERILOG_INCLUDE_DIRS) [glob $script_dir/../../verilog/rtl/syntacore/scr1/src/includes ]
#set ::env(SYNTH_DEFINES) [list SCR1_DBG_EN ]
diff --git a/verilog/rtl/lib/sync_fifo.sv b/verilog/rtl/lib/sync_fifo.sv
index 0eeb134..fb934a2 100644
--- a/verilog/rtl/lib/sync_fifo.sv
+++ b/verilog/rtl/lib/sync_fifo.sv
@@ -60,14 +60,13 @@
);
-reg [DATA_WIDTH-1:0] ram [FIFO_DEPTH-1:0];
+reg [DATA_WIDTH-1:0] ram [FIFO_DEPTH-1:0];
reg [ADDR_WIDTH-1:0] wptr; // write ptr
reg [ADDR_WIDTH-1:0] rptr; // write ptr
reg [ADDR_WIDTH:0] status_cnt; // status counter
+reg empty;
+reg full;
- //-----------Variable assignments---------------
- assign full = (status_cnt == FIFO_DEPTH);
- assign empty = (status_cnt == 0);
//-----------Code Start---------------------------
always @ (negedge rstn or posedge clk)
@@ -101,7 +100,37 @@
end
end
+// underflow is not handled
+always @ (negedge rstn or posedge clk)
+begin : EMPTY_FLAG
+ if (rstn==1'b0) begin
+ empty <= 1;
+ // Read but no write.
+ end else if (rd_en && (!wr_en) && (status_cnt == 1)) begin
+ empty <= 1;
+ // Write
+ end else if (wr_en) begin
+ empty <= 0;
+ end else if (status_cnt == 0) begin
+ empty <= 1;
+ end
+end
+// overflow is not handled
+always @ (negedge rstn or posedge clk)
+begin : FULL_FLAG
+ if (rstn==1'b0) begin
+ full <= 0;
+ // Write but no read.
+ end else if (wr_en && (!rd_en) && (status_cnt == (FIFO_DEPTH-1))) begin
+ full <= 1;
+ // Read
+ end else if (rd_en && (!wr_en) ) begin
+ full <= 0;
+ end else if (status_cnt == FIFO_DEPTH) begin
+ full <= 1;
+ end
+end
assign dout = ram[rptr];
always @ (posedge clk)
diff --git a/verilog/rtl/spi_master/src/filelist.f b/verilog/rtl/spi_master/src/filelist.f
new file mode 100644
index 0000000..6b47b62
--- /dev/null
+++ b/verilog/rtl/spi_master/src/filelist.f
@@ -0,0 +1,6 @@
+spim_top.sv
+spim_regs.sv
+spim_clkgen.sv
+spim_ctrl.sv
+spim_rx.sv
+spim_tx.sv
diff --git a/verilog/rtl/spi_master/src/spim_clkgen.sv b/verilog/rtl/spi_master/src/spim_clkgen.sv
new file mode 100644
index 0000000..022b300
--- /dev/null
+++ b/verilog/rtl/spi_master/src/spim_clkgen.sv
@@ -0,0 +1,116 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// SPI Clkgen Module ////
+//// ////
+//// This file is part of the YIFive cores project ////
+//// http://www.opencores.org/cores/yifive/ ////
+//// ////
+//// Description ////
+//// This is SPI Master Clock Generation control logic. ////
+//// This logic also generate spi clock rise and fall pulse ////
+//// Basis assumption is master clock is 2x time spi clock ////
+//// 1. spi fall pulse is used to transmit spi data ////
+//// 2. spi rise pulse is used to received spi data ////
+//// SPI Master Top module ////
+//// ////
+//// To Do: ////
+//// nothing ////
+//// ////
+//// Author(s): ////
+//// - Dinesh Annayya, dinesha@opencores.org ////
+//// ////
+//// Revision: ////
+//// 0.1 - 16th Feb 2021, Dinesh A ////
+//// Initial version ////
+//// 0.2 - 24th Mar 2021, Dinesh A ////
+//// 1. Comments are added ////
+//// 2. RTL clean-up done and the output are registred ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// 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_clkgen
+(
+ input logic clk,
+ input logic rstn,
+ input logic en,
+ input logic [7:0] cfg_sck_period,
+ output logic spi_clk,
+ output logic spi_fall,
+ output logic spi_rise
+);
+
+ logic [7:0] sck_half_period;
+ logic [7:0] clk_cnt;
+
+ assign sck_half_period = {1'b0, cfg_sck_period[7:1]};
+
+ // The first transition on the sck_toggle happens one SCK period
+ // after en is asserted
+ always @(posedge clk or negedge rstn) begin
+ if(!rstn) begin
+ clk_cnt <= 'h1;
+ spi_clk <= 1'b1;
+ spi_fall <= 1'b0;
+ spi_rise <= 1'b0;
+ end // if (!reset_n)
+ else
+ begin
+ if(en)
+ begin
+ if(clk_cnt == sck_half_period)
+ begin
+ spi_clk <= 1'b0;
+ spi_fall <= 1'b1;
+ spi_rise <= 1'b0;
+ clk_cnt <= clk_cnt + 1'b1;
+ end // if (clk_cnt == sck_half_period)
+ else begin
+ if(clk_cnt == cfg_sck_period)
+ begin
+ spi_clk <= 1'b1;
+ spi_fall <= 1'b0;
+ spi_rise <= 1'b1;
+ clk_cnt <= 'h1;
+ end // if (clk_cnt == cfg_sck_period)
+ else
+ begin
+ clk_cnt <= clk_cnt + 1'b1;
+ spi_fall <= 1'b0;
+ spi_rise <= 1'b0;
+ end // else: !if(clk_cnt == cfg_sck_period)
+ end // else: !if(clk_cnt == sck_half_period)
+ end // if (en)
+ else begin
+ clk_cnt <= 'h1;
+ spi_fall <= 1'b0;
+ spi_rise <= 1'b0;
+ end // else: !if(en)
+ end // else: !if(!reset_n)
+ end // always @ (posedge clk or negedge reset_n)
+
+endmodule
diff --git a/verilog/rtl/spi_master/src/spim_ctrl.sv b/verilog/rtl/spi_master/src/spim_ctrl.sv
new file mode 100644
index 0000000..20d2515
--- /dev/null
+++ b/verilog/rtl/spi_master/src/spim_ctrl.sv
@@ -0,0 +1,684 @@
+
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// 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 all
+ input 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_comb
+ begin
+ data_to_tx = 'h0;
+ data_to_tx_valid = 1'b0;
+
+ case(ctrl_data_mux)
+ DATA_NULL:
+ begin
+ data_to_tx = '0;
+ data_to_tx_valid = 1'b0;
+ end
+
+ DATA_EMPTY:
+ begin
+ data_to_tx = '0;
+ data_to_tx_valid = 1'b1;
+ end
+
+ DATA_CMD:
+ begin
+ data_to_tx = {spi_cmd,24'h0};
+ data_to_tx_valid = ctrl_data_valid;
+ end
+ DATA_MODE:
+ begin
+ data_to_tx = {spi_mode_cmd,24'h0};
+ data_to_tx_valid = ctrl_data_valid;
+ end
+
+ DATA_ADDR:
+ begin
+ data_to_tx = spi_addr;
+ data_to_tx_valid = ctrl_data_valid;
+ end
+
+ DATA_FIFO:
+ begin
+ data_to_tx = spi_wdata;
+ data_to_tx_valid = ctrl_data_valid;
+ end
+ endcase
+ end
+
+ always_comb
+ begin
+ spi_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:
+ begin
+ spi_status[0] = 1'b1;
+ s_spi_mode = SPI_QUAD_RX;
+ if (spi_req)
+ begin
+ spi_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;
+ end
+ else if (spi_addr_len != 0)
+ begin
+ s_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;
+ end
+ else if (spi_mode_cmd_enb != 0)
+ begin
+ s_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;
+ end
+ else if (spi_data_len != 0)
+ begin
+ if (spi_rd || spi_qrd)
+ begin
+ s_spi_mode = (spi_qrd) ? SPI_QUAD_RX : SPI_STD;
+ if(spi_dummy_rd_len != 0)
+ begin
+ counter_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;
+ end
+ else
+ begin
+ counter_rx = spi_data_len;
+ counter_rx_valid = 1'b1;
+ spi_en_rx = 1'b1;
+ state_next = DATA_RX;
+ end
+ end
+ else
+ begin
+ s_spi_mode = (spi_qwr) ? SPI_QUAD_TX : SPI_STD;
+ if(spi_dummy_wr_len != 0)
+ begin
+ counter_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;
+ end
+ else
+ begin
+ counter_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;
+ end
+ end
+ end
+ end
+ else
+ begin
+ spi_cs = 1'b1;
+ state_next = IDLE;
+ end
+ end
+
+ CMD:
+ begin
+ spi_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)
+ begin
+ if (spi_addr_len != 0)
+ begin
+ s_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;
+ end
+ else if (spi_mode_cmd_enb != 0)
+ begin
+ s_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;
+ end
+ else if (spi_data_len != 0)
+ begin
+ if (do_rx)
+ begin
+ s_spi_mode = (en_quad) ? SPI_QUAD_RX : SPI_STD;
+ if(spi_dummy_rd_len != 0)
+ begin
+ counter_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;
+ end
+ else
+ begin
+ counter_rx = spi_data_len;
+ counter_rx_valid = 1'b1;
+ spi_en_rx = 1'b1;
+ state_next = DATA_RX;
+ end
+ end
+ else
+ begin
+ s_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;
+ if(spi_dummy_wr_len != 0)
+ begin
+ counter_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;
+ end
+ else
+ begin
+ counter_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;
+ end
+ end
+ end
+ else
+ begin
+ spi_en_tx = 1'b1;
+ state_next = WAIT_EDGE;
+ end
+ end
+ else
+ begin
+ spi_en_tx = 1'b1;
+ state_next = CMD;
+ end
+ end
+
+ ADDR:
+ begin
+ spi_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)
+ begin
+ if (spi_mode_cmd_enb != 0)
+ begin
+ s_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;
+ end
+ else if (spi_data_len != 0)
+ begin
+ if (do_rx)
+ begin
+ s_spi_mode = (en_quad) ? SPI_QUAD_RX : SPI_STD;
+ if(spi_dummy_rd_len != 0)
+ begin
+ counter_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;
+ end
+ else
+ begin
+ counter_rx = spi_data_len;
+ counter_rx_valid = 1'b1;
+ spi_en_rx = 1'b1;
+ state_next = DATA_RX;
+ end
+ end
+ else
+ begin
+ s_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;
+ spi_en_tx = 1'b1;
+
+ if(spi_dummy_wr_len != 0) begin
+ counter_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 begin
+ counter_tx = spi_data_len;
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = DATA_FIFO;
+ ctrl_data_valid = 1'b1;
+ state_next = DATA_TX;
+ end
+ end
+ end
+ else
+ begin
+ state_next = WAIT_EDGE;
+ end
+ end
+ end
+
+ MODE:
+ begin
+ spi_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)
+ begin
+ if (spi_data_len != 0)
+ begin
+ if (do_rx)
+ begin
+ s_spi_mode = (en_quad) ? SPI_QUAD_RX : SPI_STD;
+ if(spi_dummy_rd_len != 0)
+ begin
+ counter_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;
+ end
+ else
+ begin
+ counter_rx = spi_data_len;
+ counter_rx_valid = 1'b1;
+ spi_en_rx = 1'b1;
+ state_next = DATA_RX;
+ end
+ end
+ else
+ begin
+ s_spi_mode = (en_quad) ? SPI_QUAD_TX : SPI_STD;
+ spi_en_tx = 1'b1;
+
+ if(spi_dummy_wr_len != 0) begin
+ counter_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 begin
+ counter_tx = spi_data_len;
+ counter_tx_valid = 1'b1;
+ ctrl_data_mux = DATA_FIFO;
+ ctrl_data_valid = 1'b1;
+ state_next = DATA_TX;
+ end
+ end
+ end
+ else
+ begin
+ state_next = WAIT_EDGE;
+ end
+ end
+ end
+
+ DUMMY:
+ begin
+ spi_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) begin
+ if (spi_data_len != 0) begin
+ if (do_rx) begin
+ counter_rx = spi_data_len;
+ counter_rx_valid = 1'b1;
+ spi_en_rx = 1'b1;
+ state_next = DATA_RX;
+ end else begin
+ counter_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;
+ end
+ end
+ else
+ begin
+ eot = 1'b1;
+ state_next = WAIT_EDGE;
+ end
+ end
+ else
+ begin
+ ctrl_data_mux = DATA_EMPTY;
+ spi_en_tx = 1'b1;
+ state_next = DUMMY;
+ end
+ end
+
+ DATA_TX:
+ begin
+ spi_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) begin
+ eot = 1'b1;
+ state_next = WAIT_EDGE;
+ spi_clock_en = 1'b0;
+ end else begin
+ state_next = DATA_TX;
+ end
+ end
+
+ DATA_RX:
+ begin
+ spi_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) begin
+ state_next = WAIT_EDGE;
+ end else begin
+ spi_en_rx = 1'b1;
+ state_next = DATA_RX;
+ end
+ end
+ WAIT_EDGE:
+ begin
+ spi_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;
+ end
+ endcase
+ end
+
+assign spi_ack = ((spi_req ==1) && (state_next == WAIT_EDGE)) ? 1'b1 : 1'b0;
+
+
+ always_ff @(posedge clk, negedge rstn)
+ begin
+ if (rstn == 1'b0)
+ begin
+ state <= IDLE;
+ en_quad_int <= 1'b0;
+ do_rx <= 1'b0;
+ do_tx <= 1'b0;
+ spi_mode <= SPI_QUAD_RX;
+ end
+ else
+ begin
+ state <= 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)
+ begin
+ do_rx <= 1'b1;
+ do_tx <= 1'b0;
+ end
+ else if (spi_wr || spi_qwr)
+ begin
+ do_rx <= 1'b0;
+ do_tx <= 1'b1;
+ end
+ else if (state_next == IDLE)
+ begin
+ do_rx <= 1'b0;
+ do_tx <= 1'b0;
+ end
+ end
+ end
+
+ assign 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
+
diff --git a/verilog/rtl/spi_master/src/spim_fifo.sv b/verilog/rtl/spi_master/src/spim_fifo.sv
new file mode 100644
index 0000000..e1c665b
--- /dev/null
+++ b/verilog/rtl/spi_master/src/spim_fifo.sv
@@ -0,0 +1,156 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// YiFive cores common library Module ////
+//// ////
+//// This file is part of the YIFive cores project ////
+//// http://www.opencores.org/cores/yifive/ ////
+//// ////
+//// Description ////
+//// Sync Fifo with full and empty ////
+//// ////
+//// To Do: ////
+//// nothing ////
+//// ////
+//// Author(s): ////
+//// - Dinesh Annayya, dinesha@opencores.org ////
+//// ////
+//// Revision : June 7, 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_fifo #(
+ parameter DATA_WIDTH = 32, // Data Width
+ parameter ADDR_WIDTH = 1, // Address Width
+ parameter FIFO_DEPTH = 2 // FIFO DEPTH
+
+)(
+ input rstn,
+ input srst,
+ input clk,
+ input wr_en, // Write
+ input [DATA_WIDTH-1:0] din,
+ output ready_o,
+
+ input rd_en, // Read
+ output [DATA_WIDTH-1:0] dout,
+ output valid_o
+);
+
+
+reg [DATA_WIDTH-1:0] ram [FIFO_DEPTH-1:0];
+reg [ADDR_WIDTH-1:0] wptr; // write ptr
+reg [ADDR_WIDTH-1:0] rptr; // write ptr
+reg [ADDR_WIDTH:0] status_cnt; // status counter
+reg empty;
+reg full;
+
+ wire ready_o = ! full;
+ wire valid_o = ! empty;
+
+ //-----------Code Start---------------------------
+ always @ (negedge rstn or posedge clk)
+ begin : WRITE_POINTER
+ if (rstn==1'b0) begin
+ wptr <= 0;
+ end else if (srst ) begin
+ wptr <= 0;
+ end else if (wr_en ) begin
+ wptr <= wptr + 1;
+ end
+ end
+
+always @ (negedge rstn or posedge clk)
+begin : READ_POINTER
+ if (rstn==1'b0) begin
+ rptr <= 0;
+ end else if (srst ) begin
+ rptr <= 0;
+ end else if (rd_en) begin
+ rptr <= rptr + 1;
+ end
+end
+
+always @ (negedge rstn or posedge clk)
+begin : STATUS_COUNTER
+ if (rstn==1'b0) begin
+ status_cnt <= 0;
+ end else if (srst ) begin
+ status_cnt <= 0;
+ // Read but no write.
+ end else if (rd_en && (!wr_en) && (status_cnt != 0)) begin
+ status_cnt <= status_cnt - 1;
+ // Write but no read.
+ end else if (wr_en && (!rd_en) && (status_cnt != FIFO_DEPTH)) begin
+ status_cnt <= status_cnt + 1;
+ end
+end
+
+// underflow is not handled
+always @ (negedge rstn or posedge clk)
+begin : EMPTY_FLAG
+ if (rstn==1'b0) begin
+ empty <= 1;
+ end else if (srst ) begin
+ empty <= 1;
+ // Read but no write.
+ end else if (rd_en && (!wr_en) && (status_cnt == 1)) begin
+ empty <= 1;
+ // Write
+ end else if (wr_en) begin
+ empty <= 0;
+ end else if (status_cnt == 0) begin
+ empty <= 1;
+ end
+end
+
+// overflow is not handled
+always @ (negedge rstn or posedge clk)
+begin : FULL_FLAG
+ if (rstn==1'b0) begin
+ full <= 0;
+ end else if (srst ) begin
+ full <= 0;
+ // Write but no read.
+ end else if (wr_en && (!rd_en) && (status_cnt == (FIFO_DEPTH-1))) begin
+ full <= 1;
+ // Read
+ end else if (rd_en && (!wr_en) ) begin
+ full <= 0;
+ end else if (status_cnt == FIFO_DEPTH) begin
+ full <= 1;
+ end
+end
+assign dout = ram[rptr];
+
+always @ (posedge clk)
+begin
+ if (wr_en) ram[wptr] <= din;
+end
+
+
+endmodule
diff --git a/verilog/rtl/spi_master/src/spim_regs.sv b/verilog/rtl/spi_master/src/spim_regs.sv
new file mode 100644
index 0000000..7d06f3e
--- /dev/null
+++ b/verilog/rtl/spi_master/src/spim_regs.sv
@@ -0,0 +1,410 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// SPI WishBone Register I/F Module ////
+//// ////
+//// This file is part of the YIFive cores project ////
+//// http://www.opencores.org/cores/yifive/ ////
+//// ////
+//// Description ////
+//// SPI WishBone I/F module ////
+//// This block support following functionality ////
+//// 1. Direct SPI Read memory support for address rang ////
+//// 0x0000 to 0x0FFF_FFFF - Use full for Instruction ////
+//// Data Memory fetch ////
+//// 2. SPI Local Register Access ////
+//// 3. Indirect register way to access SPI Memory ////
+//// ////
+//// 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_regs #( parameter WB_WIDTH = 32) (
+ input logic mclk,
+ input logic rst_n,
+
+ input logic wbd_stb_i, // strobe/request
+ input logic [WB_WIDTH-1:0] wbd_adr_i, // address
+ input logic wbd_we_i, // write
+ input logic [WB_WIDTH-1:0] wbd_dat_i, // data output
+ input logic [3:0] wbd_sel_i, // byte enable
+ output logic [WB_WIDTH-1:0] wbd_dat_o, // data input
+ output logic wbd_ack_o, // acknowlegement
+ output logic wbd_err_o, // error
+
+ output logic [7:0] spi_clk_div,
+ output logic spi_clk_div_valid,
+ input logic [7:0] spi_status,
+
+ // Towards SPI TX/RX FSM
+
+
+ output logic spi_req,
+ output logic [31:0] spi_addr,
+ output logic [5:0] spi_addr_len,
+ output logic [7:0] spi_cmd,
+ output logic [5:0] spi_cmd_len,
+ output logic [7:0] spi_mode_cmd,
+ output logic spi_mode_cmd_enb,
+ output logic [3:0] spi_csreg,
+ output logic [15:0] spi_data_len,
+ output logic [15:0] spi_dummy_rd_len,
+ output logic [15:0] spi_dummy_wr_len,
+ output logic spi_swrst,
+ output logic spi_rd,
+ output logic spi_wr,
+ output logic spi_qrd,
+ output logic spi_qwr,
+ output logic [31:0] spi_wdata,
+ input logic [31:0] spi_rdata,
+ input logic spi_ack
+
+ );
+
+//----------------------------
+// Register Decoding
+// ---------------------------
+parameter REG_CTRL = 4'b0000;
+parameter REG_CLKDIV = 4'b0001;
+parameter REG_SPICMD = 4'b0010;
+parameter REG_SPIADR = 4'b0011;
+parameter REG_SPILEN = 4'b0100;
+parameter REG_SPIDUM = 4'b0101;
+parameter REG_SPIWDATA = 4'b0110;
+parameter REG_SPIRDATA = 4'b0111;
+parameter REG_STATUS = 4'b1000;
+
+// Init FSM
+parameter SPI_INIT_IDLE = 3'b000;
+parameter SPI_INIT_CMD_WAIT = 3'b001;
+parameter SPI_INIT_WRR_CMD = 3'b010;
+parameter SPI_INIT_WRR_WAIT = 3'b011;
+
+//---------------------------------------------------------
+// Variable declartion
+// -------------------------------------------------------
+logic spi_init_done ;
+logic [2:0] spi_init_state ;
+logic spim_mem_req ;
+logic spim_reg_req ;
+
+
+logic spim_wb_req ;
+logic spim_wb_req_l ;
+logic [WB_WIDTH-1:0] spim_wb_wdata ;
+logic [WB_WIDTH-1:0] spim_wb_addr ;
+logic spim_wb_ack ;
+logic spim_wb_we ;
+logic [3:0] spim_wb_be ;
+logic [WB_WIDTH-1:0] spim_reg_rdata ;
+logic [WB_WIDTH-1:0] spim_wb_rdata ;
+logic [WB_WIDTH-1:0] reg_rdata ;
+
+// Control Signal Generated from Reg to SPI Access
+logic reg2spi_req;
+logic [31:0] reg2spi_addr;
+logic [5:0] reg2spi_addr_len;
+logic [31:0] reg2spi_cmd;
+logic [5:0] reg2spi_cmd_len;
+logic [3:0] reg2spi_csreg;
+logic [15:0] reg2spi_data_len;
+logic reg2spi_mode_enb; // mode enable
+logic [7:0] reg2spi_mode; // mode
+logic [15:0] reg2spi_dummy_rd_len;
+logic [15:0] reg2spi_dummy_wr_len;
+logic reg2spi_swrst;
+logic reg2spi_rd;
+logic reg2spi_wr;
+logic reg2spi_qrd;
+logic reg2spi_qwr;
+logic [31:0] reg2spi_wdata;
+//------------------------------------------------------------------
+// Priority given to mem2spi request over Reg2Spi
+
+ assign spi_req = (spim_mem_req && !spim_wb_we) ? 1'b1 : reg2spi_req;
+ assign spi_addr = (spim_mem_req && !spim_wb_we) ? {spim_wb_addr[23:0],8'h0} : reg2spi_addr;
+ assign spi_addr_len = (spim_mem_req && !spim_wb_we) ? 24 : reg2spi_addr_len;
+ assign spi_cmd = (spim_mem_req && !spim_wb_we) ? 8'hEB : reg2spi_cmd;
+ assign spi_cmd_len = (spim_mem_req && !spim_wb_we) ? 8 : reg2spi_cmd_len;
+ assign spi_mode_cmd = (spim_mem_req && !spim_wb_we) ? 8'h00 : reg2spi_mode;
+ assign spi_mode_cmd_enb = (spim_mem_req && !spim_wb_we) ? 1 : reg2spi_mode_enb;
+ assign spi_csreg = (spim_mem_req && !spim_wb_we) ? '1 : reg2spi_csreg;
+ assign spi_data_len = (spim_mem_req && !spim_wb_we) ? 'h10 : reg2spi_data_len;
+ assign spi_dummy_rd_len = (spim_mem_req && !spim_wb_we) ? 16 : reg2spi_dummy_rd_len;
+ assign spi_dummy_wr_len = (spim_mem_req && !spim_wb_we) ? 0 : reg2spi_dummy_wr_len;
+ assign spi_swrst = (spim_mem_req && !spim_wb_we) ? 0 : reg2spi_swrst;
+ assign spi_rd = (spim_mem_req && !spim_wb_we) ? 0 : reg2spi_rd;
+ assign spi_wr = (spim_mem_req && !spim_wb_we) ? 0 : reg2spi_wr;
+ assign spi_qrd = (spim_mem_req && !spim_wb_we) ? 1 : reg2spi_qrd;
+ assign spi_qwr = (spim_mem_req && !spim_wb_we) ? 0 : reg2spi_qwr;
+ assign spi_wdata = (spim_mem_req && !spim_wb_we) ? 0 : reg2spi_wdata;
+
+
+
+
+ //---------------------------------------------------------------
+ // Address Decoding
+ // 0x0000_0000 - 0x0FFF_FFFF - SPI FLASH MEMORY ACCESS - 256MB
+ // 0x1000_0000 - - SPI Register Access
+ // --------------------------------------------------------------
+
+ assign spim_mem_req = ((spim_wb_req) && spim_wb_addr[31:28] == 4'b0000);
+ assign spim_reg_req = ((spim_wb_req) && spim_wb_addr[31:28] == 4'b0001);
+
+
+ assign wbd_dat_o = spim_wb_rdata;
+ assign wbd_ack_o = spim_wb_ack;
+ assign wbd_err_o = 1'b0;
+
+ // To reduce the load/Timing Wishbone I/F, all the variable are registered
+always_ff @(negedge rst_n or posedge mclk) begin
+ if ( rst_n == 1'b0 ) begin
+ spim_wb_req <= '0;
+ spim_wb_req_l <= '0;
+ spim_wb_wdata <= '0;
+ spim_wb_rdata <= '0;
+ spim_wb_addr <= '0;
+ spim_wb_be <= '0;
+ spim_wb_we <= '0;
+ spim_wb_ack <= '0;
+ end else begin
+ spim_wb_req <= wbd_stb_i;
+ spim_wb_req_l <= spim_wb_req;
+ spim_wb_wdata <= wbd_dat_i;
+ spim_wb_addr <= wbd_adr_i;
+ spim_wb_be <= wbd_sel_i;
+ spim_wb_we <= wbd_we_i;
+
+
+ // If there is Reg2Spi read Access, Register the Read Data
+ if(reg2spi_req && (reg2spi_rd || reg2spi_qrd ) && spi_ack)
+ spim_reg_rdata <= spi_rdata;
+
+ if(!spim_wb_we && spim_wb_req && spi_ack)
+ spim_wb_rdata <= spi_rdata;
+ else
+ spim_wb_rdata <= reg_rdata;
+
+ // For safer design, we have generated ack after 2 cycle latter to
+ // cross-check current request is towards SPI or not
+ spim_wb_ack <= (spi_req) ? spi_ack :
+ ((spim_wb_ack==0) && spim_wb_req && spim_wb_req_l) ;
+ end
+end
+
+ integer byte_index;
+ always_ff @(negedge rst_n or posedge mclk) begin
+ if ( rst_n == 1'b0 ) begin
+ reg2spi_swrst <= 1'b0;
+ reg2spi_rd <= 1'b0;
+ reg2spi_wr <= 1'b0;
+ reg2spi_qrd <= 1'b0;
+ reg2spi_qwr <= 1'b0;
+ reg2spi_cmd <= 'h0;
+ reg2spi_addr <= 'h0;
+ reg2spi_cmd_len <= 'h0;
+ reg2spi_addr_len <= 'h0;
+ reg2spi_data_len <= 'h0;
+ reg2spi_wdata <= 'h0;
+ reg2spi_mode_enb <= 'h0;
+ reg2spi_mode <= 'h0;
+ reg2spi_dummy_rd_len <= 'h0;
+ reg2spi_dummy_wr_len <= 'h0;
+ reg2spi_csreg <= 'h0;
+ reg2spi_req <= 'h0;
+ spi_clk_div_valid <= 1'b0;
+ spi_clk_div <= 'h2;
+ spi_init_done <= 'h0;
+ spi_init_state <= SPI_INIT_IDLE;
+ end
+ else if (spi_init_done == 0) begin
+ case(spi_init_state)
+ SPI_INIT_IDLE:
+ begin
+ reg2spi_rd <= 'h0;
+ reg2spi_wr <= 'h1; // SPI Write Req
+ reg2spi_qrd <= 'h0;
+ reg2spi_qwr <= 'h0;
+ reg2spi_swrst <= 'h0;
+ reg2spi_csreg <= 'h1;
+ reg2spi_cmd[7:0] <= 'h6; // WREN command
+ reg2spi_mode[7:0] <= 'h0;
+ reg2spi_cmd_len <= 'h8;
+ reg2spi_addr_len <= 'h0;
+ reg2spi_data_len <= 'h0;
+ reg2spi_wdata <= 'h0;
+ reg2spi_req <= 'h1;
+ spi_init_state <= SPI_INIT_CMD_WAIT;
+ end
+ SPI_INIT_CMD_WAIT:
+ begin
+ if(spi_ack) begin
+ reg2spi_req <= 1'b0;
+ spi_init_state <= SPI_INIT_WRR_CMD;
+ end
+ end
+ SPI_INIT_WRR_CMD:
+ begin
+ reg2spi_rd <= 'h0;
+ reg2spi_wr <= 'h1; // SPI Write Req
+ reg2spi_qrd <= 'h0;
+ reg2spi_qwr <= 'h0;
+ reg2spi_swrst <= 'h0;
+ reg2spi_csreg <= 'h1;
+ reg2spi_cmd[7:0] <= 'h1; // WRR command
+ reg2spi_mode[7:0] <= 'h0;
+ reg2spi_cmd_len <= 'h8;
+ reg2spi_addr_len <= 'h0;
+ reg2spi_data_len <= 'h10;
+ reg2spi_wdata <= {8'h0,8'h2,16'h0}; // <sr1[7:0]><<cr1[7:0]><16'h0> cr1[1] = 1 indicate quad mode
+ reg2spi_req <= 'h1;
+ spi_init_state <= SPI_INIT_WRR_WAIT;
+ end
+ SPI_INIT_WRR_WAIT:
+ begin
+ if(spi_ack) begin
+ reg2spi_req <= 1'b0;
+ spi_init_done <= 'h1;
+ end
+ end
+ endcase
+ end else if (spim_reg_req & spim_wb_we )
+ begin
+ case(spim_wb_addr[7:4])
+ REG_CTRL:
+ begin
+ if ( spim_wb_be[0] == 1 )
+ begin
+ reg2spi_rd <= spim_wb_wdata[0];
+ reg2spi_wr <= spim_wb_wdata[1];
+ reg2spi_qrd <= spim_wb_wdata[2];
+ reg2spi_qwr <= spim_wb_wdata[3];
+ reg2spi_swrst <= spim_wb_wdata[4];
+ reg2spi_req <= 1'b1;
+ end
+ if ( spim_wb_be[1] == 1 )
+ begin
+ reg2spi_csreg <= spim_wb_wdata[11:8];
+ end
+ end
+ REG_CLKDIV:
+ if ( spim_wb_be[0] == 1 )
+ begin
+ spi_clk_div <= spim_wb_wdata[7:0];
+ spi_clk_div_valid <= 1'b1;
+ end
+ REG_SPICMD: begin
+ if ( spim_wb_be[0] == 1 )
+ reg2spi_cmd[7:0] <= spim_wb_wdata[7:0];
+ if ( spim_wb_be[1] == 1 )
+ reg2spi_mode[7:0] <= spim_wb_wdata[15:8];
+ end
+ REG_SPIADR:
+ for (byte_index = 0; byte_index < 4; byte_index = byte_index+1 )
+ if ( spim_wb_be[byte_index] == 1 )
+ reg2spi_addr[byte_index*8 +: 8] <= spim_wb_wdata[(byte_index*8) +: 8];
+ REG_SPILEN:
+ begin
+ if ( spim_wb_be[0] == 1 ) begin
+ reg2spi_mode_enb <= spim_wb_wdata[6];
+ reg2spi_cmd_len <= spim_wb_wdata[5:0];
+ end
+ if ( spim_wb_be[1] == 1 )
+ reg2spi_addr_len <= spim_wb_wdata[13:8];
+ if ( spim_wb_be[2] == 1 )
+ reg2spi_data_len[7:0] <= spim_wb_wdata[23:16];
+ if ( spim_wb_be[3] == 1 )
+ reg2spi_data_len[15:8] <= spim_wb_wdata[31:24];
+ end
+ REG_SPIDUM:
+ begin
+ if ( spim_wb_be[0] == 1 )
+ reg2spi_dummy_rd_len[7:0] <= spim_wb_wdata[7:0];
+ if ( spim_wb_be[1] == 1 )
+ reg2spi_dummy_rd_len[15:8] <= spim_wb_wdata[15:8];
+ if ( spim_wb_be[2] == 1 )
+ reg2spi_dummy_wr_len[7:0] <= spim_wb_wdata[23:16];
+ if ( spim_wb_be[3] == 1 )
+ reg2spi_dummy_wr_len[15:8] <= spim_wb_wdata[31:24];
+ end
+ REG_SPIWDATA: begin
+ reg2spi_wdata <= spim_wb_wdata;
+ end
+ endcase
+ end
+ else
+ begin
+ if(spi_ack && spim_reg_req)
+ reg2spi_req <= 1'b0;
+ end
+ end
+
+
+ // implement slave model register read mux
+ always_comb
+ begin
+ reg_rdata = '0;
+ case(spim_wb_addr[7:4])
+ REG_CTRL:
+ reg_rdata[31:0] = { 20'h0,
+ reg2spi_csreg,
+ 3'b0,
+ reg2spi_swrst,
+ reg2spi_qwr,
+ reg2spi_qrd,
+ reg2spi_wr,
+ reg2spi_rd};
+
+ REG_CLKDIV:
+ reg_rdata[31:0] = {24'h0,spi_clk_div};
+ REG_SPICMD:
+ reg_rdata[31:0] = {16'h0,reg2spi_mode,reg2spi_cmd};
+ REG_SPIADR:
+ reg_rdata[31:0] = reg2spi_addr;
+ REG_SPILEN:
+ reg_rdata[31:0] = {reg2spi_data_len,2'b00,reg2spi_addr_len,1'b0,reg2spi_mode_enb,reg2spi_cmd_len};
+ REG_SPIDUM:
+ reg_rdata[31:0] = {reg2spi_dummy_wr_len,reg2spi_dummy_rd_len};
+ REG_SPIWDATA:
+ reg_rdata[31:0] = reg2spi_wdata;
+ REG_SPIRDATA:
+ reg_rdata[31:0] = spim_reg_rdata;
+ REG_STATUS:
+ reg_rdata[31:0] = {24'h0,spi_status};
+ endcase
+ end
+
+
+endmodule
diff --git a/verilog/rtl/spi_master/src/spim_rx.sv b/verilog/rtl/spi_master/src/spim_rx.sv
new file mode 100644
index 0000000..f11c16b
--- /dev/null
+++ b/verilog/rtl/spi_master/src/spim_rx.sv
@@ -0,0 +1,175 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// SPI RX Module ////
+//// ////
+//// This file is part of the YIFive cores project ////
+//// http://www.opencores.org/cores/yifive/ ////
+//// ////
+//// Description ////
+//// SPI RX module ////
+//// ////
+//// 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_rx #(
+ parameter ENDIEAN = 0 // 0 - Little, 1 - Big endian, since RISV is Little indian default set 0
+ )
+(
+ input logic clk,
+ input logic rstn,
+ input logic en,
+ input logic rx_edge,
+ output logic rx_done,
+ input logic sdi0,
+ input logic sdi1,
+ input logic sdi2,
+ input logic sdi3,
+ input logic en_quad_in,
+ input logic [15:0] counter_in,
+ input logic counter_in_upd,
+ output logic [31:0] data,
+ input logic data_ready,
+ output logic data_valid,
+ output logic clk_en_o
+);
+
+ logic [31:0] data_int;
+ logic [31:0] data_int_next;
+ logic [15:0] counter;
+ logic [15:0] counter_trgt;
+ logic [15:0] counter_next;
+ logic [15:0] counter_trgt_next;
+ logic reg_done;
+ enum logic [1:0] { IDLE, RECEIVE, WAIT_FIFO, WAIT_FIFO_DONE } rx_CS, rx_NS;
+
+
+ assign reg_done = (!en_quad_in && (counter[4:0] == 5'b11111)) || (en_quad_in && (counter[2:0] == 3'b111));
+
+ // RISV is little endian, so data is converted to little endian format
+ assign data = (ENDIEAN) ? data_int_next : {data_int_next[7:0],data_int_next[15:8],data_int_next[23:16],data_int_next[31:24]};
+ assign rx_done = (counter == (counter_trgt-1)) & rx_edge;
+
+ always_comb
+ begin
+ if (counter_in_upd)
+ counter_trgt_next = (en_quad_in) ? {2'b00,counter_in[15:2]} : counter_in;
+ else
+ counter_trgt_next = counter_trgt;
+ end
+
+ always_comb
+ begin
+ rx_NS = rx_CS;
+ clk_en_o = 1'b0;
+ data_int_next = data_int;
+ data_valid = 1'b0;
+ counter_next = counter;
+
+ case (rx_CS)
+ IDLE: begin
+ clk_en_o = 1'b0;
+
+ // check first if there is available space instead of later
+ if (en) begin
+ rx_NS = RECEIVE;
+ end
+ end
+
+ RECEIVE: begin
+ clk_en_o = 1'b1;
+
+ if (rx_edge) begin
+ counter_next = counter + 1;
+ if (en_quad_in)
+ data_int_next = {data_int[27:0],sdi3,sdi2,sdi1,sdi0};
+ else
+ data_int_next = {data_int[30:0],sdi1};
+
+ if (rx_done) begin
+ counter_next = 0;
+ data_valid = 1'b1;
+
+ if (data_ready)
+ rx_NS = IDLE;
+ else
+ rx_NS = WAIT_FIFO_DONE;
+ end else if (reg_done) begin
+ data_valid = 1'b1;
+
+ if (~data_ready) begin
+ // no space in the FIFO, wait for free space
+ clk_en_o = 1'b0;
+ rx_NS = WAIT_FIFO;
+ end
+ end
+ end
+ end
+
+ WAIT_FIFO_DONE: begin
+ data_valid = 1'b1;
+ if (data_ready)
+ rx_NS = IDLE;
+ end
+
+ WAIT_FIFO: begin
+ data_valid = 1'b1;
+ if (data_ready)
+ rx_NS = RECEIVE;
+ end
+ endcase
+ end
+
+
+ always_ff @(posedge clk, negedge rstn)
+ begin
+ if (rstn == 0)
+ begin
+ counter <= 0;
+ counter_trgt <= 'h8;
+ data_int <= '0;
+ rx_CS <= IDLE;
+ end
+ else
+ begin
+ counter <= counter_next;
+ counter_trgt <= counter_trgt_next;
+ data_int <= data_int_next;
+ rx_CS <= rx_NS;
+ end
+ end
+
+endmodule
diff --git a/verilog/rtl/spi_master/src/spim_top.sv b/verilog/rtl/spi_master/src/spim_top.sv
new file mode 100644
index 0000000..9943f00
--- /dev/null
+++ b/verilog/rtl/spi_master/src/spim_top.sv
@@ -0,0 +1,218 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// SPI Master Top Module ////
+//// ////
+//// This file is part of the YIFive cores project ////
+//// http://www.opencores.org/cores/yifive/ ////
+//// ////
+//// Description ////
+//// SPI Master Top module ////
+//// ////
+//// 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_top
+#( parameter WB_WIDTH = 32)
+(
+ input logic mclk,
+ input logic rst_n,
+
+
+ output logic wbd_stb_i, // strobe/request
+ output logic [WB_WIDTH-1:0] wbd_adr_i, // address
+ output logic wbd_we_i, // write
+ output logic [WB_WIDTH-1:0] wbd_dat_i, // data output
+ output logic [3:0] wbd_sel_i, // byte enable
+ input logic [WB_WIDTH-1:0] wbd_dat_o, // data input
+ input logic wbd_ack_o, // acknowlegement
+ input logic wbd_err_o, // error
+
+ output logic [1:0] events_o,
+
+ 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
+);
+
+
+
+ logic [7:0] spi_clk_div;
+ logic spi_clk_div_valid;
+ logic [7:0] spi_status;
+ logic [31:0] spi_addr;
+ logic [5:0] spi_addr_len;
+ logic [7:0] spi_cmd;
+ logic [5:0] spi_cmd_len;
+ logic [7:0] spi_mode_cmd;
+ logic spi_mode_cmd_enb;
+ logic [15:0] spi_data_len;
+ logic [15:0] spi_dummy_rd_len;
+ logic [15:0] spi_dummy_wr_len;
+ logic spi_swrst;
+ logic spi_rd;
+ logic spi_wr;
+ logic spi_qrd;
+ logic spi_qwr;
+ logic [31:0] spi_wdata;
+ logic [31:0] spi_rdata;
+ logic [3:0] spi_csreg;
+ logic [31:0] spi_data_tx;
+ logic spi_data_tx_valid;
+ logic spi_data_tx_ready;
+ logic [31:0] spi_data_rx;
+ logic spi_data_rx_valid;
+ logic spi_data_rx_ready;
+ logic [7:0] spi_ctrl_status;
+ logic [31:0] spi_ctrl_data_tx;
+ logic spi_ctrl_data_tx_valid;
+ logic spi_ctrl_data_tx_ready;
+ logic [31:0] spi_ctrl_data_rx;
+ logic spi_ctrl_data_rx_valid;
+ logic spi_ctrl_data_rx_ready;
+ logic [31:0] reg2spi_wdata;
+
+ logic s_eot;
+
+
+
+
+
+ spim_regs
+ #(
+ .WB_WIDTH(WB_WIDTH)
+ )
+ u_spim_regs
+ (
+ .mclk (mclk ),
+ .rst_n (rst_n ),
+
+ .wbd_stb_i (wbd_stb_i ), // strobe/request
+ .wbd_adr_i (wbd_adr_i ), // address
+ .wbd_we_i (wbd_we_i ), // write
+ .wbd_dat_i (wbd_dat_i ), // data output
+ .wbd_sel_i (wbd_sel_i ), // byte enable
+ .wbd_dat_o (wbd_dat_o ), // data input
+ .wbd_ack_o (wbd_ack_o ), // acknowlegement
+ .wbd_err_o (wbd_err_o ), // error
+
+ .spi_clk_div (spi_clk_div ),
+ .spi_clk_div_valid (spi_clk_div_valid ),
+ .spi_status (spi_status ),
+
+
+ .spi_req (spi_req ),
+ .spi_addr (spi_addr ),
+ .spi_addr_len (spi_addr_len ),
+ .spi_cmd (spi_cmd ),
+ .spi_cmd_len (spi_cmd_len ),
+ .spi_mode_cmd (spi_mode_cmd ),
+ .spi_mode_cmd_enb (spi_mode_cmd_enb ),
+ .spi_csreg (spi_csreg ),
+ .spi_data_len (spi_data_len ),
+ .spi_dummy_rd_len (spi_dummy_rd_len ),
+ .spi_dummy_wr_len (spi_dummy_wr_len ),
+ .spi_swrst (spi_swrst ),
+ .spi_rd (spi_rd ),
+ .spi_wr (spi_wr ),
+ .spi_qrd (spi_qrd ),
+ .spi_qwr (spi_qwr ),
+ .spi_wdata (spi_wdata ),
+ .spi_rdata (spi_rdata ),
+ .spi_ack (spi_ack )
+ );
+
+ spim_ctrl u_spictrl
+ (
+ .clk (mclk ),
+ .rstn (rst_n ),
+ .eot ( ),
+
+ .spi_clk_div (spi_clk_div ),
+ .spi_clk_div_valid (spi_clk_div_valid ),
+ .spi_status (spi_ctrl_status ),
+
+ .spi_req (spi_req ),
+ .spi_addr (spi_addr ),
+ .spi_addr_len (spi_addr_len ),
+ .spi_cmd (spi_cmd ),
+ .spi_cmd_len (spi_cmd_len ),
+ .spi_mode_cmd (spi_mode_cmd ),
+ .spi_mode_cmd_enb (spi_mode_cmd_enb ),
+ .spi_csreg (spi_csreg ),
+ .spi_data_len (spi_data_len ),
+ .spi_dummy_rd_len (spi_dummy_rd_len ),
+ .spi_dummy_wr_len (spi_dummy_wr_len ),
+ .spi_swrst (spi_swrst ),
+ .spi_rd (spi_rd ),
+ .spi_wr (spi_wr ),
+ .spi_qrd (spi_qrd ),
+ .spi_qwr (spi_qwr ),
+ .spi_wdata (spi_wdata ),
+ .spi_rdata (spi_rdata ),
+ .spi_ack (spi_ack ),
+
+ .spi_clk (spi_clk ),
+ .spi_csn0 (spi_csn0 ),
+ .spi_csn1 (spi_csn1 ),
+ .spi_csn2 (spi_csn2 ),
+ .spi_csn3 (spi_csn3 ),
+ .spi_mode (spi_mode ),
+ .spi_sdo0 (spi_sdo0 ),
+ .spi_sdo1 (spi_sdo1 ),
+ .spi_sdo2 (spi_sdo2 ),
+ .spi_sdo3 (spi_sdo3 ),
+ .spi_sdi0 (spi_sdi0 ),
+ .spi_sdi1 (spi_sdi1 ),
+ .spi_sdi2 (spi_sdi2 ),
+ .spi_sdi3 (spi_sdi3 ),
+ .spi_en_tx (spi_en_tx )
+ );
+
+endmodule
diff --git a/verilog/rtl/spi_master/src/spim_tx.sv b/verilog/rtl/spi_master/src/spim_tx.sv
new file mode 100644
index 0000000..d3fd332
--- /dev/null
+++ b/verilog/rtl/spi_master/src/spim_tx.sv
@@ -0,0 +1,169 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// SPI TX Module ////
+//// ////
+//// This file is part of the YIFive cores project ////
+//// http://www.opencores.org/cores/yifive/ ////
+//// ////
+//// Description ////
+//// This is SPI Master Transmit Word control logic. ////
+//// This logic transmit data upto 32 bit in bit or Quad spi ////
+//// mode ////
+//// ////
+//// To Do: ////
+//// nothing ////
+//// ////
+//// Author(s): ////
+//// - Dinesh Annayya, dinesha@opencores.org ////
+//// ////
+//// Revision: ////
+//// 0.1 - 16th Feb 2021, Dinesh A ////
+//// Initial version ////
+//// 0.2 - 24th Mar 2021, Dinesh A ////
+//// 1. Comments are added ////
+//// 2. RTL clean-up done and the output are registred////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// 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_tx
+(
+ // General Input
+ input logic clk, // SPI clock
+ input logic rstn, // Active low Reset
+ input logic en, // Transmit Enable
+ input logic tx_edge, // Transmiting Edge
+ output logic tx_done, // Transmission completion
+ output logic sdo0, // SPI Dout0
+ output logic sdo1, // SPI Dout1
+ output logic sdo2, // SPI Dout2
+ output logic sdo3, // SPI Dout3
+ input logic en_quad_in, // SPI quad mode indication
+ input logic [15:0] counter_in, // Transmit counter
+ input logic [31:0] txdata, // 32 bit tranmsit data
+ input logic data_valid, // Input data valid
+ output logic data_ready, // Data in acepted, this for txfifo
+ output logic clk_en_o // Enable Tx clock
+);
+
+ logic [31:0] data_int ; // Data Input
+ logic [31:0] data_int_next ; // Next Data Input
+ logic [15:0] counter ; // Tx Counter
+ logic [15:0] counter_next ; // tx next counter
+ logic [15:0] counter_trgt ; // counter exit counter
+ logic tx32b_done ; // 32 bit Transmit done
+ logic en_quad;
+
+ enum logic [0:0] { IDLE, TRANSMIT } tx_CS, tx_NS;
+
+ // Counter Exit condition, quad mode div-4 , else actual counter
+ always_comb
+ begin
+ counter_trgt = (en_quad_in) ? {2'b00,counter_in[15:2]} : counter_in;
+ end
+
+ //Indicate end of transmission of all the bytes
+ assign tx_done = (counter == counter_trgt) && tx_edge;
+
+
+ // Indicate 32 bit data done, usefull for readining next 32b from txfifo
+ assign tx32b_done = (!en_quad && (counter[4:0] == 5'b11111)) || (en_quad && (counter[2:0] == 3'b111)) && tx_edge;
+
+
+
+ always_comb
+ begin
+ tx_NS = tx_CS;
+ clk_en_o = 1'b0;
+ data_int_next = data_int;
+ data_ready = 1'b0;
+ counter_next = counter;
+
+ case (tx_CS)
+ IDLE: begin
+ clk_en_o = 1'b0;
+ data_int_next = txdata;
+
+ if (en && data_valid) begin
+ data_ready = 1'b1;
+ tx_NS = TRANSMIT;
+ end
+ end
+
+ TRANSMIT: begin
+ clk_en_o = 1'b1;
+ counter_next = counter + 1;
+ data_int_next = (en_quad) ? {data_int[27:0],4'b0000} : {data_int[30:0],1'b0};
+
+ if (tx_done) begin
+ counter_next = 0;
+ // Check if there is next data
+ if (en && data_valid) begin
+ data_int_next = txdata;
+ data_ready = 1'b1;
+ tx_NS = TRANSMIT;
+ end else begin
+ clk_en_o = 1'b0;
+ tx_NS = IDLE;
+ end
+ end else if (tx32b_done) begin
+ if (data_valid) begin
+ data_int_next = txdata;
+ data_ready = 1'b1;
+ end else begin
+ clk_en_o = 1'b0;
+ tx_NS = IDLE;
+ end
+ end
+ end
+ endcase
+ end
+
+ always_ff @(posedge clk, negedge rstn)
+ begin
+ if (~rstn)
+ begin
+ counter <= 0;
+ data_int <= 'h0;
+ tx_CS <= IDLE;
+ en_quad <= 0;
+ end
+ else
+ begin
+ if(tx_edge) begin
+ counter <= counter_next;
+ data_int <= data_int_next;
+ sdo0 <= (en_quad_in) ? data_int_next[28] : data_int_next[31];
+ sdo1 <= (en_quad_in) ? data_int_next[29] : 1'b1;
+ sdo2 <= (en_quad_in) ? data_int_next[30] : 1'b1;
+ sdo3 <= (en_quad_in) ? data_int_next[31] : 1'b1;
+ tx_CS <= tx_NS;
+ en_quad <= en_quad_in;
+ end
+ end
+ end
+endmodule