recipes/ti84: first step

This was mostly lifted from my "tihello" example, but it required significant
adjustments.

This commit also introduces a font management system. A lot of fonts are
available online, but sources aren't always clear so to avoid copyright
landmines, I re-created my first 5x7 font from scratch.

As it is now, this resulting ROM gets "Collapse OS>" to be displayed on the
LCD screen. Much work still left to do.

ref #41
This commit is contained in:
Virgil Dupras 2019-11-07 11:52:29 -05:00
parent 69daf49920
commit ca84b5dac8
12 changed files with 1042 additions and 0 deletions

658
fonts/5x7.txt Normal file
View File

@ -0,0 +1,658 @@
.
.
.
.
.
.
. .
. .
. .
.....
. .
.....
. .
.
....
.
...
.
....
.
. .
.
.
.
. .
..
. .
..
.. .
. .
... .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. . .
...
.....
...
. . .
.
.
.....
.
.
.
.
.....
..
..
.
.
.
.
...
. .
. ..
. . .
.. .
. .
...
..
. .
.
.
.
.
....
...
. .
.
.
.
.
.....
...
. .
.
..
.
. .
...
..
. .
. .
.....
.
.
.
.....
.
....
.
.
. .
...
...
.
.
...
. .
. .
...
.....
.
.
.
.
.
.
...
. .
. .
...
. .
. .
...
...
. .
. .
...
.
.
...
.
.
.
.
.
.
.
.
.
..
..
.
..
..
.
.....
.....
.
..
..
.
..
..
.
...
. .
.
.
.
.
...
. .
. ..
. ..
.
. .
...
...
. .
. .
.....
. .
. .
. .
....
. .
. .
....
. .
. .
....
...
. .
.
.
.
. .
...
....
. .
. .
. .
. .
. .
....
.....
.
.
....
.
.
.....
.....
.
.
....
.
.
.
...
. .
.
. ..
. .
. .
...
. .
. .
. .
.....
. .
. .
. .
...
.
.
.
.
.
...
..
.
.
.
.
. .
...
. .
. .
..
.
..
. .
. .
.
.
.
.
.
.
.....
. .
.. ..
. . .
. .
. .
. .
. .
. .
.. .
.. .
. . .
. ..
. ..
. .
...
. .
. .
. .
. .
. .
...
....
. .
. .
....
.
.
.
...
. .
. .
. .
. . .
. ..
....
....
. .
. .
....
. .
. .
. .
...
. .
.
...
.
. .
...
.....
.
.
.
.
.
.
. .
. .
. .
. .
. .
. .
...
. .
. .
. .
. .
. .
. .
.
. .
. .
. .
. .
. . .
. . .
. .
. .
. .
. .
.
. .
. .
. .
. .
. .
. .
.
.
.
.
.....
. .
.
.
.
. .
.....
...
.
.
.
.
.
...
.
.
.
.
.
...
.
.
.
.
.
...
.
. .
. .
.....
.
.
...
. .
. .
.....
. .
. .
. .
....
. .
. .
....
. .
. .
....
...
. .
.
.
.
. .
...
....
. .
. .
. .
. .
. .
....
.....
.
.
....
.
.
.....
.....
.
.
....
.
.
.
...
. .
.
. ..
. .
. .
...
. .
. .
. .
.....
. .
. .
. .
...
.
.
.
.
.
...
..
.
.
.
.
. .
...
. .
. .
..
.
..
. .
. .
.
.
.
.
.
.
.....
. .
.. ..
. . .
. .
. .
. .
. .
. .
.. .
.. .
. . .
. ..
. ..
. .
...
. .
. .
. .
. .
. .
...
....
. .
. .
....
.
.
.
...
. .
. .
. .
. . .
. ..
....
....
. .
. .
....
. .
. .
. .
...
. .
.
...
.
. .
...
.....
.
.
.
.
.
.
. .
. .
. .
. .
. .
. .
...
. .
. .
. .
. .
. .
. .
.
. .
. .
. .
. .
. .
.. ..
. . .
. .
. .
. .
.
. .
. .
. .
. .
. .
. .
.
.
.
.
.....
. .
.
.
.
. .
.....
..
.
.
.
.
.
..
.
.
.
.
.
.
.
..
.
.
.
.
.
..
. .
. .

15
fonts/README.md Normal file
View File

@ -0,0 +1,15 @@
# fonts
This folder contains bitmap fonts that are then converted to ASM data tables.
The format for them is straightforward: dots and spaces. Each line is a line in
the letter (for example, in a 6x8 font, each character is 8 lines of 6
characters each, excluding newline).
They cover the 0x21 to 0x7e range and are placed sequentially in the file.
Dots and spaces allow easy visualisation of the result and is thus rather handy.
Padding is excluded from fonts. For example, 5x7.txt is actually a 6x8 font, but
because characters are always padded, it's useless to keep systematic blank
lines or rows around.

BIN
kernel/fnt/5x7.bin Normal file

Binary file not shown.

32
kernel/fnt/mgm.asm Normal file
View File

