Timer Time Data Conversion Sub-program Analysis In the day, I am watching a clock TSR program, analyzing one of the program fragments that convert timer data in the BIOS data area into HH: mm: SS time format data (ASCII) program segment, I learned a little thing and found a problem that I didn't understand. Now I wrote the good things you have learned and share it with you, and ask all the experts asking all the way. The program fragment is as follows: (assembly language program) ... (omit) HMS DB 8 DUP (':') ... Time Proc Lea Di, Position; (1) - Lines MOV AX, 0; (2) MOV DS, AX; (3) MOV Al, DS: [46EH]; (4) Call Clk1; (5) MOV AX, DS: [46CH]; (6) MOV DX, 0; (7) MOV BX, 444H; (8) Call CLK0; (9) MOV AX, DX; (10) MoV CX, 3CH; (11) MUL CX; (12) CLK0: Add Di, 3; (13) DIV BX; (14) CLK1: AAM (15) Add AX, 3030H; (16) XCHG AH, Al; (17) MOV CS: [DI], AX; (18) RET; (19) TIME ENDP
The principle of program fragment implementation is to interrupt BIOS's int 1ch clock control interrupt in the BIOS data area 1040: 006CH (low words) and 0040: 006EH (high character) unit 32-bit time digital counter in a relatively concise Switch into hh: mm: SS time format (for ASCII characters), then use another display subroutine to display the conversion-making character to the screen. INT1CH interrupt occurs once every 55 milliseconds, plus the contents of 0040: 006ch - 0040: 006EH in the 32-bit time digital counter of 0040: 006ch - 0040: 006EH, 24 hours a day, the maximum count value is up to 001800B0H, reaching the maximum value, INT1CH Reset this counter is 0, then re-count, and the new day begins again. I don't understand why the biggest value of the counter will be 1800B0H (1573040), 1573040 * 55/1000 = 86517.2 (second) and 24 hours is 86400 seconds, and the counter value is larger than the actual value. INT1CH is interrupted every 55 milliseconds, that is, 1 second interrupt 18.1818181818 ... (countless 18) times, if it is interrupted by 18.2 times per second, the value of the 24-hour counter should be 1572480, 560 less than 1573040 ( It is 30.8 seconds). One hour 3600 seconds interrupt is 65520 (calculated at 18.2), less than 65535 (65536) (65536) (1 second). 360 times a day, 560 times a few days ago. I really make me understand. Now assume that the value of a time counter analyzes the execution process of the above program segment. Suppose [0040: 006EH] = 0017H, [0040: 006EH] = 1AA3H. The execution process of the program fragment is: {(1) -> (4)} -> {(15) -> (19)} -> {(6) -> (8)} -> {(13) -> 19)} -> {(10) -> (19)} (the number in the parentheses is the line number, the arrow in the braces is the order command sequence, the arrow outside the braces jumps in the command)
(1) -> (3): DS = AX = 0, Di = HMS displacement, HMS is a memory unit for storing the conversion time value (ASCII). (4): MOV Al, DS: [46EH], Al = 17h (5): CALL CLK1; calling CLK1
The execution process of CLK1 is as follows: ((15) -> (19), this time the transition hour value) (15): AAM instruction, multiply ASCII adjustment instruction, adjust the value in Al as a non-compressed BCD format, ie AL divided by 0AH (10), the remaining number is placed in Al. After execution, AX = 0203H. (16): add ax, 3030h Let AX = 3233H, which is the ASCII value of 2 and 3. (17) : XCHG AH, AL AX = 3332H. (18): MOV CS: [DI], AX exists in HMS in the converted value (ASCII). (19): Ret returns. (Return to execute Article 6 instructions)
At this point, HMS is (high words) ':', ':', ':', ':', ':', ':', '3', '2' (low words)
(6): MOV AX, DS: [46CH] AX = 1AA3H (7), (8): BX = 444H, DX = 0 (9): Call CLK0; Calling CLK0CLK0 execution procedure is as follows: ((13) -> (19), convert the minute value) (12): Add di, 3 DI 3, pointing to the pointer to the HMS plus 3. (14): Div BX removes 1AA3H in 444H. 444H = 1092, 1092 / 18.2 = 60 (seconds). After the instruction is executed, AX = 06H (quotient), DX = 10BH (15) ... (19): That is to execute CLK1, the execution process is the same as the above, put ax = 06h (minute Convert to the displayed ASCII value. (19) Ret returns to subsection (10).
At this point, HMS is (high character) ':', ':', ':', '6', '0', ':', '3', '2' (low words)
Start conversion second value:
(10), (11): ax = 10bh, CX = 3CH. (3CH = 60) (12): 10bh * 3CH = 3E94, AX = 3e94h (13) ... (19): Although the CLK0 is performed again. 14) DIV BX; 3E94H / 444H AX = 0EH, DX = 2DCH. The third execution of CLK1, converts AX = 0EH (14) into a displayable ASCII character. Process is the same. (19) Ret returns call TIME subroutine From (10) to (14) 267 * 60/1092 = 267 / 18.2, (10bh = 267) means interrupting 267 times equivalent to how many seconds.
Finally, HMS is (high character) '4', '1', ':', '6', '0', ':', '3', '2' (low words), time is 23:06: 14.
As can be seen, high-character [0040: 006EH] is time value, low words [0040: 006CH] is 65520 interruptions in one hour. The above conversion process is already very clear. 0040: 006EH-0040: 006CH, high-character directly call CLK1 to convert to a video character. The low word divided by a minute value (quotient) in 444h (sub), and then the CLK1 is converted to a video character. The remainder (less than one minute interruption) is then multiplied by 3ch, other than 444 h, that is, the remainder is divided by a second value (quote), the last call CLK1 is converted into a video character. The converted characters are present in the HMS memory cell. The algorithm of the subroutine Time is very easy to understand, but the process of the implementation of INT1CH interruption is not clear, there is no corresponding reference document, there are several questions still can't do, and you will not be able to open, special super prawns (lobster?) consult. Thank you!