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:
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.
I guess, I figured out, what i was doing wrong. First of all, PIC is already initialized by BIOS, defaulting IRQ0 to interrupt 0x08. Also we need to send the EOI to the PIC in the end of out custom interrupt. Now it works! Comments in the code below are probably irrelevant and make no sense anymore.
[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
xor bp, bp
;add an IRQ_0 handler at IVT 0x08 entry:
xor ax, ax
mov ds, ax
cli ; disable interrupts while modifying
mov word [ds:0x20], IRQ_0 ; IVT entry at 0000:0x08
mov word [ds:0x22], 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 PIT:
mov al, 0x34 ; 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 100
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:
mov al, 0x20
out 0x20, al
pop ax
iret
countdown dw 0
times 510 - ($-$$) db 0
dw 0xAA55