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.

224 lines
7.7KB

  1. ( ----- 600 )
  2. TI-84+ Recipe
  3. Support code for the TI-84+ recipe. Contains drivers for the
  4. keyboard and LCD.
  5. 551 LCD 564 Keyboard
  6. ( ----- 601 )
  7. TI-84+ LCD driver
  8. Implement (emit) on TI-84+ (for now)'s LCD screen.
  9. Load range: 555-560
  10. The screen is 96x64 pixels. The 64 rows are addressed directly
  11. with CMD_ROW but columns are addressed in chunks of 6 or 8 bits
  12. (there are two modes).
  13. In 6-bit mode, there are 16 visible columns. In 8-bit mode,
  14. there are 12.
  15. Note that "X-increment" and "Y-increment" work in the opposite
  16. way than what most people expect. Y moves left and right, X
  17. moves up and down.
  18. (cont.)
  19. ( ----- 602 )
  20. # Z-Offset
  21. This LCD has a "Z-Offset" parameter, allowing to offset rows on
  22. the screen however we wish. This is handy because it allows us
  23. to scroll more efficiently. Instead of having to copy the LCD
  24. ram around at each linefeed (or instead of having to maintain
  25. an in-memory buffer), we can use this feature.
  26. The Z-Offset goes upwards, with wrapping. For example, if we
  27. have an 8 pixels high line at row 0 and if our offset is 8,
  28. that line will go up 8 pixels, wrapping itself to the bottom of
  29. the screen.
  30. The principle is this: The active line is always the bottom
  31. one. Therefore, when active row is 0, Z is FNTH+1, when row is
  32. 1, Z is (FNTH+1)*2, When row is 8, Z is 0. (cont.)
  33. ( ----- 603 )
  34. # 6/8 bit columns and smaller fonts
  35. If your glyphs, including padding, are 6 or 8 pixels wide,
  36. you're in luck because pushing them to the LCD can be done in a
  37. very efficient manner. Unfortunately, this makes the LCD
  38. unsuitable for a Collapse OS shell: 6 pixels per glyph gives us
  39. only 16 characters per line, which is hardly usable.
  40. This is why we have this buffering system. How it works is that
  41. we're always in 8-bit mode and we hold the whole area (8 pixels
  42. wide by FNTH high) in memory. When we want to put a glyph to
  43. screen, we first read the contents of that area, then add our
  44. new glyph, offsetted and masked, to that buffer, then push the
  45. buffer back to the LCD. If the glyph is split, move to the next
  46. area and finish the job.
  47. (cont.)
  48. ( ----- 604 )
  49. That being said, it's important to define clearly what CURX and
  50. CURY variable mean. Those variable keep track of the current
  51. position *in pixels*, in both axes.
  52. ( ----- 605 )
  53. ( Required config: LCD_MEM )
  54. : _mem+ [ LCD_MEM LITN ] @ + ;
  55. : FNTW 3 ; : FNTH 5 ;
  56. : COLS 96 FNTW 1+ / ; : LINES 64 FNTH 1+ / ;
  57. ( Wait until the lcd is ready to receive a command. It's a bit
  58. weird to implement a waiting routine in asm, but the forth
  59. version is a bit heavy and we don't want to wait longer than
  60. we have to. )
  61. CODE _wait
  62. BEGIN,
  63. 0x10 ( CMD ) INAi,
  64. RLA, ( When 7th bit is clr, we can send a new cmd )
  65. JRC, AGAIN,
  66. ;CODE
  67. ( ----- 606 )
  68. ( two pixel buffers that are 8 pixels wide (1b) by FNTH
  69. pixels high. This is where we compose our resulting pixels
  70. blocks when spitting a glyph. )
  71. : LCD_BUF 0 _mem+ ;
  72. : _cmd 0x10 ( CMD ) PC! _wait ;
  73. : _data! 0x11 ( DATA ) PC! _wait ;
  74. : _data@ 0x11 ( DATA ) PC@ _wait ;
  75. : LCDOFF 0x02 ( CMD_DISABLE ) _cmd ;
  76. : LCDON 0x03 ( CMD_ENABLE ) _cmd ;
  77. ( ----- 607 )
  78. : _yinc 0x07 _cmd ; : _xinc 0x05 _cmd ;
  79. : _zoff! ( off -- ) 0x40 + _cmd ;
  80. : _col! ( col -- ) 0x20 + _cmd ;
  81. : _row! ( row -- ) 0x80 + _cmd ;
  82. : LCD$
  83. H@ [ LCD_MEM LITN ] ! FNTH 2 * ALLOT
  84. LCDON 0x01 ( 8-bit mode ) _cmd
  85. FNTH 1+ _zoff!
  86. ;
  87. ( ----- 608 )
  88. : _clrrows ( n u -- Clears u rows starting at n )
  89. SWAP _row!
  90. ( u ) 0 DO
  91. _yinc 0 _col!
  92. 11 0 DO 0 _data! LOOP
  93. _xinc 0 _data!
  94. LOOP ;
  95. : NEWLN ( ln -- )
  96. DUP 1+ FNTH 1+ * _zoff!
  97. FNTH 1+ * FNTH 1+ _clrrows ;
  98. : LCDCLR 0 64 _clrrows ;
  99. ( ----- 609 )
  100. : _atrow! ( pos -- ) COLS / FNTH 1+ * _row! ;
  101. : _tocol ( pos -- col off ) COLS MOD FNTW 1+ * 8 /MOD ;
  102. : CELL! ( g pos -- )
  103. DUP _atrow! DUP _tocol _col! ROT ( pos coff g )
  104. FNTH * ~FNT + ( pos coff a )
  105. _xinc _data@ DROP
  106. FNTH 0 DO ( pos coff a )
  107. C@+ 2 PICK 8 -^ LSHIFT
  108. _data@ 8 LSHIFT OR
  109. LCD_BUF I + 2DUP FNTH + C!
  110. SWAP 8 RSHIFT SWAP C!
  111. LOOP 2DROP
  112. DUP _atrow!
  113. FNTH 0 DO LCD_BUF I + C@ _data! LOOP
  114. DUP _atrow! _tocol NIP 1+ _col!
  115. FNTH 0 DO LCD_BUF FNTH + I + C@ _data! LOOP ;
  116. ( ----- 614 )
  117. Keyboard driver
  118. Load range: 566-570
  119. Implement a (key) word that interpret keystrokes from the
  120. builtin keyboard. The word waits for a digit to be pressed and
  121. returns the corresponding ASCII value.
  122. This routine waits for a key to be pressed, but before that, it
  123. waits for all keys to be de-pressed. It does that to ensure
  124. that two calls to _wait only go through after two actual key
  125. presses (otherwise, the user doesn't have enough time to
  126. de-press the button before the next _wait routine registers the
  127. same key press as a second one).
  128. (cont.)
  129. ( ----- 615 )
  130. Sending 0xff to the port resets the keyboard, and then we have
  131. to send groups we want to "listen" to, with a 0 in the group
  132. bit. Thus, to know if *any* key is pressed, we send 0xff to
  133. reset the keypad, then 0x00 to select all groups, if the result
  134. isn't 0xff, at least one key is pressed.
  135. ( ----- 616 )
  136. ( Requires KBD_MEM, KBD_PORT )
  137. ( gm -- pm, get pressed keys mask for group mask gm )
  138. CODE _get
  139. HL POP,
  140. chkPS,
  141. DI,
  142. A 0xff LDri,
  143. KBD_PORT OUTiA,
  144. A L LDrr,
  145. KBD_PORT OUTiA,
  146. KBD_PORT INAi,
  147. EI,
  148. L A LDrr, HL PUSH,
  149. ;CODE
  150. ( ----- 617 )
  151. ( wait until all keys are de-pressed. To avoid repeat keys, we
  152. require 64 subsequent polls to indicate all depressed keys.
  153. all keys are considered depressed when the 0 group returns
  154. 0xff. )
  155. : _wait 64 BEGIN 0 _get 0xff = NOT IF DROP 64 THEN
  156. 1- DUP NOT UNTIL DROP ;
  157. ( digits table. each row represents a group. 0 means
  158. unsupported. no group 7 because it has no key. )
  159. CREATE _dtbl
  160. 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C,
  161. 0xd C, '+' C, '-' C, '*' C, '/' C, '^' C, 0 C, 0 C,
  162. 0 C, '3' C, '6' C, '9' C, ')' C, 0 C, 0 C, 0 C,
  163. '.' C, '2' C, '5' C, '8' C, '(' C, 0 C, 0 C, 0 C,
  164. '0' C, '1' C, '4' C, '7' C, ',' C, 0 C, 0 C, 0 C,
  165. 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0x80 ( alpha ) C,
  166. 0 C, 0 C, 0 C, 0 C, 0 C, 0x81 ( 2nd ) C, 0 C, 0x7f C,
  167. ( ----- 618 )
  168. ( alpha table. same as _dtbl, for when we're in alpha mode. )
  169. CREATE _atbl
  170. 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C,
  171. 0xd C, '"' C, 'W' C, 'R' C, 'M' C, 'H' C, 0 C, 0 C,
  172. '?' C, 0 C, 'V' C, 'Q' C, 'L' C, 'G' C, 0 C, 0 C,
  173. ':' C, 'Z' C, 'U' C, 'P' C, 'K' C, 'F' C, 'C' C, 0 C,
  174. 0x20 C, 'Y' C, 'T' C, 'O' C, 'J' C, 'E' C, 'B' C, 0 C,
  175. 0 C, 'X' C, 'S' C, 'N' C, 'I' C, 'D' C, 'A' C, 0x80 C,
  176. 0 C, 0 C, 0 C, 0 C, 0 C, 0x81 ( 2nd ) C, 0 C, 0x7f C,
  177. : _2nd@ [ KBD_MEM LITN ] C@ 1 AND ;
  178. : _2nd! [ KBD_MEM LITN ] C@ 0xfe AND + [ KBD_MEM LITN ] C! ;
  179. : _alock@ [ KBD_MEM LITN ] C@ 2 AND ;
  180. : _alock^ [ KBD_MEM LITN ] C@ 2 XOR [ KBD_MEM LITN ] C! ;
  181. ( ----- 619 )
  182. : _gti ( -- tindex, that it, index in _dtbl or _atbl )
  183. 0 ( gid ) 0 ( dummy )
  184. BEGIN ( loop until a digit is pressed )
  185. DROP
  186. 1+ DUP 7 = IF DROP 0 THEN ( inc gid )
  187. 1 OVER LSHIFT 0xff -^ ( group dmask ) _get
  188. DUP 0xff = NOT UNTIL _wait
  189. ( gid dmask )
  190. 0xff XOR ( dpos ) 0 ( dindex )
  191. BEGIN 1+ 2DUP RSHIFT NOT UNTIL 1-
  192. ( gid dpos dindex ) NIP
  193. ( gid dindex ) SWAP 8 * + ;
  194. ( ----- 620 )
  195. : _tbl^ ( swap input tbl )
  196. _atbl = IF _dtbl ELSE _atbl THEN ;
  197. : (key)
  198. 0 _2nd! 0 ( lastchr ) BEGIN
  199. _alock@ IF _atbl ELSE _dtbl THEN
  200. OVER 0x80 ( alpha ) =
  201. IF _tbl^ _2nd@ IF _alock^ THEN THEN
  202. SWAP 0x81 = _2nd!
  203. _gti + C@
  204. DUP 0 0x80 >< UNTIL ( loop if not in range )
  205. ( lowercase? )
  206. _2nd@ IF DUP 'A' 'Z' =><= IF 0x20 OR THEN THEN
  207. ;
  208. : KBD$ 0 [ KBD_MEM LITN ] C! ;