├── .gitignore ├── Makefile ├── README.md ├── TODO ├── addrs-flash.inc ├── addrs-ram.inc ├── crt0.s ├── csi.c ├── cursorx_lookup.inc ├── font ├── spleen-5x8.bdf ├── spleen-5x8.hex └── spleen-5x8.inc ├── getchar.s ├── isr.s ├── logo.ans ├── lpt.s ├── mailstation.h ├── mailstation.inc ├── main.c ├── meta_keys.h ├── modem.s ├── mslib.c ├── putchar.s ├── scancodes.inc ├── settings.s ├── tools ├── generate_cursorx_lookup.rb ├── generate_scancodes.rb ├── hexfont2inc.rb └── relink_packed.rb └── wifi.s /.gitignore: -------------------------------------------------------------------------------- 1 | obj/ 2 | logo.h 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # msTERM 3 | # 4 | # Copyright (c) 2019 joshua stein 5 | # 6 | # Permission to use, copy, modify, and distribute this software for any 7 | # purpose with or without fee is hereby granted, provided that the above 8 | # copyright notice and this permission notice appear in all copies. 9 | # 10 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | # 18 | 19 | ASZ80?= sdasz80 -l -ff 20 | SDCC?= sdcc -mz80 --opt-code-size 21 | 22 | SRCDIR?= ${.CURDIR} 23 | 24 | OBJ?= obj/ 25 | 26 | LOC?= ram 27 | 28 | .if ${LOC} == "flash" 29 | BASE_ADDR= 0x4000 30 | .elif ${LOC} == "ram" 31 | BASE_ADDR= 0x8000 32 | .else 33 | .BEGIN: 34 | @echo 'LOC must be "flash" or "ram"' 35 | @exit 1 36 | .endif 37 | 38 | .BEGIN: 39 | @echo "compiling for running from ${LOC} (${BASE_ADDR})" 40 | 41 | all: msterm.bin 42 | 43 | clean: 44 | rm -f *.{map,bin,ihx,lst,rel,sym,lk,noi} ${SRCDIR}/logo.h 45 | 46 | # assembly 47 | 48 | ADDRS_INC= ${SRCDIR}/addrs-${LOC}.inc 49 | 50 | crt0.rel: crt0.s 51 | $(ASZ80) -o ${.TARGET} ${ADDRS_INC} $> 52 | 53 | getchar.rel: getchar.s 54 | $(ASZ80) -o ${.TARGET} ${ADDRS_INC} $> 55 | 56 | isr.rel: isr.s 57 | $(ASZ80) -o ${.TARGET} ${ADDRS_INC} $> 58 | 59 | lpt.rel: lpt.s 60 | $(ASZ80) -o ${.TARGET} ${ADDRS_INC} $> 61 | 62 | modem.rel: modem.s 63 | $(ASZ80) -o ${.TARGET} ${ADDRS_INC} $> 64 | 65 | putchar.rel: putchar.s $(SRCDIR)/font/spleen-5x8.inc 66 | $(ASZ80) -o ${.TARGET} ${ADDRS_INC} $(SRCDIR)/putchar.s 67 | 68 | settings.rel: settings.s 69 | $(ASZ80) -o ${.TARGET} ${ADDRS_INC} $> 70 | 71 | wifi.rel: wifi.s 72 | $(ASZ80) -o ${.TARGET} ${ADDRS_INC} $> 73 | 74 | $(SRCDIR)/logo.h: logo.ans 75 | (echo "const char logo[] = {"; xxd -i < $> ; echo "};") > ${.TARGET} 76 | 77 | # c code 78 | 79 | csi.rel: csi.c 80 | $(SDCC) -c ${.TARGET} $> 81 | 82 | mslib.rel: mslib.c 83 | $(SDCC) -c ${.TARGET} $> 84 | 85 | main.rel: main.c $(SRCDIR)/logo.h 86 | $(SDCC) -c ${.TARGET} $(SRCDIR)/main.c 87 | 88 | # generated code 89 | 90 | font/spleen-5x8.inc: font/spleen-5x8.hex 91 | ruby $(SRCDIR)/tools/hexfont2inc.rb $> > $(SRCDIR)/${.TARGET} 92 | 93 | # link 94 | 95 | msterm.ihx: crt0.rel isr.rel putchar.rel getchar.rel lpt.rel modem.rel \ 96 | main.rel mslib.rel csi.rel settings.rel wifi.rel 97 | @SDCC="$(SDCC) --no-std-crt0" TARGET="$(.TARGET)" \ 98 | BASE_ADDR="$(BASE_ADDR)" CODE_OFF="$(CODE_OFF)" \ 99 | ruby $(SRCDIR)/tools/relink_packed.rb $> 100 | 101 | # convert to binary 102 | 103 | msterm.bin: msterm.ihx 104 | objcopy -Iihex -Obinary $> $@ 105 | @if [ `stat -f '%z' ${.TARGET}` -gt 16384 ]; then \ 106 | ls -l ${.TARGET}; \ 107 | echo "${.TARGET} overflows a ${LOC} page, must be <= 16384; increase DATA_SIZE"; \ 108 | exit 1; \ 109 | fi 110 | 111 | # helpers 112 | 113 | disasm: msterm.bin 114 | z80dasm -al -g ${BASE_ADDR} $> > msterm.dasm 115 | 116 | upload: all 117 | ../../WiFiStation/host/sendload /dev/cuaU0 msterm.bin 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## msTERM 2 | 3 | ![https://i.imgur.com/2l9rXK4.jpg](https://i.imgur.com/2l9rXK4.jpg) 4 | 5 | A terminal program for the Cidco MailStation. 6 | 7 | msTERM currently targets version 2.54 of the MailStation OS. 8 | 9 | ### Features 10 | 11 | - Support for [WiFiStation](https://jcs.org/wifistation) (`SOURCE_WIFI`) 12 | - Support for controlling the internal modem through `AT` comments 13 | (`SOURCE_MODEM`) 14 | - Support for interfacing with the parallel port like a serial port with 15 | [`tribble_getty`](https://github.com/jcs/mailstation-tools/blob/master/util/tribble_getty.c) 16 | on the host side 17 | - Custom version of 18 | [Spleen 5x8](https://github.com/fcambus/spleen) 19 | with DOS 437 codepage characters giving a 64x15 terminal window with a 20 | status bar 21 | - Blinking the "New Mail" LED when modem data transfers 22 | - Caps Lock key can be used as a Control key and Main Menu as Escape 23 | 24 | ### Compiling 25 | 26 | Install 27 | [SDCC](http://sdcc.sourceforge.net/). 28 | 29 | If your `make` is not a BSD Make, install it and use `bmake` instead of `make`. 30 | You'll also need `objcopy` from Binutils installed in your `$PATH`. 31 | 32 | Create an `obj` directory with `mkdir obj` and then run `make LOC=ram` to 33 | compile a version suitable for running from RAM (via the Loader). 34 | 35 | Then transfer `obj/msterm.bin` to the MailStation with 36 | [WSLoader](https://jcs.org/wifistation) 37 | which will load the application at memory address `0x8000`. 38 | 39 | ### License 40 | 41 | Copyright (c) 2019-2021 [joshua stein](https://jcs.org/) 42 | 43 | Permission to use, copy, modify, and distribute this software for any 44 | purpose with or without fee is hereby granted, provided that the above 45 | copyright notice and this permission notice appear in all copies. 46 | 47 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 48 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 49 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 50 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 51 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 52 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 53 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 54 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Make `putchar` faster (probably just `stamp_char`) because it is currently 2 | too slow to keep the modem at a high speed without dropping data. We may 3 | be able to just get away with using flow control here if we can't make things 4 | fast enough. 5 | 6 | - Add an actual Settings menu to change modem speed through DLAB, speaker 7 | volume from automated calls, etc. This will require persisting settings to a 8 | dataflash page somewhere. 9 | 10 | - Add a Call menu to dial saved phone numbers. 11 | 12 | - Maybe add battery level to status bar? 13 | -------------------------------------------------------------------------------- /addrs-flash.inc: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8:sw=8 2 | 3 | ; when running from dataflash, we are loaded at 0x4000 and use slot 8 4 | ; for swapping devices 5 | .equ RUN_ADDR, #0x4000 6 | .equ RUN_DEVICE, #0x6 7 | .equ RUN_PAGE, #0x5 8 | .equ SLOT_ADDR, #0x8000 9 | .equ SLOT_DEVICE, #0x8 10 | .equ SLOT_PAGE, #0x7 11 | -------------------------------------------------------------------------------- /addrs-ram.inc: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8:sw=8 2 | 3 | ; when running from Loader, we are loaded at 0x8000 and use slot 4 4 | ; for swapping devices 5 | ; 6 | ; CODE_LOC in Makefile should be 0x8100 7 | .equ RUN_ADDR, #0x8000 8 | .equ RUN_DEVICE, #0x8 9 | .equ RUN_PAGE, #0x7 10 | .equ SLOT_ADDR, #0x4000 11 | .equ SLOT_DEVICE, #0x6 12 | .equ SLOT_PAGE, #0x5 13 | -------------------------------------------------------------------------------- /crt0.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8 2 | ; 3 | ; msTERM 4 | ; crt0 5 | ; 6 | ; Copyright (c) 2019 joshua stein 7 | ; 8 | ; Permission to use, copy, modify, and distribute this software for any 9 | ; purpose with or without fee is hereby granted, provided that the above 10 | ; copyright notice and this permission notice appear in all copies. 11 | ; 12 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | ; 20 | 21 | .module crt0 22 | 23 | .include "mailstation.inc" 24 | .globl _main 25 | 26 | .area _HEADER (ABS) 27 | 28 | .org RUN_ADDR 29 | start: 30 | jp boot 31 | 32 | .dw (icons) 33 | .dw (caption) 34 | .dw (dunno) 35 | 36 | dunno: 37 | .db #0 38 | xpos: 39 | .dw #0 40 | ypos: 41 | .dw #0 42 | caption: 43 | .dw #0x0001 ; ? 44 | .dw (endcap - caption - 6) ; number of chars 45 | .dw #0x0006 ; offset to first char 46 | .ascii "msTERM" ; the caption string 47 | endcap: 48 | 49 | icons: 50 | .dw (icon2 - icon1) ; size of icon1 51 | .dw (icon1 - icons) ; offset to icon1 52 | .dw (iconend - icon2) ; size of icon2 53 | .dw (icon2 - icons) ; offset to icon2 54 | 55 | icon1: 56 | .dw #0x0022 ; icon width (34, 5 bytes per row) 57 | .db #0x22 ; icon height (34) 58 | 59 | .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 60 | .db #0x00, #0x00, #0x00, #0xe0, #0x03 ; .............................##### 61 | .db #0x00, #0x00, #0x00, #0x20, #0x02 ; .............................#...# 62 | .db #0x00, #0x00, #0x00, #0xa0, #0x02 ; .............................#.#.# 63 | .db #0x00, #0x00, #0x00, #0xa0, #0x02 ; .............................#.#.# 64 | .db #0x00, #0x00, #0x00, #0xa0, #0x02 ; .............................#.#.# 65 | .db #0x00, #0x00, #0x00, #0xe0, #0x03 ; .............................##### 66 | .db #0x00, #0x00, #0x00, #0x80, #0x00 ; ...............................#.. 67 | .db #0x00, #0xff, #0xff, #0x63, #0x00 ; ........##################...##... 68 | .db #0x00, #0x01, #0x00, #0x12, #0x00 ; ........#................#..#..... 69 | .db #0x00, #0x01, #0x00, #0x12, #0x00 ; ........#................#..#..... 70 | .db #0x00, #0x01, #0x00, #0x0a, #0x00 ; ........#................#.#...... 71 | .db #0xe0, #0x01, #0x00, #0x1e, #0x00 ; .....####................####..... 72 | .db #0xf0, #0x01, #0x00, #0x3e, #0x00 ; ....#####................#####.... 73 | .db #0xf0, #0x01, #0x00, #0x36, #0x00 ; ....#####................##.##.... 74 | .db #0xf8, #0xff, #0xff, #0x7f, #0x00 ; ...############################... 75 | .db #0xa8, #0x92, #0x24, #0x55, #0x00 ; ...#.#.#.#..#..#..#..#..#.#.#.#... 76 | .db #0xfc, #0xff, #0xff, #0xff, #0x00 ; ..##############################.. 77 | .db #0x54, #0x55, #0x55, #0x95, #0x00 ; ..#.#.#.#.#.#.#.#.#.#.#.#.#.#..#.. 78 | .db #0xfe, #0xff, #0xff, #0xff, #0x01 ; .################################. 79 | .db #0xaa, #0xaa, #0xaa, #0x2a, #0x01 ; .#.#.#.#.#.#.#.#.#.#.#.#.#.#.#..#. 80 | .db #0xfe, #0xff, #0xff, #0xff, #0x01 ; .################################. 81 | .db #0x53, #0x55, #0x55, #0x15, #0x03 ; ##..#.#.#.#.#.#.#.#.#.#.#.#.#...## 82 | .db #0xff, #0xff, #0xff, #0xff, #0x03 ; ################################## 83 | .db #0x26, #0x00, #0x00, #0xa8, #0x01 ; .##..#.....................#.#.##. 84 | .db #0xfc, #0xff, #0xff, #0xff, #0x00 ; ..##############################.. 85 | .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 86 | .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 87 | .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 88 | .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 89 | .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 90 | .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 91 | .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 92 | .db #0x00, #0x00, #0x00, #0x00, #0x00 ; .................................. 93 | 94 | icon2: 95 | ; not used 96 | .dw #0x0000 ; width 97 | .db #0x00 ; height 98 | iconend: 99 | 100 | boot: 101 | xor a 102 | out (#0x0d), a ; put the cpu in its highest speed 103 | 104 | ; all of our code expects to run in ram so when we're running from 105 | ; dataflash, we have to copy our page of flash into ram, then jump to 106 | ; it 107 | 108 | ; swap in a page of ram 109 | ld a, #DEVICE_RAM 110 | out (#SLOT_DEVICE), a 111 | out (#SLOT_PAGE), a 112 | 113 | ; copy ourselves into ram 114 | ld de, #SLOT_ADDR 115 | ld hl, #RUN_ADDR 116 | ld bc, #0x4000 117 | ldir ; ld (de), (hl), de++, hl++, bc-- 118 | 119 | jp SLOT_ADDR + (hijump - start) 120 | 121 | hijump: 122 | ; PC is now in SLOT_ADDR, put our new RAM page into RUN_DEVICE/PAGE 123 | out (#RUN_DEVICE), a 124 | out (#RUN_PAGE), a 125 | 126 | ; then jump back there 127 | jp RUN_ADDR + (lojump - start) 128 | 129 | lojump: 130 | call find_shadows 131 | call _main ; main c code 132 | jp _exit 133 | 134 | ; set location of port shadow variables depending on firmware version 135 | find_shadows: 136 | ld a, (#0x0037) ; firmware major version 137 | cp #0x1 138 | jr z, ver_1 139 | cp #0x2 140 | jr z, ver_2 141 | cp #0x3 142 | jr z, ver_3 143 | unrecognized_firmware: ; we can't blink because that requires 144 | jp 0x0 ; port and fw function addresses 145 | ver_1: 146 | ld a, (#0x0036) ; firmware minor version 147 | cp #0x73 148 | jr z, ver_1_73 149 | jr unrecognized_firmware 150 | ver_1_73: ; eMessage 1.73CID 151 | ld hl, #p2shadow 152 | ld (hl), #0xdb9f 153 | ld hl, #p3shadow 154 | ld (hl), #0xdba0 ; TODO: verify 155 | ret 156 | ver_2: 157 | ld a, (#0x0036) ; firmware minor version 158 | cp #0x53 159 | jr z, ver_2_53 160 | jr ver_2_54 ; else, assume 2.54 161 | ver_2_53: ; MailStation 2.53 162 | ld hl, #p2shadow 163 | ld (hl), #0xdba1 164 | ld hl, #p3shadow 165 | ld (hl), #0xdba2 166 | ld hl, #p28shadow 167 | ld (hl), #0xdba0 168 | ret 169 | ver_2_54: ; MailStation 2.54 170 | ld hl, #p2shadow 171 | ld (hl), #0xdba2 172 | ld hl, #p3shadow 173 | ld (hl), #0xdba3 174 | ld hl, #p28shadow 175 | ld (hl), #0xdba0 176 | ret 177 | ver_3: ; MailStation 3.03 178 | ld hl, #p2shadow 179 | ld (hl), #0xdba5 180 | ld hl, #p3shadow 181 | ld (hl), #0xdba6 182 | ret 183 | 184 | .area _DATA 185 | 186 | ; shadow locations 187 | p2shadow: 188 | .dw #0xdba2 189 | p3shadow: 190 | .dw #0xdba3 191 | p28shadow: 192 | .dw #0xdba0 193 | delay_func: 194 | jp 0x0a5c 195 | 196 | _msTERM_version:: 197 | .db #VERSION 198 | _debug0:: 199 | .db #0 200 | _debug1:: 201 | .db #0 202 | _debug2:: 203 | .db #0 204 | _debug3:: 205 | .db #0 206 | _debug4:: 207 | .db #0 208 | 209 | .area _CODE 210 | 211 | ; exit handler, restart 212 | _exit:: 213 | call _reboot 214 | 215 | _powerdown:: 216 | di 217 | call #0x0a6b ; firmware powerdown function 218 | jp _panic ; in case we fail to powerdown somehow 219 | 220 | _reboot:: 221 | jp 0x0000 222 | 223 | ; new_mail(unsigned char on) 224 | ; toggles 'new mail' light 225 | _new_mail:: 226 | di 227 | push ix 228 | ld ix, #0 229 | add ix, sp 230 | push hl 231 | push af 232 | ld a, 4(ix) 233 | cp #0 234 | ld hl, (p2shadow) 235 | jr z, light_off 236 | light_on: 237 | ld a, (hl) 238 | set 4, a 239 | jr write_p2 240 | light_off: 241 | ld a, (hl) 242 | res 4, a 243 | write_p2: 244 | ld (hl), a 245 | out (#0x02), a ; write p2shadow to port2 246 | pop af 247 | pop hl 248 | pop ix 249 | ei 250 | ret 251 | 252 | ; delay(unsigned int millis) 253 | ; call mailstation function that delays (stack) milliseconds 254 | _delay:: 255 | push ix 256 | ld ix, #0 257 | add ix, sp 258 | push af 259 | push bc 260 | push hl 261 | ld l, 4(ix) 262 | ld h, 5(ix) 263 | push hl 264 | call delay_func 265 | pop hl 266 | pop hl 267 | pop bc 268 | pop af 269 | pop ix 270 | ret 271 | 272 | ; blink(unsigned int millis) 273 | ; turn new mail LED on, wait millis, turn it off, wait millis 274 | _blink:: 275 | push ix 276 | ld ix, #0 277 | add ix, sp 278 | push hl 279 | ld l, #1 280 | push hl 281 | call _new_mail ; turn it on 282 | pop hl 283 | ld l, 4(ix) 284 | ld h, 5(ix) 285 | push hl 286 | call _delay ; wait 287 | pop hl 288 | ld l, #0 289 | push hl 290 | call _new_mail ; turn it off 291 | pop hl 292 | ld l, 4(ix) 293 | ld h, 5(ix) 294 | push hl 295 | call _delay ; wait 296 | pop hl 297 | pop af 298 | pop ix 299 | ret 300 | 301 | ; void panic(void) 302 | _panic:: 303 | ld hl, #200 304 | push hl 305 | call _blink 306 | pop hl; 307 | jr _panic 308 | 309 | ; void lcd_sleep(void) 310 | ; turn the LCD off 311 | _lcd_sleep:: 312 | di 313 | push hl 314 | ld hl, (p2shadow) 315 | ld a, (hl) 316 | and #0b01111111 ; LCD_ON - turn port2 bit 7 off 317 | ld (hl), a 318 | out (#0x02), a ; write p2shadow to port2 319 | pop hl 320 | ei 321 | ret 322 | 323 | 324 | ; void lcd_wake(void) 325 | ; turn the LCD on 326 | _lcd_wake:: 327 | di 328 | push hl 329 | ld hl, (p2shadow) 330 | ld a, (hl) 331 | or #0b10000000 ; LCD_ON - turn port2 bit 7 on 332 | ld (hl), a 333 | out (#0x02), a ; write p2shadow to port2 334 | pop hl 335 | ei 336 | ret 337 | 338 | ; unsigned char read_port(unsigned char port) 339 | _read_port:: 340 | push ix 341 | ld ix, #0 342 | add ix, sp 343 | push af 344 | push bc 345 | ld b, #0 346 | ld c, 4(ix) 347 | in l, (C) 348 | ld h, #0 349 | pop bc 350 | pop af 351 | pop ix 352 | ret 353 | 354 | 355 | ; 8-bit multiplication 356 | ; de * a = hl 357 | mult8:: 358 | ld b, #8 359 | ld hl, #0 360 | mult8_loop: 361 | add hl, hl 362 | rlca 363 | jr nc, mult8_noadd 364 | add hl, de 365 | mult8_noadd: 366 | djnz mult8_loop 367 | mult8_out: 368 | ret 369 | 370 | ; 16-bit multiplication 371 | ; bc * de = hl 372 | mult16: 373 | ld a, b 374 | ld b, #16 375 | ld hl, #0 376 | mult16_loop: 377 | add hl, hl 378 | sla c 379 | rla 380 | jr nc, mult16_noadd 381 | add hl, de 382 | mult16_noadd: 383 | djnz mult16_loop 384 | ret 385 | 386 | 387 | ; 8-bit division 388 | ; divide e by c, store result in a and remainder in b 389 | div8: 390 | xor a 391 | ld b, #8 392 | div8_loop: 393 | rl e 394 | rla 395 | sub c 396 | jr nc, div8_noadd 397 | add a, c 398 | div8_noadd: 399 | djnz div8_loop 400 | ld b,a 401 | ld a,e 402 | rla 403 | cpl 404 | ret 405 | 406 | ; 16-bit division 407 | ; divide bc by de, store result in bc, remainder in hl 408 | div16: 409 | ld hl, #0 410 | ld a, b 411 | ld b, #8 412 | div16_loop1: 413 | rla 414 | adc hl, hl 415 | sbc hl, de 416 | jr nc, div16_noadd1 417 | add hl, de 418 | div16_noadd1: 419 | djnz div16_loop1 420 | rla 421 | cpl 422 | ld b, a 423 | ld a, c 424 | ld c, b 425 | ld b, #8 426 | div16_loop2: 427 | rla 428 | adc hl, hl 429 | sbc hl, de 430 | jr nc, div16_noadd2 431 | add hl, de 432 | div16_noadd2: 433 | djnz div16_loop2 434 | rla 435 | cpl 436 | ld b, c 437 | ld c, a 438 | ret 439 | -------------------------------------------------------------------------------- /csi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * msTERM 3 | * ANSI CSI parser 4 | * 5 | * Copyright (c) 2019 joshua stein 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "mailstation.h" 25 | 26 | unsigned char csibuf[TEXT_COLS]; 27 | unsigned int csibuflen; 28 | 29 | unsigned char in_csi; 30 | 31 | void 32 | parseCSI(void) 33 | { 34 | int x, y, serviced; 35 | int param1 = -1, param2 = -1; 36 | char c = csibuf[csibuflen - 1]; 37 | char parambuf[4]; 38 | int parambuflen; 39 | #ifdef DEBUG 40 | char sb[TEXT_COLS]; 41 | #endif 42 | 43 | if (c < 'A' || (c > 'Z' && c < 'a') || c > 'z') 44 | return; 45 | 46 | switch (c) { 47 | case 'A': 48 | case 'B': 49 | case 'C': 50 | case 'D': 51 | case 'E': 52 | case 'F': 53 | case 'G': 54 | case 'J': 55 | case 'K': 56 | case 'S': 57 | case 'T': 58 | case 'd': 59 | case 'g': 60 | case 's': 61 | case 'u': 62 | case '7': 63 | case '8': 64 | /* optional multiplier */ 65 | if (c == 'J' || c == 'K') 66 | param1 = 0; 67 | else 68 | param1 = 1; 69 | 70 | if (csibuflen > 1) { 71 | for (x = 0; x < csibuflen - 1, x < 4; x++) { 72 | parambuf[x] = csibuf[x]; 73 | parambuf[x + 1] = '\0'; 74 | } 75 | param1 = atoi(parambuf); 76 | } 77 | break; 78 | case 'H': 79 | case 'f': 80 | /* two optional parameters separated by ; each defaulting to 1 */ 81 | param1 = 1; 82 | param2 = 1; 83 | 84 | y = -1; 85 | for (x = 0; x < csibuflen; x++) { 86 | if (csibuf[x] == ';') { 87 | y = x; 88 | break; 89 | } 90 | } 91 | if (y == -1) 92 | /* CSI 17H -> CSI 17; */ 93 | y = csibuflen - 1; 94 | 95 | if (y > 0) { 96 | for (x = 0; x < y && x < 4; x++) { 97 | parambuf[x] = csibuf[x]; 98 | parambuf[x + 1] = '\0'; 99 | } 100 | param1 = atoi(parambuf); 101 | 102 | if (y < csibuflen - 2) { 103 | parambuf[0] = '\0'; 104 | for (x = 0; x < (csibuflen - 1 - y) && x < 4; x++) { 105 | parambuf[x] = csibuf[y + 1 + x]; 106 | parambuf[x + 1] = '\0'; 107 | } 108 | param2 = atoi(parambuf); 109 | } 110 | } 111 | break; 112 | } 113 | 114 | serviced = 1; 115 | 116 | uncursor(); 117 | 118 | #ifdef DEBUG 119 | sprintf(sb, "CSI:"); 120 | for (x = 0; x < csibuflen; x++) 121 | sprintf(sb, "%s%c", sb, csibuf[x]); 122 | sprintf(sb, "%s params:%d,%d", sb, param1, param2); 123 | update_statusbar(sb); 124 | #endif 125 | 126 | switch (c) { 127 | case 'A': /* CUU - cursor up, stop at top of screen */ 128 | for (x = 0; x < param1 && cursory > 0; x++) 129 | cursory--; 130 | break; 131 | case 'B': /* CUD - cursor down, stop at bottom of screen */ 132 | for (x = 0; x < param1 && cursory < TEXT_ROWS - 1; x++) 133 | cursory++; 134 | break; 135 | case 'C': /* CUF - cursor forward, stop at screen edge */ 136 | for (x = 0; x < param1 && cursorx < TEXT_COLS; x++) 137 | cursorx++; 138 | break; 139 | case 'D': /* CUB - cursor back, stop at left edge of screen */ 140 | for (x = 0; x < param1 && cursorx > 0; x++) 141 | cursorx--; 142 | break; 143 | case 'E': /* CNL - cursor next line */ 144 | cursorx = 0; 145 | for (x = 0; x < param1 && cursory < TEXT_ROWS - 1; x++) 146 | cursory++; 147 | break; 148 | case 'F': /* CPL - cursor previous line */ 149 | cursorx = 0; 150 | for (x = 0; x < param1 && cursory > 0; x++) 151 | cursory--; 152 | break; 153 | case 'G': /* CHA - cursor horizontal absolute */ 154 | if (param1 > TEXT_COLS) 155 | param1 = TEXT_COLS; 156 | cursorx = param1; 157 | break; 158 | case 'H': /* CUP - cursor absolute position */ 159 | case 'f': /* HVP - horizontal vertical position */ 160 | if (param1 - 1 < 0) 161 | cursory = 0; 162 | else if (param1 > TEXT_ROWS) 163 | cursory = TEXT_ROWS - 1; 164 | else 165 | cursory = param1 - 1; 166 | 167 | if (param2 - 1 < 0) 168 | cursorx = 0; 169 | else if (param2 > TEXT_COLS) 170 | cursorx = TEXT_COLS - 1; 171 | else 172 | cursorx = param2 - 1; 173 | break; 174 | case 'J': /* ED - erase in display */ 175 | switch (param1) { 176 | case 0: 177 | /* clear from cursor to end of screen */ 178 | for (y = cursory; y < TEXT_ROWS; y++) { 179 | for (x = 0; x < TEXT_COLS; x++) { 180 | if (y == cursory && x < cursorx) 181 | continue; 182 | 183 | putchar_attr(y, x, ' ', 0); 184 | } 185 | } 186 | break; 187 | case 1: 188 | /* clear from cursor to beginning of the screen */ 189 | for (y = cursory; y >= 0; y--) { 190 | for (x = TEXT_COLS; x >= 0; x--) { 191 | if (y == cursory && x > cursorx) 192 | continue; 193 | 194 | putchar_attr(y, x, ' ', 0); 195 | } 196 | } 197 | break; 198 | case 2: 199 | /* clear entire screen */ 200 | for (y = 0; y < TEXT_ROWS; y++) { 201 | for (x = 0; x < TEXT_COLS; x++) 202 | putchar_attr(y, x, ' ', 0); 203 | } 204 | } 205 | break; 206 | case 'K': /* EL - erase in line */ 207 | switch (param1) { 208 | case 0: 209 | /* clear from cursor to end of line */ 210 | if (cursorx >= TEXT_COLS) 211 | break; 212 | for (x = cursorx; x < TEXT_COLS; x++) 213 | putchar_attr(cursory, x, ' ', 0); 214 | break; 215 | case 1: 216 | /* clear from cursor to beginning of line */ 217 | if (cursorx == 0) 218 | break; 219 | for (x = cursorx; x >= 0; x--) 220 | putchar_attr(cursory, x, ' ', 0); 221 | break; 222 | case 2: 223 | /* clear entire line */ 224 | for (x = 0; x < TEXT_COLS - 1; x++) 225 | putchar_attr(cursory, x, ' ', 0); 226 | } 227 | break; 228 | case 'S': /* SU - scroll up */ 229 | /* TODO */ 230 | break; 231 | case 'T': /* SD - scroll down */ 232 | /* TODO */ 233 | break; 234 | case 'd': /* absolute line number */ 235 | if (param1 < 1) 236 | cursory = 0; 237 | else if (param1 > TEXT_ROWS) 238 | cursory = TEXT_ROWS; 239 | else 240 | cursory = param1 - 1; 241 | break; 242 | case 'g': /* clear tabs, ignore */ 243 | break; 244 | case 'h': /* reset, ignore */ 245 | break; 246 | case 'm': /* graphic changes */ 247 | parambuf[0] = '\0'; 248 | parambuflen = 0; 249 | param2 = putchar_sgr; 250 | 251 | for (x = 0; x < csibuflen; x++) { 252 | /* all the way to csibuflen to catch 'm' */ 253 | if (csibuf[x] == ';' || csibuf[x] == 'm') { 254 | param1 = atoi(parambuf); 255 | 256 | switch (param1) { 257 | case 0: /* reset */ 258 | case 22: /* normal color */ 259 | param2 = 0; 260 | break; 261 | case 1: /* bold */ 262 | param2 |= ATTR_BOLD; 263 | break; 264 | case 4: /* underline */ 265 | param2 |= ATTR_UNDERLINE; 266 | break; 267 | case 7: /* reverse */ 268 | param2 |= ATTR_REVERSE; 269 | break; 270 | case 21: /* bold off */ 271 | param2 &= ~(ATTR_BOLD); 272 | break; 273 | case 24: /* underline off */ 274 | param2 &= ~(ATTR_UNDERLINE); 275 | break; 276 | case 27: /* inverse off */ 277 | param2 &= ~(ATTR_REVERSE); 278 | break; 279 | } 280 | 281 | parambuf[0] = '\0'; 282 | parambuflen = 0; 283 | } else if (parambuflen < 4) { 284 | parambuf[parambuflen] = csibuf[x]; 285 | parambuflen++; 286 | parambuf[parambuflen] = '\0'; 287 | } 288 | } 289 | 290 | putchar_sgr = param2; 291 | 292 | break; 293 | case 'n': /* DSR - device status report */ 294 | switch (param1) { 295 | case 5: /* terminal is ready */ 296 | obuf[obuf_pos++] = ESC; 297 | obuf[obuf_pos++] = '['; 298 | obuf[obuf_pos++] = '0'; 299 | obuf[obuf_pos++] = 'n'; 300 | break; 301 | case 6: /* CPR - report cursor position */ 302 | obuf[obuf_pos++] = ESC; 303 | obuf[obuf_pos++] = '['; 304 | 305 | itoa(cursory + 1, parambuf, 10); 306 | for (x = 0; x < sizeof(parambuf); x++) { 307 | if (parambuf[x] == '\0') 308 | break; 309 | obuf[obuf_pos++] = parambuf[x]; 310 | } 311 | obuf[obuf_pos++] = ';'; 312 | 313 | itoa(cursorx + 1, parambuf, 10); 314 | for (x = 0; x < sizeof(parambuf); x++) { 315 | if (parambuf[x] == '\0') 316 | break; 317 | obuf[obuf_pos++] = parambuf[x]; 318 | } 319 | 320 | obuf[obuf_pos++] = 'R'; 321 | break; 322 | } 323 | break; 324 | case '7': /* DECSC - save cursor */ 325 | case 's': /* from ANSI.SYS */ 326 | saved_cursorx = cursorx; 327 | saved_cursory = cursory; 328 | break; 329 | case '8': /* DECRC - restore cursor */ 330 | case 'u': /* from ANSI.SYS */ 331 | cursorx = saved_cursorx; 332 | cursory = saved_cursory; 333 | break; 334 | default: 335 | /* 336 | * if the last character is a letter and we haven't serviced 337 | * it, assume it's a sequence we don't support and should just 338 | * suppress 339 | */ 340 | if (c < 65 || (c > 90 && c < 97) || c > 122) 341 | serviced = 0; 342 | } 343 | 344 | if (serviced) { 345 | recursor(); 346 | csibuflen = 0; 347 | csibuf[0] = '\0'; 348 | in_csi = 0; 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /cursorx_lookup.inc: -------------------------------------------------------------------------------- 1 | ; AUTOMATICALLY GENERATED FILE - see tools/generate_cursorx_lookup.rb 2 | .db #0x98 ; 10011000 - col group 19, offset 0 3 | .db #0x9d ; 10011101 - col group 19, offset 5 4 | .db #0x92 ; 10010010 - col group 18, offset 2 5 | .db #0x97 ; 10010111 - col group 18, offset 7 6 | .db #0x8c ; 10001100 - col group 17, offset 4 7 | .db #0x81 ; 10000001 - col group 16, offset 1 8 | .db #0x86 ; 10000110 - col group 16, offset 6 9 | .db #0x7b ; 01111011 - col group 15, offset 3 10 | .db #0x70 ; 01110000 - col group 14, offset 0 11 | .db #0x75 ; 01110101 - col group 14, offset 5 12 | .db #0x6a ; 01101010 - col group 13, offset 2 13 | .db #0x6f ; 01101111 - col group 13, offset 7 14 | .db #0x64 ; 01100100 - col group 12, offset 4 15 | .db #0x59 ; 01011001 - col group 11, offset 1 16 | .db #0x5e ; 01011110 - col group 11, offset 6 17 | .db #0x53 ; 01010011 - col group 10, offset 3 18 | .db #0x48 ; 01001000 - col group 9, offset 0 19 | .db #0x4d ; 01001101 - col group 9, offset 5 20 | .db #0x42 ; 01000010 - col group 8, offset 2 21 | .db #0x47 ; 01000111 - col group 8, offset 7 22 | .db #0x3c ; 00111100 - col group 7, offset 4 23 | .db #0x31 ; 00110001 - col group 6, offset 1 24 | .db #0x36 ; 00110110 - col group 6, offset 6 25 | .db #0x2b ; 00101011 - col group 5, offset 3 26 | .db #0x20 ; 00100000 - col group 4, offset 0 27 | .db #0x25 ; 00100101 - col group 4, offset 5 28 | .db #0x1a ; 00011010 - col group 3, offset 2 29 | .db #0x1f ; 00011111 - col group 3, offset 7 30 | .db #0x14 ; 00010100 - col group 2, offset 4 31 | .db #0x09 ; 00001001 - col group 1, offset 1 32 | .db #0x0e ; 00001110 - col group 1, offset 6 33 | .db #0x03 ; 00000011 - col group 0, offset 3 34 | .db #0x98 ; 10011000 - col group 19, offset 0 35 | .db #0x9d ; 10011101 - col group 19, offset 5 36 | .db #0x92 ; 10010010 - col group 18, offset 2 37 | .db #0x97 ; 10010111 - col group 18, offset 7 38 | .db #0x8c ; 10001100 - col group 17, offset 4 39 | .db #0x81 ; 10000001 - col group 16, offset 1 40 | .db #0x86 ; 10000110 - col group 16, offset 6 41 | .db #0x7b ; 01111011 - col group 15, offset 3 42 | .db #0x70 ; 01110000 - col group 14, offset 0 43 | .db #0x75 ; 01110101 - col group 14, offset 5 44 | .db #0x6a ; 01101010 - col group 13, offset 2 45 | .db #0x6f ; 01101111 - col group 13, offset 7 46 | .db #0x64 ; 01100100 - col group 12, offset 4 47 | .db #0x59 ; 01011001 - col group 11, offset 1 48 | .db #0x5e ; 01011110 - col group 11, offset 6 49 | .db #0x53 ; 01010011 - col group 10, offset 3 50 | .db #0x48 ; 01001000 - col group 9, offset 0 51 | .db #0x4d ; 01001101 - col group 9, offset 5 52 | .db #0x42 ; 01000010 - col group 8, offset 2 53 | .db #0x47 ; 01000111 - col group 8, offset 7 54 | .db #0x3c ; 00111100 - col group 7, offset 4 55 | .db #0x31 ; 00110001 - col group 6, offset 1 56 | .db #0x36 ; 00110110 - col group 6, offset 6 57 | .db #0x2b ; 00101011 - col group 5, offset 3 58 | .db #0x20 ; 00100000 - col group 4, offset 0 59 | .db #0x25 ; 00100101 - col group 4, offset 5 60 | .db #0x1a ; 00011010 - col group 3, offset 2 61 | .db #0x1f ; 00011111 - col group 3, offset 7 62 | .db #0x14 ; 00010100 - col group 2, offset 4 63 | .db #0x09 ; 00001001 - col group 1, offset 1 64 | .db #0x0e ; 00001110 - col group 1, offset 6 65 | .db #0x03 ; 00000011 - col group 0, offset 3 66 | -------------------------------------------------------------------------------- /font/spleen-5x8.bdf: -------------------------------------------------------------------------------- 1 | STARTFONT 2.1 2 | COMMENT /* 3 | COMMENT * Spleen 5x8 1.0.3 4 | COMMENT * Copyright (c) 2018, Frederic Cambus 5 | COMMENT * https://www.cambus.net/ 6 | COMMENT * 7 | COMMENT * Created: 2018-08-08 8 | COMMENT * Last Updated: 2018-12-03 9 | COMMENT * 10 | COMMENT * Spleen is released under the BSD 2-Clause license. 11 | COMMENT * See LICENSE file for details. 12 | COMMENT */ 13 | FONT -misc-spleen-medium-r-normal--8-80-72-72-C-50-iso10646-1 14 | SIZE 8 72 72 15 | FONTBOUNDINGBOX 6 8 0 -1 16 | STARTPROPERTIES 18 17 | FAMILY_NAME "Spleen" 18 | FOUNDRY "misc" 19 | SLANT "R" 20 | SETWIDTH_NAME "Normal" 21 | PIXEL_SIZE 8 22 | POINT_SIZE 80 23 | RESOLUTION_X 72 24 | RESOLUTION_Y 72 25 | SPACING "C" 26 | AVERAGE_WIDTH 50 27 | CHARSET_REGISTRY "ISO10646" 28 | CHARSET_ENCODING "1" 29 | MIN_SPACE 5 30 | FONT_DESCENT 1 31 | FONT_ASCENT 7 32 | COPYRIGHT "Copyright (c) 2018, Frederic Cambus" 33 | DEFAULT_CHAR 32 34 | _GBDFED_INFO "Edited with gbdfed 1.6." 35 | ENDPROPERTIES 36 | CHARS 224 37 | STARTCHAR char0 38 | ENCODING 0 39 | SWIDTH 750 0 40 | DWIDTH 6 0 41 | BBX 6 8 0 -1 42 | BITMAP 43 | F8 44 | D8 45 | A8 46 | E8 47 | D8 48 | F8 49 | D8 50 | F8 51 | ENDCHAR 52 | STARTCHAR char1 53 | ENCODING 1 54 | SWIDTH 750 0 55 | DWIDTH 6 0 56 | BBX 6 8 0 -1 57 | BITMAP 58 | 70 59 | 88 60 | D8 61 | 88 62 | F8 63 | 88 64 | 70 65 | 00 66 | ENDCHAR 67 | STARTCHAR char2 68 | ENCODING 2 69 | SWIDTH 750 0 70 | DWIDTH 6 0 71 | BBX 6 8 0 -1 72 | BITMAP 73 | 70 74 | F8 75 | A8 76 | F8 77 | 88 78 | F8 79 | 70 80 | 00 81 | ENDCHAR 82 | STARTCHAR char3 83 | ENCODING 3 84 | SWIDTH 750 0 85 | DWIDTH 6 0 86 | BBX 6 8 0 -1 87 | BITMAP 88 | 00 89 | 50 90 | F8 91 | F8 92 | 70 93 | 20 94 | 00 95 | 00 96 | ENDCHAR 97 | STARTCHAR char4 98 | ENCODING 4 99 | SWIDTH 750 0 100 | DWIDTH 6 0 101 | BBX 6 8 0 -1 102 | BITMAP 103 | 00 104 | 20 105 | 70 106 | F8 107 | 70 108 | 20 109 | 00 110 | 00 111 | ENDCHAR 112 | STARTCHAR char5 113 | ENCODING 5 114 | SWIDTH 750 0 115 | DWIDTH 6 0 116 | BBX 6 8 0 -1 117 | BITMAP 118 | 00 119 | 20 120 | 70 121 | D8 122 | D8 123 | 20 124 | 70 125 | 00 126 | ENDCHAR 127 | STARTCHAR char6 128 | ENCODING 6 129 | SWIDTH 750 0 130 | DWIDTH 6 0 131 | BBX 6 8 0 -1 132 | BITMAP 133 | 00 134 | 20 135 | 70 136 | F8 137 | F8 138 | 20 139 | 70 140 | 00 141 | ENDCHAR 142 | STARTCHAR char7 143 | ENCODING 7 144 | SWIDTH 750 0 145 | DWIDTH 6 0 146 | BBX 6 8 0 -1 147 | BITMAP 148 | 00 149 | 00 150 | 20 151 | 70 152 | 70 153 | 20 154 | 00 155 | 00 156 | ENDCHAR 157 | STARTCHAR char8 158 | ENCODING 8 159 | SWIDTH 750 0 160 | DWIDTH 6 0 161 | BBX 6 8 0 -1 162 | BITMAP 163 | 70 164 | 70 165 | 50 166 | 00 167 | 50 168 | 70 169 | 70 170 | 70 171 | ENDCHAR 172 | STARTCHAR char9 173 | ENCODING 9 174 | SWIDTH 750 0 175 | DWIDTH 6 0 176 | BBX 6 8 0 -1 177 | BITMAP 178 | 00 179 | 00 180 | 20 181 | 50 182 | 50 183 | 20 184 | 00 185 | 00 186 | ENDCHAR 187 | STARTCHAR char10 188 | ENCODING 10 189 | SWIDTH 750 0 190 | DWIDTH 6 0 191 | BBX 6 8 0 -1 192 | BITMAP 193 | 70 194 | 70 195 | 50 196 | 20 197 | 20 198 | 50 199 | 70 200 | 70 201 | ENDCHAR 202 | STARTCHAR char11 203 | ENCODING 11 204 | SWIDTH 750 0 205 | DWIDTH 6 0 206 | BBX 6 8 0 -1 207 | BITMAP 208 | 00 209 | 30 210 | 70 211 | 90 212 | 90 213 | 60 214 | 00 215 | 00 216 | ENDCHAR 217 | STARTCHAR char12 218 | ENCODING 12 219 | SWIDTH 750 0 220 | DWIDTH 6 0 221 | BBX 6 8 0 -1 222 | BITMAP 223 | 00 224 | 20 225 | 50 226 | 50 227 | 20 228 | 70 229 | 20 230 | 00 231 | ENDCHAR 232 | STARTCHAR char13 233 | ENCODING 13 234 | SWIDTH 750 0 235 | DWIDTH 6 0 236 | BBX 6 8 0 -1 237 | BITMAP 238 | 00 239 | 38 240 | 38 241 | 20 242 | E0 243 | C0 244 | 00 245 | 00 246 | ENDCHAR 247 | STARTCHAR char14 248 | ENCODING 14 249 | SWIDTH 750 0 250 | DWIDTH 6 0 251 | BBX 6 8 0 -1 252 | BITMAP 253 | 00 254 | 38 255 | 38 256 | 28 257 | 28 258 | 50 259 | 00 260 | 00 261 | ENDCHAR 262 | STARTCHAR char15 263 | ENCODING 15 264 | SWIDTH 750 0 265 | DWIDTH 6 0 266 | BBX 6 8 0 -1 267 | BITMAP 268 | 00 269 | A8 270 | 70 271 | D8 272 | 70 273 | A8 274 | 00 275 | 00 276 | ENDCHAR 277 | STARTCHAR char16 278 | ENCODING 16 279 | SWIDTH 750 0 280 | DWIDTH 6 0 281 | BBX 6 8 0 -1 282 | BITMAP 283 | 00 284 | 40 285 | 60 286 | 70 287 | 70 288 | 60 289 | 40 290 | 00 291 | ENDCHAR 292 | STARTCHAR char17 293 | ENCODING 17 294 | SWIDTH 750 0 295 | DWIDTH 6 0 296 | BBX 6 8 0 -1 297 | BITMAP 298 | 00 299 | 10 300 | 30 301 | 70 302 | 70 303 | 30 304 | 10 305 | 00 306 | ENDCHAR 307 | STARTCHAR char18 308 | ENCODING 18 309 | SWIDTH 750 0 310 | DWIDTH 6 0 311 | BBX 6 8 0 -1 312 | BITMAP 313 | 00 314 | 20 315 | 70 316 | 20 317 | 70 318 | 20 319 | 00 320 | 00 321 | ENDCHAR 322 | STARTCHAR char19 323 | ENCODING 19 324 | SWIDTH 750 0 325 | DWIDTH 6 0 326 | BBX 6 8 0 -1 327 | BITMAP 328 | 00 329 | 50 330 | 50 331 | 50 332 | 50 333 | 00 334 | 50 335 | 00 336 | ENDCHAR 337 | STARTCHAR char20 338 | ENCODING 20 339 | SWIDTH 750 0 340 | DWIDTH 6 0 341 | BBX 6 8 0 -1 342 | BITMAP 343 | 00 344 | 70 345 | D0 346 | D0 347 | 50 348 | 50 349 | 00 350 | 00 351 | ENDCHAR 352 | STARTCHAR char21 353 | ENCODING 21 354 | SWIDTH 750 0 355 | DWIDTH 6 0 356 | BBX 6 8 0 -1 357 | BITMAP 358 | 60 359 | 90 360 | 60 361 | F0 362 | 70 363 | 90 364 | 60 365 | 00 366 | ENDCHAR 367 | STARTCHAR char22 368 | ENCODING 22 369 | SWIDTH 750 0 370 | DWIDTH 6 0 371 | BBX 6 8 0 -1 372 | BITMAP 373 | 00 374 | 00 375 | 00 376 | 00 377 | 00 378 | F8 379 | F8 380 | 00 381 | ENDCHAR 382 | STARTCHAR char23 383 | ENCODING 23 384 | SWIDTH 750 0 385 | DWIDTH 6 0 386 | BBX 6 8 0 -1 387 | BITMAP 388 | 20 389 | 70 390 | 20 391 | 20 392 | 70 393 | 20 394 | 70 395 | 00 396 | ENDCHAR 397 | STARTCHAR char24 398 | ENCODING 24 399 | SWIDTH 750 0 400 | DWIDTH 6 0 401 | BBX 6 8 0 -1 402 | BITMAP 403 | 20 404 | 70 405 | 20 406 | 20 407 | 20 408 | 20 409 | 00 410 | 00 411 | ENDCHAR 412 | STARTCHAR char25 413 | ENCODING 25 414 | SWIDTH 750 0 415 | DWIDTH 6 0 416 | BBX 6 8 0 -1 417 | BITMAP 418 | 20 419 | 20 420 | 20 421 | 20 422 | 70 423 | 20 424 | 00 425 | 00 426 | ENDCHAR 427 | STARTCHAR char26 428 | ENCODING 26 429 | SWIDTH 750 0 430 | DWIDTH 6 0 431 | BBX 6 8 0 -1 432 | BITMAP 433 | 00 434 | 00 435 | 20 436 | F0 437 | 20 438 | 00 439 | 00 440 | 00 441 | ENDCHAR 442 | STARTCHAR char27 443 | ENCODING 27 444 | SWIDTH 750 0 445 | DWIDTH 6 0 446 | BBX 6 8 0 -1 447 | BITMAP 448 | 00 449 | 00 450 | 40 451 | F0 452 | 40 453 | 00 454 | 00 455 | 00 456 | ENDCHAR 457 | STARTCHAR char28 458 | ENCODING 28 459 | SWIDTH 750 0 460 | DWIDTH 6 0 461 | BBX 6 8 0 -1 462 | BITMAP 463 | 00 464 | 00 465 | 80 466 | 80 467 | F8 468 | 00 469 | 00 470 | 00 471 | ENDCHAR 472 | STARTCHAR char29 473 | ENCODING 29 474 | SWIDTH 750 0 475 | DWIDTH 6 0 476 | BBX 6 8 0 -1 477 | BITMAP 478 | 00 479 | 00 480 | 50 481 | F8 482 | 50 483 | 00 484 | 00 485 | 00 486 | ENDCHAR 487 | STARTCHAR char30 488 | ENCODING 30 489 | SWIDTH 750 0 490 | DWIDTH 6 0 491 | BBX 6 8 0 -1 492 | BITMAP 493 | 00 494 | 00 495 | 20 496 | 70 497 | F8 498 | 00 499 | 00 500 | 00 501 | ENDCHAR 502 | STARTCHAR char31 503 | ENCODING 31 504 | SWIDTH 750 0 505 | DWIDTH 6 0 506 | BBX 6 8 0 -1 507 | BITMAP 508 | 00 509 | 00 510 | F8 511 | 70 512 | 20 513 | 00 514 | 00 515 | 00 516 | ENDCHAR 517 | STARTCHAR SPACE 518 | ENCODING 32 519 | SWIDTH 750 0 520 | DWIDTH 6 0 521 | BBX 6 8 0 -1 522 | BITMAP 523 | 00 524 | 00 525 | 00 526 | 00 527 | 00 528 | 00 529 | 00 530 | 00 531 | ENDCHAR 532 | STARTCHAR EXCLAMATION MARK 533 | ENCODING 33 534 | SWIDTH 750 0 535 | DWIDTH 6 0 536 | BBX 6 8 0 -1 537 | BITMAP 538 | 20 539 | 20 540 | 20 541 | 20 542 | 20 543 | 00 544 | 20 545 | 00 546 | ENDCHAR 547 | STARTCHAR QUOTATION MARK 548 | ENCODING 34 549 | SWIDTH 750 0 550 | DWIDTH 6 0 551 | BBX 6 8 0 -1 552 | BITMAP 553 | 50 554 | 50 555 | 50 556 | 00 557 | 00 558 | 00 559 | 00 560 | 00 561 | ENDCHAR 562 | STARTCHAR NUMBER SIGN 563 | ENCODING 35 564 | SWIDTH 750 0 565 | DWIDTH 6 0 566 | BBX 6 8 0 -1 567 | BITMAP 568 | 00 569 | 50 570 | F8 571 | 50 572 | 50 573 | F8 574 | 50 575 | 00 576 | ENDCHAR 577 | STARTCHAR DOLLAR SIGN 578 | ENCODING 36 579 | SWIDTH 750 0 580 | DWIDTH 6 0 581 | BBX 6 8 0 -1 582 | BITMAP 583 | 20 584 | 70 585 | A0 586 | 60 587 | 30 588 | 30 589 | E0 590 | 20 591 | ENDCHAR 592 | STARTCHAR PERCENT SIGN 593 | ENCODING 37 594 | SWIDTH 750 0 595 | DWIDTH 6 0 596 | BBX 6 8 0 -1 597 | BITMAP 598 | 10 599 | 90 600 | A0 601 | 20 602 | 40 603 | 50 604 | 90 605 | 80 606 | ENDCHAR 607 | STARTCHAR AMPERSAND 608 | ENCODING 38 609 | SWIDTH 750 0 610 | DWIDTH 6 0 611 | BBX 6 8 0 -1 612 | BITMAP 613 | 20 614 | 50 615 | 50 616 | 60 617 | A0 618 | 90 619 | 68 620 | 00 621 | ENDCHAR 622 | STARTCHAR APOSTROPHE 623 | ENCODING 39 624 | SWIDTH 750 0 625 | DWIDTH 6 0 626 | BBX 6 8 0 -1 627 | BITMAP 628 | 20 629 | 20 630 | 20 631 | 00 632 | 00 633 | 00 634 | 00 635 | 00 636 | ENDCHAR 637 | STARTCHAR LEFT PARENTHESIS 638 | ENCODING 40 639 | SWIDTH 750 0 640 | DWIDTH 6 0 641 | BBX 6 8 0 -1 642 | BITMAP 643 | 10 644 | 20 645 | 40 646 | 40 647 | 40 648 | 40 649 | 20 650 | 10 651 | ENDCHAR 652 | STARTCHAR RIGHT PARENTHESIS 653 | ENCODING 41 654 | SWIDTH 750 0 655 | DWIDTH 6 0 656 | BBX 6 8 0 -1 657 | BITMAP 658 | 40 659 | 20 660 | 10 661 | 10 662 | 10 663 | 10 664 | 20 665 | 40 666 | ENDCHAR 667 | STARTCHAR ASTERISK 668 | ENCODING 42 669 | SWIDTH 750 0 670 | DWIDTH 6 0 671 | BBX 6 8 0 -1 672 | BITMAP 673 | 00 674 | 00 675 | 90 676 | 60 677 | F0 678 | 60 679 | 90 680 | 00 681 | ENDCHAR 682 | STARTCHAR PLUS SIGN 683 | ENCODING 43 684 | SWIDTH 750 0 685 | DWIDTH 6 0 686 | BBX 6 8 0 -1 687 | BITMAP 688 | 00 689 | 00 690 | 20 691 | 20 692 | F8 693 | 20 694 | 20 695 | 00 696 | ENDCHAR 697 | STARTCHAR COMMA 698 | ENCODING 44 699 | SWIDTH 750 0 700 | DWIDTH 6 0 701 | BBX 6 8 0 -1 702 | BITMAP 703 | 00 704 | 00 705 | 00 706 | 00 707 | 00 708 | 20 709 | 20 710 | 40 711 | ENDCHAR 712 | STARTCHAR HYPHEN-MINUS 713 | ENCODING 45 714 | SWIDTH 750 0 715 | DWIDTH 6 0 716 | BBX 6 8 0 -1 717 | BITMAP 718 | 00 719 | 00 720 | 00 721 | 00 722 | F0 723 | 00 724 | 00 725 | 00 726 | ENDCHAR 727 | STARTCHAR FULL STOP 728 | ENCODING 46 729 | SWIDTH 750 0 730 | DWIDTH 6 0 731 | BBX 6 8 0 -1 732 | BITMAP 733 | 00 734 | 00 735 | 00 736 | 00 737 | 00 738 | 00 739 | 20 740 | 00 741 | ENDCHAR 742 | STARTCHAR SOLIDUS 743 | ENCODING 47 744 | SWIDTH 750 0 745 | DWIDTH 6 0 746 | BBX 6 8 0 -1 747 | BITMAP 748 | 10 749 | 10 750 | 20 751 | 20 752 | 40 753 | 40 754 | 80 755 | 80 756 | ENDCHAR 757 | STARTCHAR DIGIT ZERO 758 | ENCODING 48 759 | SWIDTH 750 0 760 | DWIDTH 6 0 761 | BBX 6 8 0 -1 762 | BITMAP 763 | 00 764 | 60 765 | 90 766 | B0 767 | D0 768 | 90 769 | 60 770 | 00 771 | ENDCHAR 772 | STARTCHAR DIGIT ONE 773 | ENCODING 49 774 | SWIDTH 750 0 775 | DWIDTH 6 0 776 | BBX 6 8 0 -1 777 | BITMAP 778 | 00 779 | 20 780 | 60 781 | 20 782 | 20 783 | 20 784 | 70 785 | 00 786 | ENDCHAR 787 | STARTCHAR DIGIT TWO 788 | ENCODING 50 789 | SWIDTH 750 0 790 | DWIDTH 6 0 791 | BBX 6 8 0 -1 792 | BITMAP 793 | 00 794 | 60 795 | 90 796 | 10 797 | 60 798 | 80 799 | F0 800 | 00 801 | ENDCHAR 802 | STARTCHAR DIGIT THREE 803 | ENCODING 51 804 | SWIDTH 750 0 805 | DWIDTH 6 0 806 | BBX 6 8 0 -1 807 | BITMAP 808 | 00 809 | 60 810 | 90 811 | 20 812 | 10 813 | 90 814 | 60 815 | 00 816 | ENDCHAR 817 | STARTCHAR DIGIT FOUR 818 | ENCODING 52 819 | SWIDTH 750 0 820 | DWIDTH 6 0 821 | BBX 6 8 0 -1 822 | BITMAP 823 | 00 824 | 80 825 | A0 826 | A0 827 | F0 828 | 20 829 | 20 830 | 00 831 | ENDCHAR 832 | STARTCHAR DIGIT FIVE 833 | ENCODING 53 834 | SWIDTH 750 0 835 | DWIDTH 6 0 836 | BBX 6 8 0 -1 837 | BITMAP 838 | 00 839 | F0 840 | 80 841 | F0 842 | 10 843 | 10 844 | E0 845 | 00 846 | ENDCHAR 847 | STARTCHAR DIGIT SIX 848 | ENCODING 54 849 | SWIDTH 750 0 850 | DWIDTH 6 0 851 | BBX 6 8 0 -1 852 | BITMAP 853 | 00 854 | 60 855 | 80 856 | E0 857 | 90 858 | 90 859 | 60 860 | 00 861 | ENDCHAR 862 | STARTCHAR DIGIT SEVEN 863 | ENCODING 55 864 | SWIDTH 750 0 865 | DWIDTH 6 0 866 | BBX 6 8 0 -1 867 | BITMAP 868 | 00 869 | F0 870 | 90 871 | 20 872 | 20 873 | 40 874 | 40 875 | 00 876 | ENDCHAR 877 | STARTCHAR DIGIT EIGHT 878 | ENCODING 56 879 | SWIDTH 750 0 880 | DWIDTH 6 0 881 | BBX 6 8 0 -1 882 | BITMAP 883 | 00 884 | 60 885 | 90 886 | 60 887 | 90 888 | 90 889 | 60 890 | 00 891 | ENDCHAR 892 | STARTCHAR DIGIT NINE 893 | ENCODING 57 894 | SWIDTH 750 0 895 | DWIDTH 6 0 896 | BBX 6 8 0 -1 897 | BITMAP 898 | 00 899 | 60 900 | 90 901 | 90 902 | 70 903 | 10 904 | 60 905 | 00 906 | ENDCHAR 907 | STARTCHAR COLON 908 | ENCODING 58 909 | SWIDTH 750 0 910 | DWIDTH 6 0 911 | BBX 6 8 0 -1 912 | BITMAP 913 | 00 914 | 00 915 | 00 916 | 20 917 | 00 918 | 00 919 | 20 920 | 00 921 | ENDCHAR 922 | STARTCHAR SEMICOLON 923 | ENCODING 59 924 | SWIDTH 750 0 925 | DWIDTH 6 0 926 | BBX 6 8 0 -1 927 | BITMAP 928 | 00 929 | 00 930 | 00 931 | 20 932 | 00 933 | 20 934 | 20 935 | 40 936 | ENDCHAR 937 | STARTCHAR LESS-THAN SIGN 938 | ENCODING 60 939 | SWIDTH 750 0 940 | DWIDTH 6 0 941 | BBX 6 8 0 -1 942 | BITMAP 943 | 00 944 | 10 945 | 20 946 | 40 947 | 40 948 | 20 949 | 10 950 | 00 951 | ENDCHAR 952 | STARTCHAR EQUALS SIGN 953 | ENCODING 61 954 | SWIDTH 750 0 955 | DWIDTH 6 0 956 | BBX 6 8 0 -1 957 | BITMAP 958 | 00 959 | 00 960 | 00 961 | F0 962 | 00 963 | F0 964 | 00 965 | 00 966 | ENDCHAR 967 | STARTCHAR GREATER-THAN SIGN 968 | ENCODING 62 969 | SWIDTH 750 0 970 | DWIDTH 6 0 971 | BBX 6 8 0 -1 972 | BITMAP 973 | 00 974 | 40 975 | 20 976 | 10 977 | 10 978 | 20 979 | 40 980 | 00 981 | ENDCHAR 982 | STARTCHAR QUESTION MARK 983 | ENCODING 63 984 | SWIDTH 750 0 985 | DWIDTH 6 0 986 | BBX 6 8 0 -1 987 | BITMAP 988 | 60 989 | 90 990 | 10 991 | 20 992 | 40 993 | 00 994 | 40 995 | 00 996 | ENDCHAR 997 | STARTCHAR COMMERCIAL AT 998 | ENCODING 64 999 | SWIDTH 750 0 1000 | DWIDTH 6 0 1001 | BBX 6 8 0 -1 1002 | BITMAP 1003 | 00 1004 | 60 1005 | 90 1006 | B0 1007 | B0 1008 | 80 1009 | 70 1010 | 00 1011 | ENDCHAR 1012 | STARTCHAR LATIN CAPITAL LETTER A 1013 | ENCODING 65 1014 | SWIDTH 750 0 1015 | DWIDTH 6 0 1016 | BBX 6 8 0 -1 1017 | BITMAP 1018 | 00 1019 | 60 1020 | 90 1021 | 90 1022 | F0 1023 | 90 1024 | 90 1025 | 00 1026 | ENDCHAR 1027 | STARTCHAR LATIN CAPITAL LETTER B 1028 | ENCODING 66 1029 | SWIDTH 750 0 1030 | DWIDTH 6 0 1031 | BBX 6 8 0 -1 1032 | BITMAP 1033 | 00 1034 | E0 1035 | 90 1036 | E0 1037 | 90 1038 | 90 1039 | E0 1040 | 00 1041 | ENDCHAR 1042 | STARTCHAR LATIN CAPITAL LETTER C 1043 | ENCODING 67 1044 | SWIDTH 750 0 1045 | DWIDTH 6 0 1046 | BBX 6 8 0 -1 1047 | BITMAP 1048 | 00 1049 | 70 1050 | 80 1051 | 80 1052 | 80 1053 | 80 1054 | 70 1055 | 00 1056 | ENDCHAR 1057 | STARTCHAR LATIN CAPITAL LETTER D 1058 | ENCODING 68 1059 | SWIDTH 750 0 1060 | DWIDTH 6 0 1061 | BBX 6 8 0 -1 1062 | BITMAP 1063 | 00 1064 | E0 1065 | 90 1066 | 90 1067 | 90 1068 | 90 1069 | E0 1070 | 00 1071 | ENDCHAR 1072 | STARTCHAR LATIN CAPITAL LETTER E 1073 | ENCODING 69 1074 | SWIDTH 750 0 1075 | DWIDTH 6 0 1076 | BBX 6 8 0 -1 1077 | BITMAP 1078 | 00 1079 | 70 1080 | 80 1081 | E0 1082 | 80 1083 | 80 1084 | 70 1085 | 00 1086 | ENDCHAR 1087 | STARTCHAR LATIN CAPITAL LETTER F 1088 | ENCODING 70 1089 | SWIDTH 750 0 1090 | DWIDTH 6 0 1091 | BBX 6 8 0 -1 1092 | BITMAP 1093 | 00 1094 | 70 1095 | 80 1096 | 80 1097 | E0 1098 | 80 1099 | 80 1100 | 00 1101 | ENDCHAR 1102 | STARTCHAR LATIN CAPITAL LETTER G 1103 | ENCODING 71 1104 | SWIDTH 750 0 1105 | DWIDTH 6 0 1106 | BBX 6 8 0 -1 1107 | BITMAP 1108 | 00 1109 | 70 1110 | 80 1111 | B0 1112 | 90 1113 | 90 1114 | 70 1115 | 00 1116 | ENDCHAR 1117 | STARTCHAR LATIN CAPITAL LETTER H 1118 | ENCODING 72 1119 | SWIDTH 750 0 1120 | DWIDTH 6 0 1121 | BBX 6 8 0 -1 1122 | BITMAP 1123 | 00 1124 | 90 1125 | 90 1126 | F0 1127 | 90 1128 | 90 1129 | 90 1130 | 00 1131 | ENDCHAR 1132 | STARTCHAR LATIN CAPITAL LETTER I 1133 | ENCODING 73 1134 | SWIDTH 750 0 1135 | DWIDTH 6 0 1136 | BBX 6 8 0 -1 1137 | BITMAP 1138 | 00 1139 | 70 1140 | 20 1141 | 20 1142 | 20 1143 | 20 1144 | 70 1145 | 00 1146 | ENDCHAR 1147 | STARTCHAR LATIN CAPITAL LETTER J 1148 | ENCODING 74 1149 | SWIDTH 750 0 1150 | DWIDTH 6 0 1151 | BBX 6 8 0 -1 1152 | BITMAP 1153 | 00 1154 | 70 1155 | 20 1156 | 20 1157 | 20 1158 | 20 1159 | C0 1160 | 00 1161 | ENDCHAR 1162 | STARTCHAR LATIN CAPITAL LETTER K 1163 | ENCODING 75 1164 | SWIDTH 750 0 1165 | DWIDTH 6 0 1166 | BBX 6 8 0 -1 1167 | BITMAP 1168 | 00 1169 | 90 1170 | 90 1171 | E0 1172 | 90 1173 | 90 1174 | 90 1175 | 00 1176 | ENDCHAR 1177 | STARTCHAR LATIN CAPITAL LETTER L 1178 | ENCODING 76 1179 | SWIDTH 750 0 1180 | DWIDTH 6 0 1181 | BBX 6 8 0 -1 1182 | BITMAP 1183 | 00 1184 | 80 1185 | 80 1186 | 80 1187 | 80 1188 | 80 1189 | 70 1190 | 00 1191 | ENDCHAR 1192 | STARTCHAR LATIN CAPITAL LETTER M 1193 | ENCODING 77 1194 | SWIDTH 750 0 1195 | DWIDTH 6 0 1196 | BBX 6 8 0 -1 1197 | BITMAP 1198 | 00 1199 | 90 1200 | F0 1201 | F0 1202 | 90 1203 | 90 1204 | 90 1205 | 00 1206 | ENDCHAR 1207 | STARTCHAR LATIN CAPITAL LETTER N 1208 | ENCODING 78 1209 | SWIDTH 750 0 1210 | DWIDTH 6 0 1211 | BBX 6 8 0 -1 1212 | BITMAP 1213 | 00 1214 | 90 1215 | D0 1216 | D0 1217 | B0 1218 | B0 1219 | 90 1220 | 00 1221 | ENDCHAR 1222 | STARTCHAR LATIN CAPITAL LETTER O 1223 | ENCODING 79 1224 | SWIDTH 750 0 1225 | DWIDTH 6 0 1226 | BBX 6 8 0 -1 1227 | BITMAP 1228 | 00 1229 | 60 1230 | 90 1231 | 90 1232 | 90 1233 | 90 1234 | 60 1235 | 00 1236 | ENDCHAR 1237 | STARTCHAR LATIN CAPITAL LETTER P 1238 | ENCODING 80 1239 | SWIDTH 750 0 1240 | DWIDTH 6 0 1241 | BBX 6 8 0 -1 1242 | BITMAP 1243 | 00 1244 | E0 1245 | 90 1246 | 90 1247 | E0 1248 | 80 1249 | 80 1250 | 00 1251 | ENDCHAR 1252 | STARTCHAR LATIN CAPITAL LETTER Q 1253 | ENCODING 81 1254 | SWIDTH 750 0 1255 | DWIDTH 6 0 1256 | BBX 6 8 0 -1 1257 | BITMAP 1258 | 00 1259 | 60 1260 | 90 1261 | 90 1262 | 90 1263 | 90 1264 | 60 1265 | 30 1266 | ENDCHAR 1267 | STARTCHAR LATIN CAPITAL LETTER R 1268 | ENCODING 82 1269 | SWIDTH 750 0 1270 | DWIDTH 6 0 1271 | BBX 6 8 0 -1 1272 | BITMAP 1273 | 00 1274 | E0 1275 | 90 1276 | 90 1277 | E0 1278 | 90 1279 | 90 1280 | 00 1281 | ENDCHAR 1282 | STARTCHAR LATIN CAPITAL LETTER S 1283 | ENCODING 83 1284 | SWIDTH 750 0 1285 | DWIDTH 6 0 1286 | BBX 6 8 0 -1 1287 | BITMAP 1288 | 00 1289 | 70 1290 | 80 1291 | 60 1292 | 10 1293 | 10 1294 | E0 1295 | 00 1296 | ENDCHAR 1297 | STARTCHAR LATIN CAPITAL LETTER T 1298 | ENCODING 84 1299 | SWIDTH 750 0 1300 | DWIDTH 6 0 1301 | BBX 6 8 0 -1 1302 | BITMAP 1303 | 00 1304 | F8 1305 | 20 1306 | 20 1307 | 20 1308 | 20 1309 | 20 1310 | 00 1311 | ENDCHAR 1312 | STARTCHAR LATIN CAPITAL LETTER U 1313 | ENCODING 85 1314 | SWIDTH 750 0 1315 | DWIDTH 6 0 1316 | BBX 6 8 0 -1 1317 | BITMAP 1318 | 00 1319 | 90 1320 | 90 1321 | 90 1322 | 90 1323 | 90 1324 | 70 1325 | 00 1326 | ENDCHAR 1327 | STARTCHAR LATIN CAPITAL LETTER V 1328 | ENCODING 86 1329 | SWIDTH 750 0 1330 | DWIDTH 6 0 1331 | BBX 6 8 0 -1 1332 | BITMAP 1333 | 00 1334 | 90 1335 | 90 1336 | 90 1337 | 90 1338 | 60 1339 | 60 1340 | 00 1341 | ENDCHAR 1342 | STARTCHAR LATIN CAPITAL LETTER W 1343 | ENCODING 87 1344 | SWIDTH 750 0 1345 | DWIDTH 6 0 1346 | BBX 6 8 0 -1 1347 | BITMAP 1348 | 00 1349 | 90 1350 | 90 1351 | 90 1352 | F0 1353 | F0 1354 | 90 1355 | 00 1356 | ENDCHAR 1357 | STARTCHAR LATIN CAPITAL LETTER X 1358 | ENCODING 88 1359 | SWIDTH 750 0 1360 | DWIDTH 6 0 1361 | BBX 6 8 0 -1 1362 | BITMAP 1363 | 00 1364 | 90 1365 | 90 1366 | 60 1367 | 60 1368 | 90 1369 | 90 1370 | 00 1371 | ENDCHAR 1372 | STARTCHAR LATIN CAPITAL LETTER Y 1373 | ENCODING 89 1374 | SWIDTH 750 0 1375 | DWIDTH 6 0 1376 | BBX 6 8 0 -1 1377 | BITMAP 1378 | 00 1379 | 90 1380 | 90 1381 | 90 1382 | 70 1383 | 10 1384 | E0 1385 | 00 1386 | ENDCHAR 1387 | STARTCHAR LATIN CAPITAL LETTER Z 1388 | ENCODING 90 1389 | SWIDTH 750 0 1390 | DWIDTH 6 0 1391 | BBX 6 8 0 -1 1392 | BITMAP 1393 | 00 1394 | F0 1395 | 10 1396 | 20 1397 | 40 1398 | 80 1399 | F0 1400 | 00 1401 | ENDCHAR 1402 | STARTCHAR LEFT SQUARE BRACKET 1403 | ENCODING 91 1404 | SWIDTH 750 0 1405 | DWIDTH 6 0 1406 | BBX 6 8 0 -1 1407 | BITMAP 1408 | 70 1409 | 40 1410 | 40 1411 | 40 1412 | 40 1413 | 40 1414 | 40 1415 | 70 1416 | ENDCHAR 1417 | STARTCHAR REVERSE SOLIDUS 1418 | ENCODING 92 1419 | SWIDTH 750 0 1420 | DWIDTH 6 0 1421 | BBX 6 8 0 -1 1422 | BITMAP 1423 | 80 1424 | 80 1425 | 40 1426 | 40 1427 | 20 1428 | 20 1429 | 10 1430 | 10 1431 | ENDCHAR 1432 | STARTCHAR RIGHT SQUARE BRACKET 1433 | ENCODING 93 1434 | SWIDTH 750 0 1435 | DWIDTH 6 0 1436 | BBX 6 8 0 -1 1437 | BITMAP 1438 | 70 1439 | 10 1440 | 10 1441 | 10 1442 | 10 1443 | 10 1444 | 10 1445 | 70 1446 | ENDCHAR 1447 | STARTCHAR CIRCUMFLEX ACCENT 1448 | ENCODING 94 1449 | SWIDTH 750 0 1450 | DWIDTH 6 0 1451 | BBX 6 8 0 -1 1452 | BITMAP 1453 | 00 1454 | 20 1455 | 50 1456 | 88 1457 | 00 1458 | 00 1459 | 00 1460 | 00 1461 | ENDCHAR 1462 | STARTCHAR LOW LINE 1463 | ENCODING 95 1464 | SWIDTH 750 0 1465 | DWIDTH 6 0 1466 | BBX 6 8 0 -1 1467 | BITMAP 1468 | 00 1469 | 00 1470 | 00 1471 | 00 1472 | 00 1473 | 00 1474 | 00 1475 | F0 1476 | ENDCHAR 1477 | STARTCHAR GRAVE ACCENT 1478 | ENCODING 96 1479 | SWIDTH 750 0 1480 | DWIDTH 6 0 1481 | BBX 6 8 0 -1 1482 | BITMAP 1483 | 40 1484 | 20 1485 | 00 1486 | 00 1487 | 00 1488 | 00 1489 | 00 1490 | 00 1491 | ENDCHAR 1492 | STARTCHAR LATIN SMALL LETTER A 1493 | ENCODING 97 1494 | SWIDTH 750 0 1495 | DWIDTH 6 0 1496 | BBX 6 8 0 -1 1497 | BITMAP 1498 | 00 1499 | 00 1500 | 60 1501 | 10 1502 | 70 1503 | 90 1504 | 70 1505 | 00 1506 | ENDCHAR 1507 | STARTCHAR LATIN SMALL LETTER B 1508 | ENCODING 98 1509 | SWIDTH 750 0 1510 | DWIDTH 6 0 1511 | BBX 6 8 0 -1 1512 | BITMAP 1513 | 80 1514 | 80 1515 | E0 1516 | 90 1517 | 90 1518 | 90 1519 | E0 1520 | 00 1521 | ENDCHAR 1522 | STARTCHAR LATIN SMALL LETTER C 1523 | ENCODING 99 1524 | SWIDTH 750 0 1525 | DWIDTH 6 0 1526 | BBX 6 8 0 -1 1527 | BITMAP 1528 | 00 1529 | 00 1530 | 70 1531 | 80 1532 | 80 1533 | 80 1534 | 70 1535 | 00 1536 | ENDCHAR 1537 | STARTCHAR LATIN SMALL LETTER D 1538 | ENCODING 100 1539 | SWIDTH 750 0 1540 | DWIDTH 6 0 1541 | BBX 6 8 0 -1 1542 | BITMAP 1543 | 10 1544 | 10 1545 | 70 1546 | 90 1547 | 90 1548 | 90 1549 | 70 1550 | 00 1551 | ENDCHAR 1552 | STARTCHAR LATIN SMALL LETTER E 1553 | ENCODING 101 1554 | SWIDTH 750 0 1555 | DWIDTH 6 0 1556 | BBX 6 8 0 -1 1557 | BITMAP 1558 | 00 1559 | 00 1560 | 70 1561 | 90 1562 | F0 1563 | 80 1564 | 70 1565 | 00 1566 | ENDCHAR 1567 | STARTCHAR LATIN SMALL LETTER F 1568 | ENCODING 102 1569 | SWIDTH 750 0 1570 | DWIDTH 6 0 1571 | BBX 6 8 0 -1 1572 | BITMAP 1573 | 30 1574 | 40 1575 | 40 1576 | E0 1577 | 40 1578 | 40 1579 | 40 1580 | 00 1581 | ENDCHAR 1582 | STARTCHAR LATIN SMALL LETTER G 1583 | ENCODING 103 1584 | SWIDTH 750 0 1585 | DWIDTH 6 0 1586 | BBX 6 8 0 -1 1587 | BITMAP 1588 | 00 1589 | 00 1590 | 70 1591 | 90 1592 | 90 1593 | 60 1594 | 10 1595 | E0 1596 | ENDCHAR 1597 | STARTCHAR LATIN SMALL LETTER H 1598 | ENCODING 104 1599 | SWIDTH 750 0 1600 | DWIDTH 6 0 1601 | BBX 6 8 0 -1 1602 | BITMAP 1603 | 80 1604 | 80 1605 | E0 1606 | 90 1607 | 90 1608 | 90 1609 | 90 1610 | 00 1611 | ENDCHAR 1612 | STARTCHAR LATIN SMALL LETTER I 1613 | ENCODING 105 1614 | SWIDTH 750 0 1615 | DWIDTH 6 0 1616 | BBX 6 8 0 -1 1617 | BITMAP 1618 | 00 1619 | 20 1620 | 00 1621 | 20 1622 | 20 1623 | 20 1624 | 20 1625 | 00 1626 | ENDCHAR 1627 | STARTCHAR LATIN SMALL LETTER J 1628 | ENCODING 106 1629 | SWIDTH 750 0 1630 | DWIDTH 6 0 1631 | BBX 6 8 0 -1 1632 | BITMAP 1633 | 00 1634 | 20 1635 | 00 1636 | 20 1637 | 20 1638 | 20 1639 | 20 1640 | C0 1641 | ENDCHAR 1642 | STARTCHAR LATIN SMALL LETTER K 1643 | ENCODING 107 1644 | SWIDTH 750 0 1645 | DWIDTH 6 0 1646 | BBX 6 8 0 -1 1647 | BITMAP 1648 | 80 1649 | 80 1650 | 90 1651 | A0 1652 | C0 1653 | A0 1654 | 90 1655 | 00 1656 | ENDCHAR 1657 | STARTCHAR LATIN SMALL LETTER L 1658 | ENCODING 108 1659 | SWIDTH 750 0 1660 | DWIDTH 6 0 1661 | BBX 6 8 0 -1 1662 | BITMAP 1663 | 40 1664 | 40 1665 | 40 1666 | 40 1667 | 40 1668 | 40 1669 | 30 1670 | 00 1671 | ENDCHAR 1672 | STARTCHAR LATIN SMALL LETTER M 1673 | ENCODING 109 1674 | SWIDTH 750 0 1675 | DWIDTH 6 0 1676 | BBX 6 8 0 -1 1677 | BITMAP 1678 | 00 1679 | 00 1680 | 90 1681 | F0 1682 | F0 1683 | 90 1684 | 90 1685 | 00 1686 | ENDCHAR 1687 | STARTCHAR LATIN SMALL LETTER N 1688 | ENCODING 110 1689 | SWIDTH 750 0 1690 | DWIDTH 6 0 1691 | BBX 6 8 0 -1 1692 | BITMAP 1693 | 00 1694 | 00 1695 | E0 1696 | 90 1697 | 90 1698 | 90 1699 | 90 1700 | 00 1701 | ENDCHAR 1702 | STARTCHAR LATIN SMALL LETTER O 1703 | ENCODING 111 1704 | SWIDTH 750 0 1705 | DWIDTH 6 0 1706 | BBX 6 8 0 -1 1707 | BITMAP 1708 | 00 1709 | 00 1710 | 60 1711 | 90 1712 | 90 1713 | 90 1714 | 60 1715 | 00 1716 | ENDCHAR 1717 | STARTCHAR LATIN SMALL LETTER P 1718 | ENCODING 112 1719 | SWIDTH 750 0 1720 | DWIDTH 6 0 1721 | BBX 6 8 0 -1 1722 | BITMAP 1723 | 00 1724 | 00 1725 | E0 1726 | 90 1727 | 90 1728 | E0 1729 | 80 1730 | 80 1731 | ENDCHAR 1732 | STARTCHAR LATIN SMALL LETTER Q 1733 | ENCODING 113 1734 | SWIDTH 750 0 1735 | DWIDTH 6 0 1736 | BBX 6 8 0 -1 1737 | BITMAP 1738 | 00 1739 | 00 1740 | 70 1741 | 90 1742 | 90 1743 | 70 1744 | 10 1745 | 10 1746 | ENDCHAR 1747 | STARTCHAR LATIN SMALL LETTER R 1748 | ENCODING 114 1749 | SWIDTH 750 0 1750 | DWIDTH 6 0 1751 | BBX 6 8 0 -1 1752 | BITMAP 1753 | 00 1754 | 00 1755 | 70 1756 | 90 1757 | 80 1758 | 80 1759 | 80 1760 | 00 1761 | ENDCHAR 1762 | STARTCHAR LATIN SMALL LETTER S 1763 | ENCODING 115 1764 | SWIDTH 750 0 1765 | DWIDTH 6 0 1766 | BBX 6 8 0 -1 1767 | BITMAP 1768 | 00 1769 | 00 1770 | 70 1771 | 80 1772 | 60 1773 | 10 1774 | E0 1775 | 00 1776 | ENDCHAR 1777 | STARTCHAR LATIN SMALL LETTER T 1778 | ENCODING 116 1779 | SWIDTH 750 0 1780 | DWIDTH 6 0 1781 | BBX 6 8 0 -1 1782 | BITMAP 1783 | 40 1784 | 40 1785 | E0 1786 | 40 1787 | 40 1788 | 40 1789 | 30 1790 | 00 1791 | ENDCHAR 1792 | STARTCHAR LATIN SMALL LETTER U 1793 | ENCODING 117 1794 | SWIDTH 750 0 1795 | DWIDTH 6 0 1796 | BBX 6 8 0 -1 1797 | BITMAP 1798 | 00 1799 | 00 1800 | 90 1801 | 90 1802 | 90 1803 | 90 1804 | 70 1805 | 00 1806 | ENDCHAR 1807 | STARTCHAR LATIN SMALL LETTER V 1808 | ENCODING 118 1809 | SWIDTH 750 0 1810 | DWIDTH 6 0 1811 | BBX 6 8 0 -1 1812 | BITMAP 1813 | 00 1814 | 00 1815 | 90 1816 | 90 1817 | 90 1818 | 60 1819 | 60 1820 | 00 1821 | ENDCHAR 1822 | STARTCHAR LATIN SMALL LETTER W 1823 | ENCODING 119 1824 | SWIDTH 750 0 1825 | DWIDTH 6 0 1826 | BBX 6 8 0 -1 1827 | BITMAP 1828 | 00 1829 | 00 1830 | 90 1831 | 90 1832 | F0 1833 | F0 1834 | 90 1835 | 00 1836 | ENDCHAR 1837 | STARTCHAR LATIN SMALL LETTER X 1838 | ENCODING 120 1839 | SWIDTH 750 0 1840 | DWIDTH 6 0 1841 | BBX 6 8 0 -1 1842 | BITMAP 1843 | 00 1844 | 00 1845 | 90 1846 | 60 1847 | 60 1848 | 90 1849 | 90 1850 | 00 1851 | ENDCHAR 1852 | STARTCHAR LATIN SMALL LETTER Y 1853 | ENCODING 121 1854 | SWIDTH 750 0 1855 | DWIDTH 6 0 1856 | BBX 6 8 0 -1 1857 | BITMAP 1858 | 00 1859 | 00 1860 | 90 1861 | 90 1862 | 90 1863 | 70 1864 | 10 1865 | E0 1866 | ENDCHAR 1867 | STARTCHAR LATIN SMALL LETTER Z 1868 | ENCODING 122 1869 | SWIDTH 750 0 1870 | DWIDTH 6 0 1871 | BBX 6 8 0 -1 1872 | BITMAP 1873 | 00 1874 | 00 1875 | F0 1876 | 10 1877 | 20 1878 | 40 1879 | F0 1880 | 00 1881 | ENDCHAR 1882 | STARTCHAR LEFT CURLY BRACKET 1883 | ENCODING 123 1884 | SWIDTH 750 0 1885 | DWIDTH 6 0 1886 | BBX 6 8 0 -1 1887 | BITMAP 1888 | 30 1889 | 40 1890 | 40 1891 | C0 1892 | C0 1893 | 40 1894 | 40 1895 | 30 1896 | ENDCHAR 1897 | STARTCHAR VERTICAL LINE 1898 | ENCODING 124 1899 | SWIDTH 750 0 1900 | DWIDTH 6 0 1901 | BBX 6 8 0 -1 1902 | BITMAP 1903 | 00 1904 | 20 1905 | 20 1906 | 20 1907 | 20 1908 | 20 1909 | 20 1910 | 00 1911 | ENDCHAR 1912 | STARTCHAR RIGHT CURLY BRACKET 1913 | ENCODING 125 1914 | SWIDTH 750 0 1915 | DWIDTH 6 0 1916 | BBX 6 8 0 -1 1917 | BITMAP 1918 | C0 1919 | 20 1920 | 20 1921 | 30 1922 | 30 1923 | 20 1924 | 20 1925 | C0 1926 | ENDCHAR 1927 | STARTCHAR TILDE 1928 | ENCODING 126 1929 | SWIDTH 750 0 1930 | DWIDTH 6 0 1931 | BBX 6 8 0 -1 1932 | BITMAP 1933 | 00 1934 | 48 1935 | B0 1936 | 00 1937 | 00 1938 | 00 1939 | 00 1940 | 00 1941 | ENDCHAR 1942 | STARTCHAR 1943 | ENCODING 127 1944 | SWIDTH 750 0 1945 | DWIDTH 6 0 1946 | BBX 6 8 0 -1 1947 | BITMAP 1948 | 00 1949 | 00 1950 | 00 1951 | 00 1952 | 00 1953 | 00 1954 | 00 1955 | 00 1956 | ENDCHAR 1957 | STARTCHAR NO-BREAK SPACE 1958 | ENCODING 160 1959 | SWIDTH 750 0 1960 | DWIDTH 6 0 1961 | BBX 6 8 0 -1 1962 | BITMAP 1963 | 00 1964 | 00 1965 | 00 1966 | 00 1967 | 00 1968 | 00 1969 | 00 1970 | 00 1971 | ENDCHAR 1972 | STARTCHAR INVERTED EXCLAMATION MARK 1973 | ENCODING 161 1974 | SWIDTH 750 0 1975 | DWIDTH 6 0 1976 | BBX 6 8 0 -1 1977 | BITMAP 1978 | 00 1979 | 00 1980 | 00 1981 | 00 1982 | 00 1983 | 00 1984 | 00 1985 | 00 1986 | ENDCHAR 1987 | STARTCHAR CENT SIGN 1988 | ENCODING 162 1989 | SWIDTH 750 0 1990 | DWIDTH 6 0 1991 | BBX 6 8 0 -1 1992 | BITMAP 1993 | 00 1994 | 00 1995 | 00 1996 | 00 1997 | 00 1998 | 00 1999 | 00 2000 | 00 2001 | ENDCHAR 2002 | STARTCHAR POUND SIGN 2003 | ENCODING 163 2004 | SWIDTH 750 0 2005 | DWIDTH 6 0 2006 | BBX 6 8 0 -1 2007 | BITMAP 2008 | 00 2009 | 00 2010 | 00 2011 | 00 2012 | 00 2013 | 00 2014 | 00 2015 | 00 2016 | ENDCHAR 2017 | STARTCHAR CURRENCY SIGN 2018 | ENCODING 164 2019 | SWIDTH 750 0 2020 | DWIDTH 6 0 2021 | BBX 6 8 0 -1 2022 | BITMAP 2023 | 00 2024 | 00 2025 | 00 2026 | 00 2027 | 00 2028 | 00 2029 | 00 2030 | 00 2031 | ENDCHAR 2032 | STARTCHAR YEN SIGN 2033 | ENCODING 165 2034 | SWIDTH 750 0 2035 | DWIDTH 6 0 2036 | BBX 6 8 0 -1 2037 | BITMAP 2038 | 00 2039 | 00 2040 | 00 2041 | 00 2042 | 00 2043 | 00 2044 | 00 2045 | 00 2046 | ENDCHAR 2047 | STARTCHAR BROKEN BAR 2048 | ENCODING 166 2049 | SWIDTH 750 0 2050 | DWIDTH 6 0 2051 | BBX 6 8 0 -1 2052 | BITMAP 2053 | 00 2054 | 00 2055 | 00 2056 | 00 2057 | 00 2058 | 00 2059 | 00 2060 | 00 2061 | ENDCHAR 2062 | STARTCHAR SECTION SIGN 2063 | ENCODING 167 2064 | SWIDTH 750 0 2065 | DWIDTH 6 0 2066 | BBX 6 8 0 -1 2067 | BITMAP 2068 | 00 2069 | 00 2070 | 00 2071 | 00 2072 | 00 2073 | 00 2074 | 00 2075 | 00 2076 | ENDCHAR 2077 | STARTCHAR DIAERESIS 2078 | ENCODING 168 2079 | SWIDTH 750 0 2080 | DWIDTH 6 0 2081 | BBX 6 8 0 -1 2082 | BITMAP 2083 | 00 2084 | 00 2085 | 00 2086 | 00 2087 | 00 2088 | 00 2089 | 00 2090 | 00 2091 | ENDCHAR 2092 | STARTCHAR COPYRIGHT SIGN 2093 | ENCODING 169 2094 | SWIDTH 750 0 2095 | DWIDTH 6 0 2096 | BBX 6 8 0 -1 2097 | BITMAP 2098 | 00 2099 | 00 2100 | 00 2101 | 00 2102 | 00 2103 | 00 2104 | 00 2105 | 00 2106 | ENDCHAR 2107 | STARTCHAR FEMININE ORDINAL INDICATOR 2108 | ENCODING 170 2109 | SWIDTH 750 0 2110 | DWIDTH 6 0 2111 | BBX 6 8 0 -1 2112 | BITMAP 2113 | 00 2114 | 00 2115 | 00 2116 | 00 2117 | 00 2118 | 00 2119 | 00 2120 | 00 2121 | ENDCHAR 2122 | STARTCHAR LEFT-POINTING DOUBLE ANGLE QUOTATION MARK 2123 | ENCODING 171 2124 | SWIDTH 750 0 2125 | DWIDTH 6 0 2126 | BBX 6 8 0 -1 2127 | BITMAP 2128 | 00 2129 | 00 2130 | 00 2131 | 00 2132 | 00 2133 | 00 2134 | 00 2135 | 00 2136 | ENDCHAR 2137 | STARTCHAR NOT SIGN 2138 | ENCODING 172 2139 | SWIDTH 750 0 2140 | DWIDTH 6 0 2141 | BBX 6 8 0 -1 2142 | BITMAP 2143 | 00 2144 | 00 2145 | 00 2146 | 00 2147 | 00 2148 | 00 2149 | 00 2150 | 00 2151 | ENDCHAR 2152 | STARTCHAR SOFT HYPHEN 2153 | ENCODING 173 2154 | SWIDTH 750 0 2155 | DWIDTH 6 0 2156 | BBX 6 8 0 -1 2157 | BITMAP 2158 | 00 2159 | 00 2160 | 00 2161 | 00 2162 | 00 2163 | 00 2164 | 00 2165 | 00 2166 | ENDCHAR 2167 | STARTCHAR REGISTERED SIGN 2168 | ENCODING 174 2169 | SWIDTH 750 0 2170 | DWIDTH 6 0 2171 | BBX 6 8 0 -1 2172 | BITMAP 2173 | 00 2174 | 00 2175 | 00 2176 | 00 2177 | 00 2178 | 00 2179 | 00 2180 | 00 2181 | ENDCHAR 2182 | STARTCHAR MACRON 2183 | ENCODING 175 2184 | SWIDTH 750 0 2185 | DWIDTH 6 0 2186 | BBX 6 8 0 -1 2187 | BITMAP 2188 | 00 2189 | 00 2190 | 00 2191 | 00 2192 | 00 2193 | 00 2194 | 00 2195 | 00 2196 | ENDCHAR 2197 | STARTCHAR DEGREE SIGN 2198 | ENCODING 176 2199 | SWIDTH 750 0 2200 | DWIDTH 6 0 2201 | BBX 6 8 0 -1 2202 | BITMAP 2203 | 00 2204 | A8 2205 | 00 2206 | A8 2207 | 00 2208 | A8 2209 | 00 2210 | A8 2211 | ENDCHAR 2212 | STARTCHAR PLUS-MINUS SIGN 2213 | ENCODING 177 2214 | SWIDTH 750 0 2215 | DWIDTH 6 0 2216 | BBX 6 8 0 -1 2217 | BITMAP 2218 | 50 2219 | A8 2220 | 50 2221 | A8 2222 | 50 2223 | A8 2224 | 50 2225 | A8 2226 | ENDCHAR 2227 | STARTCHAR SUPERSCRIPT TWO 2228 | ENCODING 178 2229 | SWIDTH 750 0 2230 | DWIDTH 6 0 2231 | BBX 6 8 0 -1 2232 | BITMAP 2233 | F8 2234 | 50 2235 | F8 2236 | 50 2237 | F8 2238 | 50 2239 | F8 2240 | 50 2241 | ENDCHAR 2242 | STARTCHAR SUPERSCRIPT THREE 2243 | ENCODING 179 2244 | SWIDTH 750 0 2245 | DWIDTH 6 0 2246 | BBX 6 8 0 -1 2247 | BITMAP 2248 | 20 2249 | 20 2250 | 20 2251 | 20 2252 | 20 2253 | 20 2254 | 20 2255 | 20 2256 | ENDCHAR 2257 | STARTCHAR ACUTE ACCENT 2258 | ENCODING 180 2259 | SWIDTH 750 0 2260 | DWIDTH 6 0 2261 | BBX 6 8 0 -1 2262 | BITMAP 2263 | 20 2264 | 20 2265 | 20 2266 | 20 2267 | E0 2268 | 20 2269 | 20 2270 | 20 2271 | ENDCHAR 2272 | STARTCHAR MICRO SIGN 2273 | ENCODING 181 2274 | SWIDTH 750 0 2275 | DWIDTH 6 0 2276 | BBX 6 8 0 -1 2277 | BITMAP 2278 | 20 2279 | 20 2280 | 20 2281 | E0 2282 | 20 2283 | E0 2284 | 20 2285 | 20 2286 | ENDCHAR 2287 | STARTCHAR PILCROW SIGN 2288 | ENCODING 182 2289 | SWIDTH 750 0 2290 | DWIDTH 6 0 2291 | BBX 6 8 0 -1 2292 | BITMAP 2293 | 50 2294 | 50 2295 | 50 2296 | 50 2297 | D0 2298 | 50 2299 | 50 2300 | 50 2301 | ENDCHAR 2302 | STARTCHAR MIDDLE DOT 2303 | ENCODING 183 2304 | SWIDTH 750 0 2305 | DWIDTH 6 0 2306 | BBX 6 8 0 -1 2307 | BITMAP 2308 | 00 2309 | 00 2310 | 00 2311 | 00 2312 | F0 2313 | 50 2314 | 50 2315 | 50 2316 | ENDCHAR 2317 | STARTCHAR CEDILLA 2318 | ENCODING 184 2319 | SWIDTH 750 0 2320 | DWIDTH 6 0 2321 | BBX 6 8 0 -1 2322 | BITMAP 2323 | 00 2324 | 00 2325 | 00 2326 | E0 2327 | 20 2328 | E0 2329 | 20 2330 | 20 2331 | ENDCHAR 2332 | STARTCHAR SUPERSCRIPT ONE 2333 | ENCODING 185 2334 | SWIDTH 750 0 2335 | DWIDTH 6 0 2336 | BBX 6 8 0 -1 2337 | BITMAP 2338 | 50 2339 | 50 2340 | 50 2341 | D0 2342 | 10 2343 | D0 2344 | 50 2345 | 50 2346 | ENDCHAR 2347 | STARTCHAR MASCULINE ORDINAL INDICATOR 2348 | ENCODING 186 2349 | SWIDTH 750 0 2350 | DWIDTH 6 0 2351 | BBX 6 8 0 -1 2352 | BITMAP 2353 | 50 2354 | 50 2355 | 50 2356 | 50 2357 | 50 2358 | 50 2359 | 50 2360 | 50 2361 | ENDCHAR 2362 | STARTCHAR RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK 2363 | ENCODING 187 2364 | SWIDTH 750 0 2365 | DWIDTH 6 0 2366 | BBX 6 8 0 -1 2367 | BITMAP 2368 | 00 2369 | 00 2370 | 00 2371 | F0 2372 | 10 2373 | D0 2374 | 50 2375 | 50 2376 | ENDCHAR 2377 | STARTCHAR VULGAR FRACTION ONE QUARTER 2378 | ENCODING 188 2379 | SWIDTH 750 0 2380 | DWIDTH 6 0 2381 | BBX 6 8 0 -1 2382 | BITMAP 2383 | 50 2384 | 50 2385 | 50 2386 | D0 2387 | 10 2388 | F0 2389 | 00 2390 | 00 2391 | ENDCHAR 2392 | STARTCHAR VULGAR FRACTION ONE HALF 2393 | ENCODING 189 2394 | SWIDTH 750 0 2395 | DWIDTH 6 0 2396 | BBX 6 8 0 -1 2397 | BITMAP 2398 | 50 2399 | 50 2400 | 50 2401 | 50 2402 | F0 2403 | 00 2404 | 00 2405 | 00 2406 | ENDCHAR 2407 | STARTCHAR VULGAR FRACTION THREE QUARTERS 2408 | ENCODING 190 2409 | SWIDTH 750 0 2410 | DWIDTH 6 0 2411 | BBX 6 8 0 -1 2412 | BITMAP 2413 | 20 2414 | 20 2415 | 20 2416 | E0 2417 | 20 2418 | E0 2419 | 00 2420 | 00 2421 | ENDCHAR 2422 | STARTCHAR INVERTED QUESTION MARK 2423 | ENCODING 191 2424 | SWIDTH 750 0 2425 | DWIDTH 6 0 2426 | BBX 6 8 0 -1 2427 | BITMAP 2428 | 00 2429 | 00 2430 | 00 2431 | 00 2432 | E0 2433 | 20 2434 | 20 2435 | 20 2436 | ENDCHAR 2437 | STARTCHAR LATIN CAPITAL LETTER A WITH GRAVE 2438 | ENCODING 192 2439 | SWIDTH 750 0 2440 | DWIDTH 6 0 2441 | BBX 6 8 0 -1 2442 | BITMAP 2443 | 20 2444 | 20 2445 | 20 2446 | 20 2447 | 3C 2448 | 00 2449 | 00 2450 | 00 2451 | ENDCHAR 2452 | STARTCHAR LATIN CAPITAL LETTER A WITH ACUTE 2453 | ENCODING 193 2454 | SWIDTH 750 0 2455 | DWIDTH 6 0 2456 | BBX 6 8 0 -1 2457 | BITMAP 2458 | 20 2459 | 20 2460 | 20 2461 | 20 2462 | FC 2463 | 00 2464 | 00 2465 | 00 2466 | ENDCHAR 2467 | STARTCHAR LATIN CAPITAL LETTER A WITH CIRCUMFLEX 2468 | ENCODING 194 2469 | SWIDTH 750 0 2470 | DWIDTH 6 0 2471 | BBX 6 8 0 -1 2472 | BITMAP 2473 | 00 2474 | 00 2475 | 00 2476 | 00 2477 | FC 2478 | 20 2479 | 20 2480 | 20 2481 | ENDCHAR 2482 | STARTCHAR LATIN CAPITAL LETTER A WITH TILDE 2483 | ENCODING 195 2484 | SWIDTH 750 0 2485 | DWIDTH 6 0 2486 | BBX 6 8 0 -1 2487 | BITMAP 2488 | 20 2489 | 20 2490 | 20 2491 | 20 2492 | 3C 2493 | 20 2494 | 20 2495 | 20 2496 | ENDCHAR 2497 | STARTCHAR LATIN CAPITAL LETTER A WITH DIAERESIS 2498 | ENCODING 196 2499 | SWIDTH 750 0 2500 | DWIDTH 6 0 2501 | BBX 6 8 0 -1 2502 | BITMAP 2503 | 00 2504 | 00 2505 | 00 2506 | 00 2507 | FC 2508 | 00 2509 | 00 2510 | 00 2511 | ENDCHAR 2512 | STARTCHAR LATIN CAPITAL LETTER A WITH RING ABOVE 2513 | ENCODING 197 2514 | SWIDTH 750 0 2515 | DWIDTH 6 0 2516 | BBX 6 8 0 -1 2517 | BITMAP 2518 | 20 2519 | 20 2520 | 20 2521 | 20 2522 | FC 2523 | 20 2524 | 20 2525 | 20 2526 | ENDCHAR 2527 | STARTCHAR LATIN CAPITAL LETTER AE 2528 | ENCODING 198 2529 | SWIDTH 750 0 2530 | DWIDTH 6 0 2531 | BBX 6 8 0 -1 2532 | BITMAP 2533 | 20 2534 | 20 2535 | 20 2536 | 3C 2537 | 20 2538 | 3C 2539 | 20 2540 | 20 2541 | ENDCHAR 2542 | STARTCHAR LATIN CAPITAL LETTER C WITH CEDILLA 2543 | ENCODING 199 2544 | SWIDTH 750 0 2545 | DWIDTH 6 0 2546 | BBX 6 8 0 -1 2547 | BITMAP 2548 | 50 2549 | 50 2550 | 50 2551 | 50 2552 | 5C 2553 | 50 2554 | 50 2555 | 50 2556 | ENDCHAR 2557 | STARTCHAR LATIN CAPITAL LETTER E WITH GRAVE 2558 | ENCODING 200 2559 | SWIDTH 750 0 2560 | DWIDTH 6 0 2561 | BBX 6 8 0 -1 2562 | BITMAP 2563 | 50 2564 | 50 2565 | 50 2566 | 5C 2567 | 40 2568 | 7C 2569 | 00 2570 | 00 2571 | ENDCHAR 2572 | STARTCHAR LATIN CAPITAL LETTER E WITH ACUTE 2573 | ENCODING 201 2574 | SWIDTH 750 0 2575 | DWIDTH 6 0 2576 | BBX 6 8 0 -1 2577 | BITMAP 2578 | 00 2579 | 00 2580 | 00 2581 | 7C 2582 | 40 2583 | 5C 2584 | 50 2585 | 50 2586 | ENDCHAR 2587 | STARTCHAR LATIN CAPITAL LETTER E WITH CIRCUMFLEX 2588 | ENCODING 202 2589 | SWIDTH 750 0 2590 | DWIDTH 6 0 2591 | BBX 6 8 0 -1 2592 | BITMAP 2593 | 50 2594 | 50 2595 | 50 2596 | DC 2597 | 00 2598 | FC 2599 | 00 2600 | 00 2601 | ENDCHAR 2602 | STARTCHAR LATIN CAPITAL LETTER E WITH DIAERESIS 2603 | ENCODING 203 2604 | SWIDTH 750 0 2605 | DWIDTH 6 0 2606 | BBX 6 8 0 -1 2607 | BITMAP 2608 | 00 2609 | 00 2610 | 00 2611 | FC 2612 | 00 2613 | DC 2614 | 50 2615 | 50 2616 | ENDCHAR 2617 | STARTCHAR LATIN CAPITAL LETTER I WITH GRAVE 2618 | ENCODING 204 2619 | SWIDTH 750 0 2620 | DWIDTH 6 0 2621 | BBX 6 8 0 -1 2622 | BITMAP 2623 | 50 2624 | 50 2625 | 50 2626 | 5C 2627 | 40 2628 | 5C 2629 | 50 2630 | 50 2631 | ENDCHAR 2632 | STARTCHAR LATIN CAPITAL LETTER I WITH ACUTE 2633 | ENCODING 205 2634 | SWIDTH 750 0 2635 | DWIDTH 6 0 2636 | BBX 6 8 0 -1 2637 | BITMAP 2638 | 00 2639 | 00 2640 | 00 2641 | FC 2642 | 00 2643 | FC 2644 | 00 2645 | 00 2646 | ENDCHAR 2647 | STARTCHAR LATIN CAPITAL LETTER I WITH CIRCUMFLEX 2648 | ENCODING 206 2649 | SWIDTH 750 0 2650 | DWIDTH 6 0 2651 | BBX 6 8 0 -1 2652 | BITMAP 2653 | 50 2654 | 50 2655 | 50 2656 | DC 2657 | 00 2658 | DC 2659 | 50 2660 | 50 2661 | ENDCHAR 2662 | STARTCHAR LATIN CAPITAL LETTER I WITH DIAERESIS 2663 | ENCODING 207 2664 | SWIDTH 750 0 2665 | DWIDTH 6 0 2666 | BBX 6 8 0 -1 2667 | BITMAP 2668 | 20 2669 | 20 2670 | 20 2671 | FC 2672 | 00 2673 | FC 2674 | 00 2675 | 00 2676 | ENDCHAR 2677 | STARTCHAR LATIN CAPITAL LETTER ETH 2678 | ENCODING 208 2679 | SWIDTH 750 0 2680 | DWIDTH 6 0 2681 | BBX 6 8 0 -1 2682 | BITMAP 2683 | 50 2684 | 50 2685 | 50 2686 | FC 2687 | 00 2688 | FC 2689 | 00 2690 | 00 2691 | ENDCHAR 2692 | STARTCHAR LATIN CAPITAL LETTER N WITH TILDE 2693 | ENCODING 209 2694 | SWIDTH 750 0 2695 | DWIDTH 6 0 2696 | BBX 6 8 0 -1 2697 | BITMAP 2698 | 00 2699 | 00 2700 | 00 2701 | FC 2702 | 00 2703 | FC 2704 | 20 2705 | 20 2706 | ENDCHAR 2707 | STARTCHAR LATIN CAPITAL LETTER O WITH GRAVE 2708 | ENCODING 210 2709 | SWIDTH 750 0 2710 | DWIDTH 6 0 2711 | BBX 6 8 0 -1 2712 | BITMAP 2713 | 00 2714 | 00 2715 | 00 2716 | 00 2717 | FC 2718 | 50 2719 | 50 2720 | 50 2721 | ENDCHAR 2722 | STARTCHAR LATIN CAPITAL LETTER O WITH ACUTE 2723 | ENCODING 211 2724 | SWIDTH 750 0 2725 | DWIDTH 6 0 2726 | BBX 6 8 0 -1 2727 | BITMAP 2728 | 50 2729 | 50 2730 | 50 2731 | 50 2732 | FC 2733 | 00 2734 | 00 2735 | 00 2736 | ENDCHAR 2737 | STARTCHAR LATIN CAPITAL LETTER O WITH CIRCUMFLEX 2738 | ENCODING 212 2739 | SWIDTH 750 0 2740 | DWIDTH 6 0 2741 | BBX 6 8 0 -1 2742 | BITMAP 2743 | 20 2744 | 20 2745 | 20 2746 | 3C 2747 | 20 2748 | 3C 2749 | 00 2750 | 00 2751 | ENDCHAR 2752 | STARTCHAR LATIN CAPITAL LETTER O WITH TILDE 2753 | ENCODING 213 2754 | SWIDTH 750 0 2755 | DWIDTH 6 0 2756 | BBX 6 8 0 -1 2757 | BITMAP 2758 | 00 2759 | 00 2760 | 00 2761 | 3C 2762 | 20 2763 | 3C 2764 | 20 2765 | 20 2766 | ENDCHAR 2767 | STARTCHAR LATIN CAPITAL LETTER O WITH DIAERESIS 2768 | ENCODING 214 2769 | SWIDTH 750 0 2770 | DWIDTH 6 0 2771 | BBX 6 8 0 -1 2772 | BITMAP 2773 | 00 2774 | 00 2775 | 00 2776 | 00 2777 | 7C 2778 | 50 2779 | 50 2780 | 50 2781 | ENDCHAR 2782 | STARTCHAR MULTIPLICATION SIGN 2783 | ENCODING 215 2784 | SWIDTH 750 0 2785 | DWIDTH 6 0 2786 | BBX 6 8 0 -1 2787 | BITMAP 2788 | 50 2789 | 50 2790 | 50 2791 | 50 2792 | FC 2793 | 50 2794 | 50 2795 | 50 2796 | ENDCHAR 2797 | STARTCHAR LATIN CAPITAL LETTER O WITH STROKE 2798 | ENCODING 216 2799 | SWIDTH 750 0 2800 | DWIDTH 6 0 2801 | BBX 6 8 0 -1 2802 | BITMAP 2803 | 20 2804 | 20 2805 | 20 2806 | FC 2807 | 00 2808 | FC 2809 | 20 2810 | 20 2811 | ENDCHAR 2812 | STARTCHAR LATIN CAPITAL LETTER U WITH GRAVE 2813 | ENCODING 217 2814 | SWIDTH 750 0 2815 | DWIDTH 6 0 2816 | BBX 6 8 0 -1 2817 | BITMAP 2818 | 20 2819 | 20 2820 | 20 2821 | 20 2822 | E0 2823 | 00 2824 | 00 2825 | 00 2826 | ENDCHAR 2827 | STARTCHAR LATIN CAPITAL LETTER U WITH ACUTE 2828 | ENCODING 218 2829 | SWIDTH 750 0 2830 | DWIDTH 6 0 2831 | BBX 6 8 0 -1 2832 | BITMAP 2833 | 00 2834 | 00 2835 | 00 2836 | 00 2837 | 3C 2838 | 20 2839 | 20 2840 | 20 2841 | ENDCHAR 2842 | STARTCHAR LATIN CAPITAL LETTER U WITH CIRCUMFLEX 2843 | ENCODING 219 2844 | SWIDTH 750 0 2845 | DWIDTH 6 0 2846 | BBX 6 8 0 -1 2847 | BITMAP 2848 | F8 2849 | F8 2850 | F8 2851 | F8 2852 | F8 2853 | F8 2854 | F8 2855 | F8 2856 | ENDCHAR 2857 | STARTCHAR LATIN CAPITAL LETTER U WITH DIAERESIS 2858 | ENCODING 220 2859 | SWIDTH 750 0 2860 | DWIDTH 6 0 2861 | BBX 6 8 0 -1 2862 | BITMAP 2863 | 00 2864 | 00 2865 | 00 2866 | F8 2867 | F8 2868 | F8 2869 | F8 2870 | F8 2871 | ENDCHAR 2872 | STARTCHAR LATIN CAPITAL LETTER Y WITH ACUTE 2873 | ENCODING 221 2874 | SWIDTH 750 0 2875 | DWIDTH 6 0 2876 | BBX 6 8 0 -1 2877 | BITMAP 2878 | E0 2879 | E0 2880 | E0 2881 | E0 2882 | E0 2883 | E0 2884 | E0 2885 | E0 2886 | ENDCHAR 2887 | STARTCHAR LATIN CAPITAL LETTER THORN 2888 | ENCODING 222 2889 | SWIDTH 750 0 2890 | DWIDTH 6 0 2891 | BBX 6 8 0 -1 2892 | BITMAP 2893 | 38 2894 | 38 2895 | 38 2896 | 38 2897 | 38 2898 | 38 2899 | 38 2900 | 38 2901 | ENDCHAR 2902 | STARTCHAR LATIN SMALL LETTER SHARP S 2903 | ENCODING 223 2904 | SWIDTH 750 0 2905 | DWIDTH 6 0 2906 | BBX 6 8 0 -1 2907 | BITMAP 2908 | F8 2909 | F8 2910 | F8 2911 | F8 2912 | 00 2913 | 00 2914 | 00 2915 | 00 2916 | ENDCHAR 2917 | STARTCHAR LATIN SMALL LETTER A WITH GRAVE 2918 | ENCODING 224 2919 | SWIDTH 750 0 2920 | DWIDTH 6 0 2921 | BBX 6 8 0 -1 2922 | BITMAP 2923 | 00 2924 | 00 2925 | 00 2926 | 00 2927 | 00 2928 | 00 2929 | 00 2930 | 00 2931 | ENDCHAR 2932 | STARTCHAR LATIN SMALL LETTER A WITH ACUTE 2933 | ENCODING 225 2934 | SWIDTH 750 0 2935 | DWIDTH 6 0 2936 | BBX 6 8 0 -1 2937 | BITMAP 2938 | 00 2939 | 00 2940 | 00 2941 | 00 2942 | 00 2943 | 00 2944 | 00 2945 | 00 2946 | ENDCHAR 2947 | STARTCHAR LATIN SMALL LETTER A WITH CIRCUMFLEX 2948 | ENCODING 226 2949 | SWIDTH 750 0 2950 | DWIDTH 6 0 2951 | BBX 6 8 0 -1 2952 | BITMAP 2953 | 00 2954 | 00 2955 | 00 2956 | 00 2957 | 00 2958 | 00 2959 | 00 2960 | 00 2961 | ENDCHAR 2962 | STARTCHAR LATIN SMALL LETTER A WITH TILDE 2963 | ENCODING 227 2964 | SWIDTH 750 0 2965 | DWIDTH 6 0 2966 | BBX 6 8 0 -1 2967 | BITMAP 2968 | 00 2969 | 00 2970 | 00 2971 | 00 2972 | 00 2973 | 00 2974 | 00 2975 | 00 2976 | ENDCHAR 2977 | STARTCHAR LATIN SMALL LETTER A WITH DIAERESIS 2978 | ENCODING 228 2979 | SWIDTH 750 0 2980 | DWIDTH 6 0 2981 | BBX 6 8 0 -1 2982 | BITMAP 2983 | 00 2984 | 00 2985 | 00 2986 | 00 2987 | 00 2988 | 00 2989 | 00 2990 | 00 2991 | ENDCHAR 2992 | STARTCHAR LATIN SMALL LETTER A WITH RING ABOVE 2993 | ENCODING 229 2994 | SWIDTH 750 0 2995 | DWIDTH 6 0 2996 | BBX 6 8 0 -1 2997 | BITMAP 2998 | 00 2999 | 00 3000 | 00 3001 | 00 3002 | 00 3003 | 00 3004 | 00 3005 | 00 3006 | ENDCHAR 3007 | STARTCHAR LATIN SMALL LETTER AE 3008 | ENCODING 230 3009 | SWIDTH 750 0 3010 | DWIDTH 6 0 3011 | BBX 6 8 0 -1 3012 | BITMAP 3013 | 00 3014 | 00 3015 | 00 3016 | 00 3017 | 00 3018 | 00 3019 | 00 3020 | 00 3021 | ENDCHAR 3022 | STARTCHAR LATIN SMALL LETTER C WITH CEDILLA 3023 | ENCODING 231 3024 | SWIDTH 750 0 3025 | DWIDTH 6 0 3026 | BBX 6 8 0 -1 3027 | BITMAP 3028 | 00 3029 | 00 3030 | 00 3031 | 00 3032 | 00 3033 | 00 3034 | 00 3035 | 00 3036 | ENDCHAR 3037 | STARTCHAR LATIN SMALL LETTER E WITH GRAVE 3038 | ENCODING 232 3039 | SWIDTH 750 0 3040 | DWIDTH 6 0 3041 | BBX 6 8 0 -1 3042 | BITMAP 3043 | 00 3044 | 00 3045 | 00 3046 | 00 3047 | 00 3048 | 00 3049 | 00 3050 | 00 3051 | ENDCHAR 3052 | STARTCHAR LATIN SMALL LETTER E WITH ACUTE 3053 | ENCODING 233 3054 | SWIDTH 750 0 3055 | DWIDTH 6 0 3056 | BBX 6 8 0 -1 3057 | BITMAP 3058 | 00 3059 | 00 3060 | 00 3061 | 00 3062 | 00 3063 | 00 3064 | 00 3065 | 00 3066 | ENDCHAR 3067 | STARTCHAR LATIN SMALL LETTER E WITH CIRCUMFLEX 3068 | ENCODING 234 3069 | SWIDTH 750 0 3070 | DWIDTH 6 0 3071 | BBX 6 8 0 -1 3072 | BITMAP 3073 | 00 3074 | 00 3075 | 00 3076 | 00 3077 | 00 3078 | 00 3079 | 00 3080 | 00 3081 | ENDCHAR 3082 | STARTCHAR LATIN SMALL LETTER E WITH DIAERESIS 3083 | ENCODING 235 3084 | SWIDTH 750 0 3085 | DWIDTH 6 0 3086 | BBX 6 8 0 -1 3087 | BITMAP 3088 | 00 3089 | 00 3090 | 00 3091 | 00 3092 | 00 3093 | 00 3094 | 00 3095 | 00 3096 | ENDCHAR 3097 | STARTCHAR LATIN SMALL LETTER I WITH GRAVE 3098 | ENCODING 236 3099 | SWIDTH 750 0 3100 | DWIDTH 6 0 3101 | BBX 6 8 0 -1 3102 | BITMAP 3103 | 00 3104 | 00 3105 | 00 3106 | 00 3107 | 00 3108 | 00 3109 | 00 3110 | 00 3111 | ENDCHAR 3112 | STARTCHAR LATIN SMALL LETTER I WITH ACUTE 3113 | ENCODING 237 3114 | SWIDTH 750 0 3115 | DWIDTH 6 0 3116 | BBX 6 8 0 -1 3117 | BITMAP 3118 | 00 3119 | 00 3120 | 00 3121 | 00 3122 | 00 3123 | 00 3124 | 00 3125 | 00 3126 | ENDCHAR 3127 | STARTCHAR LATIN SMALL LETTER I WITH CIRCUMFLEX 3128 | ENCODING 238 3129 | SWIDTH 750 0 3130 | DWIDTH 6 0 3131 | BBX 6 8 0 -1 3132 | BITMAP 3133 | 00 3134 | 00 3135 | 00 3136 | 00 3137 | 00 3138 | 00 3139 | 00 3140 | 00 3141 | ENDCHAR 3142 | STARTCHAR LATIN SMALL LETTER I WITH DIAERESIS 3143 | ENCODING 239 3144 | SWIDTH 750 0 3145 | DWIDTH 6 0 3146 | BBX 6 8 0 -1 3147 | BITMAP 3148 | 00 3149 | 00 3150 | 00 3151 | 00 3152 | 00 3153 | 00 3154 | 00 3155 | 00 3156 | ENDCHAR 3157 | STARTCHAR LATIN SMALL LETTER ETH 3158 | ENCODING 240 3159 | SWIDTH 750 0 3160 | DWIDTH 6 0 3161 | BBX 6 8 0 -1 3162 | BITMAP 3163 | 00 3164 | 00 3165 | 00 3166 | 00 3167 | 00 3168 | 00 3169 | 00 3170 | 00 3171 | ENDCHAR 3172 | STARTCHAR LATIN SMALL LETTER N WITH TILDE 3173 | ENCODING 241 3174 | SWIDTH 750 0 3175 | DWIDTH 6 0 3176 | BBX 6 8 0 -1 3177 | BITMAP 3178 | 00 3179 | 00 3180 | 00 3181 | 00 3182 | 00 3183 | 00 3184 | 00 3185 | 00 3186 | ENDCHAR 3187 | STARTCHAR LATIN SMALL LETTER O WITH GRAVE 3188 | ENCODING 242 3189 | SWIDTH 750 0 3190 | DWIDTH 6 0 3191 | BBX 6 8 0 -1 3192 | BITMAP 3193 | 00 3194 | 00 3195 | 00 3196 | 00 3197 | 00 3198 | 00 3199 | 00 3200 | 00 3201 | ENDCHAR 3202 | STARTCHAR LATIN SMALL LETTER O WITH ACUTE 3203 | ENCODING 243 3204 | SWIDTH 750 0 3205 | DWIDTH 6 0 3206 | BBX 6 8 0 -1 3207 | BITMAP 3208 | 00 3209 | 00 3210 | 00 3211 | 00 3212 | 00 3213 | 00 3214 | 00 3215 | 00 3216 | ENDCHAR 3217 | STARTCHAR LATIN SMALL LETTER O WITH CIRCUMFLEX 3218 | ENCODING 244 3219 | SWIDTH 750 0 3220 | DWIDTH 6 0 3221 | BBX 6 8 0 -1 3222 | BITMAP 3223 | 00 3224 | 00 3225 | 00 3226 | 00 3227 | 00 3228 | 00 3229 | 00 3230 | 00 3231 | ENDCHAR 3232 | STARTCHAR LATIN SMALL LETTER O WITH TILDE 3233 | ENCODING 245 3234 | SWIDTH 750 0 3235 | DWIDTH 6 0 3236 | BBX 6 8 0 -1 3237 | BITMAP 3238 | 00 3239 | 00 3240 | 00 3241 | 00 3242 | 00 3243 | 00 3244 | 00 3245 | 00 3246 | ENDCHAR 3247 | STARTCHAR LATIN SMALL LETTER O WITH DIAERESIS 3248 | ENCODING 246 3249 | SWIDTH 750 0 3250 | DWIDTH 6 0 3251 | BBX 6 8 0 -1 3252 | BITMAP 3253 | 00 3254 | 00 3255 | 00 3256 | 00 3257 | 00 3258 | 00 3259 | 00 3260 | 00 3261 | ENDCHAR 3262 | STARTCHAR DIVISION SIGN 3263 | ENCODING 247 3264 | SWIDTH 750 0 3265 | DWIDTH 6 0 3266 | BBX 6 8 0 -1 3267 | BITMAP 3268 | 00 3269 | 00 3270 | 00 3271 | 00 3272 | 00 3273 | 00 3274 | 00 3275 | 00 3276 | ENDCHAR 3277 | STARTCHAR LATIN SMALL LETTER O WITH STROKE 3278 | ENCODING 248 3279 | SWIDTH 750 0 3280 | DWIDTH 6 0 3281 | BBX 6 8 0 -1 3282 | BITMAP 3283 | 00 3284 | 00 3285 | 00 3286 | 00 3287 | 00 3288 | 00 3289 | 00 3290 | 00 3291 | ENDCHAR 3292 | STARTCHAR LATIN SMALL LETTER U WITH GRAVE 3293 | ENCODING 249 3294 | SWIDTH 750 0 3295 | DWIDTH 6 0 3296 | BBX 6 8 0 -1 3297 | BITMAP 3298 | 00 3299 | 00 3300 | 00 3301 | 00 3302 | 00 3303 | 00 3304 | 00 3305 | 00 3306 | ENDCHAR 3307 | STARTCHAR LATIN SMALL LETTER U WITH ACUTE 3308 | ENCODING 250 3309 | SWIDTH 750 0 3310 | DWIDTH 6 0 3311 | BBX 6 8 0 -1 3312 | BITMAP 3313 | 00 3314 | 00 3315 | 00 3316 | 00 3317 | 00 3318 | 00 3319 | 00 3320 | 00 3321 | ENDCHAR 3322 | STARTCHAR LATIN SMALL LETTER U WITH CIRCUMFLEX 3323 | ENCODING 251 3324 | SWIDTH 750 0 3325 | DWIDTH 6 0 3326 | BBX 6 8 0 -1 3327 | BITMAP 3328 | 00 3329 | 00 3330 | 00 3331 | 00 3332 | 00 3333 | 00 3334 | 00 3335 | 00 3336 | ENDCHAR 3337 | STARTCHAR LATIN SMALL LETTER U WITH DIAERESIS 3338 | ENCODING 252 3339 | SWIDTH 750 0 3340 | DWIDTH 6 0 3341 | BBX 6 8 0 -1 3342 | BITMAP 3343 | 00 3344 | 00 3345 | 00 3346 | 00 3347 | 00 3348 | 00 3349 | 00 3350 | 00 3351 | ENDCHAR 3352 | STARTCHAR LATIN SMALL LETTER Y WITH ACUTE 3353 | ENCODING 253 3354 | SWIDTH 750 0 3355 | DWIDTH 6 0 3356 | BBX 6 8 0 -1 3357 | BITMAP 3358 | 70 3359 | 10 3360 | 20 3361 | 70 3362 | 00 3363 | 00 3364 | 00 3365 | 00 3366 | ENDCHAR 3367 | STARTCHAR LATIN SMALL LETTER THORN 3368 | ENCODING 254 3369 | SWIDTH 750 0 3370 | DWIDTH 6 0 3371 | BBX 6 8 0 -1 3372 | BITMAP 3373 | 00 3374 | 00 3375 | F0 3376 | F0 3377 | F0 3378 | F0 3379 | 00 3380 | 00 3381 | ENDCHAR 3382 | STARTCHAR LATIN SMALL LETTER Y WITH DIAERESIS 3383 | ENCODING 255 3384 | SWIDTH 750 0 3385 | DWIDTH 6 0 3386 | BBX 6 8 0 -1 3387 | BITMAP 3388 | 00 3389 | 00 3390 | 00 3391 | 00 3392 | 00 3393 | 00 3394 | 00 3395 | 00 3396 | ENDCHAR 3397 | ENDFONT 3398 | -------------------------------------------------------------------------------- /font/spleen-5x8.hex: -------------------------------------------------------------------------------- 1 | 0000:F8D8A8E8D8F8D8F8 2 | 0001:7088D888F8887000 3 | 0002:70F8A8F888F87000 4 | 0003:0050F8F870200000 5 | 0004:002070F870200000 6 | 0005:002070D8D8207000 7 | 0006:002070F8F8207000 8 | 0007:0000207070200000 9 | 0008:7070500050707070 10 | 0009:0000205050200000 11 | 000A:7070502020507070 12 | 000B:0030709090600000 13 | 000C:0020505020702000 14 | 000D:00383820E0C00000 15 | 000E:0038382828500000 16 | 000F:00A870D870A80000 17 | 0010:0040607070604000 18 | 0011:0010307070301000 19 | 0012:0020702070200000 20 | 0013:0050505050005000 21 | 0014:0070D0D050500000 22 | 0015:609060F070906000 23 | 0016:0000000000F8F800 24 | 0017:2070202070207000 25 | 0018:2070202020200000 26 | 0019:2020202070200000 27 | 001A:000020F020000000 28 | 001B:000040F040000000 29 | 001C:00008080F8000000 30 | 001D:000050F850000000 31 | 001E:00002070F8000000 32 | 001F:0000F87020000000 33 | 0020:0000000000000000 34 | 0021:2020202020002000 35 | 0022:5050500000000000 36 | 0023:0050F85050F85000 37 | 0024:2070A0603030E020 38 | 0025:1090A02040509080 39 | 0026:20505060A0906800 40 | 0027:2020200000000000 41 | 0028:1020404040402010 42 | 0029:4020101010102040 43 | 002A:00009060F0609000 44 | 002B:00002020F8202000 45 | 002C:0000000000202040 46 | 002D:00000000F0000000 47 | 002E:0000000000002000 48 | 002F:1010202040408080 49 | 0030:006090B0D0906000 50 | 0031:0020602020207000 51 | 0032:006090106080F000 52 | 0033:0060902010906000 53 | 0034:0080A0A0F0202000 54 | 0035:00F080F01010E000 55 | 0036:006080E090906000 56 | 0037:00F0902020404000 57 | 0038:0060906090906000 58 | 0039:0060909070106000 59 | 003A:0000002000002000 60 | 003B:0000002000202040 61 | 003C:0010204040201000 62 | 003D:000000F000F00000 63 | 003E:0040201010204000 64 | 003F:6090102040004000 65 | 0040:006090B0B0807000 66 | 0041:00609090F0909000 67 | 0042:00E090E09090E000 68 | 0043:0070808080807000 69 | 0044:00E090909090E000 70 | 0045:007080E080807000 71 | 0046:00708080E0808000 72 | 0047:007080B090907000 73 | 0048:009090F090909000 74 | 0049:0070202020207000 75 | 004A:007020202020C000 76 | 004B:009090E090909000 77 | 004C:0080808080807000 78 | 004D:0090F0F090909000 79 | 004E:0090D0D0B0B09000 80 | 004F:0060909090906000 81 | 0050:00E09090E0808000 82 | 0051:0060909090906030 83 | 0052:00E09090E0909000 84 | 0053:007080601010E000 85 | 0054:00F8202020202000 86 | 0055:0090909090907000 87 | 0056:0090909090606000 88 | 0057:00909090F0F09000 89 | 0058:0090906060909000 90 | 0059:009090907010E000 91 | 005A:00F010204080F000 92 | 005B:7040404040404070 93 | 005C:8080404020201010 94 | 005D:7010101010101070 95 | 005E:0020508800000000 96 | 005F:00000000000000F0 97 | 0060:4020000000000000 98 | 0061:0000601070907000 99 | 0062:8080E0909090E000 100 | 0063:0000708080807000 101 | 0064:1010709090907000 102 | 0065:00007090F0807000 103 | 0066:304040E040404000 104 | 0067:00007090906010E0 105 | 0068:8080E09090909000 106 | 0069:0020002020202000 107 | 006A:00200020202020C0 108 | 006B:808090A0C0A09000 109 | 006C:4040404040403000 110 | 006D:000090F0F0909000 111 | 006E:0000E09090909000 112 | 006F:0000609090906000 113 | 0070:0000E09090E08080 114 | 0071:0000709090701010 115 | 0072:0000709080808000 116 | 0073:000070806010E000 117 | 0074:4040E04040403000 118 | 0075:0000909090907000 119 | 0076:0000909090606000 120 | 0077:00009090F0F09000 121 | 0078:0000906060909000 122 | 0079:00009090907010E0 123 | 007A:0000F0102040F000 124 | 007B:304040C0C0404030 125 | 007C:0020202020202000 126 | 007D:C0202030302020C0 127 | 007E:0048B00000000000 128 | 007F:0000000000000000 129 | 00A0:0000000000000000 130 | 00A1:0000000000000000 131 | 00A2:0000000000000000 132 | 00A3:0000000000000000 133 | 00A4:0000000000000000 134 | 00A5:0000000000000000 135 | 00A6:0000000000000000 136 | 00A7:0000000000000000 137 | 00A8:0000000000000000 138 | 00A9:0000000000000000 139 | 00AA:0000000000000000 140 | 00AB:0000000000000000 141 | 00AC:0000000000000000 142 | 00AD:0000000000000000 143 | 00AE:0000000000000000 144 | 00AF:0000000000000000 145 | 00B0:00A800A800A800A8 146 | 00B1:50A850A850A850A8 147 | 00B2:F850F850F850F850 148 | 00B3:2020202020202020 149 | 00B4:20202020E0202020 150 | 00B5:202020E020E02020 151 | 00B6:50505050D0505050 152 | 00B7:00000000F0505050 153 | 00B8:000000E020E02020 154 | 00B9:505050D010D05050 155 | 00BA:5050505050505050 156 | 00BB:000000F010D05050 157 | 00BC:505050D010F00000 158 | 00BD:50505050F0000000 159 | 00BE:202020E020E00000 160 | 00BF:00000000E0202020 161 | 00C0:202020203C000000 162 | 00C1:20202020FC000000 163 | 00C2:00000000FC202020 164 | 00C3:202020203C202020 165 | 00C4:00000000FC000000 166 | 00C5:20202020FC202020 167 | 00C6:2020203C203C2020 168 | 00C7:505050505C505050 169 | 00C8:5050505C407C0000 170 | 00C9:0000007C405C5050 171 | 00CA:505050DC00FC0000 172 | 00CB:000000FC00DC5050 173 | 00CC:5050505C405C5050 174 | 00CD:000000FC00FC0000 175 | 00CE:505050DC00DC5050 176 | 00CF:202020FC00FC0000 177 | 00D0:505050FC00FC0000 178 | 00D1:000000FC00FC2020 179 | 00D2:00000000FC505050 180 | 00D3:50505050FC000000 181 | 00D4:2020203C203C0000 182 | 00D5:0000003C203C2020 183 | 00D6:000000007C505050 184 | 00D7:50505050FC505050 185 | 00D8:202020FC00FC2020 186 | 00D9:20202020E0000000 187 | 00DA:000000003C202020 188 | 00DB:F8F8F8F8F8F8F8F8 189 | 00DC:000000F8F8F8F8F8 190 | 00DD:E0E0E0E0E0E0E0E0 191 | 00DE:3838383838383838 192 | 00DF:F8F8F8F800000000 193 | 00E0:0000000000000000 194 | 00E1:0000000000000000 195 | 00E2:0000000000000000 196 | 00E3:0000000000000000 197 | 00E4:0000000000000000 198 | 00E5:0000000000000000 199 | 00E6:0000000000000000 200 | 00E7:0000000000000000 201 | 00E8:0000000000000000 202 | 00E9:0000000000000000 203 | 00EA:0000000000000000 204 | 00EB:0000000000000000 205 | 00EC:0000000000000000 206 | 00ED:0000000000000000 207 | 00EE:0000000000000000 208 | 00EF:0000000000000000 209 | 00F0:0000000000000000 210 | 00F1:0000000000000000 211 | 00F2:0000000000000000 212 | 00F3:0000000000000000 213 | 00F4:0000000000000000 214 | 00F5:0000000000000000 215 | 00F6:0000000000000000 216 | 00F7:0000000000000000 217 | 00F8:0000000000000000 218 | 00F9:0000000000000000 219 | 00FA:0000000000000000 220 | 00FB:0000000000000000 221 | 00FC:0000000000000000 222 | 00FD:7010207000000000 223 | 00FE:0000F0F0F0F00000 224 | 00FF:0000000000000000 225 | -------------------------------------------------------------------------------- /font/spleen-5x8.inc: -------------------------------------------------------------------------------- 1 | .db #0x1f, #0x1b, #0x15, #0x17, #0x1b, #0x1f, #0x1b, #0x1f 2 | .db #0x0e, #0x11, #0x1b, #0x11, #0x1f, #0x11, #0x0e, #0x00 3 | .db #0x0e, #0x1f, #0x15, #0x1f, #0x11, #0x1f, #0x0e, #0x00 4 | .db #0x00, #0x0a, #0x1f, #0x1f, #0x0e, #0x04, #0x00, #0x00 5 | .db #0x00, #0x04, #0x0e, #0x1f, #0x0e, #0x04, #0x00, #0x00 6 | .db #0x00, #0x04, #0x0e, #0x1b, #0x1b, #0x04, #0x0e, #0x00 7 | .db #0x00, #0x04, #0x0e, #0x1f, #0x1f, #0x04, #0x0e, #0x00 8 | .db #0x00, #0x00, #0x04, #0x0e, #0x0e, #0x04, #0x00, #0x00 9 | .db #0x0e, #0x0e, #0x0a, #0x00, #0x0a, #0x0e, #0x0e, #0x0e 10 | .db #0x00, #0x00, #0x04, #0x0a, #0x0a, #0x04, #0x00, #0x00 11 | .db #0x0e, #0x0e, #0x0a, #0x04, #0x04, #0x0a, #0x0e, #0x0e 12 | .db #0x00, #0x0c, #0x0e, #0x09, #0x09, #0x06, #0x00, #0x00 13 | .db #0x00, #0x04, #0x0a, #0x0a, #0x04, #0x0e, #0x04, #0x00 14 | .db #0x00, #0x1c, #0x1c, #0x04, #0x07, #0x03, #0x00, #0x00 15 | .db #0x00, #0x1c, #0x1c, #0x14, #0x14, #0x0a, #0x00, #0x00 16 | .db #0x00, #0x15, #0x0e, #0x1b, #0x0e, #0x15, #0x00, #0x00 17 | .db #0x00, #0x02, #0x06, #0x0e, #0x0e, #0x06, #0x02, #0x00 18 | .db #0x00, #0x08, #0x0c, #0x0e, #0x0e, #0x0c, #0x08, #0x00 19 | .db #0x00, #0x04, #0x0e, #0x04, #0x0e, #0x04, #0x00, #0x00 20 | .db #0x00, #0x0a, #0x0a, #0x0a, #0x0a, #0x00, #0x0a, #0x00 21 | .db #0x00, #0x0e, #0x0b, #0x0b, #0x0a, #0x0a, #0x00, #0x00 22 | .db #0x06, #0x09, #0x06, #0x0f, #0x0e, #0x09, #0x06, #0x00 23 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x1f, #0x1f, #0x00 24 | .db #0x04, #0x0e, #0x04, #0x04, #0x0e, #0x04, #0x0e, #0x00 25 | .db #0x04, #0x0e, #0x04, #0x04, #0x04, #0x04, #0x00, #0x00 26 | .db #0x04, #0x04, #0x04, #0x04, #0x0e, #0x04, #0x00, #0x00 27 | .db #0x00, #0x00, #0x04, #0x0f, #0x04, #0x00, #0x00, #0x00 28 | .db #0x00, #0x00, #0x02, #0x0f, #0x02, #0x00, #0x00, #0x00 29 | .db #0x00, #0x00, #0x01, #0x01, #0x1f, #0x00, #0x00, #0x00 30 | .db #0x00, #0x00, #0x0a, #0x1f, #0x0a, #0x00, #0x00, #0x00 31 | .db #0x00, #0x00, #0x04, #0x0e, #0x1f, #0x00, #0x00, #0x00 32 | .db #0x00, #0x00, #0x1f, #0x0e, #0x04, #0x00, #0x00, #0x00 33 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 ; 032 - 34 | .db #0x04, #0x04, #0x04, #0x04, #0x04, #0x00, #0x04, #0x00 ; 033 - ! 35 | .db #0x0a, #0x0a, #0x0a, #0x00, #0x00, #0x00, #0x00, #0x00 ; 034 - " 36 | .db #0x00, #0x0a, #0x1f, #0x0a, #0x0a, #0x1f, #0x0a, #0x00 ; 035 - # 37 | .db #0x04, #0x0e, #0x05, #0x06, #0x0c, #0x0c, #0x07, #0x04 ; 036 - $ 38 | .db #0x08, #0x09, #0x05, #0x04, #0x02, #0x0a, #0x09, #0x01 ; 037 - % 39 | .db #0x04, #0x0a, #0x0a, #0x06, #0x05, #0x09, #0x16, #0x00 ; 038 - & 40 | .db #0x04, #0x04, #0x04, #0x00, #0x00, #0x00, #0x00, #0x00 ; 039 - ' 41 | .db #0x08, #0x04, #0x02, #0x02, #0x02, #0x02, #0x04, #0x08 ; 040 - ( 42 | .db #0x02, #0x04, #0x08, #0x08, #0x08, #0x08, #0x04, #0x02 ; 041 - ) 43 | .db #0x00, #0x00, #0x09, #0x06, #0x0f, #0x06, #0x09, #0x00 ; 042 - * 44 | .db #0x00, #0x00, #0x04, #0x04, #0x1f, #0x04, #0x04, #0x00 ; 043 - + 45 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x04, #0x04, #0x02 ; 044 - , 46 | .db #0x00, #0x00, #0x00, #0x00, #0x0f, #0x00, #0x00, #0x00 ; 045 - - 47 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x04, #0x00 ; 046 - . 48 | .db #0x08, #0x08, #0x04, #0x04, #0x02, #0x02, #0x01, #0x01 ; 047 - / 49 | .db #0x00, #0x06, #0x09, #0x0d, #0x0b, #0x09, #0x06, #0x00 ; 048 - 0 50 | .db #0x00, #0x04, #0x06, #0x04, #0x04, #0x04, #0x0e, #0x00 ; 049 - 1 51 | .db #0x00, #0x06, #0x09, #0x08, #0x06, #0x01, #0x0f, #0x00 ; 050 - 2 52 | .db #0x00, #0x06, #0x09, #0x04, #0x08, #0x09, #0x06, #0x00 ; 051 - 3 53 | .db #0x00, #0x01, #0x05, #0x05, #0x0f, #0x04, #0x04, #0x00 ; 052 - 4 54 | .db #0x00, #0x0f, #0x01, #0x0f, #0x08, #0x08, #0x07, #0x00 ; 053 - 5 55 | .db #0x00, #0x06, #0x01, #0x07, #0x09, #0x09, #0x06, #0x00 ; 054 - 6 56 | .db #0x00, #0x0f, #0x09, #0x04, #0x04, #0x02, #0x02, #0x00 ; 055 - 7 57 | .db #0x00, #0x06, #0x09, #0x06, #0x09, #0x09, #0x06, #0x00 ; 056 - 8 58 | .db #0x00, #0x06, #0x09, #0x09, #0x0e, #0x08, #0x06, #0x00 ; 057 - 9 59 | .db #0x00, #0x00, #0x00, #0x04, #0x00, #0x00, #0x04, #0x00 ; 058 - : 60 | .db #0x00, #0x00, #0x00, #0x04, #0x00, #0x04, #0x04, #0x02 ; 059 - ; 61 | .db #0x00, #0x08, #0x04, #0x02, #0x02, #0x04, #0x08, #0x00 ; 060 - < 62 | .db #0x00, #0x00, #0x00, #0x0f, #0x00, #0x0f, #0x00, #0x00 ; 061 - = 63 | .db #0x00, #0x02, #0x04, #0x08, #0x08, #0x04, #0x02, #0x00 ; 062 - > 64 | .db #0x06, #0x09, #0x08, #0x04, #0x02, #0x00, #0x02, #0x00 ; 063 - ? 65 | .db #0x00, #0x06, #0x09, #0x0d, #0x0d, #0x01, #0x0e, #0x00 ; 064 - @ 66 | .db #0x00, #0x06, #0x09, #0x09, #0x0f, #0x09, #0x09, #0x00 ; 065 - A 67 | .db #0x00, #0x07, #0x09, #0x07, #0x09, #0x09, #0x07, #0x00 ; 066 - B 68 | .db #0x00, #0x0e, #0x01, #0x01, #0x01, #0x01, #0x0e, #0x00 ; 067 - C 69 | .db #0x00, #0x07, #0x09, #0x09, #0x09, #0x09, #0x07, #0x00 ; 068 - D 70 | .db #0x00, #0x0e, #0x01, #0x07, #0x01, #0x01, #0x0e, #0x00 ; 069 - E 71 | .db #0x00, #0x0e, #0x01, #0x01, #0x07, #0x01, #0x01, #0x00 ; 070 - F 72 | .db #0x00, #0x0e, #0x01, #0x0d, #0x09, #0x09, #0x0e, #0x00 ; 071 - G 73 | .db #0x00, #0x09, #0x09, #0x0f, #0x09, #0x09, #0x09, #0x00 ; 072 - H 74 | .db #0x00, #0x0e, #0x04, #0x04, #0x04, #0x04, #0x0e, #0x00 ; 073 - I 75 | .db #0x00, #0x0e, #0x04, #0x04, #0x04, #0x04, #0x03, #0x00 ; 074 - J 76 | .db #0x00, #0x09, #0x09, #0x07, #0x09, #0x09, #0x09, #0x00 ; 075 - K 77 | .db #0x00, #0x01, #0x01, #0x01, #0x01, #0x01, #0x0e, #0x00 ; 076 - L 78 | .db #0x00, #0x09, #0x0f, #0x0f, #0x09, #0x09, #0x09, #0x00 ; 077 - M 79 | .db #0x00, #0x09, #0x0b, #0x0b, #0x0d, #0x0d, #0x09, #0x00 ; 078 - N 80 | .db #0x00, #0x06, #0x09, #0x09, #0x09, #0x09, #0x06, #0x00 ; 079 - O 81 | .db #0x00, #0x07, #0x09, #0x09, #0x07, #0x01, #0x01, #0x00 ; 080 - P 82 | .db #0x00, #0x06, #0x09, #0x09, #0x09, #0x09, #0x06, #0x0c ; 081 - Q 83 | .db #0x00, #0x07, #0x09, #0x09, #0x07, #0x09, #0x09, #0x00 ; 082 - R 84 | .db #0x00, #0x0e, #0x01, #0x06, #0x08, #0x08, #0x07, #0x00 ; 083 - S 85 | .db #0x00, #0x1f, #0x04, #0x04, #0x04, #0x04, #0x04, #0x00 ; 084 - T 86 | .db #0x00, #0x09, #0x09, #0x09, #0x09, #0x09, #0x0e, #0x00 ; 085 - U 87 | .db #0x00, #0x09, #0x09, #0x09, #0x09, #0x06, #0x06, #0x00 ; 086 - V 88 | .db #0x00, #0x09, #0x09, #0x09, #0x0f, #0x0f, #0x09, #0x00 ; 087 - W 89 | .db #0x00, #0x09, #0x09, #0x06, #0x06, #0x09, #0x09, #0x00 ; 088 - X 90 | .db #0x00, #0x09, #0x09, #0x09, #0x0e, #0x08, #0x07, #0x00 ; 089 - Y 91 | .db #0x00, #0x0f, #0x08, #0x04, #0x02, #0x01, #0x0f, #0x00 ; 090 - Z 92 | .db #0x0e, #0x02, #0x02, #0x02, #0x02, #0x02, #0x02, #0x0e ; 091 - [ 93 | .db #0x01, #0x01, #0x02, #0x02, #0x04, #0x04, #0x08, #0x08 ; 092 - \ 94 | .db #0x0e, #0x08, #0x08, #0x08, #0x08, #0x08, #0x08, #0x0e ; 093 - ] 95 | .db #0x00, #0x04, #0x0a, #0x11, #0x00, #0x00, #0x00, #0x00 ; 094 - ^ 96 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x0f ; 095 - _ 97 | .db #0x02, #0x04, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 ; 096 - ` 98 | .db #0x00, #0x00, #0x06, #0x08, #0x0e, #0x09, #0x0e, #0x00 ; 097 - a 99 | .db #0x01, #0x01, #0x07, #0x09, #0x09, #0x09, #0x07, #0x00 ; 098 - b 100 | .db #0x00, #0x00, #0x0e, #0x01, #0x01, #0x01, #0x0e, #0x00 ; 099 - c 101 | .db #0x08, #0x08, #0x0e, #0x09, #0x09, #0x09, #0x0e, #0x00 ; 100 - d 102 | .db #0x00, #0x00, #0x0e, #0x09, #0x0f, #0x01, #0x0e, #0x00 ; 101 - e 103 | .db #0x0c, #0x02, #0x02, #0x07, #0x02, #0x02, #0x02, #0x00 ; 102 - f 104 | .db #0x00, #0x00, #0x0e, #0x09, #0x09, #0x06, #0x08, #0x07 ; 103 - g 105 | .db #0x01, #0x01, #0x07, #0x09, #0x09, #0x09, #0x09, #0x00 ; 104 - h 106 | .db #0x00, #0x04, #0x00, #0x04, #0x04, #0x04, #0x04, #0x00 ; 105 - i 107 | .db #0x00, #0x04, #0x00, #0x04, #0x04, #0x04, #0x04, #0x03 ; 106 - j 108 | .db #0x01, #0x01, #0x09, #0x05, #0x03, #0x05, #0x09, #0x00 ; 107 - k 109 | .db #0x02, #0x02, #0x02, #0x02, #0x02, #0x02, #0x0c, #0x00 ; 108 - l 110 | .db #0x00, #0x00, #0x09, #0x0f, #0x0f, #0x09, #0x09, #0x00 ; 109 - m 111 | .db #0x00, #0x00, #0x07, #0x09, #0x09, #0x09, #0x09, #0x00 ; 110 - n 112 | .db #0x00, #0x00, #0x06, #0x09, #0x09, #0x09, #0x06, #0x00 ; 111 - o 113 | .db #0x00, #0x00, #0x07, #0x09, #0x09, #0x07, #0x01, #0x01 ; 112 - p 114 | .db #0x00, #0x00, #0x0e, #0x09, #0x09, #0x0e, #0x08, #0x08 ; 113 - q 115 | .db #0x00, #0x00, #0x0e, #0x09, #0x01, #0x01, #0x01, #0x00 ; 114 - r 116 | .db #0x00, #0x00, #0x0e, #0x01, #0x06, #0x08, #0x07, #0x00 ; 115 - s 117 | .db #0x02, #0x02, #0x07, #0x02, #0x02, #0x02, #0x0c, #0x00 ; 116 - t 118 | .db #0x00, #0x00, #0x09, #0x09, #0x09, #0x09, #0x0e, #0x00 ; 117 - u 119 | .db #0x00, #0x00, #0x09, #0x09, #0x09, #0x06, #0x06, #0x00 ; 118 - v 120 | .db #0x00, #0x00, #0x09, #0x09, #0x0f, #0x0f, #0x09, #0x00 ; 119 - w 121 | .db #0x00, #0x00, #0x09, #0x06, #0x06, #0x09, #0x09, #0x00 ; 120 - x 122 | .db #0x00, #0x00, #0x09, #0x09, #0x09, #0x0e, #0x08, #0x07 ; 121 - y 123 | .db #0x00, #0x00, #0x0f, #0x08, #0x04, #0x02, #0x0f, #0x00 ; 122 - z 124 | .db #0x0c, #0x02, #0x02, #0x03, #0x03, #0x02, #0x02, #0x0c ; 123 - { 125 | .db #0x00, #0x04, #0x04, #0x04, #0x04, #0x04, #0x04, #0x00 ; 124 - | 126 | .db #0x03, #0x04, #0x04, #0x0c, #0x0c, #0x04, #0x04, #0x03 ; 125 - } 127 | .db #0x00, #0x12, #0x0d, #0x00, #0x00, #0x00, #0x00, #0x00 ; 126 - ~ 128 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 129 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 130 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 131 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 132 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 133 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 134 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 135 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 136 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 137 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 138 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 139 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 140 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 141 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 142 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 143 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 144 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 145 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 146 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 147 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 148 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 149 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 150 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 151 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 152 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 153 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 154 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 155 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 156 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 157 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 158 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 159 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 160 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 161 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 162 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 163 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 164 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 165 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 166 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 167 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 168 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 169 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 170 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 171 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 172 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 173 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 174 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 175 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 176 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 177 | .db #0x00, #0x15, #0x00, #0x15, #0x00, #0x15, #0x00, #0x15 178 | .db #0x0a, #0x15, #0x0a, #0x15, #0x0a, #0x15, #0x0a, #0x15 179 | .db #0x1f, #0x0a, #0x1f, #0x0a, #0x1f, #0x0a, #0x1f, #0x0a 180 | .db #0x04, #0x04, #0x04, #0x04, #0x04, #0x04, #0x04, #0x04 181 | .db #0x04, #0x04, #0x04, #0x04, #0x07, #0x04, #0x04, #0x04 182 | .db #0x04, #0x04, #0x04, #0x07, #0x04, #0x07, #0x04, #0x04 183 | .db #0x0a, #0x0a, #0x0a, #0x0a, #0x0b, #0x0a, #0x0a, #0x0a 184 | .db #0x00, #0x00, #0x00, #0x00, #0x0f, #0x0a, #0x0a, #0x0a 185 | .db #0x00, #0x00, #0x00, #0x07, #0x04, #0x07, #0x04, #0x04 186 | .db #0x0a, #0x0a, #0x0a, #0x0b, #0x08, #0x0b, #0x0a, #0x0a 187 | .db #0x0a, #0x0a, #0x0a, #0x0a, #0x0a, #0x0a, #0x0a, #0x0a 188 | .db #0x00, #0x00, #0x00, #0x0f, #0x08, #0x0b, #0x0a, #0x0a 189 | .db #0x0a, #0x0a, #0x0a, #0x0b, #0x08, #0x0f, #0x00, #0x00 190 | .db #0x0a, #0x0a, #0x0a, #0x0a, #0x0f, #0x00, #0x00, #0x00 191 | .db #0x04, #0x04, #0x04, #0x07, #0x04, #0x07, #0x00, #0x00 192 | .db #0x00, #0x00, #0x00, #0x00, #0x07, #0x04, #0x04, #0x04 193 | .db #0x04, #0x04, #0x04, #0x04, #0x3c, #0x00, #0x00, #0x00 194 | .db #0x04, #0x04, #0x04, #0x04, #0x3f, #0x00, #0x00, #0x00 195 | .db #0x00, #0x00, #0x00, #0x00, #0x3f, #0x04, #0x04, #0x04 196 | .db #0x04, #0x04, #0x04, #0x04, #0x3c, #0x04, #0x04, #0x04 197 | .db #0x00, #0x00, #0x00, #0x00, #0x3f, #0x00, #0x00, #0x00 198 | .db #0x04, #0x04, #0x04, #0x04, #0x3f, #0x04, #0x04, #0x04 199 | .db #0x04, #0x04, #0x04, #0x3c, #0x04, #0x3c, #0x04, #0x04 200 | .db #0x0a, #0x0a, #0x0a, #0x0a, #0x3a, #0x0a, #0x0a, #0x0a 201 | .db #0x0a, #0x0a, #0x0a, #0x3a, #0x02, #0x3e, #0x00, #0x00 202 | .db #0x00, #0x00, #0x00, #0x3e, #0x02, #0x3a, #0x0a, #0x0a 203 | .db #0x0a, #0x0a, #0x0a, #0x3b, #0x00, #0x3f, #0x00, #0x00 204 | .db #0x00, #0x00, #0x00, #0x3f, #0x00, #0x3b, #0x0a, #0x0a 205 | .db #0x0a, #0x0a, #0x0a, #0x3a, #0x02, #0x3a, #0x0a, #0x0a 206 | .db #0x00, #0x00, #0x00, #0x3f, #0x00, #0x3f, #0x00, #0x00 207 | .db #0x0a, #0x0a, #0x0a, #0x3b, #0x00, #0x3b, #0x0a, #0x0a 208 | .db #0x04, #0x04, #0x04, #0x3f, #0x00, #0x3f, #0x00, #0x00 209 | .db #0x0a, #0x0a, #0x0a, #0x3f, #0x00, #0x3f, #0x00, #0x00 210 | .db #0x00, #0x00, #0x00, #0x3f, #0x00, #0x3f, #0x04, #0x04 211 | .db #0x00, #0x00, #0x00, #0x00, #0x3f, #0x0a, #0x0a, #0x0a 212 | .db #0x0a, #0x0a, #0x0a, #0x0a, #0x3f, #0x00, #0x00, #0x00 213 | .db #0x04, #0x04, #0x04, #0x3c, #0x04, #0x3c, #0x00, #0x00 214 | .db #0x00, #0x00, #0x00, #0x3c, #0x04, #0x3c, #0x04, #0x04 215 | .db #0x00, #0x00, #0x00, #0x00, #0x3e, #0x0a, #0x0a, #0x0a 216 | .db #0x0a, #0x0a, #0x0a, #0x0a, #0x3f, #0x0a, #0x0a, #0x0a 217 | .db #0x04, #0x04, #0x04, #0x3f, #0x00, #0x3f, #0x04, #0x04 218 | .db #0x04, #0x04, #0x04, #0x04, #0x07, #0x00, #0x00, #0x00 219 | .db #0x00, #0x00, #0x00, #0x00, #0x3c, #0x04, #0x04, #0x04 220 | .db #0x1f, #0x1f, #0x1f, #0x1f, #0x1f, #0x1f, #0x1f, #0x1f 221 | .db #0x00, #0x00, #0x00, #0x1f, #0x1f, #0x1f, #0x1f, #0x1f 222 | .db #0x07, #0x07, #0x07, #0x07, #0x07, #0x07, #0x07, #0x07 223 | .db #0x1c, #0x1c, #0x1c, #0x1c, #0x1c, #0x1c, #0x1c, #0x1c 224 | .db #0x1f, #0x1f, #0x1f, #0x1f, #0x00, #0x00, #0x00, #0x00 225 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 226 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 227 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 228 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 229 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 230 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 231 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 232 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 233 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 234 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 235 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 236 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 237 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 238 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 239 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 240 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 241 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 242 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 243 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 244 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 245 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 246 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 247 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 248 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 249 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 250 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 251 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 252 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 253 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 254 | .db #0x0e, #0x08, #0x04, #0x0e, #0x00, #0x00, #0x00, #0x00 255 | .db #0x00, #0x00, #0x0f, #0x0f, #0x0f, #0x0f, #0x00, #0x00 256 | .db #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00, #0x00 257 | -------------------------------------------------------------------------------- /getchar.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8 2 | ; 3 | ; msTERM 4 | ; getchar and other keyboard routines 5 | ; 6 | ; Copyright (c) 2019 joshua stein 7 | ; 8 | ; Permission to use, copy, modify, and distribute this software for any 9 | ; purpose with or without fee is hereby granted, provided that the above 10 | ; copyright notice and this permission notice appear in all copies. 11 | ; 12 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | ; 20 | 21 | .module getchar 22 | 23 | .include "mailstation.inc" 24 | .globl _lptrecv 25 | 26 | .area _DATA 27 | 28 | ; scancode_table holds three tables of ascii characters which 29 | ; '_getchar' uses to determine which character to return, depending on 30 | ; the scancode pressed and the state of the shift and caps lock keys. 31 | .include "scancodes.inc" 32 | 33 | keyboardbuffer: 34 | .ds 2 ; scancode buffer for _getchar 35 | capslock: 36 | .db #0 37 | 38 | .area _CODE 39 | 40 | ; unsigned char peekkey(void) 41 | ; check for a scancode using the firmware, then look it up in the scancode 42 | ; table (respecting the shift key and caps lock as control) and return the 43 | ; ascii value of the key in the l register 44 | _peekkey:: 45 | ld de, #keyboardbuffer 46 | push de 47 | call get_keycode_from_buffer 48 | pop de 49 | ld a, (keyboardbuffer) ; check for caps lock first 50 | cp #0x60 51 | jr z, is_caps_lock 52 | jr not_caps_lock 53 | is_caps_lock: 54 | ld a, (keyboardbuffer + 1) ; check flags 55 | bit 0, a ; set=pressed, reset=released 56 | jp nz, caps_down 57 | ld a, #0 ; caps lock released 58 | ld (capslock), a 59 | jr nokey 60 | caps_down: 61 | ld a, #1 62 | ld (capslock), a 63 | jr nokey 64 | not_caps_lock: 65 | ld a, (keyboardbuffer + 1) ; check flags 66 | bit 0, a ; set=pressed, reset=released 67 | jp z, nokey ; key was released, bail 68 | bit 6, a ; when set, shift was held down 69 | jr z, lowercase 70 | capital: 71 | ld hl, #scancode_table_uppercase 72 | jr char_offset 73 | lowercase: 74 | ld a, (capslock) 75 | cp #1 76 | jr z, as_control 77 | ld hl, #scancode_table 78 | jr char_offset 79 | as_control: 80 | ld hl, #scancode_table_control 81 | jr char_offset 82 | char_offset: 83 | push hl 84 | ld hl, #50 85 | push hl 86 | call _delay 87 | pop hl 88 | pop hl 89 | ld a, (keyboardbuffer) 90 | ld b, #0 91 | ld c, a 92 | add hl, bc 93 | ld a, (hl) 94 | ld h, #0 95 | ld l, a 96 | ret 97 | nokey: 98 | ld h, #0 99 | ld l, #0 100 | ret 101 | 102 | 103 | ; unsigned char getkey(void) 104 | ; peekkey() but loops until a key is available 105 | _getkey:: 106 | call _peekkey 107 | ld a, l 108 | cp #0 109 | jp z, _getkey 110 | ret 111 | 112 | 113 | ; int getchar(void) 114 | ; uses _getkey and filters out non-printables, returns in l register 115 | _getchar:: 116 | call _getkey 117 | ld a, l 118 | cp a, #META_KEY_BEGIN 119 | jr nc, _getchar ; a >= 120 | ret 121 | -------------------------------------------------------------------------------- /isr.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8 2 | ; 3 | ; msTERM 4 | ; interrupt service routine 5 | ; 6 | ; Copyright (c) 2019 joshua stein 7 | ; 8 | ; Permission to use, copy, modify, and distribute this software for any 9 | ; purpose with or without fee is hereby granted, provided that the above 10 | ; copyright notice and this permission notice appear in all copies. 11 | ; 12 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | ; 20 | 21 | .module isr 22 | 23 | .include "mailstation.inc" 24 | .globl _modem_isr 25 | 26 | .equ isrjump, #0xf7 27 | .equ isrjumptable, #0xf800 28 | 29 | ; we're going to put 0xf7 at 0xf800 - 0xf8ff and then put 0xf8 in the 30 | ; 'i' register. when an interrupt happens in interrupt mode 2, some 31 | ; garbage byte will be on the bus and form an address 0xf800+garbage. 32 | ; the cpu will then read that address+1 which we know will contain 33 | ; 0xf7f7, and then jump to 0xf7f7, which we contain our own code, 34 | ; which will just be a 'jp isr' to our real ISR 35 | 36 | .area _CODE 37 | 38 | _patch_isr:: 39 | di 40 | 41 | ; spray isrjump from isrjumptable to (isrjumptable + 0xff + 1) 42 | ld hl, #isrjumptable 43 | ld a, #isrjump 44 | ld (hl), a 45 | ld de, #isrjumptable + 1 46 | ld bc, #0x0100 47 | ldir ; ld (de), (hl); dec bc until 0 48 | 49 | ; put our jump at isrjump+isrjump 50 | ld h, #isrjump 51 | ld l, #isrjump 52 | ld (hl), #0xc3 ; jp 53 | inc hl 54 | ex de, hl 55 | ld hl, #isr 56 | ld a, h 57 | ld b, l 58 | ex de, hl 59 | ld (hl), b ; lower address of isr 60 | inc hl 61 | ld (hl), a ; upper address of isr 62 | 63 | ld hl, #isrjumptable 64 | ld a, h 65 | ld i, a ; interrupts will now be #0xf800 + rand 66 | im 2 ; enable interrupt mode 2 67 | 68 | xor a ; clear interrupt mask 69 | set 7, a ; allow interrupt 7 for power button 70 | ;set 6, a ; 6 for modem 71 | ;set 5, a ; 5 for RTC 72 | set 2, a ; 2 for keyboard 73 | set 1, a ; 1 for keyboard 74 | ld hl, (p3shadow) 75 | ld (hl), a ; store this mask in p3shadow 76 | out (0x3), a 77 | ei ; here we go! 78 | ret 79 | 80 | isr: 81 | push af 82 | push bc 83 | push de 84 | push hl 85 | push ix 86 | push iy 87 | in a, (0x3) 88 | bit 7, a ; power button 89 | jp nz, 0x1940 90 | bit 6, a ; modem 91 | jp nz, isr_6 92 | in a, (0x3) ; why read again? factory isr does 93 | bit 1, a ; keyboard scan, 64hz 94 | jp nz, 0x18d4 ; use factory handler 95 | bit 2, a ; keyboard when button pressed 96 | jp nz, 0x18e7 ; use factory handler 97 | xor a ; any other interrupt, just ignore 98 | out (0x3), a 99 | jp isrout 100 | isr_7: 101 | ld hl, (p3shadow) 102 | ld a, (hl) 103 | res 7, a 104 | out (0x3), a ; reset interrupt 105 | ld a, (hl) 106 | out (0x3), a ; set mask back to p3shadow 107 | call 0x3b19 ; default power button handler 108 | jp isrout 109 | isr_6: 110 | ld hl, (p3shadow) 111 | ld a, (hl) 112 | res 6, a 113 | out (0x3), a ; reset interrupt 114 | ld a, (hl) 115 | out (0x3), a ; set mask back to p3shadow 116 | call _modem_isr 117 | jp isrout 118 | isrout: 119 | pop iy 120 | pop ix 121 | pop hl 122 | pop de 123 | pop bc 124 | pop af 125 | ei 126 | reti 127 | -------------------------------------------------------------------------------- /logo.ans: -------------------------------------------------------------------------------- 1 | _____ _____ _____ _____ 2 | _____ ___|_ _| __| __ | | 3 | | |_ -| | | | __| -| | | | 4 | |_|_|_|___| |_| |_____|__|__|_|_|_| 5 | -------------------------------------------------------------------------------- /lpt.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8 2 | ; 3 | ; msTERM 4 | ; parallel port routines 5 | ; 6 | ; Copyright (c) 2019 joshua stein 7 | ; 8 | ; Permission to use, copy, modify, and distribute this software for any 9 | ; purpose with or without fee is hereby granted, provided that the above 10 | ; copyright notice and this permission notice appear in all copies. 11 | ; 12 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | ; 20 | 21 | .module lpt 22 | 23 | .include "mailstation.inc" 24 | 25 | .equ CONTROL, #0x2c 26 | .equ DATA, #0x2d 27 | .equ STATUS, #0x21 28 | 29 | .equ LPT_BUSY_IN, #0x40 30 | .equ LPT_BUSY_OUT, #0x08 31 | .equ LPT_STROBE_IN, #0x80 32 | .equ LPT_STROBE_OUT, #0x10 33 | .equ LPT_TRIB_MASK, #0x07 34 | .equ LPT_DIB_MASK, #0x03 35 | 36 | .area _CODE 37 | 38 | ; receive a tribble byte from host, return h=1 l=0 on error, else h=0, l=(byte) 39 | lptrecv_tribble: 40 | push bc 41 | ld hl, #0 ; h will contain error, l result 42 | xor a 43 | out (DATA), a ; drop busy/ack, wait for strobe 44 | ld b, #0xff ; try a bunch before bailing 45 | wait_for_strobe: 46 | in a, (STATUS) 47 | and #LPT_STROBE_IN ; inb(STATUS) & stbin 48 | jr nz, got_strobe 49 | djnz wait_for_strobe 50 | strobe_failed: 51 | ld h, #1 52 | ld l, #0 53 | jr lptrecv_tribble_out 54 | got_strobe: 55 | in a, (STATUS) 56 | sra a 57 | sra a 58 | sra a 59 | and #LPT_TRIB_MASK ; & tribmask 60 | ld l, a 61 | ld a, #LPT_BUSY_OUT ; raise busy/ack 62 | out (DATA), a 63 | ld b, #0xff ; retry 255 times 64 | wait_for_unstrobe: 65 | in a, (STATUS) 66 | and #LPT_STROBE_IN ; inb(STATUS) & stbin 67 | jr z, lptrecv_tribble_out 68 | djnz wait_for_unstrobe 69 | ; if we never get unstrobe, that's ok 70 | lptrecv_tribble_out: 71 | ld a, #LPT_BUSY_OUT ; raise busy/ack 72 | out (DATA), a 73 | pop bc 74 | ret 75 | 76 | 77 | ; unsigned char lptrecv(void) 78 | ; receive a full byte from host in three parts 79 | ; return h=1 l=0 on error, otherwise h=0, l=(byte) 80 | _lptrecv:: 81 | push bc 82 | call lptrecv_tribble 83 | ld a, h 84 | cp #1 85 | jr z, lptrecv_err ; bail early if h has an error 86 | ld b, l 87 | call lptrecv_tribble 88 | ld a, h 89 | cp #1 90 | jr z, lptrecv_err 91 | ld a, l 92 | sla a 93 | sla a 94 | sla a 95 | add b 96 | ld b, a ; += tribble << 3 97 | call lptrecv_tribble 98 | ld a, h 99 | cp #1 100 | jr z, lptrecv_err 101 | ld a, l 102 | and #LPT_DIB_MASK ; dibmask 103 | sla a 104 | sla a 105 | sla a 106 | sla a 107 | sla a 108 | sla a 109 | add b ; += (tribble & dibmask) << 6 110 | ld h, #0 111 | ld l, a 112 | lptrecv_out: 113 | pop bc 114 | ret 115 | lptrecv_err: 116 | pop bc 117 | ld hl, #0x0100 118 | ret 119 | 120 | 121 | ; send a tribble byte in register l to host, return l=0 on success 122 | lptsend_tribble: 123 | push bc 124 | ld h, #1 125 | ld c, #0xff ; 255*255 tries before bailing 126 | wait_for_busy_drop_outer: 127 | ld b, #0xff 128 | wait_for_busy_drop: 129 | in a, (STATUS) 130 | and #LPT_BUSY_IN ; inb(STATUS) & bsyin 131 | jr z, got_busy_drop 132 | djnz wait_for_busy_drop 133 | dec c 134 | ld a, c 135 | cp #0 136 | jr nz, wait_for_busy_drop_outer 137 | busy_drop_failed: 138 | jr lptsend_tribble_out 139 | got_busy_drop: 140 | ld a, l 141 | and #LPT_TRIB_MASK 142 | or #LPT_STROBE_OUT 143 | out (DATA), a 144 | ld c, #0xff ; try 255*255 tries before bailing 145 | wait_for_ack_outer: 146 | ld b, #0xff 147 | wait_for_ack: 148 | in a, (STATUS) 149 | and #LPT_BUSY_IN ; inb(STATUS) & stbin 150 | jr nz, lptsend_unstrobe 151 | djnz wait_for_ack 152 | dec c 153 | ld a, c 154 | cp #0 155 | jr nz, wait_for_ack_outer 156 | jr lptsend_tribble_out 157 | lptsend_unstrobe: 158 | ld a, #1 159 | out (DATA), a 160 | ld h, #0 ; success 161 | lptsend_tribble_out: 162 | ld a, #LPT_BUSY_OUT ; raise busy/ack 163 | out (DATA), a 164 | pop bc 165 | ld l, h ; l=1 error, l=0 success 166 | ld h, #0 167 | ret 168 | 169 | 170 | ; unsigned int lptsend(unsigned char b) 171 | ; returns 0 on success 172 | _lptsend:: 173 | push ix 174 | ld ix, #0 175 | add ix, sp 176 | ld l, 4(ix) ; char to send 177 | push hl 178 | call lptsend_tribble 179 | ld a, l 180 | pop hl 181 | cp #0 182 | jr z, tribble2 183 | ld hl, #0x1 184 | jr lptsend_error 185 | tribble2: 186 | push hl 187 | sra l 188 | sra l 189 | sra l ; b >> 3 190 | call lptsend_tribble 191 | ld a, l 192 | pop hl 193 | cp #0 194 | jr z, tribble3 195 | ld hl, #0x2 196 | jr lptsend_error 197 | tribble3: 198 | sra l 199 | sra l 200 | sra l 201 | sra l 202 | sra l 203 | sra l ; b >> 6 204 | call lptsend_tribble 205 | ld a, l 206 | cp #0 207 | jr z, lptsend_out 208 | ld hl, #0x3 209 | jr lptsend_error 210 | lptsend_out: 211 | ld hl, #0 212 | ld sp, ix 213 | pop ix 214 | ret 215 | lptsend_error: 216 | ld sp, ix 217 | pop ix 218 | ret 219 | 220 | 221 | ; send pushed 16-bit as two bytes 222 | _lptsend16:: 223 | push ix 224 | ld ix, #0 225 | add ix, sp 226 | push hl 227 | ld h, #0 228 | ld l, 5(ix) 229 | push hl 230 | call _lptsend 231 | pop hl 232 | ld l, 4(ix) 233 | push hl 234 | call _lptsend 235 | pop hl 236 | pop hl 237 | ld sp, ix 238 | pop ix 239 | ret 240 | -------------------------------------------------------------------------------- /mailstation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * msTERM 3 | * 4 | * Copyright (c) 2019 joshua stein 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef _INCL_MAILSTATION 20 | #define _INCL_MAILSTATION 21 | 22 | #include "meta_keys.h" 23 | 24 | /* define some ports - see 0x1b2b */ 25 | __sfr __at(0x01) portkeyboard; 26 | __sfr __at(0x02) port2; 27 | __sfr __at(0x05) slot4000page; 28 | __sfr __at(0x06) slot4000device; 29 | __sfr __at(0x07) slot8000page; 30 | __sfr __at(0x08) slot8000device; 31 | __sfr __at(0x09) portpowerstatus; 32 | __sfr __at(0x0d) portcpuclockrate; 33 | __sfr __at(0x10) rtcseconds; 34 | __sfr __at(0x11) rtc10seconds; 35 | __sfr __at(0x12) rtcminutes; 36 | __sfr __at(0x13) rtc10minutes; 37 | __sfr __at(0x14) rtchours; 38 | __sfr __at(0x15) rtc10hours; 39 | __sfr __at(0x16) rtcdayofweek; 40 | __sfr __at(0x17) rtcdays; 41 | __sfr __at(0x18) rtc10days; 42 | __sfr __at(0x19) rtcmonths; 43 | __sfr __at(0x1a) rtc10months; 44 | __sfr __at(0x1b) rtcyears; 45 | __sfr __at(0x1c) rtc10years; 46 | __sfr __at(0x28) port28; 47 | 48 | /* be sure to keep these in sync with mailstation.inc */ 49 | #define SOURCE_WIFI 0 50 | #define SOURCE_MODEM 1 51 | #define SOURCE_LPT 2 52 | #define SOURCE_ECHO 3 53 | #define SOURCE_LAST 4 54 | 55 | /* LCD parameters (2 screens) */ 56 | #define LCD_WIDTH (160 * 2) // 320 57 | #define LCD_HEIGHT 128 58 | #define LCD_COL_GROUPS 20 59 | #define LCD_COL_GROUP_WIDTH 8 60 | 61 | #define FONT_WIDTH 5 62 | #define FONT_HEIGHT 8 63 | 64 | /* columns of characters */ 65 | #define LCD_COLS (LCD_WIDTH / FONT_WIDTH) // 64 66 | #define LCD_ROWS (LCD_HEIGHT / FONT_HEIGHT) // 16 67 | #define TEXT_COLS LCD_COLS // 64 68 | #define TEXT_ROWS (LCD_ROWS - 1) // 15 69 | 70 | #define ATTR_CURSOR (1 << 0) 71 | #define ATTR_REVERSE (1 << 1) 72 | #define ATTR_BOLD (1 << 2) 73 | #define ATTR_UNDERLINE (1 << 3) 74 | 75 | /* for printf */ 76 | #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" 77 | #define BYTE_TO_BINARY(byte) \ 78 | (byte & 0x80 ? '1' : '0'), \ 79 | (byte & 0x40 ? '1' : '0'), \ 80 | (byte & 0x20 ? '1' : '0'), \ 81 | (byte & 0x10 ? '1' : '0'), \ 82 | (byte & 0x08 ? '1' : '0'), \ 83 | (byte & 0x04 ? '1' : '0'), \ 84 | (byte & 0x02 ? '1' : '0'), \ 85 | (byte & 0x01 ? '1' : '0') 86 | 87 | #define ESC 0x1b // \e 88 | #define XON 0x11 // ^Q 89 | #define XOFF 0x13 // ^S 90 | 91 | 92 | /* for debugging access from asm */ 93 | extern unsigned char debug0; 94 | extern unsigned char debug1; 95 | extern unsigned char debug2; 96 | extern unsigned char debug3; 97 | extern unsigned char debug4; 98 | 99 | 100 | /* crt0.s */ 101 | extern unsigned char msTERM_version; 102 | extern void exit(void); 103 | extern void powerdown(void); 104 | extern void new_mail(unsigned char on); 105 | extern void reboot(void); 106 | extern void delay(unsigned int millis); 107 | extern void blink(unsigned int millis); 108 | extern void panic(void); 109 | extern void lcd_paint(void); 110 | extern unsigned char read_port(unsigned char port); 111 | 112 | 113 | /* mslib.c */ 114 | extern void uitoa(unsigned int value, char *string, int radix); 115 | extern void itoa(int value, char *string, int radix); 116 | 117 | 118 | /* csi.c */ 119 | extern unsigned char saved_cursorx; 120 | extern unsigned char saved_cursory; 121 | extern void parseCSI(void); 122 | extern unsigned char in_csi; 123 | extern unsigned char csibuf[TEXT_COLS]; 124 | extern unsigned int csibuflen; 125 | 126 | 127 | /* putchar.s */ 128 | extern unsigned char cursorx; 129 | extern unsigned char cursory; 130 | extern unsigned char putchar_sgr; 131 | extern unsigned char putchar_quick; 132 | extern unsigned char *font_addr; 133 | extern void lcd_cas(unsigned char col); 134 | extern void lcd_sleep(void); 135 | extern void lcd_wake(void); 136 | extern void uncursor(void); 137 | extern void recursor(void); 138 | extern void clear_screen(void); 139 | extern void clear_screen_bufs(void); 140 | extern void redraw_screen(void); 141 | extern void scroll_lcd_half(void); 142 | extern void clear_lcd_half(void); 143 | extern void stamp_char(unsigned char row, unsigned char col); 144 | extern void putchar_attr(unsigned char row, unsigned char col, unsigned char c, 145 | unsigned char attr); 146 | 147 | 148 | /* getchar.s */ 149 | extern unsigned char getscancode(unsigned char *charbuffer); 150 | extern int getkey(void); 151 | extern int peekkey(void); 152 | 153 | 154 | /* isr.s */ 155 | extern void patch_isr(void); 156 | 157 | 158 | /* lpt.s */ 159 | extern unsigned char lptsend(unsigned char b); 160 | extern int lptrecv(void); 161 | 162 | 163 | /* mailstation.c */ 164 | extern unsigned char *firmware_version; 165 | extern void setup(void); 166 | 167 | 168 | /* modem.s */ 169 | extern volatile unsigned char modem_buf[]; 170 | extern volatile unsigned char modem_buf_pos; 171 | extern volatile unsigned char modem_buf_read_pos; 172 | extern volatile unsigned char modem_curmsr; 173 | extern void modem_init(void); 174 | extern void modem_powerdown(void); 175 | extern int modem_ier(void); 176 | extern int modem_iir(void); 177 | extern int modem_lcr(void); 178 | extern int modem_lsr(void); 179 | extern int modem_msr(void); 180 | extern char modem_read(void); 181 | extern void modem_write(char c); 182 | extern void modem_hangup(void); 183 | 184 | 185 | /* msterm.c */ 186 | extern volatile unsigned char mem0; 187 | extern volatile unsigned char obuf[]; 188 | extern volatile unsigned char obuf_pos; 189 | extern void update_statusbar(char which, char *status, ...); 190 | 191 | 192 | /* settings.s */ 193 | extern volatile unsigned int setting_modem_speed; 194 | extern volatile unsigned char setting_default_source; 195 | extern void settings_read(void); 196 | extern void settings_write(void); 197 | 198 | 199 | /* wifi.s */ 200 | void wifi_init(void); 201 | extern int wifi_write(char); 202 | extern int wifi_read(void); 203 | 204 | #endif 205 | -------------------------------------------------------------------------------- /mailstation.inc: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8:sw=8 2 | 3 | .equ VERSION, #0x4 4 | 5 | ; these are defined in addrs-*, either of which is linked into the 6 | ; build based on where we're running from 7 | .globl RUN_ADDR 8 | .globl RUN_DEVICE 9 | .globl RUN_PAGE 10 | .globl SLOT_ADDR 11 | .globl SLOT_DEVICE 12 | .globl SLOT_PAGE 13 | 14 | ; per-firmware version port shadow variables 15 | .globl p2shadow 16 | .globl p3shadow 17 | .globl p28shadow 18 | 19 | ; functions 20 | .equ get_keycode_from_buffer,#0x0a9a 21 | .equ lcd_buf_to_screen, #0x2473 22 | 23 | ; lcd bit storage buffer, copied with lcd_buf_to_screen 24 | .equ lcd_buf, #0xc010 25 | .equ lcd_buf_end, #lcd_buf + ((LCD_WIDTH * LCD_HEIGHT) / 8) - 1 26 | 27 | ; circular char[] buffer offset by *_modem_buf_pos 28 | .equ _modem_buf, #0xf600 29 | .equ _modem_buf_pos, #0xf700 30 | .equ _modem_buf_read_pos, #0xf702 31 | 32 | .equ _obuf, #0xf500 33 | .equ _obuf_pos, #0xf704 34 | 35 | ; some random dataflash location (0x18000) that looked empty 36 | .equ settings_page, #6 37 | .equ settings_sector, #0 ; sectors are 256 bytes 38 | 39 | ; some constants from mailstion.h 40 | .equ LCD_WIDTH, #160 * 2 ; 320 41 | .equ LCD_HEIGHT, #128 42 | .equ LCD_COL_GROUPS, #20 43 | .equ LCD_COL_GROUP_WIDTH, #8 44 | .equ FONT_WIDTH, #5 45 | .equ FONT_HEIGHT, #8 46 | .equ LCD_COLS, #LCD_WIDTH / FONT_WIDTH ; 64 47 | .equ LCD_ROWS, #LCD_HEIGHT / FONT_HEIGHT ; 16 48 | .equ TEXT_ROWS, #LCD_ROWS - 1 ; 15 49 | 50 | .equ DEVICE_RAM, #0x01 51 | .equ DEVICE_LCD_LEFT, #0x02 52 | .equ DEVICE_DATAFLASH, #0x03 53 | .equ DEVICE_LCD_RIGHT, #0x04 54 | .equ DEVICE_MODEM, #0x05 55 | 56 | ; addressing the LCD once it's loaded in SLOT_ADDR 57 | .equ LCD_START, #SLOT_ADDR + 0x0038 58 | 59 | .equ ATTR_BIT_CURSOR, #0 60 | .equ ATTR_BIT_REVERSE, #1 61 | .equ ATTR_BIT_BOLD, #2 62 | .equ ATTR_BIT_UNDERLINE, #3 63 | 64 | .equ ATTR_CURSOR, #(1 << ATTR_CURSOR) 65 | .equ ATTR_REVERSE, #(1 << ATTR_REVERSE) 66 | .equ ATTR_BOLD, #(1 << ATTR_BOLD) 67 | .equ ATTR_UNDERLINE, #(1 << ATTR_UNDERLINE) 68 | 69 | .equ MODEM_DEFAULT_SPEED, #14400 70 | .equ ESC, #0x1b 71 | .equ XON, #0x11 72 | .equ XOFF, #0x13 73 | 74 | ; be sure to keep these in sync with mailstation.h 75 | .equ SOURCE_WIFI, #0 76 | .equ SOURCE_MODEM, #1 77 | .equ SOURCE_LPT, #2 78 | .equ SOURCE_ECHO, #3 79 | .equ SOURCE_LAST, #4 80 | 81 | .globl _saved_cursorx 82 | .globl _saved_cursory 83 | .globl _delay 84 | 85 | ; settings 86 | .globl _setting_modem_speed 87 | .globl _setting_default_source 88 | 89 | .globl _modem_buf 90 | .globl _modem_buf_pos 91 | .globl _modem_buf_read_pos 92 | .globl _modem_curmsr 93 | .globl _modem_flowing 94 | 95 | .globl _obuf 96 | .globl _obuf_pos 97 | 98 | ; debug variables 99 | .globl _debug0 100 | .globl _debug1 101 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * msTERM 3 | * 4 | * Copyright (c) 2019 joshua stein 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "mailstation.h" 24 | #include "logo.h" 25 | 26 | unsigned char last_key; 27 | unsigned char esc; 28 | unsigned char old_minutes; 29 | unsigned char obuf_sent_pos; 30 | unsigned char last_modem_msr; 31 | 32 | #define MODEM_MSR_DCD (1 << 7) 33 | 34 | int process_keyboard(void); 35 | void process_input(unsigned char b); 36 | void update_clock(void); 37 | void update_f1(void); 38 | void obuf_flush(void); 39 | void wifi_hangup(void); 40 | 41 | unsigned char source; 42 | 43 | enum { 44 | STATUSBAR_F1, 45 | STATUSBAR_F2, 46 | STATUSBAR_F3, 47 | STATUSBAR_F4, 48 | STATUSBAR_F5, 49 | STATUSBAR_INIT, 50 | }; 51 | 52 | void 53 | obuf_queue(unsigned char *c) 54 | { 55 | unsigned char x; 56 | 57 | for (x = 0; c[x] != '\0'; x++) 58 | obuf[obuf_pos++] = c[x]; 59 | } 60 | 61 | int 62 | main(void) 63 | { 64 | unsigned char ms[10]; 65 | unsigned char shown_logo; 66 | int b, j; 67 | 68 | /* ignore first peekkey() if it returns power button */ 69 | last_key = KEY_POWER; 70 | esc = 0; 71 | putchar_sgr = 0; 72 | in_csi = 0; 73 | csibuflen = 0; 74 | obuf_pos = 0; 75 | obuf_sent_pos = 0; 76 | debug0 = 0; 77 | shown_logo = 0; 78 | 79 | patch_isr(); 80 | 81 | settings_read(); 82 | source = setting_default_source; 83 | if (source >= SOURCE_LAST) 84 | source = SOURCE_WIFI; 85 | 86 | clear_screen_bufs(); 87 | clear_screen(); 88 | update_statusbar(STATUSBAR_INIT, NULL); 89 | 90 | begin: 91 | if (source == SOURCE_WIFI) 92 | /* call this early to sleep while we draw the logo */ 93 | wifi_init(); 94 | 95 | if (!shown_logo) { 96 | /* - 1 to ignore final null byte */ 97 | for (b = 0; b < sizeof(logo) - 1; b++) { 98 | if (b == 0 || logo[b - 1] == '\n') { 99 | /* center without wasting space in logo[] */ 100 | for (j = 0; j < 14; j++) 101 | putchar(' '); 102 | } 103 | 104 | putchar(logo[b]); 105 | } 106 | printf(" v%u\n\n", msTERM_version); 107 | shown_logo = 1; 108 | } 109 | 110 | old_minutes = 0xff; 111 | update_clock(); 112 | 113 | update_f1(); 114 | 115 | switch (source) { 116 | case SOURCE_MODEM: 117 | modem_init(); 118 | 119 | /* Restore factory configuration 0 */ 120 | obuf_queue("AT&F0"); 121 | /* Select modulation - V.34, automode, min_rate */ 122 | obuf_queue("+MS=11,1,300,"); 123 | /* max_rate */ 124 | itoa(setting_modem_speed, ms, 10); 125 | obuf_queue(ms); 126 | /* Turn speaker on */ 127 | obuf_queue("M1"); 128 | /* Set low speaker volume */ 129 | obuf_queue("L0"); 130 | /* Allow result codes to DTE */ 131 | obuf_queue("Q0"); 132 | /* Enable transparent XON/XOFF flow control */ 133 | obuf_queue("&K5\r"); 134 | break; 135 | case SOURCE_WIFI: 136 | obuf_queue("\rAT\r"); 137 | obuf_flush(); 138 | break; 139 | } 140 | 141 | obuf_flush(); 142 | 143 | for (;;) { 144 | b = process_keyboard(); 145 | if (b == KEY_F4) 146 | /* we changed sources */ 147 | goto begin; 148 | 149 | switch (source) { 150 | case SOURCE_MODEM: 151 | if (modem_msr() != last_modem_msr) { 152 | update_f1(); 153 | last_modem_msr = modem_curmsr; 154 | } 155 | if (modem_lsr() & (1 << 0)) { 156 | process_input(modem_read()); 157 | continue; 158 | } 159 | break; 160 | case SOURCE_LPT: 161 | b = lptrecv(); 162 | if (b <= 0xff) { 163 | process_input(b & 0xff); 164 | continue; 165 | } 166 | break; 167 | case SOURCE_WIFI: 168 | b = wifi_read(); 169 | if (b != -1) { 170 | process_input(b & 0xff); 171 | continue; 172 | } 173 | break; 174 | } 175 | 176 | if (obuf_sent_pos != obuf_pos) 177 | obuf_flush(); 178 | 179 | update_clock(); 180 | } 181 | 182 | return 0; 183 | } 184 | 185 | void 186 | update_statusbar(char which, char *status, ...) 187 | { 188 | va_list args; 189 | char tstatus[64]; 190 | char *result = NULL; 191 | unsigned char i, l; 192 | 193 | if (which == STATUSBAR_INIT) { 194 | for (i = 0; i < LCD_COLS; i++) 195 | putchar_attr(LCD_ROWS - 1, i, 196 | ((i + 1) % 13 == 0 ? '|' : ' '), ATTR_REVERSE); 197 | return; 198 | } 199 | 200 | va_start(args, status); 201 | l = vsprintf(tstatus, status, args); 202 | va_end(args); 203 | 204 | if (l > sizeof(tstatus)) { 205 | new_mail(1); 206 | panic(); 207 | } 208 | 209 | for (i = 0; i < l; i++) { 210 | putchar_attr(LCD_ROWS - 1, (which * 13) + i, tstatus[i], 211 | ATTR_REVERSE); 212 | } 213 | } 214 | 215 | void 216 | update_clock(void) 217 | { 218 | static const char modem_s[] = "Modem"; 219 | static const char wifi_s[] = "WiFi "; 220 | 221 | if (rtcminutes == old_minutes) 222 | return; 223 | 224 | update_statusbar(STATUSBAR_F4, " %s ", 225 | (source == SOURCE_MODEM ? modem_s: wifi_s)); 226 | update_statusbar(STATUSBAR_F5, " %02d:%02d ", 227 | (rtc10hours * 10) + rtchours, 228 | (rtc10minutes * 10) + rtcminutes); 229 | 230 | old_minutes = rtcminutes; 231 | } 232 | 233 | void 234 | update_f1(void) 235 | { 236 | unsigned char s = 0; 237 | 238 | if (source == SOURCE_MODEM) { 239 | if (modem_curmsr & MODEM_MSR_DCD) 240 | update_statusbar(STATUSBAR_F1, " Hangup "); 241 | else 242 | update_statusbar(STATUSBAR_F1, " No Carrier"); 243 | } else if (source == SOURCE_WIFI) { 244 | update_statusbar(STATUSBAR_F1, " Hangup "); 245 | } 246 | } 247 | 248 | int 249 | process_keyboard(void) 250 | { 251 | unsigned char b; 252 | 253 | b = peekkey(); 254 | 255 | /* this breaks key-repeat, but it's needed to debounce */ 256 | if (b == 0) 257 | last_key = 0; 258 | else if (b == last_key) 259 | b = 0; 260 | else 261 | last_key = b; 262 | 263 | if (b == 0) 264 | return 0; 265 | 266 | switch (b) { 267 | case KEY_POWER: 268 | /* not sure why the delay is needed to actually power down */ 269 | clear_screen(); 270 | delay(200); 271 | powerdown(); 272 | break; 273 | case KEY_F1: 274 | if (source == SOURCE_MODEM) { 275 | if (modem_curmsr & MODEM_MSR_DCD) 276 | modem_hangup(); 277 | } else if (source == SOURCE_WIFI) { 278 | wifi_hangup(); 279 | } 280 | break; 281 | case KEY_F4: 282 | if (source == SOURCE_MODEM) { 283 | printf("\nHanging up modem...\n"); 284 | modem_hangup(); 285 | modem_powerdown(); 286 | printf("\nSwitching to WiFiStation...\n"); 287 | source = SOURCE_WIFI; 288 | } else if (source == SOURCE_WIFI) { 289 | printf("\nDisconnecting WiFiStation...\n"); 290 | wifi_hangup(); 291 | printf("\nSwitching to modem...\n"); 292 | source = SOURCE_MODEM; 293 | } 294 | setting_default_source = source; 295 | settings_write(); 296 | break; 297 | case KEY_MAIN_MENU: 298 | /* send escape */ 299 | obuf[obuf_pos++] = ESC; 300 | break; 301 | case KEY_EMAIL: 302 | reboot(); 303 | break; 304 | case KEY_PAGE_UP: 305 | obuf[obuf_pos++] = ESC; 306 | obuf[obuf_pos++] = '['; 307 | obuf[obuf_pos++] = '5'; 308 | obuf[obuf_pos++] = '~'; 309 | break; 310 | case KEY_PAGE_DOWN: 311 | obuf[obuf_pos++] = ESC; 312 | obuf[obuf_pos++] = '['; 313 | obuf[obuf_pos++] = '6'; 314 | obuf[obuf_pos++] = '~'; 315 | break; 316 | case KEY_UP: 317 | obuf[obuf_pos++] = ESC; 318 | obuf[obuf_pos++] = '['; 319 | obuf[obuf_pos++] = 'A'; 320 | break; 321 | case KEY_DOWN: 322 | obuf[obuf_pos++] = ESC; 323 | obuf[obuf_pos++] = '['; 324 | obuf[obuf_pos++] = 'B'; 325 | break; 326 | case KEY_LEFT: 327 | obuf[obuf_pos++] = ESC; 328 | obuf[obuf_pos++] = '['; 329 | obuf[obuf_pos++] = 'D'; 330 | break; 331 | case KEY_RIGHT: 332 | obuf[obuf_pos++] = ESC; 333 | obuf[obuf_pos++] = '['; 334 | obuf[obuf_pos++] = 'C'; 335 | break; 336 | case KEY_SIZE: 337 | redraw_screen(); 338 | update_f1(); 339 | break; 340 | default: 341 | if (b >= META_KEY_BEGIN) 342 | return 0; 343 | 344 | if (b == '\n') 345 | b = '\r'; 346 | 347 | obuf[obuf_pos++] = b; 348 | } 349 | 350 | return b; 351 | } 352 | 353 | void 354 | process_input(unsigned char b) 355 | { 356 | if (in_csi) { 357 | if (csibuflen >= sizeof(csibuf) - 1) { 358 | /* going to overflow, dump */ 359 | parseCSI(); 360 | in_csi = 0; 361 | esc = 0; 362 | csibuf[0] = '\0'; 363 | csibuflen = 0; 364 | } 365 | 366 | if (b == ESC) { 367 | /* esc, maybe new csi, dump previous */ 368 | parseCSI(); 369 | in_csi = 0; 370 | esc = 1; 371 | csibuf[0] = '\0'; 372 | csibuflen = 0; 373 | } else { 374 | csibuf[csibuflen] = b; 375 | csibuflen++; 376 | parseCSI(); 377 | } 378 | 379 | return; 380 | } 381 | 382 | switch (b) { 383 | case 7: /* visual bell, ping 'new mail' light */ 384 | new_mail(1); 385 | delay(150); 386 | new_mail(0); 387 | break; 388 | case 9: /* tab */ 389 | while ((cursorx + 1) % 8 != 0) 390 | putchar(' '); 391 | break; 392 | case 26: /* ^Z end of ansi */ 393 | break; 394 | case ESC: /* esc */ 395 | if (esc) 396 | /* our previous esc is literal */ 397 | putchar(b); 398 | esc = 1; 399 | break; 400 | case 91: /* [ */ 401 | if (esc) { 402 | esc = 0; 403 | in_csi = 1; 404 | break; 405 | } 406 | /* fall through */ 407 | default: 408 | putchar(b); 409 | } 410 | } 411 | 412 | void 413 | obuf_flush(void) 414 | { 415 | int b; 416 | 417 | while (obuf_sent_pos != obuf_pos) { 418 | switch (source) { 419 | case SOURCE_MODEM: 420 | if (modem_lsr() & (1 << 5)) 421 | /* Transmitter Holding Register Empty */ 422 | modem_write(obuf[obuf_sent_pos++]); 423 | break; 424 | case SOURCE_LPT: 425 | lptsend(obuf[obuf_sent_pos++]); 426 | break; 427 | case SOURCE_ECHO: 428 | putchar(obuf[obuf_sent_pos++]); 429 | break; 430 | case SOURCE_WIFI: 431 | if (wifi_write(obuf[obuf_sent_pos]) == -1) { 432 | if ((b = wifi_read()) != -1) 433 | process_input(b & 0xff); 434 | } else 435 | obuf_sent_pos++; 436 | break; 437 | } 438 | } 439 | } 440 | 441 | void 442 | wifi_hangup(void) 443 | { 444 | obuf[obuf_pos++] = '+'; 445 | obuf[obuf_pos++] = '+'; 446 | obuf[obuf_pos++] = '+'; 447 | obuf_flush(); 448 | delay(800); 449 | obuf[obuf_pos++] = 'A'; 450 | obuf[obuf_pos++] = 'T'; 451 | obuf[obuf_pos++] = 'H'; 452 | obuf[obuf_pos++] = '\r'; 453 | obuf_flush(); 454 | } 455 | -------------------------------------------------------------------------------- /meta_keys.h: -------------------------------------------------------------------------------- 1 | /* AUTOMATICALLY GENERATED FILE - see tools/generate_scancodes.rb */ 2 | #define META_KEY_BEGIN 200 3 | #define KEY_MAIN_MENU 200 4 | #define KEY_BACK 201 5 | #define KEY_PRINT 202 6 | #define KEY_F1 203 7 | #define KEY_F2 204 8 | #define KEY_F3 205 9 | #define KEY_F4 206 10 | #define KEY_F5 207 11 | #define KEY_POWER 208 12 | #define KEY_SIZE 209 13 | #define KEY_SPELLING 210 14 | #define KEY_EMAIL 211 15 | #define KEY_PAGE_UP 212 16 | #define KEY_PAGE_DOWN 213 17 | #define KEY_CAPS_LOCK 214 18 | #define KEY_LEFT_SHIFT 215 19 | #define KEY_RIGHT_SHIFT 216 20 | #define KEY_FN 217 21 | #define KEY_UP 218 22 | #define KEY_DOWN 219 23 | #define KEY_LEFT 220 24 | #define KEY_RIGHT 221 25 | 26 | #define META_KEY_NONE 255 27 | -------------------------------------------------------------------------------- /modem.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8 2 | ; 3 | ; msTERM 4 | ; modem routines for Rockwell RCV336DPFSP 5 | ; https://github.com/jcs/mailstation-tools/blob/master/docs/modem-RCV336DPFSP.pdf 6 | ; 7 | ; Copyright (c) 2019 joshua stein 8 | ; 9 | ; Permission to use, copy, modify, and distribute this software for any 10 | ; purpose with or without fee is hereby granted, provided that the above 11 | ; copyright notice and this permission notice appear in all copies. 12 | ; 13 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 | ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 | ; 21 | 22 | .module modem 23 | 24 | .include "mailstation.inc" 25 | .globl _new_mail 26 | 27 | .area _DATA 28 | 29 | ; modem msr 30 | _modem_curmsr:: 31 | .db #0 32 | _modem_flowing:: 33 | .db #0 34 | 35 | .area _CODE 36 | 37 | _modem_isr:: 38 | push af 39 | push hl 40 | push bc 41 | ld l, #1 42 | call _modem_iir ; read IIR to identify interrupt 43 | bit #0, l 44 | jr nz, modem_isr_out ; no interrupt, how did we get here? 45 | ld a, l 46 | and #0b00001111 ; mask off high 4 bits 47 | ld l, a 48 | has_irq: 49 | and #0b00000110 ; receiver line status, some error 50 | jr nz, no_rls 51 | push hl 52 | call _modem_lsr ; what are we supposed to do with it? (FCR bit 1?) 53 | pop hl 54 | jr modem_isr_out 55 | no_rls: 56 | ld a, l 57 | and #0b00000100 ; received data available or timeout 58 | jr z, modem_isr_out 59 | ld b, #16 ; read 16 bytes at a time 60 | modem_read_loop: 61 | push bc 62 | push hl 63 | call _modem_read 64 | ld b, l 65 | pop hl 66 | ld hl, #_modem_buf 67 | ld a, (_modem_buf_pos) 68 | ld l, a ; 0xf600 + (modembufpos) 69 | ld (hl), b 70 | inc a 71 | ld (_modem_buf_pos), a 72 | pop bc 73 | djnz check_for_more_bytes 74 | jr modem_isr_out 75 | check_for_more_bytes: 76 | call _modem_lsr 77 | bit 0, l 78 | jr nz, modem_read_loop 79 | modem_isr_out: 80 | call _modem_msr ; modem status update 81 | ld a, l 82 | ld (_modem_curmsr), a 83 | pop bc 84 | pop hl 85 | pop af 86 | ret 87 | 88 | 89 | ; void modem_init(void) 90 | _modem_init:: 91 | push bc 92 | push de 93 | push hl 94 | in a, (#SLOT_DEVICE) ; store old slot device 95 | ld d, a 96 | push de 97 | ld a, #0 98 | ld (_modem_buf_pos), a 99 | call _modem_powerdown 100 | ld a, #0x01 101 | out (#0x26), a ; turn port 26 on 102 | ld hl, #2000 103 | push hl 104 | call _delay ; delay 2 seconds 105 | pop hl 106 | ld a, #DEVICE_MODEM 107 | out (#SLOT_DEVICE), a ; switch slot device to modem 108 | ld a, #0b11000111 ; 14 byte FIFO 109 | ld (#SLOT_ADDR + 0x2), a ; FCR = enable FIFO 110 | ld a, #0b10000011 111 | ld (#SLOT_ADDR + 0x3), a ; LCR = DLAB=1, 8n1 112 | xor a 113 | ld (#SLOT_ADDR + 0x1), a ; DLM = 0 114 | determine_dlab: 115 | dlab_57600: 116 | ld hl, (_setting_modem_speed) 117 | ld de, #57600 118 | or a ; reset c 119 | sbc hl, de 120 | add hl, de 121 | jr c, dlab_38400 122 | ld a, #0x2 ; DLL = 2, baud rate = 57600 123 | jp set_dlab 124 | dlab_38400: 125 | ld hl, (_setting_modem_speed) 126 | ld de, #38400 127 | or a ; reset c 128 | sbc hl, de 129 | add hl, de 130 | jr c, dlab_28800 131 | ld a, #0x3 ; DLL = 3, baud rate = 38400 132 | jr set_dlab 133 | dlab_28800: 134 | ld hl, (_setting_modem_speed) 135 | ld de, #28800 136 | or a ; reset c 137 | sbc hl, de 138 | add hl, de 139 | jr c, dlab_19200 140 | ld a, #0x4 ; DLL = 4, baud rate = 28800 141 | jr set_dlab 142 | dlab_19200: 143 | ld hl, (_setting_modem_speed) 144 | ld de, #19200 145 | or a ; reset c 146 | sbc hl, de 147 | add hl, de 148 | jr c, dlab_9600 149 | ld a, #0x6 ; DLL = 6, baud rate = 19200 150 | jr set_dlab 151 | dlab_9600: 152 | ld hl, (_setting_modem_speed) 153 | ld de, #9600 154 | or a ; reset c 155 | sbc hl, de 156 | add hl, de 157 | jr c, dlab_4800 158 | ld a, #0x0c ; DLL = 0x0c, baud rate = 9600 159 | jr set_dlab 160 | dlab_4800: 161 | ld hl, (_setting_modem_speed) 162 | ld de, #4800 163 | or a ; reset c 164 | sbc hl, de 165 | add hl, de 166 | jr c, dlab_2400 167 | ld a, #0x18 ; DLL = 0x18, baud rate = 4800 168 | jr set_dlab 169 | dlab_2400: 170 | ld hl, (_setting_modem_speed) 171 | ld de, #2400 172 | or a ; reset c 173 | sbc hl, de 174 | add hl, de 175 | jr c, dlab_1200 176 | ld a, #0x30 ; DLL = 0x30, baud rate = 2400 177 | jr set_dlab 178 | dlab_1200: 179 | ld hl, (_setting_modem_speed) 180 | ld de, #1200 181 | or a ; reset c 182 | sbc hl, de 183 | add hl, de 184 | jr c, dlab_300 185 | ld a, #0x60 ; DLL = 0x60, baud rate = 1200 186 | jr set_dlab 187 | dlab_300: 188 | ld hl, (_setting_modem_speed) 189 | ld de, #300 190 | or a ; reset c 191 | sbc hl, de 192 | add hl, de 193 | jr c, dlab_default 194 | ld a, #0x01 195 | ld (#SLOT_ADDR + 0x1), a ; DLM = 0x1 196 | ld a, #0x80 ; DLL = 0x80, baud rate = 300 197 | jr set_dlab 198 | dlab_default: 199 | ld hl, #MODEM_DEFAULT_SPEED 200 | ld (_setting_modem_speed), hl 201 | jp determine_dlab ; run through the loop again 202 | set_dlab: 203 | ld (#SLOT_ADDR), a ; DLL 204 | ld a, #0b00000011 205 | ld (#SLOT_ADDR + 0x3), a ; LCR = DLAB=0, 8n1 206 | ld a, (#SLOT_ADDR + 0x4) ; read MCR 207 | or #0b00001011 208 | ld (#SLOT_ADDR + 0x4), a ; MCR = DTR, RTS, HINT 209 | ; ld b, #0x01 210 | ; ld c, #0x06 211 | ; call 0x0a2f ; jp 0x1afb, do something with port 3 212 | ; call 0x33ca ; init modem vars, activate interrupts 213 | ld a, #0b00001001 ; IER = EDSSI, ERBFI 214 | ld (#SLOT_ADDR + 0x1), a 215 | ld a, (#SLOT_ADDR + 0x6) 216 | ld (_modem_curmsr), a ; read and store MSR 217 | pop de 218 | ld a, d 219 | out (#SLOT_DEVICE), a ; restore old slot device 220 | pop hl 221 | pop de 222 | pop bc 223 | ret 224 | 225 | 226 | ; void modem_powerdown(void) 227 | ; most of this is from 0x33f6 in v2.54 firmware 228 | _modem_powerdown:: 229 | push bc 230 | push de 231 | push hl 232 | call 0x3dbe ; disable caller id? 233 | ld hl, (p3shadow) 234 | ld a, (hl) 235 | res 7, a ; disable caller id interrupt 236 | ld (hl),a 237 | out (#0x03), a 238 | in a, (#0x29) ; XXX what is port 29? 239 | or #0x0c 240 | out (#0x29), a 241 | ld hl, (p28shadow) 242 | ld a, (hl) 243 | set 2, a 244 | res 3, a 245 | ld (hl), a 246 | out (#0x28), a ; XXX what is port 28? 247 | xor a 248 | ld (#0xe63b), a ; no idea what these shadow vars are 249 | ld (#0xe63a), a 250 | ld (#0xe64d), a 251 | ld (#0xe638), a ; but init them all to 0 252 | ; l33f8 253 | ld a, #0x01 254 | ld (#0xe638), a 255 | in a, (#SLOT_DEVICE) ; store old slot device 256 | ld d, a 257 | push de 258 | ld hl, (p2shadow) 259 | ld a, (hl) ; read p2shadow 260 | res 5, a ; turn off port 2.5 - modem power 261 | ld (hl), a ; write p2shadow 262 | out (#0x02), a ; also write it to port2 263 | ld hl, #300 264 | push hl 265 | call _delay ; delay 300ms 266 | pop hl 267 | ld a, #0 268 | out (#0x26), a ; turn port 26 off 269 | ld hl, #100 270 | push hl 271 | call _delay ; delay 100ms 272 | pop hl 273 | pop de 274 | ld a, d 275 | out (#SLOT_DEVICE), a ; restore old slot device 276 | pop hl 277 | pop de 278 | pop bc 279 | ret 280 | 281 | 282 | ; char modem_read(void) 283 | ; return a byte in hl from the modem FIFO, from 0x3328 in v2.54 firmware 284 | _modem_read:: 285 | ; use hl 286 | in a, (#SLOT_ADDR) ; save old slot device 287 | ld h, a ; into h 288 | ld a, #DEVICE_MODEM 289 | out (#SLOT_DEVICE), a ; slot device = modem 290 | ld a, (#SLOT_ADDR) ; read byte from modem 291 | ld l, a ; into l 292 | ld a, h 293 | out (#SLOT_DEVICE), a ; set old slot device 294 | ld h, #0x00 295 | ret ; return hl 296 | 297 | 298 | ; void modem_write(char c) 299 | ; write a byte to the modem TX FIFO, from 0x33b6 in v2.54 firmware 300 | _modem_write:: 301 | push ix 302 | ld ix, #0 303 | add ix, sp 304 | ld a, 4(ix) 305 | ld l, a 306 | in a, (#SLOT_DEVICE) 307 | ld h, a 308 | ld a, #DEVICE_MODEM 309 | out (#SLOT_DEVICE), a 310 | ld a, l 311 | ld (#SLOT_ADDR), a 312 | ld a, h 313 | out (#SLOT_DEVICE), a 314 | pop ix 315 | ret 316 | 317 | 318 | ; int modem_ier(void) 319 | ; return modem IER register in hl, from 0x3339 in v2.54 firmware 320 | _modem_ier:: 321 | in a, (#SLOT_DEVICE) 322 | ld h, a 323 | ld a, #DEVICE_MODEM 324 | out (#SLOT_DEVICE), a 325 | ld a, (#SLOT_ADDR + 0x1) ; read modem IER 326 | ld l, a 327 | ld a, h 328 | out (#SLOT_DEVICE), a 329 | ld h, #0x0 330 | ret 331 | 332 | 333 | ; int modem_iir(void) 334 | ; return modem IIR register in hl, from 0x334a in v2.54 firmware 335 | _modem_iir:: 336 | in a, (#SLOT_DEVICE) 337 | ld h, a 338 | ld a, #DEVICE_MODEM 339 | out (#SLOT_DEVICE), a 340 | ld a, (#SLOT_ADDR + 0x2) ; read modem IIR 341 | ld l, a 342 | ld a, h 343 | out (#SLOT_DEVICE), a 344 | ld h, #0x0 345 | ret 346 | 347 | 348 | ; int modem_lcr(void) 349 | ; return modem LCR register in hl 350 | _modem_lcr:: 351 | in a, (#SLOT_DEVICE) 352 | ld h, a 353 | ld a, #DEVICE_MODEM 354 | out (#SLOT_DEVICE), a 355 | ld a, (#SLOT_ADDR + 0x3) ; read LCR 356 | ld l, a 357 | ld a, h 358 | out (#SLOT_DEVICE), a 359 | ld h, #0x00 360 | ret 361 | 362 | 363 | ; int modem_lsr(void) 364 | ; return modem LSR register in hl 365 | _modem_lsr:: 366 | in a, (#SLOT_DEVICE) 367 | ld h, a 368 | ld a, #DEVICE_MODEM 369 | out (#SLOT_DEVICE), a 370 | ld a, (#SLOT_ADDR + 0x5) ; read LSR 371 | ld l, a 372 | ld a, h 373 | out (#SLOT_DEVICE), a 374 | ld h, #0x00 375 | ret 376 | 377 | 378 | ; int modem_msr(void) 379 | ; return modem MSR register in hl 380 | _modem_msr:: 381 | in a, (#SLOT_DEVICE) 382 | ld h, a 383 | ld a, #DEVICE_MODEM 384 | out (#SLOT_DEVICE), a 385 | ld a, (#SLOT_ADDR + 0x6) ; read modem MSR 386 | ld (_modem_curmsr), a 387 | ld l, a 388 | ld a, h 389 | out (#SLOT_DEVICE), a 390 | ld h, #0x0 391 | ret 392 | 393 | ; void modem_hangup(void) 394 | ; drop DTR to force a hangup 395 | _modem_hangup:: 396 | push hl 397 | in a, (#SLOT_DEVICE) 398 | ld h, a 399 | ld a, #DEVICE_MODEM 400 | out (#SLOT_DEVICE), a 401 | ld a, (#SLOT_ADDR + 0x4) ; read modem MCR 402 | res 0, a ; drop DTR 403 | ld (#SLOT_ADDR + 0x4), a 404 | push af 405 | push hl 406 | ld hl, #500 407 | push hl 408 | call _delay ; sleep 500ms 409 | pop hl 410 | pop hl 411 | pop af 412 | set 0, a ; restore DTR 413 | ld a, (#SLOT_ADDR + 0x6) 414 | ld (_modem_curmsr), a 415 | ld (#SLOT_ADDR + 0x4), a 416 | ld a, (#SLOT_ADDR + 0x6) 417 | ld (_modem_curmsr), a 418 | ld a, h 419 | out (#SLOT_DEVICE), a 420 | pop hl 421 | ret 422 | 423 | ; void modem_pause(void) 424 | ; send XOFF 425 | _modem_pause:: 426 | push hl 427 | ld l, #XOFF 428 | push hl 429 | call _modem_write 430 | pop hl 431 | pop hl 432 | ld a, #0 433 | ld (_modem_flowing), a 434 | ret 435 | 436 | ; void modem_unpause(void) 437 | ; send XON 438 | _modem_unpause:: 439 | push hl 440 | ld l, #XON 441 | push hl 442 | call _modem_write 443 | pop hl 444 | pop hl 445 | ret 446 | -------------------------------------------------------------------------------- /mslib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * msTERM 3 | * utility functions 4 | * 5 | * Copyright (c) 2019 joshua stein 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | /* From Bela Torok, 1999 */ 21 | 22 | #define NUMBER_OF_DIGITS 16 23 | 24 | void 25 | uitoa(unsigned int value, char *string, int radix) 26 | { 27 | unsigned char t[NUMBER_OF_DIGITS + 1]; 28 | unsigned char index, i; 29 | 30 | index = NUMBER_OF_DIGITS; 31 | i = 0; 32 | 33 | do { 34 | t[--index] = '0' + (value % radix); 35 | if (t[index] > '9') 36 | t[index] += 'A' - ':'; 37 | value /= radix; 38 | } while (value != 0); 39 | 40 | do { 41 | string[i++] = t[index++]; 42 | } while (index < NUMBER_OF_DIGITS); 43 | 44 | string[i] = '\0'; 45 | } 46 | 47 | void 48 | itoa(int value, char *string, int radix) 49 | { 50 | if (value < 0 && radix == 10) { 51 | *string++ = '-'; 52 | uitoa(-value, string, radix); 53 | } else { 54 | uitoa(value, string, radix); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /putchar.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8 2 | ; 3 | ; msTERM 4 | ; putchar 5 | ; 6 | ; Copyright (c) 2019 joshua stein 7 | ; 8 | ; Permission to use, copy, modify, and distribute this software for any 9 | ; purpose with or without fee is hereby granted, provided that the above 10 | ; copyright notice and this permission notice appear in all copies. 11 | ; 12 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | ; 20 | 21 | .module putchar 22 | 23 | .include "mailstation.inc" 24 | 25 | ; screen contents (characters) array in upper memory 26 | .equ _screenbuf, #0xc000 27 | .equ _screenbufend, #0xc3ff 28 | 29 | ; per-character attributes array in upper memory 30 | .equ _screenattrs, #0xc400 31 | .equ _screenattrsend, #0xc7ff 32 | 33 | .area _DATA 34 | 35 | font_data:: 36 | .include "font/spleen-5x8.inc" 37 | 38 | ; lookup table for putchar 39 | ; left-most 5 bits are col group for lcd_cas 40 | ; last 3 bits are offset into col group 41 | cursorx_lookup_data:: 42 | .include "cursorx_lookup.inc" 43 | 44 | _cursorx:: ; cursor x position, 0-indexed 45 | .db #0 46 | _cursory:: ; cursor y position, 0-indexed 47 | .db #0 48 | _saved_cursorx:: ; cursor x position, 0-indexed 49 | .db #0 50 | _saved_cursory:: ; cursor y position, 0-indexed 51 | .db #0 52 | _putchar_sgr:: ; current SGR for putchar() 53 | .db #0 54 | 55 | 56 | .area _CODE 57 | 58 | ; void lcd_cas(unsigned char col) 59 | ; enable CAS, address the LCD column col (in h), and disable CAS 60 | _lcd_cas:: 61 | push ix 62 | ld ix, #0 63 | add ix, sp 64 | push de 65 | push hl 66 | ld hl, (p2shadow) 67 | ld a, (hl) 68 | and #0b11110111 ; CAS(0) - turn port2 bit 3 off 69 | ld (hl), a 70 | out (#0x02), a ; write p2shadow to port2 71 | ld de, #LCD_START 72 | ld a, 4(ix) 73 | ld (de), a ; write col argument 74 | ld a, (hl) 75 | or #0b00001000 ; CAS(1) - turn port2 bit 3 on 76 | ld (hl), a 77 | out (#0x02), a 78 | pop hl 79 | pop de 80 | ld sp, ix 81 | pop ix 82 | ret 83 | 84 | 85 | ; void clear_screen(void) 86 | _clear_screen:: 87 | di 88 | push hl 89 | in a, (#SLOT_DEVICE) 90 | ld h, a 91 | in a, (#SLOT_PAGE) 92 | ld l, a 93 | push hl 94 | ld a, #DEVICE_LCD_RIGHT 95 | out (#SLOT_DEVICE), a 96 | call _clear_lcd_half 97 | ld a, #DEVICE_LCD_LEFT 98 | out (#SLOT_DEVICE), a 99 | call _clear_lcd_half 100 | pop hl 101 | ld a, h 102 | out (#SLOT_DEVICE), a 103 | ld a, l 104 | out (#SLOT_PAGE), a 105 | pop hl 106 | ei 107 | ret 108 | 109 | _clear_screen_bufs:: 110 | di 111 | push bc 112 | push de 113 | push hl 114 | xor a 115 | ld (_cursorx), a 116 | ld (_cursory), a 117 | ld (_saved_cursorx), a 118 | ld (_saved_cursory), a 119 | ld (_putchar_sgr), a 120 | zero_screenbuf: 121 | ld hl, #_screenbuf 122 | ld de, #_screenbuf + 1 123 | ld bc, #_screenbufend - _screenbuf 124 | ld (hl), #' ' 125 | ldir 126 | zero_screenattrs: 127 | ld hl, #_screenattrs 128 | ld de, #_screenattrs + 1 129 | ld bc, #_screenattrsend - _screenattrs 130 | ld (hl), #0 131 | ldir 132 | clear_screen_out: 133 | pop hl 134 | pop de 135 | pop bc 136 | ei 137 | ret 138 | 139 | 140 | ; void clear_lcd_half(void) 141 | ; zero out the current LCD module (must already be in SLOT_DEVICE) 142 | ; from v2.54 firmware at 0x2490 143 | _clear_lcd_half:: 144 | push bc 145 | push de 146 | ld b, #20 ; do 20 columns total 147 | clear_lcd_column: 148 | ld h, #0 149 | ld a, b 150 | dec a ; columns are 0-based 151 | ld l, a 152 | push hl 153 | call _lcd_cas 154 | pop hl 155 | push bc ; preserve our column counter 156 | ld hl, #LCD_START 157 | ld (hl), #0 ; zero out hl, then copy it to de 158 | ld de, #LCD_START + 1 ; de will always be the next line 159 | ld bc, #128 - 1 ; iterate (LCD_HEIGHT - 1) times 160 | ldir ; ld (de), (hl), bc-- until 0 161 | pop bc ; restore column counter 162 | djnz clear_lcd_column ; column--, if not zero keep going 163 | clear_done: 164 | pop de 165 | pop bc 166 | ret 167 | 168 | 169 | ; void redraw_screen(void) 170 | _redraw_screen:: 171 | push bc 172 | push de 173 | push hl 174 | ld b, #0 175 | redraw_rows: 176 | ld d, b ; store rows in d 177 | ld b, #0 178 | redraw_cols: 179 | push bc ; XXX figure out what is corrupting 180 | push de ; bc and de in stamp_char, these shouldn't be needed 181 | push hl 182 | ld h, #0 ; cols 183 | ld l, b 184 | push hl 185 | ld h, #0 ; rows 186 | ld l, d 187 | push hl 188 | call _stamp_char 189 | pop hl 190 | pop hl 191 | pop hl 192 | pop de 193 | pop bc 194 | redraw_cols_next: 195 | inc hl 196 | inc b 197 | ld a, b 198 | cp #LCD_COLS 199 | jr nz, redraw_cols 200 | ld b, d 201 | inc b 202 | ld a, b 203 | cp #LCD_ROWS 204 | jr nz, redraw_rows 205 | redraw_screen_out: 206 | pop hl 207 | pop de 208 | pop bc 209 | ret 210 | 211 | 212 | ; void scroll_lcd(void) 213 | ; scroll entire screen up by FONT_HEIGHT rows, minus statusbar 214 | _scroll_lcd:: 215 | di 216 | push bc 217 | push de 218 | push hl 219 | in a, (#SLOT_DEVICE) 220 | ld h, a 221 | in a, (#SLOT_PAGE) 222 | ld l, a 223 | push hl 224 | ld a, #DEVICE_LCD_LEFT 225 | out (#SLOT_DEVICE), a 226 | call _scroll_lcd_half 227 | ld a, #DEVICE_LCD_RIGHT 228 | out (#SLOT_DEVICE), a 229 | call _scroll_lcd_half 230 | pop hl 231 | ld a, h 232 | out (#SLOT_DEVICE), a 233 | ld a, l 234 | out (#SLOT_PAGE), a 235 | shift_bufs: 236 | ld b, #0 237 | screenbuf_shift_loop: 238 | ld h, b 239 | ld l, #0 240 | call screenbuf_offset 241 | ld de, #_screenbuf 242 | add hl, de ; hl = screenbuf[b * LCD_COLS] 243 | push hl 244 | ld de, #LCD_COLS 245 | add hl, de ; hl += LCD_COLS 246 | pop de ; de = screenbuf[b * LCD_COLS] 247 | push bc 248 | ld bc, #LCD_COLS 249 | ldir ; ld (de), (hl), de++, hl++, bc-- 250 | pop bc 251 | inc b 252 | ld a, b 253 | cp #TEXT_ROWS - 1 254 | jr nz, screenbuf_shift_loop 255 | screenattrs_shift: 256 | ld b, #0 257 | screenattrs_shift_loop: 258 | ld h, b 259 | ld l, #0 260 | call screenbuf_offset 261 | ld de, #_screenattrs 262 | add hl, de ; hl = screenattrs[b * LCD_COLS] 263 | push hl 264 | ld de, #LCD_COLS 265 | add hl, de 266 | pop de 267 | push bc 268 | ld bc, #LCD_COLS 269 | ldir 270 | pop bc 271 | inc b 272 | ld a, b 273 | cp #TEXT_ROWS - 1 274 | jr nz, screenattrs_shift_loop 275 | last_row_zero: 276 | ld a, #TEXT_ROWS - 1 277 | ld h, a 278 | ld l, #0 279 | call screenbuf_offset 280 | ld de, #_screenbuf 281 | add hl, de 282 | ld d, #0 283 | ld e, #LCD_COLS - 1 284 | add hl, de 285 | ld b, #LCD_COLS 286 | ld a, (_putchar_sgr) 287 | last_row_zero_loop: 288 | ld (hl), #' ' 289 | dec hl 290 | djnz last_row_zero_loop 291 | scroll_lcd_out: 292 | pop hl 293 | pop de 294 | pop bc 295 | ei 296 | ret 297 | 298 | 299 | ; void scroll_lcd_half(void) 300 | ; scroll current LCD module up by FONT_HEIGHT rows, minus statusbar and 301 | ; zero out the last line of text (only to the LCD) 302 | _scroll_lcd_half:: 303 | push ix 304 | ld ix, #0 305 | add ix, sp 306 | push bc 307 | push de 308 | push hl 309 | ; alloc 2 bytes on the stack for local storage 310 | push hl 311 | ld a, #LCD_HEIGHT - (FONT_HEIGHT * 2) ; iterations of pixel row moves 312 | scroll_init: 313 | ld -1(ix), a ; store iterations 314 | ld b, #20 ; do 20 columns total 315 | scroll_lcd_column: 316 | ld -2(ix), b ; store new column counter 317 | ld a, b 318 | sub #1 ; columns are 0-based 319 | ld h, #0 320 | ld l, a 321 | push hl 322 | call _lcd_cas 323 | pop hl 324 | scroll_rows: 325 | ld b, #0 326 | ld c, -1(ix) ; bc = row counter 327 | ld hl, #LCD_START + 8 ; start of next line 328 | ld de, #LCD_START 329 | ldir ; ld (de), (hl), bc-- until 0 330 | scroll_zerolast: 331 | ld hl, #LCD_START 332 | ld d, #0 333 | ld e, -1(ix) 334 | add hl, de 335 | ld b, #FONT_HEIGHT 336 | scroll_zerolastloop: ; 8 times: zero hl, hl++ 337 | ld (hl), #0 338 | inc hl 339 | djnz scroll_zerolastloop 340 | ld b, -2(ix) 341 | djnz scroll_lcd_column ; column--, if not zero keep going 342 | pop hl 343 | pop de 344 | pop bc 345 | ld sp, ix 346 | pop ix 347 | ret 348 | 349 | 350 | ; address of screenbuf or screenattrs offset for a row/col in hl, returns in hl 351 | screenbuf_offset: 352 | push bc 353 | push de 354 | ; uses hl 355 | ex de, hl 356 | ld hl, #0 357 | ld a, d ; row 358 | cp #0 359 | jr z, multiply_srow_out ; only add rows if > 0 360 | ld bc, #LCD_COLS 361 | multiply_srow: 362 | add hl, bc 363 | dec a 364 | cp #0 365 | jr nz, multiply_srow 366 | multiply_srow_out: 367 | ld d, #0 ; col in e 368 | add hl, de ; hl = (row * LCD_COLS) + col 369 | pop de 370 | pop bc 371 | ret ; hl 372 | 373 | 374 | ; void stamp_char(unsigned int row, unsigned int col) 375 | ; row at 4(ix), col at 6(ix) 376 | _stamp_char:: 377 | push ix 378 | ld ix, #0 379 | add ix, sp 380 | push bc 381 | push de 382 | push hl 383 | ld hl, #-15 ; stack bytes for local storage 384 | add hl, sp 385 | ld sp, hl 386 | in a, (#SLOT_DEVICE) 387 | ld -3(ix), a ; stack[-3] = old slot device 388 | in a, (#SLOT_PAGE) 389 | ld -4(ix), a ; stack[-4] = old slot page 390 | find_char: 391 | ld h, 4(ix) 392 | ld l, 6(ix) 393 | call screenbuf_offset 394 | push hl 395 | ld de, #_screenbuf 396 | add hl, de ; hl = screenbuf[(row * LCD_COLS) + col] 397 | ld a, (hl) 398 | ld -5(ix), a ; stack[-5] = character to stamp 399 | pop hl 400 | ld de, #_screenattrs 401 | add hl, de ; hl = screenattrs[(row * LCD_COLS) + col] 402 | ld a, (hl) 403 | ld -6(ix), a ; stack[-6] = character attrs 404 | calc_font_data_base: 405 | ld h, #0 406 | ld l, -5(ix) ; char 407 | add hl, hl ; hl = char * FONT_HEIGHT (8) 408 | add hl, hl 409 | add hl, hl 410 | ld de, #font_data 411 | add hl, de 412 | ld -7(ix), l 413 | ld -8(ix), h ; stack[-8,-7] = char font data base addr 414 | calc_char_cell_base: 415 | ld h, #0 416 | ld l, 4(ix) ; row 417 | add hl, hl 418 | add hl, hl 419 | add hl, hl ; hl = row * FONT_HEIGHT (8) 420 | ld de, #LCD_START 421 | add hl, de ; hl = 4038 + (row * FONT_HEIGHT) 422 | ld -9(ix), l 423 | ld -10(ix), h ; stack[-10,-9] = lcd char cell base 424 | fetch_from_table: 425 | ld a, 6(ix) ; col 426 | ld hl, #cursorx_lookup_data 427 | ld b, #0 428 | ld c, a 429 | add hl, bc 430 | ld b, (hl) 431 | ld a, b 432 | pluck_col_group: 433 | and #0b11111000 ; upper 5 bits are col group 434 | srl a 435 | srl a 436 | srl a 437 | ld -11(ix), a ; stack[-11] = col group 438 | pluck_offset: 439 | ld a, b 440 | and #0b00000111 ; lower 3 bits are offset 441 | ld -12(ix), a ; stack[-12] = offset 442 | ld -15(ix), #0 ; stack[-15] = previous lcd col 443 | ld d, #FONT_HEIGHT ; for (row = FONT_HEIGHT; row >= 0; row--) 444 | next_char_row: 445 | ld a, d 446 | dec a 447 | ld h, -8(ix) ; char font data base 448 | ld l, -7(ix) 449 | ld b, #0 450 | ld c, a 451 | add hl, bc 452 | ld a, (hl) ; font_addr + (char * FONT_HEIGHT) + row 453 | ld b, -6(ix) 454 | bit #ATTR_BIT_REVERSE, b 455 | jr nz, reverse 456 | bit #ATTR_BIT_CURSOR, b 457 | jr nz, reverse 458 | jr not_reverse 459 | reverse: 460 | cpl ; flip em 461 | and #0b00011111 ; mask off bits not within FONT_WIDTH 462 | not_reverse: 463 | ld -13(ix), a ; stack[-13] = working font data 464 | ld a, -6(ix) 465 | bit #ATTR_BIT_UNDERLINE, a 466 | jr z, not_underline 467 | ld a, d 468 | cp #FONT_HEIGHT 469 | jr nz, not_underline 470 | underline: 471 | ld -13(ix), #0xff 472 | not_underline: 473 | ld a, 6(ix) ; col 474 | cp #LCD_COLS / 2 ; assume a char never spans both LCD sides 475 | jr nc, rightside 476 | leftside: 477 | ld a, #DEVICE_LCD_LEFT 478 | jr swap_lcd 479 | rightside: 480 | ld a, #DEVICE_LCD_RIGHT 481 | swap_lcd: 482 | out (#SLOT_DEVICE), a 483 | ld e, #FONT_WIDTH ; for (col = FONT_WIDTH; col > 0; col--) 484 | next_char_col: ; inner loop, each col of each row 485 | ld -14(ix), #0b00011111 ; font data mask that will get shifted 486 | determine_cas: 487 | ld c, #0 488 | ld b, -11(ix) ; col group 489 | ld a, -12(ix) ; bit offset 490 | add #FONT_WIDTH 491 | sub e ; if offset+(5-col) is >= 8, advance col 492 | cp #LCD_COL_GROUP_WIDTH 493 | jr c, skip_advance ; if a >= 8, advance (dec b) 494 | dec b 495 | ld c, -12(ix) ; bit offset 496 | ld a, #LCD_COL_GROUP_WIDTH 497 | sub c 498 | ld c, a ; c = number of right shifts 499 | skip_advance: 500 | do_lcd_cas: 501 | ld a, -15(ix) ; previous lcd cas 502 | cp b 503 | jr z, prep_right_shift 504 | ld h, #0 505 | ld l, b 506 | push hl 507 | call _lcd_cas 508 | pop hl 509 | ld -15(ix), b ; store lcd col for next round 510 | ; if this character doesn't fit entirely in one lcd column, we need to 511 | ; span two of them and on the left one, shift font data and masks right 512 | ; to remove right-most bits that will be on the next column 513 | prep_right_shift: 514 | ld a, c 515 | cp #0 516 | jr z, prep_left_shift 517 | ld b, c 518 | ld c, -14(ix) ; matching mask 00011111 519 | ld a, -13(ix) ; load font data like 00010101 520 | right_shift: 521 | srl a ; shift font data right #b times 522 | srl c ; and mask to match 523 | djnz right_shift ; -> 10101000 524 | ld -14(ix), c 525 | jr done_left_shift 526 | prep_left_shift: 527 | ld c, -14(ix) ; mask 528 | ld a, -12(ix) ; (bit offset) times, shift font data 529 | cp #0 530 | ld b, a 531 | ld a, -13(ix) ; read new font data 532 | jr z, done_left_shift 533 | left_shift: 534 | sla a 535 | sla c 536 | djnz left_shift 537 | done_left_shift: 538 | ld b, a 539 | ld a, c 540 | cpl 541 | ld -14(ix), a ; store inverted mask 542 | ld a, b 543 | read_lcd_data: 544 | ld h, -10(ix) 545 | ld l, -9(ix) 546 | ld b, a 547 | ld a, d 548 | dec a 549 | ld c, a 550 | ld a, b 551 | ld b, #0 552 | add hl, bc ; hl = 4038 + (row * FONT_HEIGHT) + row - 1 553 | ld b, a ; store new font data 554 | ld a, (hl) ; read existing cell data 555 | and -14(ix) ; mask off new char cell 556 | or b ; combine data into cell 557 | ld (hl), a 558 | dec e 559 | jp nz, next_char_col 560 | dec d 561 | jp nz, next_char_row 562 | stamp_char_out: 563 | ld a, -3(ix) ; restore old slot device 564 | out (#SLOT_DEVICE), a 565 | ld a, -4(ix) ; restore old slot page 566 | out (#SLOT_PAGE), a 567 | ld hl, #15 ; remove stack bytes 568 | add hl, sp 569 | ld sp, hl 570 | pop hl 571 | pop de 572 | pop bc 573 | ld sp, ix 574 | pop ix 575 | ret 576 | 577 | 578 | ; void uncursor(void) 579 | ; remove cursor attribute from old cursor position 580 | _uncursor:: 581 | push de 582 | push hl 583 | ld a, (_cursory) 584 | ld h, a 585 | ld a, (_cursorx) 586 | ld l, a 587 | call screenbuf_offset 588 | ld de, #_screenattrs 589 | add hl, de ; screenattrs[(cursory * TEXT_COLS) + cursorx] 590 | ld a, (hl) 591 | res #ATTR_BIT_CURSOR, a ; &= ~(ATTR_CURSOR) 592 | ld (hl), a 593 | ld a, (_cursorx) 594 | ld l, a 595 | push hl 596 | ld a, (_cursory) 597 | ld l, a 598 | push hl 599 | call _stamp_char 600 | pop hl 601 | pop hl 602 | pop hl 603 | pop de 604 | ret 605 | 606 | ; void recursor(void) 607 | ; force-set cursor attribute 608 | _recursor:: 609 | push de 610 | push hl 611 | ld a, (_cursory) 612 | ld h, a 613 | ld a, (_cursorx) 614 | ld l, a 615 | call screenbuf_offset 616 | ld de, #_screenattrs 617 | add hl, de ; screenattrs[(cursory * TEXT_COLS) + cursorx] 618 | ld a, (hl) 619 | set #ATTR_BIT_CURSOR, a 620 | ld (hl), a 621 | pop hl 622 | pop de 623 | ret 624 | 625 | 626 | ; int putchar(int c) 627 | _putchar:: 628 | push ix 629 | ld ix, #0 630 | add ix, sp ; char to print is at 4(ix) 631 | push de 632 | push hl 633 | call _uncursor 634 | ld a, 4(ix) 635 | cp #'\b' ; backspace 636 | jr nz, not_backspace 637 | backspace: 638 | ld a, (_cursorx) 639 | cp #0 640 | jr nz, cursorx_not_zero 641 | ld a, (_cursory) 642 | cp #0 643 | jp z, putchar_fastout ; cursorx/y at 0,0, nothing to do 644 | dec a 645 | ld (_cursory), a ; cursory-- 646 | ld a, #LCD_COLS - 2 647 | ld (_cursorx), a 648 | jp putchar_draw_cursor 649 | cursorx_not_zero: 650 | dec a 651 | ld (_cursorx), a ; cursorx--; 652 | jp putchar_draw_cursor 653 | not_backspace: 654 | cp #'\r' 655 | jr nz, not_cr 656 | xor a 657 | ld (_cursorx), a ; cursorx = 0 658 | jr not_crlf 659 | not_cr: 660 | cp #'\n' 661 | jr nz, not_crlf 662 | xor a 663 | ld (_cursorx), a ; cursorx = 0 664 | ld a, (_cursory) 665 | inc a 666 | ld (_cursory), a ; cursory++ 667 | not_crlf: 668 | ld a, (_cursorx) 669 | cp #LCD_COLS 670 | jr c, not_longer_text_cols ; cursorx < TEXT_COLS 671 | xor a 672 | ld (_cursorx), a ; cursorx = 0 673 | ld a, (_cursory) 674 | inc a 675 | ld (_cursory), a 676 | not_longer_text_cols: 677 | ld a, (_cursory) 678 | cp #TEXT_ROWS 679 | jr c, scroll_out 680 | scroll_up_screen: 681 | call _scroll_lcd 682 | xor a 683 | ld (_cursorx), a 684 | ld a, #TEXT_ROWS - 1 685 | ld (_cursory), a ; cursory = TEXT_ROWS - 1 686 | scroll_out: 687 | ld a, 4(ix) 688 | cp a, #'\r' 689 | jr z, cr_or_lf 690 | cp a, #'\n' 691 | jr z, cr_or_lf 692 | jr store_char_in_buf 693 | cr_or_lf: 694 | jp putchar_draw_cursor 695 | store_char_in_buf: 696 | ld a, (_cursory) 697 | ld h, a 698 | ld a, (_cursorx) 699 | ld l, a 700 | call screenbuf_offset 701 | push hl 702 | ld de, #_screenbuf 703 | add hl, de ; hl = screenbuf[(cursory * LCD_COLS) + cursorx] 704 | ld a, 4(ix) 705 | ld (hl), a ; store character 706 | pop hl 707 | ld de, #_screenattrs 708 | add hl, de ; hl = screenattrs[(cursory * LCD_COLS) + cursorx] 709 | ld a, (_putchar_sgr) 710 | ld (hl), a ; = putchar_sgr 711 | ld a, (_cursorx) 712 | ld l, a 713 | push hl 714 | ld a, (_cursory) 715 | ld l, a 716 | push hl 717 | call _stamp_char 718 | pop hl 719 | pop hl 720 | advance_cursorx: 721 | ld a, (_cursorx) 722 | inc a 723 | ld (_cursorx), a 724 | cp #LCD_COLS ; if (cursorx >= LCD_COLS) 725 | jr c, putchar_draw_cursor 726 | xor a 727 | ld (_cursorx), a 728 | ld a, (_cursory) 729 | inc a 730 | ld (_cursory), a 731 | check_cursory: 732 | cp #TEXT_ROWS ; and if (cursory >= TEXT_ROWS) 733 | jr c, putchar_draw_cursor 734 | call _scroll_lcd 735 | ld a, #TEXT_ROWS - 1 736 | ld (_cursory), a ; cursory = TEXT_ROWS - 1 737 | putchar_draw_cursor: 738 | ld a, (_cursory) 739 | ld h, a 740 | ld a, (_cursorx) 741 | ld l, a 742 | call screenbuf_offset 743 | ld de, #_screenattrs 744 | add hl, de ; hl = screenattrs[(cursory * LCD_COLS) + cursorx] 745 | ld a, (hl) ; read existing attrs 746 | set #ATTR_BIT_CURSOR, a 747 | ld (hl), a ; = putchar_sgr | ATTR_CURSOR 748 | ld a, (_cursorx) 749 | ld l, a 750 | push hl 751 | ld a, (_cursory) 752 | ld l, a 753 | push hl 754 | call _stamp_char 755 | pop hl 756 | pop hl 757 | putchar_fastout: 758 | pop hl 759 | pop de 760 | ld sp, ix 761 | pop ix 762 | ret 763 | 764 | 765 | ; void putchar_attr(unsigned char row, unsigned char col, char c, char attr) 766 | ; directly manipulates screenbuf/attrs without scrolling or length checks 767 | ; row at 4(ix), col at 5(ix), c at 6(ix), attr at 7(ix) 768 | _putchar_attr:: 769 | push ix 770 | ld ix, #0 771 | add ix, sp 772 | push de 773 | push hl 774 | store_char: 775 | ld h, 4(ix) 776 | ld l, 5(ix) 777 | call screenbuf_offset 778 | push hl 779 | ld de, #_screenbuf 780 | add hl, de ; screenbuf[(row * TEXT_COLS) + col] 781 | ld a, 6(ix) 782 | ld (hl), a 783 | store_attrs: 784 | pop hl 785 | ld de, #_screenattrs 786 | add hl, de ; screenattrs[(row * TEXT_COLS) + col] 787 | ld a, 7(ix) 788 | ld (hl), a 789 | ld l, 5(ix) 790 | push hl 791 | ld l, 4(ix) 792 | push hl 793 | call _stamp_char 794 | pop hl 795 | pop hl 796 | pop hl 797 | pop de 798 | ld sp, ix 799 | pop ix 800 | ret 801 | -------------------------------------------------------------------------------- /scancodes.inc: -------------------------------------------------------------------------------- 1 | ; AUTOMATICALLY GENERATED FILE - see tools/generate_scancodes.rb 2 | .equ META_KEY_BEGIN, #0d200 3 | .equ META_KEY_NONE, #0d255 4 | 5 | scancode_table: 6 | .db #0d200 ; :MAIN_MENU 7 | .db #0d201 ; :BACK 8 | .db #0d202 ; :PRINT 9 | .db #0d203 ; :F1 10 | .db #0d204 ; :F2 11 | .db #0d205 ; :F3 12 | .db #0d206 ; :F4 13 | .db #0d207 ; :F5 14 | .db #0d255 15 | .db #0d255 16 | .db #0d255 17 | .db #0d255 18 | .db #0d255 19 | .db #0d255 20 | .db #0d255 21 | .db #0d208 ; :POWER 22 | .db #0d255 23 | .db #0d255 24 | .db #0d255 25 | .db #0d064 ; "@" 26 | .db #0d209 ; :SIZE 27 | .db #0d210 ; :SPELLING 28 | .db #0d211 ; :EMAIL 29 | .db #0d212 ; :PAGE_UP 30 | .db #0d255 31 | .db #0d255 32 | .db #0d255 33 | .db #0d255 34 | .db #0d255 35 | .db #0d255 36 | .db #0d255 37 | .db #0d255 38 | .db #0d096 ; "`" 39 | .db #0d049 ; "1" 40 | .db #0d050 ; "2" 41 | .db #0d051 ; "3" 42 | .db #0d052 ; "4" 43 | .db #0d053 ; "5" 44 | .db #0d054 ; "6" 45 | .db #0d055 ; "7" 46 | .db #0d255 47 | .db #0d255 48 | .db #0d255 49 | .db #0d255 50 | .db #0d255 51 | .db #0d255 52 | .db #0d255 53 | .db #0d255 54 | .db #0d056 ; "8" 55 | .db #0d057 ; "9" 56 | .db #0d048 ; "0" 57 | .db #0d045 ; "-" 58 | .db #0d061 ; "=" 59 | .db #0d008 ; "\b" 60 | .db #0d092 ; "\\" 61 | .db #0d213 ; :PAGE_DOWN 62 | .db #0d255 63 | .db #0d255 64 | .db #0d255 65 | .db #0d255 66 | .db #0d255 67 | .db #0d255 68 | .db #0d255 69 | .db #0d255 70 | .db #0d009 ; "\t" 71 | .db #0d113 ; "q" 72 | .db #0d119 ; "w" 73 | .db #0d101 ; "e" 74 | .db #0d114 ; "r" 75 | .db #0d116 ; "t" 76 | .db #0d121 ; "y" 77 | .db #0d117 ; "u" 78 | .db #0d255 79 | .db #0d255 80 | .db #0d255 81 | .db #0d255 82 | .db #0d255 83 | .db #0d255 84 | .db #0d255 85 | .db #0d255 86 | .db #0d105 ; "i" 87 | .db #0d111 ; "o" 88 | .db #0d112 ; "p" 89 | .db #0d091 ; "[" 90 | .db #0d093 ; "]" 91 | .db #0d059 ; ";" 92 | .db #0d039 ; "'" 93 | .db #0d010 ; "\n" 94 | .db #0d255 95 | .db #0d255 96 | .db #0d255 97 | .db #0d255 98 | .db #0d255 99 | .db #0d255 100 | .db #0d255 101 | .db #0d255 102 | .db #0d214 ; :CAPS_LOCK 103 | .db #0d097 ; "a" 104 | .db #0d115 ; "s" 105 | .db #0d100 ; "d" 106 | .db #0d102 ; "f" 107 | .db #0d103 ; "g" 108 | .db #0d104 ; "h" 109 | .db #0d106 ; "j" 110 | .db #0d255 111 | .db #0d255 112 | .db #0d255 113 | .db #0d255 114 | .db #0d255 115 | .db #0d255 116 | .db #0d255 117 | .db #0d255 118 | .db #0d107 ; "k" 119 | .db #0d108 ; "l" 120 | .db #0d044 ; "," 121 | .db #0d046 ; "." 122 | .db #0d047 ; "/" 123 | .db #0d218 ; :UP 124 | .db #0d219 ; :DOWN 125 | .db #0d221 ; :RIGHT 126 | .db #0d255 127 | .db #0d255 128 | .db #0d255 129 | .db #0d255 130 | .db #0d255 131 | .db #0d255 132 | .db #0d255 133 | .db #0d255 134 | .db #0d215 ; :LEFT_SHIFT 135 | .db #0d122 ; "z" 136 | .db #0d120 ; "x" 137 | .db #0d099 ; "c" 138 | .db #0d118 ; "v" 139 | .db #0d098 ; "b" 140 | .db #0d110 ; "n" 141 | .db #0d109 ; "m" 142 | .db #0d255 143 | .db #0d255 144 | .db #0d255 145 | .db #0d255 146 | .db #0d255 147 | .db #0d255 148 | .db #0d255 149 | .db #0d255 150 | .db #0d217 ; :FN 151 | .db #0d255 152 | .db #0d255 153 | .db #0d032 ; " " 154 | .db #0d255 155 | .db #0d255 156 | .db #0d216 ; :RIGHT_SHIFT 157 | .db #0d220 ; :LEFT 158 | 159 | scancode_table_uppercase: 160 | .db #0d200 ; :MAIN_MENU 161 | .db #0d201 ; :BACK 162 | .db #0d202 ; :PRINT 163 | .db #0d203 ; :F1 164 | .db #0d204 ; :F2 165 | .db #0d205 ; :F3 166 | .db #0d206 ; :F4 167 | .db #0d207 ; :F5 168 | .db #0d255 169 | .db #0d255 170 | .db #0d255 171 | .db #0d255 172 | .db #0d255 173 | .db #0d255 174 | .db #0d255 175 | .db #0d208 ; :POWER 176 | .db #0d255 177 | .db #0d255 178 | .db #0d255 179 | .db #0d064 ; "@" 180 | .db #0d209 ; :SIZE 181 | .db #0d210 ; :SPELLING 182 | .db #0d211 ; :EMAIL 183 | .db #0d212 ; :PAGE_UP 184 | .db #0d255 185 | .db #0d255 186 | .db #0d255 187 | .db #0d255 188 | .db #0d255 189 | .db #0d255 190 | .db #0d255 191 | .db #0d255 192 | .db #0d126 ; "~" 193 | .db #0d033 ; "!" 194 | .db #0d064 ; "@" 195 | .db #0d035 ; "#" 196 | .db #0d036 ; "$" 197 | .db #0d037 ; "%" 198 | .db #0d094 ; "^" 199 | .db #0d038 ; "&" 200 | .db #0d255 201 | .db #0d255 202 | .db #0d255 203 | .db #0d255 204 | .db #0d255 205 | .db #0d255 206 | .db #0d255 207 | .db #0d255 208 | .db #0d042 ; "*" 209 | .db #0d040 ; "(" 210 | .db #0d041 ; ")" 211 | .db #0d095 ; "_" 212 | .db #0d043 ; "+" 213 | .db #0d008 ; "\b" 214 | .db #0d124 ; "|" 215 | .db #0d213 ; :PAGE_DOWN 216 | .db #0d255 217 | .db #0d255 218 | .db #0d255 219 | .db #0d255 220 | .db #0d255 221 | .db #0d255 222 | .db #0d255 223 | .db #0d255 224 | .db #0d009 ; "\t" 225 | .db #0d081 ; "Q" 226 | .db #0d087 ; "W" 227 | .db #0d069 ; "E" 228 | .db #0d082 ; "R" 229 | .db #0d084 ; "T" 230 | .db #0d089 ; "Y" 231 | .db #0d085 ; "U" 232 | .db #0d255 233 | .db #0d255 234 | .db #0d255 235 | .db #0d255 236 | .db #0d255 237 | .db #0d255 238 | .db #0d255 239 | .db #0d255 240 | .db #0d073 ; "I" 241 | .db #0d079 ; "O" 242 | .db #0d080 ; "P" 243 | .db #0d123 ; "{" 244 | .db #0d125 ; "}" 245 | .db #0d058 ; ":" 246 | .db #0d034 ; "\"" 247 | .db #0d010 ; "\n" 248 | .db #0d255 249 | .db #0d255 250 | .db #0d255 251 | .db #0d255 252 | .db #0d255 253 | .db #0d255 254 | .db #0d255 255 | .db #0d255 256 | .db #0d214 ; :CAPS_LOCK 257 | .db #0d065 ; "A" 258 | .db #0d083 ; "S" 259 | .db #0d068 ; "D" 260 | .db #0d070 ; "F" 261 | .db #0d071 ; "G" 262 | .db #0d072 ; "H" 263 | .db #0d074 ; "J" 264 | .db #0d255 265 | .db #0d255 266 | .db #0d255 267 | .db #0d255 268 | .db #0d255 269 | .db #0d255 270 | .db #0d255 271 | .db #0d255 272 | .db #0d075 ; "K" 273 | .db #0d076 ; "L" 274 | .db #0d060 ; "<" 275 | .db #0d062 ; ">" 276 | .db #0d063 ; "?" 277 | .db #0d218 ; :UP 278 | .db #0d219 ; :DOWN 279 | .db #0d221 ; :RIGHT 280 | .db #0d255 281 | .db #0d255 282 | .db #0d255 283 | .db #0d255 284 | .db #0d255 285 | .db #0d255 286 | .db #0d255 287 | .db #0d255 288 | .db #0d215 ; :LEFT_SHIFT 289 | .db #0d090 ; "Z" 290 | .db #0d088 ; "X" 291 | .db #0d067 ; "C" 292 | .db #0d086 ; "V" 293 | .db #0d066 ; "B" 294 | .db #0d078 ; "N" 295 | .db #0d077 ; "M" 296 | .db #0d255 297 | .db #0d255 298 | .db #0d255 299 | .db #0d255 300 | .db #0d255 301 | .db #0d255 302 | .db #0d255 303 | .db #0d255 304 | .db #0d217 ; :FN 305 | .db #0d255 306 | .db #0d255 307 | .db #0d032 ; " " 308 | .db #0d255 309 | .db #0d255 310 | .db #0d216 ; :RIGHT_SHIFT 311 | .db #0d220 ; :LEFT 312 | 313 | scancode_table_control: 314 | .db #0d200 ; :MAIN_MENU 315 | .db #0d201 ; :BACK 316 | .db #0d202 ; :PRINT 317 | .db #0d203 ; :F1 318 | .db #0d204 ; :F2 319 | .db #0d205 ; :F3 320 | .db #0d206 ; :F4 321 | .db #0d207 ; :F5 322 | .db #0d255 323 | .db #0d255 324 | .db #0d255 325 | .db #0d255 326 | .db #0d255 327 | .db #0d255 328 | .db #0d255 329 | .db #0d208 ; :POWER 330 | .db #0d255 331 | .db #0d255 332 | .db #0d255 333 | .db #0d064 ; "@" 334 | .db #0d209 ; :SIZE 335 | .db #0d210 ; :SPELLING 336 | .db #0d211 ; :EMAIL 337 | .db #0d212 ; :PAGE_UP 338 | .db #0d255 339 | .db #0d255 340 | .db #0d255 341 | .db #0d255 342 | .db #0d255 343 | .db #0d255 344 | .db #0d255 345 | .db #0d255 346 | .db #0d096 ; "`" 347 | .db #0d049 ; "1" 348 | .db #0d050 ; "2" 349 | .db #0d027 ; 27 350 | .db #0d028 ; 28 351 | .db #0d029 ; 29 352 | .db #0d030 ; 30 353 | .db #0d031 ; 31 354 | .db #0d255 355 | .db #0d255 356 | .db #0d255 357 | .db #0d255 358 | .db #0d255 359 | .db #0d255 360 | .db #0d255 361 | .db #0d255 362 | .db #0d127 ; 127 363 | .db #0d057 ; "9" 364 | .db #0d048 ; "0" 365 | .db #0d031 ; 31 366 | .db #0d061 ; "=" 367 | .db #0d008 ; "\b" 368 | .db #0d028 ; 28 369 | .db #0d213 ; :PAGE_DOWN 370 | .db #0d255 371 | .db #0d255 372 | .db #0d255 373 | .db #0d255 374 | .db #0d255 375 | .db #0d255 376 | .db #0d255 377 | .db #0d255 378 | .db #0d009 ; "\t" 379 | .db #0d017 ; 17 380 | .db #0d023 ; 23 381 | .db #0d005 ; 5 382 | .db #0d018 ; 18 383 | .db #0d020 ; 20 384 | .db #0d025 ; 25 385 | .db #0d021 ; 21 386 | .db #0d255 387 | .db #0d255 388 | .db #0d255 389 | .db #0d255 390 | .db #0d255 391 | .db #0d255 392 | .db #0d255 393 | .db #0d255 394 | .db #0d009 ; 9 395 | .db #0d015 ; 15 396 | .db #0d016 ; 16 397 | .db #0d027 ; 27 398 | .db #0d029 ; 29 399 | .db #0d059 ; ";" 400 | .db #0d039 ; "'" 401 | .db #0d010 ; "\n" 402 | .db #0d255 403 | .db #0d255 404 | .db #0d255 405 | .db #0d255 406 | .db #0d255 407 | .db #0d255 408 | .db #0d255 409 | .db #0d255 410 | .db #0d214 ; :CAPS_LOCK 411 | .db #0d001 ; 1 412 | .db #0d019 ; 19 413 | .db #0d004 ; 4 414 | .db #0d006 ; 6 415 | .db #0d007 ; 7 416 | .db #0d008 ; 8 417 | .db #0d010 ; 10 418 | .db #0d255 419 | .db #0d255 420 | .db #0d255 421 | .db #0d255 422 | .db #0d255 423 | .db #0d255 424 | .db #0d255 425 | .db #0d255 426 | .db #0d011 ; 11 427 | .db #0d012 ; 12 428 | .db #0d044 ; "," 429 | .db #0d046 ; "." 430 | .db #0d031 ; 31 431 | .db #0d218 ; :UP 432 | .db #0d219 ; :DOWN 433 | .db #0d221 ; :RIGHT 434 | .db #0d255 435 | .db #0d255 436 | .db #0d255 437 | .db #0d255 438 | .db #0d255 439 | .db #0d255 440 | .db #0d255 441 | .db #0d255 442 | .db #0d215 ; :LEFT_SHIFT 443 | .db #0d026 ; 26 444 | .db #0d024 ; 24 445 | .db #0d003 ; 3 446 | .db #0d022 ; 22 447 | .db #0d002 ; 2 448 | .db #0d014 ; 14 449 | .db #0d013 ; 13 450 | .db #0d255 451 | .db #0d255 452 | .db #0d255 453 | .db #0d255 454 | .db #0d255 455 | .db #0d255 456 | .db #0d255 457 | .db #0d255 458 | .db #0d217 ; :FN 459 | .db #0d255 460 | .db #0d255 461 | .db #0d032 ; " " 462 | .db #0d255 463 | .db #0d255 464 | .db #0d216 ; :RIGHT_SHIFT 465 | .db #0d220 ; :LEFT 466 | -------------------------------------------------------------------------------- /settings.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8 2 | ; 3 | ; msTERM 4 | ; settings routines manipulating dataflash 5 | ; https://github.com/jcs/mailstation-tools/blob/master/docs/flash-28SF040.pdf 6 | ; 7 | ; Copyright (c) 2019 joshua stein 8 | ; 9 | ; Permission to use, copy, modify, and distribute this software for any 10 | ; purpose with or without fee is hereby granted, provided that the above 11 | ; copyright notice and this permission notice appear in all copies. 12 | ; 13 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 | ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 | ; 21 | 22 | .module settings 23 | 24 | .include "mailstation.inc" 25 | 26 | .equ SDP_LOCK, #SLOT_ADDR + 0x040a 27 | .equ SDP_UNLOCK, #SLOT_ADDR + 0x041a 28 | 29 | .equ settings_ident_0, 'j' 30 | .equ settings_ident_1, 'c' 31 | .equ settings_ident_2, 's' 32 | 33 | .area _DATA 34 | 35 | settings_begin: 36 | settings_ident: 37 | .db #settings_ident_0 38 | .db #settings_ident_1 39 | .db #settings_ident_2 40 | _setting_modem_speed: 41 | .dw #MODEM_DEFAULT_SPEED 42 | _setting_default_source: 43 | .db #SOURCE_WIFI 44 | settings_end: 45 | 46 | .area _CODE 47 | 48 | ; void settings_read(void) 49 | _settings_read:: 50 | push bc 51 | push de 52 | push hl 53 | in a, (#SLOT_DEVICE) ; store device and page 54 | ld h, a 55 | in a, (#SLOT_PAGE) 56 | ld l, a 57 | push hl 58 | ld a, #DEVICE_DATAFLASH ; slot 4 device = dataflash 59 | out (#SLOT_DEVICE), a 60 | ld a, #settings_page 61 | out (#SLOT_PAGE), a 62 | ld hl, #SLOT_ADDR + (settings_sector * 256) 63 | push hl 64 | ld a, (hl) 65 | cp #settings_ident_0 ; verify that the first 3 bytes are 66 | jr nz, skip_loading ; our ident characters before loading 67 | inc hl 68 | ld a, (hl) 69 | cp #settings_ident_1 70 | jr nz, skip_loading 71 | inc hl 72 | ld a, (hl) 73 | cp #settings_ident_2 74 | jr nz, skip_loading 75 | inc hl 76 | ld bc, #settings_end - settings_begin 77 | ld de, #settings_begin 78 | pop hl 79 | ldir ; ld (de), (hl), bc-- until bc == 0 80 | push hl 81 | skip_loading: 82 | pop hl 83 | pop hl 84 | ld a, h 85 | out (#SLOT_DEVICE), a 86 | ld a, l 87 | out (#SLOT_PAGE), a 88 | pop hl 89 | pop de 90 | pop bc 91 | ret 92 | 93 | sdp: 94 | ld a, (#SLOT_ADDR + 0x1823) ; 28SF040 Software Data Protection 95 | ld a, (#SLOT_ADDR + 0x1820) 96 | ld a, (#SLOT_ADDR + 0x1822) 97 | ld a, (#SLOT_ADDR + 0x0418) 98 | ld a, (#SLOT_ADDR + 0x041b) 99 | ld a, (#SLOT_ADDR + 0x0419) 100 | ret 101 | ; caller needs to read final SDP_LOCK or SDP_UNLOCK address 102 | 103 | ; void settings_write(void) 104 | _settings_write:: 105 | push bc 106 | push de 107 | push hl 108 | in a, (#SLOT_DEVICE) ; store device and page 109 | ld h, a 110 | in a, (#SLOT_PAGE) 111 | ld l, a 112 | push hl 113 | ld a, #DEVICE_DATAFLASH ; slot 4 device = dataflash 114 | out (#SLOT_DEVICE), a 115 | xor a 116 | out (#SLOT_PAGE), a ; slot 4 page = 0 117 | call sdp 118 | ld a, (#SDP_UNLOCK) 119 | ld a, #settings_page 120 | out (#SLOT_PAGE), a 121 | ld hl, #SLOT_ADDR + (settings_sector * 256) 122 | sector_erase: 123 | ld (hl), #0x20 ; 28SF040 Sector-Erase Setup 124 | ld (hl), #0xd0 ; 28SF040 Execute 125 | sector_erase_wait: 126 | ld a, (hl) ; wait until End-of-Write 127 | ld b, a 128 | ld a, (hl) 129 | cp b 130 | jr nz, sector_erase_wait 131 | dump_setting_bytes: 132 | ld de, #settings_begin 133 | ld b, #settings_end - settings_begin 134 | byte_program_loop: 135 | ld a, (de) 136 | ld c, a 137 | ld (hl), #0x10 ; 28SF040 Byte-Program Setup 138 | ld (hl), a ; 28SF040 Execute 139 | byte_program: 140 | ld a, (hl) 141 | ld c, a 142 | ld a, (hl) ; End-of-Write by reading it 143 | cp c 144 | jr nz, byte_program ; read until writing succeeds 145 | inc hl 146 | inc de 147 | djnz byte_program_loop 148 | flash_lock: 149 | xor a ; slot page = 0 150 | out (#SLOT_PAGE), a 151 | call sdp 152 | ld a, (#SDP_LOCK) 153 | pop hl 154 | ld a, h 155 | out (#SLOT_DEVICE), a 156 | ld a, l 157 | out (#SLOT_PAGE), a 158 | pop hl 159 | pop de 160 | pop bc 161 | ret 162 | -------------------------------------------------------------------------------- /tools/generate_cursorx_lookup.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # generate_cursorx_lookup 4 | # generate cursorx lookup table using 5 bits for col group and 3 for offset 5 | # msTERM 6 | # 7 | # Copyright (c) 2019 joshua stein 8 | # 9 | # Permission to use, copy, modify, and distribute this software for any 10 | # purpose with or without fee is hereby granted, provided that the above 11 | # copyright notice and this permission notice appear in all copies. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 | # 21 | 22 | # pixels: 01234567012345670123456801234567012345670123456701234567012345670 23 | # col group: | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 24 | # font cell: .....11111.....11111.....11111.....11111.....11111.....11111..... 25 | 26 | File.open("#{__dir__}/../cursorx_lookup.inc", "w+") do |f| 27 | f.puts "; AUTOMATICALLY GENERATED FILE - see tools/generate_cursorx_lookup.rb" 28 | 29 | pcol = 0 30 | 64.times do |x| 31 | col_group = 20 - (pcol / 8) - 1 32 | off = pcol % 8 33 | 34 | v = sprintf("%05b%03b", col_group, off).to_i(2) 35 | 36 | f.puts "\t.db #0x#{sprintf("%02x", v)}\t\t\t; #{sprintf("%08b", v)} - col group #{col_group}, offset #{off}" 37 | 38 | pcol += 5 39 | 40 | if pcol == 160 41 | pcol = 0 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /tools/generate_scancodes.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # generate_scancodes 4 | # generate scancode lookup tables 5 | # msTERM 6 | # 7 | # Copyright (c) 2019 joshua stein 8 | # 9 | # Permission to use, copy, modify, and distribute this software for any 10 | # purpose with or without fee is hereby granted, provided that the above 11 | # copyright notice and this permission notice appear in all copies. 12 | # 13 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 | # 21 | 22 | META_KEY_BEGIN = 200 23 | 24 | KEYS = [ 25 | :MAIN_MENU, 26 | :BACK, 27 | :PRINT, 28 | :F1, 29 | :F2, 30 | :F3, 31 | :F4, 32 | :F5, 33 | :POWER, 34 | :SIZE, 35 | :SPELLING, 36 | :EMAIL, 37 | :PAGE_UP, 38 | :PAGE_DOWN, 39 | :CAPS_LOCK, 40 | :LEFT_SHIFT, 41 | :RIGHT_SHIFT, 42 | :FN, 43 | :UP, 44 | :DOWN, 45 | :LEFT, 46 | :RIGHT, 47 | ] 48 | 49 | META_KEY_NONE = 255 50 | 51 | UPPERCASES = { 52 | "`" => "~", 53 | "1" => "!", 54 | "2" => "@", 55 | "3" => "#", 56 | "4" => "$", 57 | "5" => "%", 58 | "6" => "^", 59 | "7" => "&", 60 | "8" => "*", 61 | "9" => "(", 62 | "0" => ")", 63 | "-" => "_", 64 | "=" => "+", 65 | "\\" => "|", 66 | "[" => "{", 67 | "]" => "}", 68 | ";" => ":", 69 | "'" => "\"", 70 | "," => "<", 71 | "." => ">", 72 | "/" => "?", 73 | } 74 | 75 | CONTROLS = { 76 | "a" => 1, 77 | "b" => 2, 78 | "c" => 3, 79 | "d" => 4, 80 | "e" => 5, 81 | "f" => 6, 82 | "g" => 7, 83 | "h" => 8, 84 | "i" => 9, 85 | "j" => 10, 86 | "k" => 11, 87 | "l" => 12, 88 | "m" => 13, 89 | "n" => 14, 90 | "o" => 15, 91 | "p" => 16, 92 | "q" => 17, 93 | "r" => 18, 94 | "s" => 19, 95 | "t" => 20, 96 | "u" => 21, 97 | "v" => 22, 98 | "w" => 23, 99 | "x" => 24, 100 | "y" => 25, 101 | "z" => 26, 102 | "3" => 27, 103 | "[" => 27, 104 | "4" => 28, 105 | "\\" => 28, 106 | "5" => 29, 107 | "]" => 29, 108 | "6" => 30, 109 | "7" => 31, 110 | "-" => 31, 111 | "/" => 31, 112 | "8" => 127, 113 | } 114 | 115 | SCANCODES = { 116 | 0 => :MAIN_MENU, 117 | 1 => :BACK, 118 | 2 => :PRINT, 119 | 3 => :F1, 120 | 4 => :F2, 121 | 5 => :F3, 122 | 6 => :F4, 123 | 7 => :F5, 124 | 15 => :POWER, 125 | 19 => "@", 126 | 20 => :SIZE, 127 | 21 => :SPELLING, 128 | 22 => :EMAIL, 129 | 23 => :PAGE_UP, 130 | 32 => "`", 131 | 33 => "1", 132 | 34 => "2", 133 | 35 => "3", 134 | 36 => "4", 135 | 37 => "5", 136 | 38 => "6", 137 | 39 => "7", 138 | 48 => "8", 139 | 49 => "9", 140 | 50 => "0", 141 | 51 => "-", 142 | 52 => "=", 143 | 53 => "\b", # backspace 144 | 54 => "\\", 145 | 55 => :PAGE_DOWN, 146 | 64 => "\t", 147 | 65 => "q", 148 | 66 => "w", 149 | 67 => "e", 150 | 68 => "r", 151 | 69 => "t", 152 | 70 => "y", 153 | 71 => "u", 154 | 80 => "i", 155 | 81 => "o", 156 | 82 => "p", 157 | 83 => "[", 158 | 84 => "]", 159 | 85 => ";", 160 | 86 => "'", 161 | 87 => "\n", 162 | 96 => :CAPS_LOCK, 163 | 97 => "a", 164 | 98 => "s", 165 | 99 => "d", 166 | 100 => "f", 167 | 101 => "g", 168 | 102 => "h", 169 | 103 => "j", 170 | 112 => "k", 171 | 113 => "l", 172 | 114 => ",", 173 | 115 => ".", 174 | 116 => "/", 175 | 117 => :UP, 176 | 118 => :DOWN, 177 | 119 => :RIGHT, 178 | 128 => :LEFT_SHIFT, 179 | 129 => "z", 180 | 130 => "x", 181 | 131 => "c", 182 | 132 => "v", 183 | 133 => "b", 184 | 134 => "n", 185 | 135 => "m", 186 | 144 => :FN, 187 | 147 => " ", 188 | 150 => :RIGHT_SHIFT, 189 | 151 => :LEFT, 190 | } 191 | 192 | File.open("#{__dir__}/../scancodes.inc", "w+") do |scf| 193 | scf.puts "; AUTOMATICALLY GENERATED FILE - see tools/generate_scancodes.rb" 194 | scf.puts "\t.equ\tMETA_KEY_BEGIN,\t#0d#{sprintf("%03d", META_KEY_BEGIN)}" 195 | scf.puts "\t.equ\tMETA_KEY_NONE,\t#0d#{sprintf("%03d", META_KEY_NONE)}" 196 | scf.puts 197 | 198 | 3.times do |x| 199 | if x == 0 200 | scf.puts "scancode_table:" 201 | elsif x == 1 202 | scf.puts 203 | scf.puts "scancode_table_uppercase:" 204 | elsif x == 2 205 | scf.puts 206 | scf.puts "scancode_table_control:" 207 | end 208 | 209 | (0 .. SCANCODES.keys.last).each do |sc| 210 | if k = SCANCODES[sc] 211 | origk = k 212 | if k.is_a?(Symbol) 213 | k = META_KEY_BEGIN + KEYS.index(k) 214 | elsif k.is_a?(String) 215 | k = k.ord 216 | end 217 | raise if !k 218 | 219 | if x == 1 220 | if u = UPPERCASES[origk] 221 | k = u.ord 222 | origk = u 223 | elsif ("a" .. "z").include?(origk) 224 | k = origk.upcase.ord 225 | origk = origk.upcase 226 | end 227 | elsif x == 2 228 | if u = CONTROLS[origk] 229 | k = u 230 | origk = u 231 | end 232 | end 233 | 234 | scf.puts "\t.db #0d#{sprintf("%03d", k)}\t\t; #{origk.inspect}" 235 | else 236 | scf.puts "\t.db #0d#{sprintf("%03d", META_KEY_NONE)}" 237 | end 238 | end 239 | end 240 | end 241 | 242 | File.open("#{__dir__}/../meta_keys.h", "w+") do |mkh| 243 | mkh.puts "/* AUTOMATICALLY GENERATED FILE - see tools/generate_scancodes.rb */" 244 | mkh.puts "#define\tMETA_KEY_BEGIN\t#{META_KEY_BEGIN}" 245 | 246 | KEYS.each_with_index do |k,x| 247 | mkh.puts "#define\tKEY_#{k}\t#{k.length < 3 ? "\t" : ""}#{META_KEY_BEGIN + x}" 248 | end 249 | 250 | mkh.puts 251 | mkh.puts "#define\tMETA_KEY_NONE\t#{META_KEY_NONE}" 252 | end 253 | -------------------------------------------------------------------------------- /tools/hexfont2inc.rb: -------------------------------------------------------------------------------- 1 | # 2 | # hexfont2inc 3 | # convert a hex-exported bitmap font (like from gbdfed) to an asm include file 4 | # msTERM 5 | # 6 | # Copyright (c) 2019 joshua stein 7 | # 8 | # Permission to use, copy, modify, and distribute this software for any 9 | # purpose with or without fee is hereby granted, provided that the above 10 | # copyright notice and this permission notice appear in all copies. 11 | # 12 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | # 20 | 21 | chars = [] 22 | char_size = 0 23 | all_bytes = [] 24 | 25 | if !ARGV[0] 26 | puts "usage: #{$0} " 27 | exit 1 28 | end 29 | 30 | File.open(ARGV[0], "r") do |f| 31 | char = 0 32 | 33 | while f && !f.eof? 34 | line = f.gets 35 | 36 | # 0023:A0E0A0E0A000 37 | if !(m = line.match(/^(....):(.+)$/)) 38 | raise "unexpected format: #{line.inspect}" 39 | end 40 | 41 | char = m[1].to_i(16) 42 | char_size = (m[2].length / 2) 43 | 44 | # A0E0A0E0A000 45 | # -> [ "A0", "e0", "A0", "e0", "A0", "00", "00" ] 46 | bytes = m[2].scan(/(..)/).flatten 47 | 48 | # -> [ 0xa0, 0xe0, 0xa0, 0xe0, 0xa0, 0x00, 0x00 ] 49 | bytes = bytes.map{|c| c.to_i(16) } 50 | 51 | # -> [ 101000000, 11100000, ... ] 52 | # -> [ [ 1, 0, 1, 0, 0, 0, 0, 0 ], [ 1, 1, 1, 0, 0, 0, 0, 0 ], ... ] 53 | bytes = bytes.map{|c| sprintf("%08b", c).split(//).map{|z| z.to_i } } 54 | 55 | # -> [ [ 0, 0, 0, 0, 0, 1, 0, 1 ], [ 0, 0, 0, 0, 0, 1, 1, 1 ], ... ] 56 | bytes = bytes.map{|a| a.reverse } 57 | 58 | # -> [ 0x5, 0x7, ... ] 59 | bytes = bytes.map{|a| a.join.to_i(2) } 60 | 61 | chars[char] = bytes 62 | end 63 | end 64 | 65 | (0 .. 255).each do |c| 66 | if chars[c] && chars[c].any? 67 | print ".db " << chars[c].map{|c| sprintf("#0x%02x", c) }.join(", ") 68 | if c >= 32 && c <= 126 69 | print "\t; #{sprintf("%.3d", c)} - #{c.chr}" 70 | end 71 | print "\n" 72 | else 73 | puts ".db " << char_size.times.map{|c| "#0x00" }.join(", ") 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /tools/relink_packed.rb: -------------------------------------------------------------------------------- 1 | #/usr/bin/env ruby 2 | # 3 | # link, figure out header/code/data sizes, then relink with them packed tightly 4 | # msTERM 5 | # 6 | # Copyright (c) 2021 joshua stein 7 | # 8 | # Permission to use, copy, modify, and distribute this software for any 9 | # purpose with or without fee is hereby granted, provided that the above 10 | # copyright notice and this permission notice appear in all copies. 11 | # 12 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | # 20 | 21 | def get_size(area) 22 | File.open("msterm.map", "r") do |f| 23 | while f && !f.eof? 24 | line = f.gets 25 | # _HEADER0 00000000 000000F9 = 249. bytes (ABS,CON) 26 | if m = line.match(/^#{area} .* (\d+)\. *bytes/) 27 | return m[1].to_i 28 | end 29 | end 30 | end 31 | 32 | raise "can't find #{area} in msterm.map" 33 | end 34 | 35 | def sdcc(code_start, data_start) 36 | s = "#{ENV["SDCC"]} --code-loc #{sprintf("0x%04x", code_start)} " + 37 | "--data-loc #{sprintf("0x%04x", data_start)} -o #{ENV["TARGET"]} " + 38 | "#{ARGV.join(" ")}" 39 | puts s 40 | system(s) 41 | end 42 | 43 | base_addr = ENV["BASE_ADDR"].to_i(16) 44 | header_size = 0x1000 45 | code_start = base_addr + header_size 46 | data_start = base_addr + 0x4000 47 | 48 | # link once at a large offset data-loc 49 | sdcc(code_start, data_start) 50 | 51 | header_size = get_size("_HEADER0") 52 | printf "header: %d bytes (0x%04x)\n", header_size, header_size 53 | 54 | code_size = get_size("_CODE") 55 | printf "code: %d bytes (0x%04x)\n", code_size, code_size 56 | 57 | data_size = get_size("_DATA") 58 | printf "data: %d bytes (0x%04x)\n", data_size, data_size 59 | 60 | printf "total: %d bytes (0x%04x)\n", header_size + code_size + data_size, 61 | header_size + code_size + data_size 62 | 63 | code_start = base_addr + header_size 64 | data_start = code_start + code_size 65 | printf "relinking with base: 0x%04x code: 0x%04x data:0x%04x\n", 66 | base_addr, code_start, data_start 67 | 68 | sdcc(code_start, data_start) 69 | -------------------------------------------------------------------------------- /wifi.s: -------------------------------------------------------------------------------- 1 | ; vim:syntax=z8a:ts=8 2 | ; 3 | ; msTERM 4 | ; WiFiStation parallel port routines 5 | ; 6 | ; Copyright (c) 2019-2021 joshua stein 7 | ; 8 | ; Permission to use, copy, modify, and distribute this software for any 9 | ; purpose with or without fee is hereby granted, provided that the above 10 | ; copyright notice and this permission notice appear in all copies. 11 | ; 12 | ; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | ; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | ; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | ; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | ; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | ; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | ; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | ; 20 | 21 | .module wifi 22 | 23 | .include "mailstation.inc" 24 | 25 | .area _CODE 26 | 27 | .equ CONTROL_DIR, #0x0a 28 | .equ CONTROL_DIR_OUT, #0b00001111 29 | .equ CONTROL_DIR_IN, #0 30 | 31 | .equ CONTROL_PORT, #0x9 32 | .equ CONTROL_STROBE_BIT, #0 33 | .equ CONTROL_STROBE, #(1 << CONTROL_STROBE_BIT) 34 | .equ CONTROL_LINEFEED_BIT, #1 35 | .equ CONTROL_LINEFEED, #(1 << CONTROL_LINEFEED_BIT) 36 | .equ CONTROL_INIT, #(1 << 2) 37 | .equ CONTROL_SELECT, #(1 << 3) 38 | 39 | .equ DATA_DIR, #0x2c 40 | .equ DATA_DIR_OUT, #0xff 41 | .equ DATA_DIR_IN, #0 42 | .equ DATA_PORT, #0x2d 43 | 44 | .equ STATUS_PORT, #0x21 45 | .equ STATUS_BUSY, #(1 << 7) 46 | .equ STATUS_ACK, #(1 << 6) 47 | 48 | ; void wifi_init(void); 49 | _wifi_init:: 50 | ; lower control lines 51 | ld a, #CONTROL_DIR_OUT 52 | out (#CONTROL_DIR), a 53 | xor a 54 | out (#CONTROL_PORT), a 55 | ret 56 | 57 | ; at idle, lower all control lines 58 | ; writer: reader: 59 | ; raise strobe 60 | ; see high strobe as high busy 61 | ; raise linefeed 62 | ; see high linefeed as high ack 63 | ; write all data pins 64 | ; lower strobe 65 | ; see low strobe as low busy 66 | ; read data 67 | ; lower linefeed 68 | ; see lower linefeed as high ack 69 | 70 | ; int wifi_write(char); -1 on error, 0 on success 71 | _wifi_write:: 72 | push ix 73 | ld ix, #0 74 | add ix, sp 75 | push bc 76 | push de 77 | ld c, 4(ix) ; char to send 78 | ld a, #DATA_DIR_OUT 79 | out (#DATA_DIR), a ; we're sending out 80 | ld a, #CONTROL_STROBE 81 | out (#CONTROL_PORT), a ; raise strobe 82 | ld de, #0xffff 83 | wait_for_ack: 84 | in a, (#STATUS_PORT) 85 | and #STATUS_ACK ; is ack high? 86 | jr nz, got_ack ; yes, break 87 | dec de ; no, de-- 88 | ld a, d 89 | cp #0 90 | jr nz, wait_for_ack 91 | ld a, e 92 | cp #0 93 | jr nz, wait_for_ack 94 | jr abort_send ; de == 0, fail 95 | got_ack: 96 | ld a, c 97 | out (#DATA_PORT), a ; write data 98 | xor a 99 | out (#CONTROL_PORT), a ; lower strobe 100 | ld de, #0xffff 101 | wait_for_final_ack: 102 | in a, (#STATUS_PORT) 103 | and #STATUS_ACK ; is ack low? 104 | jr z, got_final_ack ; yes, break 105 | dec de ; no, de-- 106 | ld a, d 107 | cp #0 108 | jr nz, wait_for_final_ack 109 | ld a, e 110 | cp #0 111 | jr nz, wait_for_final_ack 112 | got_final_ack: 113 | pop de 114 | pop bc 115 | pop ix 116 | ld hl, #0 ; return 0 117 | ret 118 | abort_send: 119 | xor a 120 | out (#CONTROL_PORT), a ; lower strobe 121 | pop de 122 | pop bc 123 | pop ix 124 | ld hl, #-1 ; return -1 125 | ret 126 | 127 | 128 | ; int wifi_read(void); -1 on nothing read, >= 0 on success returning char 129 | _wifi_read:: 130 | push ix 131 | ld ix, #0 132 | add ix, sp 133 | push de 134 | ld hl, #-1 ; return -1 unless we read something 135 | in a, (#STATUS_PORT) 136 | and #STATUS_BUSY ; is busy high? 137 | jr z, recv_done ; no, bail 138 | and #STATUS_ACK ; but is ack high too? probably bogus 139 | jr nz, recv_done 140 | ld a, #DATA_DIR_IN 141 | out (#DATA_DIR), a ; we're reading in 142 | ld a, #CONTROL_LINEFEED ; raise linefeed 143 | out (#CONTROL_PORT), a 144 | ld de, #0xffff 145 | wait_for_busy_ack: 146 | in a, (#STATUS_PORT) 147 | and #STATUS_BUSY ; is busy high? 148 | jr z, read_data ; no, break 149 | dec de ; no, de-- 150 | ld a, d 151 | cp #0 152 | jr nz, wait_for_busy_ack 153 | ld a, e 154 | cp #0 155 | jr nz, wait_for_busy_ack 156 | jr recv_done ; de == 0, fail 157 | read_data: 158 | in a, (#DATA_PORT) 159 | ld h, #0 160 | ld l, a 161 | raise_lf: 162 | xor a 163 | out (#CONTROL_PORT), a ; lower linefeed 164 | recv_done: 165 | pop de 166 | pop ix 167 | ret 168 | --------------------------------------------------------------------------------