/* Demonstrate serial RS-232 communication via the 8251 UART/USART*/ // A simple demonstration of the 8251 UART connected to the MIPS // system bus. This program just transmits a welcome message, and // then starts to send out a counter value... // TinyMips doesn't support interrupts (yet), so polling is used. // Remember that nCTS must be kept low to enable the transmitter // of the UART 8251. // axxx.xxxx would be mapped to 0xxx.xxxx by the (static) MMU, // but we have disabled the MMU. So, the addresses are unchanged. // #define UART_BASE 0xa0080020 #define UART_DATA (UART_BASE+0) #define UART_CMD (UART_BASE+4) // mode register bits // #define UART_STOP_MASK 0xc0 #define UART_2STOP 0xc0 #define UART_15STOP 0x80 #define UART_1STOP 0x40 #define UART_0STOP 0x00 // invalid #define UART_PARITY_MASK 0x30 #define UART_EVEN_PARITY 0x20 #define UART_ODD_PARITY 0x10 #define UART_NO_PARITY 0x00 #define UART_BITS_MASK 0x0c #define UART_8BITS 0x0c #define UART_7BITS 0x08 #define UART_6BITS 0x04 #define UART_5BITS 0x00 #define UART_PRESCALER 0x03 #define UART_X64 0x03 #define UART_X16 0x02 #define UART_X1 0x01 #define UART_SYNC_MODE 0x00 // not implemented // command register bits // #define UART_EH 0x80 // enter hunt-mode: not implemented #define UART_IR 0x40 // internal reset #define UART_RTS 0x20 // 1: nRTS=0 0: nRTS=1 #define UART_ER 0x10 // reset error flags in status register #define UART_SBRK 0x08 // send break, forces TXD low #define UART_RXE 0x04 // receiver enable bit #define UART_DTR 0x02 // 1: nDTR=0 1: nDTR=1 #define UART_TXE 0x01 // transmitter enable bit // status register bits // #define UART_DSR 0x80 #define UART_SYNDET_BD 0x40 #define UART_FE 0x20 #define UART_OE 0x10 #define UART_PE 0x08 #define UART_TXEMPTY 0x04 #define UART_RXRDY 0x02 #define UART_TXRDY 0x01 static int* global; /* * re-configures the UART to the given parameters in async mode */ void uartAsyncMode( int value ) { int* uart = (int*) UART_CMD; // // assuming we don't know the exact status of the UART 8251, // it might be in its internal WAIT_FOR_SYNC_1_AND_2 state. // Therefore, the first two write operations might end up as data // in the SYNC1 and SYNC2 data registers. But the third write // operation is guaranteed to be decoded as an internal-reset command // which re-initializes the 8251 to expect a mode command next. // *uart = UART_IR; *uart = UART_IR; *uart = UART_IR; // now, we can write the mode command requested by the user. // *uart = value & 0xff; } void uartAsync8N2_X1() { uartAsyncMode( UART_2STOP | UART_NO_PARITY | UART_8BITS | UART_X1 ); } /* * write the given data value to the command register. * The user is responsible to provide sensible data values here. * Also, there is no way to check that the UART is actually expecting * a command. */ void uartCommand( int value ) { int *uart = (int *) UART_CMD; *uart = value&0xff; } /* * write the value UART_CMD_ER or 0x10 to the 8251 in command mode, * that is, CnD=1. This resets the receiver error status flags when * the 8251 is in command mode (but no check is made to ensure that * this is actually the case). */ void uartResetErrors() { uartCommand( UART_ER ); } /* * write the given data character to the transmit buffer of the 8251. * It is the user's responsibility to check that the 8251 is ready * to accept a new data character (i.e., transmitter is enabled and * TXEMPTY). * Actual transmission might be delayed until nCTS is asserted low. */ void uartSendData( char c ) { int *uart = (int *) UART_DATA; *uart = c & 0xff; } /** * reads the 8251 status register. * See the datasheet for the meaning of the individual bits. * Note that SYNDET/BD always reads zero, because the Hades simulation * model of the 8251 does not yet support break-detect or sync mode. */ int uartReadStatus() { int *uart = (int*) UART_DATA; int tmp = 0; tmp = *(uart+1); // *(uart+1) = 0x87; return tmp; } /* returns the error flags, or 0 if no errors set. */ int uartHasError() { int status = uartReadStatus(); int mask = (UART_FE | UART_OE | UART_PE); return (status & mask) == 0; } int uartIsRXRDY() { int status = uartReadStatus(); int mask = UART_RXRDY; return (status & mask) == UART_RXRDY; } int uartIsTXRDY() { int status = uartReadStatus(); int mask = UART_TXRDY; return (status & mask) == UART_TXRDY; } int uartIsTXEMPTY() { int status = uartReadStatus(); int mask = UART_TXEMPTY; return (status & mask) == UART_TXEMPTY; } char uartReadData() { char tmp; int *uart = (int *) UART_DATA; tmp = (*uart) & 0xff; return tmp; } void uartSendDataPolling( char c ) { int tmp = 0; int status = 0; int* global = (int*) 0x00001000; while( !uartIsTXEMPTY() ) { tmp ++; *global = 0xcccc0000 + tmp; // write counter value status = uartReadStatus(); *(global+4) = status; // and uart status } uartSendData( c ); } char hex( int digit ) { digit = digit & 0xf; if (digit <= 9) return ('0' + digit); else return ('a' + digit - 10); } void sayHello( int value ) { uartSendDataPolling( 0x0a ); uartSendDataPolling( 0x0d ); uartSendDataPolling( 'H' ); uartSendDataPolling( 'e' ); uartSendDataPolling( 'l' ); uartSendDataPolling( 'l' ); uartSendDataPolling( 'o' ); uartSendDataPolling( ',' ); uartSendDataPolling( ' ' ); uartSendDataPolling( 'w' ); uartSendDataPolling( 'o' ); uartSendDataPolling( 'r' ); uartSendDataPolling( 'l' ); uartSendDataPolling( 'd' ); uartSendDataPolling( '!' ); uartSendDataPolling( ' ' ); uartSendDataPolling( ' ' ); uartSendDataPolling( hex( (value&0xf000) >> 12) ); uartSendDataPolling( hex( (value&0x0f00) >> 8) ); uartSendDataPolling( hex( (value&0x00f0) >> 4) ); uartSendDataPolling( hex( (value&0x000f) >> 0) ); } int main( int argc, char** argv ) { int count; int sum, dbg1, dbg2; for( count=0; count < 0x33; count++ ) { sum = sum + count; } dbg1 = count; uartAsyncMode( UART_8BITS | UART_2STOP | UART_NO_PARITY | UART_X1 ); uartCommand( UART_ER | UART_RXE | UART_TXE ); for( count=0; ; count++ ) { sayHello( count ); } sayHello( sum ); }