--- /dev/null
+/* ****************************************************************************\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