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:
parent
983caa7138
commit
8e5f209115
@ -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
114
spi/hdl/spi_slave.v
Normal 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
181
spi/hdl/spi_slave_io.v
Normal 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
191
spi/hdl/spi_slave_regs.v
Normal 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. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
Loading…
x
Reference in New Issue
Block a user