//---------------------------------------------------------------- // divtest.cpp // // This program uses "inline assembly language" to test our // external 'softdivb' software division function, based on // comparing all its possible outputs with results produced // when the same divisions are performed in hardware. Note // that we have installed signal-handlers here to catch the // SIGSEGV and SIGFPE signals which are generated by divide // overflow exceptions and software interrupt instructions, // respectively. Our signal-handler counts the type of the // signal and advances the return-address past the two-byte // instruction which caused the fault to avoid retriggering // the very same signal all over again in an infinite loop. // // compile using: $ g++ divtest.cpp softdivb.s -o divtest // // programmer: ALLAN CRUSE // written on: 12 OCT 2003 // revised on: 15 MAR 2006 -- incorporated signal-handlers // revised on: 15 MAR 2009 -- for x86_64 Linux environment //---------------------------------------------------------------- #include // needed for printf() #include // needed for signal() extern void softdivb( void ); // function symbol unsigned int a, b, c, d; // global variables int signaled, segv, fpe; // shared variables void upon_signal( int signo ) { // update our counters ++signaled; if ( signo == SIGFPE ) ++fpe; if ( signo == SIGSEGV ) ++segv; // then adjust the image of the RIP register which the // Linux operating system will have saved on our stack // so that on return from this signal-handler we shall // avoid encountering the very same instruction again // (Here we use the fact that the Pentium's 'divb %bl' // and 'int $0' instructons are each 2-bytes in size) unsigned long *tos; asm(" mov %%rbp, %0 " : "=m" (tos) :: ); tos[23] += 2; } int main( void ) { // install signal-handlers for SIGFPE and SIGSEGV signal( SIGFPE, upon_signal ); signal( SIGSEGV, upon_signal ); // display output legend printf( "\n---a--- --b-- hardware software \n" ); // iterate over every possible combination // of an 8-bit divisor and a 16-bit dividend int errors = 0; for (b = 0; b < 256; b++) { for (a = 0; a < 65536; a++) { signaled = 0; c = d = 0; asm(" movw a, %ax "); asm(" movb b, %bl "); asm(" divb %bl "); asm(" movw %ax, d "); asm(" movw a, %ax "); asm(" movb b, %bl "); asm(" call softdivb "); asm(" movw %ax, c "); printf( " a=%04X b=%02X ", a, b ); printf( " c=%04X d=%04X ", c, d ); if ( ( signaled &&( signaled == 2 )) ||( !signaled &&( c == d )) ) { printf( " ok \n" ); } else { ++errors; printf( "<--- error #%d \n", errors ); } } } printf( "\n\tNumber of errors = %d \n\n", errors ); }