https://blackmesalabs.wordpress.com/2016/10/24/sump2-96-msps-logic-analyzer-for-22/
[BML_sump2] / sump2 / source / mesa_uart.v
diff --git a/sump2/source/mesa_uart.v b/sump2/source/mesa_uart.v
new file mode 100644 (file)
index 0000000..a786847
--- /dev/null
@@ -0,0 +1,482 @@
+/* ****************************************************************************\r
+-- (C) Copyright 2015 Kevin M. Hubbard - Black Mesa Labs\r
+-- Source file: mesa_uart.v                \r
+-- Date:        June 1, 2015   \r
+-- Author:      khubbard\r
+-- Description: A UART that autobauds to first "\n" 0x0A character.\r
+-- Language:    Verilog-2001 \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
+-- 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
+-- RXD    \START/<D0><D1><D2><..><D7>/STOP\r
+-- Design Statistics after Packing\r
+-- en_clr_lock = 1;\r
+--    Number of LUTs  : 190 / 384\r
+--    Number of DFFs  : 110 / 384\r
+--\r
+-- Revision History:\r
+-- Ver#  When      Who      What\r
+-- ----  --------  -------- ---------------------------------------------------\r
+-- 0.1   06.01.15  khubbard Creation\r
+-- 0.2   08.18.16  khubbard rx_sr[2:0] fix for metastable sampling issue.\r
+-- ***************************************************************************/\r
+//`default_nettype none // Strictly enforce all nets to be declared\r
+                                                                                \r
+module mesa_uart\r
+(\r
+  input  wire         reset,\r
+  input  wire         clk,\r
+  input  wire         clr_baudlock,\r
+  input  wire         en_autobaud,\r
+  output wire         flush,\r
+  input  wire         rxd,\r
+  output reg          txd,\r
+  output reg  [7:0]   dbg,\r
+  output wire [7:0]   rx_byte,\r
+  output reg          rx_rdy,\r
+  input  wire [7:0]   tx_byte,\r
+  input  wire         tx_en,\r
+  output reg          tx_busy,\r
+  output reg          tx_idle,\r
+  output wire         rx_idle,\r
+  output wire [15:0]  baud_rate,\r
+  output wire         baud_lock\r
+); // module mesa_uart\r
+\r
+\r
+  reg  [8:0]    rx_byte_sr;\r
+  reg  [3:0]    rx_bit_cnt;\r
+  reg  [3:0]    tx_bit_cnt;\r
+  reg           sample_now;\r
+  reg           sample_now_p1;\r
+  reg           rxd_meta;\r
+  reg           rxd_loc;\r
+  wire          rxd_sample;\r
+  reg  [7:0]    rxd_sr;\r
+  reg           clr_bit_lock;\r
+  reg           dbg_sample_togl;\r
+  reg           dbg_sample_togl_p1;\r
+  reg           dbg_byte_togl;\r
+  reg           clr_jk;\r
+  reg           bad_jk;\r
+  reg           bit_lock_jk;\r
+  reg           bit_lock_jk_p1;\r
+  reg           baud_lock_jk;\r
+  reg           rx_byte_jk;\r
+  reg           rx_byte_jk_p1;\r
+\r
+  wire [7:0]    rx_byte_loc;\r
+  reg  [15:0]   rx_cnt_16b;\r
+  reg  [15:0]   tx_cnt_16b;\r
+  reg  [15:0]   baud_rate_loc;\r
+  reg           rx_cnt_16b_p1;\r
+  reg           rx_cnt_16b_roll;\r
+  reg           rx_start_a;\r
+  reg           rx_start_b;\r
+  reg           rx_cnt_en_a_jk;\r
+  reg           rx_cnt_en_b;\r
+  reg           rx_rdy_loc;\r
+  reg           rx_rdy_pre;\r
+  wire          en_loopback;\r
+  wire          en_fast_autobaud;\r
+  reg  [7:0]    tx_byte_loc;\r
+  reg           tx_en_loc;\r
+  reg  [9:0]    tx_sr;\r
+  reg           txd_loc;\r
+  reg           rxd_fal;\r
+  reg           rxd_ris;\r
+  reg  [7:0]    rxd_fal_sr;\r
+  reg           tx_shift;\r
+  reg           tx_now;\r
+  reg           rx_ascii_cr;\r
+  reg           rx_bad_symbol;\r
+  reg  [7:0]    dbg_loc;\r
+  reg  [7:0]    dbg_loc_p1;\r
+  reg  [3:0]    dbg_cnt;\r
+  reg           sample_first;\r
+\r
+\r
+// Send RXD to TXD to test circuit\r
+  assign en_loopback = 0;\r
+//assign en_fast_autobaud = 0;\r
+  assign en_fast_autobaud = 1;\r
+  assign rx_idle = 0;\r
+\r
+// When baud_lock asserts, send "\n" to downstream nodes for detection\r
+  assign baud_rate = baud_rate_loc[15:0];\r
+  assign baud_lock = baud_lock_jk;\r
+\r
+//-----------------------------------------------------------------------------\r
+// Output some debug signals for Saleae. Pulse extend short events\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_dbg\r
+ begin\r
+// dbg_loc[0] <= ~ rxd_meta;\r
+   dbg_loc[0] <= rxd_sample;\r
+   dbg_loc[1] <= txd_loc;\r
+   dbg_loc[2] <= bit_lock_jk;\r
+   dbg_loc[3] <= baud_lock_jk;\r
+// dbg_loc[4] <= sample_now;\r
+   dbg_loc[4] <= reset;\r
+// dbg_loc[5] <= rx_rdy_loc;\r
+   dbg_loc[5] <= clr_jk;\r
+   dbg_loc[6] <= dbg_sample_togl;\r
+   dbg_loc[7] <= dbg_byte_togl;\r
+// dbg_loc[7] <= bad_jk;\r
+// dbg_loc[7] <= rx_ascii_cr;\r
+   dbg_loc_p1 <= dbg_loc[7:0];\r
+\r
+   // Extend transitions for Saleae\r
+   if ( dbg_cnt != 4'hF ) begin\r
+     dbg_cnt <= dbg_cnt + 1;\r
+   end\r
+\r
+   if ( dbg_loc[7:4] != dbg_loc_p1[7:4] && dbg_cnt == 4'hF ) begin\r
+     dbg     <= dbg_loc[7:0];\r
+     dbg_cnt <= 4'h0;\r
+   end\r
+   if ( reset == 1 ) begin\r
+     dbg_cnt <= 4'h0;\r
+   end\r
+\r
+   dbg[0] <= dbg_loc[0];\r
+   dbg[1] <= dbg_loc[1];\r
+   dbg[2] <= dbg_loc[2];\r
+   dbg[3] <= dbg_loc[3];\r
+\r
+ end \r
+end // proc_din\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Asynchronous sampling of RXD into 4 bit Shift Register\r
+// Note: RXD is immediately inverted to prevent runt '0's from pipeline \r
+// being detected as start bits. FPGA Flops powerup to '0', so inverting fixes.\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_din\r
+ begin\r
+   rxd_meta    <= ~ rxd;// Note Inversion to prevent runt post config\r
+   rxd_loc     <= rxd_meta;\r
+// rxd_sr[7:0] <= { rxd_sr[6:0], rxd_meta };\r
+   rxd_sr[7:0] <= { rxd_sr[6:0], rxd_loc  };\r
+   rxd_fal <= 0;\r
+   rxd_ris <= 0;\r
+\r
+// if ( rxd_sr[3:0] == 4'b0001 ) begin      \r
+// if ( rxd_sr[2:0] == 3'b001 ) begin      \r
+// if ( rxd_sr[2:0] == 3'b011 ) begin      \r
+   if ( rxd_sr[7:6] == 2'b00 && rxd_sr[2:0] == 3'b011 ) begin      \r
+     rxd_fal <= 1;\r
+   end \r
+// if ( rxd_sr[3:0] == 4'b1110 ) begin      \r
+// if ( rxd_sr[2:0] == 3'b110 ) begin      \r
+// if ( rxd_sr[2:0] == 3'b100 ) begin      \r
+   if ( rxd_sr[7:6] == 2'b11 && rxd_sr[2:0] == 3'b100 ) begin      \r
+     rxd_ris <= 1;\r
+   end \r
+\r
+ end \r
+end // proc_din\r
+  assign rxd_sample = ~ rxd_sr[2];\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// 16bit Counter used for both rx_start_bit width count and sample count\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_cnt\r
+ begin\r
+\r
+  if ( rx_start_a == 1 || rx_start_b == 1 ) begin\r
+    rx_cnt_16b <= 16'd0;\r
+  end else if ( rx_cnt_en_a_jk == 1 || \r
+                rx_cnt_en_b    == 1    ) begin\r
+    rx_cnt_16b <= rx_cnt_16b + 1;\r
+  end\r
+\r
+  if ( en_fast_autobaud == 1 ) begin\r
+    rx_cnt_16b[15:12] <= 4'd0;\r
+    rx_cnt_16b_p1    <= rx_cnt_16b[11];\r
+    rx_cnt_16b_roll  <= rx_cnt_16b_p1 & ~ rx_cnt_16b[11];\r
+  end else begin\r
+    rx_cnt_16b_p1    <= rx_cnt_16b[15];\r
+    rx_cnt_16b_roll  <= rx_cnt_16b_p1 & ~ rx_cnt_16b[15];\r
+  end\r
+\r
+  rx_cnt_16b[15:8] <= 8'd0;// 2016_10_17\r
+\r
+ end\r
+end // proc_cnt\r
+\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Autobaud off "\n" character. Tricky, as both start bit at D0 are 0.\r
+// When there is no bit_lock, look for falling edge of RXD and count width of \r
+// StartBit and the 1st '0' of 0xA "\n" "01010000". \r
+// bit_lock remains on unless we don't get baud_lock \r
+// bit_lock  == Think we know where to sample each symbol.\r
+// baud_lock == We sampled 8 symbols and got 0x0A or "\n"\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_s1 \r
+ begin\r
+  sample_first   <= 0;\r
+  rx_start_a     <= 0;\r
+  bit_lock_jk_p1 <= bit_lock_jk;\r
+  if ( bit_lock_jk == 0 && baud_lock_jk == 0 ) begin\r
+    if ( rxd_fal == 1 ) begin\r
+      rx_start_a     <= 1;\r
+      rx_cnt_en_a_jk <= 1;\r
+    end else if ( rxd_ris == 1 && rx_cnt_en_a_jk == 1 ) begin\r
+      baud_rate_loc  <= { 1'b0, rx_cnt_16b[15:1] } - 16'd1;// Div2 Shift\r
+      bit_lock_jk    <= 1;\r
+      rx_start_a     <= 1;\r
+      rx_cnt_en_a_jk <= 0;\r
+      sample_first   <= 1;\r
+    end\r
+  end else begin\r
+    rx_cnt_en_a_jk <= 0;\r
+  end\r
+\r
+  if (   clr_bit_lock == 1 ) begin\r
+    bit_lock_jk <= 0;\r
+  end\r
+\r
+  if ( en_fast_autobaud == 1 ) begin\r
+    baud_rate_loc[15:12] <= 4'd0;\r
+  end\r
+\r
+//if ( en_autobaud == 0 ) begin\r
+//  baud_rate_loc <= 16'd43;\r
+//  bit_lock_jk   <= 1;\r
+//end\r
+\r
+// fix baud rate for smaller design. Note the subtract-2\r
+//baud_rate_loc[15:0] <= 16'd109;// 100 MHz / 921600 baud\r
+//baud_rate_loc[15:0] <= 16'd104;//  96 MHz / 921600 baud = WORKS\r
+//baud_rate_loc[15:0] <= 16'd104;//  12 MHz / 115200 baud = WORKS \r
+  baud_rate_loc[15:0] <= 16'd24;//   24 MHz / 921600 baud = WORKS\r
+//baud_rate_loc[15:0] <= 16'd12;//   12 MHz / 921600 baud = DOESNT WORK\r
+//bit_lock_jk   <= 1;\r
+\r
+ end\r
+end // proc_s1 \r
+  assign flush = rx_ascii_cr;\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// Decode the character bytes\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_s3 \r
+ begin\r
+   rx_ascii_cr   <= 0;\r
+   rx_bad_symbol <= 0;\r
+   clr_bit_lock  <= 0; \r
+   rx_rdy_loc    <= 0;\r
+   rx_rdy        <= rx_rdy_loc & baud_lock_jk;\r
+\r
+   // Assert baud_lock if 1st char is "\n" else clear and start over.\r
+   if ( sample_now_p1  == 1 && rx_bit_cnt == 4'd9 ) begin\r
+     if ( rx_byte_loc[7:0] == 8'h0a ) begin\r
+       baud_lock_jk <= 1;\r
+       rx_ascii_cr  <= 1;\r
+       clr_jk <= 0;\r
+       bad_jk <= 0;\r
+     end else if ( baud_lock_jk == 0 ) begin\r
+       clr_bit_lock <= 1;\r
+     end\r
+     // Only expect ASCII 0x20 - 0x7F, detect 0x80+ as bad and clear baud lock\r
+     if ( rx_byte_loc[7] == 1 ) begin     \r
+       rx_bad_symbol <= 1;\r
+     end\r
+     // Only expect ASCII 0x20 - 0x7F, detect under 0x20 and clear baud lock\r
+     if ( rx_byte_loc != 8'h0A && rx_byte_loc < 8'h20 ) begin\r
+       rx_bad_symbol <= 1;\r
+     end\r
+   end\r
+\r
+   // Grab received byte after last bit received\r
+   if ( sample_now_p1  == 1 && rx_bit_cnt == 4'd9 ) begin\r
+     rx_rdy_loc <= 1;\r
+   end\r
+\r
+   if ( reset == 1 || rx_bad_symbol == 1 || clr_baudlock == 1 ) begin\r
+     baud_lock_jk <= 0;\r
+     clr_bit_lock <= 1;\r
+     rx_rdy_loc   <= 0;\r
+   end\r
+\r
+// if ( dbg_sample_togl != dbg_sample_togl_p1 ) begin\r
+//   clr_jk <= 0;\r
+//   bad_jk <= 0;\r
+// end\r
+   if ( rx_bad_symbol == 1 ) begin\r
+     bad_jk <= 1;\r
+   end \r
+   if ( clr_baudlock == 1 ) begin\r
+     clr_jk <= 1;\r
+   end \r
+   if ( reset == 1 ) begin\r
+     clr_jk <= 0;\r
+     bad_jk <= 0;\r
+   end\r
+   \r
+\r
+ end\r
+end // proc_s3 \r
+\r
+  assign rx_byte_loc = rx_byte_sr[8:1];\r
+  assign rx_byte     = rx_byte_sr[8:1];\r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// look for falling edge of rx_start_bit and count 1/2 way into bit and sample\r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_s2 \r
+ begin\r
+  tx_en_loc     <= 0;\r
+  sample_now    <= 0;\r
+  rx_start_b    <= 0;\r
+  rx_cnt_en_b   <= 0;\r
+  rx_byte_jk_p1    <= rx_byte_jk;\r
+  sample_now_p1 <= sample_now;\r
+  dbg_sample_togl_p1 <= dbg_sample_togl;\r
+\r
+  if ( rx_byte_jk == 0 ) begin\r
+    rx_bit_cnt <= 4'd0;\r
+    if ( rxd_fal == 1 ) begin\r
+      rx_start_b <= 1;\r
+      rx_byte_jk <= 1;// Starting a new Byte\r
+      dbg_byte_togl <= ~dbg_byte_togl;\r
+    end\r
+  end\r
+\r
+  // When to start sample_now is tricky as for bit_lock, it is 1/2 baud into\r
+  // the D1 data bit of \n, after lock, it is 1/2 baud into D0 data bit.\r
+  // cnt=0 is StartBit, cnt=1 is D0, cnt=2 is D1\r
+  if ( bit_lock_jk == 1 && rx_byte_jk == 1 ) begin\r
+    rx_cnt_en_b  <= 1;\r
+    if ( \r
+         ( baud_lock_jk == 0 && rx_bit_cnt == 4'd2 ) ||\r
+         ( baud_lock_jk == 1 && rx_bit_cnt == 4'd1 )    ) begin\r
+      // Div-2 baud count to sample middle of eye\r
+      if ( rx_cnt_16b[15:0] == { 1'b0, baud_rate_loc[15:1] } ) begin\r
+        rx_bit_cnt <= rx_bit_cnt + 1;\r
+        rx_start_b <= 1;\r
+        sample_now <= 1;\r
+      end\r
+    end else if ( rx_cnt_16b[15:0] == baud_rate_loc[15:0] ) begin\r
+      rx_bit_cnt <= rx_bit_cnt + 1;\r
+      rx_start_b <= 1;\r
+      sample_now <= 1;\r
+    end\r
+  end\r
+\r
+  //  Assume "\n" and stuff the 1st 0 since it already flew by\r
+  if ( sample_first == 1 ) begin\r
+    rx_bit_cnt <= 4'd2;\r
+    rx_byte_sr[8]   <= 0;\r
+    rx_byte_sr[7:0] <= rx_byte_sr[8:1];\r
+  end\r
+\r
+  if ( sample_now == 1 ) begin\r
+    rx_byte_sr[8]   <= rxd_sample;\r
+    rx_byte_sr[7:0] <= rx_byte_sr[8:1];\r
+    dbg_sample_togl <= ~dbg_sample_togl;\r
+  end\r
+\r
+  if ( sample_now_p1 == 1 && rx_bit_cnt == 4'd9  ) begin\r
+    rx_byte_jk <= 0;\r
+    rx_bit_cnt <= 4'd0;\r
+  end\r
+\r
+  if ( rx_rdy_loc == 1 && baud_lock_jk == 1 && en_loopback == 1 ) begin\r
+    tx_byte_loc <= rx_byte_loc[7:0];  \r
+    tx_en_loc   <= 1;\r
+  end else if ( tx_en == 1 ) begin\r
+    tx_byte_loc <= tx_byte[7:0];  \r
+    tx_en_loc   <= 1;\r
+  end\r
+\r
+  if ( reset == 1 ) begin\r
+    rx_byte_jk <= 0;\r
+    rx_byte_sr[8:0] <= 9'd0;\r
+    dbg_sample_togl <= 0;\r
+    dbg_byte_togl <= 0;\r
+  end\r
+\r
+ end\r
+end // proc_s2 \r
+\r
+\r
+//-----------------------------------------------------------------------------\r
+// TX : Load 8bits into 10bit SR and shift out at the RX baud rate    \r
+//-----------------------------------------------------------------------------\r
+always @ ( posedge clk ) begin : proc_tx \r
+ begin\r
+  tx_shift <= 0;\r
+  tx_busy  <= 0;\r
+//txd      <= txd_loc;\r
+  txd      <= tx_sr[0];\r
+  txd_loc  <= tx_sr[0];\r
+//txd_loc  <= tx_sr[0] | ~ baud_lock;\r
+  tx_now   <= 0;\r
+\r
+  // Load a new Byte to send\r
+  if ( tx_en_loc == 1 ) begin\r
+    tx_bit_cnt <= 4'd10;\r
+    tx_cnt_16b <= 16'h0000;\r
+    tx_idle    <= 0;\r
+    tx_busy    <= 1;\r
+    tx_shift   <= 1;\r
+    tx_sr[9:0] <= { 1'b1, tx_byte_loc[7:0], 1'b0 };\r
+\r
+  // Shift and send the byte until bit_cnt goes to 0\r
+  end else if ( tx_bit_cnt != 4'd0 ) begin\r
+    tx_cnt_16b <= tx_cnt_16b + 1;\r
+    tx_busy    <= 1;\r
+    tx_idle    <= 0;\r
+    if ( tx_now == 1 ) begin\r
+      tx_shift   <= 1;\r
+      tx_bit_cnt <= tx_bit_cnt[3:0] - 1;\r
+      tx_cnt_16b <= 16'h0000;\r
+      tx_sr[9:0] <= { 1'b1, tx_sr[9:1] };\r
+    end\r
+  end else begin\r
+    tx_sr <= 10'H3FF;\r
+    if ( tx_now == 1 ) begin\r
+      tx_idle <= 1;\r
+    end else begin\r
+      tx_cnt_16b <= tx_cnt_16b + 1;\r
+    end\r
+  end\r
+\r
+  if ( tx_cnt_16b[15:0] == baud_rate_loc[15:0] ) begin\r
+    tx_now <= 1;\r
+  end\r
+\r
+  if ( reset == 1 ) begin\r
+    tx_bit_cnt <= 4'd0;\r
+    tx_idle    <= 1;\r
+  end\r
+\r
+  if ( en_fast_autobaud == 1 ) begin\r
+    tx_cnt_16b[15:12] <= 4'd0;\r
+  end\r
+\r
+ end\r
+end // proc_tx\r
+\r
+\r
+endmodule // mesa_uart\r