I've been trying to set up a fixed-duration timer using a PC-compatible 8253 timer #2. Basically I don't want to use a dumb countdown loop because I know it's CPU-dependent.
I'm in a situation where I can't just use the normal timer interrupt (it may not be initialized, early BIOS bring-up), but the 8253 should be available.
* I start by modifying port 61-- clear the last two bits to deactivate the speaker and counter.
* Then I send 10111000 to port 43 -- which should set up timer #2 in software-triggered mode, and feed in my countdown to port 42, LSB then MSB.
* Then turn on port 61 lowest bit to enable the counter.
Where it goes wrong: I want to read back the counter to determine when it reaches 0000.
I've tried:
* Send 10000000 to port 43 -- to "latch" counter 0
* Read in port 42 twice.
What I seem to get is a lot of very random data. If I'm initializing the timer at 0x100, I feel like I shouldn't be getting values over 0x100!
I figure if it was some sort of timing mismatch, and it was reading the LSB twice, you'd see a lot of repeated values (i.e. 7F7F), but that doesn't seem common. If it were a count-up by accident, I'd never see values below 0x100, but the coverage is pretty good.
It eventually DOES get to zero, and the loop ends, and different start values seem subjectively to affect the delay, but is there something wrong with my probing logic? I don't feel confident in a countdown that doesn't count down.
Code as it stands. AX is supposed to be the timer start The outermost indented code is debugging-- it will try to draw a mark on the screen offset "current counter" positions from the top left, of character "original start value / 0x100 + 3".
I'd expect it to fill the screen from the bottom up , potentially with gaps, if ran with a high value of AX, and if ran with a low number (i. e. 0x100) only do the first 0x100 characters. Instead, we get almost the whole screen covered with all characters tried.
I'm in a situation where I can't just use the normal timer interrupt (it may not be initialized, early BIOS bring-up), but the 8253 should be available.
* I start by modifying port 61-- clear the last two bits to deactivate the speaker and counter.
* Then I send 10111000 to port 43 -- which should set up timer #2 in software-triggered mode, and feed in my countdown to port 42, LSB then MSB.
* Then turn on port 61 lowest bit to enable the counter.
Where it goes wrong: I want to read back the counter to determine when it reaches 0000.
I've tried:
* Send 10000000 to port 43 -- to "latch" counter 0
* Read in port 42 twice.
What I seem to get is a lot of very random data. If I'm initializing the timer at 0x100, I feel like I shouldn't be getting values over 0x100!
I figure if it was some sort of timing mismatch, and it was reading the LSB twice, you'd see a lot of repeated values (i.e. 7F7F), but that doesn't seem common. If it were a count-up by accident, I'd never see values below 0x100, but the coverage is pretty good.
It eventually DOES get to zero, and the loop ends, and different start values seem subjectively to affect the delay, but is there something wrong with my probing logic? I don't feel confident in a countdown that doesn't count down.
Code as it stands. AX is supposed to be the timer start The outermost indented code is debugging-- it will try to draw a mark on the screen offset "current counter" positions from the top left, of character "original start value / 0x100 + 3".
I'd expect it to fill the screen from the bottom up , potentially with gaps, if ran with a high value of AX, and if ran with a low number (i. e. 0x100) only do the first 0x100 characters. Instead, we get almost the whole screen covered with all characters tried.
Code:
PUSH DS
PUSH CX
PUSH BX
PUSH AX
PUSH AX ; Save another copy for the count-down quantity
MOV CL, AH
INC CL
INC CL
INC CL
MOV AX, 0xb800
MOV DS, AX
IN AL, 0x61
AND AL, 0b11111100 ; Force counter and speaker off
OUT 0x61, AL
MOV AL, 0b10111000 ; Put timer #2 into soft-trigger mode
OUT 0x43, AL
POP AX
NOP
NOP
OUT 0x42, AL
MOV AL, AH
NOP
NOP
OUT 0x42, AL
IN AL, 0x61
PUSH AX ; Save the control flags
OR AL, 0b00000001 ; Turn on counter but not speaker itself
OUT 0x61, AL
WAIT_FOR_COUNTDOWN:
MOV AL, 0b10001000 ; Latch counter for timer #2
OUT 0x43, AL
NOP
NOP
IN AL, 0x42 ; Yes this is backwards, read LSB then MSB, but since we're looking for 0, it's equal.
MOV AH, AL
NOP
NOP
IN AL, 0x42
MOV BL, AH
MOV BH, AL
SHL BX, 1
MOV [DS:BX],CL
CMP AX, 0000
JNE WAIT_FOR_COUNTDOWN
POP AX
OUT 0x61, AL ; Restore control flags
POP AX
POP BX
POP CX
POP DS
RET