991124d8786e9f027a3f11fdfcc67b4ed4e65ec2
[BML_sump2] / sump2 / source / spi_byte2bit.v
1 /* ****************************************************************************\r
2 -- Source file: spi_byte2bit.v\r
3 -- Date:        June 1,2014   \r
4 -- Author:      khubbard\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
17 --\r
18 --                                 spi_byte2bit     \r
19 --                                 ----------\r
20 --            clk        -------->|          |\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
27 --                                |          |\r
28 --                   spi_miso --->|          |--> spi_mosi\r
29 --                                |          |--> spi_sck \r
30 --                                |          |--> spi_cs_l\r
31 --                                 ----------\r
32 --\r
33 -- spi_sck    _/\/\/\/\/\/\/\/\____/\/\/\/\/\/\/\/\/\/\/\/\/\r
34 -- spi_cs_l              \_________________________/\r
35 -- spi_mosi   -----------< B0 >----< B1 >------------------\r
36 -- spi_miso   --------------------------< B2 >< B3>------\r
37 --\r
38 -- xfer_start_/   \_______________________________________\r
39 -- xfer_stall___________________________________/   \_____\r
40 -- tx_bytes  -< 2 >---------------------------------------\r
41 -- rx_bytes  -< 2 >---------------------------------------\r
42 --\r
43 -- mosi_byte_en     __/  \__..._/  \_____\r
44 -- mosi_byte_d[7:0] --<B0>--...-<B1>-----\r
45 -- mosi_byte_req   ______/      \_______\r
46 --\r
47 -- miso_byte_rdy    ________________________/  \___/  \__\r
48 -- miso_byte_d[7:0] ------------------------<B2>---<B3>--\r
49 -- \r
50 -- \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
53 --\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
56 --\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
65 \r
66 module spi_byte2bit \r
67 (\r
68   input  wire         reset,\r
69   input  wire         clk,\r
70   input  wire [7:0]   ck_divisor,\r
71   input  wire [3:0]   spi_ctrl,\r
72 \r
73   output reg          spi_sck,\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
78 \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
83 \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
88 \r
89   output reg  [7:0]   miso_byte_d,\r
90   output reg          miso_byte_rdy\r
91 );\r
92 \r
93   reg  [7:0]              ck_cnt;\r
94   wire [7:0]              ck_div;\r
95   reg                     ck_loc;\r
96   reg                     ck_off_pre;\r
97   reg                     ck_off;\r
98   reg                     ck_en_fal;\r
99   reg                     ck_en_ris;\r
100   reg                     spi_cs_pre;\r
101   reg                     spi_cs_l_loc;\r
102   reg                     mosi_load;\r
103   reg                     mosi_loaded;\r
104   reg  [7:0]              mosi_sr;\r
105   wire [7:0]              mosi_sr_loc;\r
106   reg  [7:0]              mosi_byte_queue;\r
107   reg                     mosi_queued_jk;\r
108   reg                     mosi_refused;\r
109   reg                     mosi_byte_req_loc;\r
110   reg                     mosi_byte_en_p1;\r
111   reg                     miso_loc;\r
112   reg  [7:0]              miso_sr;\r
113   reg  [11:0]             xfer_cnt;\r
114   reg                     xfer_tx_jk;\r
115   reg                     xfer_tx_jk_p1;\r
116   reg                     xfer_rx_jk;\r
117   reg  [4:0]              xfer_rx_jk_sr;\r
118   reg                     xfer_start_jk;\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
127 \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
130 \r
131 \r
132 //-----------------------------------------------------------------------------\r
133 // Generate spi_ck. Counts 1/2 periods and toggles a bit.       \r
134 //   ck         _/ \_/ \_/ \_/ \_/ \_/ \_/\r
135 //   cnt          1   2   1   2   1   2\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
141  begin\r
142   if ( xfer_stall == 0 ) begin\r
143     ck_en_fal     <= 0;\r
144     ck_en_ris     <= 0;\r
145     // Clock Divider\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
151         ck_cnt <= 8'h1;\r
152         if ( ck_loc == 1 ) begin\r
153           ck_en_fal <= 1;\r
154         end else begin\r
155           ck_en_ris <= 1;\r
156         end\r
157       end\r
158     end\r
159 //  end else begin\r
160 //    ck_cnt <= ck_cnt[7:0];\r
161 //    ck_loc <= 0;\r
162 //  end\r
163   \r
164     if ( reset == 1 ) begin\r
165       ck_cnt <= 8'd1;\r
166       ck_loc <= 0;\r
167     end\r
168   end\r
169  end\r
170 end // proc_spi_ck   \r
171 \r
172 \r
173 //-----------------------------------------------------------------------------\r
174 // Shift in the MISO data\r
175 //-----------------------------------------------------------------------------\r
176 always @ ( posedge clk ) begin : proc_miso_sr  \r
177  begin\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
194         end\r
195      end\r
196    end \r
197   end \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
204    end\r
205  end\r
206 end // proc_miso_sr\r
207 \r
208 \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
221  begin\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
226    end\r
227 \r
228    if ( ck_en_fal == 1 ) begin\r
229      mosi_err           <= 0;\r
230      mosi_load          <= 0; \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
236        xfer_tx_jk  <= 1;\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
242            end else begin\r
243              mosi_err <= 1; // Nothing to send.\r
244            end\r
245          end\r
246          xfer_cnt <= xfer_cnt - 1;\r
247          if ( xfer_cnt == 12'd1 ) begin\r
248            xfer_tx_jk <= 0;\r
249            if ( xfer_rx_length[8:0] != 9'd0 ) begin\r
250              xfer_rx_jk <= 1;\r
251              xfer_cnt   <= { xfer_rx_length[8:0] , 3'b000 };\r
252            end\r
253          end\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
257            xfer_rx_jk <= 0;\r
258          end\r
259        end\r
260      end\r
261    end\r
262 \r
263    if ( reset == 1 ) begin\r
264      mosi_load       <= 0;\r
265      xfer_cnt        <= 12'd0;\r
266      xfer_tx_jk      <= 0;\r
267      xfer_rx_jk      <= 0;\r
268      xfer_tx_jk_p1   <= 0;\r
269      xfer_rx_jk_sr   <= 5'd0;\r
270    end \r
271   end \r
272  end\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
276 \r
277 \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
282  begin\r
283   if ( xfer_stall == 0 ) begin\r
284    mosi_refused    <= 0;\r
285    mosi_byte_en_p1 <= mosi_byte_en;\r
286    if ( ck_en_fal == 1 ) begin\r
287      xfer_start_jk <= 0;\r
288    end \r
289 \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
299      end\r
300    end // if ( mosi_byte_en == 1 ) begin\r
301 \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
307      end\r
308    end \r
309 \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
315   end\r
316  end\r
317 end // proc_mosi_sr \r
318 \r
319   assign mosi_sr_loc[7:0] = mosi_sr[7:0];\r
320   assign mosi_byte_req = mosi_byte_req_loc;\r
321 \r
322 \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
327  begin\r
328   if ( xfer_stall == 0 ) begin\r
329    mosi_loaded <= 0;\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
333        mosi_loaded <= 1;\r
334      end else begin\r
335        mosi_sr <= { mosi_sr[6:0], 1'd0 }; // Shift the Byte Out\r
336      end\r
337    end // if ( ck_en_fal == 1 ) begin\r
338    if ( reset == 1 ) begin\r
339      mosi_sr <= 8'd0;\r
340    end \r
341   end \r
342  end\r
343 end // proc mosi_shift\r
344 \r
345 \r
346 //-----------------------------------------------------------------------------\r
347 // SPI Master Output : The serial bits.\r
348 //-----------------------------------------------------------------------------\r
349 always @ ( posedge clk ) begin : proc_mosi_out\r
350  begin\r
351   if ( xfer_stall == 0 ) begin\r
352    if ( spi_ctrl[0] == 0 ) begin\r
353      spi_sck     <= ck_loc & ~ ck_off;\r
354    end else begin\r
355      spi_sck     <= ~ ck_loc & ~ ck_off;\r
356    end\r
357                              \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
369         ck_off_pre <= 1;\r
370       end else begin\r
371         ck_off_pre <= 0;\r
372         ck_off     <= 0;\r
373       end\r
374     end\r
375   end // if ( xfer_stall == 0 ) begin\r
376   if ( reset == 1 ) begin\r
377     ck_off_pre   <= 0;\r
378     ck_off       <= 0;\r
379     spi_cs_pre   <= 0;\r
380     spi_cs_l_loc <= 1;\r
381   end\r
382  end\r
383 end // proc_mosi_out\r
384   assign spi_cs_l = spi_cs_l_loc;\r
385 \r
386 \r
387 endmodule // spi_byte2bit\r