From 8e5f20911599c56cbdaf52cdaa15ceede5d3afc8 Mon Sep 17 00:00:00 2001 From: Andreas Olofsson Date: Mon, 7 Mar 2016 22:47:17 -0500 Subject: [PATCH] Implemented parametrized spi slave module - Compiles, but not debugged yet! (needs cleanup) - Next up : implement master, testbench --- spi/hdl/spi_regmap.v | 13 --- spi/hdl/spi_slave.v | 114 +++++++++++++++++++++++ spi/hdl/spi_slave_io.v | 181 +++++++++++++++++++++++++++++++++++++ spi/hdl/spi_slave_regs.v | 191 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 486 insertions(+), 13 deletions(-) delete mode 100644 spi/hdl/spi_regmap.v create mode 100644 spi/hdl/spi_slave.v create mode 100644 spi/hdl/spi_slave_io.v create mode 100644 spi/hdl/spi_slave_regs.v diff --git a/spi/hdl/spi_regmap.v b/spi/hdl/spi_regmap.v deleted file mode 100644 index 16bfadd..0000000 --- a/spi/hdl/spi_regmap.v +++ /dev/null @@ -1,13 +0,0 @@ -`ifndef GPIO_REGMAP_V_ - `define GPIO_REGMAP_V_ - -`define SPI_CFG 6'h0 -`define SPI_STATUS 6'h1 -`define SPI_ILAT 6'h2 -`define SPI_IMASK 6'h3 -`define SPI_DELAY 6'h4 -`define SPI_TX 6'h5 -`define SPI_RX 6'h6 - -`endif // `ifndef GPIO_REGMAP_V_ - diff --git a/spi/hdl/spi_slave.v b/spi/hdl/spi_slave.v new file mode 100644 index 0000000..fe09e3b --- /dev/null +++ b/spi/hdl/spi_slave.v @@ -0,0 +1,114 @@ +//############################################################################# +//# Purpose: SPI slave module # +//############################################################################# +//# Author: Andreas Olofsson # +//# License: MIT (see below) # +//############################################################################# + +module spi_slave(/*AUTOARG*/ + // Outputs + spi_regs, miso, core_spi_access, core_spi_packet, core_spi_wait, + // Inputs + nreset, chipid, sclk, mosi, ss, core_clk, core_access, core_packet + ); + + //parameters + parameter REGS = 16; // total regs + parameter AW = 32; // addresss width + localparam PW = (2*AW+40); // packet width + + //clk,reset, cfg + input nreset; // async active low reset + input [7:0] chipid; // chip id + output [REGS*8-1:0] spi_regs; // all registers for control + + //IO interface + input sclk; // serial clock + input mosi; // slave input + input ss; // slave select + output miso; // slave output + + //core interface (cclk domain) + input core_clk; // core clock (for synchronization) + output core_spi_access; // valid transaction + output [PW-1:0] core_spi_packet; // data to core + output core_spi_wait; // pushback to core + input core_access; // read response from core + input [PW-1:0] core_packet; // read response packet from core + + /*AUTOINPUT*/ + /*AUTOOUTPUT*/ + + /*AUTOWIRE*/ + // Beginning of automatic wires (for undeclared instantiated-module outputs) + wire core_spi_read; // From spi_slave_io of spi_slave_io.v + wire [6:0] spi_addr; // From spi_slave_io of spi_slave_io.v + wire spi_clk; // From spi_slave_io of spi_slave_io.v + wire [7:0] spi_data; // From spi_slave_io of spi_slave_io.v + wire spi_write; // From spi_slave_io of spi_slave_io.v + // End of automatics + + spi_slave_regs #(.AW(AW)) + spi_slave_regs (/*AUTOINST*/ + // Outputs + .spi_regs (spi_regs[REGS*8-1:0]), + // Inputs + .nreset (nreset), + .chipid (chipid[7:0]), + .spi_clk (spi_clk), + .spi_data (spi_data[7:0]), + .spi_write (spi_write), + .spi_addr (spi_addr[5:0]), + .core_clk (core_clk), + .core_access (core_access), + .core_packet (core_packet[PW-1:0]), + .core_spi_read (core_spi_read)); + + + spi_slave_io #(.AW(AW), + .REGS(REGS) + ) + spi_slave_io (/*AUTOINST*/ + // Outputs + .miso (miso), + .spi_clk (spi_clk), + .spi_write (spi_write), + .spi_addr (spi_addr[6:0]), + .spi_data (spi_data[7:0]), + .core_spi_access (core_spi_access), + .core_spi_packet (core_spi_packet[PW-1:0]), + .core_spi_read (core_spi_read), + // Inputs + .sclk (sclk), + .mosi (mosi), + .ss (ss), + .spi_regs (spi_regs[REGS*8-1:0]), + .core_clk (core_clk)); + + +endmodule // spi_slave + +////////////////////////////////////////////////////////////////////////////// +// The MIT License (MIT) // +// // +// Copyright (c) 2015-2016, Adapteva, Inc. // +// // +// Permission is hereby granted, free of charge, to any person obtaining a // +// copy of this software and associated documentation files (the "Software")// +// to deal in the Software without restriction, including without limitation// +// the rights to use, copy, modify, merge, publish, distribute, sublicense, // +// and/or sell copies of the Software, and to permit persons to whom the // +// Software is furnished to do so, subject to the following conditions: // +// // +// The above copyright notice and this permission notice shall be included // +// in all copies or substantial portions of the Software. // +// // +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT// +// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR // +// THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +// // +////////////////////////////////////////////////////////////////////////////// diff --git a/spi/hdl/spi_slave_io.v b/spi/hdl/spi_slave_io.v new file mode 100644 index 0000000..cef44b0 --- /dev/null +++ b/spi/hdl/spi_slave_io.v @@ -0,0 +1,181 @@ +//############################################################################# +//# Purpose: SPI slave IO and statemachine # +//############################################################################# +//# Author: Andreas Olofsson # +//# License: MIT (see below) # +//############################################################################# + +module spi_slave_io(/*AUTOARG*/ + // Outputs + miso, spi_clk, spi_write, spi_addr, spi_data, core_spi_access, + core_spi_packet, core_spi_read, + // Inputs + sclk, mosi, ss, spi_regs, core_clk + ); + + //################################# + //# INTERFACE + //################################# + + //parameters + parameter REGS = 16; // total regs (16/32/64) + parameter AW = 32; // address width + localparam PW = (2*AW+40); // packet width + + //IO interface + input sclk; // slave clock + input mosi; // slave input + input ss; // slave select + output miso; // slave output + + //register file interface + output spi_clk; // spi clock for regfile + output spi_write; // regfile write + output [6:0] spi_addr; // regfile addre + output [7:0] spi_data; // data for regfile + input [REGS*8-1:0] spi_regs; // all registers + + //core interface (synced to core clk) + input core_clk; // core clock + output core_spi_access; // read or write core command + output [PW-1:0] core_spi_packet; // packet + output core_spi_read; // read core command (for regfile) + + //################################# + //# BODY + //################################# + + reg [2:0] spi_state; + reg [7:0] bit_count; + reg [PW-1:0] spi_rx; + reg [PW-1:0] spi_tx; + reg spi_access; + reg packet_done_reg; + reg core_spi_read; + reg [PW-1:0] core_spi_packet; + wire [7:0] packetsize; + + //################################# + //# RX SHIFT REGISTER + //################################# + + always @ (posedge sclk) + if(~ss) + spi_rx[PW-1:0] <= {spi_rx[PW-2:0],mosi}; + + //################################# + //# STATE MACHINE + //################################# + + assign packetsize[7:0] = spi_regs[15:8]; + +`define SPI_IDLE 3'b000 // when ss is high +`define SPI_CMD 3'b001 // 8 cycles for command/addr +`define SPI_READ 3'b010 // 8 cycles to shift out data +`define SPI_WRITE 3'b011 // 8 cycles for data to write +`define SPI_REMOTE 3'b100 // PW cycles (split transaction) + + //state machine + always @ (posedge sclk or posedge ss) + if(ss) + spi_state[1:0] <= `SPI_IDLE; + else + case (spi_state[1:0]) + `SPI_IDLE : + spi_state[2:0] <= `SPI_CMD; + `SPI_CMD : + spi_state[2:0] <= read_cmd ? `SPI_READ : + write_cmd ? `SPI_WRITE : + remote_cmd ? `SPI_REMOTE : + `SPI_CMD; + `SPI_READ : + spi_state[2:0] <= byte_done ? `SPI_IDLE : + `SPI_READ; + `SPI_WRITE : + spi_state[2:0] <= byte_done ? `SPI_IDLE : + `SPI_WRITE; + `SPI_REMOTE : + spi_state[2:0] <= packet_done ? `SPI_IDLE : + `SPI_REMOTE; + endcase // case (spi_state[1:0]) + + //bit counter + always @ (posedge sclk or posedge ss) + if(ss) + bit_count[7:0] <= 'b0; + else + bit_count[7:0] <= bit_count[7:0] + 1'b1; + + assign read_cmd = (spi_rx[7:6]==2'b10) & + (spi_state[2:0]==`SPI_CMD); + + assign write_cmd = (spi_rx[7:6]==2'b00) & + (spi_state[2:0]==`SPI_CMD); + + assign remote_cmd = (spi_rx[7:6]==2'b11) & + (spi_state[2:0]==`SPI_CMD); + + assign byte_done = &bit_count[2:0]; + + assign packet_done = (bit_count[7:0]==packetsize[7:0]); + + //################################# + //# TX SHIFT REGISTER + //################################# + + assign load_tx = byte_done & (spi_state[1:0]==`SPI_CMD); + + always @ (posedge sclk) + if(load_tx) + spi_tx[7:0] <= spi_regs[spi_rx[6:0]]; // + else if(~ss) + spi_tx[7:0] <= {spi_tx[6:0],1'b0}; + + assign miso = spi_tx[7]; + + //################################# + //# REGISTER FILE INTERFACE + //################################# + assign spi_clk = sclk; + assign spi_addr[5:0] = spi_rx[5:0]; + assign spi_write = byte_done & (spi_state[2:0]==`SPI_WRITE); + assign spi_read = byte_done & (spi_state[2:0]==`SPI_READ); + assign spi_data[7:0] = spi_rx[7:0]; + + //################################# + //# CLOCK SYNCHRONIZATION + //################################# + + //!!! CLK_CORE FRE MUST BE > 2 * SCLK FREQ !!! + + //synchronizer + oh_dsync dsync (.dout (packet_done_sync), + .clk (core_clk), + .din (packet_done) + ); + + //posedge detect and pipeline to line up with data + always @ (posedge core_clk) + begin + packet_done_reg <= packet_done_sync; + spi_access <= spi_access_pulse; + end + + assign spi_access_pulse = packet_done_sync & ~packet_done_reg; + + //spi read + always @ (posedge core_clk) + if(spi_access_pulse) + core_spi_read <= spi_read; + else + core_spi_read <= 1'b0; + + //sample rx data + always @ (posedge core_clk) + if(spi_access_pulse) + core_spi_packet[PW-1:0] <= spi_rx[PW-1:0]; + +endmodule // spi_slave_io +// Local Variables: +// verilog-library-directories:("." "../../common/hdl") +// diff --git a/spi/hdl/spi_slave_regs.v b/spi/hdl/spi_slave_regs.v new file mode 100644 index 0000000..964fce0 --- /dev/null +++ b/spi/hdl/spi_slave_regs.v @@ -0,0 +1,191 @@ +//############################################################################# +//# Purpose: SPI slave port register file # +//############################################################################# +//# Author: Andreas Olofsson # +//# License: MIT (see below) # +//############################################################################# + +`include "spi_regmap.vh" +module spi_slave_regs (/*AUTOARG*/ + // Outputs + spi_regs, + // Inputs + nreset, chipid, spi_clk, spi_data, spi_write, spi_addr, core_clk, + core_access, core_packet, core_spi_read + ); + + //parameters + parameter REGS = 16; // number of total regs (>16) + parameter AW = 32; // address width + localparam PW = (2*AW+40); // packet width + + // power on defaults + input nreset; // asych active low + input [7:0] chipid; // default chipid + + // sclk domain + input spi_clk; // slave clock + input [7:0] spi_data; // slave data in (for write) + input spi_write; // slave write + input [5:0] spi_addr; // slave write addr (64 regs) + output [REGS*8-1:0] spi_regs; // all regs concatenated + + // extension for core clock domain + input core_clk; + input core_access; + input [PW-1:0] core_packet; // writeback data + input core_spi_read;// read + + //regs + reg [7:0] spi_config; + reg [7:0] spi_packetsize; + reg [7:0] user_regs[47:0]; + reg [63:0] core_regs; + reg [7:0] core_valid; + reg [REGS*8-1:0] spi_regs; + wire [7:0] spi_chipid; + wire [4*8-1:0] spi_reserved; + wire [63:0] core_data; + integer i; + + //##################################### + //# SPI DECODE + //##################################### + + assign spi_config_write = spi_write & (spi_addr[5:0]==`SPI_CONFIG); + assign spi_packetsize_write = spi_write & (spi_addr[5:0]==`SPI_PACKETSIZE); + assign spi_user_write = spi_write & (|spi_addr[5:4]); + + //##################################### + //# CORE DECODE + //##################################### + + packet2emesh #(.AW(AW)) + pe2 (.write_in (core_write), + .datamode_in (), + .ctrlmode_in (), + .dstaddr_in (), + .srcaddr_in (core_data[63:32]), + .data_in (core_data[31:0]), + // Inputs + .packet_in (core_packet[PW-1:0])); + + //##################################### + //# CONFIG [0] + //##################################### + //[0] = 1--> user regs valid (default is off) + //[1] = 1--> disable spi port (default is enabled) + //[7:2] = reserved + + always @ (posedge spi_clk or negedge nreset) + if(!nreset) + spi_config[7:0] <= 'b0; + else if(spi_config_write) + spi_config[7:0] <= spi_data[7:0]; + + //##################################### + //# PACKET SIZE [1] + //##################################### + + always @ (posedge spi_clk or negedge nreset) + if(!nreset) + spi_packetsize[7:0] <= PW; + else if(spi_packetsize_write) + spi_packetsize[7:0] <= spi_data[7:0]; + + //##################################### + //# CHIPID [2] + //##################################### + + assign spi_chipid[7:0] = chipid[7:0]; + + //##################################### + //# RESERVED [6:3] + //##################################### + + assign spi_reserved[4*8-1:0] = 'b0; + + //##################################### + //# CORE STATUS [7] + //##################################### + + //TODO: implement per byte valid + + always @ (posedge core_clk or negedge nreset) + if(!nreset) + core_valid[7:0] <= 'b0; + else if (core_write & core_access) + core_valid[7:0] <= 8'b1; + else if (core_spi_read) + core_valid[7:0] <= 'b0; + + //##################################### + //# CORE DATA [15:8] + //##################################### + + always @ (posedge core_clk) + if(core_write & core_access) + core_regs[63:0] <= core_data[63:0]; + + //##################################### + //# USER SPACE REGISTERS + //##################################### + + always @ (posedge spi_clk) + if(spi_user_write) + user_regs[spi_addr[5:0]] <= spi_data[7:0]; + + //##################################### + //# CONCATENATE ALL REGISTERS TOGETHER + //##################################### + + //TODO: parametrize to make the smaller config efficient + //user configs should get optimized away + + always @* + begin + //3 config regs + spi_regs[7:0] = spi_config[7:0]; + spi_regs[15:8] = spi_packetsize[7:0]; + spi_regs[23:16] = spi_chipid[7:0]; + //4 reserved regs + spi_regs[56:24] = spi_reserved[4*8-1:0]; + //1 core data valid reg + spi_regs[63:56] = core_valid[7:0]; + //8 core data regs + spi_regs[127:64] = core_regs[63:0]; + //48 user regs + for(i=0;i