Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

207 line
4.6KB

  1. ; pad - read input from MD controller
  2. ;
  3. ; Conveniently expose an API to read the status of a MD pad A. Moreover,
  4. ; implement a mechanism to input arbitrary characters from it. It goes as
  5. ; follow:
  6. ;
  7. ; * Direction pad select characters. Up/Down move by one, Left/Right move by 5\
  8. ; * Start acts like Return
  9. ; * A acts like Backspace
  10. ; * B changes "character class": lowercase, uppercase, numbers, special chars.
  11. ; The space character is the first among special chars.
  12. ; * C confirms letter selection
  13. ;
  14. ; This module is currently hard-wired to sms/vdp, that is, it calls vdp's
  15. ; routines during padGetC to update character selection.
  16. ;
  17. ; *** Consts ***
  18. ;
  19. .equ PAD_CTLPORT 0x3f
  20. .equ PAD_D1PORT 0xdc
  21. .equ PAD_UP 0
  22. .equ PAD_DOWN 1
  23. .equ PAD_LEFT 2
  24. .equ PAD_RIGHT 3
  25. .equ PAD_BUTB 4
  26. .equ PAD_BUTC 5
  27. .equ PAD_BUTA 6
  28. .equ PAD_START 7
  29. ; *** Variables ***
  30. ;
  31. ; Button status of last padUpdateSel call. Used for debouncing.
  32. .equ PAD_SELSTAT PAD_RAMSTART
  33. ; Current selected character
  34. .equ PAD_SELCHR @+1
  35. ; When non-zero, will be the next char returned in GetC. So far, only used for
  36. ; LF that is feeded when Start is pressed.
  37. .equ PAD_NEXTCHR @+1
  38. .equ PAD_RAMEND @+1
  39. ; *** Code ***
  40. padInit:
  41. ld a, 0xff
  42. ld (PAD_SELSTAT), a
  43. xor a
  44. ld (PAD_NEXTCHR), a
  45. ld a, 'a'
  46. ld (PAD_SELCHR), a
  47. ret
  48. ; Put status for port A in register A. Bits, from MSB to LSB:
  49. ; Start - A - C - B - Right - Left - Down - Up
  50. ; Each bit is high when button is unpressed and low if button is pressed. For
  51. ; example, when no button is pressed, 0xff is returned.
  52. padStatus:
  53. ; This logic below is for the Genesis controller, which is modal. TH is
  54. ; an output pin that swiches the meaning of TL and TR. When TH is high
  55. ; (unselected), TL = Button B and TR = Button C. When TH is low
  56. ; (selected), TL = Button A and TR = Start.
  57. push bc
  58. ld a, 0b11111101 ; TH output, unselected
  59. out (PAD_CTLPORT), a
  60. in a, (PAD_D1PORT)
  61. and 0x3f ; low 6 bits are good
  62. ld b, a ; let's store them
  63. ; Start and A are returned when TH is selected, in bits 5 and 4. Well
  64. ; get them, left-shift them and integrate them to B.
  65. ld a, 0b11011101 ; TH output, selected
  66. out (PAD_CTLPORT), a
  67. in a, (PAD_D1PORT)
  68. and 0b00110000
  69. sla a
  70. sla a
  71. or b
  72. pop bc
  73. ret
  74. ; From a pad status in A, update current char selection and return it.
  75. ; Sets Z if current selection was unchanged, unset if changed.
  76. padUpdateSel:
  77. call padStatus
  78. push hl ; --> lvl 1
  79. ld hl, PAD_SELSTAT
  80. cp (hl)
  81. ld (hl), a
  82. pop hl ; <-- lvl 1
  83. jr z, .nothing ; nothing changed
  84. bit PAD_UP, a
  85. jr z, .up
  86. bit PAD_DOWN, a
  87. jr z, .down
  88. bit PAD_LEFT, a
  89. jr z, .left
  90. bit PAD_RIGHT, a
  91. jr z, .right
  92. bit PAD_BUTB, a
  93. jr z, .nextclass
  94. jr .nothing
  95. .up:
  96. ld a, (PAD_SELCHR)
  97. inc a
  98. jr .setchr
  99. .down:
  100. ld a, (PAD_SELCHR)
  101. dec a
  102. jr .setchr
  103. .left:
  104. ld a, (PAD_SELCHR)
  105. dec a \ dec a \ dec a \ dec a \ dec a
  106. jr .setchr
  107. .right:
  108. ld a, (PAD_SELCHR)
  109. inc a \ inc a \ inc a \ inc a \ inc a
  110. jr .setchr
  111. .nextclass:
  112. ; Go to the beginning of the next "class" of characters
  113. push bc
  114. ld a, (PAD_SELCHR)
  115. ld b, '0'
  116. cp b
  117. jr c, .setclass ; A < '0'
  118. ld b, ':'
  119. cp b
  120. jr c, .setclass
  121. ld b, 'A'
  122. cp b
  123. jr c, .setclass
  124. ld b, '['
  125. cp b
  126. jr c, .setclass
  127. ld b, 'a'
  128. cp b
  129. jr c, .setclass
  130. ld b, ' '
  131. ; continue to .setclass
  132. .setclass:
  133. ld a, b
  134. pop bc
  135. ; continue to .setchr
  136. .setchr:
  137. ; check range first
  138. cp 0x7f
  139. jr nc, .tooHigh
  140. cp 0x20
  141. jr nc, .setchrEnd ; not too low
  142. ; too low, probably because we overdecreased. Let's roll over
  143. ld a, '~'
  144. jr .setchrEnd
  145. .tooHigh:
  146. ; too high, probably because we overincreased. Let's roll over
  147. ld a, ' '
  148. ; continue to .setchrEnd
  149. .setchrEnd:
  150. ld (PAD_SELCHR), a
  151. jp unsetZ
  152. .nothing:
  153. ; Z already set
  154. ld a, (PAD_SELCHR)
  155. ret
  156. ; Repeatedly poll the pad for input and returns the resulting "input char".
  157. ; This routine takes a long time to return because it waits until C, B or Start
  158. ; was pressed. Until this is done, this routine takes care of updating the
  159. ; "current selection" directly in the VDP.
  160. padGetC:
  161. ld a, (PAD_NEXTCHR)
  162. or a
  163. jr nz, .nextchr
  164. call padUpdateSel
  165. jp z, padGetC ; nothing changed, loop
  166. ; pad status was changed, let's see if an action button was pressed
  167. ld a, (PAD_SELSTAT)
  168. bit PAD_BUTC, a
  169. jr z, .advance
  170. bit PAD_BUTA, a
  171. jr z, .backspace
  172. bit PAD_START, a
  173. jr z, .return
  174. ; no action button pressed, but because our pad status changed, update
  175. ; VDP before looping.
  176. ld a, (PAD_SELCHR)
  177. call vdpConv
  178. call vdpSpitC
  179. jp padGetC
  180. .return:
  181. ld a, LF
  182. ld (PAD_NEXTCHR), a
  183. ; continue to .advance
  184. .advance:
  185. ld a, (PAD_SELCHR)
  186. ; Z was already set from previous BIT instruction
  187. ret
  188. .backspace:
  189. ld a, BS
  190. ; Z was already set from previous BIT instruction
  191. ret
  192. .nextchr:
  193. ; We have a "next char", return it and clear it.
  194. cp a ; ensure Z
  195. ex af, af'
  196. xor a
  197. ld (PAD_NEXTCHR), a
  198. ex af, af'
  199. ret