Category : Tutorials + Patches
Archive   : NAT_UART.ZIP
Filename : I450.C

 
Output of file : I450.C contained in archive : NAT_UART.ZIP
/* i450.c 11/3/88 Louis Shay
This function will test the functions of a NS16450 or compatible UART
device. The base address of the UART is referenced by a global
integer variable, ubase, which is defined by the calling program.

The program consists of the following sections:
1. Internal loopback data test.
Bytes from 00 to ff are sent, received, and checked for all cominations
of LCR values.
2. Modem control / modem status loopback test.
All combinations of MCR values 10H to 1fH are set, and the MSR values
checked for each.
3. Interrrupt functionality.
All types of interrupts are tested individually, then the priority
control logic is tested.
4. Comprehensive Test.
Tests loopback data transmitter and receiver functions with interrupts
enabled, with special case operations.

Error messages are printed in the form Error (n)..., where n refers to
the section of this source listing. The total number of errors is returned
to the caller
*/

#include
#include
#include "ns16550a.h"

#define TIMEOUT 10000 /* WATCHDOG COUNTER */
#define MAX_ERRS 50 /* Max. error count before Test 1 aborts */

int i450()
{
extern int ubase, fatal_error;
extern void delay ();
int error_count = 0;
/* varaibles for section 1 */
int count_1, r, rddata;
int datalen, stop, pty, dog = 0;
int dataval, maxdata, lcrval, lsrval, rxval, t;
/* variables for section 2. */
static int mcrdata[10] = {0x1f,0x10,0x11,0x10,0x12,0x10,0x14,0x10,0x18,0x10};
static int expect_1[10] = {0xfb,0x0f,0x22,0x02,0x11,0x01,0x40,0x04,0x88,0x08};
static int expect_2[10] = {0xf0,0x00,0x20,0x00,0x10,0x00,0x40,0x00,0x80,0x00};
int count, msr_read1, msr_read2, iir_read1, iir_read2;
/* variables for section 3 */
int wr_data, rbrval, lsr_read1, lsr_read2, int_error=0;
int iir_read3, iir_read4, iir_read5, iir_read6, iir_read7;

/* 0. Start test */

printf("\nINS8250A/NS16450 Loopback Diagnostic Test...\n");

/* 1. 450-mode loopback data test.
This test will send data bytes from 00 to ffH for every combination
of LCR value from 00 to 3fH. Receiver data is compared to sent data
and Line Status Error bits are also checked. */

/* initialize uart */
wrLCR( 0x80 ); /* LCR - set DLAB */
wrDLL( 0x0c ); /* 9600 baud @ 1.8 MHz input */
wrDLM( 0 );
wrLCR( 0 ); /* LCR - clear DLAB */
wrFCR( 0 ); /* FCR = 0 ( applies to 16550 devices only ) */
wrIER( 0 ); /* IER - interrupts off */
wrMCR( 0x10 ); /* enable internal loopback */
(void)rdLSR(); /* clear LSR */
(void)rdMSR(); /* clear MSR */
(void)rdRBR(); /* clear data buffer */

/* test loop */
for( pty = 0 ; pty <= 3 ; pty++ )
{ /* cycle parity controls */
for( stop = 0 ; stop <= 1 ; stop++ )
{ /* cycle stop bits: 1, 1.5, 2 */
for( datalen = 0 ; datalen <= 3 ; datalen++ )
{ /* cycle data word length: 5 - 8 bits */
switch(datalen)
{
case 0:
maxdata = 0x01f;
break;
case 1:
maxdata = 0x03f;
break;
case 2:
maxdata = 0x07f;
break;
case 3:
maxdata = 0x0ff;
break;
}
lcrval = datalen + ( stop << 2 ) + ( pty << 3 );
wrLCR( lcrval ); /* set LCR - line parameters */
for( dataval = 0 ; dataval <= 0xff ; dataval++ )
{ /* data word cycle 0 - ff */
dog = 0; /* set watchdog */
while(1)
{ /* wait for THRE, TEMT set */
lsrval = rdLSR() & 0x60; /* mask THRE, TEMT */
if( lsrval == 0x60 )
break;
if( (dog++) >= TIMEOUT ) { /* watchdog counter for protection */
printf(" Error (1)..TEMT timeout: LSR=%2x - Test 1 aborted.\n",
lsrval );
error_count++;
fatal_error++;
goto T2; /* fatal error - no THRE indicator set */
}
}
(void)rdRBR(); /* clear rx buffer */
(void)rdRBR();
wrTHR( dataval ); /* send data */
dog = 0; /* set watchdog */
while(1)
{ /* wait for DR */
delay ();
delay ();
lsrval = rdLSR(); /* read status */
if( ( lsrval & 0x01 ) ) /* mask DR bit */
break;
if( (dog++) >= TIMEOUT ) { /* watchdog for protection */
printf(" Error (1)..DR timeout: LSR=%2x - Test 1 aborted.\n",
lsrval );
error_count++;
fatal_error++;
goto T2;
}
}
delay ();
rxval = rdRBR(); /* read data back */
if(( rxval != (dataval & maxdata)) || (( lsrval & 0x1e ) != 0 ))
{ /* if data mismatch or OE/FE/PE/BI set, then error */
printf(" Error (1).. LCR = %x Tx = %x LSR = %x Rx = %x\n",
lcrval, dataval, lsrval, rxval);
error_count++;
}
if( error_count >= MAX_ERRS ) {
printf(" -- too many errors. Test 1 aborted.\n");
fatal_error++;
goto T2;
}
}
}
}
}

T2:
/* 2. Modem control / modem status test
This section test Modem Control / Modem Status / IIR functions. The
MCR is programmed with a sequence of mcr_write values int the array
mcrdata[]. For each write value, the IIR and MSR are each read twice.
The read data is compared against known expected values.*/

/* initialize the UART */
wrLCR( 0 ); /* clear DLAB */
wrIER( 0x08 ); /* enable Modem Status Interrupt */
wrMCR( 0x10 ); /* initial MCR state */
(void)rdMSR(); /* clear MSR delta bits */
if(( msr_read2 = rdMSR() ) != 0x00 )
{ /* fatal initialization error */
printf(" Error (2)..Intialization Error: mcr = %2x msr_read2 = %2x\n",
rdMCR(), msr_read2 );
printf(" -- Test 2 aborted.\n");
error_count++;
goto T3;
}

/* mcr/msr test loop */
for( count = 0 ; count <= 9 ; count++ )
{
wrMCR( mcrdata[count] ); /* program the MCR */
iir_read1 = rdIIR(); /* first IIR read */
msr_read1 = rdMSR(); /* first msr read */
iir_read2 = rdIIR(); /* second iir read */
msr_read2 = rdMSR(); /* second MSR read */
if( (msr_read1 != expect_1[count] )
|| ( msr_read2 != expect_2[count] )
|| (( iir_read1 != 00 ) & ( mcrdata[count] != 0x14))
|| ( iir_read2 != 01 ))
{ /* error */
printf(" Error (2)..mcr=%2x msr1=%2x (%2x) msr2=%2x (%2x)",
mcrdata[count], msr_read1, expect_1[count], msr_read2,
expect_2[count] );
printf(" iir1=%2x(00) iir2=%2x(01)\n", iir_read1, iir_read2 );
error_count++;
}
}

/* 3. Interrupt functionality test.
this section tests device interrupts by writing to status register bits
and checking the resulting IIR read value. All interrupt sources are
tested, as well as the priority resolving logic */

T3:
/* intialize test */
wrLCR( 0x80 ); /* set DLAB */
wrDLL( 0x0c ); /* set baud = 9600 */
wrDLM( 0 );
wrLCR( 0 ); /* DLAB = 0 */
wrIER( 0 ); /* interrupts off */
wrFCR( 0 ); /* FIFO's off ( NS16550A only ) */
wrMCR( 0x10 ); /* loopback mode */
(void)rdRBR(); /* clear UART registers */
(void)rdLSR();
(void)rdMSR();

/* 3a. test LSI / LSR functionality */

wrIER( 0x04 ); /* enable lsi only */
iir_read1 = rdIIR(); /* check initial state - no interrupt */
if( iir_read1 != 1 ) {
printf(" Error (3a)..LSI initially active. IIR=%2x LSR=%2x\n", iir_read1,
rdLSR() );
error_count++;
}
wr_data = 0x02; /* init. LSR error bit data */
for( count = 1 ; count <= 4 ; count++ )
{ /* Test each LSR interrupt OE, PE, FE, BI. */
int_error = 0;
wrLSR( wr_data ); /* write lsr */
iir_read1 = rdIIR(); /* read iir - interrupt is pending */
iir_read2 = rdIIR(); /* read IIR should not clear LSI interrupt */
wrIER( 0 ); /* disable & reenable interrupt */
wrIER( 0x04 );
iir_read3 = rdIIR(); /* disable/reenable does not clear LSI */
lsr_read1 = rdLSR(); /* read lsr - clears interrupt */
iir_read4 = rdIIR(); /* check for interrupt clear */
lsr_read2 = rdLSR();
if( iir_read1 != 6 ) {
printf(" Error (3a)..Interrupt not active after write to LSR.\n");
error_count++;
int_error++;
goto LSIDATA;
}
if( iir_read2 != 6 ) {
printf(" Error (3a)..LSI cleared by read of IIR.\n");
error_count++;
int_error++;
}
if( iir_read3 != 6 ) {
printf(" Error (3a)..LSI cleared by disable/reenable of LSI.\n");

error_count++;
int_error++;
}
if( iir_read4 != 1 ) {
printf(" Error (3a)..LSI not cleared by read of LSR.\n");
error_count++;
int_error++;
}
LSIDATA: /* print out register read data */

if( int_error != 0 )
printf("\twrLSR=%2x IIR1=%2x IIR2=%2x IIR3=%2x LSR1=%2x IIR4=%2x LSR2=%2x\n",
wr_data, iir_read1, iir_read2, iir_read3, lsr_read1, iir_read4, lsr_read2 );

wr_data = wr_data * 2; /* shift to next LSR error bit */
}

/* 3b. test MSI / MSR functionality */

(void)rdMSR(); /* clear MSR bits */
wrIER( 0x08 ); /* enable MSI only */
iir_read1 = rdIIR(); /* check initial state - no interrupt */
if( iir_read1 != 1 ) {
printf(" Error (3a)..MSI initially active. IIR=%2x MSR=%2x\n", iir_read1,
rdMSR() );
error_count++;
}
wr_data = 0x01; /* init. MSR error bit data */
for( count = 1 ; count <= 4 ; count++ )
{ /* Test each MSR bit: DDSR, DCTS, DRI, DDCD. */
int_error = 0;
wrMSR( wr_data ); /* write MSR */
iir_read1 = rdIIR(); /* read iir - interrupt is pending */
iir_read2 = rdIIR(); /* read IIR should not clear interrupt */
wrIER( 0 ); /* disable & reenable interrupt */
wrIER( 0x08 );
iir_read3 = rdIIR(); /* disable/reenable does not clear interrupt */
msr_read1 = rdMSR(); /* read MSR - clears interrupt */
iir_read4 = rdIIR(); /* check for interrupt clear */
msr_read2 = rdMSR();
if( iir_read1 != 0 ) {
printf(" Error (3b)..MSI not set by write to MSR.\n");
error_count++;
int_error++;
goto MSIDATA;
}
if( iir_read2 != 0 ) {
printf(" Error (3b)..MSI cleared by read of IIR.\n");
error_count++;
int_error++;
}
if( iir_read3 != 0 ) {
printf(" Error (3b)..MSI cleared by disable/reenable of MSI.\n");
error_count++;
int_error++;
}
if( iir_read4 != 1 ) {
printf(" Error (3b)..MSI not cleared by read of MSR.\n");
error_count++;
int_error++;
}
MSIDATA: /* print out register read data */

if( int_error != 0 )
printf("\twrMSR=%2x IIR1=%2x IIR2=%2x IIR3=%2x MSR1=%2x IIR4=%2x MSR2=%2x\n",
wr_data, iir_read1, iir_read2, iir_read3, msr_read1, iir_read4, msr_read2 );

wr_data = wr_data * 2; /* shift to next MSR bit */
}

/* 3c. Test Receiver data interrupt functions. */
dog = 0; /* set a watchdog counter */
while(( rdLSR() & 0x60 ) != 0x60 ) { /* wait for TEMT condition */
if( dog++ >= TIMEOUT ) {
printf(" Error (3c)..TEMT timeout. Test aborted.\n");
goto END;
}
}
int_error = 0; /* reset flag */
(void)rdRBR(); /* clear receiver buffer */
wrIER( 0x01 ); /* enable RDAI only */
iir_read1 = rdIIR(); /* should be initially clear */
if( iir_read1 != 1 ) {
printf(" Error (3c)..RDAI initially set.\n");
error_count++;
int_error++;
}
wrLSR( 0x61 ); /* set DR */
iir_read2 = rdIIR(); /* check for the interrupt active */
if( iir_read2 != 4 ) {
printf(" Error (3c)..RDAI not set after write to LSR bit 0.\n");
error_count++;
int_error++;
goto RDAIDATA;
}
iir_read3 = rdIIR(); /* reading IIR does not clear RDAI */
if( iir_read3 != 4 ) {
printf(" Error (3c)..Reading IIR clears receiver interrupt.\n");
error_count++;
int_error++;
wrLSR( 0x61 ); /* reset DR */
}
wrIER( 0 ); /* disable/reenable does not clear interrupt */
wrIER( 1 );
iir_read4 = rdIIR();
if( iir_read4 != 4 ) {
printf(" Error (3c)..Disable/reenable clears receiver interrupt.\n");
error_count++;
int_error++;
wrLSR( 0x61 ); /* reset DR */
}
lsrval = rdLSR(); /* reading LSR does not clear interrupt */
iir_read5 = rdIIR();
if( iir_read5 != 4 ) {
printf(" Error (3c)..Reading LSR clears receiver interrupt.\n");
error_count++;
int_error++;
wrLSR( 0x61 ); /* reset DR */
}
(void)rdRBR(); /* reading RBR clears the interrupt */
iir_read6 = rdIIR();
if( iir_read6 != 1 ) {
printf(" Error (3c)..Read RBR does not clear receiver interrupt.\n");
error_count++;
int_error++;
}

RDAIDATA: /* print out register read data */

if( int_error != 0 )
printf("\tIIR1=%2x IIR2=%2x IIR3=%2x IIR4=%2x IIR5=%2x IIR6=%2x\n",
iir_read1, iir_read2, iir_read3, iir_read4, iir_read5, iir_read6 );

/* 3d. THRE interrupt functionality test */
rdIIR ();
wrIER( 0x02 ); /* THREI only */
iir_read1 = rdIIR(); /* interrupt should be pending */
if( iir_read1 != 2 ) {
printf(" Error (3d)..THREI not initially set: IIR = %2x LSR = %2x\n",
iir_read1, rdLSR() );
error_count++;
goto T3E; /* skip rest of test if THREI not set. */
}
iir_read1 = rdIIR(); /* check if cleared */
if( iir_read1 != 1 ) {
printf(" Error (3d)..Read IIR does not clear THREI: IIR = %2x\n", iir_read1 );
error_count++;
}
wrIER( 2 ); /* write IER - reset THRE */
iir_read1 = rdIIR(); /* check for active THREI */
if( iir_read1 != 2 ) {
printf(" Error (3d)..THREI not reenabled: wrIER= 2 LSR=%2x IIR=%2x\n",
rdLSR(), iir_read1 );
error_count++;
}

T3E:

/* 3e. priority resolver test */
wrIER( 0x0f ); /* enable all interrupts */
wrLSR( 0x7f ); /* all interrupts pending */
wrMSR( 0x0f );
iir_read1 = rdIIR(); /* read iir */
if( iir_read1 != 0x06 )
printf(" Error (3e)..priority error - LSI expected: IIR = %2x\n", iir_read1 );
(void)rdLSR(); /* clear LSI */
iir_read1 = rdIIR(); /* read IIR */
if( iir_read1 != 0x04 ) {
printf(" Error (3e)..priority error - RDAI expected: IIR = %2x\n", iir_read1 );
error_count++;
}
(void)rdRBR(); /* clear RDAI */
wrIER( 0x0f ); /* THREI - full duplex bug fix */
iir_read1 = rdIIR(); /* read iir */
if( iir_read1 != 0x02 ) {
printf(" Error (3e)..priority error - THREI expected: IIR = %2x\n", iir_read1);
error_count++;
}
iir_read1 = rdIIR(); /* check if THREI cleared & MSI pending */
if( iir_read1 != 0 ) {
printf(" Error (3e)..priority error - MSI expected: IIR = %2x\n", iir_read1 );
error_count++;
}
(void)rdMSR(); /* clear MSI */
iir_read1 = rdIIR(); /* check if all cleared */
lsrval = rdLSR();
msr_read1 = rdMSR();
if( iir_read1 != 1 ) {
printf(" Error (3e)..priority error - IIR not cleared: IIR=%2x LSR=%2x ",
iir_read1, lsrval );
printf("MSR=%2x\n", msr_read1 );
error_count++;
}
wrIER( 0 ); /* turn off interrupts */

/* 4. Comprehensive test - loopback data with interrupt checking */

dog = 0; /* set a watchdog - wait for THRE condition */
while( (( lsr_read1 = rdLSR() ) & 0x60 ) != 0x60 ) {
if( dog++ >= TIMEOUT ) {
printf("Error (4)..TEMT Timeout. Test aborted.\n");
error_count++;
goto END;
}
}
wrLCR( 3 ); /* 8 data bits */
wrFCR( 0 ); /* no fifo mode */
(void)rdLSR(); /* clear status & data registers */
(void)rdMSR();
(void)rdRBR();

/* 4a. Transmit two characters - overrun the receiver. */

wrMCR( 0x1f ); /* toggle modem lines - set MSI interrupt */
wrMCR( 0x10 );
wrIER( 0x0f ); /* enable interrupts */
iir_read1 = rdIIR(); /* expecting a transmitter interrupt */
wrTHR( 1 ); /* send data byte #1 - clear THREI */
iir_read2 = rdIIR(); /* expecting a modem status interrupt */
(void)rdMSR(); /* clear MSI */
iir_read3 = rdIIR(); /* expecting no interrupt */
while( ( rdLSR() & 0x60 ) != 0x60 ); /* wait for empty transmitter */
wrTHR( 2 ); /* load character #2 */

/* 4b. receive characters and errors */

dog = 0; /* reset watchdog */
while( rdIIR() != 6 ) { /* wait for a Line Status interrupt */
if( dog++ >= TIMEOUT ) {
printf(" Error (4b)..Line Status Interrupt Timeout. Test 4 aborted.\n");
goto END;
}
}
iir_read4 = rdIIR(); /* expecting Line status interrupt */
lsr_read1 = rdLSR(); /* expecting OE bit set */
iir_read5 = rdIIR(); /* expecting receiver data interrupt */
rbrval = rdRBR(); /* expecting data = 02 */
iir_read6 = rdIIR(); /* expecting THRE interrupt */
iir_read7 = rdIIR(); /* expecting No interrupt */
if( iir_read1 != 2 ) {
printf(" Error (4a)..Expected THRE Interrupt: IIR=%2x\n", iir_read1 );
error_count++;
}
if( iir_read2 != 0 ) {
printf(" Error (4a)..Expected Modem Status Interrupt: IIR=%2x\n", iir_read2 );
error_count++;
}
if( iir_read3 != 1 ) {
printf(" Error (4a)..Expected No Interrupt: IIR=%2x\n", iir_read3 );
error_count++;
}
if( iir_read4 != 6 ) {
printf(" Error (4b)..Expected Line Status Interrupt: IIR=%2x\n", iir_read4 );
error_count++;
}
if( ( lsr_read1 & 0x03 ) != 3 ) {
printf(" Error (4b)..Expected LSR=0xx00011. Actual LSR=%2x\n", lsr_read1 );
error_count++;
}
if( iir_read5 != 4 ) {
printf(" Error (4b)..Expected Receiver Data Interrupt: IIR=%2x\n", iir_read5 );
error_count++;
}
if( rbrval != 0x02 ) {
printf(" Error(4b)..Unexpected Reciever Data (expected 02): RBR=%2x\n", rbrval);
error_count++;
}
if( iir_read6 != 2 ) {
printf(" Error (4b)..Expected THRE Interrupt: IIR=%2x\n", iir_read6 );
error_count++;
}
if( iir_read7 != 1 ) {
printf(" Error (4b)..Expected No Interrupt: IIR=%2x\n", iir_read7 );
error_count++;
}

/* end of test code */

goto END;
END: wrIER( 0 ); /* interrupts off */
wrMCR( 0 ); /* loopback off */
if( fatal_error )
printf(" -- Fatal errors found.\n");
return( error_count );
}


  3 Responses to “Category : Tutorials + Patches
Archive   : NAT_UART.ZIP
Filename : I450.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/