1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-17 20:02:53 +08:00

Implemented parametrized spi slave module

- Compiles, but not debugged yet! (needs cleanup)
- Next up : implement master, testbench
This commit is contained in:
Andreas Olofsson 2016-03-07 22:47:17 -05:00
parent 983caa7138
commit 8e5f209115
4 changed files with 486 additions and 13 deletions

View File

@ -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_

114
spi/hdl/spi_slave.v Normal file
View File

@ -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. //
// //
//////////////////////////////////////////////////////////////////////////////

181
spi/hdl/spi_slave_io.v Normal file
View File

@ -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")
//

191
spi/hdl/spi_slave_regs.v Normal file
View File

@ -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<REGS-16;i=i+1)
spi_regs[128+i*8 +:8] = user_regs[i];
end
endmodule // spi_slave_regs
// Local Variables:
// verilog-library-directories:("." "../../common/hdl" "../../emesh/hdl")
// End:
//////////////////////////////////////////////////////////////////////////////
// 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. //
// //
//////////////////////////////////////////////////////////////////////////////