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
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
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
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
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
38 -- SubSlot=0 : LocalBus
\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
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
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
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
78 input wire [31:0] oob_rd_d,
\r
79 input wire oob_rd_rdy,
\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
91 reg [31:0] addr_cnt;
\r
92 reg [31:0] addr_len;
\r
93 reg [31:0] dword_sr;
\r
97 reg rx_byte_stop_p1;
\r
98 reg rx_byte_stop_p2;
\r
99 reg rx_byte_stop_p3;
\r
104 reg [2:0] dword_stage;
\r
109 reg [31:0] lb_rd_sr;
\r
110 reg [3:0] lb_rd_fsm;
\r
112 reg [7:0] rd_byte_d;
\r
113 //reg [7:0] rd_timeout_cnt;
\r
114 //reg rd_timeout_cnt_p1;
\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
129 //-----------------------------------------------------------------------------
\r
130 // Shift a nibble into a byte shift register.
\r
131 // |---- Header ----|--- Payload ---|
\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
145 if ( rx_byte_start == 1 ) begin
\r
148 end else if ( rx_byte_rdy == 1 ) begin
\r
149 byte_cnt <= byte_cnt + 1;
\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
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
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
166 if ( dword_sr[15:12] == 4'h0 ) begin
\r
168 end else if ( dword_sr[15:12] == 4'hE ) begin
\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
175 dword_stage <= 3'b001;
\r
177 if ( dword_sr[11:8] == 4'h1 || dword_sr[11:8] == 4'h3 ) begin
\r
179 dword_stage <= 3'b001;
\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
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
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
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
202 if ( rx_byte_stop_p3 == 1 ) begin
\r
205 if ( rd_done == 1 && rd_done_p1 == 0 ) begin
\r
208 if ( reset == 1 ) begin
\r
220 //-----------------------------------------------------------------------------
\r
221 // Convert serial stream into parallel local bus
\r
222 //-----------------------------------------------------------------------------
\r
223 always @ ( posedge clk ) begin : proc_lb2
\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
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
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
249 end // if ( dword_rdy == 1 && wr_jk == 1 ) begin
\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
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
259 end // if ( dword_rdy == 1 && rd_jk == 1 ) begin
\r
261 if ( rd_jk == 0 ) 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
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
273 if ( rpt_jk == 0 ) begin
\r
274 addr_cnt <= addr_cnt + 4; // Increment address for next cycle
\r
278 if ( reading == 1 ) begin
\r
282 end // if ( rd_jk == 0 ) begin
\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
290 assign lb_rd = lb_rd_loc & lb_user_jk;
\r
291 assign prom_rd = lb_rd_loc & lb_prom_jk;
\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
300 rd_byte_d <= 8'H00;
\r
301 //rd_timeout_cnt_p1 <= rd_timeout_cnt[7];
\r
303 // Timeout after 128 clocks
\r
304 //if ( reset == 1 ) begin
\r
305 // rd_timeout_cnt <= 8'H00;// Stopped
\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
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
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
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
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
347 if ( lb_rd_loc == 1 ) begin
\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
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
358 if ( rd_jk == 0 && oob_en == 0 ) begin
\r
364 if ( reset == 1 ) begin
\r
365 lb_rd_fsm <= 4'b0000;
\r
371 endmodule // mesa2lb
\r