`timescale 1ps / 1ps module SerialUart ( Clk, Reset, RX, TX, Read_RX_FIFO, Write_TX_FIFO, TX_Buffer_Full, RX_Data_Present, TX_Data, RX_Data ); input Clk; input Reset; input RX; output TX; input Read_RX_FIFO; input Write_TX_FIFO; output TX_Buffer_Full; output RX_Data_Present; input [7:0] TX_Data; output [7:0] RX_Data; wire uart_internal_clock; wire uart_x4_internal_clock; wire RX_FIFO_Empty; assign RX_Data_Present = !RX_FIFO_Empty; /* 57600 * 4 = 230400 50x10^6/230400 = 217 or 7 * 31 div0 = 7 - 2 div1 = 31 // 9600 parameter div0 = 8'd4, //4, div1 = 8'd217; // 217; */ // Set the UART Clk divisor for 56kbaud // 57600 //parameter div0 = 8'd2, // div1 = 8'd27; parameter div0 = 8'd5, div1 = 8'd31; // // Baud rate generator // sasc_brg uart_baud_rate_generator( .clk( Clk ), .rst( Reset ), .div0( div0 ), .div1( div1 ), .sio_ce( uart_internal_clock ), .sio_ce_x4( uart_x4_internal_clock ) ); sasc_top uart_sasc_top( .clk( Clk ), .rst( Reset ), // extrnal interfaces .rxd_i( RX ), .txd_o( TX ), // Clear to Send, 0 .cts_i( 1'b0 ), // ' // Ready to send, not hooked up externally .rts_o( uart_sasc_top_rts ), // brg hookups .sio_ce( uart_internal_clock ), .sio_ce_x4( uart_x4_internal_clock ), .din_i( TX_Data ), .dout_o( RX_Data ), .re_i( Read_RX_FIFO ), .we_i( Write_TX_FIFO ), .full_o( TX_Buffer_Full ), .empty_o( RX_FIFO_Empty ) ); endmodule /* Serial IO Interface =============================== RTS I Request To Send CTS O Clear to send TD I Transmit Data RD O Receive Data */ module sasc_top( clk, rst, // SIO rxd_i, txd_o, cts_i, rts_o, // External Baud Rate Generator sio_ce, sio_ce_x4, // Internal Interface din_i, dout_o, re_i, we_i, full_o, empty_o); input clk; input rst; input rxd_i; output txd_o; input cts_i; output rts_o; input sio_ce; input sio_ce_x4; input [7:0] din_i; output [7:0] dout_o; input re_i, we_i; output full_o, empty_o; /////////////////////////////////////////////////////////////////// // // Local Wires and Registers // parameter START_BIT = 1'b0, STOP_BIT = 1'b1, IDLE_BIT = 1'b1; wire [7:0] txd_p; reg load; reg load_r; wire load_e; reg [9:0] hold_reg; wire txf_empty; reg txd_o; reg shift_en; reg [3:0] tx_bit_cnt; reg rxd_s, rxd_r; wire start; reg [3:0] rx_bit_cnt; reg rx_go; reg [9:0] rxr; reg rx_valid, rx_valid_r; wire rx_we; wire rxf_full; reg rts_o; reg txf_empty_r; reg shift_en_r; reg rxd_r1, rxd_r2; //wire lock_en; reg change; reg rx_sio_ce_d, rx_sio_ce_r1, rx_sio_ce_r2, rx_sio_ce; reg [1:0] dpll_state, dpll_next_state; /////////////////////////////////////////////////////////////////// // // IO Fifo's // sasc_fifo4 tx_fifo( .clk( clk ), .rst( rst ), .clr( 1'b0 ), .din( din_i ), .we( we_i ), .dout( txd_p ), .re( load_e ), .full( full_o ), .empty( txf_empty ) ); sasc_fifo4 rx_fifo( .clk( clk ), .rst( rst ), .clr( 1'b0 ), .din( rxr[9:2] ), .we( rx_we ), .dout( dout_o ), .re( re_i ), .full( rxf_full ), .empty( empty_o ) ); /////////////////////////////////////////////////////////////////// // // Transmit Logic // always @(posedge clk) if(rst) txf_empty_r <= #1 1'b1; else if(sio_ce) txf_empty_r <= #1 txf_empty; always @(posedge clk) load <= #1 !txf_empty_r & !shift_en & !cts_i; always @(posedge clk) load_r <= #1 load; assign load_e = load & sio_ce; always @(posedge clk) if(load_e) hold_reg <= #1 {STOP_BIT, txd_p, START_BIT}; else if(shift_en & sio_ce) hold_reg <= #1 {IDLE_BIT, hold_reg[9:1]}; always @(posedge clk) if(rst) txd_o <= #1 IDLE_BIT; else if(sio_ce) if(shift_en | shift_en_r) txd_o <= #1 hold_reg[0]; else txd_o <= #1 IDLE_BIT; always @(posedge clk) if(rst) tx_bit_cnt <= #1 4'h9; else if(load_e) tx_bit_cnt <= #1 4'h0; else if(shift_en & sio_ce) tx_bit_cnt <= #1 tx_bit_cnt + 4'h1; always @(posedge clk) shift_en <= #1 (tx_bit_cnt != 4'h9); always @(posedge clk) if(rst) shift_en_r <= #1 1'b0; else if(sio_ce) shift_en_r <= #1 shift_en; /////////////////////////////////////////////////////////////////// // // Recieve Logic // always @(posedge clk) rxd_s <= #1 rxd_i; always @(posedge clk) rxd_r <= #1 rxd_s; assign start = (rxd_r == IDLE_BIT) & (rxd_s == START_BIT); always @(posedge clk) if(rst) rx_bit_cnt <= #1 4'ha; else if(!rx_go & start) rx_bit_cnt <= #1 4'h0; else if(rx_go & rx_sio_ce) rx_bit_cnt <= #1 rx_bit_cnt + 4'h1; always @(posedge clk) rx_go <= #1 (rx_bit_cnt != 4'ha); always @(posedge clk) rx_valid <= #1 (rx_bit_cnt == 4'h9); always @(posedge clk) rx_valid_r <= #1 rx_valid; assign rx_we = !rx_valid_r & rx_valid & !rxf_full; always @(posedge clk) if(rx_go & rx_sio_ce) rxr <= {rxd_s, rxr[9:1]}; always @(posedge clk) rts_o <= #1 rxf_full; /////////////////////////////////////////////////////////////////// // // Reciever DPLL // // Uses 4x baud clock to lock to incoming stream // Edge detector always @(posedge clk) if(sio_ce_x4) rxd_r1 <= #1 rxd_s; always @(posedge clk) if(sio_ce_x4) rxd_r2 <= #1 rxd_r1; always @(posedge clk) if(rst) change <= #1 1'b0; else if(rxd_r != rxd_s) change <= #1 1'b1; else if(sio_ce_x4) change <= #1 1'b0; // DPLL FSM always @(posedge clk or posedge rst) if(rst) dpll_state <= #1 2'h1; else if(sio_ce_x4) dpll_state <= #1 dpll_next_state; always @(dpll_state or change) begin rx_sio_ce_d = 1'b0; case(dpll_state) 2'h0: if(change) dpll_next_state = 3'h0; else dpll_next_state = 3'h1; 2'h1:begin rx_sio_ce_d = 1'b1; if(change) dpll_next_state = 3'h3; else dpll_next_state = 3'h2; end 2'h2: if(change) dpll_next_state = 3'h0; else dpll_next_state = 3'h3; 2'h3: if(change) dpll_next_state = 3'h0; else dpll_next_state = 3'h0; endcase end // Compensate for sync registers at the input - allign sio // clock enable to be in the middle between two bit changes ... always @(posedge clk) rx_sio_ce_r1 <= #1 rx_sio_ce_d; always @(posedge clk) rx_sio_ce_r2 <= #1 rx_sio_ce_r1; always @(posedge clk) rx_sio_ce <= #1 rx_sio_ce_r1 & !rx_sio_ce_r2; endmodule module sasc_brg(clk, rst, div0, div1, sio_ce, sio_ce_x4); input clk; input rst; input [7:0] div0, div1; output sio_ce, sio_ce_x4; /////////////////////////////////////////////////////////////////// // // Local Wires and Registers // reg [7:0] ps; reg ps_clr; reg [7:0] br_cnt; reg br_clr; reg sio_ce_x4_r; reg [1:0] cnt; reg sio_ce, sio_ce_x4; reg sio_ce_r ; reg sio_ce_x4_t; /////////////////////////////////////////////////////////////////// // // Boud Rate Generator // // ----------------------------------------------------- // Prescaler always @(posedge clk) if(rst) ps <= #1 8'h0; else if(ps_clr) ps <= #1 8'h0; else ps <= #1 ps + 8'h1; always @(posedge clk) ps_clr <= #1 (ps == div0); // Desired number of cycles less 2 // ----------------------------------------------------- // Oversampled Boud Rate (x4) always @(posedge clk) if(rst) br_cnt <= #1 8'h0; else if(br_clr) br_cnt <= #1 8'h0; else if(ps_clr) br_cnt <= #1 br_cnt + 8'h1; always @(posedge clk) br_clr <= #1 (br_cnt == div1); // Prciese number of PS cycles always @(posedge clk) sio_ce_x4_r <= #1 br_clr; always @(posedge clk) sio_ce_x4_t <= #1 !sio_ce_x4_r & br_clr; always @(posedge clk) sio_ce_x4 <= #1 sio_ce_x4_t; // ----------------------------------------------------- // Actual Boud rate always @(posedge clk) if(rst) cnt <= #1 2'h0; else if(!sio_ce_x4_r & br_clr) cnt <= #1 cnt + 2'h1; always @(posedge clk) sio_ce_r <= #1 (cnt == 2'h0); always @(posedge clk) sio_ce <= #1 !sio_ce_r & (cnt == 2'h0); endmodule module sasc_fifo4(clk, rst, clr, din, we, dout, re, full, empty); input clk, rst; input clr; input [7:0] din; input we; output [7:0] dout; input re; output full, empty; //////////////////////////////////////////////////////////////////// // // Local Wires // reg [7:0] mem[0:3]; reg [1:0] wp; reg [1:0] rp; wire [1:0] wp_p1; wire [1:0] wp_p2; wire [1:0] rp_p1; wire full, empty; reg gb; //////////////////////////////////////////////////////////////////// // // Misc Logic // always @(posedge clk or posedge rst) if(rst) wp <= #1 2'h0; else if(clr) wp <= #1 2'h0; else if(we) wp <= #1 wp_p1; assign wp_p1 = wp + 2'h1; assign wp_p2 = wp + 2'h2; always @(posedge clk or posedge rst) if(rst) rp <= #1 2'h0; else if(clr) rp <= #1 2'h0; else if(re) rp <= #1 rp_p1; assign rp_p1 = rp + 2'h1; // Fifo Output assign dout = mem[ rp ]; // Fifo Input always @(posedge clk) if(we) mem[ wp ] <= #1 din; // Status assign empty = (wp == rp) & !gb; assign full = (wp == rp) & gb; // Guard Bit ... always @(posedge clk) if(rst) gb <= #1 1'b0; else if(clr) gb <= #1 1'b0; else if((wp_p1 == rp) & we) gb <= #1 1'b1; else if(re) gb <= #1 1'b0; endmodule