PRODUCT : Borland C++ NUMBER : 1028 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 1/9 TITLE : Using the Borland Emulator asynchronously. Using the Emulator within asynchronous processes. The Borland C/C++ Floating Point emulator is NOT reentrant. This therefore requires that one refrains from using MATH/FLOAT RTL Functions and instructions within an asynchronous process ( eg. ISRs ). However, if the state of the foreground process is saved and restored, an asynchronous routine can safely use the emulator. ( NOTE: This document assumes an application using the emulator. When not linking with the emulator, asynchronous processes may merely save and restore the state of the 80x87 using the FNSAVE/FNRSTOR instructions - See. an INTEL 80x87 Reference manual or your TASM Quick Reference guide for more information. ) The current version of the Borland C/C++ Emulator's maintains various variables on the Stack (NOTE: In NEAR DATA Memory Models the Emulator's associated variables are actually in DGROUP with the Stack Segment - SS pointing to DGROUP ). Accessing the emulator from an asynchronous routine therefore requires that: (1) The asynchronous process use the Foreground's Stack ( since the latter has been properly initialized by the Emulator's initialization Code ). (2) The asynchronous process save the state of the variables and restore them latter upon returning to the foreground process. In FAR DATA memory models, the above can be easily implemented by: (1) Making sure that the asynchronous process is using the Foreground's stack ( Comparing the value of _SS ) (2) Saving and restoring the area of the stack ( approximately 512 bytes from Offset 0 ) which is used by the emulator. In NEAR DATA memory models the same care must be taken except that the emulator's variables are not at SS:(OFFSET 0) but rather within DGROUP. Time critical events ( i.e. need to process whether the stack segment points to the Foreground's stack or not when PRODUCT : Borland C++ NUMBER : 1028 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 2/9 TITLE : Using the Borland Emulator asynchronously. trigerred ) must save the foreground stack to an allocated buffer & switch to the foreground stack prior to using the EMULATOR. The values of SS and SP must be restored as well as the foreground's stack ). The CODE below provides an example where the state of the emulator is saved and the latter used in two Hardware Interrupt Service Routines while multiple MATH functions are being used in the 'foreground'. #include #include #include #include #include #include #include #include #define ESC_SCAN 0x011B /* Scan Code for the ESCAPE Key*/ #define TIMER_INT 0x08 /* Timer interrupt Number... */ #define KBD_INT 0x09 /* Keyboard interrupt Number */ #define PIE (22.0 / 7.0) /* Simple PIE definition.... */ #define _CLD __emit__( 0xFC ) /* Op:Clr Direction Flag */ #define _REP_MOVSW __emit__( 0xF3,0xA5 )/*: ds:si -> es:di */ #define _PUSH_DS __emit__( 0x1E ) /* Op: Push DS register */ #define _POP_DS __emit__( 0x1F ) /* Op: Pop DS register */ #if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__) #error This Example assumes a FAR DATA Memory Model ! #endif void interrupt ( *OldTimerHandler )(...); /* Save Old Timer.. */ void interrupt ( *OldKbdHandler )(...); /* To save Old Kbd. */ PRODUCT : Borland C++ NUMBER : 1028 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 3/9 TITLE : Using the Borland Emulator asynchronously. static unsigned AppsEmuSeg; /* App's Stack Seg */ /* ----------- [ USING THE emulator FROM INT8 ]------------ *\ | The following is called from the INT 8 Handler - It merely | | calls a few routines from the MATH section of the Runtime | | Library... | \*--------------------------------------------------------- */ void UseFloatFromTimer() { static unsigned count, x, y; static float flt; count++; if ( count % 10 ) return; x = wherex(); y = wherey(); textattr( 14 ); flt = flt + PIE/3; gotoxy( 1, 17 ); cprintf("INT 8 ISR- COUNTER %04X", count++ ); gotoxy( 1, 18 ); cprintf("Current value of Float: %f", flt ); gotoxy( 1, 19 ); cprintf("Sine of Float : %lf Angle: %3.2lf\xF8", sin( flt ), asin( sin( flt ))/PIE * 180 ); clreol(); gotoxy( 1, 20 ); cprintf("Cosine of Float : %lf Angle: %3.2lf\xE3", cos( flt ), acos( cos( flt )) ); clreol(); PRODUCT : Borland C++ NUMBER : 1028 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 4/9 TITLE : Using the Borland Emulator asynchronously. gotoxy( 1, 21 ); cprintf("Tangent of Float : %lf Angle: %3.2lf\xF8", tan( flt ), atan( tan( flt ))/PIE * 180 ); clreol(); gotoxy( 1, 22 ); cprintf("Sin/Cos of Float : %lf", sin( flt )/cos( flt )); gotoxy( x, y ); } /* ------------ [ NEW interrupt 8 HANDLER ]------------*\ | The following is an example Timer Handler. The state of | | the EMULATOR is saved prior to calling functions using the | | latter... | \* -------------------------------------------------------- */ void interrupt NewTimerHandler(...) { static unsigned BusyFlag = 0x00, far SaveStack[256]; OldTimerHandler(); // Chain to Old Handler ! if ( !BusyFlag && _SS == AppsEmuSeg ) { BusyFlag++; _SI = 0x00; _DI = FP_OFF( SaveStack ); _CLD; _PUSH_DS; _DS = AppsEmuSeg; _ES = FP_SEG( SaveStack ); _CX = 256; _REP_MOVSW; _POP_DS; PRODUCT : Borland C++ NUMBER : 1028 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 5/9 TITLE : Using the Borland Emulator asynchronously. UseFloatFromTimer(); _SI = FP_OFF( SaveStack ); _DI = 0x00; _CLD; _PUSH_DS; _ES = AppsEmuSeg; _DS = FP_SEG( SaveStack ); _CX = 256; _REP_MOVSW; _POP_DS; BusyFlag--; } } /* ------------ [ USING THE emulator FROM INT9 ]------------*\ | The following is called from the INT 9 Handler - It merely | | calls a few routines from the MATH section of the Runtime | | Library... | \* -------------------------------------------------------- */ void UseFloatFromKbd() { static unsigned count, x, y, flg; static float flt; flg++; if ( flg % 2 ) return; count++; x = wherex(); y = wherey(); textattr( 10 ); PRODUCT : Borland C++ NUMBER : 1028 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 6/9 TITLE : Using the Borland Emulator asynchronously. flt = flt + ( 1.0 / 4.0 ); gotoxy( 1, 10 ); cprintf("INT 9 ISR- COUNTER %04X", count++ ); gotoxy( 1, 11 ); cprintf("Current value of Float: %f", flt ); gotoxy( 1, 12 ); cprintf("Sin/Cos of Float : %lf", sin( flt )/cos( flt )); if ( flt > 100.0000 ) flt = 0.0000; gotoxy( 1, 13 ); cprintf("Exp of 'e' to Float : %lf", exp( flt )); clreol(); gotoxy( 1, 14 ); cprintf("Ceil/floor of flt : %lf/%lf", ceil( flt ), floor( flt )); gotoxy( x, y ); } /* ------------ [ NEW interrupt 9 HANDLER ] ------------ *\ | The following is an example Keybd Handler. The state of the | | EMULATOR is saved prior to calling functions using the | | latter... | \* --------------------------------------------------------- */ void interrupt NewKbdHandler(...) { static unsigned BusyFlag = 0x00, far SaveStack[256]; PRODUCT : Borland C++ NUMBER : 1028 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 7/9 TITLE : Using the Borland Emulator asynchronously. OldKbdHandler(); if ( !BusyFlag && _SS == AppsEmuSeg ) { BusyFlag++; _SI = 0x00; _DI = FP_OFF( SaveStack ); _CLD; _PUSH_DS; _DS = AppsEmuSeg; _ES = FP_SEG( SaveStack ); _CX = 256; _REP_MOVSW; _POP_DS; UseFloatFromKbd(); _SI = FP_OFF( SaveStack ); _DI = 0x00; _CLD; _PUSH_DS; _ES = AppsEmuSeg; _DS = FP_SEG( SaveStack ); _CX = 256; _REP_MOVSW; _POP_DS; BusyFlag--; } } void UseFloatForeground() { static unsigned count = 0x00; static float flt = 0.00; PRODUCT : Borland C++ NUMBER : 1028 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 8/9 TITLE : Using the Borland Emulator asynchronously. count++; flt = flt + PIE/4; textattr( 12 ); gotoxy( 1, 3 ); cprintf("FOREGROUND COUNTER %04X", count++ ); gotoxy( 1, 4 ); cprintf("Current value of Float: %f", flt ); gotoxy( 1, 5 ); cprintf("Sine of Float : %lf", sin( flt )); gotoxy( 1, 6 ); cprintf("Cosine of Float : %lf", cos( flt )); gotoxy( 1, 7 ); cprintf("Tangent of Float : %lf", tan( flt )); gotoxy( 1, 8 ); cprintf("Sin/Cos of Float : %lf", sin( flt )/cos( flt )); } int main( void ) { struct time t; AppsEmuSeg = _SS; clrscr(); OldTimerHandler = getvect( TIMER_INT ); OldKbdHandler = getvect( KBD_INT ); PRODUCT : Borland C++ NUMBER : 1028 VERSION : 3.x OS : DOS DATE : October 19, 1993 PAGE : 9/9 TITLE : Using the Borland Emulator asynchronously. _control87( MCW_EM, MCW_EM ); /* Mask All exceptions...*/ setvect( TIMER_INT, NewTimerHandler ); setvect( KBD_INT, NewKbdHandler ); textattr( 31 ); gotoxy( 12, 25 ); cprintf( " Hit any key to trigger the INT 9H ISR - " "< ESC to Exit > " ); while( 1 ) { if ( bioskey( 1 ) && bioskey( 0 )==ESC_SCAN ) break; gettime( &t ); gotoxy( 65, 1 ); textattr( 63 ); cprintf("[%02d:%02d:%02d.%02d]", t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund); delay( 100 ); UseFloatForeground(); } setvect( TIMER_INT, OldTimerHandler ); setvect( KBD_INT, OldKbdHandler ); gotoxy ( 80, 25 ); return( 0 ); }