1 /* ****************************************************************************
\r
2 -- Source file: spi_byte2bit.v
\r
3 -- Date: June 1,2014
\r
5 -- Description: Simple interface to SPI that xfers Bytes to Bits.
\r
6 -- Supports read stalling of MISO stream.
\r
7 -- Language: Verilog-2001
\r
8 -- Simulation: Mentor-Modelsim
\r
9 -- Synthesis: Xilinst-XST
\r
10 -- License: This project is licensed with the CERN Open Hardware Licence
\r
11 -- v1.2. You may redistribute and modify this project under the
\r
12 -- terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl).
\r
13 -- This project is distributed WITHOUT ANY EXPRESS OR IMPLIED
\r
14 -- WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY
\r
15 -- AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL
\r
16 -- v.1.2 for applicable Conditions.
\r
21 -- xfer_start ------->| |
\r
22 -- xfer_tx_bytes[7:0]->| |
\r
23 -- xfer_rx_bytes[7:0]->| |
\r
24 -- mosi_byte_d[7:0]--->| |--> miso_byte_d[7:0]
\r
25 -- mosi_byte_en ------>| |--> miso_byte_rdy
\r
26 -- mosi_byte_req <-----| |
\r
28 -- spi_miso --->| |--> spi_mosi
\r
33 -- spi_sck _/\/\/\/\/\/\/\/\____/\/\/\/\/\/\/\/\/\/\/\/\/
\r
34 -- spi_cs_l \_________________________/
\r
35 -- spi_mosi -----------< B0 >----< B1 >------------------
\r
36 -- spi_miso --------------------------< B2 >< B3>------
\r
38 -- xfer_start_/ \_______________________________________
\r
39 -- xfer_stall___________________________________/ \_____
\r
40 -- tx_bytes -< 2 >---------------------------------------
\r
41 -- rx_bytes -< 2 >---------------------------------------
\r
43 -- mosi_byte_en __/ \__..._/ \_____
\r
44 -- mosi_byte_d[7:0] --<B0>--...-<B1>-----
\r
45 -- mosi_byte_req ______/ \_______
\r
47 -- miso_byte_rdy ________________________/ \___/ \__
\r
48 -- miso_byte_d[7:0] ------------------------<B2>---<B3>--
\r
51 -- Note: Starving the MOSI stream is allowed. The block will gate the SPI clock
\r
52 -- and wait until the MOSI byte arrives.
\r
54 -- Note: Stalling the MISO stream is allowed. Asserting xfer_stall will gate
\r
55 -- the entire block, allowing for the MISO stream to be stalled.
\r
57 -- Revision History:
\r
58 -- Ver# When Who What
\r
59 -- ---- -------- -------- --------------------------------------------------
\r
60 -- 0.1 06.01.14 khubbard Creation
\r
61 -- 0.1 06.25.14 khubbard Removed mosi_starved logic. Not worth complication
\r
62 -- 0.2 01.29.16 khubbard Fixed reset issue when ck_div is 0x00 at reset.
\r
63 -- ***************************************************************************/
\r
64 //`default_nettype none // Strictly enforce all nets to be declared
\r
66 module spi_byte2bit
\r
70 input wire [7:0] ck_divisor,
\r
71 input wire [3:0] spi_ctrl,
\r
74 output wire spi_cs_l,
\r
75 output reg spi_mosi,
\r
76 input wire spi_miso,
\r
77 output reg spi_is_idle,
\r
79 input wire xfer_start,
\r
80 input wire xfer_stall,
\r
81 input wire [11:0] xfer_tx_bytes,
\r
82 input wire [11:0] xfer_rx_bytes,
\r
84 input wire [7:0] mosi_byte_d,
\r
85 input wire mosi_byte_en,
\r
86 output wire mosi_byte_req,
\r
87 output reg mosi_err,
\r
89 output reg [7:0] miso_byte_d,
\r
90 output reg miso_byte_rdy
\r
105 wire [7:0] mosi_sr_loc;
\r
106 reg [7:0] mosi_byte_queue;
\r
107 reg mosi_queued_jk;
\r
109 reg mosi_byte_req_loc;
\r
110 reg mosi_byte_en_p1;
\r
113 reg [11:0] xfer_cnt;
\r
117 reg [4:0] xfer_rx_jk_sr;
\r
119 reg [11:0] xfer_length;
\r
120 reg [11:0] xfer_rx_length;
\r
121 wire [8:0] xfer_byte;
\r
122 wire [2:0] xfer_bit;
\r
123 reg [2:0] xfer_bit_p1;
\r
124 reg [2:0] xfer_bit_p2;
\r
125 reg [2:0] xfer_bit_p3;
\r
126 reg [2:0] xfer_bit_p4;
\r
128 //assign ck_div = 8'd10;
\r
129 assign ck_div = ck_divisor[7:0];// Num of clocks in 1/2 spi clock period
\r
132 //-----------------------------------------------------------------------------
\r
133 // Generate spi_ck. Counts 1/2 periods and toggles a bit.
\r
134 // ck _/ \_/ \_/ \_/ \_/ \_/ \_/
\r
136 // ck_loc _/ \_______/ \_
\r
137 // ck_en_ris _/ \___________/ \_____
\r
138 // ck_en_fal _________/ \___________/
\r
139 //-----------------------------------------------------------------------------
\r
140 always @ ( posedge clk ) begin : proc_spi_ck
\r
142 if ( xfer_stall == 0 ) begin
\r
146 // if ( ck_cnt != 8'hFF ) begin
\r
147 if ( 1 == 1 ) begin
\r
148 ck_cnt <= ck_cnt + 1;
\r
149 if ( ck_cnt == ck_div ) begin
\r
150 ck_loc <= ~ ck_loc;
\r
152 if ( ck_loc == 1 ) begin
\r
160 // ck_cnt <= ck_cnt[7:0];
\r
164 if ( reset == 1 ) begin
\r
170 end // proc_spi_ck
\r
173 //-----------------------------------------------------------------------------
\r
174 // Shift in the MISO data
\r
175 //-----------------------------------------------------------------------------
\r
176 always @ ( posedge clk ) begin : proc_miso_sr
\r
178 if ( xfer_stall == 0 ) begin
\r
179 // miso_byte_d <= 8'd0;
\r
180 miso_byte_rdy <= 0;
\r
181 // if ( ck_en_fal == 1 ) begin
\r
182 if ( ck_en_ris == 1 ) begin
\r
183 xfer_bit_p1 <= xfer_bit[2:0];
\r
184 xfer_bit_p2 <= xfer_bit_p1[2:0];
\r
185 xfer_bit_p3 <= xfer_bit_p2[2:0];
\r
186 xfer_bit_p4 <= xfer_bit_p3[2:0];
\r
187 if ( xfer_rx_jk == 1 || xfer_rx_jk_sr != 5'd0 ) begin
\r
188 miso_loc <= spi_miso;
\r
189 miso_sr[0] <= miso_loc;
\r
190 miso_sr[7:1] <= miso_sr[6:0];
\r
191 if ( xfer_bit_p4 == 3'd0 && xfer_rx_jk_sr[4] == 1 ) begin
\r
192 miso_byte_d <= miso_sr[7:0];
\r
193 miso_byte_rdy <= 1;
\r
198 if ( reset == 1 ) begin
\r
199 miso_byte_rdy <= 0;
\r
200 xfer_bit_p1 <= 3'd0;
\r
201 xfer_bit_p2 <= 3'd0;
\r
202 xfer_bit_p3 <= 3'd0;
\r
203 xfer_bit_p4 <= 3'd0;
\r
206 end // proc_miso_sr
\r
209 //-----------------------------------------------------------------------------
\r
210 // On rising edge of xfer_start_jk, load the number of bytes * 8bits into a
\r
211 // bit counter and start the counter. Count down to 0 then turn off xfer_tx_jk.
\r
212 // xfer_start __/ \_________________________/ \___
\r
213 // tx_bytes --<2>-------------------------<2>---
\r
214 // rx_bytes --<4>-------------------------<4>---
\r
215 // mosi -------<0><1>-----------------------
\r
216 // miso -------------<0><1><2><3>-----------
\r
217 // xfer_tx_jk _______/ \______________________
\r
218 // xfer_rx_jk _____________/ \__________
\r
219 //-----------------------------------------------------------------------------
\r
220 always @ ( posedge clk ) begin : proc_xfer_req
\r
222 if ( xfer_stall == 0 ) begin
\r
223 if ( xfer_start == 1 ) begin
\r
224 xfer_length <= xfer_tx_bytes[11:0];
\r
225 xfer_rx_length <= xfer_rx_bytes[11:0];
\r
228 if ( ck_en_fal == 1 ) begin
\r
231 xfer_tx_jk_p1 <= xfer_tx_jk;
\r
232 xfer_rx_jk_sr[0] <= xfer_rx_jk;
\r
233 xfer_rx_jk_sr[4:1] <= xfer_rx_jk_sr[3:0];
\r
234 if ( xfer_start_jk != 0 ) begin
\r
235 xfer_cnt <= { xfer_length[8:0] , 3'b000 };
\r
237 end else if ( xfer_cnt != 12'd0 ) begin
\r
238 if ( xfer_tx_jk == 1 ) begin
\r
239 if ( xfer_bit == 2'd0 ) begin
\r
240 if ( mosi_queued_jk == 1 ) begin
\r
241 mosi_load <= 1; // Time for a new Byte
\r
243 mosi_err <= 1; // Nothing to send.
\r
246 xfer_cnt <= xfer_cnt - 1;
\r
247 if ( xfer_cnt == 12'd1 ) begin
\r
249 if ( xfer_rx_length[8:0] != 9'd0 ) begin
\r
251 xfer_cnt <= { xfer_rx_length[8:0] , 3'b000 };
\r
254 end else if ( xfer_rx_jk == 1 ) begin
\r
255 xfer_cnt <= xfer_cnt - 1;
\r
256 if ( xfer_cnt == 12'd1 ) begin
\r
263 if ( reset == 1 ) begin
\r
268 xfer_tx_jk_p1 <= 0;
\r
269 xfer_rx_jk_sr <= 5'd0;
\r
273 end // proc_xfer_req
\r
274 assign xfer_byte[8:0] = xfer_cnt[11:3];
\r
275 assign xfer_bit[2:0] = xfer_cnt[2:0];
\r
278 //-----------------------------------------------------------------------------
\r
279 // Latch the MOSI byte data and start shifting out
\r
280 //-----------------------------------------------------------------------------
\r
281 always @ ( posedge clk ) begin : proc_mosi_sr
\r
283 if ( xfer_stall == 0 ) begin
\r
285 mosi_byte_en_p1 <= mosi_byte_en;
\r
286 if ( ck_en_fal == 1 ) begin
\r
287 xfer_start_jk <= 0;
\r
290 // When new mosi byte comes in, place in queue and drop request
\r
291 if ( mosi_byte_en == 1 ) begin
\r
292 xfer_start_jk <= ~ xfer_tx_jk; // A new Xfer
\r
293 mosi_byte_queue <= mosi_byte_d[7:0];
\r
294 mosi_queued_jk <= 1;
\r
295 mosi_byte_req_loc <= 0;
\r
296 // Assert refused if not expecting a byte.
\r
297 if ( xfer_tx_jk == 1 ) begin
\r
298 mosi_refused <= ~ mosi_byte_req_loc;
\r
300 end // if ( mosi_byte_en == 1 ) begin
\r
302 if ( mosi_loaded == 1 || xfer_start == 1 ) begin
\r
303 mosi_byte_queue <= 8'd0;
\r
304 mosi_queued_jk <= 0;
\r
305 if ( xfer_byte != 9'd0 || xfer_start == 1 ) begin
\r
306 mosi_byte_req_loc <= 1;
\r
310 if ( reset == 1 ) begin
\r
311 mosi_queued_jk <= 0;
\r
312 mosi_byte_req_loc <= 0;
\r
313 xfer_start_jk <= 0;
\r
314 end // if ( reset == 1 ) begin
\r
317 end // proc_mosi_sr
\r
319 assign mosi_sr_loc[7:0] = mosi_sr[7:0];
\r
320 assign mosi_byte_req = mosi_byte_req_loc;
\r
323 //-----------------------------------------------------------------------------
\r
324 // Either Latch a new MOSI byte or shift existing byte
\r
325 //-----------------------------------------------------------------------------
\r
326 always @ ( posedge clk ) begin : proc_mosi_shift
\r
328 if ( xfer_stall == 0 ) begin
\r
330 if ( ck_en_fal == 1 ) begin
\r
331 if ( mosi_load == 1 ) begin
\r
332 mosi_sr <= mosi_byte_queue[7:0];
\r
335 mosi_sr <= { mosi_sr[6:0], 1'd0 }; // Shift the Byte Out
\r
337 end // if ( ck_en_fal == 1 ) begin
\r
338 if ( reset == 1 ) begin
\r
343 end // proc mosi_shift
\r
346 //-----------------------------------------------------------------------------
\r
347 // SPI Master Output : The serial bits.
\r
348 //-----------------------------------------------------------------------------
\r
349 always @ ( posedge clk ) begin : proc_mosi_out
\r
351 if ( xfer_stall == 0 ) begin
\r
352 if ( spi_ctrl[0] == 0 ) begin
\r
353 spi_sck <= ck_loc & ~ ck_off;
\r
355 spi_sck <= ~ ck_loc & ~ ck_off;
\r
358 // if ( ck_en_fal == 1 ) begin
\r
359 if ( ( ck_en_fal == 1 && spi_ctrl[1] == 0 ) ||
\r
360 ( ck_en_ris == 1 && spi_ctrl[1] == 1 ) ) begin
\r
361 ck_off <= ck_off_pre;
\r
362 spi_cs_pre <= xfer_tx_jk_p1 | xfer_rx_jk_sr[0];
\r
363 spi_cs_l_loc <= ~ spi_cs_pre;
\r
364 spi_is_idle <= ~ spi_cs_pre;
\r
365 spi_mosi <= mosi_sr_loc[7];
\r
366 if ( spi_cs_pre == 0 &&
\r
367 xfer_tx_jk_p1 == 0 &&
\r
368 xfer_rx_jk_sr[0] == 0 ) begin
\r
375 end // if ( xfer_stall == 0 ) begin
\r
376 if ( reset == 1 ) begin
\r
383 end // proc_mosi_out
\r
384 assign spi_cs_l = spi_cs_l_loc;
\r
387 endmodule // spi_byte2bit
\r