I have decided to write a small program to check, if I am able to implement a sleep function in a real mode app. Thats, what I did:
- Added an IRQ_0 handler function to the address at 0x0000:0x80, corresponding to the 0x20 interrupt in the IVT
- Set up two PICs, telling the primary one in the ICW2 to bind its IRQ0 to the 0x20 interrupt in the IVT
- Set up PIT wit the divisor value 11931 in order to get approximately 100hz freq
- Set up the stack at 0xffff, since it is a small program, written just to test the sleep function, so I doubt it will need more than 1kib of memory.
- Enabled the VGA graphics mode with a 320x200 screen and 256 colors via the 0x10 BIOS interrupt
- Put a pink pixel somewhere in the middle of the screen
- sleep for some short amount of time
- Put a differently colored pixel right next to it.
And my program never gets to printing the second pixel. Though, I am sure that interrupt 0x20 is my IRQ0 handler, since i called it via int 0x20 for testing.
[BITS 16]
[ORG 0x7C00]
%macro sleep 1 ; one argument, word sized, time to sleep
mov word [countdown], %1; store the arg in the countdown
push ax
%%sleeploop:
cli ; disable interrupts
mov ax, word [countdown]
sti
test ax, ax
jz %%endsleep
nop
nop
nop
nop
nop
nop
jmp %%sleeploop
%%endsleep:
sti
pop ax
%endmacro
;add an IRQ_0 handler at IVT 0x20 entry:
xor ax, ax
mov ds, ax
cli ; disable interrupts while modifying
mov word [ds:0x80], IRQ_0 ; IVT entry at 0000:0x80 = 128 / 4 = interrupt number 32, left open fo user to initialize
mov word [ds:0x82], ax ; our interrupts segment is also 0000, since were touching just the first kib of RAM
sti ; enable interrupts, since were finished with modifying IVT
; set up the PIC:
;ICW1:
mov al, 0x11 ; load the ICW1 into al
out 0x20, al ; send it to the port 0x20(master PIC)
out 0xa0, al ; send it to the port 0xa0(slave PIC)
;ICW2:
mov al, 0x20 ; the number of the 0 interrupt of the master PIC
out 0x20, al ; send it to the master PIC. Now IRQ0 is interrupt 0x20 in the IVT table
mov al, 0x28 ; the number of the first interrupt of the slave PIC
out 0xa0, al ; send it to the slave PIC. Now IRQ9 is interrupt 0x28 in the IVT table
;ICW3:
mov al, 0x4 ; 0x4 - IRQ2, used to call the slave PIC
out 0x21, al ; send it to the master PIC
mov al, 0x2 ; IRQ2 for the slacve PIC
out 0xa1, al ; send it to the slave PIC
;ICW4:
mov al, 1 ; only the bit 0 is set.
out 0x21, al ; by sending it, tell the master PIC, that we are in a 8086 PC
out 0xa1, al ; same, for the slave PIC
;Null out the PIC data registers
xor al, al
out 0x21, al
out 0xa1, al
; set up the PIT:
mov al, 0x36 ; a control word fot PIT, tellig that next values will be in binary, not BCD
out 0x43, al ; send it to PIT
mov ax, 11931 ; our divisor for frequency in order to get 100hz
out 0x40, al ;}
mov al, ah ;}=> send the divisor to PIT
out 0x40, al ;}
; set up the stack:
mov sp, 0xffff
cld
xor ah, ah
mov al, 0x13
int 0x10
mov ax, 0xa000
mov es, ax
mov al, 60
mov byte [es:0x7d96], al
sleep 1
mov al, 50
mov byte [es:0x7d97], al
hlt
IRQ_0: ; a function, bound to the IRQ_0 interrupt
push ax
mov ax, word [countdown]
test ax, ax
jz .IRQ0_end
dec ax
mov word [countdown], ax
.IRQ0_end:
pop ax
iret
countdown dw 0
times 510 - ($-$$) db 0
dw 0xAA55
I guess, I do something wrong with the PIC or PIT initialization.