123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- ; Synchronize with Vertical Retrace
- ; Find the exact cycle at which the interrupt is triggered.
- ; Auxiliary routines which will presumably be used by several tests
- ; Given a signed number of T-states in HL, wait for exactly (CycPerFrame + HL) T-states.
- ; HL is typically negative; it's easier to reason through the signs that way.
- ; HL must be between -32478 and 33057 inclusive.
- ; Trashes AF, HL
- WaitFrmPlusHL proc
- push de ; 12T
- ld de,-282 ; 11T ; Factor in the number of T-states we use
- add hl,de ; 12T
- ; Calculate CycFrm + hl into h:l:e
- ld a,h ; 5T
- rlca ; 5T ; bit 7 to carry
- sbc a,a ; 5T ; 0 or FF
- ld d,a ; 5T ; Sign-extend h into d
- ld a,(CycFrm1) ; 14T
- add a,l ; 5T
- ld e,a ; 5T
- ld a,(CycFrm2) ; 14T
- adc a,h ; 5T
- ld l,a ; 5T
- ld a,(CycFrm3) ; 14T
- adc a,d ; 5T
- ld h,a ; 5T
- ; Wait (hl*256) T states
- ; (
- _Wait256: ld a,11 ; 8T
- ; 11*(
- _WaitHelper: dec a ; 5T
- jr nz,_WaitHelper ; 13T
- ; )
- ; -5T ; for the false condition in JR
- nop ; 5T
- nop ; 5T
- nop ; 5T
- nop ; 5T
- nop ; 5T
- dec hl ; 7T
- ld a,h ; 5T
- or l ; 5T
- jr nz,_Wait256 ; 13T
- ; ) * HL
- ; -5T ; for the false condition in JR
- ld a,e ; 5T
- pop de ; 11T
- ; 12+11+12+5+5+5+5+14+5+5+14+5+5+14+5+5 + (8+11*(5+13)-5+5+5+5+5+5+7+5+5+13)*HL + (-5)+5+11 + 144+E = 282 + HL*256 + E
- ; Fall through to WaitAplus144
- endp
- ; Wait for A+144 T-states
- ; Input: A = number of T-states to wait (144 extra T-states will be inserted)
- ; Trashes AF, HL
- WaitAplus144 proc
- ld l,16 ; 8T ; 16 = Number of T-states in the loop
- ; Wait (A/16+1)*16 = A/16*16+16
- _Wait_16: sub l ; (5T - not counted as part of the extra)
- jp nc,_Wait_16 ; (11T - not counted as part of the extra)
- ; 16T ; =5+11, because we've subtracted one too many
- ; A is now in range -16..-1. With some trickery we could work with the
- ; negative value, but that's at the expense of code clarity, not
- ; worth for just a 5T saving.
- add a,l ; 5T ; we have A mod 16 now
- ; Now wait A mod 16 plus some constant, via a jump table
- ld l,a ; 5T
- ld h,0 ; 8T
- ; Calculate HL = WaitJTab + 2*A
- add hl,hl ; 12T
- ld a,low WaitJTab ; 8T
- add a,l ; 5T
- ld l,a ; 5T
- ld a,high WaitJTab ; 8T
- adc a,h ; 5T
- ld h,a ; 5T
- ; Calculate HL=(HL)
- ld a,(hl) ; 8T
- inc hl ; 7T
- ld h,(hl) ; 8T
- ld l,a ; 5T
- ; Tail call HL
- jp (hl) ; 5T
- ; Routines below wait for 21+A
- ; 8+16+5+5+8+12+8+5+5+8+5+5+8+7+8+5+5+21+A = 144+A
- ; Jump table for waiting 0 to 15 T-states plus a fixed amount
- WaitJTab dw _Wait_00,_Wait_01,_Wait_02,_Wait_03
- dw _Wait_04,_Wait_05,_Wait_06,_Wait_07
- dw _Wait_08,_Wait_09,_Wait_10,_Wait_11
- dw _Wait_12,_Wait_13,_Wait_14,_Wait_15
- ; Allow disassemblers to sync correctly after the data
- dw 0
- ; We can't wait 9T so the minimum wait is 10T.
- _Wait_15: nop ; 5T
- ; Fall through
- _Wait_10: nop ; 5T
- ; Fall through
- _Wait_05: nop ; 5T
- ; Fall through
- _Wait_00: nop ; 5T ; \_ 10T
- nop ; 5T ; /
- ret ; 11T
- _Wait_11: nop ; 5T
- ; Fall through
- _Wait_06: nop ; 5T
- ; Fall through
- _Wait_01: ld hl,0 ; 11T ; >- 11T
- ret ; 11T
- _Wait_12: nop ; 5T
- ; Fall through
- _Wait_07: nop ; 5T
- ; Fall through
- _Wait_02: nop ; 5T ; \_ 12T
- inc hl ; 7T ; /
- ret ; 11T
- _Wait_13: nop ; 5T
- ; Fall through
- _Wait_08: nop ; 5T
- ; Fall through
- _Wait_03: nop ; 5T ; \_ 13T
- or 0 ; 8T ; /
- ret ; 11T
- _Wait_14: nop ; 5T
- ; Fall through
- _Wait_09: nop ; 5T
- ; Fall through
- _Wait_04: inc hl ; 7T ; \_ 14T
- inc hl ; 7T ; /
- ret
- endp
- ; Synchronize with the VDP's Vertical interrupt to the exact cycle where it happens.
- ; Possible TODO: Synchronize with a known phase of the VDP, once we know exactly
- ; how fast it runs stuff and whether that's distinguishable by software.
- ;
- ; Trashes AF, HL, IntVec
- SyncVInt proc
- ld hl,_PreSyncISR
- ld (IntVec),hl
- im 2
- ei
- halt ; Pre-sync with int ack
- ld hl,_SyncISR
- ld (IntVec),hl
- pop hl ; Pop return address (for faster return)
- ei
- halt ; 5T, does not return
- ; On entry: ; 30T ; =19+11
- _SyncISR: in a,(99h) ; 12T
- inc sp ; 7T
- inc sp ; 7T ; Remove return address from stack
- push hl ; 12T
- ld hl,-119 ; 11T ; 30+12+7+7+12+11+5+18+11+5+1 = 119
- ei ; 5T
- call WaitFrmPlusHL ; 18T
- pop hl ; 11T
- nop ; 5T ; 4 out of 5 times it will be interrupted here
- di ; 5T ; If it executes the first cycle of this, we've caught it.
- jp (hl) ; 5T
- ; On return, we're 9T = 4+5 after the interrupt
- ; with im2, di, and the interrupt *not* acknowledged yet.
- _PreSyncISR: in a,(99h)
- ret
- endp
|