123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- ; Measure vertical retrace time
- TestCycPerFrame proc
- ; Set up the Measurer
- ; (a bunch of 'inc de' instructions)
- N_INCS equ 4287 ; Max ~80000 T-states between interrupts
- ld hl,Measurer
- ld de,Measurer+1
- ld bc,N_INCS-1
- ld (hl),19 ; inc de
- ; inc de is 7T-states (it's the core of this algorithm)
- ldir ; This takes more than 1 frame
- ; Wait for first retrace (so we aren't caught in an inconvenient place)
- ; Also give the BIOS a chance to check the keyboard.
- halt
- inc hl
- ld (hl),243 ; di
- inc hl
- ld (hl),62 ; ld a,N
- inc hl
- ld (hl),1 ; Error code 1: "Too slow"
- inc hl
- ld (hl),195 ; jp NN
- inc hl
- ld (hl),LOW Finish
- inc hl
- ld (hl),HIGH Finish
- ; Clear cycles per frame counter
- xor a
- ld h,a
- ld l,a
- ld (CycFrm1),hl
- ld (CycFrm3),a
- ; Prepare everything for IM2
- ld hl,IntMeasure
- ld (IntVec),hl
- ; The test works on this principle. Say you have two gears, a small one with 7
- ; teeth and a bigger one with an unknown number of teeth, but you can check at
- ; any time whether the big gear has completed a revolution. Now, you can count
- ; how many revs of the small gear it takes for the big gear to complete a
- ; whole turn, but that will only be exact if the number of teeth in the big
- ; gear is an exact multiple of 7. But if you wait until the big gear takes 7
- ; revs, you can be sure that (a) the gears are in the same relative position
- ; as at the start, and (b) more importantly, the number of revs of the small
- ; gear is exactly the number of teeth in the big gear.
- ; Run the test 7 times.
- ld b,1+7 ; Number of times to run. The first one is used to sync.
- ld de,0 ; Do not add anything the first time
- ; Switch to IM 2
- im 2
- ; Start of measurement loop
- halt
- ; never returns
- endp
- IntMeasure proc
- ; On arrival: ; 30T ; (19 + 11)
- in a,(99h) ; 12T ; Ack interrupt
- inc sp ; 7T
- inc sp ; 7T ; Ignore return address
- ld hl,(CycFrm1) ; 17T
- add hl,de ; 12T
- ld (CycFrm1),hl ; 17T
- ld hl,CycFrm3 ; 11T
- ld a,(hl) ; 8T
- adc a,0 ; 8T
- ld (hl),a ; 8T
- ld hl,_TooFast ; 11T
- ld (IntVec),hl ; 17T
- dec b ; 5T ; Check test counter
- jp z,_Exit ; 11T
- ld hl,0 ; 11T ; delay
- cp 0 ; 8T ; delay, total 19T
- ei ; 5T
- ; Wait for a while more. This reduces memory requirements by reducing the number
- ; of INC DE instructions expected.
- ld hl,1658 ; 11T ; adjusted to give 50,001T = 7*7143 total
- ; 1658 * (
- _Waiting: dec hl ; 7T
- ld a,h ; 5T
- or l ; 5T
- jr nz,_Waiting ; 13T
- ; )
- ; -5T ; for the false jr condition
- ; 30+12+7+7+17+12+17+11+8+8+8+11+17+5+11+11+8+5+11+1658*(7+5+5+13)-5+11+11+17+11 = 7*7143
- ld de,7143 ; 11T ; Preload DE with total cycles in this routine / 7
- ; (the value it would have if INC DE was executing
- ; continuously this whole time)
- ld hl,IntMeasure ; 11T
- ld (IntVec),hl ; 17T ; hopefully we're not so unlucky as to get an interrupt right here!
- jp Measurer ; 11T ; ... or here
- _Exit:
- ; We're done. There's almost 1 frame left until the next expected interrupt.
- ; Total so far: ; 181T = 30+12+7+7+17+12+17+11+8+8+8+11+17+5+11
- im 1 ; 10T
- ei ; 5T
- ret ; 11T
- ; Triggered if an interrupt comes before ~50K T-states
- _TooFast: ld a,2 ; Error code 2: "Unexpected or too fast interrupt"
- jp Finish
- endp
|