Turbo-C/C++'s int86
function is used to make system interrupt calls to DOS and BIOS services. The REGS
union is a way to address individual registers in the interrupt context data structure. In order to make a DOS or BIOS call you need to set up values in the registers based on the requirements of the system call you want to make. Ralph Brown's Interrupt List (RBIL) is an excellent source of DOS and BIOS system calls, their parameters and their return values. The Turbo-C documentation defines int86
this way:
Name int86 - general 8086 software interrupt interface
Usage int int86(int intr_num, union REGS *inregs,
union REGS *outregs);
Prototype in dos.h
Description Both of these functions execute an 8086 software
interrupt specified by the argument intr_num.
Before executing the software interrupt, both functions
copy register values from inregs into the registers.
In addition, int86x copies the segregs->x.ds and
segregs->x.es values into the corresponding registers
before executing the software interrupt. This feature
allows programs that use far pointers, or that use a
large data memory model, to specify which segment is
to be used during the software interrupt.
After the software interrupt returns, both functions
copy the current register values to outregs, copy the
status of the system carry flag to the x.cflag field
in outregs, and copy the value of the 8086 flags register
to the x.flags field in outregs. In addition, int86x
restores DS, and sets the segregs->es and segregs->ds
fields to the values of the corresponding segment
registers.
If the carry flag is set, it indicates that an error
occurred.
int86x allows you to invoke an 8086 software interrupt
that takes a value of DS different from the default data
segment, and/or that takes an argument in ES.
Note that inregs can point to the same structure that
outregs points to.
Return value int86 and int86x return the value of AX after completion
of the software interrupt. If the carry flag is set
(outregs->x.cflag != 0), indicating an error, these
functions set _doserrno to the error code.
int86
takes the interrupt number to call and two REGS
union pointers. The first one contains the values that need to be set upon entry to the interrupt handler and the second is a way to retrieve the register values that are returned by the interrupt.
Turbo-C/C++'s definition of REGS
looks similar to:
struct WORDREGS {
unsigned int ax, bx, cx, dx, si, di, cflag, flags;
};
struct BYTEREGS {
unsigned char al, ah, bl, bh, cl, ch, dl, dh;
};
union REGS {
struct WORDREGS x;
struct BYTEREGS h;
};
The h
part of the union is simply a mechanism of addressing the high and low 8-bit registers of the 16-bit registers AX, BX, CX, and DX rather than through the full 16-bit register via x
. This code:
i.h.ah=0;
simply sets the AH register (The top 8-bit register of AX) to 0 to pass into the int86
function. This code:
int86(22,&i,&o);
Is making a call to software interrupt 22 (0x16). If you look at RBIL Int 0x16/AH=x00
you find that it is the BIOS call for:
KEYBOARD - GET KEYSTROKE
AH = 00h
Return:
AH = BIOS scan code
AL = ASCII character
You will see that this BIOS call returns the BIOS scan code of the next character pressed in AH and AL is the ASCII code.
The line:
return(o.h.ah);
returns the BIOS scan code of the character pressed from getkeys
Note: The code while(!kbhit( ));
waits in a loop until a key press is detected. The Int 0x16/AH=0x00 call is being used to retrieve the BIOS scan code of that key press.
i
ando
are the input and output registers for theint86
call.ah
is a register. On input it contains the function code which is0
for "Wait for Keypress and Read Character". On output it contains the scancode read. – Bleedingi.h.ah=0;
is being done inside the while loop (which is not the case). Some people put the semicolon after the while on a line by itself to help avoid this kind of confusion. – Laburnum