| //---------------------------------------------------------------------------- |
| // Copyright (C) 2009 , Olivier Girard |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions |
| // are met: |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution. |
| // * Neither the name of the authors nor the names of its contributors |
| // may be used to endorse or promote products derived from this software |
| // without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
| // OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| // THE POSSIBILITY OF SUCH DAMAGE |
| // |
| //---------------------------------------------------------------------------- |
| // |
| // *File Name: omsp_dbg_uart.v |
| // |
| // *Module Description: |
| // Debug UART communication interface (8N1, Half-duplex) |
| // |
| // *Author(s): |
| // - Olivier Girard, olgirard@gmail.com |
| // |
| //---------------------------------------------------------------------------- |
| // $Rev: 134 $ |
| // $LastChangedBy: olivier.girard $ |
| // $LastChangedDate: 2012-03-22 21:31:06 +0100 (Thu, 22 Mar 2012) $ |
| //---------------------------------------------------------------------------- |
| `ifdef OMSP_NO_INCLUDE |
| `else |
| `include "openMSP430_defines.v" |
| `endif |
| |
| module omsp_dbg_uart ( |
| |
| // OUTPUTs |
| dbg_addr, // Debug register address |
| dbg_din, // Debug register data input |
| dbg_rd, // Debug register data read |
| dbg_uart_txd, // Debug interface: UART TXD |
| dbg_wr, // Debug register data write |
| |
| // INPUTs |
| dbg_clk, // Debug unit clock |
| dbg_dout, // Debug register data output |
| dbg_rd_rdy, // Debug register data is ready for read |
| dbg_rst, // Debug unit reset |
| dbg_uart_rxd, // Debug interface: UART RXD |
| mem_burst, // Burst on going |
| mem_burst_end, // End TX/RX burst |
| mem_burst_rd, // Start TX burst |
| mem_burst_wr, // Start RX burst |
| mem_bw // Burst byte width |
| ); |
| |
| // OUTPUTs |
| //========= |
| output [5:0] dbg_addr; // Debug register address |
| output [15:0] dbg_din; // Debug register data input |
| output dbg_rd; // Debug register data read |
| output dbg_uart_txd; // Debug interface: UART TXD |
| output dbg_wr; // Debug register data write |
| |
| // INPUTs |
| //========= |
| input dbg_clk; // Debug unit clock |
| input [15:0] dbg_dout; // Debug register data output |
| input dbg_rd_rdy; // Debug register data is ready for read |
| input dbg_rst; // Debug unit reset |
| input dbg_uart_rxd; // Debug interface: UART RXD |
| input mem_burst; // Burst on going |
| input mem_burst_end; // End TX/RX burst |
| input mem_burst_rd; // Start TX burst |
| input mem_burst_wr; // Start RX burst |
| input mem_bw; // Burst byte width |
| |
| |
| //============================================================================= |
| // 1) UART RECEIVE LINE SYNCHRONIZTION & FILTERING |
| //============================================================================= |
| |
| // Synchronize RXD input |
| //-------------------------------- |
| `ifdef SYNC_DBG_UART_RXD |
| |
| wire uart_rxd_n; |
| |
| omsp_sync_cell sync_cell_uart_rxd ( |
| .data_out (uart_rxd_n), |
| .data_in (~dbg_uart_rxd), |
| .clk (dbg_clk), |
| .rst (dbg_rst) |
| ); |
| wire uart_rxd = ~uart_rxd_n; |
| `else |
| wire uart_rxd = dbg_uart_rxd; |
| `endif |
| |
| // RXD input buffer |
| //-------------------------------- |
| reg [1:0] rxd_buf; |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) rxd_buf <= 2'h3; |
| else rxd_buf <= {rxd_buf[0], uart_rxd}; |
| |
| // Majority decision |
| //------------------------ |
| reg rxd_maj; |
| |
| wire rxd_maj_nxt = (uart_rxd & rxd_buf[0]) | |
| (uart_rxd & rxd_buf[1]) | |
| (rxd_buf[0] & rxd_buf[1]); |
| |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) rxd_maj <= 1'b1; |
| else rxd_maj <= rxd_maj_nxt; |
| |
| wire rxd_s = rxd_maj; |
| wire rxd_fe = rxd_maj & ~rxd_maj_nxt; |
| wire rxd_re = ~rxd_maj & rxd_maj_nxt; |
| wire rxd_edge = rxd_maj ^ rxd_maj_nxt; |
| |
| //============================================================================= |
| // 2) UART STATE MACHINE |
| //============================================================================= |
| |
| // Receive state |
| //------------------------ |
| reg [2:0] uart_state; |
| reg [2:0] uart_state_nxt; |
| |
| wire sync_done; |
| wire xfer_done; |
| reg [19:0] xfer_buf; |
| wire [19:0] xfer_buf_nxt; |
| |
| // State machine definition |
| parameter RX_SYNC = 3'h0; |
| parameter RX_CMD = 3'h1; |
| parameter RX_DATA1 = 3'h2; |
| parameter RX_DATA2 = 3'h3; |
| parameter TX_DATA1 = 3'h4; |
| parameter TX_DATA2 = 3'h5; |
| |
| // State transition |
| always @(uart_state or xfer_buf_nxt or mem_burst or mem_burst_wr or mem_burst_rd or mem_burst_end or mem_bw) |
| case (uart_state) |
| RX_SYNC : uart_state_nxt = RX_CMD; |
| RX_CMD : uart_state_nxt = mem_burst_wr ? |
| (mem_bw ? RX_DATA2 : RX_DATA1) : |
| mem_burst_rd ? |
| (mem_bw ? TX_DATA2 : TX_DATA1) : |
| (xfer_buf_nxt[`DBG_UART_WR] ? |
| (xfer_buf_nxt[`DBG_UART_BW] ? RX_DATA2 : RX_DATA1) : |
| (xfer_buf_nxt[`DBG_UART_BW] ? TX_DATA2 : TX_DATA1)); |
| RX_DATA1 : uart_state_nxt = RX_DATA2; |
| RX_DATA2 : uart_state_nxt = (mem_burst & ~mem_burst_end) ? |
| (mem_bw ? RX_DATA2 : RX_DATA1) : |
| RX_CMD; |
| TX_DATA1 : uart_state_nxt = TX_DATA2; |
| TX_DATA2 : uart_state_nxt = (mem_burst & ~mem_burst_end) ? |
| (mem_bw ? TX_DATA2 : TX_DATA1) : |
| RX_CMD; |
| // pragma coverage off |
| default : uart_state_nxt = RX_CMD; |
| // pragma coverage on |
| endcase |
| |
| // State machine |
| always @(posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) uart_state <= RX_SYNC; |
| else if (xfer_done | sync_done | |
| mem_burst_wr | mem_burst_rd) uart_state <= uart_state_nxt; |
| |
| // Utility signals |
| wire cmd_valid = (uart_state==RX_CMD) & xfer_done; |
| wire rx_active = (uart_state==RX_DATA1) | (uart_state==RX_DATA2) | (uart_state==RX_CMD); |
| wire tx_active = (uart_state==TX_DATA1) | (uart_state==TX_DATA2); |
| |
| |
| //============================================================================= |
| // 3) UART SYNCHRONIZATION |
| //============================================================================= |
| // After DBG_RST, the host needs to fist send a synchronization character (0x80) |
| // If this feature doesn't work properly, it is possible to disable it by |
| // commenting the DBG_UART_AUTO_SYNC define in the openMSP430.inc file. |
| |
| reg sync_busy; |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) sync_busy <= 1'b0; |
| else if ((uart_state==RX_SYNC) & rxd_fe) sync_busy <= 1'b1; |
| else if ((uart_state==RX_SYNC) & rxd_re) sync_busy <= 1'b0; |
| |
| assign sync_done = (uart_state==RX_SYNC) & rxd_re & sync_busy; |
| |
| `ifdef DBG_UART_AUTO_SYNC |
| |
| reg [`DBG_UART_XFER_CNT_W+2:0] sync_cnt; |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) sync_cnt <= {{`DBG_UART_XFER_CNT_W{1'b1}}, 3'b000}; |
| else if (sync_busy | (~sync_busy & sync_cnt[2])) sync_cnt <= sync_cnt+{{`DBG_UART_XFER_CNT_W+2{1'b0}}, 1'b1}; |
| |
| wire [`DBG_UART_XFER_CNT_W-1:0] bit_cnt_max = sync_cnt[`DBG_UART_XFER_CNT_W+2:3]; |
| `else |
| wire [`DBG_UART_XFER_CNT_W-1:0] bit_cnt_max = `DBG_UART_CNT; |
| `endif |
| |
| |
| //============================================================================= |
| // 4) UART RECEIVE / TRANSMIT |
| //============================================================================= |
| |
| // Transfer counter |
| //------------------------ |
| reg [3:0] xfer_bit; |
| reg [`DBG_UART_XFER_CNT_W-1:0] xfer_cnt; |
| |
| wire txd_start = dbg_rd_rdy | (xfer_done & (uart_state==TX_DATA1)); |
| wire rxd_start = (xfer_bit==4'h0) & rxd_fe & ((uart_state!=RX_SYNC)); |
| wire xfer_bit_inc = (xfer_bit!=4'h0) & (xfer_cnt=={`DBG_UART_XFER_CNT_W{1'b0}}); |
| assign xfer_done = rx_active ? (xfer_bit==4'ha) : (xfer_bit==4'hb); |
| |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) xfer_bit <= 4'h0; |
| else if (txd_start | rxd_start) xfer_bit <= 4'h1; |
| else if (xfer_done) xfer_bit <= 4'h0; |
| else if (xfer_bit_inc) xfer_bit <= xfer_bit+4'h1; |
| |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) xfer_cnt <= {`DBG_UART_XFER_CNT_W{1'b0}}; |
| else if (rx_active & rxd_edge) xfer_cnt <= {1'b0, bit_cnt_max[`DBG_UART_XFER_CNT_W-1:1]}; |
| else if (txd_start | xfer_bit_inc) xfer_cnt <= bit_cnt_max; |
| else if (|xfer_cnt) xfer_cnt <= xfer_cnt+{`DBG_UART_XFER_CNT_W{1'b1}}; |
| |
| |
| // Receive/Transmit buffer |
| //------------------------- |
| assign xfer_buf_nxt = {rxd_s, xfer_buf[19:1]}; |
| |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) xfer_buf <= 20'h00000; |
| else if (dbg_rd_rdy) xfer_buf <= {1'b1, dbg_dout[15:8], 2'b01, dbg_dout[7:0], 1'b0}; |
| else if (xfer_bit_inc) xfer_buf <= xfer_buf_nxt; |
| |
| |
| // Generate TXD output |
| //------------------------ |
| reg dbg_uart_txd; |
| |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) dbg_uart_txd <= 1'b1; |
| else if (xfer_bit_inc & tx_active) dbg_uart_txd <= xfer_buf[0]; |
| |
| |
| //============================================================================= |
| // 5) INTERFACE TO DEBUG REGISTERS |
| //============================================================================= |
| |
| reg [5:0] dbg_addr; |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) dbg_addr <= 6'h00; |
| else if (cmd_valid) dbg_addr <= xfer_buf_nxt[`DBG_UART_ADDR]; |
| |
| reg dbg_bw; |
| always @ (posedge dbg_clk or posedge dbg_rst) |
| if (dbg_rst) dbg_bw <= 1'b0; |
| else if (cmd_valid) dbg_bw <= xfer_buf_nxt[`DBG_UART_BW]; |
| |
| wire dbg_din_bw = mem_burst ? mem_bw : dbg_bw; |
| |
| wire [15:0] dbg_din = dbg_din_bw ? {8'h00, xfer_buf_nxt[18:11]} : |
| {xfer_buf_nxt[18:11], xfer_buf_nxt[9:2]}; |
| wire dbg_wr = (xfer_done & (uart_state==RX_DATA2)); |
| wire dbg_rd = mem_burst ? (xfer_done & (uart_state==TX_DATA2)) : |
| (cmd_valid & ~xfer_buf_nxt[`DBG_UART_WR]) | mem_burst_rd; |
| |
| |
| |
| endmodule // omsp_dbg_uart |
| |
| `ifdef OMSP_NO_INCLUDE |
| `else |
| `include "openMSP430_undefines.v" |
| `endif |