; ============================================================================= ; ; Litos8 system timer ; ; ============================================================================= ; ----------------------------------------------------------------------------- ; Exported user functions (4): ; TimerSetMode - initialize timer counter ; TimerSetVal - set counter new initial value ; TimerGetVal - get counter current value ; TimerGetOut - get counter ouput ; ----------------------------------------------------------------------------- ; Ports 40h-43h, clock 1193182 Hz, timer Intel 8254 ; ; 40h - counter 0, system timer (default set to TIMER_MODE_GEN, 65536) ; 41h - counter 1, RAM refresh counter (don't use it!) ; 42h - counter 2, speaker ; 43h - control (whole action must be done after write, or system may hang) ; B0: 0=counter is a 16-bit binary counter (0..0FFFFh) ; 1=counter is a 16-bit decimal counter 4x4 bit decades (0..9999h) ; B1..B3: counter mode (see below) ; B4..B5: latch mode: 0=counter Latch, 1=LOW, 2=HIGH, 3=LOW then HIGH ; B6..B7: counter index 0..2 ; or B6..B7 = 3, read status: ; B1..B3: mask of counters to access ; B4..B5: 1=read counter value ; 2=read counter status (from 40h..42h): ; B7: out pin state ; B6: 1=counter value is 0 ; B0..B5: like defined in the Control Word Reg. CODE_SECTION ; ----------------------------------------------------------------------------- ; Initialize timer counter ; ----------------------------------------------------------------------------- ; INPUT: AL = timer mode (TIMER_MODE_CNT, ...) ; CX = counter initial value (1 to 65535, 0 stands for 65536) ; DL = counter index (0 to 2) ; NOTES: On mode TIMER_MODE_GEN value of 1 is illegal. ; It temporaly disables interrupts. ; It takes aprox. 7 us. ; ----------------------------------------------------------------------------- ; ------------- push registers TimerSetMode: pushf ; push flags push ax ; push AX cli ; disable interrupts ; ------------- prepare control word -> AL shl al,1 ; AL = timer mode << 1, BIN mode or al,B5+B4 ; set 2-byte mode mov ah,dl ; AH <- counter index ror ah,1 ror ah,1 ; AH <- shift to bits 6-7 or al,ah ; AH <- add counter index ; ------------- set counter mode out TIMER_CTRL,al ; set counter mode SHORT_DELAY ; short delay ; ------------- prepare counter port -> DX TimerSetMode4: push dx ; push DX mov dh,0 ; DH <- 0 add dl,TIMER_BASE ; DX <- counter port ; ------------- set initial value LOW mov al,cl ; AL <- initial value LOW out dx,al ; set initial value LOW SHORT_DELAY ; short delay ; ------------- set initial value HIGH mov al,ch ; AL <- initial value HIGH out dx,al ; set initial value HIGH ; ------------- pop registers pop dx ; pop DX pop ax ; pop AX popf ; pop flags (maybe enable interrupts) ret ; ----------------------------------------------------------------------------- ; Set counter new initial value ; ----------------------------------------------------------------------------- ; INPUT: CX = counter new init. value (1 to 65535, 0 stands for 65536) ; DL = counter index (0 to 2) ; NOTES: On mode TIMER_MODE_GEN value of 1 is illegal. ; It temporaly disables interrupts. ; It takes aprox. 4 us. ; ----------------------------------------------------------------------------- ; ------------- push registers TimerSetVal: pushf ; push flags push ax ; push AX cli ; disable interrupts jmp short TimerSetMode4 ; ----------------------------------------------------------------------------- ; Get counter current value ; ----------------------------------------------------------------------------- ; INPUT: DL = counter index (0 to 2) ; OUTPUT: AX = counter current value ; NOTES: It temporaly disables interrupts. ; It takes aprox. 7 us. ; ----------------------------------------------------------------------------- ; ------------- push registers TimerGetVal: pushf ; push flags push dx ; push DX cli ; disable interrupts ; ------------- set counter LATCH command mov al,dl ; AL <- counter index ror al,1 ror al,1 ; AL <- shift to bits 6-7 out TIMER_CTRL,al ; set counter latch command SHORT_DELAY ; short delay ; ------------- prepare counter port -> DX mov dh,0 ; DH <- 0 add dl,TIMER_BASE ; DX <- counter port ; ------------- get current value LOW in al,dx ; AL <- get current value LOW SHORT_DELAY ; short delay mov ah,al ; AH <- current value LOW ; ------------- get current value HIGH in al,dx ; AL <- get current value HIGH xchg al,ah ; AL <- value LOW, AH <- value HIGH ; ------------- pop registers pop dx ; pop DX popf ; pop flags (maybe enable interrupts) ret ; ----------------------------------------------------------------------------- ; Get counter output ; ----------------------------------------------------------------------------- ; INPUT: DL = counter index (0 to 2) ; OUTPUT: AL = counter current output state (0 or 1) ; NOTES: It temporaly disables interrupts. ; It takes aprox. 4 us. ; ----------------------------------------------------------------------------- ; ------------- push registers TimerGetOut: pushf ; push flags push dx ; push DX cli ; disable interrupts ; ------------- set counter LATCH STATUS command mov al,B1 ; AL <- prepare bit of COUNTER 0 xchg cx,dx ; CL <- counter index shl al,cl ; AL <- counter bit xchg cx,dx ; CX, DX <- return old value or al,B7+B6+B5 ; prepare LATCH STATUS command out TIMER_CTRL,al ; set LATCH STATUS command SHORT_DELAY ; short delay ; ------------- Get current status add dl,TIMER_BASE ; EDX <- counter port in al,dx ; AL <- get current status rol al,1 ; AL <- OUT pin value shift B7 -> B0 and al,B0 ; mask value ; ------------- Pop registers pop dx ; pop DX popf ; pop flags (maybe enable interrupts) ret ; ----------------------------------------------------------------------------- ; Constant data ; ----------------------------------------------------------------------------- CONST_SECTION ; ----------------------------------------------------------------------------- ; Uninitialised data ; ----------------------------------------------------------------------------- DATA_SECTION