URL
https://opencores.org/ocsvn/tiny_spi/tiny_spi/trunk
Subversion Repositories tiny_spi
Compare Revisions
- This comparison shows the changes necessary to convert path
/tiny_spi/trunk
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/rtl/verilog/tiny_spi.v
0,0 → 1,232
////////////////////////////////////////////////////////////////////// |
//// //// |
//// tiny_spi.v //// |
//// //// |
//// This file is part of the TINY SPI IP core project //// |
//// http://www.opencores.org/projects/tiny_spi/ //// |
//// //// |
//// Author(s): //// |
//// - Thomas Chou <thomas@wytron.com.tw> //// |
//// //// |
//// All additional information is avaliable in the README //// |
//// file. //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2010 Authors //// |
//// //// |
//// 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 tiny_spi( |
// system |
input rst_i, |
input clk_i, |
// memory mapped |
input stb_i, |
input we_i, |
output [31:0] dat_o, |
input [31:0] dat_i, |
output int_o, |
input [2:0] adr_i, |
input cyc_i, // comment out for avalon |
output ack_o, // comment out for avalon |
|
// spi |
output MOSI, |
output SCLK, |
input MISO |
); |
|
parameter BAUD_WIDTH = 8; |
parameter BAUD_DIV = 0; |
parameter SPI_MODE = 0; |
parameter BC_WIDTH = 3; |
parameter DIV_WIDTH = BAUD_DIV ? $clog2(BAUD_DIV / 2 - 1) : BAUD_WIDTH; |
|
|
reg [7:0] sr8, bb8; |
wire [7:0] sr8_sf; |
reg [BC_WIDTH - 1:0] bc, bc_next; |
reg [DIV_WIDTH - 1:0] ccr; |
reg [DIV_WIDTH - 1:0] cc, cc_next; |
wire misod; |
wire cstb, wstb, bstb, istb; |
reg sck; |
reg sf, ld; |
reg bba; // buffer flag |
reg txren, txeen; |
wire txr, txe; |
wire cpol, cpha; |
reg cpolr, cphar; |
wire wr; |
// wire cyc_i; // comment out for wishbone |
// wire ack_o; // comment out for wishbone |
// assign cyc_i = 1'b1; // comment out for wishbone |
assign ack_o = stb_i & cyc_i; // zero wait |
assign wr = stb_i & cyc_i & we_i & ack_o; |
assign wstb = wr & (adr_i == 1); |
assign istb = wr & (adr_i == 2); |
assign cstb = wr & (adr_i == 3); |
assign bstb = wr & (adr_i == 4); |
assign sr8_sf = { sr8[6:0],misod }; |
assign dat_o = |
(sr8 & {8{(adr_i == 0)}}) |
| (bb8 & {8{(adr_i == 1)}}) |
| ({ txr, txe } & {8{(adr_i == 2)}}) |
; |
|
parameter |
IDLE = 0, |
PHASE1 = 1, |
PHASE2 = 2 |
; |
|
reg [1:0] spi_seq, spi_seq_next; |
always @(posedge clk_i or posedge rst_i) |
if (rst_i) |
spi_seq <= IDLE; |
else |
spi_seq <= spi_seq_next; |
|
always @(posedge clk_i) |
begin |
cc <= cc_next; |
bc <= bc_next; |
end |
|
always @(/*AS*/bba or bc or cc or ccr or cpha or cpol or spi_seq) |
begin |
sck = cpol; |
cc_next = BAUD_DIV ? (BAUD_DIV / 2 - 1) : ccr; |
bc_next = bc; |
ld = 1'b0; |
sf = 1'b0; |
|
case (spi_seq) |
IDLE: |
begin |
if (bba) |
begin |
bc_next = 7; |
ld = 1'b1; |
spi_seq_next = PHASE2; |
end |
else |
spi_seq_next = IDLE; |
end |
PHASE2: |
begin |
sck = (cpol ^ cpha); |
if (cc == 0) |
spi_seq_next = PHASE1; |
else |
begin |
cc_next = cc - 1; |
spi_seq_next = PHASE2; |
end |
end |
PHASE1: |
begin |
sck = ~(cpol ^ cpha); |
if (cc == 0) |
begin |
bc_next = bc -1; |
sf = 1'b1; |
if (bc == 0) |
begin |
if (bba) |
begin |
bc_next = 7; |
ld = 1'b1; |
spi_seq_next = PHASE2; |
end |
else |
spi_seq_next = IDLE; |
end |
else |
spi_seq_next = PHASE2; |
end |
else |
begin |
cc_next = cc - 1; |
spi_seq_next = PHASE1; |
end |
end |
endcase |
end // always @ (... |
|
always @(posedge clk_i) |
begin |
if (cstb) // control reg |
{ cpolr, cphar } <= dat_i; |
else |
{ cpolr, cphar } <= { cpolr, cphar }; |
|
if (istb) // irq enable reg |
{ txren, txeen } <= dat_i; |
else |
{ txren, txeen } <= { txren, txeen }; |
|
if (bstb) // baud reg |
ccr <= dat_i; |
else |
ccr <= ccr; |
|
if (ld) // shift reg |
sr8 <= bb8; |
else if (sf) |
sr8 <= sr8_sf; |
else |
sr8 <= sr8; |
|
if (wstb) // buffer reg |
bb8 <= dat_i; |
else if (ld) |
bb8 <= (spi_seq == IDLE) ? sr8 : sr8_sf; |
else |
bb8 <= bb8; |
end // always @ (posedge clk_i) |
|
always @(posedge clk_i or posedge rst_i) |
begin |
if (rst_i) |
bba <= 1'b0; |
else if (wstb) |
bba <= 1'b1; |
else if (ld) |
bba <= 1'b0; |
else |
bba <= bba; |
end |
|
assign { cpol, cpha } = ((SPI_MODE >= 0) & (SPI_MODE < 4)) ? |
SPI_MODE : { cpolr, cphar }; |
assign txe = (spi_seq == IDLE); |
assign txr = ~bba; |
assign int_o = (txr & txren) | (txe & txeen); |
assign SCLK = sck; |
assign MOSI = sr8[7]; |
assign misod = MISO; |
|
endmodule |