133 lines
4.9 KiB
NASM
133 lines
4.9 KiB
NASM
|
|
||
|
; NOTE: the code in this section is mostly copied from the OSDev wiki. (wiki.osdev.org) {though osdev.org/osdev.com works just fine.}
|
||
|
|
||
|
|
||
|
|
||
|
section .bss
|
||
|
system_timer_fractions: resd 1 ; Fractions of 1 ms since timer initialized
|
||
|
system_timer_ms: resd 1 ; Number of whole ms since timer initialized
|
||
|
IRQ0_fractions: resd 1 ; Fractions of 1 ms between IRQs
|
||
|
IRQ0_ms: resd 1 ; Number of whole ms between IRQs
|
||
|
IRQ0_frequency: resd 1 ; Actual frequency of PIT
|
||
|
PIT_reload_value: resw 1 ; Current PIT reload value
|
||
|
|
||
|
section .text
|
||
|
|
||
|
global IRQ0_handler
|
||
|
global init_PIT
|
||
|
|
||
|
IRQ0_handler:
|
||
|
push eax
|
||
|
push ebx
|
||
|
|
||
|
mov eax, [IRQ0_fractions]
|
||
|
mov ebx, [IRQ0_ms] ; eax.ebx = amount of time between IRQs
|
||
|
add [system_timer_fractions], eax ; Update system timer tick fractions
|
||
|
adc [system_timer_ms], ebx ; Update system timer tick milli-seconds
|
||
|
|
||
|
mov al, 0x20
|
||
|
out 0x20, al ; Send the EOI to the PIC
|
||
|
|
||
|
pop ebx
|
||
|
pop eax
|
||
|
iretd
|
||
|
|
||
|
|
||
|
;Input
|
||
|
; ebx Desired PIT frequency in Hz
|
||
|
|
||
|
init_PIT:
|
||
|
pushad
|
||
|
|
||
|
; Do some checking
|
||
|
|
||
|
mov eax,0x10000 ;eax = reload value for slowest possible frequency (65536)
|
||
|
cmp ebx,18 ;Is the requested frequency too low?
|
||
|
jbe .gotReloadValue ; yes, use slowest possible frequency
|
||
|
|
||
|
mov eax,1 ;ax = reload value for fastest possible frequency (1)
|
||
|
cmp ebx,1193181 ;Is the requested frequency too high?
|
||
|
jae .gotReloadValue ; yes, use fastest possible frequency
|
||
|
|
||
|
; Calculate the reload value
|
||
|
|
||
|
mov eax,3579545
|
||
|
mov edx,0 ;edx:eax = 3579545
|
||
|
div ebx ;eax = 3579545 / frequency, edx = remainder
|
||
|
cmp edx,3579545 / 2 ;Is the remainder more than half?
|
||
|
jb .l1 ; no, round down
|
||
|
inc eax ; yes, round up
|
||
|
.l1:
|
||
|
mov ebx,3
|
||
|
mov edx,0 ;edx:eax = 3579545 * 256 / frequency
|
||
|
div ebx ;eax = (3579545 * 256 / 3 * 256) / frequency
|
||
|
cmp edx,3 / 2 ;Is the remainder more than half?
|
||
|
jb .l2 ; no, round down
|
||
|
inc eax ; yes, round up
|
||
|
.l2:
|
||
|
|
||
|
|
||
|
; Store the reload value and calculate the actual frequency
|
||
|
|
||
|
.gotReloadValue:
|
||
|
push eax ;Store reload_value for later
|
||
|
mov [PIT_reload_value],ax ;Store the reload value for later
|
||
|
mov ebx,eax ;ebx = reload value
|
||
|
|
||
|
mov eax,3579545
|
||
|
mov edx,0 ;edx:eax = 3579545
|
||
|
div ebx ;eax = 3579545 / reload_value, edx = remainder
|
||
|
cmp edx,3579545 / 2 ;Is the remainder more than half?
|
||
|
jb .l3 ; no, round down
|
||
|
inc eax ; yes, round up
|
||
|
.l3:
|
||
|
mov ebx,3
|
||
|
mov edx,0 ;edx:eax = 3579545 / reload_value
|
||
|
div ebx ;eax = (3579545 / 3) / frequency
|
||
|
cmp edx,3 / 2 ;Is the remainder more than half?
|
||
|
jb .l4 ; no, round down
|
||
|
inc eax ; yes, round up
|
||
|
.l4:
|
||
|
mov [IRQ0_frequency],eax ;Store the actual frequency for displaying later
|
||
|
|
||
|
|
||
|
; Calculate the amount of time between IRQs in 32.32 fixed point
|
||
|
;
|
||
|
; Note: The basic formula is:
|
||
|
; time in ms = reload_value / (3579545 / 3) * 1000
|
||
|
; This can be rearranged in the following way:
|
||
|
; time in ms = reload_value * 3000 / 3579545
|
||
|
; time in ms = reload_value * 3000 / 3579545 * (2^42)/(2^42)
|
||
|
; time in ms = reload_value * 3000 * (2^42) / 3579545 / (2^42)
|
||
|
; time in ms * 2^32 = reload_value * 3000 * (2^42) / 3579545 / (2^42) * (2^32)
|
||
|
; time in ms * 2^32 = reload_value * 3000 * (2^42) / 3579545 / (2^10)
|
||
|
|
||
|
pop ebx ;ebx = reload_value
|
||
|
mov eax,0xDBB3A062 ;eax = 3000 * (2^42) / 3579545
|
||
|
mul ebx ;edx:eax = reload_value * 3000 * (2^42) / 3579545
|
||
|
shrd eax,edx,10
|
||
|
shr edx,10 ;edx:eax = reload_value * 3000 * (2^42) / 3579545 / (2^10)
|
||
|
|
||
|
mov [IRQ0_ms],edx ;Set whole ms between IRQs
|
||
|
mov [IRQ0_fractions],eax ;Set fractions of 1 ms between IRQs
|
||
|
|
||
|
|
||
|
; Program the PIT channel
|
||
|
|
||
|
pushfd
|
||
|
cli ;Disabled interrupts (just in case)
|
||
|
|
||
|
mov al,00110100b ;channel 0, lobyte/hibyte, rate generator
|
||
|
out 0x43, al
|
||
|
|
||
|
mov ax,[PIT_reload_value] ;ax = 16 bit reload value
|
||
|
out 0x40,al ;Set low byte of PIT reload value
|
||
|
mov al,ah ;ax = high 8 bits of reload value
|
||
|
out 0x40,al ;Set high byte of PIT reload value
|
||
|
|
||
|
popfd
|
||
|
|
||
|
popad
|
||
|
ret
|
||
|
|