https://blackmesalabs.wordpress.com/2016/10/24/sump2-96-msps-logic-analyzer-for-22/
[BML_sump2] / sump2 / source / mesa2lb.v
1 /* ****************************************************************************\r
2 -- (C) Copyright 2015 Kevin M. Hubbard @ Black Mesa Labs\r
3 -- Source file: mesa2lb.v                \r
4 -- Date:        October 4, 2015   \r
5 -- Author:      khubbard\r
6 -- Language:    Verilog-2001 \r
7 -- Description: The Mesa Bus to LocalBus translator. Uses a Subslot for LB\r
8 --              Reads and Writes using 4 different command nibbles. Also\r
9 --              decodes the BSP subslots for things like pin control, power\r
10 --              modes and scope out debug features.\r
11 -- License:     This project is licensed with the CERN Open Hardware Licence\r
12 --              v1.2.  You may redistribute and modify this project under the\r
13 --              terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl).\r
14 --              This project is distributed WITHOUT ANY EXPRESS OR IMPLIED\r
15 --              WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY\r
16 --              AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL\r
17 --              v.1.2 for applicable Conditions.\r
18 --\r
19 --\r
20 --    "\n"..."FFFF"."(F0-12-34-04)[11223344]\n" : \r
21 --        0xFF = Bus Idle ( NULLs )\r
22 --  B0    0xF0 = New Bus Cycle to begin ( Nibble and bit orientation )\r
23 --  B1    0x12 = Slot Number, 0xFF = Broadcast all slots, 0xFE = NULL Dest\r
24 --  B2    0x3  = Sub-Slot within the chip (0-0xF)\r
25 --        0x4  = Command Nibble for Sub-Slot\r
26 --  B3    0x04 = Number of Payload Bytes (0-255)\r
27 --        0x11223344 = Payload\r
28 --\r
29 --    Slot 0xFF    = Broadcast all slots\r
30 --    Sub-Slot 0x0 = User Local Bus Access\r
31 --    Sub-Slot 0xE = PROM Local Bus Access\r
32 --                   0x0 = Bus Write\r
33 --                   0x1 = Bus Read\r
34 --                   0x2 = Bus Write Repeat ( burst to single address )\r
35 --                   0x3 = Bus Read  Repeat ( burst read from single address )\r
36 --    Sub-Slot 0xF = Power and Pin Control ( Write Only )\r
37 -- \r
38 -- SubSlot=0 : LocalBus\r
39 -- Command\r
40 --       0 : Write\r
41 --       1 : Read\r
42 --\r
43 -- Ro : 0xF0FE3404 : \r
44 --      0xFF = Bus Idle ( NULLs )\r
45 --  B0  0xF0 = New Bus Cycle to begin ( Nibble and bit orientation )\r
46 --  B1  0xFE = Slot Number - Default is 0xFE for Ro traffic\r
47 --  B2  0x3  = Sub-Slot within the chip (0-0xF)\r
48 --      0x4  = Command Nibble for Sub-Slot\r
49 --  B3  0x04 = Number of Payload Bytes (0-255)\r
50 --     \r
51 --\r
52 -- Revision History:\r
53 -- Ver#  When      Who      What\r
54 -- ----  --------  -------- ---------------------------------------------------\r
55 -- 0.1   10.04.15  khubbard Creation\r
56 -- ***************************************************************************/\r
57 `default_nettype none // Strictly enforce all nets to be declared\r
58                                                                                 \r
59 module mesa2lb\r
60 (\r
61   input  wire         clk,\r
62   input  wire         reset,\r
63   input  wire         rx_byte_start,\r
64   input  wire         rx_byte_stop,\r
65   input  wire         rx_byte_rdy,\r
66   input  wire [7:0]   rx_byte_d,\r
67   output wire [7:0]   tx_byte_d,\r
68   output wire         tx_byte_rdy,\r
69   output reg          tx_done,\r
70   input  wire         tx_busy,\r
71   output reg          lb_wr,\r
72   output wire         lb_rd,\r
73   output reg  [31:0]  lb_wr_d,\r
74   output reg  [31:0]  lb_addr,\r
75   input  wire [31:0]  lb_rd_d,\r
76   input  wire         lb_rd_rdy,\r
77   input  wire         oob_en,\r
78   input  wire [31:0]  oob_rd_d,\r
79   input  wire         oob_rd_rdy,\r
80   output reg          prom_wr,\r
81   output wire         prom_rd,\r
82   output reg  [31:0]  prom_wr_d,\r
83   output reg  [31:0]  prom_addr,\r
84   input  wire [31:0]  prom_rd_d,\r
85   input  wire         prom_rd_rdy\r
86 ); // module mesa2lb\r
87 \r
88 \r
89   reg           lb_rd_loc;\r
90   reg [3:0]     byte_cnt;\r
91   reg [31:0]    addr_cnt;\r
92   reg [31:0]    addr_len;\r
93   reg [31:0]    dword_sr;\r
94   reg           rx_byte_rdy_p1;\r
95   reg           rx_byte_rdy_p2;\r
96   reg           rx_byte_rdy_p3;\r
97   reg           rx_byte_stop_p1;\r
98   reg           rx_byte_stop_p2;\r
99   reg           rx_byte_stop_p3;\r
100   reg           header_jk;\r
101   reg           wr_jk;\r
102   reg           rd_jk;\r
103   reg           rpt_jk;\r
104   reg [2:0]     dword_stage;\r
105   reg           dword_rdy;\r
106   reg           reading;\r
107   reg           rd_done;\r
108   reg           rd_done_p1;\r
109   reg [31:0]    lb_rd_sr;\r
110   reg [3:0]     lb_rd_fsm;\r
111   reg           rd_busy;\r
112   reg [7:0]     rd_byte_d;\r
113 //reg [7:0]     rd_timeout_cnt;\r
114 //reg           rd_timeout_cnt_p1;\r
115   reg           rd_byte_rdy;\r
116   reg           lb_user_jk;\r
117   reg           lb_prom_jk;\r
118   reg           ro_header_rdy;\r
119 \r
120 \r
121 // TODO: Write and Read burst Lengths should be reduced from 32bits for timing\r
122 // TODO: A new cycle should always clear wr_jk and rd_jk in case a read timeout\r
123   assign tx_byte_d   = rd_byte_d[7:0];\r
124   assign tx_byte_rdy = rd_byte_rdy;\r
125 \r
126 \r
127 \r
128 \r
129 //-----------------------------------------------------------------------------\r
130 // Shift a nibble into a byte shift register. \r
131 //        |---- Header ----|--- Payload ---|\r
132 //           0   1   2   3\r
133 // Write : <F0><00><00><08>[<ADDR><DATA>]\r
134 // Read  : <F0><00><00><08>[<ADDR><Length>]\r
135 //-----------------------------------------------------------------------------\r
136 always @ ( posedge clk ) begin : proc_lb1\r
137  rx_byte_rdy_p1  <= rx_byte_rdy;\r
138  rx_byte_rdy_p2  <= rx_byte_rdy_p1;\r
139  rx_byte_rdy_p3  <= rx_byte_rdy_p2;\r
140  rx_byte_stop_p1 <= rx_byte_stop;\r
141  rx_byte_stop_p2 <= rx_byte_stop_p1;\r
142  rx_byte_stop_p3 <= rx_byte_stop_p2;\r
143  dword_rdy       <= 0;\r
144 \r
145  if ( rx_byte_start == 1 ) begin\r
146    byte_cnt   <= 4'd0;\r
147    header_jk  <= 1;\r
148  end else if ( rx_byte_rdy == 1 ) begin \r
149    byte_cnt   <= byte_cnt + 1; \r
150  end \r
151 \r
152  // Shift bytes into a 32bit SR\r
153  if ( rx_byte_rdy == 1 ) begin \r
154    dword_sr[31:0] <= { dword_sr[23:0], rx_byte_d[7:0] };\r
155  end\r
156 \r
157  // After we have 4 bytes, look for Slot=00,SubSlot=0,Command=0or1 (WR or RD)\r
158  if ( rx_byte_rdy_p2 == 1 && byte_cnt[1:0] == 2'd3 ) begin\r
159    dword_rdy <= 1;\r
160    header_jk <= 0;\r
161    if ( header_jk == 1 && wr_jk == 0 && rd_jk == 0 ) begin \r
162      // Note: This doesn't handle slot broadcast - only direct for LB Access\r
163      if ( dword_sr[31:16] == 16'hF000 ) begin\r
164        lb_user_jk <= 0;\r
165        lb_prom_jk <= 0;\r
166        if          ( dword_sr[15:12] == 4'h0 ) begin\r
167          lb_user_jk <= 1;\r
168        end else if ( dword_sr[15:12] == 4'hE ) begin\r
169          lb_prom_jk <= 1;\r
170        end\r
171 \r
172        if ( dword_sr[15:12] == 4'h0 || dword_sr[15:12] == 4'hE ) begin\r
173          if ( dword_sr[11:8] == 4'h0 || dword_sr[11:8] == 4'h2 ) begin\r
174            wr_jk       <= 1;\r
175            dword_stage <= 3'b001;\r
176          end \r
177          if ( dword_sr[11:8] == 4'h1 || dword_sr[11:8] == 4'h3 ) begin\r
178            rd_jk         <= 1;\r
179            dword_stage   <= 3'b001;\r
180          end \r
181          // Repeat_JK Asserts to burst to/from single address\r
182          if ( dword_sr[11:8] == 4'h2 || dword_sr[11:8] == 4'h3 ) begin\r
183            rpt_jk <= 1;\r
184          end else begin\r
185            rpt_jk <= 0;\r
186          end\r
187        end // if ( dword_sr[15:12] == 4'h0 || dword_sr[15:12] == 4'hE ) begin\r
188      end // if ( dword_sr[31:16] == 16'hF000 ) begin\r
189    end else begin\r
190      // Payload\r
191      if ( wr_jk == 1 || rd_jk == 1 ) begin\r
192        // This shifts 001 to 010, 100 then halts at 100\r
193        // It records burst write stages of header,addr,data,data\r
194        dword_stage <= { ( dword_stage[2] | dword_stage[1] ), \r
195                           dword_stage[0],\r
196                           1'b0 };\r
197      end\r
198    end // if ( wr_jk == 0 && rd_jk == 0 ) begin \r
199  end // if ( rx_byte_rdy_p2 == 1 && byte_cnt[1:0] == 2'd3 ) begin\r
200 \r
201  //\r
202  if ( rx_byte_stop_p3 == 1 ) begin\r
203    wr_jk   <= 0;\r
204  end\r
205  if ( rd_done == 1 && rd_done_p1 == 0 ) begin\r
206    rd_jk   <= 0;\r
207  end\r
208  if ( reset == 1 ) begin\r
209    wr_jk      <= 0;\r
210    rd_jk      <= 0;\r
211    rpt_jk     <= 0;\r
212    lb_user_jk <= 0;\r
213    lb_prom_jk <= 0;\r
214    header_jk  <= 0;\r
215  end\r
216  \r
217 end // proc_lb1\r
218 \r
219 \r
220 //-----------------------------------------------------------------------------\r
221 // Convert serial stream into parallel local bus\r
222 //-----------------------------------------------------------------------------\r
223 always @ ( posedge clk ) begin : proc_lb2\r
224   lb_wr      <= 0;\r
225   prom_wr    <= 0;\r
226   lb_rd_loc  <= 0;\r
227 //lb_wr_d    <= 32'd0;\r
228 //lb_addr    <= 32'd0;\r
229 //prom_wr_d  <= 32'd0;\r
230 //prom_addr  <= 32'd0;\r
231   rd_done_p1 <= rd_done;\r
232   ro_header_rdy <= 0;\r
233 \r
234   if ( dword_rdy == 1 && wr_jk == 1 ) begin\r
235     if ( dword_stage[1] == 1 ) begin\r
236       addr_cnt <= dword_sr[31:0];// 1st DWORD of WR is LB Address\r
237     end\r
238     if ( dword_stage[2] == 1 ) begin\r
239       lb_wr     <= lb_user_jk;\r
240       prom_wr   <= lb_prom_jk;\r
241       lb_addr   <= addr_cnt[31:0];// Load the stored address\r
242       prom_addr <= addr_cnt[31:0];// Load the stored address\r
243       lb_wr_d   <= dword_sr[31:0];// 2nd+ DWORDs or WR is Burst Data\r
244       prom_wr_d <= dword_sr[31:0];// 2nd+ DWORDs or WR is Burst Data\r
245       if ( rpt_jk == 0 ) begin\r
246         addr_cnt  <= addr_cnt + 4;  // Increment address for next cycle\r
247       end\r
248     end\r
249   end // if ( dword_rdy == 1 && wr_jk == 1 ) begin\r
250 \r
251   if ( dword_rdy == 1 && rd_jk == 1 ) begin\r
252     if ( dword_stage[1] == 1 ) begin\r
253       addr_cnt      <= dword_sr[31:0];// 1st DWORD of RD is LB Address\r
254     end\r
255     if ( dword_stage[2] == 1 ) begin\r
256       addr_len      <= dword_sr[31:0];// 2nd DWORD of RD is Num DWORDs to Read\r
257       ro_header_rdy <= 1;// Send Ro Header as we know length of packet to send\r
258     end\r
259   end // if ( dword_rdy == 1 && rd_jk == 1 ) begin\r
260 \r
261   if ( rd_jk == 0 ) begin\r
262     addr_len       <= 32'd0;\r
263     rd_done        <= 0;\r
264     reading        <= 0;\r
265   end else begin\r
266     if ( addr_len != 32'd0 ) begin\r
267       if ( ro_header_rdy == 0 && rd_busy == 0 && lb_rd_loc == 0 ) begin\r
268         lb_rd_loc <= 1;\r
269         lb_addr   <= addr_cnt[31:0];// Load stored address\r
270         prom_addr <= addr_cnt[31:0];// Load stored address\r
271         addr_len  <= addr_len - 1;  // Decrement DWORD length counter   \r
272         reading   <= 1;\r
273         if ( rpt_jk == 0 ) begin\r
274           addr_cnt  <= addr_cnt + 4;  // Increment address for next cycle\r
275         end\r
276       end\r
277     end else begin\r
278       if ( reading == 1 ) begin\r
279         rd_done <= 1;\r
280       end\r
281     end\r
282   end // if ( rd_jk == 0 ) begin\r
283 \r
284 //addr_cnt[31:12] <= 20'd0;// Harvest bits for timing\r
285 //addr_len[31:12] <= 20'd0;// Harvest bits for timing\r
286 // Max 63 DWORD Read as MesaBus payload max size is 255 bytes\r
287   addr_len[31:6]  <= 26'd0;// Harvest bits for timing. \r
288 \r
289 end // proc_lb2\r
290   assign lb_rd   = lb_rd_loc & lb_user_jk;\r
291   assign prom_rd = lb_rd_loc & lb_prom_jk;\r
292 \r
293 \r
294 //-----------------------------------------------------------------------------\r
295 // Shift the readback data out 1 byte at a time \r
296 //-----------------------------------------------------------------------------\r
297 always @ ( posedge clk ) begin : proc_lb3\r
298   tx_done     <= 0;\r
299   rd_byte_rdy <= 0;\r
300   rd_byte_d   <= 8'H00;\r
301 //rd_timeout_cnt_p1 <= rd_timeout_cnt[7];\r
302 \r
303   // Timeout after 128 clocks\r
304 //if ( reset == 1 ) begin\r
305 //  rd_timeout_cnt <= 8'H00;// Stopped\r
306 //end else begin\r
307 //  if ( lb_user_jk == 1 || lb_prom_jk == 1 ) begin\r
308 //    if ( lb_rd_loc == 1 ) begin\r
309 //      rd_timeout_cnt    <= 8'H80;// Enable the count For 0-127\r
310 //    end else if ( lb_rd_rdy == 1 || prom_rd_rdy == 1 ) begin\r
311 //      rd_timeout_cnt[7] <= 0;// Stop the Count\r
312 //      rd_timeout_cnt_p1 <= 0;\r
313 //    end else if ( rd_timeout_cnt[7] == 1 ) begin\r
314 //      rd_timeout_cnt    <= rd_timeout_cnt + 1;\r
315 //    end else if ( rd_timeout_cnt_p1 == 1 ) begin\r
316 //      rd_timeout_cnt <= 8'H00;// Stopped\r
317 //      lb_rd_sr       <= 32'hDEADBEEF;\r
318 //      lb_rd_fsm      <= 4'b1111;\r
319 //      rd_busy        <= 1;\r
320 //    end\r
321 //  end\r
322 //end\r
323 \r
324   // rd_busy asserts when a 32bit Ro shift out is starting to pause bursts\r
325   if ( ro_header_rdy == 1 && ( lb_prom_jk == 1 || lb_user_jk == 1 ) ) begin\r
326     lb_rd_sr[31:8] <= 24'hF0FE00;\r
327     lb_rd_sr[7:0]  <= { addr_len[5:0], 2'b00 };// Number of Return Bytes\r
328     lb_rd_fsm      <= 4'b1111;\r
329     rd_busy        <= 1;\r
330   end\r
331   if ( lb_rd_rdy == 1 && lb_user_jk == 1 ) begin\r
332     lb_rd_sr  <= lb_rd_d[31:0];\r
333     lb_rd_fsm <= 4'b1111;\r
334     rd_busy   <= 1;\r
335   end\r
336   if ( prom_rd_rdy == 1 && lb_prom_jk == 1 ) begin\r
337     lb_rd_sr  <= prom_rd_d[31:0];\r
338     lb_rd_fsm <= 4'b1111;\r
339     rd_busy   <= 1;\r
340   end\r
341   if ( oob_rd_rdy == 1 && oob_en == 1 ) begin\r
342     lb_rd_sr  <= oob_rd_d[31:0];// oob stands for Out of Band signaling\r
343     lb_rd_fsm <= 4'b1111;\r
344     rd_busy   <= 1;\r
345   end\r
346 \r
347   if ( lb_rd_loc == 1 ) begin\r
348     rd_busy <= 1;\r
349   end\r
350 \r
351   if ( lb_rd_fsm != 4'b0000 && rd_byte_rdy == 0 && tx_busy == 0 ) begin\r
352     rd_byte_d   <= lb_rd_sr[31:24];\r
353     rd_byte_rdy <= 1;\r
354     lb_rd_sr    <= { lb_rd_sr[23:0], 8'h00 };\r
355     lb_rd_fsm   <= { lb_rd_fsm[2:0], 1'b0  };\r
356     if ( lb_rd_fsm == 4'b1000 ) begin\r
357       rd_busy <= 0;\r
358       if ( rd_jk == 0 && oob_en == 0 ) begin\r
359         tx_done <= 1;\r
360       end\r
361     end\r
362   end\r
363 \r
364   if ( reset == 1 ) begin \r
365     lb_rd_fsm  <= 4'b0000;\r
366     rd_busy    <= 0;\r
367   end \r
368 end // proc_lb3\r
369 \r
370 \r
371 endmodule // mesa2lb\r