PRODUCT : Borland C++ NUMBER : 1535 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 1/5 TITLE : Creating an IOPL segment in BC++ for OS/2 2.X The following files RTC.CPP, RTC.DEF, and IO16.ASM demonstrate how to use Borland C++ for OS/2 to create an IOPL segment. An IOPL segment will allow your program to directly access hardware using the IN and OUT assembly language instructions. Under OS/2 2.X user programs run at privilege level 3 which does not allow the use of the IN or OUT assembly language instructions. These in instructions are only allowed at privilege level 2, which is the privilege level of the IOPL segment. Borland C++ does not allow functions that reside in IOPL segments to have any parameters passed on the stack. This limitation requires the IOPL function to use the CPU registers for both passed parameters and return values. The IOPL segment is required to be a 16 bit segment which adds yet another layer of complexity to the situation. Since the IOPL segment resides in a 16 bit segment, special thunking code must be created by the compiler to call from the 32 bit flat model segment to the 16 bit IOPL segment. The 32 bit to 16 bit thunking code makes extensive use of almost all the CPU registers. EDX is the only register that is not used used by the 32->16 bit thunking code. The reduced complexity of the return code from the 16 bit IOPL segment allows the use of ECX for a return values. The code that follows will work provided these registers are used to pass and return values to the IOPL 16 Bit functions. *** USE ONLY THE DOCUMENTED REGISTERS TO PASS AND *** *** RETURN VALUES FROM THE LISTED IOPL FUNCTIONS *** -------------------- START OF RTC.CPP ------------------------ // // Delcare the following prototypes for the 16 bit functions // that have IOPL. // extern "C" { void __pascal __far16 WPORTW(void); void __pascal __far16 WPORTB(void); void __pascal __far16 RPORTW(void); void __pascal __far16 RPORTB(void); } PRODUCT : Borland C++ NUMBER : 1535 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 2/5 TITLE : Creating an IOPL segment in BC++ for OS/2 2.X #include #include // Structure to hold the time read from the CMOS. struct Time { unsigned Seconds; unsigned Minutes; unsigned Hours; }; void getTime(Time &t) { // Get the seconds count from the Real Time Clock. _EDX = 0x00000070; WPORTB(); _EDX = 0x00000071; RPORTB(); t.Seconds = _CL; // Get the minutes from the RTC. _EDX = 0x00020070; WPORTB(); _EDX = 0x00000071; RPORTB(); t.Minutes = _CL; // Get the hours from the RTC. _EDX = 0x00040070; WPORTB(); _EDX = 0x00000071; RPORTB(); t.Hours = _CL; } // Display the current time void DisplayTime(Time &t) { cout<< hex << setfill('0') << setw(2) << t.Hours << ":" << hex << setfill('0') << setw(2) << t.Minutes << ":" << hex << setfill('0') << setw(2) << t.Seconds << endl; } PRODUCT : Borland C++ NUMBER : 1535 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 3/5 TITLE : Creating an IOPL segment in BC++ for OS/2 2.X void main(void) { cout << "TIME IS: "; Time time; getTime(time); DisplayTime(time); cout << endl; } ----------------------- END OF RTC.CPP -------------------- ---------------------- START OF RTC.DEF ------------------- NAME IOPLTEST STACKSIZE 2000 SEGMENTS IOPLCODE IOPL ---------------------- END OF RTC.DEF --------------------- ----------------------- START OF IO16.ASM ----------------- ; ************************************************************* ; * Assembly Language module that declares a 16 bit segment. * ; * It is required that a 16 bit segment is used to create an * ; * IOPL segment. * ; ************************************************************* P386 ; Procedure in the IOPL segment must be pascal to ; clean up their stack. MODEL LARGE, PASCAL IOPLCODE SEGMENT WORD PUBLIC USE16 'CODE' ASSUME CS:IOPLCODE PUBLIC WPORTW ; Write a word to a port PUBLIC WPORTB ; Write a byte to a port PUBLIC RPORTW ; Read a word from a port PUBLIC RPORTB ; Read a byte from a port ; ************************************************************** PRODUCT : Borland C++ NUMBER : 1535 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 4/5 TITLE : Creating an IOPL segment in BC++ for OS/2 2.X ; * Write port functions WPORTW and WPORTB are called with EDX * ; * holding both the port address and the value to write. * ; * EDX low word contains the address of the port, and the EDX * ; * high word contains the value to write. * ; ************************************************************** WPORTW PROC FAR push edx xor eax, eax ; clear eax shld eax, edx, 16 ; get the value to write out dx,ax pop edx ret ENDP WPORTB PROC FAR push edx xor eax, eax ; clear the eax shld eax, edx, 16 ; get the value to write out dx,al pop edx ret ENDP ;************************************************************** ;* The Read port functions should contain the port address to * ;* read from the DX register. The CX register will contain * ;* the value read from the port in either CL or CX for byte * ;* or word port reads. * ;************************************************************** RPORTW PROC FAR in ax,dx mov ecx, eax ret ENDP PRODUCT : Borland C++ NUMBER : 1535 VERSION : 1.0 OS : OS/2 DATE : October 25, 1993 PAGE : 5/5 TITLE : Creating an IOPL segment in BC++ for OS/2 2.X RPORTB PROC FAR in al,dx mov ecx, eax ret ENDP IOPLCODE ENDS END ----------------------- END OF IO16.ASM -------------------- DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.