blob: e8a6494a0e1b99e81dc16e336b21e71548921ca1 [file] [log] [blame]
Tim Edwards04ba17f2020-10-02 22:27:50 -04001//------------------------------------------------------
2// caravel_spi_slave.v
3//------------------------------------------------------
4// General purpose SPI slave module for the Caravel chip
5//------------------------------------------------------
6// Written by Tim Edwards
7// efabless, inc., September 28, 2020
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// 11000100 Pass-through read/write to management area flash SPI until CSB raised
34// 11000101 Pass-through read/write to user area flash SPI until CSB raised
35// wrnnn000 Read/write as above, for nnn = 1 to 7 bytes, then terminate
36
37// Lower three bits are reserved for future use.
38// All serial bytes are read and written msb first.
39
40// Fixed control and status registers
41
42// Address 0 is reserved and contains flags for SPI mode. This is
43// currently undefined and is always value 0.
44// Address 1 is reserved and contains manufacturer ID low 8 bits.
45// Address 2 is reserved and contains manufacturer ID high 4 bits.
46// Address 3 is reserved and contains product ID (8 bits).
47// Addresses 4 to 7 are reserved and contain the mask ID (32 bits).
48// Addresses 8 to 255 are available for general purpose use.
49
50`define COMMAND 3'b000
51`define ADDRESS 3'b001
52`define DATA 3'b010
53`define USERPASS 3'b100
54`define MGMTPASS 3'b101
55
56module caravel_spi_slave(reset, SCK, SDI, CSB, SDO,
57 sdoenb, idata, odata, oaddr, rdstb, wrstb,
58 pass_thru_mgmt, pass_thru_mgmt_delay,
59 pass_thru_user, pass_thru_user_delay, pass_thru_reset);
60
61 input reset;
62 input SCK;
63 input SDI;
64 input CSB;
65 output SDO;
66 output sdoenb;
67 input [7:0] idata;
68 output [7:0] odata;
69 output [7:0] oaddr;
70 output rdstb;
71 output wrstb;
72 output pass_thru_mgmt;
73 output pass_thru_mgmt_delay;
74 output pass_thru_user;
75 output pass_thru_user_delay;
76 output pass_thru_reset;
77
78 reg [7:0] addr;
79 reg wrstb;
80 reg rdstb;
81 reg sdoenb;
82 reg [2:0] state;
83 reg [2:0] count;
84 reg writemode;
85 reg readmode;
86 reg [2:0] fixed;
87 wire [7:0] odata;
88 reg [6:0] predata;
89 wire [7:0] oaddr;
90 reg [7:0] ldata;
91 reg pass_thru_mgmt;
92 reg pass_thru_mgmt_delay;
93 reg pre_pass_thru_mgmt;
94 reg pass_thru_user;
95 reg pass_thru_user_delay;
96 reg pre_pass_thru_user;
97 wire csb_reset;
98
99 assign odata = {predata, SDI};
100 assign oaddr = (state == `ADDRESS) ? {addr[6:0], SDI} : addr;
101 assign SDO = ldata[7];
102 assign csb_reset = CSB | reset;
103 assign pass_thru_reset = pass_thru_mgmt_delay | pre_pass_thru_mgmt;
104
105 // Readback data is captured on the falling edge of SCK so that
106 // it is guaranteed valid at the next rising edge.
107 always @(negedge SCK or posedge CSB) begin
108 if (CSB == 1'b1) begin
109 wrstb <= 1'b0;
110 ldata <= 8'b00000000;
111 sdoenb <= 1'b1;
112 end else begin
113
114 // After CSB low, 1st SCK starts command
115
116 if (state == `DATA) begin
117 if (readmode == 1'b1) begin
118 sdoenb <= 1'b0;
119 if (count == 3'b000) begin
120 ldata <= idata;
121 end else begin
122 ldata <= {ldata[6:0], 1'b0}; // Shift out
123 end
124 end else begin
125 sdoenb <= 1'b1;
126 end
127
128 // Apply write strobe on SCK negative edge on the next-to-last
129 // data bit so that it updates data on the rising edge of SCK
130 // on the last data bit.
131
132 if (count == 3'b111) begin
133 if (writemode == 1'b1) begin
134 wrstb <= 1'b1;
135 end
136 end else begin
137 wrstb <= 1'b0;
138 end
139 end else if (state == `MGMTPASS || state == `USERPASS) begin
140 wrstb <= 1'b0;
141 sdoenb <= 1'b0;
142 end else begin
143 wrstb <= 1'b0;
144 sdoenb <= 1'b1;
145 end // ! state `DATA
146 end // ! CSB
147 end // always @ ~SCK
148
149 always @(posedge SCK or posedge CSB) begin
150 if (csb_reset == 1'b1) begin
151 // Default state on reset
152 addr <= 8'h00;
153 rdstb <= 1'b0;
154 predata <= 7'b0000000;
155 state <= `COMMAND;
156 count <= 3'b000;
157 readmode <= 1'b0;
158 writemode <= 1'b0;
159 fixed <= 3'b000;
160 pass_thru_mgmt <= 1'b0;
161 pass_thru_mgmt_delay <= 1'b0;
162 pre_pass_thru_mgmt <= 1'b0;
163 pass_thru_user = 1'b0;
164 pass_thru_user_delay <= 1'b0;
165 pre_pass_thru_user <= 1'b0;
166 end else begin
167 // After CSB low, 1st SCK starts command
168 if (state == `COMMAND) begin
169 rdstb <= 1'b0;
170 count <= count + 1;
171 if (count == 3'b000) begin
172 writemode <= SDI;
173 end else if (count == 3'b001) begin
174 readmode <= SDI;
175 end else if (count < 3'b101) begin
176 fixed <= {fixed[1:0], SDI};
177 end else if (count < 3'b110) begin
178 pass_thru_mgmt_delay <= pre_pass_thru_mgmt;
179 pass_thru_user_delay <= pre_pass_thru_user;
180 end else if (count == 3'b111) begin
181 if (pre_pass_thru_mgmt == 1'b1) begin
182 state <= `MGMTPASS;
183 pre_pass_thru_mgmt <= 1'b0;
184 end else if (pre_pass_thru_user == 1'b1) begin
185 state <= `USERPASS;
186 pre_pass_thru_user <= 1'b0;
187 end else begin
188 state <= `ADDRESS;
189 end
190 end
191 end else if (state == `ADDRESS) begin
192 count <= count + 1;
193 addr <= {addr[6:0], SDI};
194 if (count == 3'b111) begin
195 if (readmode == 1'b1) begin
196 rdstb <= 1'b1;
197 end
198 state <= `DATA;
199 end else begin
200 rdstb <= 1'b0;
201 end
202 end else if (state == `DATA) begin
203 predata <= {predata[6:0], SDI};
204 count <= count + 1;
205 if (count == 3'b111) begin
206 if (fixed == 3'b001) begin
207 state <= `COMMAND;
208 end else if (fixed != 3'b000) begin
209 fixed <= fixed - 1;
210 addr <= addr + 1; // Auto increment address (fixed)
211 end else begin
212 addr <= addr + 1; // Auto increment address (streaming)
213 end
214 end else begin
215 rdstb <= 1'b0;
216 end
217 end // ! state `DATA
218 end // ! CSB
219 end // always @ SCK
220
221endmodule // caravel_spi_slave