blob: 50a6520984e7995ecdcda220eab9b063b77418ec [file] [log] [blame]
Tim Edwardscd64af52020-08-07 11:11:58 -04001//------------------------------------------------
2// spi_slave.v
3//------------------------------------------------
4// General purpose SPI slave module
5//------------------------------------------------
6// Written by Tim Edwards
7// efabless, inc., april 23, 2017
8//------------------------------------------------
9// This file is distributed free and open source
10//------------------------------------------------
11
12// SCK --- Clock input
13// SDI --- Data input
14// SDO --- Data output
15// CSB --- Chip select (sense negative)
16// idata --- Data from chip to transmit out, in 8 bits
17// odata --- Input data to chip, in 8 bits
18// addr --- Decoded address to upstream circuits
19// rdstb --- Read strobe, tells upstream circuit to supply next byte to idata
20// wrstb --- Write strobe, tells upstream circuit to latch odata.
21
22// Data format (general purpose):
23// 8 bit format
24// 1st byte: Command word (see below)
25// 2nd byte: Address word (register 0 to 255)
26// 3rd byte: Data word (value 0 to 255)
27
28// Command format:
29// 00000000 No operation
30// 10000000 Write until CSB raised
31// 01000000 Read until CSB raised
32// 11000000 Simultaneous read/write until CSB raised
33// wrnnn000 Read/write as above, for nnn = 1 to 7 bytes, then terminate
34
35// Lower three bits are reserved for future use.
36// All serial bytes are read and written msb first.
37
38// Fixed control and status registers
39
40// Address 0 is reserved and contains flags for SPI mode. This is
41// currently undefined and is always value 0.
42// Address 1 is reserved and contains manufacturer ID low 8 bits.
43// Address 2 is reserved and contains manufacturer ID high 4 bits
44// and mask revision number (4 bits).
45// Address 3 is reserved and contains product ID (8 bits).
46// Addresses 4 to 255 are available for general purpose use.
47
48`define COMMAND 2'b00
49`define ADDRESS 2'b01
50`define DATA 2'b10
51`define IDLE 2'b11 // Not used
52
53module spi_slave(SCK, SDI, CSB, SDO, sdoenb, idata, odata, oaddr, rdstb, wrstb);
54 input SCK;
55 input SDI;
56 input CSB;
57 output SDO;
58 output sdoenb;
59 input [7:0] idata;
60 output [7:0] odata;
61 output [7:0] oaddr;
62 output rdstb;
63 output wrstb;
64
65 reg [7:0] addr;
66 reg wrstb;
67 reg rdstb;
68 reg sdoenb;
69 reg [1:0] state;
70 reg [2:0] count;
71 reg writemode;
72 reg readmode;
73 reg [2:0] fixed;
74 wire [7:0] odata;
75 reg [6:0] predata;
76 wire [7:0] oaddr;
77 reg [7:0] ldata;
78
79 assign odata = {predata, SDI};
80 assign oaddr = (state == `ADDRESS) ? {addr[6:0], SDI} : addr;
81 assign SDO = ldata[7];
82
83 // Readback data is captured on the falling edge of SCK so that
84 // it is guaranteed valid at the next rising edge.
85 always @(negedge SCK or posedge CSB) begin
86 if (CSB == 1'b1) begin
87 wrstb <= 1'b0;
88 ldata <= 8'b00000000;
89 sdoenb <= 1'b1;
90 end else begin
91
92 // After CSB low, 1st SCK starts command
93
94 if (state == `DATA) begin
95 if (readmode == 1'b1) begin
96 sdoenb <= 1'b0;
97 if (count == 3'b000) begin
98 ldata <= idata;
99 end else begin
100 ldata <= {ldata[6:0], 1'b0}; // Shift out
101 end
102 end else begin
103 sdoenb <= 1'b1;
104 end
105
106 // Apply write strobe on SCK negative edge on the next-to-last
107 // data bit so that it updates data on the rising edge of SCK
108 // on the last data bit.
109
110 if (count == 3'b111) begin
111 if (writemode == 1'b1) begin
112 wrstb <= 1'b1;
113 end
114 end else begin
115 wrstb <= 1'b0;
116 end
117 end else begin
118 wrstb <= 1'b0;
119 sdoenb <= 1'b1;
120 end // ! state `DATA
121 end // ! CSB
122 end // always @ ~SCK
123
124 always @(posedge SCK or posedge CSB) begin
125 if (CSB == 1'b1) begin
126 // Default state on reset
127 addr <= 8'h00;
128 rdstb <= 1'b0;
129 predata <= 7'b0000000;
130 state <= `COMMAND;
131 count <= 3'b000;
132 readmode <= 1'b0;
133 writemode <= 1'b0;
134 fixed <= 3'b000;
135 end else begin
136 // After CSB low, 1st SCK starts command
137 if (state == `COMMAND) begin
138 rdstb <= 1'b0;
139 count <= count + 1;
140 if (count == 3'b000) begin
141 writemode <= SDI;
142 end else if (count == 3'b001) begin
143 readmode <= SDI;
144 end else if (count < 3'b101) begin
145 fixed <= {fixed[1:0], SDI};
146 end else if (count == 3'b111) begin
147 state <= `ADDRESS;
148 end
149 end else if (state == `ADDRESS) begin
150 count <= count + 1;
151 addr <= {addr[6:0], SDI};
152 if (count == 3'b111) begin
153 if (readmode == 1'b1) begin
154 rdstb <= 1'b1;
155 end
156 state <= `DATA;
157 end else begin
158 rdstb <= 1'b0;
159 end
160 end else if (state == `DATA) begin
161 predata <= {predata[6:0], SDI};
162 count <= count + 1;
163 if (count == 3'b111) begin
164 if (fixed == 3'b001) begin
165 state <= `COMMAND;
166 end else if (fixed != 3'b000) begin
167 fixed <= fixed - 1;
168 addr <= addr + 1; // Auto increment address (fixed)
169 end else begin
170 addr <= addr + 1; // Auto increment address (streaming)
171 end
172 end else begin
173 rdstb <= 1'b0;
174 end
175 end // ! state `DATA
176 end // ! CSB
177 end // always @ SCK
178
179endmodule // spi_slave