URL
https://opencores.org/ocsvn/amber/amber/trunk
Subversion Repositories amber
[/] [amber/] [trunk/] [hw/] [vlog/] [system/] [uart.v] - Rev 54
Go to most recent revision | Compare with Previous | Blame | View Log
////////////////////////////////////////////////////////////////// // // // UART // // // // This file is part of the Amber project // // http://www.opencores.org/project,amber // // // // Description // // This is a synchronous UART meaning it uses the system // // clock rather than having its own clock. This means the // // standard UART Baud rates are approximated and not exact. // // However the UART tandard provides for a 10% margin on // // baud rates and this module is much more accurate than that. // // // // The Baud rate must be set before synthesis and is not // // programmable. This keeps the UART small. // // // // The UART uses 8 data bits, 1 stop bit and no parity bits. // // // // The UART has a 16-byte transmit and a 16-byte receive FIFO // // These FIFOs are implemented in flipflops - FPGAs have lots // // of flipflops! // // // // Author(s): // // - Conor Santifort, csantifort.amber@gmail.com // // // ////////////////////////////////////////////////////////////////// // // // Copyright (C) 2010 Authors and OPENCORES.ORG // // // // This source file may be used and distributed without // // restriction provided that this copyright statement is not // // removed from the file and that any derivative work contains // // the original copyright notice and the associated disclaimer. // // // // This source file is free software; you can redistribute it // // and/or modify it under the terms of the GNU Lesser General // // Public License as published by the Free Software Foundation; // // either version 2.1 of the License, or (at your option) any // // later version. // // // // This source is distributed in the hope that it will be // // useful, but WITHOUT ANY WARRANTY; without even the implied // // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // // PURPOSE. See the GNU Lesser General Public License for more // // details. // // // // You should have received a copy of the GNU Lesser General // // Public License along with this source; if not, download it // // from http://www.opencores.org/lgpl.shtml // // // ////////////////////////////////////////////////////////////////// `include "system_config_defines.v" // Normally AMBER_UART_BAUD is defined in the system_config_defines.v file. `ifndef AMBER_UART_BAUD `define AMBER_UART_BAUD 230400 `endif module uart #( parameter WB_DWIDTH = 32, parameter WB_SWIDTH = 4 )( input i_clk, input [31:0] i_wb_adr, input [WB_SWIDTH-1:0] i_wb_sel, input i_wb_we, output [WB_DWIDTH-1:0] o_wb_dat, input [WB_DWIDTH-1:0] i_wb_dat, input i_wb_cyc, input i_wb_stb, output o_wb_ack, output o_wb_err, output o_uart_int, input i_uart_cts_n, // Clear To Send output o_uart_txd, // Transmit data output o_uart_rts_n, // Request to Send input i_uart_rxd // Receive data ); `include "register_addresses.v" localparam [3:0] TXD_IDLE = 4'd0, TXD_START = 4'd1, TXD_DATA0 = 4'd2, TXD_DATA1 = 4'd3, TXD_DATA2 = 4'd4, TXD_DATA3 = 4'd5, TXD_DATA4 = 4'd6, TXD_DATA5 = 4'd7, TXD_DATA6 = 4'd8, TXD_DATA7 = 4'd9, TXD_STOP1 = 4'd10, TXD_STOP2 = 4'd11, TXD_STOP3 = 4'd12; localparam [3:0] RXD_IDLE = 4'd0, RXD_START = 4'd1, RXD_START_MID = 4'd2, RXD_START_MID1 = 4'd3, RXD_DATA0 = 4'd4, RXD_DATA1 = 4'd5, RXD_DATA2 = 4'd6, RXD_DATA3 = 4'd7, RXD_DATA4 = 4'd8, RXD_DATA5 = 4'd9, RXD_DATA6 = 4'd10, RXD_DATA7 = 4'd11, RXD_STOP = 4'd12; localparam RX_INTERRUPT_COUNT = 24'h3fffff; // ------------------------------------------------------------------------- // Baud Rate Configuration // ------------------------------------------------------------------------- `ifndef Veritak localparam real UART_BAUD = `AMBER_UART_BAUD; // Hz `ifdef XILINX_VIRTEX6_FPGA localparam real CLK_FREQ = 1200.0 / `AMBER_CLK_DIVIDER ; // MHz `else localparam real CLK_FREQ = 800.0 / `AMBER_CLK_DIVIDER ; // MHz `endif localparam real UART_BIT_PERIOD = 1000000000 / UART_BAUD; // nS localparam real UART_WORD_PERIOD = ( UART_BIT_PERIOD * 12 ); // nS localparam real CLK_PERIOD = 1000 / CLK_FREQ; // nS localparam real CLKS_PER_WORD = UART_WORD_PERIOD / CLK_PERIOD; localparam real CLKS_PER_BIT = CLKS_PER_WORD / 12; // These are rounded to the nearest whole number // i.e. 29.485960 -> 29 // 29.566303 -> 30 localparam [9:0] TX_BITPULSE_COUNT = CLKS_PER_BIT; localparam [9:0] TX_CLKS_PER_WORD = CLKS_PER_WORD; `else localparam [9:0] TX_BITPULSE_COUNT = 30; localparam [9:0] TX_CLKS_PER_WORD = 360; `endif localparam [9:0] TX_BITADJUST_COUNT = TX_CLKS_PER_WORD - 11*TX_BITPULSE_COUNT; localparam [9:0] RX_BITPULSE_COUNT = TX_BITPULSE_COUNT-2; localparam [9:0] RX_HALFPULSE_COUNT = TX_BITPULSE_COUNT/2 - 4; // ------------------------------------------------------------------------- reg tx_interrupt = 'd0; reg rx_interrupt = 'd0; reg [23:0] rx_int_timer = 'd0; wire fifo_enable; reg [7:0] tx_fifo [0:15]; wire tx_fifo_full; wire tx_fifo_empty; wire tx_fifo_half_or_less_full; wire tx_fifo_push; wire tx_fifo_push_not_full; wire tx_fifo_pop_not_empty; reg [4:0] tx_fifo_wp = 'd0; reg [4:0] tx_fifo_rp = 'd0; reg [4:0] tx_fifo_count = 'd0; // number of entries in the fifo reg tx_fifo_full_flag = 'd0; reg [7:0] rx_fifo [0:15]; reg rx_fifo_empty = 1'd1; reg rx_fifo_full = 1'd0; wire rx_fifo_half_or_more; // true when half full or greater reg [4:0] rx_fifo_count = 'd0; // number of entries in the fifo wire rx_fifo_push; wire rx_fifo_push_not_full; wire rx_fifo_pop; wire rx_fifo_pop_not_empty; reg [4:0] rx_fifo_wp = 'd0; reg [4:0] rx_fifo_rp = 'd0; wire [7:0] tx_byte; reg [3:0] txd_state = TXD_IDLE; reg txd = 1'd1; reg tx_bit_pulse = 'd0; reg [9:0] tx_bit_pulse_count = 'd0; reg [7:0] rx_byte = 'd0; reg [3:0] rxd_state = RXD_IDLE; wire rx_start; reg rxen = 'd0; reg [9:0] rx_bit_pulse_count = 'd0; reg restart_rx_bit_count = 'd0; reg [4:0] rxd_d = 5'h1f; reg [3:0] uart0_cts_n_d = 4'hf; // Wishbone registers reg [7:0] uart_rsr_reg = 'd0; // Receive status, (Write) Error Clear reg [7:0] uart_lcrh_reg = 'd0; // Line Control High Byte reg [7:0] uart_lcrm_reg = 'd0; // Line Control Middle Byte reg [7:0] uart_lcrl_reg = 'd0; // Line Control Low Byte reg [7:0] uart_cr_reg = 'd0; // Control Register // Wishbone interface reg [31:0] wb_rdata32 = 'd0; wire wb_start_write; wire wb_start_read; reg wb_start_read_d1 = 'd0; wire [31:0] wb_wdata32; integer i; // ====================================================== // Wishbone Interface // ====================================================== // Can't start a write while a read is completing. The ack for the read cycle // needs to be sent first assign wb_start_write = i_wb_stb && i_wb_we && !wb_start_read_d1; assign wb_start_read = i_wb_stb && !i_wb_we && !o_wb_ack; always @( posedge i_clk ) wb_start_read_d1 <= wb_start_read; assign o_wb_err = 1'd0; assign o_wb_ack = i_wb_stb && ( wb_start_write || wb_start_read_d1 ); generate if (WB_DWIDTH == 128) begin : wb128 assign wb_wdata32 = i_wb_adr[3:2] == 2'd3 ? i_wb_dat[127:96] : i_wb_adr[3:2] == 2'd2 ? i_wb_dat[ 95:64] : i_wb_adr[3:2] == 2'd1 ? i_wb_dat[ 63:32] : i_wb_dat[ 31: 0] ; assign o_wb_dat = {4{wb_rdata32}}; end else begin : wb32 assign wb_wdata32 = i_wb_dat; assign o_wb_dat = wb_rdata32; end endgenerate // ====================================================== // UART 0 Receive FIFO // ====================================================== assign rx_fifo_pop = wb_start_read && i_wb_adr[15:0] == AMBER_UART_DR; assign rx_fifo_push_not_full = rx_fifo_push && !rx_fifo_full; assign rx_fifo_pop_not_empty = rx_fifo_pop && !rx_fifo_empty; assign rx_fifo_half_or_more = rx_fifo_count >= 5'd8; always @ ( posedge i_clk ) begin if ( fifo_enable ) begin // RX FIFO Push if ( rx_fifo_push_not_full ) begin rx_fifo[rx_fifo_wp[3:0]] <= rx_byte; rx_fifo_wp <= rx_fifo_wp + 1'd1; end if ( rx_fifo_pop_not_empty ) begin rx_fifo_rp <= rx_fifo_rp + 1'd1; end if ( rx_fifo_push_not_full && !rx_fifo_pop_not_empty ) rx_fifo_count <= rx_fifo_count + 1'd1; else if ( rx_fifo_pop_not_empty && !rx_fifo_push_not_full ) rx_fifo_count <= rx_fifo_count - 1'd1; rx_fifo_full <= rx_fifo_wp == {~rx_fifo_rp[4], rx_fifo_rp[3:0]}; rx_fifo_empty <= rx_fifo_wp == rx_fifo_rp; if ( rx_fifo_empty || rx_fifo_pop ) rx_int_timer <= 'd0; else if ( rx_int_timer != RX_INTERRUPT_COUNT ) rx_int_timer <= rx_int_timer + 1'd1; end else // No FIFO begin rx_int_timer <= 'd0; if ( rx_fifo_push ) begin rx_fifo[0] <= rx_byte; rx_fifo_empty <= 1'd0; rx_fifo_full <= 1'd1; end else if ( rx_fifo_pop ) begin rx_fifo_empty <= 1'd1; rx_fifo_full <= 1'd0; end end end // ====================================================== // Transmit Interrupts // ====================================================== // UART 0 Transmit Interrupt always @ ( posedge i_clk ) begin // Clear the interrupt if ( wb_start_write && i_wb_adr[15:0] == AMBER_UART_ICR ) tx_interrupt <= 1'd0; // Set the interrupt else if ( fifo_enable ) // This interrupt clears automatically as bytes are pushed into the tx fifo // cr bit 5 is Transmit Interrupt Enable tx_interrupt <= tx_fifo_half_or_less_full && uart_cr_reg[5]; else // This interrupt clears automatically when a byte is written to tx // cr bit 5 is Transmit Interrupt Enable tx_interrupt <= tx_fifo_empty && uart_cr_reg[5]; end // ====================================================== // Receive Interrupts // ====================================================== always @ ( posedge i_clk ) if (fifo_enable) rx_interrupt <= rx_fifo_half_or_more || rx_int_timer == RX_INTERRUPT_COUNT; else rx_interrupt <= rx_fifo_full; assign o_uart_int = ( tx_interrupt & uart_cr_reg[5] ) | // UART transmit interrupt w/ enable ( rx_interrupt & uart_cr_reg[4] ) ; // UART receive interrupt w/ enable assign fifo_enable = uart_lcrh_reg[4]; // ======================================================== // UART Transmit // ======================================================== assign o_uart_txd = txd; assign tx_fifo_full = fifo_enable ? tx_fifo_count >= 5'd16 : tx_fifo_full_flag; assign tx_fifo_empty = fifo_enable ? tx_fifo_count == 5'd00 : !tx_fifo_full_flag; assign tx_fifo_half_or_less_full = tx_fifo_count <= 5'd8; assign tx_byte = fifo_enable ? tx_fifo[tx_fifo_rp[3:0]] : tx_fifo[0] ; assign tx_fifo_push = wb_start_write && i_wb_adr[15:0] == AMBER_UART_DR; assign tx_fifo_push_not_full = tx_fifo_push && !tx_fifo_full; assign tx_fifo_pop_not_empty = txd_state == TXD_STOP3 && tx_bit_pulse == 1'd1 && !tx_fifo_empty; // Transmit FIFO always @( posedge i_clk ) begin // Use 8-entry FIFO if ( fifo_enable ) begin // Push if ( tx_fifo_push_not_full ) begin tx_fifo[tx_fifo_wp[3:0]] <= wb_wdata32[7:0]; tx_fifo_wp <= tx_fifo_wp + 1'd1; end // Pop if ( tx_fifo_pop_not_empty ) tx_fifo_rp <= tx_fifo_rp + 1'd1; // Count up if (tx_fifo_push_not_full && !tx_fifo_pop_not_empty) tx_fifo_count <= tx_fifo_count + 1'd1; // Count down else if (tx_fifo_pop_not_empty && !tx_fifo_push_not_full) tx_fifo_count <= tx_fifo_count - 1'd1; end // Do not use 8-entry FIFO, single entry register instead else begin // Clear FIFO values tx_fifo_wp <= 'd0; tx_fifo_rp <= 'd0; tx_fifo_count <= 'd0; // Push if ( tx_fifo_push_not_full ) begin tx_fifo[0] <= wb_wdata32[7:0]; tx_fifo_full_flag <= 1'd1; end // Pop else if ( tx_fifo_pop_not_empty ) tx_fifo_full_flag <= 1'd0; end end // ======================================================== // Register Clear to Send Input // ======================================================== always @( posedge i_clk ) uart0_cts_n_d <= {uart0_cts_n_d[2:0], i_uart_cts_n}; // ======================================================== // Transmit Pulse generater - matches baud rate // ======================================================== always @( posedge i_clk ) if (( tx_bit_pulse_count == (TX_BITADJUST_COUNT-1) && txd_state == TXD_STOP2 ) || ( tx_bit_pulse_count == (TX_BITPULSE_COUNT-1) && txd_state != TXD_STOP2 ) ) begin tx_bit_pulse_count <= 'd0; tx_bit_pulse <= 1'd1; end else begin tx_bit_pulse_count <= tx_bit_pulse_count + 1'd1; tx_bit_pulse <= 1'd0; end // ======================================================== // Byte Transmitted // ======================================================== // Idle state, txd = 1 // start bit, txd = 0 // Data x 8, lsb first // stop bit, txd = 1 // X = 0x58 = 01011000 always @( posedge i_clk ) if ( tx_bit_pulse ) case ( txd_state ) TXD_IDLE : begin txd <= 1'd1; if ( uart0_cts_n_d[3:1] == 3'b000 && !tx_fifo_empty ) txd_state <= TXD_START; end TXD_START : begin txd <= 1'd0; txd_state <= TXD_DATA0; end TXD_DATA0 : begin txd <= tx_byte[0]; txd_state <= TXD_DATA1; end TXD_DATA1 : begin txd <= tx_byte[1]; txd_state <= TXD_DATA2; end TXD_DATA2 : begin txd <= tx_byte[2]; txd_state <= TXD_DATA3; end TXD_DATA3 : begin txd <= tx_byte[3]; txd_state <= TXD_DATA4; end TXD_DATA4 : begin txd <= tx_byte[4]; txd_state <= TXD_DATA5; end TXD_DATA5 : begin txd <= tx_byte[5]; txd_state <= TXD_DATA6; end TXD_DATA6 : begin txd <= tx_byte[6]; txd_state <= TXD_DATA7; end TXD_DATA7 : begin txd <= tx_byte[7]; txd_state <= TXD_STOP1; end TXD_STOP1 : begin txd <= 1'd1; txd_state <= TXD_STOP2; end TXD_STOP2 : begin txd <= 1'd1; txd_state <= TXD_STOP3; end TXD_STOP3 : begin txd <= 1'd1; txd_state <= TXD_IDLE; end default : begin txd <= 1'd1; end endcase // ======================================================== // UART Receive // ======================================================== assign o_uart_rts_n = ~rxen; assign rx_fifo_push = rxd_state == RXD_STOP && rx_bit_pulse_count == 10'd0; // ======================================================== // Receive bit pulse // ======================================================== // Pulse generater - matches baud rate always @( posedge i_clk ) if ( restart_rx_bit_count ) rx_bit_pulse_count <= 'd0; else rx_bit_pulse_count <= rx_bit_pulse_count + 1'd1; // ======================================================== // Detect 1->0 transition. Filter out glitches and jaggedy transitions // ======================================================== always @( posedge i_clk ) rxd_d[4:0] <= {rxd_d[3:0], i_uart_rxd}; assign rx_start = rxd_d[4:3] == 2'b11 && rxd_d[1:0] == 2'b00; // ======================================================== // Receive state machine // ======================================================== always @( posedge i_clk ) case ( rxd_state ) RXD_IDLE : if ( rx_fifo_full ) rxen <= 1'd0; else begin rxd_state <= RXD_START; rxen <= 1'd1; restart_rx_bit_count <= 1'd1; rx_byte <= 'd0; end RXD_START : // Filter out glitches and jaggedy transitions if ( rx_start ) begin rxd_state <= RXD_START_MID1; restart_rx_bit_count <= 1'd1; end else restart_rx_bit_count <= 1'd0; // This state just delays the check on the // rx_bit_pulse_count value by 1 clock cycle to // give it time to reset RXD_START_MID1 : rxd_state <= RXD_START_MID; RXD_START_MID : if ( rx_bit_pulse_count == RX_HALFPULSE_COUNT ) begin rxd_state <= RXD_DATA0; restart_rx_bit_count <= 1'd1; end else restart_rx_bit_count <= 1'd0; RXD_DATA0 : if ( rx_bit_pulse_count == RX_BITPULSE_COUNT ) begin rxd_state <= RXD_DATA1; restart_rx_bit_count <= 1'd1; rx_byte[0] <= i_uart_rxd; end else restart_rx_bit_count <= 1'd0; RXD_DATA1 : if ( rx_bit_pulse_count == RX_BITPULSE_COUNT ) begin rxd_state <= RXD_DATA2; restart_rx_bit_count <= 1'd1; rx_byte[1] <= i_uart_rxd; end else restart_rx_bit_count <= 1'd0; RXD_DATA2 : if ( rx_bit_pulse_count == RX_BITPULSE_COUNT ) begin rxd_state <= RXD_DATA3; restart_rx_bit_count <= 1'd1; rx_byte[2] <= i_uart_rxd; end else restart_rx_bit_count <= 1'd0; RXD_DATA3 : if ( rx_bit_pulse_count == RX_BITPULSE_COUNT ) begin rxd_state <= RXD_DATA4; restart_rx_bit_count <= 1'd1; rx_byte[3] <= i_uart_rxd; end else restart_rx_bit_count <= 1'd0; RXD_DATA4 : if ( rx_bit_pulse_count == RX_BITPULSE_COUNT ) begin rxd_state <= RXD_DATA5; restart_rx_bit_count <= 1'd1; rx_byte[4] <= i_uart_rxd; end else restart_rx_bit_count <= 1'd0; RXD_DATA5 : if ( rx_bit_pulse_count == RX_BITPULSE_COUNT ) begin rxd_state <= RXD_DATA6; restart_rx_bit_count <= 1'd1; rx_byte[5] <= i_uart_rxd; end else restart_rx_bit_count <= 1'd0; RXD_DATA6 : if ( rx_bit_pulse_count == RX_BITPULSE_COUNT ) begin rxd_state <= RXD_DATA7; restart_rx_bit_count <= 1'd1; rx_byte[6] <= i_uart_rxd; end else restart_rx_bit_count <= 1'd0; RXD_DATA7 : if ( rx_bit_pulse_count == RX_BITPULSE_COUNT ) begin rxd_state <= RXD_STOP; restart_rx_bit_count <= 1'd1; rx_byte[7] <= i_uart_rxd; end else restart_rx_bit_count <= 1'd0; RXD_STOP : if ( rx_bit_pulse_count == RX_BITPULSE_COUNT ) // half way through stop bit begin rxd_state <= RXD_IDLE; restart_rx_bit_count <= 1'd1; end else restart_rx_bit_count <= 1'd0; default : begin rxd_state <= RXD_IDLE; end endcase // ======================================================== // Register Writes // ======================================================== always @( posedge i_clk ) if ( wb_start_write ) case ( i_wb_adr[15:0] ) // Receive status, (Write) Error Clear AMBER_UART_RSR: uart_rsr_reg <= wb_wdata32[7:0]; // Line Control High Byte AMBER_UART_LCRH: uart_lcrh_reg <= wb_wdata32[7:0]; // Line Control Middle Byte AMBER_UART_LCRM: uart_lcrm_reg <= wb_wdata32[7:0]; // Line Control Low Byte AMBER_UART_LCRL: uart_lcrl_reg <= wb_wdata32[7:0]; // Control Register AMBER_UART_CR: uart_cr_reg <= wb_wdata32[7:0]; endcase // ======================================================== // Register Reads // ======================================================== always @( posedge i_clk ) if ( wb_start_read ) case ( i_wb_adr[15:0] ) AMBER_UART_CID0: wb_rdata32 <= 32'h0d; AMBER_UART_CID1: wb_rdata32 <= 32'hf0; AMBER_UART_CID2: wb_rdata32 <= 32'h05; AMBER_UART_CID3: wb_rdata32 <= 32'hb1; AMBER_UART_PID0: wb_rdata32 <= 32'h10; AMBER_UART_PID1: wb_rdata32 <= 32'h10; AMBER_UART_PID2: wb_rdata32 <= 32'h04; AMBER_UART_PID3: wb_rdata32 <= 32'h00; AMBER_UART_DR: // Rx data if ( fifo_enable ) wb_rdata32 <= {24'd0, rx_fifo[rx_fifo_rp[3:0]]}; else wb_rdata32 <= {24'd0, rx_fifo[0]}; AMBER_UART_RSR: wb_rdata32 <= uart_rsr_reg; // Receive status, (Write) Error Clear AMBER_UART_LCRH: wb_rdata32 <= uart_lcrh_reg; // Line Control High Byte AMBER_UART_LCRM: wb_rdata32 <= uart_lcrm_reg; // Line Control Middle Byte AMBER_UART_LCRL: wb_rdata32 <= uart_lcrl_reg; // Line Control Low Byte AMBER_UART_CR: wb_rdata32 <= uart_cr_reg; // Control Register // UART Tx/Rx Status AMBER_UART_FR: wb_rdata32 <= {tx_fifo_empty, // tx fifo empty rx_fifo_full, // rx fifo full tx_fifo_full, // tx fifo full rx_fifo_empty, // rx fifo empty !tx_fifo_empty, // uart busy 1'd1, // !Data Carrier Detect 1'd1, // !Data Set Ready !uart0_cts_n_d[3] // !Clear to Send }; // Flag Register // Interrupt Status AMBER_UART_IIR: wb_rdata32 <= {5'd0, 1'd0, // RTIS - receive timeout interrupt tx_interrupt, // TIS - transmit interrupt status rx_interrupt, // RIS - receive interrupt status 1'd0 // Modem interrupt status }; // (Write) Clear Int default: wb_rdata32 <= 32'h00c0ffee; endcase // ======================================================================================= // ======================================================================================= // ======================================================================================= // Non-synthesizable debug code // ======================================================================================= //synopsys translate_off // ======================================================== // Report UART Register accesses // ======================================================== `ifndef Veritak // Check in case UART approximate period // is too far off initial begin if ((( TX_BITPULSE_COUNT * CLK_PERIOD ) > (UART_BIT_PERIOD * 1.03) ) || (( TX_BITPULSE_COUNT * CLK_PERIOD ) < (UART_BIT_PERIOD * 0.97) ) ) begin `TB_ERROR_MESSAGE $display("UART TX bit period, %.1f, is too big. UART will not work!", TX_BITPULSE_COUNT * CLK_PERIOD); $display("Baud rate is %f, and baud bit period is %.1f", UART_BAUD, UART_BIT_PERIOD); $display("Either reduce the baud rate, or increase the system clock frequency"); $display("------"); end end `endif `ifdef AMBER_UART_DEBUG wire wb_read_ack; reg uart0_rx_int_d1 = 'd0; assign wb_read_ack = i_wb_stb && !i_wb_we && o_wb_ack; `ifndef Veritak initial begin $display("%m UART period = %f nS, want %f nS, %d, %d", (TX_BITPULSE_COUNT*11 + TX_BITADJUST_COUNT) * CLK_PERIOD, UART_WORD_PERIOD, TX_BITPULSE_COUNT, TX_BITADJUST_COUNT); end `endif // Transmit Interrupts always @ ( posedge i_clk ) if ( wb_start_write && i_wb_adr[15:0] == AMBER_UART_ICR ) ; else if ( fifo_enable ) begin if (tx_interrupt == 1'd0 && tx_fifo_half_or_less_full && uart_cr_reg[5]) $display("%m: tx_interrupt Interrupt Set with FIFO enabled"); if (tx_interrupt == 1'd1 && !(tx_fifo_half_or_less_full && uart_cr_reg[5])) $display("%m: tx_interrupt Interrupt Cleared with FIFO enabled"); end else begin if (tx_interrupt == 1'd0 && tx_fifo_empty && uart_cr_reg[5]) $display("%m: tx_interrupt Interrupt Set with FIFO disabled"); if (tx_interrupt == 1'd1 && !(tx_fifo_empty && uart_cr_reg[5])) $display("%m: tx_interrupt Interrupt Cleared with FIFO disabled"); end // Receive Interrupts always @ ( posedge i_clk ) begin uart0_rx_int_d1 <= rx_interrupt; if ( rx_interrupt && !uart0_rx_int_d1 ) begin `TB_DEBUG_MESSAGE $display("rx_interrupt Interrupt fifo_enable %d, rx_fifo_full %d", fifo_enable, rx_fifo_full); $display("rx_fifo_half_or_more %d, rx_int_timer 0x%08h, rx_fifo_count %d", rx_fifo_half_or_more, rx_int_timer, rx_fifo_count); end if ( !rx_interrupt && uart0_rx_int_d1 ) begin `TB_DEBUG_MESSAGE $display("rx_interrupt Interrupt Cleared fifo_enable %d, rx_fifo_full %d", fifo_enable, rx_fifo_full); $display(" rx_fifo_half_or_more %d, rx_int_timer 0x%08h, rx_fifo_count %d", rx_fifo_half_or_more, rx_int_timer, rx_fifo_count); end end always @( posedge i_clk ) if ( wb_read_ack || wb_start_write ) begin `TB_DEBUG_MESSAGE if ( wb_start_write ) $write("Write 0x%08x to ", wb_wdata32); else $write("Read 0x%08x from ", o_wb_dat); case ( i_wb_adr[15:0] ) AMBER_UART_PID0: $write("UART PID0 register"); AMBER_UART_PID1: $write("UART PID1 register"); AMBER_UART_PID2: $write("UART PID2 register"); AMBER_UART_PID3: $write("UART PID3 register"); AMBER_UART_CID0: $write("UART CID0 register"); AMBER_UART_CID1: $write("UART CID1 register"); AMBER_UART_CID2: $write("UART CID2 register"); AMBER_UART_CID3: $write("UART CID3 register"); AMBER_UART_DR: $write("UART Tx/Rx char %c", wb_start_write ? wb_wdata32[7:0] : o_wb_dat[7:0] ); AMBER_UART_RSR: $write("UART (Read) Receive status, (Write) Error Clear"); AMBER_UART_LCRH: $write("UART Line Control High Byte"); AMBER_UART_LCRM: $write("UART Line Control Middle Byte"); AMBER_UART_LCRL: $write("UART Line Control Low Byte"); AMBER_UART_CR: $write("UART Control Register"); AMBER_UART_FR: $write("UART Flag Register"); AMBER_UART_IIR: $write("UART (Read) Interrupt Identification Register"); default: begin `TB_ERROR_MESSAGE $write("Unknown UART Register region"); end endcase $write(", Address 0x%08h\n", i_wb_adr); end `endif // ======================================================== // Assertions // ======================================================== always @ ( posedge i_clk ) begin if ( rx_fifo_pop && !rx_fifo_push && rx_fifo_empty ) begin `TB_WARNING_MESSAGE $write("UART rx FIFO underflow\n"); end if ( !rx_fifo_pop && rx_fifo_push && rx_fifo_full ) begin `TB_WARNING_MESSAGE $write("UART rx FIFO overflow\n"); end if ( tx_fifo_push && tx_fifo_full ) begin `TB_WARNING_MESSAGE $display("UART tx FIFO overflow - char = %c", wb_wdata32[7:0]); end end // ======================================================== // Debug State Machines // ======================================================== wire [(10*8)-1:0] xTXD_STATE; wire [(14*8)-1:0] xRXD_STATE; assign xTXD_STATE = txd_state == TXD_IDLE ? "TXD_IDLE" : txd_state == TXD_START ? "TXD_START" : txd_state == TXD_DATA0 ? "TXD_DATA0" : txd_state == TXD_DATA1 ? "TXD_DATA1" : txd_state == TXD_DATA2 ? "TXD_DATA2" : txd_state == TXD_DATA3 ? "TXD_DATA3" : txd_state == TXD_DATA4 ? "TXD_DATA4" : txd_state == TXD_DATA5 ? "TXD_DATA5" : txd_state == TXD_DATA6 ? "TXD_DATA6" : txd_state == TXD_DATA7 ? "TXD_DATA7" : txd_state == TXD_STOP1 ? "TXD_STOP1" : txd_state == TXD_STOP2 ? "TXD_STOP2" : txd_state == TXD_STOP3 ? "TXD_STOP3" : "UNKNOWN" ; assign xRXD_STATE = rxd_state == RXD_IDLE ? "RXD_IDLE" : rxd_state == RXD_START ? "RXD_START" : rxd_state == RXD_START_MID1 ? "RXD_START_MID1": rxd_state == RXD_START_MID ? "RXD_START_MID" : rxd_state == RXD_DATA0 ? "RXD_DATA0" : rxd_state == RXD_DATA1 ? "RXD_DATA1" : rxd_state == RXD_DATA2 ? "RXD_DATA2" : rxd_state == RXD_DATA3 ? "RXD_DATA3" : rxd_state == RXD_DATA4 ? "RXD_DATA4" : rxd_state == RXD_DATA5 ? "RXD_DATA5" : rxd_state == RXD_DATA6 ? "RXD_DATA6" : rxd_state == RXD_DATA7 ? "RXD_DATA7" : rxd_state == RXD_STOP ? "RXD_STOP" : "UNKNOWN" ; //synopsys translate_on endmodule
Go to most recent revision | Compare with Previous | Blame | View Log