mirror of
https://github.com/aolofsson/oh.git
synced 2025-01-17 20:02:53 +08:00
Debugged most of SPI
-Changed to FIFO on TX path (cleaner) -No good solution on RX with CDC since clock can stop, so you can't use an async fifo. -Slave needs cleanup, rethink... -Using commong par2ser and ser2par blocks
This commit is contained in:
parent
ef790c1a59
commit
8c350eed91
@ -1,37 +1,75 @@
|
||||
//#############################################################################
|
||||
//# Purpose: Serial to Parallel Converter #
|
||||
//#############################################################################
|
||||
//# Author: Andreas Olofsson #
|
||||
//# License: MIT (see below) #
|
||||
//#############################################################################
|
||||
|
||||
//convert serial stream to parallel
|
||||
module oh_ser2par (/*AUTOARG*/
|
||||
// Outputs
|
||||
dout,
|
||||
// Inputs
|
||||
clk, din, dout
|
||||
clk, din, lsbfirst, shift
|
||||
);
|
||||
|
||||
//###############################################################
|
||||
//# Interface
|
||||
//###############################################################
|
||||
//###########################
|
||||
//# INTERFACE
|
||||
//###########################
|
||||
|
||||
input clk; //sampling clock
|
||||
input din; //serial data
|
||||
output [DW-1:0] dout; //parallel data
|
||||
|
||||
parameter DW = 64; //width of converter
|
||||
parameter TYPE = "MSB"; //MSB first or LSB first
|
||||
|
||||
//###############################################################
|
||||
// parameters
|
||||
parameter PW = 64; // parallel packet width
|
||||
parameter SW = 1; // serial packet width
|
||||
localparam CW = $clog2(PW/SW); // serialization factor (for counter)
|
||||
|
||||
// reset, clk
|
||||
input clk; // sampling clock
|
||||
|
||||
//data interface
|
||||
input [SW-1:0] din; // serial data
|
||||
output [PW-1:0] dout; // parallel data
|
||||
|
||||
// control interface
|
||||
input lsbfirst; // lsb first order
|
||||
input shift; // shift the shifter
|
||||
|
||||
//##############################
|
||||
//# BODY
|
||||
//###############################################################
|
||||
reg [DW-1:0] dout;
|
||||
generate
|
||||
if(TYPE=="MSB")
|
||||
begin
|
||||
always @ (posedge clk)
|
||||
dout[DW-1:0] = {dout[DW-2:0],din};
|
||||
end
|
||||
else
|
||||
begin
|
||||
always @ (posedge clk)
|
||||
dout[DW-1:0] = {din,dout[DW-1:1]};
|
||||
end
|
||||
endgenerate
|
||||
//##############################
|
||||
|
||||
reg [PW-1:0] dout;
|
||||
reg [CW-1:0] count;
|
||||
wire [PW-1:0] shiftdata;
|
||||
|
||||
always @ (posedge clk)
|
||||
if(shift & lsbfirst)
|
||||
dout[PW-1:0] <= {din[SW-1:0],dout[PW-1:SW]};
|
||||
else if(shift)
|
||||
dout[PW-1:0] <= {dout[PW-SW-1:0],din[SW-1:0]};
|
||||
|
||||
endmodule // oh_ser2par
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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. //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
DEADBEEF_99999999_00000000_05_0010 //write gpio_oen
|
||||
DEADBEEF_FFFFFFFF_00000008_05_0010 //write gpio_out
|
||||
DEADBEEF_BBBBBBBB_00000010_05_0010 //write gpio_ien
|
||||
DEADBEEF_CCCCCCCC_00000018_05_0010 //write gpio_in
|
||||
DEADBEEF_11111111_00000020_05_0010 //write gpio_outand
|
||||
DEADBEEF_22222222_00000028_05_0010 //write gpio_outorr
|
||||
DEADBEEF_FFFFFFFF_00000030_05_0010 //write gpio_outxor
|
||||
DEADBEEF_55555555_00000038_05_0010 //write gpio_irqmask
|
||||
DEADBEEF_00000000_00000000_01_0000 //CONFIG (DEFAULT)
|
||||
DEADBEEF_00000000_00000004_01_0000 //STATUS (CLEAR)
|
||||
DEADBEEF_00000003_00000008_01_0020 //CLKDIV (BAUDRATE, DIVIDE by 8)
|
||||
DEADBEEF_00000021_00000020_01_0000 //TX DATA (B0)
|
||||
DEADBEEF_00000043_00000020_01_0000 //TX DATA (B1)
|
||||
DEADBEEF_00000065_00000020_01_0000 //TX DATA (B2)
|
||||
DEADBEEF_00000087_00000020_01_0000 //TX DATA (B3)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
//#############################################################################
|
||||
//# Purpose: SPI top (configuravbe as master or slave) #
|
||||
//# Purpose: SPI top (configurable as master or slave) #
|
||||
//#############################################################################
|
||||
//# Author: Andreas Olofsson #
|
||||
//# License: MIT (see below) #
|
||||
|
@ -13,6 +13,7 @@ module spi_master(/*AUTOARG*/
|
||||
);
|
||||
|
||||
//parameters
|
||||
parameter DEPTH = 16; // fifo depth
|
||||
parameter REGS = 16; // total regs
|
||||
parameter AW = 32; // addresss width
|
||||
localparam PW = (2*AW+40); // packet width
|
||||
@ -43,28 +44,32 @@ module spi_master(/*AUTOARG*/
|
||||
/*AUTOWIRE*/
|
||||
// Beginning of automatic wires (for undeclared instantiated-module outputs)
|
||||
wire [7:0] clkdiv_reg; // From spi_master_regs of spi_master_regs.v
|
||||
wire [7:0] cmd_reg; // From spi_master_regs of spi_master_regs.v
|
||||
wire cpha; // From spi_master_regs of spi_master_regs.v
|
||||
wire cpol; // From spi_master_regs of spi_master_regs.v
|
||||
wire [7:0] psize_reg; // From spi_master_regs of spi_master_regs.v
|
||||
wire emode; // From spi_master_regs of spi_master_regs.v
|
||||
wire [7:0] fifo_dout; // From spi_master_fifo of spi_master_fifo.v
|
||||
wire fifo_empty; // From spi_master_fifo of spi_master_fifo.v
|
||||
wire fifo_read; // From spi_master_io of spi_master_io.v
|
||||
wire lsbfirst; // From spi_master_regs of spi_master_regs.v
|
||||
wire rx_access; // From spi_master_io of spi_master_io.v
|
||||
wire [7:0] rx_data; // From spi_master_io of spi_master_io.v
|
||||
wire spi_en; // From spi_master_regs of spi_master_regs.v
|
||||
wire [2:0] spi_state; // From spi_master_io of spi_master_io.v
|
||||
wire tx_access; // From spi_master_regs of spi_master_regs.v
|
||||
wire [PW-1:0] tx_data; // From spi_master_regs of spi_master_regs.v
|
||||
wire [1:0] spi_state; // From spi_master_io of spi_master_io.v
|
||||
// End of automatics
|
||||
|
||||
|
||||
//#####################################################
|
||||
//# Master control registers
|
||||
//#####################################################
|
||||
|
||||
spi_master_regs #(.AW(AW))
|
||||
spi_master_regs (/*AUTOINST*/
|
||||
// Outputs
|
||||
.tx_access (tx_access),
|
||||
.cmd_reg (cmd_reg[7:0]),
|
||||
.tx_data (tx_data[PW-1:0]),
|
||||
.cpol (cpol),
|
||||
.cpha (cpha),
|
||||
.lsbfirst (lsbfirst),
|
||||
.emode (emode),
|
||||
.spi_en (spi_en),
|
||||
.psize_reg (psize_reg[7:0]),
|
||||
.clkdiv_reg (clkdiv_reg[7:0]),
|
||||
.wait_out (wait_out),
|
||||
.access_out (access_out),
|
||||
@ -74,16 +79,44 @@ module spi_master(/*AUTOARG*/
|
||||
.nreset (nreset),
|
||||
.rx_data (rx_data[PW-1:0]),
|
||||
.rx_access (rx_access),
|
||||
.spi_state (spi_state[2:0]),
|
||||
.spi_state (spi_state[1:0]),
|
||||
.access_in (access_in),
|
||||
.packet_in (packet_in[PW-1:0]),
|
||||
.wait_in (wait_in));
|
||||
|
||||
spi_master_io #(.AW(AW)
|
||||
)
|
||||
//#####################################################
|
||||
//# Transmit FIFO (SPI_TX)
|
||||
//#####################################################
|
||||
|
||||
/* spi_master_fifo AUTO_TEMPLATE (.fifo_dout (fifo_dout[7:0]),
|
||||
);
|
||||
*/
|
||||
|
||||
spi_master_fifo #(.AW(AW),
|
||||
.DEPTH(DEPTH))
|
||||
|
||||
spi_master_fifo(/*AUTOINST*/
|
||||
// Outputs
|
||||
.wait_out (wait_out),
|
||||
.fifo_empty (fifo_empty),
|
||||
.fifo_dout (fifo_dout[7:0]), // Templated
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.nreset (nreset),
|
||||
.emode (emode),
|
||||
.access_in (access_in),
|
||||
.packet_in (packet_in[PW-1:0]),
|
||||
.fifo_read (fifo_read));
|
||||
|
||||
//#####################################################
|
||||
//# SPI IO (8 bit)
|
||||
//#####################################################
|
||||
|
||||
spi_master_io #(.AW(AW))
|
||||
spi_master_io (/*AUTOINST*/
|
||||
// Outputs
|
||||
.spi_state (spi_state[2:0]),
|
||||
.spi_state (spi_state[1:0]),
|
||||
.fifo_read (fifo_read),
|
||||
.rx_data (rx_data[7:0]),
|
||||
.rx_access (rx_access),
|
||||
.sclk (sclk),
|
||||
@ -95,16 +128,14 @@ module spi_master(/*AUTOARG*/
|
||||
.spi_en (spi_en),
|
||||
.cpol (cpol),
|
||||
.cpha (cpha),
|
||||
.lsbfirst (lsbfirst),
|
||||
.clkdiv_reg (clkdiv_reg[7:0]),
|
||||
.psize_reg (psize_reg[7:0]),
|
||||
.cmd_reg (cmd_reg[7:0]),
|
||||
.tx_data (tx_data[PW-1:0]),
|
||||
.tx_access (tx_access),
|
||||
.fifo_dout (fifo_dout[7:0]),
|
||||
.fifo_empty (fifo_empty),
|
||||
.miso (miso));
|
||||
|
||||
|
||||
endmodule // spi_slave
|
||||
|
||||
endmodule // spi_master
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// The MIT License (MIT) //
|
||||
|
133
spi/hdl/spi_master_fifo.v
Normal file
133
spi/hdl/spi_master_fifo.v
Normal file
@ -0,0 +1,133 @@
|
||||
`include "spi_regmap.vh"
|
||||
module spi_master_fifo (/*AUTOARG*/
|
||||
// Outputs
|
||||
wait_out, fifo_empty, fifo_dout,
|
||||
// Inputs
|
||||
clk, nreset, emode, access_in, packet_in, fifo_read
|
||||
);
|
||||
//#####################################################################
|
||||
//# INTERFACE
|
||||
//#####################################################################
|
||||
|
||||
//parameters
|
||||
parameter DEPTH = 16; // fifo entries
|
||||
parameter AW = 32; // architecture address width
|
||||
parameter SW = 8; // output packet width
|
||||
localparam PW = 2*AW+40; // input packet width
|
||||
localparam FAW = $clog2(DEPTH); // fifo address width
|
||||
localparam SRW = $clog2(PW/SW); // serializer cycle count width
|
||||
|
||||
//clk,reset, cfg
|
||||
input clk; // clk
|
||||
input nreset; // async active low reset
|
||||
input emode; // epiphany transfer mode
|
||||
|
||||
// Incoming interface
|
||||
input access_in; // access by core
|
||||
input [PW-1:0] packet_in;
|
||||
output wait_out;
|
||||
|
||||
// IO interface
|
||||
input fifo_read;
|
||||
output fifo_empty;
|
||||
output [SW-1:0] fifo_dout;
|
||||
|
||||
//##################################
|
||||
//# BODY
|
||||
//##################################
|
||||
|
||||
wire [SRW-1:0] datasize;
|
||||
wire [PW-1:0] tx_data;
|
||||
wire [SW-1:0] fifo_din;
|
||||
|
||||
/*AUTOWIRE*/
|
||||
// Beginning of automatic wires (for undeclared instantiated-module outputs)
|
||||
wire [4:0] ctrlmode_in; // From p2e of packet2emesh.v
|
||||
wire [AW-1:0] data_in; // From p2e of packet2emesh.v
|
||||
wire [1:0] datamode_in; // From p2e of packet2emesh.v
|
||||
wire [AW-1:0] dstaddr_in; // From p2e of packet2emesh.v
|
||||
wire [AW-1:0] srcaddr_in; // From p2e of packet2emesh.v
|
||||
wire write_in; // From p2e of packet2emesh.v
|
||||
// End of automatics
|
||||
|
||||
//##################################
|
||||
//# DECODE
|
||||
//###################################
|
||||
|
||||
packet2emesh p2e (/*AUTOINST*/
|
||||
// Outputs
|
||||
.write_in (write_in),
|
||||
.datamode_in (datamode_in[1:0]),
|
||||
.ctrlmode_in (ctrlmode_in[4:0]),
|
||||
.dstaddr_in (dstaddr_in[AW-1:0]),
|
||||
.srcaddr_in (srcaddr_in[AW-1:0]),
|
||||
.data_in (data_in[AW-1:0]),
|
||||
// Inputs
|
||||
.packet_in (packet_in[PW-1:0]));
|
||||
|
||||
|
||||
assign datasize[SRW-1:0] = emode ? (PW/SW) :
|
||||
(1<<datamode_in[1:0]);
|
||||
|
||||
|
||||
assign tx_write = write_in &
|
||||
access_in &
|
||||
(dstaddr_in[7:2]==`SPI_TX);
|
||||
|
||||
//epiphany mode works in msb or lsb mode
|
||||
//data mode up to 64 bits works in lsb mode
|
||||
//for msb transfer, use byte writes only
|
||||
|
||||
assign tx_data[PW-1:0] = emode ? packet_in[PW-1:0] :
|
||||
{{(40){1'b0}},
|
||||
srcaddr_in[AW-1:0],
|
||||
data_in[AW-1:0]};
|
||||
|
||||
//##################################
|
||||
//# FIFO PACKET WRITE
|
||||
//##################################
|
||||
|
||||
oh_par2ser #(.PW(PW),
|
||||
.SW(SW))
|
||||
|
||||
oh_par2ser (// Outputs
|
||||
.dout (fifo_din[SW-1:0]),
|
||||
.access_out (fifo_wr),
|
||||
.wait_out (wait_out),
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.nreset (nreset),
|
||||
.din (tx_data[PW-1:0]),
|
||||
.shift (1'b1),
|
||||
.datasize (datasize[SRW-1:0]),
|
||||
.load (tx_write),
|
||||
.lsbfirst (1'b1),
|
||||
.fill (1'b0),
|
||||
.wait_in (fifo_prog_full)
|
||||
);
|
||||
|
||||
//##################################
|
||||
//# FIFO
|
||||
//###################################
|
||||
|
||||
oh_fifo_sync #(.DEPTH(DEPTH),
|
||||
.DW(SW))
|
||||
fifo(// Outputs
|
||||
.dout (fifo_dout[7:0]),
|
||||
.full (),
|
||||
.prog_full (fifo_prog_full),
|
||||
.empty (fifo_empty),
|
||||
.rd_count (),
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.nreset (nreset),
|
||||
.din (fifo_din[7:0]),
|
||||
.wr_en (fifo_wr),
|
||||
.rd_en (fifo_read));
|
||||
|
||||
endmodule // spi_master_fifo
|
||||
|
||||
// Local Variables:
|
||||
// verilog-library-directories:("." "../../common/hdl" "../../emesh/hdl")
|
||||
// End:
|
||||
|
@ -7,10 +7,10 @@
|
||||
|
||||
module spi_master_io(/*AUTOARG*/
|
||||
// Outputs
|
||||
spi_state, rx_data, rx_access, sclk, mosi, ss,
|
||||
spi_state, fifo_read, rx_data, rx_access, sclk, mosi, ss,
|
||||
// Inputs
|
||||
clk, nreset, spi_en, cpol, cpha, clkdiv_reg, psize_reg, cmd_reg,
|
||||
tx_data, tx_access, miso
|
||||
clk, nreset, spi_en, cpol, cpha, lsbfirst, clkdiv_reg, fifo_dout,
|
||||
fifo_empty, miso
|
||||
);
|
||||
|
||||
//#################################
|
||||
@ -30,16 +30,16 @@ module spi_master_io(/*AUTOARG*/
|
||||
input spi_en; // spi enable
|
||||
input cpol; // cpol
|
||||
input cpha; // cpha
|
||||
input lsbfirst; // send lsbfirst
|
||||
input [7:0] clkdiv_reg; // baudrate
|
||||
input [7:0] psize_reg; // packetsize
|
||||
output [2:0] spi_state; // current spi tx state
|
||||
output [1:0] spi_state; // current spi tx state
|
||||
|
||||
//data to transmit
|
||||
input [7:0] cmd_reg; // 8 bit command
|
||||
input [PW-1:0] tx_data; // data payload
|
||||
input tx_access; // start transfer
|
||||
input [7:0] fifo_dout; // data payload
|
||||
input fifo_empty; //
|
||||
output fifo_read; // read new byte
|
||||
|
||||
//receive data
|
||||
//receive data (for sregs)
|
||||
output [7:0] rx_data; // rx data
|
||||
output rx_access; // rx ready pulse
|
||||
|
||||
@ -50,48 +50,60 @@ module spi_master_io(/*AUTOARG*/
|
||||
input miso; // slave output
|
||||
|
||||
reg [7:0] baud_counter = 'b0; //works b/c of free running counter!
|
||||
reg [2:0] spi_state;
|
||||
reg [PW-1:0] tx_shiftreg;
|
||||
reg [7:0] bit_count;
|
||||
|
||||
reg [1:0] spi_state;
|
||||
reg [2:0] bit_count;
|
||||
reg sclk;
|
||||
|
||||
//#################################
|
||||
//# STATE MACHINE
|
||||
//#################################
|
||||
|
||||
`define SPI_IDLE 3'b000 // clear ss
|
||||
`define SPI_SETUP 3'b001 // load tx
|
||||
`define SPI_CMD 3'b010 // send command
|
||||
`define SPI_DATA 3'b011 // send packet
|
||||
`define SPI_FINISH 3'b100 // raise
|
||||
`define SPI_IDLE 2'b00 // set ss to 1
|
||||
`define SPI_SETUP 2'b01 // setup time
|
||||
`define SPI_DATA 2'b10 // send data
|
||||
`define SPI_HOLD 2'b11 // hold time
|
||||
|
||||
//state machine
|
||||
//NOTE: tx access pulse is lost if there is ongoing transactio (makes sense..)
|
||||
always @ (posedge clk or negedge nreset)
|
||||
if(!nreset)
|
||||
spi_state[1:0] <= `SPI_IDLE;
|
||||
else if(baud_match)
|
||||
case (spi_state[1:0])
|
||||
`SPI_IDLE :
|
||||
spi_state[2:0] <= tx_access ? `SPI_CMD : `SPI_IDLE;
|
||||
spi_state[1:0] <= ~fifo_empty ? `SPI_SETUP : `SPI_IDLE;
|
||||
`SPI_SETUP :
|
||||
spi_state[2:0] <=`SPI_CMD;
|
||||
`SPI_CMD :
|
||||
spi_state[2:0] <= byte_done ? `SPI_DATA : `SPI_CMD;
|
||||
spi_state[1:0] <=`SPI_DATA;
|
||||
`SPI_DATA :
|
||||
spi_state[2:0] <= packet_done ? `SPI_FINISH : `SPI_DATA;
|
||||
`SPI_FINISH :
|
||||
spi_state[2:0] <= `SPI_IDLE;
|
||||
endcase // case (spi_state[1:0])
|
||||
|
||||
|
||||
always @ (posedge sclk)
|
||||
if(spi_state[2:0]==`SPI_IDLE)
|
||||
bit_count[7:0] <= 'b0;
|
||||
spi_state[1:0] <= fifo_empty_reg & byte_done ? `SPI_HOLD : `SPI_DATA;
|
||||
`SPI_HOLD :
|
||||
spi_state[1:0] <= `SPI_IDLE;
|
||||
endcase // case (spi_state[1:0])
|
||||
|
||||
//Bit counter
|
||||
always @ (posedge clk)
|
||||
if(spi_state[1:0]==`SPI_IDLE)
|
||||
bit_count[2:0] <= 'b0;
|
||||
else if(baud_match)
|
||||
bit_count[7:0] <= bit_count[7:0] + 1'b1;
|
||||
bit_count[2:0] <= bit_count[2:0] + 1'b1;
|
||||
|
||||
assign byte_done = &bit_count[2:0];
|
||||
assign byte_done = (bit_count[2:0]==3'b000);
|
||||
|
||||
assign packet_done = (bit_count[7:0]==psize_reg[7:0]);
|
||||
assign fifo_read = ((spi_state[1:0]==`SPI_IDLE) & phase_match ) |
|
||||
((spi_state[1:0]==`SPI_DATA) & phase_match & byte_done);
|
||||
|
||||
assign load_byte = baud_match & byte_done & (spi_state[1:0]!=`SPI_IDLE);
|
||||
|
||||
assign shift = baud_match & (spi_state[1:0]==`SPI_DATA);
|
||||
|
||||
//TODO: Ugly Fifo goes empty on one clk cycle, need to add hold time using baud match
|
||||
//better solution?
|
||||
|
||||
reg fifo_empty_reg;
|
||||
|
||||
always @ (posedge clk)
|
||||
if(baud_match)
|
||||
fifo_empty_reg <= fifo_empty;
|
||||
|
||||
//#################################
|
||||
//# BAUD COUNTER
|
||||
@ -103,37 +115,79 @@ module spi_master_io(/*AUTOARG*/
|
||||
else
|
||||
baud_counter[7:0] <= baud_counter[7:0] + 1'b1;
|
||||
|
||||
assign baud_match = (baud_counter[7:0]==clkdiv_reg[7:0]);
|
||||
assign phase_match = (baud_counter[7:0]==(clkdiv_reg[7:0]>>1));
|
||||
assign baud_match = (baud_counter[7:0]==((1 << clkdiv_reg[7:0]) - 1'b1));
|
||||
assign phase_match = (baud_counter[7:0]==((1 << (clkdiv_reg[7:0]) >> 1) - 1'b1));
|
||||
|
||||
//#################################
|
||||
//# CHIP SELECT
|
||||
//#################################
|
||||
assign ss = (spi_state==`SPI_IDLE);
|
||||
assign ss = (spi_state[1:0]==`SPI_IDLE);
|
||||
|
||||
//#################################
|
||||
//# SCLK GENERATOR
|
||||
//#################################
|
||||
|
||||
//TODO!!
|
||||
//TODO: implement cpol/cpha (cpha=0 for now)
|
||||
|
||||
always @ (posedge clk)
|
||||
if(spi_state[1:0]!=`SPI_DATA)
|
||||
sclk <= 1'b0;
|
||||
else if(phase_match)
|
||||
sclk <= 1'b1;
|
||||
else if(baud_match)
|
||||
sclk <= 1'b0;
|
||||
|
||||
//#################################
|
||||
//# RX/TX SHIFT REGISTER
|
||||
//#################################
|
||||
|
||||
always @ (posedge clk)
|
||||
if (tx_access)
|
||||
tx_shiftreg[PW-1:0] <= tx_data[PW-1:0];
|
||||
else if(baud_match)
|
||||
tx_shiftreg[PW-1:0] <= {tx_shiftreg[PW-2:0],miso};
|
||||
|
||||
assign mosi = tx_shiftreg[PW-1];
|
||||
|
||||
assign rx_data[7:0] = tx_shiftreg[7:0];
|
||||
|
||||
|
||||
oh_par2ser #(.PW(8),
|
||||
.SW(1))
|
||||
par2ser (// Outputs
|
||||
.dout (mosi), // serial output
|
||||
.access_out (),
|
||||
.wait_out (),
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.nreset (nreset), // async active low reset
|
||||
.din (fifo_dout[7:0]), // 8 bit data from fifo
|
||||
.shift (shift), // shift on neg edge
|
||||
.datasize (3'b111), // 8 bits
|
||||
.load (load_byte), // load data from fifo
|
||||
.lsbfirst (lsbfirst), // serializer direction
|
||||
.fill (miso), // fill with slave data
|
||||
.wait_in (1'b0) // no wait
|
||||
);
|
||||
|
||||
endmodule // spi_slave_io
|
||||
|
||||
// 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. //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
@ -7,16 +7,16 @@
|
||||
`include "spi_regmap.vh"
|
||||
module spi_master_regs (/*AUTOARG*/
|
||||
// Outputs
|
||||
tx_access, cmd_reg, tx_data, cpol, cpha, spi_en, psize_reg,
|
||||
clkdiv_reg, wait_out, access_out, packet_out,
|
||||
cpol, cpha, lsbfirst, emode, spi_en, clkdiv_reg, wait_out,
|
||||
access_out, packet_out,
|
||||
// Inputs
|
||||
clk, nreset, rx_data, rx_access, spi_state, access_in, packet_in,
|
||||
wait_in
|
||||
);
|
||||
|
||||
//parameters
|
||||
parameter CLKDIV = 16; // default clkdiv
|
||||
parameter PSIZE = 32; // default is 32 bits
|
||||
parameter CLKDIV = 1; // default clkdiv
|
||||
parameter PSIZE = 0; // default is 32 bits
|
||||
parameter AW = 32; // addresss width
|
||||
localparam PW = (2*AW+40); // packet width
|
||||
|
||||
@ -25,20 +25,17 @@ module spi_master_regs (/*AUTOARG*/
|
||||
input nreset; // async active low reset
|
||||
|
||||
//io interface
|
||||
output tx_access; // start the transfer
|
||||
output [7:0] cmd_reg; // first 8 bites to send
|
||||
output [PW-1:0] tx_data; // data payload
|
||||
|
||||
input [PW-1:0] rx_data; // rx data
|
||||
input rx_access; // rx access pulse
|
||||
|
||||
//control
|
||||
output cpol;
|
||||
output cpha;
|
||||
output cpha;
|
||||
output lsbfirst; // send lsbfirst
|
||||
output emode; // send emesh transaction
|
||||
output spi_en; // enable transmitter
|
||||
output [7:0] psize_reg; // packet size
|
||||
output [7:0] clkdiv_reg; // baud rate setting
|
||||
input [2:0] spi_state; // transmit state
|
||||
input [1:0] spi_state; // transmit state
|
||||
|
||||
//packet to transmit
|
||||
input access_in; // access from core
|
||||
@ -57,7 +54,7 @@ module spi_master_regs (/*AUTOARG*/
|
||||
reg [7:0] config_reg;
|
||||
reg [7:0] status_reg;
|
||||
reg [7:0] cmd_reg;
|
||||
reg [7:0] psize_reg;
|
||||
reg [31:0] psize_reg;
|
||||
reg [7:0] clkdiv_reg;
|
||||
reg [63:0] tx_reg[3:0];
|
||||
reg [7:0] rx_reg;
|
||||
@ -100,14 +97,7 @@ module spi_master_regs (/*AUTOARG*/
|
||||
|
||||
assign config_write = reg_write & (dstaddr_in[7:2]==`SPI_CONFIG);
|
||||
assign status_write = reg_write & (dstaddr_in[7:2]==`SPI_STATUS);
|
||||
assign cmd_write = reg_write & (dstaddr_in[7:2]==`SPI_CMD);
|
||||
assign psize_write = reg_write & (dstaddr_in[7:2]==`SPI_PSIZE);
|
||||
assign clkdiv_write = reg_write & (dstaddr_in[7:2]==`SPI_CLKDIV);
|
||||
assign tx_write = reg_write & (dstaddr_in[7:2]==`SPI_TX);
|
||||
assign tx_manualstart = reg_write & (dstaddr_in[7:2]==`SPI_START);
|
||||
|
||||
//autostart on write to lowest tx register
|
||||
assign tx_autostart = tx_write & (dstaddr_in[4:3]==2'b00);
|
||||
|
||||
//####################################
|
||||
//# CONFIG
|
||||
@ -119,15 +109,15 @@ module spi_master_regs (/*AUTOARG*/
|
||||
else if(config_write)
|
||||
config_reg[7:0] <= data_in[7:0];
|
||||
|
||||
assign spi_en = config_reg[0]; // enable spi
|
||||
assign irq_en = config_reg[1]; // enable interrupt
|
||||
assign cpol = config_reg[2]; // cpol
|
||||
assign cpha = config_reg[3]; // cpha
|
||||
assign auto_mode = config_reg[4]; // auto starts transfer on tx write
|
||||
|
||||
assign tx_access = auto_mode ? tx_autostart :
|
||||
tx_manualstart;
|
||||
|
||||
assign spi_en = config_reg[0]; // enable spi
|
||||
assign irq_en = config_reg[1]; // enable interrupt
|
||||
assign cpol = config_reg[2]; // cpol
|
||||
assign cpha = config_reg[3]; // cpha
|
||||
assign lsbfirst = config_reg[4]; // send lsb first
|
||||
assign manual_ss = config_reg[5]; // manually control ss pin
|
||||
assign rxauto_mode = config_reg[6]; // rx auto return mode
|
||||
assign emode = config_reg[7]; // emesh transfer mode
|
||||
|
||||
//####################################
|
||||
//# STATUS
|
||||
//####################################
|
||||
@ -138,21 +128,10 @@ module spi_master_regs (/*AUTOARG*/
|
||||
else if(status_write)
|
||||
status_reg[7:0] <= reg_wdata[7:0];
|
||||
else
|
||||
status_reg[7:0] <= {4'b0, //7:4
|
||||
spi_state[2:0], //3:1
|
||||
status_reg[7:0] <= {4'b0, //7:3
|
||||
spi_state[1:0], //2:1
|
||||
(rx_access | status_reg[0])};//0
|
||||
|
||||
|
||||
//####################################
|
||||
//# PSIZE (packet size)
|
||||
//####################################
|
||||
|
||||
always @ (posedge clk or negedge nreset)
|
||||
if (~nreset)
|
||||
psize_reg[7:0] <= PSIZE;
|
||||
else if(psize_write)
|
||||
psize_reg[7:0] <= reg_wdata[7:0];
|
||||
|
||||
|
||||
//####################################
|
||||
//# CLKDIV
|
||||
//####################################
|
||||
@ -160,16 +139,9 @@ module spi_master_regs (/*AUTOARG*/
|
||||
always @ (posedge clk or negedge nreset)
|
||||
if (~nreset)
|
||||
clkdiv_reg[7:0] <= CLKDIV;
|
||||
else if(psize_write)
|
||||
else if(clkdiv_write)
|
||||
clkdiv_reg[7:0] <= reg_wdata[7:0];
|
||||
|
||||
//####################################
|
||||
//# COMMAND REG
|
||||
//####################################
|
||||
always @ (posedge clk or negedge nreset)
|
||||
if(cmd_write)
|
||||
cmd_reg[7:0] <= reg_wdata[7:0];
|
||||
|
||||
|
||||
//####################################
|
||||
//# RX REG
|
||||
//####################################
|
||||
@ -177,30 +149,6 @@ module spi_master_regs (/*AUTOARG*/
|
||||
if(rx_access)
|
||||
rx_reg[7:0] <= rx_data[7:0];
|
||||
|
||||
//####################################
|
||||
//# TX REGS
|
||||
//####################################
|
||||
|
||||
//auto start on writing to lowest tx data register
|
||||
|
||||
|
||||
assign write_mask[63:0] = (datamode_in[1:0]==2'b00) ? 64'h00000000000000FF :
|
||||
(datamode_in[1:0]==2'b01) ? 64'h000000000000FFFF :
|
||||
(datamode_in[1:0]==2'b10) ? 64'h00000000FFFFFFFF :
|
||||
64'hFFFFFFFFFFFFFFFF;
|
||||
|
||||
always @ (posedge clk)
|
||||
for(i=0;i<64;i=i+1)
|
||||
if(tx_write & write_mask[i])
|
||||
tx_reg[dstaddr_in[4:3]][i] <= reg_wdata[i];
|
||||
|
||||
assign tx_vector[255:0]= {tx_reg[3],
|
||||
tx_reg[2],
|
||||
tx_reg[1],
|
||||
tx_reg[0]};
|
||||
//only taking
|
||||
assign tx_data[PW-1:0] = tx_vector[PW-1:0];
|
||||
|
||||
endmodule // spi_master_regs
|
||||
|
||||
// Local Variables:
|
||||
|
@ -3,14 +3,12 @@
|
||||
`define GPIO_REGMAP_V_
|
||||
`define SPI_CONFIG 6'd0 // config register
|
||||
`define SPI_STATUS 6'd1 // status register
|
||||
`define SPI_CMD 6'd2 // command register (first byte)
|
||||
`define SPI_PSIZE 6'd3 // package size (32 bits)
|
||||
`define SPI_CLKDIV 6'd4 // baud rate (master)
|
||||
`define SPI_START 6'd5 // manual transfer (master)
|
||||
`define SPI_JUNK 6'd6 // reserved
|
||||
`define SPI_JUNK 6'd7 // reserved
|
||||
`define SPI_TX 6'd8 // 4 regs for tx x 32
|
||||
`define SPI_RX 6'd12 // 4 regs for rx x 32
|
||||
`define SPI_CLKDIV 6'd2 // baud rate (master)
|
||||
`define SPI_CMD 6'd3 // manual ss control (master)
|
||||
`define SPI_RXADDR0 6'd4 // auto return address (31:0)
|
||||
`define SPI_RXADDR1 6'd6 // auto return address (63:32)
|
||||
`define SPI_TX 6'd8 // TX FIFO
|
||||
`define SPI_RX 6'd12 // RX FIFO
|
||||
|
||||
`endif // `ifndef GPIO_REGMAP_V_
|
||||
|
||||
|
@ -46,23 +46,31 @@ module spi_slave_io(/*AUTOARG*/
|
||||
//#################################
|
||||
|
||||
reg [2:0] spi_state;
|
||||
reg [7:0] bit_count;
|
||||
reg [PW-1:0] spi_rx;
|
||||
reg [7:0] bit_count;
|
||||
reg [PW-1:0] spi_tx;
|
||||
reg spi_access;
|
||||
reg packet_done_reg;
|
||||
reg spi_request;
|
||||
reg [PW-1:0] packet_out;
|
||||
wire [7:0] psize;
|
||||
|
||||
wire [PW-1:0] rx_data;
|
||||
|
||||
//#################################
|
||||
//# RX SHIFT REGISTER
|
||||
//#################################
|
||||
|
||||
always @ (posedge sclk)
|
||||
if(~ss)
|
||||
spi_rx[PW-1:0] <= {spi_rx[PW-2:0],mosi};
|
||||
|
||||
oh_ser2par #(.PW(PW),
|
||||
.SW(1))
|
||||
ser2par (// Outputs
|
||||
.dout (rx_data[PW-1:0]),
|
||||
// Inputs
|
||||
.clk (sclk),
|
||||
.din (mosi),
|
||||
.lsbfirst (1'b0), //msb first
|
||||
.shift (~ss)
|
||||
);
|
||||
|
||||
|
||||
//#################################
|
||||
//# STATE MACHINE
|
||||
//#################################
|
||||
@ -106,17 +114,18 @@ module spi_slave_io(/*AUTOARG*/
|
||||
else
|
||||
bit_count[7:0] <= bit_count[7:0] + 1'b1;
|
||||
|
||||
assign read_cmd = (spi_rx[7:6]==2'b10) &
|
||||
assign read_cmd = (rx_data[7:6]==2'b10) &
|
||||
(spi_state[2:0]==`SPI_CMD);
|
||||
|
||||
assign write_cmd = (spi_rx[7:6]==2'b00) &
|
||||
assign write_cmd = (rx_data[7:6]==2'b00) &
|
||||
(spi_state[2:0]==`SPI_CMD);
|
||||
|
||||
assign remote_cmd = (spi_rx[7:6]==2'b11) &
|
||||
assign remote_cmd = (rx_data[7:6]==2'b11) &
|
||||
(spi_state[2:0]==`SPI_CMD);
|
||||
|
||||
assign byte_done = &bit_count[2:0];
|
||||
|
||||
//change to sl?
|
||||
assign packet_done = (bit_count[7:0]==psize[7:0]);
|
||||
|
||||
//#################################
|
||||
@ -127,7 +136,7 @@ module spi_slave_io(/*AUTOARG*/
|
||||
|
||||
always @ (posedge sclk)
|
||||
if(load_tx)
|
||||
spi_tx[7:0] <= spi_regs[spi_rx[6:0]]; //
|
||||
spi_tx[7:0] <= spi_regs[rx_data[6:0]]; //
|
||||
else if(~ss)
|
||||
spi_tx[7:0] <= {spi_tx[6:0],1'b0};
|
||||
|
||||
@ -137,10 +146,10 @@ module spi_slave_io(/*AUTOARG*/
|
||||
//# REGISTER FILE INTERFACE
|
||||
//#################################
|
||||
assign spi_clk = sclk;
|
||||
assign spi_addr[5:0] = spi_rx[5:0];
|
||||
assign spi_addr[5:0] = rx_data[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];
|
||||
assign spi_data[7:0] = rx_data[7:0];
|
||||
|
||||
//#################################
|
||||
//# CLOCK SYNCHRONIZATION
|
||||
@ -173,9 +182,34 @@ module spi_slave_io(/*AUTOARG*/
|
||||
//sample rx data
|
||||
always @ (posedge clk)
|
||||
if(spi_access_pulse)
|
||||
packet_out[PW-1:0] <= spi_rx[PW-1:0];
|
||||
packet_out[PW-1:0] <= rx_data[PW-1:0];
|
||||
|
||||
endmodule // spi_slave_io
|
||||
// Local Variables:
|
||||
// verilog-library-directories:("." "../../common/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. //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -61,7 +61,6 @@ module spi_slave_regs (/*AUTOARG*/
|
||||
//#####################################
|
||||
|
||||
assign spi_config_write = spi_write & (spi_addr[5:0]==`SPI_CONFIG);
|
||||
assign spi_psize_write = spi_write & (spi_addr[5:0]==`SPI_PSIZE);
|
||||
assign spi_user_write = spi_write & (|spi_addr[5:4]);
|
||||
|
||||
//#####################################
|
||||
@ -108,17 +107,7 @@ module spi_slave_regs (/*AUTOARG*/
|
||||
//#####################################
|
||||
|
||||
//TBD
|
||||
|
||||
//#####################################
|
||||
//# PACKET SIZE [3]
|
||||
//#####################################
|
||||
|
||||
always @ (posedge spi_clk or negedge nreset)
|
||||
if(!nreset)
|
||||
spi_psize[7:0] <= PW;
|
||||
else if(spi_psize_write)
|
||||
spi_psize[7:0] <= spi_data[7:0];
|
||||
|
||||
|
||||
//#####################################
|
||||
//# CORE DATA [15:8]
|
||||
//#####################################
|
||||
@ -147,10 +136,10 @@ module spi_slave_regs (/*AUTOARG*/
|
||||
//8 standard regs
|
||||
spi_vector[7:0] = spi_config[7:0]; //0
|
||||
spi_vector[15:8] = spi_status[7:0]; //1
|
||||
spi_vector[23:16] = spi_cmd[7:0]; //2
|
||||
spi_vector[31:24] = spi_psize[7:0]; //3
|
||||
spi_vector[23:16] = 8'b0; //2
|
||||
spi_vector[31:24] = spi_cmd[7:0]; //3
|
||||
spi_vector[63:32] = 32'b0; //7:4
|
||||
spi_vector[127:64] = 64'b0; //15:8
|
||||
spi_vector[127:64] = 64'b0; //15:8
|
||||
//16 core data tx vector
|
||||
spi_vector[255:128] = core_regs[63:0];
|
||||
//16 core data rx vector
|
||||
@ -160,8 +149,6 @@ module spi_slave_regs (/*AUTOARG*/
|
||||
spi_vector[512+i*8 +:8] = user_regs[i];
|
||||
end
|
||||
|
||||
|
||||
|
||||
endmodule // spi_slave_regs
|
||||
|
||||
// Local Variables:
|
||||
|
Loading…
x
Reference in New Issue
Block a user