;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
;
; Filename : Irq.asm
; Included from: Main Assembley Module
; Description : Irq handler for timing/tracking vertical retrace
;
; Written by: John McCarthy
; 1316 Redwood Lane
; Pickering, Ontario.
; Canada, Earth, Milky Way (for those out-of-towners)
; L1X 1C5
;
; Internet/Usenet: BRIAN.MCCARTHY@CANREM.COM
; Fidonet: Brian McCarthy 1:229/15
; RIME/Relaynet: ->CRS
;
; Home phone, (905) 831-1944, don't call at 2 am eh!
;
; John Mccarthy would really love to work for a company programming Robots
; or doing some high intensive CPU work. Hint. Hint.
;
; Send me your protected mode source code!
; Send me your Objects!
; But most of all, Send me a postcard!!!!
;
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
.386p
jumps
include pmode.ext
include macros.inc
public _irq_setpmirq
public _irq_resetpmirq
public _irq_resetrastercount
public _irq_timeraster
public _irq_set_timer
public _irq_reset_timer
public _irq_findcontrol
public _irq_tracespast
public _irq_framenumber
public _irqcontrol
input_1 equ 03dah ; input status #1 register
pmodeirq equ 0 ; you could also use irq 8
number_of_irq_subroutines equ 8
.386p
jumps
code32 segment para public use32
assume cs:code32, ds:code32
_irq_tracespast dd 0 ; contains frame speed (irq driven)
_irq_framenumber dd 0 ; number of frames total,eg 23400 = 13 mins
rmirqbuf db 21 dup(?) ; buffer for rm IRQ callback code
ormirqvect dd 0
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Protected mode IRQ handler
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
pmirq0: ; protected mode IRQ0 handler
push eax
mov al,20h
out 20h,al
sti
cld
push ebx ecx edx esi edi ebp ds
mov ds, [cs:_seldata]
; put your protected mode irq code here!!!!!
;-------------------------------------------
;-------------------------------------------
; now my code, this is where I inc that variable
; protected mode version is easy!
inc _irq_tracespast
inc _irq_framenumber
i = 0
rept number_of_irq_subroutines
call [d _irqcontrol+i*4] ; call selected IRQ subroutines
i=i+1
endm
pop ds ebp edi esi edx ecx ebx eax
iretd
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; _irq_setpmirq: Get protected mode IRQ going
; In=Out=Null
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_irq_setpmirq:
pushad
mov ax,900h
int 31h
push ax
mov bl,pmodeirq
mov edx,offset pmirq0
call _setirqvect
xor al,al
call _setirqmask
mov edi,offset rmirqbuf
call _rmpmirqset
mov ormirqvect,eax
call _irq_timeraster
call _irq_set_timer
pop ax
int 31h
popad
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; _irq_resetpmirq: Unhook protected mode IRQ and reset original timer
; In=Out=Null
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_irq_resetpmirq:
mov ax, 900h
int 31h
push ax
mov bl,pmodeirq
mov eax,ormirqvect
call _rmpmirqfree
mov al,1
call _setirqmask
pop ax
int 31h
jmp _irq_reset_timer
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set Irq speed
; In:
; AX = 1193180/# interrupts per second
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_irq_set_timer:
push ax
mov al,36h
out 43h,al
pop ax
out 40h,al
mov al,ah
out 40h,al
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Reset Irq speed to default speed
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_irq_reset_timer: ; reset timer for exit
mov al,36h
out 43h,al
mov ax,0
out 40h,al
out 40h,al
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; _irq_resetrastercount: reset counters (done before anmation loop)
; In=Out=Null
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_irq_resetrastercount: ; reset count before any animation loop
mov _irq_tracespast,1
mov _irq_framenumber,0
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; _irq_timeraster: Guess what this does?
; In=Null
; Out:
; AX=time for raster to occure
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_irq_timeraster:
pushad
mov ax, 900h
int 31h
push ax
mov dx, input_1 ; input# 1 reg
loop1:
in al,dx ; wait for vsync
test al,8
jnz loop1
loop2:
in al,dx
test al,8
jz loop2
mov al,36h ; reset timer
out 43h,al
mov al,0
out 40h,al
mov al,0
out 40h,al
loop3:
in al,dx ; wait for vsync
test al,8
jnz loop3
loop4:
in al,dx
test al,8
jz loop4
xor al,al ; this calculation code courtesy future_crew
out 43h,al ; from mental.exe
in al,40h
mov ah,al
in al,40h
xchg al,ah
neg ax
shr ax,1
movzx eax,ax
mov [esp+30],ax
pop ax
int 31h
popad
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Find next available control vector
; Out:
; CF - 1 no control availeble
; ECX = ?
; CF - 0 control available
; ECX = next usable jump number. eg _irqcontrol[ecx*4] (0,1,2,3...)
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_irq_findcontrol:
push eax edi
mov ecx,number_of_irq_subroutines
mov edi,offset _irqcontrol
mov eax,offset _ret
repnz scasd
neg ecx
sub ecx,-number_of_irq_subroutines+1
pop edi eax
ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; These are the user difinable IRQ controlled jump vectors:
;
; You can have a certine function performed every vertical retrace just
; by setting these to point to the code you wish to be called. When
; you want to disable the subroutine, just reset these vectors to offset
; _ret.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_irqcontrol:
rept number_of_irq_subroutines
dd offset _ret
endm
code32 ends
end