OpenCores
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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.