123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- IF !DEFINED origin
- .ERROR "Run pasmo with: --equ origin=<addr>"
- ENDIF
- ; System variables
- VALTYP equ 0F663h
- DAC equ 0F7F6h
- ; <addr> must end with FDh
- ; 0CEFDh
- org origin
- jp Start
- ; 0CF00h
- IntVecs: rept 257
- db HIGH IntProc
- endm
- ; 0D001h
- ; Vars (NOTE: KEEP IT TO MAX 128 BYTES! Otherwise move them after IntProc)
- ; Low 16 bits of number of cycles between vertical interrupts
- Cyc_lo dw 0
- ; High 8 bits of number of cycles between vertical interrupts
- Cyc_hi db 0
- ErrCode db 0
- ; Save the I register. There's no technical reason, it's just that I like leaving things
- ; the same way I find them :)
- SaveI db 0
- ; Allows a "panic exit"
- SaveSP dw 0
- ; Interrupt entry point
- org (HIGH $)*0101h
- IntProc: db 195 ; 11T ; jp NN
- IntVec: dw IntMeasure
- ; Clean up and exit (A=exit code)
- Finish proc
- di
- ld sp,(SaveSP)
- ei
- im 1
- ld (DAC+2),a
- xor a
- ld (DAC+3),a
- ld l,a
- ld h,a
- ld (DAC),hl
- ld (DAC+4),hl
- ld (DAC+6),hl
- ld a,2
- ld (VALTYP),a
- ld a,(SaveI)
- ld i,a
- ret
- endp
- ; Main starting point
- Start proc
- ld a,i
- ld (SaveI),a
- ld (SaveSP),sp
- call Measure
- xor a
- jp Finish
- endp
- ; Measure vertical retrace time
- Measure proc
- ; Set up the Measurer
- ; (a bunch of 'inc de' instructions)
- ld hl,IntMeasure
- ld (IntVec),hl
- ld hl,Measurer
- ld de,Measurer+1
- ld bc,4287-1 ; Max ~80000 T-states between interrupts
- ld (hl),19 ; inc de
- ; inc de is 7T-states (it's the core of this algorithm)
- ldir
- 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
- ; Wait for first retrace (so we aren't caught in an inconvenient place)
- halt
- ; Setup
- xor a
- ld h,a
- ld l,a
- ld (Cyc_lo),hl
- ld (Cyc_hi),a
- ld a,HIGH IntVecs
- ld i,a
- im 2
- ; 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
- ; Start of measurement loop
- halt
- ; never returns
- endp
- IntMeasure proc
- local Waiting
- ; On arrival: ; 30T ; (19 + 11)
- in a,(99h) ; 12T ; Ack interrupt
- inc sp ; 7T
- inc sp ; 7T ; Ignore return address
- ld hl,(Cyc_lo) ; 17T
- add hl,de ; 12T
- ld (Cyc_lo),hl ; 17T
- ld hl,Cyc_hi ; 11T
- ld a,(hl) ; 8T
- adc a,0 ; 8T
- ld (hl),a ; 8T
- ld hl,TooFast ; 11T
- ld (IntVec),hl ; 17T
- ei ; 5T
- ; Wait for a while more. This reduces memory requirements.
- ld hl,1659 ; 11T
- ; (
- Waiting: dec hl ; 7T
- ld a,h ; 5T
- or l ; 5T
- jr nz,Waiting ; 13T
- ; ) * 1659
- ; -5T ; for the false jr condition
- ld de,7143 ; 11T ; Total cycles in this routine / 7
- dec b ; 5T
- ld hl,IntMeasure ; 11T
- ld (IntVec),hl ; 17T ; hopefully we're not so unlucky as to get an interrupt right here!
- jp nz,Measurer ; 11T ; ... or here
- ; 30+12+7+7+17+12+17+11+8+8+8+11+17+5+11+(7+5+5+13)*1659-5+11+5+11+17+11 = 7*7143
- ; We're done. There's ~9000 T-states left until the next expected interrupt.
- im 1
- ret
- endp
- ; Triggered if an interrupt comes before ~50K T-states
- TooFast proc
- ld a,2 ; Error code for "Unexpected or too fast interrupt"
- jp Finish
- endp
- Measurer:
|