Program function: Write program in the middle of the screen display "a" ~ "Z", and can let people see, this task is better to achieve.
(1) in b800:[160*12+40*2] Place the ASCII code of A, (2) in the loop using a 100000000000H cycle idling to achieve the delay effect, (3) press the keyboard to raise the INT9 interrupt color change
So how to implement, press the ESC key, change the color of the display?
When the keyboard input reaches the 60h port, a 9th interrupt is thrown, and the CPU goes to execute the INT 9 interrupt routine.
We can write an int 9 interrupt routine with the following functions:
? (1) read out the keyboard input from the 60h port;
? (2) Call the BIOS int 9 interrupt routine to handle other hardware details;
? (3) Determine if the scan code is ESC, and if so, change the color of the display and return if it is not.
We analyze the implementation of these functions
1, from the port 60h readout keyboard input use: in al,60h
2. Call the BIOS int 9 interrupt Routine
One thing to note is that the interrupt handler we write is going to be the new int 9 interrupt routine, and the main program must change the entry address of the Int 9 interrupt routine in the interrupt vector table to the entry address of the interrupt handler we wrote. Then when invoking the original int 9 interrupt routine in the new interrupt handler, the entry address of the Int 9 interrupt routine in the interrupt vector table is not the address of the original int 9 interrupt routine. So we cannot call directly with the INT directive. To invoke the original interrupt routine in the new interrupt routine we wrote, we must save the original entry address before changing the entry address of the interrupt routine in the interrupt vector table to the new address. In this way, we can find the entry of the original interrupt routine when the call is needed. For our current question, suppose we save the offset address and segment address of the original int 9 interrupt routine in ds:[0] and ds:[2] cells. Then we can find its entry address in the ds:[0], ds:[2] cell when we need to invoke the original int 9 interrupt routine. So, with the entry address, how do we make the call?
Of course, you cannot use the directive int 9来 call. We can use a different instruction to perform some simulations of the int instruction, thus implementing a call to the interrupt routine. In our view, the int command executes at the time the CPU performs the following work:
(1) Take interrupt type code n;
(2) Sign register into the stack;
(3) If=0,tf=0;
(4) CS, IP into the stack;
(5) Set (IP) = (n*4), (cs= (n*4+2).
The interrupt type code is taken to locate the entry address of the interrupt routine, and in our problem, the entry address of the interrupt routine is known. Therefore, we do not need to do step (1) When we use other instructions to simulate the INT command. Assuming that the ingress address of the interrupt routine to invoke is in the ds:0 and ds:2 cells, we will simulate the int process in the following steps:
(1) Sign register into the stack;
(2) if=0,tf=0;
(3) CS, IP into the stack;
(4) (IP) = ((ds) *16+0), (CS) = ((ds) *16+2).
You can notice the same functionality as (3), (4) and call DWORD ptr ds:[0]. The function of call DWORD ptr ds:[0] is also: (1) CS, IP into the stack, (2) (IP) = ((ds) *16+0), (cs) = ((ds) *16+2).
Description: If you have questions, review the contents of section 10.6.
So the simulation process of the int process becomes:
(1) Sign register into the stack;
(2) if=0,tf=0;
(3) Call DWORD ptr ds:[0]
for (1), PUSHF can be used to implement.
for (2), the and and Popf implementations can be implemented, as in the following directives.
To implement If=0,tf=0 steps:
Pushf
Pop ax
and ah,11111100b; if and of the 9th and 8th digits of the flag register
Push AX
Popf
In this way, the calling function of the analog INT directive, the procedure for invoking the interrupt routines in ds:0, Ds:2, of the ingress address is as follows
PUSHF; flag register into the stack
PUSHF; realize the function of if=0,tf=0
Pop ax
and ah,11111100b; if and of the 9th and 8th digits of the flag register
Push AX
Popf, If=0, tf=0
Call DWORD ptr Ds:[0];call function: ①cs, IP into the stack, ②;(IP) = ((ds) *16+0), ③;(CS) = ((ds) *16+2)
3, if the ESC key scan code, change the color of the display back, how to change the color of the display?
The location shown is the middle of the screen, that is, the 12th row 40 column, the offset address in the video memory is: 160*12+40* 2. So the ASCII code of the character is sent to the b800:160*12+40*2 place. B800:160*12+40*2+1 is a character attribute, so we can change the color of the characters displayed at b800:160*12+40*2 just by changing the data here.
The last problem with this program is to restore the entry address of the INI 9 interrupt routine in the interrupt vector table to its original address before the program returns. Otherwise the program will not be able to use the keyboard after it returns.
Note that all programs in this chapter that are related to the keyboard must run in DOS real mode because you want to access real hardware directly. In the DOS mode of Windows 2000, there are some phenomena that do not conform to the principle of hardware operation.
To develop the INT9 interrupt routine schema:
① in the main program to save the original int9 to the data section, and write their own int9 interrupt routine entry address to the interrupt Vector table 9th interrupt address, corresponding to the IP is 0: [9*4] and CS is 0[9*4+2]
② wait for an external interrupt to automatically call INT9
③ Restore Int9 The original interrupt routine entry after the program is finished running
In the INT9 interrupt routine internal structure
1. Save the common registers used
2. Receiving data from 60h ports
3. Modify the IF and TF values to 0
4. Processing data
5. Invoking the INT9 system interrupt routine using call impersonation
6. Restoring Universal Registers
Note: Since the interrupt routine uses iret return, while the iret process is to ① restore the IP from the stack and Cs,② restore the register state from the stack, this uses the call's far jump (the address in the data section), and by using the process, the CS and IP are saved into the stack. Jump to the specified address after execution and return through RETF, the call is completed and then restore the IP and CS from the stack, and here we call the interrupt routine, is returned with Iret, RETF and Iret return the same IP and CS order, and iret more than RETF restore the register state, So we're going to construct the stack data for the Iret: Save the Register state before call, and then you can restore the program's IP,CS, flag register using the Iret form. We can simply call the BIOS's int 9 interrupt routine As soon as we have finished processing our own data in the interrupt routine we have written.
;program function: Display all characters A-Z at the same point in the middle of the screen;1. Implementing latency with CPU loop empty run;2. Press the ESC key to change the color of the character that is being looped;3. When the program is complete, restore the int9 interrupt vector table againAssumeCS:CodeData Segmentdb -Dup0) data Endscode segmentStart: ;Init ds,es movAx,datamovDs,axmovAx0 movEs,ax;save Int9 IP and CS movAxes:[9*4] mov ds:[0],axmovAxes:[9*4+2] mov ds:[2],axmov es:[9*4],offset int9mov es:[9*4+2],cs;cycle through all characters of a-Z movax,0b800hmovEs,axmovAh'a' Show: mov es:[ the* A+ +*2],ahPagerDelay;Call Delay IncAhCMPAh'Z' JNAShow;restore int9 interrupt vector table movAx0 movEs,axPush ds:[0] Pop es:[9*4] Push ds:[2] Pop es:[9*4+2] movax,4c00hint21h;Use the cup loop to run empty, to achieve the effect of delay time;32-bit borrow subtraction for 0000 0000h CyclesDelay: PushAxPushDXmovdx,1000hmovAx0 S: SubAx1 SBBDx0 CMPAx0 jnesCMPDx0 jnesPopDXPopAxret;implementing the Int9 interrupt routine;PUSHF is 16 bits, pop is 16 bitint9: PushAx;Saving Temporary variables inchal,60hPUSHF ;Popf operation for call simulation Int9 PUSHF ;for modifying if=0, tf=0 operations PopBX andbh,111111 - PushBXPopf PagerDWORD ptrds:[0] ;after the int9 of this simulation is called, the iret operation is performed ;will first Popf out the first PUSHF value. CMPAl1 jneInt9retAddbyte ptres:[ the* A+ +*2+1],11hInt9ret: PopAxIretCode endsend start
Program Simplification:
1) trigger the INT9 interrupt routine when the keyboard is pressed, and if and TF are already set to 0, we don't need to set the
2) The original int9 can be saved to 0:200, using interrupt calls in the program
Problems that exist:
In the above program, if you set the interrupt vector table when not all completed, is to reposition the interrupt vector table address when the keyboard key interrupt, the Cup will jump to an incorrect address execution, how to solve it? Tip: Use STI and CLI commands
Display in the middle of the screen, press ESC to change the color of the character