syncvint.code.asm 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. ; Synchronize with Vertical Retrace
  2. ; Find the exact cycle at which the interrupt is triggered.
  3. ; Auxiliary routines which will presumably be used by several tests
  4. ; Given a signed number of T-states in HL, wait for exactly (CycPerFrame + HL) T-states.
  5. ; HL is typically negative; it's easier to reason through the signs that way.
  6. ; HL must be between -32478 and 33057 inclusive.
  7. ; Trashes AF, HL
  8. WaitFrmPlusHL proc
  9. push de ; 12T
  10. ld de,-282 ; 11T ; Factor in the number of T-states we use
  11. add hl,de ; 12T
  12. ; Calculate CycFrm + hl into h:l:e
  13. ld a,h ; 5T
  14. rlca ; 5T ; bit 7 to carry
  15. sbc a,a ; 5T ; 0 or FF
  16. ld d,a ; 5T ; Sign-extend h into d
  17. ld a,(CycFrm1) ; 14T
  18. add a,l ; 5T
  19. ld e,a ; 5T
  20. ld a,(CycFrm2) ; 14T
  21. adc a,h ; 5T
  22. ld l,a ; 5T
  23. ld a,(CycFrm3) ; 14T
  24. adc a,d ; 5T
  25. ld h,a ; 5T
  26. ; Wait (hl*256) T states
  27. ; (
  28. _Wait256: ld a,11 ; 8T
  29. ; 11*(
  30. _WaitHelper: dec a ; 5T
  31. jr nz,_WaitHelper ; 13T
  32. ; )
  33. ; -5T ; for the false condition in JR
  34. nop ; 5T
  35. nop ; 5T
  36. nop ; 5T
  37. nop ; 5T
  38. nop ; 5T
  39. dec hl ; 7T
  40. ld a,h ; 5T
  41. or l ; 5T
  42. jr nz,_Wait256 ; 13T
  43. ; ) * HL
  44. ; -5T ; for the false condition in JR
  45. ld a,e ; 5T
  46. pop de ; 11T
  47. ; 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
  48. ; Fall through to WaitAplus144
  49. endp
  50. ; Wait for A+144 T-states
  51. ; Input: A = number of T-states to wait (144 extra T-states will be inserted)
  52. ; Trashes AF, HL
  53. WaitAplus144 proc
  54. ld l,16 ; 8T ; 16 = Number of T-states in the loop
  55. ; Wait (A/16+1)*16 = A/16*16+16
  56. _Wait_16: sub l ; (5T - not counted as part of the extra)
  57. jp nc,_Wait_16 ; (11T - not counted as part of the extra)
  58. ; 16T ; =5+11, because we've subtracted one too many
  59. ; A is now in range -16..-1. With some trickery we could work with the
  60. ; negative value, but that's at the expense of code clarity, not
  61. ; worth for just a 5T saving.
  62. add a,l ; 5T ; we have A mod 16 now
  63. ; Now wait A mod 16 plus some constant, via a jump table
  64. ld l,a ; 5T
  65. ld h,0 ; 8T
  66. ; Calculate HL = WaitJTab + 2*A
  67. add hl,hl ; 12T
  68. ld a,low WaitJTab ; 8T
  69. add a,l ; 5T
  70. ld l,a ; 5T
  71. ld a,high WaitJTab ; 8T
  72. adc a,h ; 5T
  73. ld h,a ; 5T
  74. ; Calculate HL=(HL)
  75. ld a,(hl) ; 8T
  76. inc hl ; 7T
  77. ld h,(hl) ; 8T
  78. ld l,a ; 5T
  79. ; Tail call HL
  80. jp (hl) ; 5T
  81. ; Routines below wait for 21+A
  82. ; 8+16+5+5+8+12+8+5+5+8+5+5+8+7+8+5+5+21+A = 144+A
  83. ; Jump table for waiting 0 to 15 T-states plus a fixed amount
  84. WaitJTab dw _Wait_00,_Wait_01,_Wait_02,_Wait_03
  85. dw _Wait_04,_Wait_05,_Wait_06,_Wait_07
  86. dw _Wait_08,_Wait_09,_Wait_10,_Wait_11
  87. dw _Wait_12,_Wait_13,_Wait_14,_Wait_15
  88. ; Allow disassemblers to sync correctly after the data
  89. dw 0
  90. ; We can't wait 9T so the minimum wait is 10T.
  91. _Wait_15: nop ; 5T
  92. ; Fall through
  93. _Wait_10: nop ; 5T
  94. ; Fall through
  95. _Wait_05: nop ; 5T
  96. ; Fall through
  97. _Wait_00: nop ; 5T ; \_ 10T
  98. nop ; 5T ; /
  99. ret ; 11T
  100. _Wait_11: nop ; 5T
  101. ; Fall through
  102. _Wait_06: nop ; 5T
  103. ; Fall through
  104. _Wait_01: ld hl,0 ; 11T ; >- 11T
  105. ret ; 11T
  106. _Wait_12: nop ; 5T
  107. ; Fall through
  108. _Wait_07: nop ; 5T
  109. ; Fall through
  110. _Wait_02: nop ; 5T ; \_ 12T
  111. inc hl ; 7T ; /
  112. ret ; 11T
  113. _Wait_13: nop ; 5T
  114. ; Fall through
  115. _Wait_08: nop ; 5T
  116. ; Fall through
  117. _Wait_03: nop ; 5T ; \_ 13T
  118. or 0 ; 8T ; /
  119. ret ; 11T
  120. _Wait_14: nop ; 5T
  121. ; Fall through
  122. _Wait_09: nop ; 5T
  123. ; Fall through
  124. _Wait_04: inc hl ; 7T ; \_ 14T
  125. inc hl ; 7T ; /
  126. ret
  127. endp
  128. ; Synchronize with the VDP's Vertical interrupt to the exact cycle where it happens.
  129. ; Possible TODO: Synchronize with a known phase of the VDP, once we know exactly
  130. ; how fast it runs stuff and whether that's distinguishable by software.
  131. ;
  132. ; Trashes AF, HL, IntVec
  133. SyncVInt proc
  134. ld hl,_PreSyncISR
  135. ld (IntVec),hl
  136. im 2
  137. ei
  138. halt ; Pre-sync with int ack
  139. ld hl,_SyncISR
  140. ld (IntVec),hl
  141. pop hl ; Pop return address (for faster return)
  142. ei
  143. halt ; 5T, does not return
  144. ; On entry: ; 30T ; =19+11
  145. _SyncISR: in a,(99h) ; 12T
  146. inc sp ; 7T
  147. inc sp ; 7T ; Remove return address from stack
  148. push hl ; 12T
  149. ld hl,-119 ; 11T ; 30+12+7+7+12+11+5+18+11+5+1 = 119
  150. ei ; 5T
  151. call WaitFrmPlusHL ; 18T
  152. pop hl ; 11T
  153. nop ; 5T ; 4 out of 5 times it will be interrupted here
  154. di ; 5T ; If it executes the first cycle of this, we've caught it.
  155. jp (hl) ; 5T
  156. ; On return, we're 9T = 4+5 after the interrupt
  157. ; with im2, di, and the interrupt *not* acknowledged yet.
  158. _PreSyncISR: in a,(99h)
  159. ret
  160. endp