|
- ( ----- 600 )
- TI-84+ Recipe
-
- Support code for the TI-84+ recipe. Contains drivers for the
- keyboard and LCD.
-
- 551 LCD 564 Keyboard
- ( ----- 601 )
- TI-84+ LCD driver
-
- Implement (emit) on TI-84+ (for now)'s LCD screen.
- Load range: 555-560
-
- The screen is 96x64 pixels. The 64 rows are addressed directly
- with CMD_ROW but columns are addressed in chunks of 6 or 8 bits
- (there are two modes).
-
- In 6-bit mode, there are 16 visible columns. In 8-bit mode,
- there are 12.
-
- Note that "X-increment" and "Y-increment" work in the opposite
- way than what most people expect. Y moves left and right, X
- moves up and down.
- (cont.)
- ( ----- 602 )
- # Z-Offset
-
- This LCD has a "Z-Offset" parameter, allowing to offset rows on
- the screen however we wish. This is handy because it allows us
- to scroll more efficiently. Instead of having to copy the LCD
- ram around at each linefeed (or instead of having to maintain
- an in-memory buffer), we can use this feature.
-
- The Z-Offset goes upwards, with wrapping. For example, if we
- have an 8 pixels high line at row 0 and if our offset is 8,
- that line will go up 8 pixels, wrapping itself to the bottom of
- the screen.
-
- The principle is this: The active line is always the bottom
- one. Therefore, when active row is 0, Z is FNTH+1, when row is
- 1, Z is (FNTH+1)*2, When row is 8, Z is 0. (cont.)
- ( ----- 603 )
- # 6/8 bit columns and smaller fonts
-
- If your glyphs, including padding, are 6 or 8 pixels wide,
- you're in luck because pushing them to the LCD can be done in a
- very efficient manner. Unfortunately, this makes the LCD
- unsuitable for a Collapse OS shell: 6 pixels per glyph gives us
- only 16 characters per line, which is hardly usable.
-
- This is why we have this buffering system. How it works is that
- we're always in 8-bit mode and we hold the whole area (8 pixels
- wide by FNTH high) in memory. When we want to put a glyph to
- screen, we first read the contents of that area, then add our
- new glyph, offsetted and masked, to that buffer, then push the
- buffer back to the LCD. If the glyph is split, move to the next
- area and finish the job.
- (cont.)
- ( ----- 604 )
- That being said, it's important to define clearly what CURX and
- CURY variable mean. Those variable keep track of the current
- position *in pixels*, in both axes.
- ( ----- 605 )
- ( Required config: LCD_MEM )
- : _mem+ [ LCD_MEM LITN ] @ + ;
- : FNTW 3 ; : FNTH 5 ;
- : COLS 96 FNTW 1+ / ; : LINES 64 FNTH 1+ / ;
- ( Wait until the lcd is ready to receive a command. It's a bit
- weird to implement a waiting routine in asm, but the forth
- version is a bit heavy and we don't want to wait longer than
- we have to. )
- CODE _wait
- BEGIN,
- 0x10 ( CMD ) INAi,
- RLA, ( When 7th bit is clr, we can send a new cmd )
- JRC, AGAIN,
- ;CODE
- ( ----- 606 )
- ( two pixel buffers that are 8 pixels wide (1b) by FNTH
- pixels high. This is where we compose our resulting pixels
- blocks when spitting a glyph. )
- : LCD_BUF 0 _mem+ ;
- : _cmd 0x10 ( CMD ) PC! _wait ;
- : _data! 0x11 ( DATA ) PC! _wait ;
- : _data@ 0x11 ( DATA ) PC@ _wait ;
- : LCDOFF 0x02 ( CMD_DISABLE ) _cmd ;
- : LCDON 0x03 ( CMD_ENABLE ) _cmd ;
- ( ----- 607 )
- : _yinc 0x07 _cmd ; : _xinc 0x05 _cmd ;
- : _zoff! ( off -- ) 0x40 + _cmd ;
- : _col! ( col -- ) 0x20 + _cmd ;
- : _row! ( row -- ) 0x80 + _cmd ;
- : LCD$
- H@ [ LCD_MEM LITN ] ! FNTH 2 * ALLOT
- LCDON 0x01 ( 8-bit mode ) _cmd
- FNTH 1+ _zoff!
- ;
- ( ----- 608 )
- : _clrrows ( n u -- Clears u rows starting at n )
- SWAP _row!
- ( u ) 0 DO
- _yinc 0 _col!
- 11 0 DO 0 _data! LOOP
- _xinc 0 _data!
- LOOP ;
- : NEWLN ( ln -- )
- DUP 1+ FNTH 1+ * _zoff!
- FNTH 1+ * FNTH 1+ _clrrows ;
- : LCDCLR 0 64 _clrrows ;
- ( ----- 609 )
- : _atrow! ( pos -- ) COLS / FNTH 1+ * _row! ;
- : _tocol ( pos -- col off ) COLS MOD FNTW 1+ * 8 /MOD ;
- : CELL! ( g pos -- )
- DUP _atrow! DUP _tocol _col! ROT ( pos coff g )
- FNTH * ~FNT + ( pos coff a )
- _xinc _data@ DROP
- FNTH 0 DO ( pos coff a )
- C@+ 2 PICK 8 -^ LSHIFT
- _data@ 8 LSHIFT OR
- LCD_BUF I + 2DUP FNTH + C!
- SWAP 8 RSHIFT SWAP C!
- LOOP 2DROP
- DUP _atrow!
- FNTH 0 DO LCD_BUF I + C@ _data! LOOP
- DUP _atrow! _tocol NIP 1+ _col!
- FNTH 0 DO LCD_BUF FNTH + I + C@ _data! LOOP ;
- ( ----- 614 )
- Keyboard driver
-
- Load range: 566-570
-
- Implement a (key) word that interpret keystrokes from the
- builtin keyboard. The word waits for a digit to be pressed and
- returns the corresponding ASCII value.
-
- This routine waits for a key to be pressed, but before that, it
- waits for all keys to be de-pressed. It does that to ensure
- that two calls to _wait only go through after two actual key
- presses (otherwise, the user doesn't have enough time to
- de-press the button before the next _wait routine registers the
- same key press as a second one).
-
- (cont.)
- ( ----- 615 )
- Sending 0xff to the port resets the keyboard, and then we have
- to send groups we want to "listen" to, with a 0 in the group
- bit. Thus, to know if *any* key is pressed, we send 0xff to
- reset the keypad, then 0x00 to select all groups, if the result
- isn't 0xff, at least one key is pressed.
- ( ----- 616 )
- ( Requires KBD_MEM, KBD_PORT )
- ( gm -- pm, get pressed keys mask for group mask gm )
- CODE _get
- HL POP,
- chkPS,
- DI,
- A 0xff LDri,
- KBD_PORT OUTiA,
- A L LDrr,
- KBD_PORT OUTiA,
- KBD_PORT INAi,
- EI,
- L A LDrr, HL PUSH,
- ;CODE
- ( ----- 617 )
- ( wait until all keys are de-pressed. To avoid repeat keys, we
- require 64 subsequent polls to indicate all depressed keys.
- all keys are considered depressed when the 0 group returns
- 0xff. )
- : _wait 64 BEGIN 0 _get 0xff = NOT IF DROP 64 THEN
- 1- DUP NOT UNTIL DROP ;
- ( digits table. each row represents a group. 0 means
- unsupported. no group 7 because it has no key. )
- CREATE _dtbl
- 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C,
- 0xd C, '+' C, '-' C, '*' C, '/' C, '^' C, 0 C, 0 C,
- 0 C, '3' C, '6' C, '9' C, ')' C, 0 C, 0 C, 0 C,
- '.' C, '2' C, '5' C, '8' C, '(' C, 0 C, 0 C, 0 C,
- '0' C, '1' C, '4' C, '7' C, ',' C, 0 C, 0 C, 0 C,
- 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0x80 ( alpha ) C,
- 0 C, 0 C, 0 C, 0 C, 0 C, 0x81 ( 2nd ) C, 0 C, 0x7f C,
- ( ----- 618 )
- ( alpha table. same as _dtbl, for when we're in alpha mode. )
- CREATE _atbl
- 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C, 0 C,
- 0xd C, '"' C, 'W' C, 'R' C, 'M' C, 'H' C, 0 C, 0 C,
- '?' C, 0 C, 'V' C, 'Q' C, 'L' C, 'G' C, 0 C, 0 C,
- ':' C, 'Z' C, 'U' C, 'P' C, 'K' C, 'F' C, 'C' C, 0 C,
- 0x20 C, 'Y' C, 'T' C, 'O' C, 'J' C, 'E' C, 'B' C, 0 C,
- 0 C, 'X' C, 'S' C, 'N' C, 'I' C, 'D' C, 'A' C, 0x80 C,
- 0 C, 0 C, 0 C, 0 C, 0 C, 0x81 ( 2nd ) C, 0 C, 0x7f C,
- : _2nd@ [ KBD_MEM LITN ] C@ 1 AND ;
- : _2nd! [ KBD_MEM LITN ] C@ 0xfe AND + [ KBD_MEM LITN ] C! ;
- : _alock@ [ KBD_MEM LITN ] C@ 2 AND ;
- : _alock^ [ KBD_MEM LITN ] C@ 2 XOR [ KBD_MEM LITN ] C! ;
- ( ----- 619 )
- : _gti ( -- tindex, that it, index in _dtbl or _atbl )
- 0 ( gid ) 0 ( dummy )
- BEGIN ( loop until a digit is pressed )
- DROP
- 1+ DUP 7 = IF DROP 0 THEN ( inc gid )
- 1 OVER LSHIFT 0xff -^ ( group dmask ) _get
- DUP 0xff = NOT UNTIL _wait
- ( gid dmask )
- 0xff XOR ( dpos ) 0 ( dindex )
- BEGIN 1+ 2DUP RSHIFT NOT UNTIL 1-
- ( gid dpos dindex ) NIP
- ( gid dindex ) SWAP 8 * + ;
- ( ----- 620 )
- : _tbl^ ( swap input tbl )
- _atbl = IF _dtbl ELSE _atbl THEN ;
- : (key)
- 0 _2nd! 0 ( lastchr ) BEGIN
- _alock@ IF _atbl ELSE _dtbl THEN
- OVER 0x80 ( alpha ) =
- IF _tbl^ _2nd@ IF _alock^ THEN THEN
- SWAP 0x81 = _2nd!
- _gti + C@
- DUP 0 0x80 >< UNTIL ( loop if not in range )
- ( lowercase? )
- _2nd@ IF DUP 'A' 'Z' =><= IF 0x20 OR THEN THEN
- ;
- : KBD$ 0 [ KBD_MEM LITN ] C! ;
|