@ -0,0 +1,32 @@
; Font management
;
; There can only ever be one active font.
;
; *** Defines ***
; FNT_DATA: Pointer to the beginning of the binary font data to work with.
; FNT_WIDTH: Width of the font.
; FNT_HEIGHT: Height of the font.
;
; *** Code ***
; If A is in the range 0x20-0x7e, make HL point to the beginning of the
; corresponding glyph and set Z to indicate success.
; If A isn't in the range, do nothing and unset Z.
fntGet:
cp 0x20
ret c ; A < 0x20. Z was unset by cp
cp 0x7f
jr nc, unsetZ ; A >= 0x7f. Z might be set
push af ; --> lvl 1
push bc ; --> lvl 2
sub 0x20
ld hl, FNT_DATA
ld b, FNT_HEIGHT
.loop:
call addHL
djnz .loop
pop bc ; <-- lvl 2
pop af ; <-- lvl 1
cp a ; set Z
ret

27
kernel/ti/kbd.asm Normal file
View File

@ -0,0 +1,27 @@
; kbd
;
; Control TI-84+'s keyboard.
;
; *** Constants ***
.equ KBD_PORT 0x01
; *** Code ***
; 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.
waitForKey:
push af
ld a, 0xff
out (KBD_PORT), a
ld a, 0x00
out (KBD_PORT), a
.loop:
in a, (KBD_PORT)
inc a ; if a was 0xff, will become 0 (z test)
jr z, .loop ; zero? nothing pressed
pop af
ret

139
kernel/ti/lcd.asm Normal file
View File

@ -0,0 +1,139 @@
; lcd
;
; Implement PutC on TI-84+ (for now)'s LCD screen.
;
; *** Requirements ***
; fnt/mgm
;
; *** Constants ***
.equ LCD_PORT_CMD 0x10
.equ LCD_PORT_DATA 0x11
.equ LCD_CMD_6BIT 0x00
.equ LCD_CMD_DISABLE 0x02
.equ LCD_CMD_ENABLE 0x03
.equ LCD_CMD_XINC 0x05
.equ LCD_CMD_YINC 0x07
.equ LCD_CMD_COL 0x20
.equ LCD_CMD_ROW 0x80
.equ LCD_CMD_CONTRAST 0xc0
; *** Code ***
lcdInit:
; Enable the LCD
ld a, LCD_CMD_ENABLE
call lcdWait
out (LCD_PORT_CMD), a
; Hack to get LCD to work. According to WikiTI, we're to sure why TIOS
; sends these, but it sends it, and it is required to make the LCD
; work. So...
ld a, 0x17
call lcdWait
out (LCD_PORT_CMD), a
ld a, 0x0b
call lcdWait
out (LCD_PORT_CMD), a
; Set some usable contrast
ld a, LCD_CMD_CONTRAST+0x34
call lcdWait
out (LCD_PORT_CMD), a
; Enable 6-bit mode.
ld a, LCD_CMD_6BIT
call lcdWait
out (LCD_PORT_CMD), a
; Enable X-increment mode
ld a, LCD_CMD_XINC
call lcdWait
out (LCD_PORT_CMD), a
ret
; Wait until the lcd is ready to receive a command
lcdWait:
push af
.loop:
in a, (LCD_PORT_CMD)
; When 7th bit is cleared, we can send a new command
rla
jr c, .loop
pop af
ret
; Turn LCD off
lcdOff:
ld a, LCD_CMD_DISABLE
call lcdWait
out (LCD_PORT_CMD), a
ret
; Set LCD's current column to A
lcdSetCol:
; The col index specified in A is compounded with LCD_CMD_COL
add a, LCD_CMD_COL
call lcdWait
out (LCD_PORT_CMD), a
ret
; Set LCD's current row to A
lcdSetRow:
; The col index specified in A is compounded with LCD_CMD_COL
add a, LCD_CMD_ROW
call lcdWait
out (LCD_PORT_CMD), a
ret
; Send the 5x7 glyph that HL points to to the LCD, at its current position.
; After having called this, the LCD's position will have advanced by one
; position
lcdSendGlyph:
push af
push bc
push hl
; For the purpose of this program, we only write on the first line.
; We can assume that we always start at row 0.
xor a
call lcdSetRow
ld b, 7
.loop:
ld a, (hl)
inc hl
call lcdWait
out (LCD_PORT_DATA), a
djnz .loop
; Now that we've sent our 7 rows of pixels, let's go in "Y-increment"
; mode to let the LCD increase by one column after we've sent our 8th
; line, which is blank (padding).
ld a, LCD_CMD_YINC
call lcdWait
out (LCD_PORT_CMD), a
; send blank line
xor a
call lcdWait
out (LCD_PORT_DATA), a
; go back in X-increment mode
ld a, LCD_CMD_XINC
call lcdWait
out (LCD_PORT_CMD), a
pop hl
pop bc
pop af
ret
lcdPutC:
push hl
call fntGet
jr nz, .end
call lcdSendGlyph
.end:
pop hl
ret

