vdptest.asm 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. IF !DEFINED origin
  2. .ERROR "Run pasmo with: --equ origin=<addr>"
  3. ENDIF
  4. ; System variables
  5. VALTYP equ 0F663h
  6. DAC equ 0F7F6h
  7. ; <addr> must end with FDh
  8. ; 0CEFDh
  9. org origin
  10. jp Start
  11. ; 0CF00h
  12. IntVecs: rept 257
  13. db HIGH IntProc
  14. endm
  15. ; 0D001h
  16. ; Vars (NOTE: KEEP IT TO MAX 128 BYTES! Otherwise move them after IntProc)
  17. ; Low 16 bits of number of cycles between vertical interrupts
  18. Cyc_lo dw 0
  19. ; High 8 bits of number of cycles between vertical interrupts
  20. Cyc_hi db 0
  21. ErrCode db 0
  22. ; Save the I register. There's no technical reason, it's just that I like leaving things
  23. ; the same way I find them :)
  24. SaveI db 0
  25. ; Allows a "panic exit"
  26. SaveSP dw 0
  27. ; Interrupt entry point
  28. org (HIGH $)*0101h
  29. IntProc: db 195 ; 11T ; jp NN
  30. IntVec: dw IntMeasure
  31. ; Clean up and exit (A=exit code)
  32. Finish proc
  33. di
  34. ld sp,(SaveSP)
  35. ei
  36. im 1
  37. ld (DAC+2),a
  38. xor a
  39. ld (DAC+3),a
  40. ld l,a
  41. ld h,a
  42. ld (DAC),hl
  43. ld (DAC+4),hl
  44. ld (DAC+6),hl
  45. ld a,2
  46. ld (VALTYP),a
  47. ld a,(SaveI)
  48. ld i,a
  49. ret
  50. endp
  51. ; Main starting point
  52. Start proc
  53. ld a,i
  54. ld (SaveI),a
  55. ld (SaveSP),sp
  56. call Measure
  57. xor a
  58. jp Finish
  59. endp
  60. ; Measure vertical retrace time
  61. Measure proc
  62. ; Set up the Measurer
  63. ; (a bunch of 'inc de' instructions)
  64. ld hl,IntMeasure
  65. ld (IntVec),hl
  66. ld hl,Measurer
  67. ld de,Measurer+1
  68. ld bc,4287-1 ; Max ~80000 T-states between interrupts
  69. ld (hl),19 ; inc de
  70. ; inc de is 7T-states (it's the core of this algorithm)
  71. ldir
  72. inc hl
  73. ld (hl),243 ; di
  74. inc hl
  75. ld (hl),62 ; ld a,N
  76. inc hl
  77. ld (hl),1 ; Error code 1: "Too slow"
  78. inc hl
  79. ld (hl),195 ; jp NN
  80. inc hl
  81. ld (hl),LOW Finish
  82. inc hl
  83. ld (hl),HIGH Finish
  84. ; Wait for first retrace (so we aren't caught in an inconvenient place)
  85. halt
  86. ; Setup
  87. xor a
  88. ld h,a
  89. ld l,a
  90. ld (Cyc_lo),hl
  91. ld (Cyc_hi),a
  92. ld a,HIGH IntVecs
  93. ld i,a
  94. im 2
  95. ; The test works on this principle. Say you have two gears, a small one with 7
  96. ; teeth and a bigger one with an unknown number of teeth, but you can check at
  97. ; any time whether the big gear has completed a revolution. Now, you can count
  98. ; how many revs of the small gear it takes for the big gear to complete a
  99. ; whole turn, but that will only be exact if the number of teeth in the big
  100. ; gear is an exact multiple of 7. But if you wait until the big gear takes 7
  101. ; revs, you can be sure that (a) the gears are in the same relative position
  102. ; as at the start, and (b) more importantly, the number of revs of the small
  103. ; gear is exactly the number of teeth in the big gear.
  104. ; Run the test 7 times.
  105. ld b,1+7 ; Number of times to run. The first one is used to sync.
  106. ld de,0 ; Do not add anything the first time
  107. ; Start of measurement loop
  108. halt
  109. ; never returns
  110. endp
  111. IntMeasure proc
  112. local Waiting
  113. ; On arrival: ; 30T ; (19 + 11)
  114. in a,(99h) ; 12T ; Ack interrupt
  115. inc sp ; 7T
  116. inc sp ; 7T ; Ignore return address
  117. ld hl,(Cyc_lo) ; 17T
  118. add hl,de ; 12T
  119. ld (Cyc_lo),hl ; 17T
  120. ld hl,Cyc_hi ; 11T
  121. ld a,(hl) ; 8T
  122. adc a,0 ; 8T
  123. ld (hl),a ; 8T
  124. ld hl,TooFast ; 11T
  125. ld (IntVec),hl ; 17T
  126. ei ; 5T
  127. ; Wait for a while more. This reduces memory requirements.
  128. ld hl,1659 ; 11T
  129. ; (
  130. Waiting: dec hl ; 7T
  131. ld a,h ; 5T
  132. or l ; 5T
  133. jr nz,Waiting ; 13T
  134. ; ) * 1659
  135. ; -5T ; for the false jr condition
  136. ld de,7143 ; 11T ; Total cycles in this routine / 7
  137. dec b ; 5T
  138. ld hl,IntMeasure ; 11T
  139. ld (IntVec),hl ; 17T ; hopefully we're not so unlucky as to get an interrupt right here!
  140. jp nz,Measurer ; 11T ; ... or here
  141. ; 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
  142. ; We're done. There's ~9000 T-states left until the next expected interrupt.
  143. im 1
  144. ret
  145. endp
  146. ; Triggered if an interrupt comes before ~50K T-states
  147. TooFast proc
  148. ld a,2 ; Error code for "Unexpected or too fast interrupt"
  149. jp Finish
  150. endp
  151. Measurer: