https://blackmesalabs.wordpress.com/2016/10/24/sump2-96-msps-logic-analyzer-for-22/
[BML_sump2] / sump2 / source / mesa2lb.v
diff --git a/sump2/source/mesa2lb.v b/sump2/source/mesa2lb.v
new file mode 100644 (file)
index 0000000..2a1b0ef
--- /dev/null
@@ -0,0 +1,371 @@
+/* ****************************************************************************\r
+-- (C) Copyright 2015 Kevin M. Hubbard @ Black Mesa Labs\r
+-- Source file: mesa2lb.v                \r
+-- Date:        October 4, 2015   \r
+-- Author:      khubbard\r
+-- Language:    Verilog-2001 \r
+-- Description: The Mesa Bus to LocalBus translator. Uses a Subslot for LB\r
+--              Reads and Writes using 4 different command nibbles. Also\r
+--              decodes the BSP subslots for things like pin control, power\r
+--              modes and scope out debug features.\r
+-- License:     This project is licensed with the CERN Open Hardware Licence\r
+--              v1.2.  You may redistribute and modify this project under the\r
+--              terms of the CERN OHL v.1.2. (http://ohwr.org/cernohl).\r
+--              This project is distributed WITHOUT ANY EXPRESS OR IMPLIED\r
+--              WARRANTY, INCLUDING OF MERCHANTABILITY, SATISFACTORY QUALITY\r
+--              AND FITNESS FOR A PARTICULAR PURPOSE. Please see the CERN OHL\r
+--              v.1.2 for applicable Conditions.\r
+--\r
+--\r
+--    "\n"..."FFFF"."(F0-12-34-04)[11223344]\n" : \r
+--        0xFF = Bus Idle ( NULLs )\r
+--  B0    0xF0 = New Bus Cycle to begin ( Nibble and bit orientation )\r
+--  B1    0x12 = Slot Number, 0xFF = Broadcast all slots, 0xFE = NULL Dest\r
+--  B2    0x3  = Sub-Slot within the chip (0-0xF)\r
+--        0x4  = Command Nibble for Sub-Slot\r
+--  B3    0x04 = Number of Payload Bytes (0-255)\r
+--        0x11223344 = Payload\r
+--\r
+--    Slot 0xFF    = Broadcast all slots\r
+--    Sub-Slot 0x0 = User Local Bus Access\r
+--    Sub-Slot 0xE = PROM Local Bus Access\r
+--                   0x0 = Bus Write\r
+--                   0x1 = Bus Read\r
+--                   0x2 = Bus Write Repeat ( burst to single address )\r
+--                   0x3 = Bus Read  Repeat ( burst read from single address )\r
+--    Sub-Slot 0xF = Power and Pin Control ( Write Only )\r
+-- \r
+-- SubSlot=0 : LocalBus\r
+-- Command\r
+--       0 : Write\r
+--       1 : Read\r
+--\r
+-- Ro : 0xF0FE3404 : \r
+--      0xFF = Bus Idle ( NULLs )\r
+--  B0  0xF0 = New Bus Cycle to begin ( Nibble and bit orientation )\r
+--  B1  0xFE = Slot Number - Default is 0xFE for Ro traffic\r
+--  B2  0x3  = Sub-Slot within the chip (0-0xF)\r
+--      0x4  = Command Nibble for Sub-Slot\r
+--  B3  0x04 = Number of Payload Bytes (0-255)\r
+--     \r
+--\r
+-- Revision History:\r
+-- Ver#  When      Who      What\r
+-- ----  --------  -------- ---------------------------------------------------\r
+-- 0.1   10.04.15  khubbard Creation\r
+-- ***************************************************************************/\r
+`default_nettype none // Strictly enforce all nets to be declared\r
+                                                                                \r
+module mesa2lb\r
+(\r
+  input  wire         clk,\r
+  input  wire         reset,\r
+  input  wire         rx_byte_start,\r
+  input  wire         rx_byte_stop,\r
+  input  wire         rx_byte_rdy,\r
+  input  wire [7:0]   rx_byte_d,\r
+  output wire [7:0]   tx_byte_d,\r
+  output wire         tx_byte_rdy,\r
+  output reg          tx_done,\r
+  input  wire         tx_busy,\r
+  output reg          lb_wr,\r
+  output wire         lb_rd,\r
+  output reg  [31:0]  lb_wr_d,\r
+  output reg  [31:0]  lb_addr,\r
+  input  wire [31:0]  lb_rd_d,\r
+  input  wire         lb_rd_rdy,\r
+  input  wire         oob_en,\r
+  input  wire [31:0]  oob_rd_d,\r
+  input  wire         oob_rd_rdy,\r
+  output reg          prom_wr,\r
+  output wire         prom_rd,\r
+  output reg  [31:0]  prom_wr_d,\r
+  output reg  [31:0]  prom_addr,\r
+  input  wire [31:0]  prom_rd_d,\r
+  input  wire         prom_rd_rdy\r
+); // module mesa2lb\r
+\r
+\r
+  reg           lb_rd_loc;\r
+  reg [3:0]     byte_cnt;\r
+  reg [31:0]    addr_cnt;\r
+  reg [31:0]    addr_len;\r
+  reg [31:0]    dword_sr;\r
+  reg           rx_byte_rdy_p1;\r
+  reg           rx_byte_rdy_p2;\r
+  reg           rx_byte_rdy_p3;\r
+  reg           rx_byte_stop_p1;\r
+  reg           rx_byte_stop_p2;\r
+  reg           rx_byte_stop_p3;\r
+  reg           header_jk;\r
+  reg           wr_jk;\r
+  reg           rd_jk;\r
+  reg           rpt_jk;\r
+  reg [2:0]     dword_stage;\r
+  reg           dword_rdy;\r
+  reg           reading;\r
+  reg           rd_done;\r
+  reg           rd_done_p1;\r
+  reg [31:0]    lb_rd_sr;\r
+  reg [3:0]     lb_rd_fsm;\r
+  reg           rd_busy;\r
+  reg [7:0]     rd_byte_d;\r
+//reg [7:0]     rd_timeout_cnt;\r
+//reg           rd_timeout_cnt_p1;\r
+  reg           rd_byte_rdy;\r
+  reg           lb_user_jk;\r
+  reg           lb_prom_jk;\r
+  reg           ro_header_rdy;\r
+\r
+\r
+// TODO: Write and Read burst Lengths should be reduced from 32bits for timing\r
+// TODO: A new cycle should always clear wr_jk and rd_jk in case a read timeout\r
+  assign tx_byte_d   = rd_byte_d[7:0];\r
+  assign tx_byte_rdy = rd_byte_rdy;\r
+\r
+\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Shift a nibble into a byte shift register. \r
+//        |---- Header ----|--- Payload ---|\r
+//           0   1   2   3\r
+// Write : <F0><00><00><08>[<ADDR><DATA>]\r
+// Read  : <F0><00><00><08>[<ADDR><Length>]\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_lb1\r
+ rx_byte_rdy_p1  <= rx_byte_rdy;\r
+ rx_byte_rdy_p2  <= rx_byte_rdy_p1;\r
+ rx_byte_rdy_p3  <= rx_byte_rdy_p2;\r
+ rx_byte_stop_p1 <= rx_byte_stop;\r
+ rx_byte_stop_p2 <= rx_byte_stop_p1;\r
+ rx_byte_stop_p3 <= rx_byte_stop_p2;\r
+ dword_rdy       <= 0;\r
+\r
+ if ( rx_byte_start == 1 ) begin\r
+   byte_cnt   <= 4'd0;\r
+   header_jk  <= 1;\r
+ end else if ( rx_byte_rdy == 1 ) begin \r
+   byte_cnt   <= byte_cnt + 1; \r
+ end \r
+\r
+ // Shift bytes into a 32bit SR\r
+ if ( rx_byte_rdy == 1 ) begin \r
+   dword_sr[31:0] <= { dword_sr[23:0], rx_byte_d[7:0] };\r
+ end\r
+\r
+ // After we have 4 bytes, look for Slot=00,SubSlot=0,Command=0or1 (WR or RD)\r
+ if ( rx_byte_rdy_p2 == 1 && byte_cnt[1:0] == 2'd3 ) begin\r
+   dword_rdy <= 1;\r
+   header_jk <= 0;\r
+   if ( header_jk == 1 && wr_jk == 0 && rd_jk == 0 ) begin \r
+     // Note: This doesn't handle slot broadcast - only direct for LB Access\r
+     if ( dword_sr[31:16] == 16'hF000 ) begin\r
+       lb_user_jk <= 0;\r
+       lb_prom_jk <= 0;\r
+       if          ( dword_sr[15:12] == 4'h0 ) begin\r
+         lb_user_jk <= 1;\r
+       end else if ( dword_sr[15:12] == 4'hE ) begin\r
+         lb_prom_jk <= 1;\r
+       end\r
+\r
+       if ( dword_sr[15:12] == 4'h0 || dword_sr[15:12] == 4'hE ) begin\r
+         if ( dword_sr[11:8] == 4'h0 || dword_sr[11:8] == 4'h2 ) begin\r
+           wr_jk       <= 1;\r
+           dword_stage <= 3'b001;\r
+         end \r
+         if ( dword_sr[11:8] == 4'h1 || dword_sr[11:8] == 4'h3 ) begin\r
+           rd_jk         <= 1;\r
+           dword_stage   <= 3'b001;\r
+         end \r
+         // Repeat_JK Asserts to burst to/from single address\r
+         if ( dword_sr[11:8] == 4'h2 || dword_sr[11:8] == 4'h3 ) begin\r
+           rpt_jk <= 1;\r
+         end else begin\r
+           rpt_jk <= 0;\r
+         end\r
+       end // if ( dword_sr[15:12] == 4'h0 || dword_sr[15:12] == 4'hE ) begin\r
+     end // if ( dword_sr[31:16] == 16'hF000 ) begin\r
+   end else begin\r
+     // Payload\r
+     if ( wr_jk == 1 || rd_jk == 1 ) begin\r
+       // This shifts 001 to 010, 100 then halts at 100\r
+       // It records burst write stages of header,addr,data,data\r
+       dword_stage <= { ( dword_stage[2] | dword_stage[1] ), \r
+                          dword_stage[0],\r
+                          1'b0 };\r
+     end\r
+   end // if ( wr_jk == 0 && rd_jk == 0 ) begin \r
+ end // if ( rx_byte_rdy_p2 == 1 && byte_cnt[1:0] == 2'd3 ) begin\r
+\r
+ //\r
+ if ( rx_byte_stop_p3 == 1 ) begin\r
+   wr_jk   <= 0;\r
+ end\r
+ if ( rd_done == 1 && rd_done_p1 == 0 ) begin\r
+   rd_jk   <= 0;\r
+ end\r
+ if ( reset == 1 ) begin\r
+   wr_jk      <= 0;\r
+   rd_jk      <= 0;\r
+   rpt_jk     <= 0;\r
+   lb_user_jk <= 0;\r
+   lb_prom_jk <= 0;\r
+   header_jk  <= 0;\r
+ end\r
\r
+end // proc_lb1\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Convert serial stream into parallel local bus\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_lb2\r
+  lb_wr      <= 0;\r
+  prom_wr    <= 0;\r
+  lb_rd_loc  <= 0;\r
+//lb_wr_d    <= 32'd0;\r
+//lb_addr    <= 32'd0;\r
+//prom_wr_d  <= 32'd0;\r
+//prom_addr  <= 32'd0;\r
+  rd_done_p1 <= rd_done;\r
+  ro_header_rdy <= 0;\r
+\r
+  if ( dword_rdy == 1 && wr_jk == 1 ) begin\r
+    if ( dword_stage[1] == 1 ) begin\r
+      addr_cnt <= dword_sr[31:0];// 1st DWORD of WR is LB Address\r
+    end\r
+    if ( dword_stage[2] == 1 ) begin\r
+      lb_wr     <= lb_user_jk;\r
+      prom_wr   <= lb_prom_jk;\r
+      lb_addr   <= addr_cnt[31:0];// Load the stored address\r
+      prom_addr <= addr_cnt[31:0];// Load the stored address\r
+      lb_wr_d   <= dword_sr[31:0];// 2nd+ DWORDs or WR is Burst Data\r
+      prom_wr_d <= dword_sr[31:0];// 2nd+ DWORDs or WR is Burst Data\r
+      if ( rpt_jk == 0 ) begin\r
+        addr_cnt  <= addr_cnt + 4;  // Increment address for next cycle\r
+      end\r
+    end\r
+  end // if ( dword_rdy == 1 && wr_jk == 1 ) begin\r
+\r
+  if ( dword_rdy == 1 && rd_jk == 1 ) begin\r
+    if ( dword_stage[1] == 1 ) begin\r
+      addr_cnt      <= dword_sr[31:0];// 1st DWORD of RD is LB Address\r
+    end\r
+    if ( dword_stage[2] == 1 ) begin\r
+      addr_len      <= dword_sr[31:0];// 2nd DWORD of RD is Num DWORDs to Read\r
+      ro_header_rdy <= 1;// Send Ro Header as we know length of packet to send\r
+    end\r
+  end // if ( dword_rdy == 1 && rd_jk == 1 ) begin\r
+\r
+  if ( rd_jk == 0 ) begin\r
+    addr_len       <= 32'd0;\r
+    rd_done        <= 0;\r
+    reading        <= 0;\r
+  end else begin\r
+    if ( addr_len != 32'd0 ) begin\r
+      if ( ro_header_rdy == 0 && rd_busy == 0 && lb_rd_loc == 0 ) begin\r
+        lb_rd_loc <= 1;\r
+        lb_addr   <= addr_cnt[31:0];// Load stored address\r
+        prom_addr <= addr_cnt[31:0];// Load stored address\r
+        addr_len  <= addr_len - 1;  // Decrement DWORD length counter   \r
+        reading   <= 1;\r
+        if ( rpt_jk == 0 ) begin\r
+          addr_cnt  <= addr_cnt + 4;  // Increment address for next cycle\r
+        end\r
+      end\r
+    end else begin\r
+      if ( reading == 1 ) begin\r
+        rd_done <= 1;\r
+      end\r
+    end\r
+  end // if ( rd_jk == 0 ) begin\r
+\r
+//addr_cnt[31:12] <= 20'd0;// Harvest bits for timing\r
+//addr_len[31:12] <= 20'd0;// Harvest bits for timing\r
+// Max 63 DWORD Read as MesaBus payload max size is 255 bytes\r
+  addr_len[31:6]  <= 26'd0;// Harvest bits for timing. \r
+\r
+end // proc_lb2\r
+  assign lb_rd   = lb_rd_loc & lb_user_jk;\r
+  assign prom_rd = lb_rd_loc & lb_prom_jk;\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Shift the readback data out 1 byte at a time \r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_lb3\r
+  tx_done     <= 0;\r
+  rd_byte_rdy <= 0;\r
+  rd_byte_d   <= 8'H00;\r
+//rd_timeout_cnt_p1 <= rd_timeout_cnt[7];\r
+\r
+  // Timeout after 128 clocks\r
+//if ( reset == 1 ) begin\r
+//  rd_timeout_cnt <= 8'H00;// Stopped\r
+//end else begin\r
+//  if ( lb_user_jk == 1 || lb_prom_jk == 1 ) begin\r
+//    if ( lb_rd_loc == 1 ) begin\r
+//      rd_timeout_cnt    <= 8'H80;// Enable the count For 0-127\r
+//    end else if ( lb_rd_rdy == 1 || prom_rd_rdy == 1 ) begin\r
+//      rd_timeout_cnt[7] <= 0;// Stop the Count\r
+//      rd_timeout_cnt_p1 <= 0;\r
+//    end else if ( rd_timeout_cnt[7] == 1 ) begin\r
+//      rd_timeout_cnt    <= rd_timeout_cnt + 1;\r
+//    end else if ( rd_timeout_cnt_p1 == 1 ) begin\r
+//      rd_timeout_cnt <= 8'H00;// Stopped\r
+//      lb_rd_sr       <= 32'hDEADBEEF;\r
+//      lb_rd_fsm      <= 4'b1111;\r
+//      rd_busy        <= 1;\r
+//    end\r
+//  end\r
+//end\r
+\r
+  // rd_busy asserts when a 32bit Ro shift out is starting to pause bursts\r
+  if ( ro_header_rdy == 1 && ( lb_prom_jk == 1 || lb_user_jk == 1 ) ) begin\r
+    lb_rd_sr[31:8] <= 24'hF0FE00;\r
+    lb_rd_sr[7:0]  <= { addr_len[5:0], 2'b00 };// Number of Return Bytes\r
+    lb_rd_fsm      <= 4'b1111;\r
+    rd_busy        <= 1;\r
+  end\r
+  if ( lb_rd_rdy == 1 && lb_user_jk == 1 ) begin\r
+    lb_rd_sr  <= lb_rd_d[31:0];\r
+    lb_rd_fsm <= 4'b1111;\r
+    rd_busy   <= 1;\r
+  end\r
+  if ( prom_rd_rdy == 1 && lb_prom_jk == 1 ) begin\r
+    lb_rd_sr  <= prom_rd_d[31:0];\r
+    lb_rd_fsm <= 4'b1111;\r
+    rd_busy   <= 1;\r
+  end\r
+  if ( oob_rd_rdy == 1 && oob_en == 1 ) begin\r
+    lb_rd_sr  <= oob_rd_d[31:0];// oob stands for Out of Band signaling\r
+    lb_rd_fsm <= 4'b1111;\r
+    rd_busy   <= 1;\r
+  end\r
+\r
+  if ( lb_rd_loc == 1 ) begin\r
+    rd_busy <= 1;\r
+  end\r
+\r
+  if ( lb_rd_fsm != 4'b0000 && rd_byte_rdy == 0 && tx_busy == 0 ) begin\r
+    rd_byte_d   <= lb_rd_sr[31:24];\r
+    rd_byte_rdy <= 1;\r
+    lb_rd_sr    <= { lb_rd_sr[23:0], 8'h00 };\r
+    lb_rd_fsm   <= { lb_rd_fsm[2:0], 1'b0  };\r
+    if ( lb_rd_fsm == 4'b1000 ) begin\r
+      rd_busy <= 0;\r
+      if ( rd_jk == 0 && oob_en == 0 ) begin\r
+        tx_done <= 1;\r
+      end\r
+    end\r
+  end\r
+\r
+  if ( reset == 1 ) begin \r
+    lb_rd_fsm  <= 4'b0000;\r
+    rd_busy    <= 0;\r
+  end \r
+end // proc_lb3\r
+\r
+\r
+endmodule // mesa2lb\r