2
recipes/.gitignore vendored
View File

@ -2,3 +2,5 @@
*.cfs
*.hex
*.obj
*.rom
*.sms

10
recipes/ti84/Makefile Normal file
View File

@ -0,0 +1,10 @@
TARGET = os.rom
ZASM = ../../tools/zasm.sh
KERNEL = ../../kernel
.PHONY: all
all: $(TARGET)
$(TARGET): glue.asm
$(ZASM) $(KERNEL) < $< > $@
truncate -s 1M $@

32
recipes/ti84/README.md Normal file
View File

@ -0,0 +1,32 @@
# TI-84+
**This is a work-in-progress, this is far from complete.**
## Recipe
This recipe gets the Collapse OS shell to run on the TI-84+, using its LCD
screen as output and its builtin keyboard as input.
## Build the ROM
Running `make` will result in `os.rom` being created.
## Emulate through z80e
[KnightOS][knightos] has a handy emulator, [z80e][z80e] for TI calculators and
it also emulates the screen. It is recommended to use this tool.
Once z80e is installed (build it with SDL support) and `os.rom` is created,
you can run the emulator with:
z80e-sdl -d TI84p --no-rom-check os.rom
You will start with a blank screen, it's normal, you haven't pressed the "ON"
key yet. This key is mapped to F12 in the emulator. Once you press it, the
Collapse OS prompt will appear.
**WIP: the keyboard does nothing else than halting the CPU for now.**
## Upload to the calculator
TODO

96
recipes/ti84/glue.asm Normal file
View File

@ -0,0 +1,96 @@
.equ RAMSTART 0x8000
.equ RAMEND 0xbfff
.equ PORT_INT_MASK 0x03
.equ INT_MASK_ON 0x00
.equ PORT_INT_TRIG 0x04
.equ INT_TRIG_ON 0x00
.equ PORT_BANKB 0x07
jp boot
.fill 0x18-$
jp boot ; reboot
.fill 0x38-$
jp handleInterrupt
.fill 0x53-$
jp boot
; 0x0056
.db 0xFF, 0xA5, 0xFF
.fill 0x64-$
.inc "err.h"
.inc "core.asm"
.equ FNT_WIDTH 5
.equ FNT_HEIGHT 7
.inc "fnt/mgm.asm"
.inc "ti/lcd.asm"
.inc "ti/kbd.asm"
.equ STDIO_RAMSTART RAMSTART
.equ STDIO_GETC GetC
.equ STDIO_PUTC lcdPutC
.inc "stdio.asm"
.inc "parse.asm"
.equ SHELL_RAMSTART STDIO_RAMEND
.equ SHELL_EXTRA_CMD_COUNT 0
.inc "shell.asm"
boot:
di
ld hl, RAMEND
ld sp, hl
im 1
; enable ON key interrupt
in a, (PORT_INT_MASK)
set INT_MASK_ON, a
out (PORT_INT_MASK), a
ld a, 0x80
out (PORT_BANKB), a
ei
call lcdOff
; sleep until we press ON
halt
main:
call lcdInit
xor a
call lcdSetCol
call shellInit
jp shellLoop
GetC:
call waitForKey
jr boot
handleInterrupt:
di
push af
; did we push the ON button?
in a, (PORT_INT_TRIG)
bit INT_TRIG_ON, a
jp z, .done ; no? we're done
; yes? acknowledge and boot
in a, (PORT_INT_MASK)
res INT_MASK_ON, a ; acknowledge interrupt
out (PORT_INT_MASK), a
pop af
ei
jp main
.done:
pop af
ei
reti
FNT_DATA:
.bin "fnt/5x7.bin"

30
tools/font_compile.pl Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/perl
use strict;
# This script converts "space-dot" fonts to binary "glyph rows". One byte for
# each row. In a 5x7 font, each glyph thus use 7 bytes.
my $fn = @ARGV[0];
unless ($fn =~ /.*(\d)x(\d)\.txt/) { die "$fn isn't a font filename" };
my ($width, $height) = ($1, $2);
print STDERR "Reading a $width x $height font.\n";
my $handle;
unless (open($handle, '<', $fn)) { die "Can't open $fn"; }
# We start the binary data with our first char, space, which is not in our input
# but needs to be in our output.
print pack('C*', (0) x $height);
while (<$handle>) {
unless (/( |\.){${width}}\n/) { die "Invalid line format '$_'"; }
my @line = split //, $_;
my $num = 0;
for (my $i=$width-1; $i>=0; $i--) {
if (@line[$width-$i-1] eq '.') {
$num += (1 << $i);
}
}
printf pack('C', $num);
}

View File

@ -13,6 +13,7 @@ INCCFS=$(mktemp)
for p in "$@"; do
"${CFSPACK}" "${p}" "*.h" >> "${INCCFS}"
"${CFSPACK}" "${p}" "*.asm" >> "${INCCFS}"
"${CFSPACK}" "${p}" "*.bin" >> "${INCCFS}"
done
"${ZASMBIN}" "${INCCFS}"