frametime.code.asm 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. ; Measure vertical retrace time
  2. TestCycPerFrame proc
  3. ; Set up the Measurer
  4. ; (a bunch of 'inc de' instructions)
  5. N_INCS equ 4287 ; Max ~80000 T-states between interrupts
  6. ld hl,Measurer
  7. ld de,Measurer+1
  8. ld bc,N_INCS-1
  9. ld (hl),19 ; inc de
  10. ; inc de is 7T-states (it's the core of this algorithm)
  11. ldir ; This takes more than 1 frame
  12. ; Wait for first retrace (so we aren't caught in an inconvenient place)
  13. ; Also give the BIOS a chance to check the keyboard.
  14. halt
  15. inc hl
  16. ld (hl),243 ; di
  17. inc hl
  18. ld (hl),62 ; ld a,N
  19. inc hl
  20. ld (hl),1 ; Error code 1: "Too slow"
  21. inc hl
  22. ld (hl),195 ; jp NN
  23. inc hl
  24. ld (hl),LOW Finish
  25. inc hl
  26. ld (hl),HIGH Finish
  27. ; Clear cycles per frame counter
  28. xor a
  29. ld h,a
  30. ld l,a
  31. ld (CycFrm1),hl
  32. ld (CycFrm3),a
  33. ; Prepare everything for IM2
  34. ld hl,IntMeasure
  35. ld (IntVec),hl
  36. ; The test works on this principle. Say you have two gears, a small one with 7
  37. ; teeth and a bigger one with an unknown number of teeth, but you can check at
  38. ; any time whether the big gear has completed a revolution. Now, you can count
  39. ; how many revs of the small gear it takes for the big gear to complete a
  40. ; whole turn, but that will only be exact if the number of teeth in the big
  41. ; gear is an exact multiple of 7. But if you wait until the big gear takes 7
  42. ; revs, you can be sure that (a) the gears are in the same relative position
  43. ; as at the start, and (b) more importantly, the number of revs of the small
  44. ; gear is exactly the number of teeth in the big gear.
  45. ; Run the test 7 times.
  46. ld b,1+7 ; Number of times to run. The first one is used to sync.
  47. ld de,0 ; Do not add anything the first time
  48. ; Switch to IM 2
  49. im 2
  50. ; Start of measurement loop
  51. halt
  52. ; never returns
  53. endp
  54. IntMeasure proc
  55. local Waiting, Exit, TooFast
  56. ; On arrival: ; 30T ; (19 + 11)
  57. in a,(99h) ; 12T ; Ack interrupt
  58. inc sp ; 7T
  59. inc sp ; 7T ; Ignore return address
  60. ld hl,(CycFrm1) ; 17T
  61. add hl,de ; 12T
  62. ld (CycFrm1),hl ; 17T
  63. ld hl,CycFrm3 ; 11T
  64. ld a,(hl) ; 8T
  65. adc a,0 ; 8T
  66. ld (hl),a ; 8T
  67. ld hl,TooFast ; 11T
  68. ld (IntVec),hl ; 17T
  69. dec b ; 5T ; Check test counter
  70. jp z,Exit ; 11T
  71. ld hl,0 ; 11T ; delay
  72. cp 0 ; 8T ; delay, total 19T
  73. ei ; 5T
  74. ; Wait for a while more. This reduces memory requirements by reducing the number
  75. ; of INC DE instructions expected.
  76. ld hl,1658 ; 11T ; adjusted to give 50,001T = 7*7143 total
  77. ; 1658 * (
  78. Waiting: dec hl ; 7T
  79. ld a,h ; 5T
  80. or l ; 5T
  81. jr nz,Waiting ; 13T
  82. ; )
  83. ; -5T ; for the false jr condition
  84. ; 30+12+7+7+17+12+17+11+8+8+8+11+17+5+11+11+8+5+11+1658*(7+5+5+13)-5+11+11+17+11 = 7*7143
  85. ld de,7143 ; 11T ; Preload DE with total cycles in this routine / 7
  86. ; (the value it would have if INC DE was executing
  87. ; continuously this whole time)
  88. ld hl,IntMeasure ; 11T
  89. ld (IntVec),hl ; 17T ; hopefully we're not so unlucky as to get an interrupt right here!
  90. jp Measurer ; 11T ; ... or here
  91. Exit:
  92. ; We're done. There's almost 1 frame left until the next expected interrupt.
  93. ; Total so far: ; 181T = 30+12+7+7+17+12+17+11+8+8+8+11+17+5+11
  94. im 1 ; 10T
  95. ei ; 5T
  96. ret ; 11T
  97. ; Triggered if an interrupt comes before ~50K T-states
  98. TooFast: ld a,2 ; Error code 2: "Unexpected or too fast interrupt"
  99. jp Finish
  100. endp