URL
https://opencores.org/ocsvn/yifive/yifive/trunk
Subversion Repositories yifive
Compare Revisions
- This comparison shows the changes necessary to convert path
/yifive
- from Rev 17 to Rev 18
- ↔ Reverse comparison
Rev 17 → Rev 18
/trunk/caravel_yifive/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 |
} |
trunk/caravel_yifive/openlane/spi_master/config.tcl
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: trunk/caravel_yifive/openlane/spi_master/pin_order.cfg
===================================================================
--- trunk/caravel_yifive/openlane/spi_master/pin_order.cfg (nonexistent)
+++ trunk/caravel_yifive/openlane/spi_master/pin_order.cfg (revision 18)
@@ -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.*
+
Index: trunk/caravel_yifive/openlane/syntacore/config.tcl
===================================================================
--- trunk/caravel_yifive/openlane/syntacore/config.tcl (revision 17)
+++ trunk/caravel_yifive/openlane/syntacore/config.tcl (revision 18)
@@ -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 ]
/trunk/caravel_yifive/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) |
/trunk/caravel_yifive/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 |
/trunk/caravel_yifive/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 |
/trunk/caravel_yifive/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 |
|
/trunk/caravel_yifive/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 |
/trunk/caravel_yifive/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 |
/trunk/caravel_yifive/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 |
/trunk/caravel_yifive/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 |
/trunk/caravel_yifive/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 |