syncvint.code.asm 4.7 KB

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