Browse Source

rewriting history .___.

Zeda Thomas 4 years ago
commit
5a35d64d6c
95 changed files with 21956 additions and 0 deletions
  1. 5 0
      .atom-build.json
  2. 10 0
      .gitignore
  3. 3 0
      .gitmodules
  4. 19 0
      Readme.md
  5. 5 0
      Readme.txt
  6. 19 0
      compile
  7. 28 0
      compile.bat
  8. 493 0
      src/01.z80
  9. 1 0
      src/Readme.md
  10. 79 0
      src/SetUpData.z80
  11. 123 0
      src/cmd/fire.z80
  12. 16 0
      src/cmd/input_OS.z80
  13. 240 0
      src/cmd/line.z80
  14. 17 0
      src/cmd/loadtsa.z80
  15. 316 0
      src/cmd/menu.z80
  16. 61 0
      src/cmd/ncr.z80
  17. 52 0
      src/cmd/nom.z80
  18. 99 0
      src/cmd/param.z80
  19. 417 0
      src/cmd/particle.z80
  20. 49 0
      src/cmd/prime.z80
  21. 79 0
      src/cmd/searchstring.z80
  22. 196 0
      src/cmd/solve.z80
  23. 267 0
      src/commandtable.z80
  24. 179 0
      src/compile.z80
  25. 115 0
      src/err.z80
  26. 405 0
      src/experimental/experimental.z80
  27. 1027 0
      src/fonts/ffont.asm
  28. BIN
      src/fonts/gramfont_fix.mfefont
  29. BIN
      src/fonts/gramfont_var.mfefont
  30. 2268 0
      src/fonts/vfont.asm
  31. 44 0
      src/gfx/GetPixelLoc.z80
  32. 104 0
      src/gfx/TileMap1.z80
  33. 338 0
      src/gfx/bigsprite.z80
  34. 201 0
      src/gfx/bigtile.z80
  35. 110 0
      src/gfx/circle.z80
  36. 868 0
      src/gfx/drawrect.z80
  37. 85 0
      src/gfx/filledcircle.z80
  38. 269 0
      src/gfx/gbufToLCD.z80
  39. 88 0
      src/gfx/gbufToLCD_old.z80
  40. 415 0
      src/gfx/gbufToLCD_speed.z80
  41. 33 0
      src/gfx/getpixelloc_nobound.z80
  42. 136 0
      src/gfx/line.z80
  43. 441 0
      src/gfx/rect.z80
  44. 313 0
      src/gfx/sprite.z80
  45. 460 0
      src/gfx/text.z80
  46. 877 0
      src/gfx/tilemap.z80
  47. 127 0
      src/grammer.inc
  48. 4499 0
      src/grammer.z80
  49. 225 0
      src/grammer2.5.inc
  50. 51 0
      src/grammerdata.z80
  51. 10 0
      src/grampkg.z80
  52. 42 0
      src/interrupt.z80
  53. 161 0
      src/io/getKeyChar.z80
  54. 167 0
      src/io/getKeyTok.z80
  55. 357 0
      src/io/input.z80
  56. 473 0
      src/io/menu.z80
  57. 53 0
      src/io/sound.z80
  58. 237 0
      src/isort.z80
  59. 147 0
      src/jmptable.z80
  60. 41 0
      src/jt.py
  61. 24 0
      src/main.z80
  62. 598 0
      src/math.z80
  63. 16 0
      src/math/DEHL_Div_BC_special.z80
  64. 26 0
      src/math/DEHL_Div_C.z80
  65. 56 0
      src/math/HL_Div_BC.z80
  66. 13 0
      src/math/HL_Div_C.z80
  67. 126 0
      src/math/atanbin.z80
  68. 31 0
      src/math/gcdHL_DE.z80
  69. 171 0
      src/math/mul16.z80
  70. 75 0
      src/math/ncr_HL_DE.z80
  71. 51 0
      src/math/rand_single.z80
  72. 123 0
      src/modemenu.z80
  73. 150 0
      src/module.z80
  74. 92 0
      src/module_old.z80
  75. 177 0
      src/parserhook.z80
  76. 30 0
      src/parserinterrupt.z80
  77. 149 0
      src/precompile.z80
  78. 95 0
      src/progmeta.z80
  79. 98 0
      src/ramcode.z80
  80. 57 0
      src/readarc.z80
  81. 147 0
      src/routines.z80
  82. 397 0
      src/startmenu.z80
  83. 97 0
      src/subroutines/ConvOP1.z80
  84. 56 0
      src/subroutines/chardim.z80
  85. 24 0
      src/subroutines/diRestore.z80
  86. 18 0
      src/subroutines/getbyte.z80
  87. 121 0
      src/subroutines/heapsort.z80
  88. 137 0
      src/subroutines/insertdelmem.z80
  89. 26 0
      src/subroutines/searchline.z80
  90. 32 0
      src/subroutines/sendbyte.z80
  91. 349 0
      src/subroutines/zcomp.z80
  92. 240 0
      src/subroutines/zlz_comp.z80
  93. 102 0
      src/subroutines/zlz_decomp.z80
  94. 91 0
      src/tokenhook.z80
  95. 1 0
      z80float

+ 5 - 0
.atom-build.json

@@ -0,0 +1,5 @@
+{
+  "cmd": "./compile",
+  "sh": "true",
+  "cwd": "{PROJECT_PATH}"
+}

+ 10 - 0
.gitignore

@@ -0,0 +1,10 @@
+/screenshot
+/old
+/readme
+/examples
+*.zip
+*.8*
+*.exe
+*.bin
+*.png
+*.gif

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "z80float"]
+	path = z80float
+	url = https://github.com/Zeda/z80float.git

+ 19 - 0
Readme.md

@@ -0,0 +1,19 @@
+# Readme
+For a tutorial/documentation on the commands open [/readme/commands.html](/docs/readme.md)
+
+# Building
+
+Binaries are available in the `/bin` folder, but for developers, building from source might be useful.
+
+This project uses [`spasm-ng`](https://github.com/alberthdev/spasm-ng) to compile, and I use Linux. On windows you can either use the [`linux subsytem`](https://www.windowscentral.com/install-windows-subsystem-linux-windows-10)(only on windows 10) and install spasm from there or you can download the [`spasm-ng`](https://github.com/alberthdev/spasm-ng/releases) for Windows release.
+
+***NOTE:** at the time of this writing, it appears that spasm-ng has a bug that doesn't parse the name field correctly.
+Please use this version for now: https://github.com/alberthdev/spasm-ng/tree/feature/app-name-var-size.*
+
+## Linux:
+From the command line, run `./compile`
+
+## Windows:
+Download Windows [`spasm-ng`](https://github.com/alberthdev/spasm-ng/releases) release, rename it to `spasm.exe` and place it in the project directory. From command prompt or powershell cd to the project directory and run `compile.bat`.
+
+This generates the jump table and compiles the app and Grammer package.

+ 5 - 0
Readme.txt

@@ -0,0 +1,5 @@
+Hey! Look in the "readme" folder, and open "readme.html" in your browser :)
+The easiest way to submit bug reports is through GitHub:
+    https://github.com/Zeda/Grammer2/issues
+
+That's also where the most up-to-date versions will be :)

+ 19 - 0
compile

@@ -0,0 +1,19 @@
+#!/bin/bash
+
+cd src
+
+echo -e "\e[1m\e[37mGenerating grammer2.5.inc\e[0m"
+python jt.py jmptable.z80 grammer2.5.inc
+cp grammer2.5.inc ../docs/grammer2.5.inc
+
+#echo -e "\e[1m\e[37mAssembling Default Package\e[0m"
+#spasm grampkg.z80 ../bin/grampkg.8xv
+
+echo -e "\e[1m\e[37mAssembling App\e[0m"
+spasm grammer.z80 ../bin/grammer.8xk -I ../z80float/single
+
+# Check for an experimental package
+if [ ! -f "experimental/experimental.z80" ];then
+  echo -e "\e[1m\e[37mAssembling Experimental Package\e[0m"
+  spasm experimental/experimental.z80 ../bin/EXPRMNTL.8xv -I single
+fi

+ 28 - 0
compile.bat

@@ -0,0 +1,28 @@
+@echo off
+if exist spasm.exe (
+  echo "Starting Compile..."
+) else (
+  echo "Opening readme..."
+  start "" https://github.com/Zeda/Grammer2/blob/master/Readme.md
+  exit
+)
+
+cd src
+
+echo "Generating grammer2.5.inc"
+python jt.py jmptable.z80 grammer2.5.inc
+copy /Y grammer2.5.inc ..\docs\grammer2.5.inc
+
+echo "Assembling Default Package"
+..\spasm.exe grampkg.z80 ..\bin\grampkg.8xv
+
+echo "Assembling App"
+..\spasm.exe grammer.z80 ..\bin\grammer.8xk -I ..\z80float\single
+
+rem Check for an experimental package
+if exist experimental\experimental.z80 (
+  echo "Assembling Experimental Package"
+  ..\spasm.exe experimental\experimental.z80 ..\bin\EXPRMNTL.8xv -I single
+)
+
+cd..

+ 493 - 0
src/01.z80

@@ -0,0 +1,493 @@
+.org $4000
+#define scrap 8000h
+#include "gfx/bigtile.z80"
+#include "isort.z80"
+;#include "compile.z80"
+
+drawrect:
+#include "gfx/drawrect.z80"
+#include "math/rand_single.z80"
+#include "math/atanbin.z80"
+#include "gfx/circle.z80"
+#include "gfx/filledcircle.z80"
+#include "gfx/tilemap.z80"
+
+p1_GraphToLCD:
+#include "gfx/gbufToLCD_speed.z80"
+
+call_ix_01:
+  jp (ix)
+
+pixelOn_pattern:
+  call getpixelloc
+  ret nc
+  or (hl)
+  ld (hl),a
+  ret
+pixelOff_pattern:
+  call getpixelloc
+  ret nc
+  cpl
+  and (hl)
+  ld (hl),a
+  ret
+pixelToggle_pattern:
+  call getpixelloc
+  ret nc
+  xor (hl)
+  ld (hl),a
+  ret
+
+#include "absSingle.z80"
+#include "negSingle.z80"
+#include "cmpSingle.z80"
+
+#include "randSingle.z80"
+
+#include "acosSingle.z80"
+#include "asinSingle.z80"
+#include "atanSingle.z80"
+#include "acoshSingle.z80"
+#include "asinhSingle.z80"
+#include "atanhSingle.z80"
+#include "coshSingle.z80"
+#include "sinhSingle.z80"
+#include "tanhSingle.z80"
+#include "tanSingle.z80"
+
+
+#include "powSingle.z80"
+#include "pow10Single.z80"
+#include "logSingle.z80"
+#include "lgSingle.z80"
+#include "log10Single.z80"
+
+#include "single2str.z80"
+#include "str2single.z80"
+#include "singleTo_int16.z80"
+
+
+#ifdef INCLUDE_GRAMPKG
+grampkg_start:
+#define EXCLUDE_GRAMPKG_INC
+#include "grampkg.z80"
+grampkg_end:
+#endif
+
+menu_code_start:
+#include "cmd/menu.z80"
+#include "cmd/searchstring.z80"
+
+#include "io/getKeyChar.z80"
+#include "io/getKeyTok.z80"
+#include "io/input.z80"
+#include "io/menu.z80"
+#include "io/sound.z80"
+
+#include "cmd/prime.z80"
+#include "cmd/param.z80"
+#include "cmd/solve.z80"
+#include "subroutines/searchline.z80"
+#include "subroutines/zlz_decomp.z80"
+#include "subroutines/zlz_comp.z80"
+#include "subroutines/heapsort.z80"
+#include "subroutines/zcomp.z80"
+
+p1_PutTokenText:
+  ld bc,PutTokenText
+  ld (prev_page_call_address),bc
+  jp prev_page_call
+
+p1_ParseFullArg:
+  ld hl,ParseFullArg
+  ld (prev_page_call_address),hl
+  jp prev_page_call
+
+p1_ParseNextFullArg:
+  ld hl,ParseNextFullArg
+  ld (prev_page_call_address),hl
+  jp prev_page_call
+
+p1_ParserNext:
+  ld hl,ParserNext
+  ld (prev_page_call_address),hl
+  jp prev_page_call
+
+p1_err_fatal:
+p1_err_syntax:
+  push hl
+  ld hl,err_fatal
+  jr jp_prev_page_call
+
+p1_ErrBadToken:
+  push hl
+  ld hl,ErrBadToken
+  jr jp_prev_page_call
+
+p1_ErrStackOverflow_push:
+  push hl
+  ld hl,ErrStackOverflow_push
+  jr jp_prev_page_call
+
+p1_ErrStackOverflow_pop:
+  push hl
+  ld hl,ErrStackOverflow_pop
+  jr jp_prev_page_call
+
+p1_ErrMem:
+  push hl
+  ld hl,ErrMem
+  jr jp_prev_page_call
+
+p1_VarP:
+  push hl
+  ld hl,VarP
+  jr jp_prev_page_call
+
+p1_parse_by_ptr_to_ptr:
+  push hl
+  ld hl,parse_by_ptr_to_ptr
+  jr jp_prev_page_call
+
+p1_GetGrammerStr:
+  push hl
+  ld hl,GetGrammerStr
+  jr jp_prev_page_call
+
+p1_GetVarInfo2:
+  push hl
+  ld hl,GetVarInfo2
+  jr jp_prev_page_call
+
+p1_GetVarInfo:
+  push hl
+  ld hl,GetVarInfo
+  jr jp_prev_page_call
+
+p1_EndOfLine:
+  push hl
+  ld hl,EndOfLine
+  jr jp_prev_page_call
+
+p1_getKeyDebounce:
+  push hl
+  ld hl,getKeyDebounce
+jp_prev_page_call:
+  ld (prev_page_call_address),hl
+  pop hl
+  jp prev_page_call
+
+verify_package:
+;A:HL points to the data
+;BC is the size of the data
+;Returns carry flag reset if good, carry set if bad
+
+;Need to read 4-byte magic number
+;Need to read the valid version number and size of table
+;Verify that the package has at least 8 bytes
+  inc b
+  dec b
+  jr nz,+_
+  ld b,a
+  ld a,c
+  cp 8
+  ld a,b
+  ret c
+_:
+;If magic number doesn't match, then we quit
+;If it does match, then we'll assume it is formatted
+;correctly. No need to save BC (or DE for that matter)
+;Just need A:HL
+
+  ld bc,6
+  ld de,cmdShadow
+  call ReadArc
+
+;magic number
+  ex de,hl
+  or a
+  ld hl,(cmdShadow)
+  .db 1 ;start of ld bc,**
+  .db "Gr"
+  sbc hl,bc
+  scf
+  ret nz
+  or a
+  ld hl,(cmdShadow+2)
+  .db 1 ;start of ld bc,**
+  .db "am"
+  sbc hl,bc
+  scf
+  ret nz
+;pkg version
+  ld hl,(cmdShadow+4)
+  ld bc,MODULE_VERSION-1
+  sbc hl,bc
+  ret
+
+FS_find_new:
+  ld hl,(FS_begin)
+  jr FS_find_new_start
+
+FS_find_new_loop:
+  ld b,a
+  ld c,a
+  cpir
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+  add hl,bc
+FS_find_new_start:
+  xor a
+  cp (hl)
+  jr nz,FS_find_new_loop
+  ret
+
+FS_createvar_max_01:
+;Input:
+;   HL points to the name
+;   BC is the size of the name (sans null-byte)
+;Output:
+;   HL points to the data
+;   BC is the size
+;   DE points to the name
+;
+  push hl
+  push bc
+
+  call FS_find_new
+  ;HL points to where to write it
+  ;Make sure that HL+BC+2 - (FS_end) < 0
+  push hl
+  add hl,bc
+  inc hl
+  inc hl
+  ld de,(FS_end)
+  ; or a
+  sbc hl,de
+  jp nc,p1_ErrMem
+
+
+  ;Now -HL-1 is going to be the size of the var!
+  ld a,h
+  cpl
+  ld h,a
+  ld a,l
+  cpl
+  ld l,a
+
+
+  pop de
+  pop bc
+  ex (sp),hl
+  ;DE is where to write
+  ;HL is the string
+  ;BC is the size
+  push de
+  ldir
+  ex de,hl
+  pop de
+  pop bc
+  ld (hl),0
+  inc hl
+  ld (hl),c
+  inc hl
+  ld (hl),b
+  inc hl
+  ret
+
+FS_delvar_01:
+  call FS_findvar_01
+  add hl,bc
+  ; or a
+  sbc hl,de
+  ; Need to delete HL bytes at DE
+
+  ;Need to set up the buf_end and buf_top, first
+  push hl
+  ld hl,(FS_end)
+  ld (buf_top),hl
+  call FS_find_new
+  ld (buf_end),hl
+  pop bc
+  ex de,hl
+  call delmem
+  ret nc
+  jp p1_ErrMem
+
+FS_resize_01:
+;HL points to the data
+;BC is the new size
+  ;Need to set up the buf_end and buf_top, though
+  ex de,hl
+  push bc
+  ld hl,(FS_end)
+  ld (buf_top),hl
+  call FS_find_new
+  ld (buf_end),hl
+  pop bc
+  ex de,hl
+
+  dec hl
+  ld d,(hl)
+  ld (hl),b
+  dec hl
+  ld e,(hl)
+  ld (hl),c
+  inc hl
+  inc hl
+  push hl
+  push bc
+
+  add hl,bc
+  ;HL points to the end of the data
+  ;need to deallocate DE-BC bytes (if negative, then bytes are allocated!)
+  ex de,hl
+;  or a
+  sbc hl,bc
+  ex de,hl
+
+  ld b,d
+  ld c,e
+  call delmem
+  pop bc
+  pop hl
+  ret nc
+  jp p1_ErrMem
+
+#include "subroutines/insertdelmem.z80"
+
+
+
+FS_findvar_01:
+;Input:
+;   HL points to the name of the var to find
+;Output:
+;   Carry flag is set if found
+;     HL points to the var's data
+;     DE pointing to the var name
+;     BC is the size
+;
+  ex de,hl
+  ld hl,(FS_begin)
+  jr FS_findvar_begin
+
+FS_findvar_loop:
+
+  ;Then assume the file is not malformed
+  push hl
+  push de
+  call cpstr
+  pop de
+  jr z,FS_file_found
+  pop af    ;Don't need to save the pointer to the file name
+
+
+  ;File not found, so seek the end of the name
+  xor a
+  ld b,a
+  ld c,a
+  cpir
+
+  ;Now HL points to the size bytes
+  ;need to skip the data
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+  add hl,bc
+
+FS_findvar_begin:
+  ;Check if there are any more files
+  ld a,(hl)
+  or a
+  ret z
+
+  ;Check if HL is past FS_end
+  ld bc,FS_end
+  or a
+  sbc hl,bc
+  add hl,bc
+  ret z
+  jr c,FS_findvar_loop
+  scf
+  ret
+
+FS_file_found:
+  inc hl
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+  pop de
+  ret
+
+_:
+  inc de
+  inc hl
+cpstr:
+;Compare two strings at HL and DE
+;returns z if they are equal
+;returns c is DE points to the smaller string
+;returns nc if DE is the bigger (or equal) string.
+  ld a,(de)
+  cp (hl)
+  ret nz
+  or a
+  jr nz,-_
+  ret
+
+LblToken_01:
+  call p1_ParseFullArg
+  push bc
+  ld h,b
+  ld l,c
+  call p1_GetGrammerStr
+  pop hl
+  push bc
+
+  ld de,OP2
+  ld a,3Fh
+  ld (de),a
+  inc de
+  ld a,3Ah
+  ld (de),a
+  inc de
+  ldir
+  ld a,3Fh
+  ld (de),a
+  ld hl,(parsePtr)
+  ld a,(hl)
+  cp 2Bh
+  jr nz,+_
+  inc hl
+  ld (parsePtr),hl
+  call p1_GetVarInfo2
+  jr nc,LblToken_ptrdone
+_:
+  ld hl,(progEnd)
+  ld de,(progStart)
+  or a
+  sbc hl,de
+  ld b,h
+  ld c,l
+  ex de,hl
+LblToken_ptrdone:
+  ld de,OP2
+  pop ix
+  ld de,3
+  add ix,de
+  ld de,OP2
+  call searchstring_routine
+  jp nc,p1_ErrBadToken
+  inc hl
+  call p1_EndOfLine
+  ld b,h
+  ld c,l
+  ret
+
+#include "tokenhook.z80"
+#include "modemenu.z80"
+
+.echo "Page 1: ",$8000-$," bytes remaining"

+ 1 - 0
src/Readme.md

@@ -0,0 +1 @@
+My near-term plan is to do some simple optimizations when copying programs to RAM. My first idea is to replace all Lbl commands with their actual pointer value since labels are static. This will also allow me to remove labels/comments from executing code making it smaller and slightly faster. Note that I won't be doing this to code already in RAM :(

+ 79 - 0
src/SetUpData.z80

@@ -0,0 +1,79 @@
+SetUpData:
+  bcall(_RunIndicOff)
+  call setup_readarc
+
+;initialize the float rand routine
+  ld hl,randinit
+  ld (next_page_call_address),hl
+  call next_page_call
+
+  ld hl,floatstack_bottom
+  ld (floatstack_ptr),hl
+  ld hl,seed2+1
+  set 6,(hl)
+  dec l
+  dec l
+  ld a,r \ xor (hl) \ ld (hl),a
+  ld hl,plotSScreen
+  ld (BufPtr),hl
+  ld (GrayBufPtr),hl
+  ld hl,PBuf
+  ld (PBufPtr),hl
+  ld hl,766
+  ld (PBuf),hl
+  ld a,3
+  ld (OutputLogic),a
+  ld (TextPauseTime),a
+  ld hl,FontSet
+  ld (FontPointer),hl
+  xor a
+  ld (font_ptr_page),a
+  ld (module_count),a
+  ld h,a
+  ld l,a
+  ld (flags+33),a
+  ld (flags+34),hl
+  ld (IntLoc),hl
+  ld (PBufType),hl
+  ld (textmode),a
+  ld hl,$0155
+  ld (GrayMask),hl
+
+  ld hl,saveSScreen+256
+  ld (stack_base),hl
+  ld (stack_ptr),hl
+  inc h
+  inc h
+  ld (stack_top),hl
+
+  ld hl,textShadow
+  ld (input_base),hl
+  ld hl,128
+  ld (input_size),hl
+
+
+#ifndef INCLUDE_GRAMPKG
+;Verify the grammer package
+  ld hl,verify_package
+  ld (next_page_call_address),hl
+  ld hl,s_grampkg
+  rst rMov9ToOP1
+  bcall(_ChkFindSym)
+  ld a,b
+  ld b,0
+  call nc,next_page_call
+  jr nc,+_
+  set nogrampkg,(iy+InternalFlags)
+_:
+#endif
+
+  pop hl
+  ld (SPSave),sp
+  jp (hl)
+setupRAMdata:
+;not speed critical
+  ld de,8100h
+  ld hl,RAMCodeStart
+  ld bc,RAMCodeEnd-RAMCodeStart
+  ldir
+  ret

+ 123 - 0
src/cmd/fire.z80

@@ -0,0 +1,123 @@
+FireCycle:
+  dec a \ jr nz,FireCycle2
+
+  ld a,e
+  ld de,12
+  ex de,hl
+  add hl,de
+  ld bc,2F4h
+  or a
+  jr z,BlackFireLoop
+FireLoop:
+  call Random
+  cpl
+  and (hl)
+  ld (de),a
+  inc de
+  cpi
+  jp pe,FireLoop
+  ret
+BlackFireLoop:
+  call Random
+  or (hl)
+  ld (de),a
+  inc de
+  cpi
+  jp pe,BlackFireLoop
+  ret
+FireCycle2:
+  dec a
+  ret nz
+  push de
+  push hl
+  call ParseNextFullArg
+;Y,X
+  ld h,b
+  ld l,c
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  pop bc
+  add hl,bc
+  push hl
+  call ParseNextFullArg
+  pop hl
+  add hl,bc
+  push hl
+;HL is now the start location
+;Width,Height:
+  call ParseNextFullArg
+  ld a,c
+  push af
+  call ParseNextFullArg
+  pop af
+  ld b,a
+  pop hl
+  pop de
+;b is width
+;c is height
+;e is the particle type
+  ld d,c
+  ld a,12
+  sub b
+  ld c,a
+  ld a,e \ or a
+  ld a,d
+  ld de,12
+  ex de,hl
+  add hl,de
+;a=height
+;b is width
+;c=12-b
+  jr z,BlackFireLoop2
+FireLoop2:
+  push af
+  push bc
+  call Random
+  cpl
+  and (hl)
+  ld (de),a
+  inc de
+  inc hl
+  djnz FireLoop2+2
+  add hl,bc
+  ex de,hl
+  add hl,bc
+  ex de,hl
+  pop bc
+  pop af
+  dec a
+  jr nz,FireLoop2
+  ret
+BlackFireLoop2:
+  push af
+  push bc
+  call Random
+  or (hl)
+  ld (de),a
+  inc de
+  inc hl
+  djnz BlackFireLoop2+2
+  add hl,bc
+  ex de,hl
+  add hl,bc
+  ex de,hl
+  pop bc
+  pop af
+  dec a
+  jr nz,BlackFireLoop2
+  ret
+Random:
+;preserve HL,DE,BC
+  push hl
+  push de
+  push bc
+  call prng16
+  ld a,h
+  and l
+  and b
+  pop bc
+  pop de
+  pop hl
+  ret

+ 16 - 0
src/cmd/input_OS.z80

@@ -0,0 +1,16 @@
+;From Axe
+p_Input:
+ res 6,(iy+$1C)
+ set 7,(iy+$09)
+ xor a
+ ld (ioPrompt),a
+ B_CALL(_GetStringInput)
+ B_CALL(_ZeroOP1)
+ ld a,$2D
+ ld (OP1+1),a
+ rst rFindSym
+ inc de
+ inc de
+ ex de,hl
+ ret
+__InputEnd:

+ 240 - 0
src/cmd/line.z80

@@ -0,0 +1,240 @@
+LineToken:
+
+  call ParseNextFullArg_Inc
+  push bc
+  call ParseNextFullArg
+  pop de
+  ld b,e
+  push bc
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+  pop de
+  ld b,e
+  push bc
+  cp $2b
+  ld c,1
+  call z,ParseNextFullArg
+  cp $2b
+  ld a,c
+  push af
+  call ParseNextFullArg_BC
+  cp $2b
+  jr nz,L5971
+  inc hl
+  ld a,(hl)
+  cp $ae
+  jr nz,+_
+  call ParseNextFullArg_Inc
+  push bc
+  jr L596f
+_:
+  ld hl,$80ff
+  push hl
+_:
+  push hl
+  call ParseNextFullArg
+  pop hl
+  ld (hl),c
+  dec l
+  jp p,+_
+  cp $2b
+  jr z,-_
+_:
+  ld (hl),$ff
+L596f:
+  pop ix
+L5971:
+  pop af
+  pop de
+  pop hl
+  ld c,a
+  ld a,d
+  sub h
+  ld d,a
+  ld a,e
+  sub l
+  ld e,a
+  ld a,c
+DrawLine:
+  di
+  res FactorialFlag,(iy+InternalFlag)
+  res Mod2nd,(iy+InternalFlag)
+  bit 2,a
+  jr z,+_
+  set FactorialFlag,(iy+InternalFlag)
+_:
+  bit 3,a
+  jr z,+_
+  set Mod2nd,(iy+InternalFlag)
+_:
+  and $f3
+  ld bc,$A62F
+  dec a
+  jr nz,+_
+  ld bc,$00B6
+_:
+  dec a
+  jr nz,+_
+  ld bc,$00AE
+_:
+  ld ($8101),bc
+  ld a,$ff
+  ld ($811a),a
+  res grayMode,(iy+InternalFlag)
+  ld a,(ix)
+  bit Mod2nd,(iy+InternalFlag)
+  jr nz,+_
+  inc a
+_:
+  ld ($8109),a
+  or a
+  call z,L7158
+  ld c,0
+  ld a,d
+  bit 7,a
+  jr z,+_
+  neg
+  set 6,c
+  ld d,a
+_:
+  ld a,e
+  bit 7,a
+  jr z,+_
+  neg
+  set 7,c
+  ld e,a
+_:
+  ld b,a
+  ex af,af'
+  ld a,c
+  exx
+  rla
+  ld de,12
+  ld bc,1
+  jr nc,+_
+  ld de,-12
+_:
+  rla
+  jr nc,+_
+  dec bc
+  dec bc
+_:
+  exx
+  ld a,h
+  push hl
+  push bc
+  ld h,00
+  ld b,h
+  ld c,l
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  ld c,a
+  sra c
+  sra c
+  sra c
+  jp p,+_
+  dec b
+_:
+  add hl,bc
+  ld bc,(gbuf_temp)
+  add hl,bc
+  and $07
+  ld b,a
+  ld a,$80
+  jr z,+_
+  rrca
+  djnz $-1
+_:
+  push hl
+  exx
+  pop hl
+  exx
+  ex af,af'
+  pop bc
+  pop hl
+  sla e
+  jr nz,L5a2b
+  ld b,d
+_:
+  call L5a6f
+  call L5a5d
+  djnz -_
+  ret
+
+L5a2b:
+ sla d
+L5a2d:
+ call L5a6f
+ sub d
+ jr c,L5a39
+ call L5a4b
+ djnz L5a2d
+ ret
+
+L5a39:
+ call L5a5d
+ add a,e
+ jr c,L5a45
+ call L5a6f
+ jp L5a39
+L5a45:
+ call L5a4b
+ djnz L5a2d
+ ret
+
+L5a4b:
+ bit Mod2nd,(iy+InternalFlag)
+ call nz,$8106
+ exx
+ add hl,de
+ exx
+ inc l
+ bit 7,c
+ ret z
+ dec l
+ dec l
+ ret
+
+L5a5d:
+ ex af,af'
+ rrca
+ inc h
+ bit 6,c
+ jr z,+_
+ dec h
+ dec h
+ rlca
+ rlca
+_:
+  jr nc,+_
+  exx
+  add hl,bc
+  exx
+_:
+  ex af,af'
+  ret
+
+L5a6f:
+  bit FactorialFlag,(iy+InternalFlag)
+  call nz,$8106
+  bit grayMode,(iy+InternalFlag)
+  ret nz
+  push af
+  ld a,l
+  cp $40
+  jr nc,+_
+  ld a,h
+  cp $60
+  jr nc,+_
+  ex af,af'
+  exx
+  call $8100
+  exx
+  ex af,af'
+_:
+  pop af
+  ret
+.echo "DrawLine : ",$-DrawLine

+ 17 - 0
src/cmd/loadtsa.z80

@@ -0,0 +1,17 @@
+LoadTSA:
+  di
+  push af
+  push bc
+  push de
+  push ix
+  ex (sp),hl
+  ld c,(hl) \ inc hl
+  ld b,(hl) \ inc hl
+  ld de,TSA
+  ;should I do a fastLDIR ?
+  ldir
+  pop hl
+  pop de
+  pop bc
+  pop af
+  ret

+ 316 - 0
src/cmd/menu.z80

@@ -0,0 +1,316 @@
+menuMem = saveSScreen
+;Now define where vars are located, 17 bytes required in all.
+textbox_top     = menuMem
+textbox_left    = textbox_top+1    ;needs to follow textbox_top
+textbox_bottom  = menuMem+2
+textbox_width   = textbox_bottom
+textbox_right   = textbox_bottom+1 ;needs to follow textbox_bottom
+menucallptr     = menuMem+4
+menutop         = menuMem+6
+menucur         = menuMem+8
+menuselection   = menuMem+10
+menuheader_ptr  = menuMem+12
+menuheader_coord= menuMem+14
+menuheader_cur  = menuMem+16  ;1 byte
+menu_num_items  = menuMem+17  ;2 bytes
+menu_get        = menuMem+19
+menu_sel        = menuMem+21
+menu_temp       = menuMem+23
+menuopts        = menuMem+25
+menudefault     = TempWord1
+menutopinit     = TempWord4
+
+#define MENU_MAX_ELEMENTS ((menuMem+768-menuopts)>>1)
+
+;Menu:
+;Get the y coordinate
+  ld hl,(parsePtr)
+  ld a,(hl)
+  cp $AE
+  jp z,fancymenu
+  call p1_ParseFullArg
+  push bc
+
+;Get the x coordinate
+  call p1_ParseNextFullArg
+  pop hl
+  ld h,c
+
+;Save the coords
+  ld (textbox_top),hl
+
+; Get the width of the menu
+  call p1_ParseNextFullArg
+  ld (textbox_width),bc
+
+;Get the header
+  call p1_ParseNextFullArg
+  ld (menuheader_ptr),bc
+
+  ld hl,menuopts
+  ld bc,0
+menu_param_loop:
+  inc bc
+  ld a,b
+  cp MENU_MAX_ELEMENTS>>8
+  jr nz,+_
+  ld a,c
+  cp MENU_MAX_ELEMENTS&255
+  jp menu_err
+_:
+  push bc
+  push hl
+  ld hl,(parsePtr)
+  inc hl
+  ld a,(hl)
+  cp $AE
+  jr z,menu_select_default
+
+  call p1_ParseNextFullArg
+  pop hl
+  ld (hl),c
+  inc hl
+  ld (hl),b
+  inc hl
+  pop bc
+  cp $2B
+  jr z,menu_param_loop
+_:
+  ld de,0
+  jr +_
+menu_select_default:
+  pop hl
+  call p1_ParseNextFullArg
+  ld h,b
+  ld l,c
+  dec hl
+  pop bc
+  dec bc
+  ;If hl is negative, set DE to 0
+  ld a,h
+  add a,a
+  jr c,-_
+  ;set DE to min(HL,BC)
+  ld d,b
+  ld e,c
+  dec de
+  sbc hl,de
+  jr nc,+_
+  add hl,de
+  ex de,hl
+_:
+
+  ld (menudefault),de
+
+;Save the number of elements
+  ld (menu_num_items),bc
+
+;Now we need to render the menu, but first we'll get the height of the menu in pixels
+;4+font_height*min(9-int(y/font_height),BC+1
+  ld a,(textbox_top)
+  ld e,9
+  add a,a
+  jr c,cmp_menu_height
+  .db $FE
+_:
+  dec e
+  sub FONT_HEIGHT*2
+  jr nc,-_
+cmp_menu_height:
+;E is the max height
+;if BC+1 is smaller, use that
+  inc bc
+  inc b
+  dec b
+  jr nz,+_
+  ld a,c
+  cp e
+  jr nc,+_
+  ld e,c
+_:
+
+;Now E is the number of items shown
+;if menudefault>=E, then need to set menutopinit to menudefault-E+1
+  ld hl,(menudefault)
+  inc h
+  dec h
+  jr nz,$+6
+  ld a,l
+  sub e
+  jr c,+_
+  ld l,a
+  jr nc,$+3
+  inc h
+  inc hl
+  jr $+5
+_:
+  ld hl,0
+  ld (menutopinit),hl
+
+;now do E*FONT_HEIGHT+4, given that it won't overflow 8 bits
+  ld a,5
+  ld b,FONT_HEIGHT
+_:
+  add a,e
+  djnz -_
+
+;now set the width and height
+  ld e,a
+  ld a,(textbox_width)
+  ld d,a
+
+  ld ix,menu_command_lookup
+
+menu_entry:
+  ;Set the default graphics buffer
+  ld hl,(BufPtr)
+  ld (gbuf_temp),hl
+
+
+;save and set the the font method
+  ld a,(textmode)
+  push af
+  ld a,2
+  ld (textmode),a
+  ld hl,(FontPointer)
+  push hl
+  ld hl,FontSet
+  ld (FontPointer),hl
+  xor a
+  ld (font_ptr_page),a
+  ld bc,(textbox_top)
+  ld hl,(menuheader_ptr)
+
+  call menuroutine
+
+  pop hl
+  ld (FontPointer),hl
+  xor a
+  ld (font_ptr_page),a
+  pop af
+  ld (textmode),a
+  ret
+
+fancymenu:
+;header,y,x,h,w,get,sel
+  call p1_ParseNextFullArg
+  ld (menuheader_ptr),bc
+
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  pop hl
+  ld h,c
+  ld (textbox_top),hl
+
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  pop hl
+  ld h,c
+  push hl ;w,h
+
+  call p1_ParseNextFullArg
+  ld (menu_get),bc
+
+  call p1_ParseNextFullArg
+  ld (menu_sel),bc
+
+  ld hl,0
+  ld (menutopinit),hl
+  ld (menudefault),hl
+
+  pop de
+  ld ix,fancymenu_lookup
+  jr menu_entry
+
+
+menu_err:
+  ld hl,ErrStackOverflow_push
+  ld (prev_page_call),hl
+  jp prev_page_call
+
+fancymenu_lookup:
+;save the current parsePtr
+  ld hl,(parsePtr)
+  push hl
+
+;save Ans and replace with the current cursor
+  ld hl,(Ans)
+  push hl
+
+;save thetaprime
+  ld hl,(ThetaPrimeVar)
+  push hl
+
+;Save the text coordinates
+  ld hl,(TextRow)
+  push hl
+
+;Set ThetaPrime
+  ld l,a
+  ld h,0
+  ld (ThetaPrimeVar),hl
+
+
+
+;now set the location to start parsing at
+  ld hl,(menu_get)
+  jr nc,+_
+  ld hl,(menu_sel)
+  ld bc,(menucur)
+_:
+  ld (parsePtr),hl
+
+;set Ans
+  ld (Ans),bc
+
+;Now parse
+  call p1_ParserNext
+
+;Restore text coordinates
+  pop hl
+  ld (TextRow),hl
+
+;restore thetaprimevar
+  pop hl
+  ld (ThetaPrimeVar),hl
+
+;restore Ans
+  pop hl
+  ld (Ans),hl
+
+;restore parsePtr
+  pop hl
+  ld (parsePtr),hl
+
+;return 0 if failed
+  ld h,b
+  ld l,c
+  ld a,b
+  or c
+  ret nz
+  scf
+  ret
+
+
+menu_command_lookup:
+  jr c,menu_command_select
+;get element number BC
+  ld hl,(menu_num_items)
+  scf
+  sbc hl,bc
+  ret c
+  ld hl,menuopts
+  add hl,bc
+  add hl,bc
+  ld a,(hl)
+  inc hl
+  ld h,(hl)
+  ld l,a
+  ret
+
+menu_command_select:
+  ld bc,(menucur)
+  inc bc
+  ret

+ 61 - 0
src/cmd/ncr.z80

@@ -0,0 +1,61 @@
+nCrToken:
+  push bc
+  call ParseFullArg
+  pop hl
+  ld d,b \ ld e,c
+  call ncr_HL_DE
+  ld b,h
+  ld c,l
+  ret
+#include "math/ncr_HL_DE.z80"
+
+; ;===============================================================
+; nCrAlgorithm:
+; ;===============================================================
+; ;Inputs:
+; ;     hl is "n"
+; ;     de is "r"
+; ;Outputs:
+; ;     interrupts off
+; ;     a is 0
+; ;     bc is the result
+; ;     de is "n"
+; ;     hl is the result
+; ;     a' is not changed
+; ;     bc' is "r"+1
+; ;     de' is an intermediate calculation
+; ;     hl' is "r" or the compliment, whichever is smaller
+; ;===============================================================
+;   or a                     ;reset carry flag
+;   sbc hl,de
+;   ret c                    ;r should not be bigger than n
+;   di
+;   sbc hl,de \ add hl,de
+;   jr nc,$+3
+;   ex de,hl              ;hl is R
+;
+;   push de
+;   ld bc,1                 ;A
+;   exx
+;   pop de                  ;N
+;   ld bc,1                 ;C
+;   ld h,b \ ld l,c         ;D
+; nCrLoop:
+;   push de
+;   push hl
+;   call DE_Times_BC
+;   push hl \ exx \ pop de
+;   push hl
+;   call DE_Div_BC
+;   pop de
+;   push hl \ ex de,hl \ exx \ pop hl
+;   ld b,h \ ld c,l
+;   pop de \ add hl,de
+;   pop de \ inc de
+;   exx
+;   inc bc
+;   or a \ sbc hl,bc \ add hl,bc
+;   exx
+;   jr nc,nCrLoop
+;   ld b,h \ ld c,l
+;   ret

+ 52 - 0
src/cmd/nom.z80

@@ -0,0 +1,52 @@
+  dec hl \ dec hl \ dec hl
+  ld a,(hl) \ cp 'M' \ jr nz,+_
+  dec hl
+  ld a,(hl) \ cp 'O' \ jr nz,+_
+  call ParseFullArg
+  ld a,c \ and 3
+  add a,12
+  out (16),a
+  ret
+_:
+
+; Save the location of the names of the variables to save.
+  ld hl,(parsePtr)
+  dec hl
+  push hl
+  ld (parsePtr),hl
+
+; Save the stack base
+  ld hl,(stack_ptr)
+  push hl
+  call pushvars_00
+
+; Now resume parsing
+  call ParserNext
+
+;Restore vars!
+; Restore stack pointer to the original state.
+  pop hl
+  ld (stack_ptr),hl
+
+; Get the vars list
+  ex (sp),hl
+
+; Begin looping. If the stack overflowed, there would have been an error,
+; so no need to verify
+_:
+  inc hl
+  ld a,(hl)
+  inc hl
+  call VarP
+  jr nc,+_
+  ex de,hl
+  ex (sp),hl
+  ldi
+  ldi
+  ex (sp),hl
+  ld a,(hl)
+  cp 2Bh
+  jr z,-_
+_:
+  pop hl
+  ret

+ 99 - 0
src/cmd/param.z80

@@ -0,0 +1,99 @@
+ParamToken:
+; This is a fancy routine for pushing and popping data, as well as loading parameters
+;       ParamA,B,...      Loads parameters into these values.
+;           For example, if a routine is called with `prgm(Z,1,2,3` then `ParamA,B,C` will store 1->A, 2->B, 3->C
+;       Param'A,0,B,...   acts as a push operation
+;       Param°A,B,...     acts as a pop operation
+  ld a,(hl)
+  cp $AE    ;'
+  jr z,pushvars
+  cp $0B    ;°
+  jr z,popvars
+;Basically, ]?->A:]?->B:... etc.
+  .db $FE   ;start of `cp *`
+parse_param:
+  inc hl
+  ld a,(hl)
+  inc hl
+  call p1_VarP
+  jr nc,+_
+
+  ;Need to parse the next parameter
+  push de
+  push hl
+  ld hl,qmarkVar
+  call p1_parse_by_ptr_to_ptr
+  pop hl
+  ld (hl),c
+  inc hl
+  ld (hl),b
+  pop hl
+  ld a,(hl)
+  cp 2Bh
+  jr z,parse_param
+_:
+  dec hl
+  ld (parsePtr),hl
+  ret
+pushvars:
+  call p1_ParseNextFullArg
+  ld a,(hl)
+  call pushbc
+  cp 2Bh
+  jr z,pushvars
+  ret
+popvars:
+  inc hl
+  ld a,(hl)
+  inc hl
+  call p1_VarP
+  jr nc,+_
+  ;Need to pop the last item off the stack and copy it to where HL points
+  call popbc
+  ld (hl),c
+  inc hl
+  ld (hl),b
+  ex de,hl
+  ld a,(hl)
+  cp 2Bh
+  jr z,popvars
+_:
+  dec hl
+  ld (parsePtr),hl
+  ret
+
+
+popbc:
+  push hl
+  push de
+  ; Make sure (stack_ptr)-2-(stack_base)>=0
+
+  ld hl,(stack_ptr)
+  ld de,(stack_base)
+  dec hl
+  scf
+  sbc hl,de
+  jp c,p1_ErrStackOverflow_pop
+  add hl,de
+  ld (stack_ptr),hl
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  pop de
+  pop hl
+  ret
+pushbc:
+  ld de,(stack_ptr)
+  ld hl,(stack_top)
+  inc de
+  inc de
+  or a
+  sbc hl,de
+  jp c,p1_ErrStackOverflow_push
+  ex de,hl
+  ld (stack_ptr),hl
+  dec hl
+  ld (hl),b
+  dec hl
+  ld (hl),c
+  ret

+ 417 - 0
src/cmd/particle.z80

@@ -0,0 +1,417 @@
+PToRy:
+  call ParseFullArg
+  cp 2Bh
+  ld (PBufType),bc
+  ld bc,%01100001
+  jr nz,GetRuleNum+3
+  inc hl
+  ld a,(hl)
+  sub 2Ah
+  jr nz,GetRuleNum
+  ld b,h
+  ld c,l
+  ld h,a
+  ld l,a
+ConvRuleLoop:
+  inc bc
+  ld a,(bc)
+  call EndOArg
+  jr nz,more_rules
+  cp 2Bh
+  jr z,more_rule_args
+_:
+  ld a,h \ and $F0
+  jr nz,+_
+  add hl,hl
+  add hl,hl
+  add hl,hl
+  add hl,hl
+  jr -_
+_:
+  ld (PBufRule),hl
+  ret
+more_rule_args:
+  add hl,hl
+  add hl,hl
+  add hl,hl
+  add hl,hl
+more_rules:
+  cp 'U'
+  jr nz,+_
+  set 3,l
+_:
+  cp 'R'
+  jr nz,+_
+  set 2,l
+_:
+  cp 'L'
+  jr nz,+_
+  set 1,l
+_:
+  cp 'D'
+  jr nz,ConvRuleLoop
+  set 0,l
+  jr ConvRuleLoop
+GetRuleNum:
+  call ParseNextFullArg
+  ld a,b
+  rlca \ rlca \ rlca \ rlca
+  ld (PBufRule),a
+  ld a,c
+  rlca \ rlca \ rlca \ rlca
+  ld (PBufRule+1),a
+  ret
+RToPr:
+  ld hl,(PBufPtr)
+  inc hl \ inc hl
+  ld (hl),0 \ inc hl
+  ld (hl),0 \ inc hl
+  ret
+
+;===============================================================
+RToPTheta:
+;===============================================================
+;This executes one particle cycle
+;===============================================================
+  ld a,(hl)
+  call EndOArg
+  jr z,DefaultBuffer
+  call ParseFullArg
+  push bc
+  cp $2b
+  call ParseNextFullArg_Buffer
+  pop bc
+g_ParticleCycle:
+  ld (PBufPtr),bc
+DefaultBuffer:
+  ld hl,(PBufPtr)
+  ld a,(PBufType)
+  ld de,(PBufRule)
+  or a
+  jr nz,+_
+  ld de,%0001011000000000
+_:
+  dec a
+  jr nz,+_
+  ld de,%0001011010000000
+_:
+  ld (TempWord1),de
+;RuleSet=DE
+  inc hl
+  inc hl
+  ld (TempWord4),hl
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  ld a,b
+  or c
+  ret z
+  inc hl
+;BC now is the number of particles
+;HL now points to the particles
+;(TempWord1) is the ruleset
+  ld (TempWord2),bc
+  add hl,bc
+  add hl,bc
+  dec hl
+  ld (TempWord3),hl
+  inc hl
+  sbc hl,bc
+  sbc hl,bc
+;TempWord2 contains the number of particles left in the buffer
+;TempWord3 points to the last particle
+;TempWord4 points to the particle size bytes
+ParticleDrawLoop:
+  push bc
+  push hl
+  call EraseParticle
+  push hl
+  pop ix
+  ld hl,(TempWord1)
+  push af
+  ld a,(flags+ParticleFlag)
+  and %11100000
+  ld (flags+ParticleFlag),a
+  ld a,b
+  or a
+  jr nz,PLeft
+  set Xis0,(iy+ParticleFlag)
+  jr PUpDown
+PLeft:
+  sub 95
+  jr c,PUpDown
+  set Xis95,(iy+ParticleFlag)
+PUpDown:
+  ld a,c
+  or a
+  jr nz,PDown
+  set Yis0,(iy+ParticleFlag)
+  jr PPPp
+PDown:
+  sub 63
+  jr c,PPPp
+  set Yis63,(iy+ParticleFlag)
+PPPp:
+  pop bc
+  ld c,0
+ParticleTestLoop:
+  add hl,hl
+  jr nc,CheckPRight
+  ld a,b
+  and (ix-12)
+  jr nz,CheckPRight
+  ld c,8
+  bit Yis0,(iy+ParticleFlag)
+  jr z,CheckPRight
+  set OffScrn,(iy+ParticleFlag)
+CheckPRight:
+  add hl,hl
+  jr nc,CheckPLeft
+  ld a,b
+  rrca
+  jr c,$+7
+  and (ix)
+  jr +_
+  and (ix+1)
+_:
+  jr nz,CheckPLeft
+  ld a,c
+  or a
+  jr z,$+8
+  ld a,r
+  bit 4,a
+  jr nz,+_
+  ld c,4
+_:
+  bit Xis95,(iy+ParticleFlag)
+  jr z,CheckPLeft
+  set OffScrn,(iy+ParticleFlag)
+CheckPLeft:
+  add hl,hl
+  jr nc,CheckPDown
+  ld a,b
+  rlca
+  jr c,$+7
+  and (ix)
+  jr +_
+  and (ix-1)
+_:
+  jr nz,CheckPDown
+  ld a,c
+  or a
+  jr z,$+8
+  ld a,r
+  bit 4,a
+  jr nz,+_
+  ld c,2
+_:
+  bit Xis0,(iy+ParticleFlag)
+  jr z,CheckPDown
+  set OffScrn,(iy+ParticleFlag)
+CheckPDown:
+  add hl,hl
+  jr nc,PChecked
+  ld a,b
+  and (ix+12)
+  jr nz,PChecked
+  ld a,c
+  or a
+  jr z,$+8
+  ld a,r
+  bit 4,a
+  jr nz,+_
+  ld c,1
+_:
+  bit Yis63,(iy+ParticleFlag)
+  jr z,PChecked
+  set OffScrn,(iy+ParticleFlag)
+PChecked:
+  ld a,c
+  or a
+  jr nz,MoveP
+  ld a,h
+  or l
+  jp nz,ParticleTestLoop
+MoveP:
+  pop hl
+  ld a,c
+  or a
+  jr z,MovedP
+  ld a,b
+  cpl
+  and (ix)
+  ld (ix),a
+  bit OffScrn,(iy+ParticleFlag)
+  jr nz,RemoveParticle
+  ld a,b
+  rrc c
+  jr nc,+_
+  or (ix+12)
+  ld (ix+12),a
+  inc (hl)
+  jr MovedP
+_:
+  rrc c
+  jr nc,$+23
+  rlca
+  jr nc,$+10
+  or (ix-1)
+  ld (ix-1),a
+  jr $+8
+  or (ix)
+  ld (ix),a
+  inc hl
+  dec (hl)
+  jr MovedP+1
+  rrc c
+  jr nc,$+23
+  rrca
+  jr nc,$+10
+  or (ix+1)
+  ld (ix+1),a
+  jr +_
+  or (ix)
+  ld (ix),a
+_:
+  inc hl
+  inc (hl)
+  jr MovedP+1
+  or (ix-12)
+  ld (ix-12),a
+  dec (hl)
+MovedP:
+  inc hl
+  pop bc
+  cpi
+  jp pe,ParticleDrawLoop
+  ret
+RemoveParticle:
+;HL points to particle data
+;TempWord2 contains the number of particles left in the buffer
+;TempWord3 points to the last particle
+;TempWord4 points to the particle size bytes
+  res OffScrn,(iy+ParticleFlag)
+  ld bc,(TempWord2)
+  cpi
+  ex de,hl
+  push af
+  ld hl,(TempWord3)
+  ld (TempWord2),bc
+  ldd
+  ldd
+  ld (TempWord3),hl
+  ld hl,(TempWord4)
+  inc bc
+  inc bc
+  ld (hl),c
+  inc hl
+  ld (hl),b
+  ex de,hl
+  pop af
+  pop bc
+  ret po
+  cpi
+  jp pe,ParticleDrawLoop
+  ret
+;===============================================================
+PBufInfoDef:
+  ld hl,(PBufPtr)
+PBufInfo:
+  ld c,(hl) \ inc hl
+  ld b,(hl) \ inc hl
+  ld e,(hl) \ inc hl
+  ld d,(hl) \ inc hl
+  ret
+NextParticle:
+  sra b \ rr c \ dec bc
+  ex de,hl
+  sbc hl,bc \ ret z
+  add hl,bc
+  inc hl
+  ex de,hl
+  ld (TempWord1),hl
+  dec hl \ ld (hl),d
+  dec hl \ ld (hl),e
+  ex de,hl
+  add hl,hl
+  add hl,de
+  or 1
+  ret
+PartConv:
+; jr $
+  push bc
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+  ld a,c
+  pop bc \ ld b,a
+  push bc
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+
+  cp $2b
+
+  ld a,c
+
+  push af
+  call ParseNextFullArg_Buffer
+  pop af
+
+  pop bc \ ld b,a
+  pop hl \ ld (TempWord3),hl
+  add hl,bc \ dec h \ dec l
+  ld (TempWord2),bc
+;HL contains the lower-left coordinates
+PartConvLoop:
+  push hl
+  push bc
+  ld (TempWord4),hl
+  ld b,h \ ld c,l
+  call GetPixelLoc
+  jr nc,FinishPartAdd
+  and (hl) \ jr z,FinishPartAdd
+  call PBufInfoDef
+  call NextParticle \ jr z,PConvComplete
+  ld bc,(TempWord4)
+  ld (hl),c \ inc hl \ ld (hl),b
+FinishPartAdd:
+  pop bc \ pop hl
+;TempWord2 is the size of the reqion
+;TempWord3 is is the upper right coordinate
+  dec h \ djnz PartConvLoop
+  ld hl,(TempWord3)
+  ld bc,(TempWord2) \ dec c
+  add hl,bc
+  jr nz,PartConvLoop-6
+  pop bc \ ret
+PConvComplete:
+  pop bc \ pop hl \ pop bc \ ret ;zuviel
+FillPart:
+  ret
+PToRX:
+  ld a,(hl) \ cp $AE
+  jr z,PartConv
+  cp 11 \ jr z,FillPart
+  call PBufInfoDef
+;BC=Max number of particles
+;DE=Current number of particles
+;HL=particle pointer
+  call NextParticle
+  ld de,(TempWord1)
+  push de
+  push hl
+;HL points to where particle data gets written
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  ld a,c
+  pop bc \ ld b,a
+  pop hl \ pop de
+AddParticle:
+  ld (hl),c \ inc hl
+  ld (hl),b
+  call GetPixelLoc
+  or (hl) \ ld (hl),a
+  ld b,d \ ld c,e
+  ret

+ 49 - 0
src/cmd/prime.z80

@@ -0,0 +1,49 @@
+FracToken:
+  ld h,b \ ld l,c
+  call PrimeTest
+  ld b,0
+  ld (ThetaPrimeVar),bc
+  ld b,h \ ld c,l
+  ret
+PrimeTest:
+  bit 0,l
+  jr nz,+_
+  ld bc,2
+  srl h \ rr l
+  ret
+_:
+  ld de,PrimeNumbers
+  ld bc,3501h
+PrimeTestLoop:
+  push bc
+  push hl
+  ld a,(de)
+  ld c,a
+  call HL_Div_C
+  pop hl
+  or a
+  jr nz,+_
+  pop de
+  ret
+_:
+  pop bc
+  inc de
+  djnz PrimeTestLoop
+  scf
+;6 bytes, 24cc
+  ld a,h
+  ld h,b
+  ld b,l
+  ld l,c
+  ld c,b
+  ld b,a
+;3 bytes, 40cc
+;  push bc
+;  ex (sp),hl
+;  pop bc
+  ret
+PrimeNumbers:
+ .db 3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97
+ .db 101,103,107,109,113,127,131,137,139,149,151,157,163
+ .db 167,173,179,181
+ .db 191,193,197,199,211,223,227,229,233,239,241,251

+ 79 - 0
src/cmd/searchstring.z80

@@ -0,0 +1,79 @@
+;SearchString is used by inString  and Lbl
+
+
+
+
+searchstring_routine:
+;Inputs:
+;     HL points to the string to search
+;     BC size of the string to search
+;     DE points to string to find
+;     IX is the size of the string to find
+;Outputs:
+;     c flag set if there was a match, nc if no match was found
+;     HL points to the match if there was one
+;     DE is preserved
+;Destroys:
+;     A,BC
+
+;First, we'll do BC-IX -> BC, and make sure it isn't negative
+
+  push hl
+
+  ld h,b
+  ld l,c
+  push ix
+  pop bc
+  dec bc
+;Save the size of the string to find
+  ld (TempWord1),bc
+  or a
+  sbc hl,bc
+  ld b,h
+  ld c,l
+  pop hl
+
+  ret z
+  ccf
+  ret nc  ;This means the input was smaller than the string to search for!
+
+
+  jr searchstring_begin
+searchstring_match:
+  dec hl
+  scf
+  ret
+
+_:
+;at this point, we have a match
+;now we need to compare the strings
+  push hl
+  push de
+  push bc
+  call +_
+  pop bc
+  pop de
+  pop hl
+  jr z,searchstring_match  ;we found our match!
+  ld a,b
+  or c
+  jr z,searchstring_nomatch+1
+searchstring_begin:
+  ld a,(de)
+  cpir
+  jr z,-_
+searchstring_nomatch:
+  xor a
+  ld h,a
+  ld l,a
+  ret
+
+_:
+  ld bc,(TempWord1)
+_:
+  inc de
+  ld a,(de)
+  cpi
+  ret nz
+  jp pe,-_
+  ret

+ 196 - 0
src/cmd/solve.z80

@@ -0,0 +1,196 @@
+solveset_p1:
+  add a,4
+  add a,a
+  cp solveset_LUT_end-solveset_LUT
+  jp nc,p1_err_syntax
+  ld hl,solveset_LUT
+  add a,l
+  ld l,a
+  jr nc,$+3
+  inc h
+  ld a,(hl)
+  inc hl
+  ld h,(hl)
+  ld l,a
+  jp (hl)
+
+solveset_LUT:
+  .dw CopyVar
+  .dw CopyDataUp
+  .dw CopyDataDown
+  .dw p1_err_fatal
+  .dw p1_err_fatal
+  .dw PortWrite
+  .dw PortRead
+  .dw CopyVars
+  .dw OverwriteVar
+  .dw solve_zlz_comp
+  .dw solve_zlz_decomp
+  .dw solve_zcomp
+  .dw solve_sortVAT
+  .dw solve_getname
+solveset_LUT_end:
+
+CopyVar:
+  call p1_GetVarInfo2
+  ret c
+  push af
+  push hl
+  push bc
+  ld hl,(parsePtr)
+  inc hl
+  ld (parsePtr),hl
+  call p1_GetVarInfo
+  jr c,+_
+  bcall(_DelVarArc)
+_:
+  ld hl,(parsePtr)
+  ld a,2Bh
+  cp (hl)
+  pop bc
+  call z,p1_ParseNextFullArg
+  push bc
+  ld bc,0
+  cp 2Bh
+  call z,p1_ParseNextFullArg
+  pop de
+  pop hl
+  add hl,bc
+  push hl
+  push de
+  ex de,hl
+  ld a,(OP1)
+  and $1F
+  bcall(_EnoughMem)
+  jp c,ErrMEM
+  ex de,hl
+  bcall(_CreateVar)
+  inc de
+  inc de
+  pop bc
+  pop hl
+  pop af
+  push de
+  push bc
+  call ReadArc
+  pop hl
+  ld (ThetaPrimeVar),hl
+  pop bc
+  ret
+
+
+CopyDataUp:
+  push bc
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  pop de
+  pop hl
+  ldir
+  pop bc
+  ret
+
+CopyDataDown:
+  push bc
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  pop de
+  pop hl
+  lddr
+  pop bc
+  ret
+
+
+PortWrite:
+  call p1_ParseNextFullArg
+  push bc
+  ld c,0
+  cp 2Bh
+  call z,p1_ParseNextFullArg
+  pop de
+  out (c),e
+  ret
+
+PortRead:
+  ld hl,(parsePtr)
+  ld a,(hl)
+  ld c,0
+  cp 2Bh
+  call z,p1_ParseNextFullArg
+  in c,(c)
+  ld b,0
+  ret
+
+CopyVars:
+;Copy variables to a new location
+  call p1_ParseNextFullArg
+  ld d,b
+  ld e,c
+  ld hl,smallEditRAM
+  jr mov108
+
+OverwriteVar:
+;Overwrite all pointer vars
+  call p1_ParseNextFullArg
+  ld h,b
+  ld l,c
+  ld de,smallEditRAM
+mov108:
+  ld bc,108    ;2*54, 4*(26+1)
+  ldir
+  ret
+
+solve_sortVAT = sortVAT
+
+solve_getname:
+  call p1_ParseNextFullArg
+  cp $2B
+  jr z,solve_getname_any_type
+  ld a,c    ;type
+  push af
+  call p1_ParseNextFullArg
+  pop af
+  ;A is the type, BC is the index
+
+
+  ret
+
+solve_getname_any_type:
+;BC is the index
+  ret
+
+solve_zlz_decomp:
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  pop de
+  pop hl
+  jp zlz_decomp
+
+solve_zlz_comp:
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  pop de
+  pop hl
+  jp zlz_comp
+
+
+solve_zcomp:
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  pop de
+  pop hl
+  jp zcomp

+ 267 - 0
src/commandtable.z80

@@ -0,0 +1,267 @@
+#ifdef ALIGN_COMMAND_TABLE
+#if $&255>0
+.echo 256-($&255)," bytes before the commandtable"
+.fill 256-($&255),255
+#endif
+#endif
+CommandJumpTable:
+ .dw ErrBadToken      ; $00
+ .dw module           ; $01 ;>DMS
+ .dw todectoken       ; $02
+ .dw FracToken_00     ; $03
+ .dw StoToken         ; $04
+ .dw ErrBadToken      ; $05
+ .dw SetData          ; $06
+ .dw ExecLine_        ; $07
+ .dw LeftBracket      ; $08
+ .dw _Ret             ; $09
+ .dw ErrBadToken      ; $0A
+ .dw DegreeToken      ; $0B
+ .dw ErrBadToken      ; $0C
+ .dw Squared          ; $0D
+ .dw ErrBadToken      ; $0E
+ .dw ErrBadToken      ; $0F
+ .dw LeftParantheses  ; $10
+ .dw _Ret             ; $11
+ .dw ErrBadToken      ; $12
+ .dw PxlTestToken     ; $13
+ .dw Augment          ; $14
+ .dw ErrBadToken      ; $15
+ .dw ErrBadToken      ; $16
+ .dw ErrBadToken      ; $17
+ .dw ErrBadToken      ; $18
+ .dw MaxToken         ; $19
+ .dw MinToken         ; $1A
+ .dw RToPr            ; $1B
+ .dw RToPTheta        ; $1C
+ .dw PToRX            ; $1D
+ .dw PToRy            ; $1E
+ .dw ErrBadToken      ; $1F
+ .dw ErrBadToken      ; $20
+ .dw meanToken        ; $21
+ .dw SolveSet         ; $22
+ .dw ErrBadToken      ; $23
+ .dw ErrBadToken      ; $24
+ .dw ErrBadToken      ; $25
+ .dw ErrBadToken      ; $26
+ .dw ErrBadToken      ; $27
+ .dw ErrBadToken      ; $28
+ .dw Incptr           ; $29
+ .dw QuoteToken       ; $2A
+ .dw _Ret             ; $2B
+ .dw OSVarToken       ; $2C
+ .dw factorialToken   ; $2D
+ .dw ErrBadToken      ; $2E
+ .dw ErrBadToken      ; $2F
+ .dw ConvRStr         ; $30
+ .dw ConvRStr         ; $31
+ .dw ConvRStr         ; $32
+ .dw ConvRStr         ; $33
+ .dw ConvRStr         ; $34
+ .dw ConvRStr         ; $35
+ .dw ConvRStr         ; $36
+ .dw ConvRStr         ; $37
+ .dw ConvRStr         ; $38
+ .dw ConvRStr         ; $39
+ .dw SkipLine         ; $3A
+ .dw Base2Num         ; $3B
+ .dw orLogic          ; $3C
+ .dw xorLogic         ; $3D
+ .dw _Ret             ; $3E
+ .dw NewLine          ; $3F
+ .dw andLogic         ; $40
+ .dw VarToken         ; $41
+ .dw VarToken         ; $42
+ .dw VarToken         ; $43
+ .dw VarToken         ; $44
+ .dw VarToken         ; $45
+ .dw VarToken         ; $46
+ .dw VarToken         ; $47
+ .dw VarToken         ; $48
+ .dw VarToken         ; $49
+ .dw VarToken         ; $4A
+ .dw VarToken         ; $4B
+ .dw VarToken         ; $4C
+ .dw VarToken         ; $4D
+ .dw VarToken         ; $4E
+ .dw VarToken         ; $4F
+ .dw VarToken         ; $50
+ .dw VarToken         ; $51
+ .dw VarToken         ; $52
+ .dw VarToken         ; $53
+ .dw VarToken         ; $54
+ .dw VarToken         ; $55
+ .dw VarToken         ; $56
+ .dw VarToken         ; $57
+ .dw VarToken         ; $58
+ .dw VarToken         ; $59
+ .dw VarToken         ; $5A
+ .dw VarToken         ; $5B
+ .dw VarName          ; $5C
+ .dw VarName          ; $5D
+ .dw VarName          ; $5E
+ .dw prgmToken        ; $5F
+ .dw VarName          ; $60
+ .dw VarName          ; $61
+ .dw VarName          ; $62
+ .dw ErrBadToken      ; $63
+ .dw ErrBadToken      ; $64
+ .dw ErrBadToken      ; $65
+ .dw ErrBadToken      ; $66
+ .dw ErrBadToken      ; $67
+ .dw ErrBadToken      ; $68
+ .dw FloatModeToggle  ; $69
+ .dw Equals           ; $6A
+ .dw Less             ; $6B
+ .dw Greater          ; $6C
+ .dw LessOrEqual      ; $6D
+ .dw MoreOrEqual      ; $6E
+ .dw NotEqual         ; $6F
+ .dw Add              ; $70
+ .dw SubtractToken    ; $71
+ .dw AnsToken         ; $72
+ .dw FixToken         ; $73
+ .dw ErrBadToken      ; $74
+ .dw FullToken        ; $75
+ .dw FuncToken        ; $76
+ .dw ParamToken_00    ; $77
+ .dw ErrBadToken      ; $78
+ .dw ErrBadToken      ; $79
+ .dw ErrBadToken      ; $7A
+ .dw ErrBadToken      ; $7B
+ .dw ErrBadToken      ; $7C
+ .dw ErrBadToken      ; $7D
+ .dw ErrBadToken      ; $7E
+ .dw ErrBadToken      ; $7F
+ .dw ErrBadToken      ; $80
+ .dw ErrBadToken      ; $81
+ .dw Multiply         ; $82
+ .dw SkiplineDiv      ; $83
+ .dw ErrBadToken      ; $84
+ .dw ClrDrawToken     ; $85
+ .dw ErrBadToken      ; $86
+ .dw ErrBadToken      ; $87
+ .dw ErrBadToken      ; $88
+ .dw ErrBadToken      ; $89
+ .dw ErrBadToken      ; $8A
+ .dw ErrBadToken      ; $8B
+ .dw ErrBadToken      ; $8C
+ .dw ErrBadToken      ; $8D
+ .dw ErrBadToken      ; $8E
+ .dw ErrBadToken      ; $8F
+ .dw ErrBadToken      ; $90
+ .dw ErrBadToken      ; $91
+ .dw ErrBadToken      ; $92
+ .dw TextToken        ; $93
+ .dw ErrBadToken      ; $94
+#ifdef include_ncr
+ .dw nCrToken         ; $95
+#else
+ .dw ErrBadToken      ; $95
+#endif
+ .dw ErrBadToken      ; $96
+ .dw ErrBadToken      ; $97
+ .dw StorePicToken    ; $98
+ .dw RecallPicToken   ; $99
+ .dw ErrBadToken      ; $9A
+ .dw ErrBadToken      ; $9B
+ .dw LineToken        ; $9C
+ .dw VerticalToken    ; $9D
+ .dw PtOn             ; $9E
+ .dw PtOff            ; $9F
+ .dw PtChange         ; $A0
+ .dw PxlTokens        ; $A1
+ .dw PxlTokens        ; $A2
+ .dw PxlTokens        ; $A3
+ .dw ShadeToken       ; $A4
+ .dw CircleToken      ; $A5
+ .dw HorizontalToken  ; $A6
+ .dw TangentToken     ; $A7
+ .dw ErrBadToken      ; $A8
+ .dw ErrBadToken      ; $A9
+ .dw VarName          ; $AA
+ .dw RandToken        ; $AB
+ .dw PiToken          ; $AC
+ .dw GetKeyToken      ; $AD
+ .dw Incptr           ; $AE
+ .dw VarToken         ; $AF
+ .dw Negative         ; $B0
+ .dw int              ; $B1
+ .dw absToken         ; $B2
+ .dw ErrBadToken      ; $B3
+ .dw ErrBadToken      ; $B4
+ .dw ErrBadToken      ; $B5
+ .dw ErrBadToken      ; $B6
+ .dw ErrBadToken      ; $B7
+ .dw notLogic         ; $B8
+ .dw iPart            ; $B9
+ .dw ErrBadToken      ; $BA
+ .dw BBTokens         ; $BB
+ .dw Sqrt             ; $BC
+ .dw ErrBadToken      ; $BD
+ .dw LnToken          ; $BE
+ .dw PowerOf2         ; $BF
+ .dw logToken         ; $C0
+ .dw pow10Token       ; $C1
+ .dw Sin              ; $C2
+ .dw asinToken        ; $C3
+ .dw Cos              ; $C4
+ .dw acosToken        ; $C5
+ .dw tanToken         ; $C6
+ .dw atanToken        ; $C7
+ .dw sinhToken        ; $C8
+ .dw asinhToken       ; $C9
+ .dw coshToken        ; $CA
+ .dw acoshToken       ; $CB
+ .dw tanhToken        ; $CC
+ .dw atanhToken       ; $CD
+ .dw IfToken          ; $CE
+ .dw ParserNext       ; $CF
+ .dw ElseToken        ; $D0
+ .dw WhileToken       ; $D1
+ .dw RepeatToken      ; $D2
+ .dw ForToken         ; $D3
+ .dw EndToken         ; $D4
+ .dw Return           ; $D5
+ .dw LblToken         ; $D6
+ .dw GotoToken        ; $D7
+ .dw PauseToken       ; $D8
+ .dw StopToken        ; $D9
+ .dw ISToken          ; $DA
+ .dw DSToken          ; $DB
+ .dw InputToken       ; $DC
+ .dw ErrBadToken      ; $DD
+ .dw DispToken        ; $DE
+ .dw DispGraph        ; $DF
+ .dw OutputToken      ; $E0
+ .dw ClrHomeToken     ; $E1
+ .dw FillToken        ; $E2
+ .dw ErrBadToken      ; $E3
+ .dw ErrBadToken      ; $E4
+ .dw ErrBadToken      ; $E5
+ .dw Menu             ; $E6
+ .dw SendToken        ; $E7
+ .dw GetToken         ; $E8
+ .dw ErrBadToken      ; $E9
+ .dw ErrBadToken      ; $EA
+ .dw ExecLine         ; $EB
+ .dw Byte             ; $EC
+ .dw Word             ; $ED
+ .dw NegRelPtr        ; $EE
+ .dw ErrBadToken      ; $EF
+ .dw PowToken         ; $F0
+ .dw ErrBadToken      ; $F1
+ .dw ErrBadToken      ; $F2
+ .dw ErrBadToken      ; $F3
+ .dw ErrBadToken      ; $F4
+ .dw ErrBadToken      ; $F5
+ .dw ErrBadToken      ; $F6
+ .dw ErrBadToken      ; $F7
+ .dw ErrBadToken      ; $F8
+ .dw ErrBadToken      ; $F9
+ .dw ErrBadToken      ; $FA
+ .dw ErrBadToken      ; $FB
+ .dw ErrBadToken      ; $FC
+ .dw ErrBadToken      ; $FD
+ .dw ErrBadToken      ; $FE
+ .dw ErrBadToken      ; $FF

+ 179 - 0
src/compile.z80

@@ -0,0 +1,179 @@
+;If the numbers are 1 digit, the output will be larger :(
+;If the numbers are 2 digits, the output will be the same size :|
+;If the number is 3 digits, less than 256, the output will be smaller! (3 digits, but >=256 is same size :|)
+;All other numbers will be more compact!
+;
+;When a comment/label is parsed, we need to instead copy it to an LUT at the back, along with the address where it would be inserted.
+;If the "Lbl " command is come across, first search for if the label has already found.
+;  If yes, just replace it with a pointer value
+;  If no, then store a pointer of 0x0000, and in another LUT, if the name does not exist yet, add it along with the address, else append the address to it.
+;Move Strings to the data section
+;
+;Parse through the source, looking for '.' or 'Lbl ' (0x3A and 0xD6, respectively)
+
+compile:
+;A is passed in as the byte to parse
+;DE is where to output
+;HL is where the input is
+;Be careful not to overlap or exceed data_top
+  inc hl  ;We are going to do nothing :P
+  inc de
+  ret
+
+
+  cp 2Ah
+  jp z,compile_string
+  sub 3Ah
+  add a,10
+  jp c,compile_number
+  inc hl
+  inc de
+  ret
+compile_string:
+;move the string to the data section and replace with a relative pointer
+;We are removing the starting quote, but adding 3 bytes for the pointer. Net gain of two bytes.
+
+;We need to verify that we have two bytes available
+  ld bc,2
+  call enoughmem
+  jp c,err_LowMem
+
+;The easy way to do this is to copy the string to the data section, and leave a gap between the in_head and out_head
+;However, if we only have three bytes or RAM available, and the string is 4 bytes, we'll be overwriting stuff!
+;Instead, we'll copy the string to saveSScreen in up to 768 byte chunks, shift the source down copy the string to the end of the source (essentially rotating), then move the string data to the end
+;It's slower, but better on RAM usage :)
+
+;Save the pointers of the output and input
+  inc hl
+  push de
+  ld (TempWord1),hl
+  call GetGrammerStr
+  inc bc
+  ld hl,(TempWord1)
+  ld (TempWord2),bc
+compile_str_loop:
+  ld a,b
+  sub 3
+  jr c,compile_str_finalchunk
+  ld b,a
+  push bc
+  ld bc,768
+  ld de,saveSScreen
+  ldir
+  ;So now we move (end_of_src)-HL bytes at DE to (TempWord1)
+  push de
+  ex de,hl
+  ld hl,(end_of_src)
+  or a
+  sbc hl,de
+  ld b,h
+  ld c,l
+  pop hl
+  ld de,(TempWord1)
+  jr z,+_
+  ldir
+_:
+  pop bc
+  jr compile_str_loop
+compile_str_finalchunk:
+  ld a,b
+  or c
+  ld de,saveSScreen
+  jr z,compile_str_adjust
+  ldir
+  ;So now we move (end_of_src)-HL bytes at DE to (TempWord1)
+  push de
+  ex de,hl
+  ld hl,(end_of_src)
+  or a
+  sbc hl,de
+  ld b,h
+  ld c,l
+  pop hl
+  ld de,(TempWord1)
+  jr z,compile_str_adjust
+  ldir
+compile_str_adjust:
+  ld hl,(data_top)
+  ld bc,(TempWord2)
+  or a
+  sbc hl,bc
+  ld (data_top),hl
+  ex de,hl
+
+  ld hl,(end_of_src)
+  ld bc,(TempWord2)
+  or a
+  sbc hl,bc
+  ld (end_of_src),hl
+
+
+  ld a,b
+  or c
+  jr z,+_
+  ldir
+_:
+
+;Now we need to insert two bytes at (TempWord1)
+  ld de,(TempWord1)
+  ld hl,(end_of_src)
+  sbc hl,de
+  jr z,+_
+  ld b,h
+  ld c,l
+  add hl,de
+  ld d,h
+  ld e,l
+  inc de
+  dec hl
+  ldir
+_:
+
+  ld hl,(end_of_src)
+  inc hl
+  inc hl
+  ld (end_of_src),hl
+
+  ld hl,(end_of_buffer)
+  ld de,(data_top)
+  sbc hl,de
+  ex de,hl
+;DE is the relative pointer
+
+  ld hl,(TempWord2)
+  dec hl
+  ld (hl),tok_NegRelPtr
+  inc hl
+  ld (hl),e
+  inc hl
+  ld (hl),d
+  inc hl
+  ld d,h
+  ld e,l
+  ret
+compile_number:
+;If it is an int, we need to replace with a uint8, uint16
+;If it is a float, we need to move it to the data section and replace with a relative pointer
+  inc hl
+  inc de
+  ret
+enoughmem:
+;Returns nc if there are at least BC bytes available. Preserves registers.
+;Need data_top-end_of_src>=BC
+;We'll check data_top>=BC+end_of_src
+
+;preserve HL
+  push hl
+
+  ld hl,(end_of_src)
+  add hl,bc
+  jr c,+_       ;checking for wayyy too much RAM
+;preserve DE
+  push de
+  ex de,hl
+  ld hl,(data_top)
+  sbc hl,bc
+  pop de
+_:
+  pop hl
+  ret

+ 115 - 0
src/err.z80

@@ -0,0 +1,115 @@
+#ifdef SHELL_BROKEN
+GramErr:
+  ld de,StrGram
+  jp CustomError
+#endif
+MOSIONErr:
+  inc hl \ ld a,(hl) \ cp $30 \ jr nz,MirageErr
+  ld de,StrION
+  jp CustomError
+MirageErr:
+  dec a \ jp nz,HomeRunASM
+  ld de,StrMirage
+  jp CustomError
+DCSErr:
+  rlca
+  cp (hl) \ jp nz,HomeRunASM
+  inc hl \ ld a,(hl) \ cp $C9 \ jp nz,HomeRunASM
+  ld de,StrDCS
+  jp CustomError
+
+
+ErrStackOverflow_pop:
+  ld hl,s_StackOverflow_pop
+  ld a,6
+  jr custerrd
+ErrStackOverflow_push:
+  ld hl,s_StackOverflow_push
+  ld a,5
+  jr custerrd
+ErrPkgNotFound:
+  ld hl,s_PkgNotFound
+  ld a,4
+custerrd:
+  ld de,appErr1
+  call mov13
+  jr err
+ErrBadToken:
+  ld a,3
+  jr Err
+onbreak:
+  in a,(4)
+  and 8
+  ret nz
+ONErr:
+  xor a
+  .db $C2 ;start of jp nz,**
+ErrMEM:
+err_fatal:
+  ld a,1
+Err:
+  ld (cxErrorEP),a
+  jp ErrorJump
+GramHandl:
+  ld hl,(ErrorLoc)
+  ld (parsePtr),hl
+  cp errmap_end-errmap \ jr nc,BreakProgram
+  ld hl,errmap
+  add a,l
+  ld l,a
+#if (errmap&255)>251
+  jr nc,+_
+  inc h
+_:
+#endif
+  ld a,(hl)
+  .db $FE  ;start of cp *s
+StopToken:
+BreakProgram:
+  xor a
+  push af
+;Reset the keypress
+_:
+  call GetKeyDebounce
+  or a
+  jr nz,-_
+;Reset the link port
+  out (0),a
+;Reset the OS keypress
+  ld (843Fh),a
+  ld (8444h),a
+;Reset textShadow and cmdShadow
+	bcall(_clrTxtShd)
+  bcall(_saveCmdShadow)
+
+  pop af
+  ld hl,(parsePtr)
+  dec hl
+  ld (parsePtr),hl
+  ld sp,(SPSave)
+  di
+  im 1
+  or a
+  jr z,+_
+  ld b,a
+  ld a,(basic_prog)
+  cp 5
+  ld a,b
+  jr nz,$+4
+  or 128
+  bcall(_JError)
+_:
+  or 1
+  ret
+errmap:
+  .db 6,14,43,36,43,43,43
+errmap_end:
+
+
+
+;The following are errors thrown outside of parsing.
+;Ex., during compiling, or loading a source file from archive
+
+err_LowMem:
+;Need to actually show to the user
+  ret

+ 405 - 0
src/experimental/experimental.z80

@@ -0,0 +1,405 @@
+;All routines must be 768 bytes or less
+;They get copied to moduleExec
+#include "grammer2.5.inc"
+mymodule:
+  .db "Gram"            ;magic number
+  .dw MODULE_VERSION    ;minimum version
+  .dw (mod_start-2-$)/2 ;num elements
+  .dw func11-mod_start  ; ADDSTR
+  .dw func12-mod_start  ; ARRAY
+  .dw func1-mod_start   ; DEL
+  .dw func9-mod_start   ; FLOAT
+  .dw func4-mod_start   ; GET
+  .dw func0-mod_start   ; INITFS
+  .dw func2-mod_start   ; LIST
+  .dw func3-mod_start   ; MAT
+  .dw func6-mod_start   ; NAME
+  .dw func5-mod_start   ; SET
+  .dw func10-mod_start  ; STR
+  .dw func8-mod_start   ; UINT16
+  .dw func7-mod_start   ; UINT8
+
+
+; File storage format needs
+;     - Find
+;     - Create
+;     - Delete
+;     - Resize
+
+
+mod_start:
+
+func0: .db "INITFS",$29 \ .dw func1-$-2
+; This routine initializes the FS
+;
+;   INITFS ptr,size
+;
+  call ParseFullArg
+  ld (FS_begin),bc
+  push bc
+  call ParseNextFullArg
+  pop hl
+  add hl,bc
+  ld (FS_end),hl
+  ret
+
+func1: .db "DEL",$29 \ .dw func12-$-2
+; This routine deletes a var in the FS
+;
+;   DEL "name"
+;
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  call GetGrammerText
+  ld h,d
+  ld l,e
+  add hl,bc
+  ld (hl),0
+  ex de,hl
+  call FS_findvar
+  jp FS_delvar
+
+func12: .db "ARRAY",$29 \ .dw func2-$-2
+; This routine creates an array in the FS
+;
+;   ARRAY "name",TYPE,[elem0,elem1,elem2,...]
+;
+func12_start:
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  call GetGrammerText
+  ld h,d
+  ld l,e
+  add hl,bc
+  ld (hl),0
+  ex de,hl
+  call FS_createvar_max
+  ;HL points to the data
+  ;BC is the size of the entry
+  push hl
+  push hl
+  push bc
+
+; Get the variable type
+  call ParseNextFullArg
+  ld e,c
+
+;Now write the bytes: FS_array, type
+;Make sure there is enough room!
+  pop bc
+  pop hl
+  ld a,b
+  or c
+  jp z,ErrMem
+  ld (hl),FS_array
+  cpi
+  jp po,ErrMem
+  ld (hl),e
+  cpi
+
+  push hl
+  ld hl,(parsePtr)
+  ld a,(hl)
+  pop hl
+  jr array_loop_end
+_:
+  push hl
+  push bc
+  push de
+  call ParseNextFullArg
+  pop hl  ;L is type
+  ld h,a  ;Next byte to be parsed
+  ld a,l  ;A is type
+  ld d,b
+  ld e,c
+  pop bc  ;size remaining
+  ex (sp),hl  ;points to where to write
+  call moduleExec+array_write-func12_start
+  pop de
+  ld a,d
+array_loop_end:
+  cp $2B
+  jr z,-_
+  ;Now calculate the size of the array
+  pop de    ;points to the start
+  or a
+  sbc hl,de
+  ld b,h
+  ld c,l
+  ex de,hl
+  call FS_resize
+  ld b,h
+  ld c,l
+  ret
+
+array_write:
+;A is the type
+;HL is where to write
+;DE is the value to write
+;BC is number of bytes available
+  or a
+  jr z,array_write_uint8
+  dec a
+  jr z,array_write_uint16
+  dec a
+  jp nz,ErrMem
+array_write_float:
+  ;make sure BC>=4
+  ld a,c
+  sub 4
+  ld a,b
+  sbc a,0
+  jp c,ErrMem
+  ex de,hl
+  ldi
+  ldi
+  ldi
+  ldi
+  ex de,hl
+  ret
+array_write_uint8:
+  ;make sure BC>=1
+  ld a,b
+  or c
+  jp z,ErrMem
+  ld (hl),e
+  cpi
+  ret
+array_write_uint16:
+  ;make sure BC>=2
+  ld a,c
+  sub 2
+  ld a,b
+  sbc a,0
+  jp c,ErrMem
+  ld (hl),e
+  cpi
+  ld (hl),d
+  cpi
+  ret
+
+func2: .db "LIST",$29 \ .dw func3-$-2
+; This routine creates a list in the FS
+;
+;   LIST "name",elem0,elem1,elem2,...
+;
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  call GetGrammerText
+  ld h,d
+  ld l,e
+  add hl,bc
+  ld (hl),0
+  ex de,hl
+  call FS_createvar_max
+  ;HL points to the data
+  ;DE points to the entry
+  ld bc,0
+  jp FS_resize
+
+func3: .db "MAT",$29 \ .dw func10-$-2
+; This routine creates a list in the FS
+;
+;   MAT "name",[elem0,elem1,elem2,...],[...
+;
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  call GetGrammerText
+  ld h,d
+  ld l,e
+  add hl,bc
+  ld (hl),0
+  ex de,hl
+  call FS_createvar_max
+  ;HL points to the data
+  ;BC is the size of the entry
+  ld bc,0
+  jp FS_resize
+
+func10: .db "STR",$29 \ .dw func11-$-2
+; This routine creates a list in the FS
+;
+;   STR "name",ptr
+;
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  call GetGrammerText
+  ld h,d
+  ld l,e
+  add hl,bc
+  ld (hl),0
+  ex de,hl
+  call FS_createvar_max
+  ;HL points to the data
+  ;BC is the size available
+  push hl
+  push bc
+  call ParseNextFullArg
+  push bc
+  ld h,b
+  ld l,c
+  call GetGrammerStr
+  pop de    ;string to copy
+  pop hl    ;available space
+  scf
+  inc bc
+  sbc hl,bc
+  dec bc
+  jp c,ErrMem
+  pop hl    ;Where to copy the string to
+  ld (hl),FS_STR
+  push hl
+  inc hl
+  ex de,hl
+  ld a,b
+  or c
+  jr z,+_
+  push bc
+  ldir
+  pop bc
+_:
+  xor a
+  ld (de),a
+  inc bc
+  inc bc
+  pop hl
+  call FS_resize
+  ld b,h
+  ld c,l
+  ld l,(hl)
+  ld h,0
+  ld (ThetaPrimeVar),hl
+  ret
+
+func11: .db "ADDSTR",$29 \ .dw func4-$-2
+; This routine creates a list in the FS
+;
+;   ADDSTR ptr,ptr
+;
+  call ParseFullArg
+  push bc
+  push bc
+  call ParseNextFullArg
+  ;BC points to the second string
+  ld a,(bc)
+  cp FS_STR
+  jp nz,ErrMem      ;actually a syntax issue
+  ld h,b
+  ld l,c
+  dec hl
+  ld b,(hl)
+  dec hl
+  ld c,(hl)
+  inc hl
+  inc hl
+  ex (sp),hl
+  ;HL points to the first var
+  ;BC is the size of the second string
+  ld a,(hl)
+  cp FS_STR
+  jp nz,ErrMem      ;actually a syntax issue
+
+  dec hl
+  ld d,(hl)
+  dec hl
+  ld e,(hl)
+  inc hl
+  inc hl
+  push bc     ;size of str
+  push de
+  ex de,hl
+  add hl,bc
+  ld b,h
+  ld c,l
+  dec bc  ;Don't want to duplicate the type byte and ending null-byte
+  dec bc
+  ex de,hl
+  ;BC is the new size
+  call FS_resize
+  pop de
+  pop bc
+  add hl,de
+  pop de
+  ex de,hl
+  dec de    ;overwrite the ending null byte
+  inc hl    ;don't write the type byte
+  dec bc    ;not writing first byte
+  dec bc    ;skip writing last byte
+  ld a,b
+  or c
+  jr z,+_
+  ldir
+_:
+  ;Finish by writing a 0 to the end
+  ;Q: "But Zeda, why not just use the end byte of the second string?"
+  ;A: Trying concatenating a string to itself :P
+  xor a
+  ld (de),a
+  pop bc
+  ret
+
+
+func4: .db "GET",$29 \ .dw func5-$-2
+; This routine reads an element from a var
+;
+;   GET ptr,index[,index2[,index3[,...
+;
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  ;HL points to the data
+  ret
+
+func5: .db "SET",$29 \ .dw func6-$-2
+; This routine sets the value of an element in a var
+;
+;   SET ptr,value,index[,index2[,index3[,...
+;
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  ;HL points to the data
+  ret
+
+func6: .db "NAME",$29 \ .dw func7-$-2
+; This routine gets a pointer to a var by its name
+;
+;   NAME "name"
+;
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  call GetGrammerText
+  ld h,d
+  ld l,e
+  add hl,bc
+  ld (hl),0
+  ex de,hl
+  call FS_findvar
+  ld b,h
+  ld c,l
+  ld l,(hl)
+  ld h,0
+  ld (ThetaPrimeVar),hl
+  inc bc
+  ret
+
+func7: .db "UINT8",0 \ .dw func8-$-2
+  ld bc,0
+  ret
+
+func8: .db "UINT16",0 \ .dw func9-$-2
+  ld bc,1
+  ret
+
+func9: .db "FLOAT",0 \ .dw mod_end-$-2
+  ld bc,2
+  ret
+
+mod_end:
+.echo $-mymodule," bytes"

+ 1027 - 0
src/fonts/ffont.asm

@@ -0,0 +1,1027 @@
+; FONT METADATA; Code Page = ASCII
+; 
+; FONT DATA
+; Char 00 �  
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 01 �  
+	.db	$0C
+	.db	$AA
+	.db	$A0
+; Char 02 �  
+	.db	$0A
+	.db	$AA
+	.db	$60
+; Char 03 �  
+	.db	$0A
+	.db	$AA
+	.db	$40
+; Char 04 �  
+	.db	$0A
+	.db	$AE
+	.db	$A0
+; Char 05 �  
+	.db	$8C
+	.db	$EC
+	.db	$80
+; Char 06 �  
+	.db	$4E
+	.db	$44
+	.db	$40
+; Char 07 �  
+	.db	$44
+	.db	$4E
+	.db	$40
+; Char 08 �  
+	.db	$25
+	.db	$42
+	.db	$A4
+; Char 09 �  
+	.db	$0A
+	.db	$4A
+	.db	$00
+; Char 0A �  
+	.db	$0E
+	.db	$AE
+	.db	$00
+; Char 0B �  
+	.db	$04
+	.db	$E4
+	.db	$00
+; Char 0C �  
+	.db	$00
+	.db	$80
+	.db	$00
+; Char 0D �  
+	.db	$00
+	.db	$E4
+	.db	$40
+; Char 0E �  
+	.db	$E4
+	.db	$2C
+	.db	$00
+; Char 0F �  
+	.db	$0F
+	.db	$CE
+	.db	$C0
+; Char 10 �  
+	.db	$74
+	.db	$4C
+	.db	$40
+; Char 11 �  
+	.db	$31
+	.db	$D1
+	.db	$00
+; Char 12 �  
+	.db	$C2
+	.db	$4E
+	.db	$00
+; Char 13 �  
+	.db	$02
+	.db	$48
+	.db	$E0
+; Char 14 �  
+	.db	$69
+	.db	$96
+	.db	$00
+; Char 15 �  
+	.db	$AC
+	.db	$88
+	.db	$00
+; Char 16 �  
+	.db	$E4
+	.db	$40
+	.db	$00
+; Char 17 �  
+	.db	$68
+	.db	$60
+	.db	$E0
+; Char 18 �  
+	.db	$2E
+	.db	$4E
+	.db	$80
+; Char 19 �  
+	.db	$C2
+	.db	$C0
+	.db	$E0
+; Char 1A �  
+	.db	$00
+	.db	$60
+	.db	$00
+; Char 1B �  
+	.db	$E8
+	.db	$C8
+	.db	$E0
+; Char 1C �  
+	.db	$42
+	.db	$F2
+	.db	$40
+; Char 1D �  
+	.db	$AD
+	.db	$DD
+	.db	$A0
+; Char 1E �  
+	.db	$4E
+	.db	$44
+	.db	$40
+; Char 1F �  
+	.db	$44
+	.db	$4E
+	.db	$40
+; Char 20     
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 21 ! ! 
+	.db	$88
+	.db	$80
+	.db	$80
+; Char 22 " " 
+	.db	$AA
+	.db	$A0
+	.db	$00
+; Char 23 # # 
+	.db	$5F
+	.db	$5F
+	.db	$50
+; Char 24 $ $ 
+	.db	$8A
+	.db	$E2
+	.db	$00
+; Char 25 % % 
+	.db	$A2
+	.db	$48
+	.db	$A0
+; Char 26 & & 
+	.db	$69
+	.db	$4B
+	.db	$60
+; Char 27 ' ' 
+	.db	$88
+	.db	$00
+	.db	$00
+; Char 28 ( ( 
+	.db	$48
+	.db	$88
+	.db	$40
+; Char 29 ) ) 
+	.db	$84
+	.db	$44
+	.db	$80
+; Char 2A * * 
+	.db	$00
+	.db	$40
+	.db	$00
+; Char 2B + + 
+	.db	$04
+	.db	$E4
+	.db	$00
+; Char 2C , , 
+	.db	$00
+	.db	$04
+	.db	$48
+; Char 2D - - 
+	.db	$00
+	.db	$E0
+	.db	$00
+; Char 2E . . 
+	.db	$00
+	.db	$00
+	.db	$40
+; Char 2F / / 
+	.db	$22
+	.db	$48
+	.db	$80
+; Char 30 0 0 
+	.db	$4A
+	.db	$AA
+	.db	$40
+; Char 31 1 1 
+	.db	$4C
+	.db	$44
+	.db	$E0
+; Char 32 2 2 
+	.db	$C2
+	.db	$48
+	.db	$E0
+; Char 33 3 3 
+	.db	$C2
+	.db	$42
+	.db	$C0
+; Char 34 4 4 
+	.db	$AA
+	.db	$E2
+	.db	$20
+; Char 35 5 5 
+	.db	$E8
+	.db	$C2
+	.db	$C0
+; Char 36 6 6 
+	.db	$68
+	.db	$EA
+	.db	$E0
+; Char 37 7 7 
+	.db	$E2
+	.db	$44
+	.db	$40
+; Char 38 8 8 
+	.db	$EA
+	.db	$EA
+	.db	$E0
+; Char 39 9 9 
+	.db	$EA
+	.db	$E2
+	.db	$C0
+; Char 3A : : 
+	.db	$04
+	.db	$04
+	.db	$00
+; Char 3B ; ; 
+	.db	$04
+	.db	$04
+	.db	$48
+; Char 3C < < 
+	.db	$24
+	.db	$84
+	.db	$20
+; Char 3D = = 
+	.db	$0E
+	.db	$0E
+	.db	$00
+; Char 3E > > 
+	.db	$84
+	.db	$24
+	.db	$80
+; Char 3F ? ? 
+	.db	$C2
+	.db	$40
+	.db	$40
+; Char 40 @ @ 
+	.db	$69
+	.db	$BA
+	.db	$87
+; Char 41 A A 
+	.db	$4A
+	.db	$EA
+	.db	$A0
+; Char 42 B B 
+	.db	$CA
+	.db	$CA
+	.db	$C0
+; Char 43 C C 
+	.db	$68
+	.db	$88
+	.db	$60
+; Char 44 D D 
+	.db	$CA
+	.db	$AA
+	.db	$C0
+; Char 45 E E 
+	.db	$E8
+	.db	$C8
+	.db	$E0
+; Char 46 F F 
+	.db	$E8
+	.db	$C8
+	.db	$80
+; Char 47 G G 
+	.db	$68
+	.db	$AA
+	.db	$60
+; Char 48 H H 
+	.db	$AA
+	.db	$EA
+	.db	$A0
+; Char 49 I I 
+	.db	$E4
+	.db	$44
+	.db	$E0
+; Char 4A J J 
+	.db	$62
+	.db	$2A
+	.db	$40
+; Char 4B K K 
+	.db	$AA
+	.db	$CA
+	.db	$A0
+; Char 4C L L 
+	.db	$88
+	.db	$88
+	.db	$E0
+; Char 4D M M 
+	.db	$AE
+	.db	$AA
+	.db	$A0
+; Char 4E N N 
+	.db	$CA
+	.db	$AA
+	.db	$A0
+; Char 4F O O 
+	.db	$EA
+	.db	$AA
+	.db	$E0
+; Char 50 P P 
+	.db	$CA
+	.db	$C8
+	.db	$80
+; Char 51 Q Q 
+	.db	$EA
+	.db	$AE
+	.db	$60
+; Char 52 R R 
+	.db	$CA
+	.db	$CA
+	.db	$A0
+; Char 53 S S 
+	.db	$68
+	.db	$42
+	.db	$C0
+; Char 54 T T 
+	.db	$E4
+	.db	$44
+	.db	$40
+; Char 55 U U 
+	.db	$AA
+	.db	$AA
+	.db	$E0
+; Char 56 V V 
+	.db	$AA
+	.db	$AA
+	.db	$40
+; Char 57 W W 
+	.db	$AA
+	.db	$AE
+	.db	$A0
+; Char 58 X X 
+	.db	$AA
+	.db	$4A
+	.db	$A0
+; Char 59 Y Y 
+	.db	$AA
+	.db	$44
+	.db	$40
+; Char 5A Z Z 
+	.db	$E2
+	.db	$48
+	.db	$E0
+; Char 5B [ [ 
+	.db	$4A
+	.db	$EA
+	.db	$40
+; Char 5C \ \ 
+	.db	$88
+	.db	$42
+	.db	$20
+; Char 5D ] ] 
+	.db	$C4
+	.db	$44
+	.db	$C0
+; Char 5E ^ ^ 
+	.db	$4A
+	.db	$00
+	.db	$00
+; Char 5F _ _ 
+	.db	$00
+	.db	$00
+	.db	$E0
+; Char 60 ` ` 
+	.db	$84
+	.db	$00
+	.db	$00
+; Char 61 a a 
+	.db	$06
+	.db	$AA
+	.db	$60
+; Char 62 b b 
+	.db	$88
+	.db	$CA
+	.db	$C0
+; Char 63 c c 
+	.db	$06
+	.db	$88
+	.db	$60
+; Char 64 d d 
+	.db	$22
+	.db	$6A
+	.db	$60
+; Char 65 e e 
+	.db	$04
+	.db	$AC
+	.db	$60
+; Char 66 f f 
+	.db	$24
+	.db	$E4
+	.db	$40
+; Char 67 g g 
+	.db	$06
+	.db	$A6
+	.db	$2C
+; Char 68 h h 
+	.db	$88
+	.db	$CA
+	.db	$A0
+; Char 69 i i 
+	.db	$40
+	.db	$44
+	.db	$40
+; Char 6A j j 
+	.db	$20
+	.db	$22
+	.db	$A4
+; Char 6B k k 
+	.db	$8A
+	.db	$CA
+	.db	$A0
+; Char 6C l l 
+	.db	$88
+	.db	$88
+	.db	$40
+; Char 6D m m 
+	.db	$0A
+	.db	$EA
+	.db	$A0
+; Char 6E n n 
+	.db	$0C
+	.db	$AA
+	.db	$A0
+; Char 6F o o 
+	.db	$04
+	.db	$AA
+	.db	$40
+; Char 70 p p 
+	.db	$0C
+	.db	$AC
+	.db	$80
+; Char 71 q q 
+	.db	$06
+	.db	$A6
+	.db	$22
+; Char 72 r r 
+	.db	$0A
+	.db	$C8
+	.db	$80
+; Char 73 s s 
+	.db	$06
+	.db	$42
+	.db	$60
+; Char 74 t t 
+	.db	$4E
+	.db	$44
+	.db	$20
+; Char 75 u u 
+	.db	$0A
+	.db	$AA
+	.db	$E0
+; Char 76 v v 
+	.db	$0A
+	.db	$AA
+	.db	$40
+; Char 77 w w 
+	.db	$0A
+	.db	$AE
+	.db	$A0
+; Char 78 x x 
+	.db	$0A
+	.db	$44
+	.db	$A0
+; Char 79 y y 
+	.db	$0A
+	.db	$A6
+	.db	$24
+; Char 7A z z 
+	.db	$0E
+	.db	$24
+	.db	$E0
+; Char 7B { { 
+	.db	$64
+	.db	$84
+	.db	$60
+; Char 7C | | 
+	.db	$44
+	.db	$44
+	.db	$40
+; Char 7D } } 
+	.db	$C4
+	.db	$24
+	.db	$C0
+; Char 7E ~ ~ 
+	.db	$05
+	.db	$A0
+	.db	$00
+; Char 7F   
+	.db	$F0
+	.db	$F0
+	.db	$F0
+; Char 80 �  
+	.db	$04
+	.db	$AA
+	.db	$A4
+; Char 81 �  
+	.db	$04
+	.db	$C4
+	.db	$4E
+; Char 82 �  
+	.db	$0C
+	.db	$24
+	.db	$8E
+; Char 83 �  
+	.db	$0C
+	.db	$24
+	.db	$2C
+; Char 84 �  
+	.db	$0A
+	.db	$AE
+	.db	$22
+; Char 85 �  
+	.db	$0E
+	.db	$8C
+	.db	$2C
+; Char 86 �  
+	.db	$08
+	.db	$8E
+	.db	$AE
+; Char 87 �  
+	.db	$0E
+	.db	$24
+	.db	$44
+; Char 88 �  
+	.db	$0E
+	.db	$AE
+	.db	$AE
+; Char 89 �  
+	.db	$0E
+	.db	$AE
+	.db	$2C
+; Char 8A �  
+	.db	$24
+	.db	$4A
+	.db	$EA
+; Char 8B �  
+	.db	$84
+	.db	$4A
+	.db	$EA
+; Char 8C �  
+	.db	$4A
+	.db	$4A
+	.db	$EA
+; Char 8D �  
+	.db	$A0
+	.db	$4A
+	.db	$EA
+; Char 8E �  
+	.db	$24
+	.db	$06
+	.db	$A5
+; Char 8F �  
+	.db	$42
+	.db	$06
+	.db	$A5
+; Char 90 �  
+	.db	$4A
+	.db	$06
+	.db	$A5
+; Char 91 �  
+	.db	$A0
+	.db	$6A
+	.db	$60
+; Char 92 �  
+	.db	$24
+	.db	$E8
+	.db	$CE
+; Char 93 �  
+	.db	$84
+	.db	$E8
+	.db	$CE
+; Char 94 �  
+	.db	$4A
+	.db	$E8
+	.db	$CE
+; Char 95 �  
+	.db	$A0
+	.db	$E8
+	.db	$CE
+; Char 96 �  
+	.db	$48
+	.db	$4A
+	.db	$C6
+; Char 97 �  
+	.db	$42
+	.db	$4A
+	.db	$C6
+; Char 98 �  
+	.db	$4A
+	.db	$4A
+	.db	$C6
+; Char 99 �  
+	.db	$A0
+	.db	$4A
+	.db	$C6
+; Char 9A �  
+	.db	$24
+	.db	$E4
+	.db	$4E
+; Char 9B �  
+	.db	$84
+	.db	$E4
+	.db	$4E
+; Char 9C �  
+	.db	$4A
+	.db	$E4
+	.db	$4E
+; Char 9D �  
+	.db	$A0
+	.db	$E4
+	.db	$4E
+; Char 9E �  
+	.db	$24
+	.db	$04
+	.db	$44
+; Char 9F �  
+	.db	$84
+	.db	$04
+	.db	$44
+; Char A0 �  
+	.db	$4A
+	.db	$04
+	.db	$44
+; Char A1 �  
+	.db	$A0
+	.db	$04
+	.db	$44
+; Char A2 �  
+	.db	$24
+	.db	$69
+	.db	$96
+; Char A3 �  
+	.db	$42
+	.db	$69
+	.db	$96
+; Char A4 �  
+	.db	$4A
+	.db	$69
+	.db	$96
+; Char A5 �  
+	.db	$A0
+	.db	$69
+	.db	$96
+; Char A6 �  
+	.db	$24
+	.db	$04
+	.db	$A4
+; Char A7 �  
+	.db	$84
+	.db	$04
+	.db	$A4
+; Char A8 �  
+	.db	$4A
+	.db	$04
+	.db	$A4
+; Char A9 �  
+	.db	$A0
+	.db	$04
+	.db	$A4
+; Char AA �  
+	.db	$24
+	.db	$AA
+	.db	$A6
+; Char AB �  
+	.db	$84
+	.db	$AA
+	.db	$A6
+; Char AC �  
+	.db	$4A
+	.db	$AA
+	.db	$A6
+; Char AD �  
+	.db	$A0
+	.db	$AA
+	.db	$A6
+; Char AE �  
+	.db	$24
+	.db	$0A
+	.db	$A6
+; Char AF �  
+	.db	$84
+	.db	$0A
+	.db	$A6
+; Char B0 �  
+	.db	$4A
+	.db	$0A
+	.db	$A6
+; Char B1 �  
+	.db	$A0
+	.db	$0A
+	.db	$A6
+; Char B2 �  
+	.db	$68
+	.db	$88
+	.db	$6C
+; Char B3 �  
+	.db	$06
+	.db	$88
+	.db	$6C
+; Char B4 �  
+	.db	$5A
+	.db	$CA
+	.db	$AA
+; Char B5 �  
+	.db	$5A
+	.db	$0C
+	.db	$AA
+; Char B6 �  
+	.db	$64
+	.db	$00
+	.db	$00
+; Char B7 �  
+	.db	$42
+	.db	$00
+	.db	$00
+; Char B8 �  
+	.db	$A0
+	.db	$00
+	.db	$00
+; Char B9 �  
+	.db	$40
+	.db	$48
+	.db	$60
+; Char BA �  
+	.db	$80
+	.db	$88
+	.db	$88
+; Char BB �  
+	.db	$05
+	.db	$AA
+	.db	$50
+; Char BC �  
+	.db	$02
+	.db	$56
+	.db	$5A
+; Char BD �  
+	.db	$05
+	.db	$A2
+	.db	$20
+; Char BE �  
+	.db	$00
+	.db	$4A
+	.db	$E0
+; Char BF �  
+	.db	$34
+	.db	$27
+	.db	$96
+; Char C0 �  
+	.db	$68
+	.db	$E8
+	.db	$60
+; Char C1 �  
+	.db	$C8
+	.db	$88
+	.db	$C0
+; Char C2 �  
+	.db	$84
+	.db	$26
+	.db	$90
+; Char C3 �  
+	.db	$0A
+	.db	$AA
+	.db	$D8
+; Char C4 �  
+	.db	$0F
+	.db	$55
+	.db	$90
+; Char C5 �  
+	.db	$25
+	.db	$56
+	.db	$48
+; Char C6 �  
+	.db	$F4
+	.db	$24
+	.db	$F0
+; Char C7 �  
+	.db	$07
+	.db	$AA
+	.db	$40
+; Char C8 �  
+	.db	$07
+	.db	$A2
+	.db	$20
+; Char C9 �  
+	.db	$4E
+	.db	$AE
+	.db	$40
+; Char CA �  
+	.db	$69
+	.db	$99
+	.db	$69
+; Char CB �  
+	.db	$E0
+	.db	$A4
+	.db	$A0
+; Char CC �  
+	.db	$E0
+	.db	$A6
+	.db	$24
+; Char CD �  
+	.db	$A4
+	.db	$A0
+	.db	$00
+; Char CE �  
+	.db	$00
+	.db	$00
+	.db	$A0
+; Char CF �  
+	.db	$26
+	.db	$E6
+	.db	$20
+; Char D0 �  
+	.db	$88
+	.db	$80
+	.db	$00
+; Char D1 �  
+	.db	$22
+	.db	$48
+	.db	$80
+; Char D2 �  
+	.db	$00
+	.db	$C0
+	.db	$00
+; Char D3 �  
+	.db	$C4
+	.db	$8C
+	.db	$00
+; Char D4 �  
+	.db	$EA
+	.db	$E0
+	.db	$00
+; Char D5 �  
+	.db	$E4
+	.db	$2C
+	.db	$00
+; Char D6 �  
+	.db	$00
+	.db	$00
+	.db	$00
+; Char D7 �  
+	.db	$40
+	.db	$44
+	.db	$20
+; Char D8 �  
+	.db	$4A
+	.db	$CA
+	.db	$C8
+; Char D9 �  
+	.db	$8A
+	.db	$4A
+	.db	$20
+; Char DA �  
+	.db	$F8
+	.db	$AE
+	.db	$A8
+; Char DB �  
+	.db	$69
+	.db	$E8
+	.db	$60
+; Char DC �  
+	.db	$00
+	.db	$88
+	.db	$C0
+; Char DD �  
+	.db	$9D
+	.db	$FF
+	.db	$B9
+; Char DE �  
+	.db	$A5
+	.db	$55
+	.db	$A0
+; Char DF �  
+	.db	$4E
+	.db	$FE
+	.db	$40
+; Char E0 �  
+	.db	$FF
+	.db	$FF
+	.db	$FF
+; Char E1 �  
+	.db	$FB
+	.db	$1B
+	.db	$BF
+; Char E2 �  
+	.db	$FB
+	.db	$51
+	.db	$5F
+; Char E3 �  
+	.db	$FF
+	.db	$95
+	.db	$9F
+; Char E4 �  
+	.db	$00
+	.db	$00
+	.db	$0F
+; Char E5 �  
+	.db	$4E
+	.db	$44
+	.db	$0F
+; Char E6 �  
+	.db	$4A
+	.db	$EA
+	.db	$0F
+; Char E7 �  
+	.db	$06
+	.db	$A6
+	.db	$0F
+; Char E8 �  
+	.db	$00
+	.db	$84
+	.db	$20
+; Char E9 �  
+	.db	$00
+	.db	$C6
+	.db	$20
+; Char EA �  
+	.db	$00
+	.db	$E6
+	.db	$20
+; Char EB �  
+	.db	$00
+	.db	$8C
+	.db	$E0
+; Char EC �  
+	.db	$25
+	.db	$D5
+	.db	$20
+; Char ED �  
+	.db	$4A
+	.db	$AA
+	.db	$40
+; Char EE �  
+	.db	$08
+	.db	$02
+	.db	$00
+; Char EF �  
+	.db	$4E
+	.db	$44
+	.db	$40
+; Char F0 �  
+	.db	$44
+	.db	$4E
+	.db	$40
+; Char F1 �  
+	.db	$5A
+	.db	$5A
+	.db	$5A
+; Char F2 �  
+	.db	$27
+	.db	$A6
+	.db	$3E
+; Char F3 �  
+	.db	$4E
+	.db	$44
+	.db	$00
+; Char F4 �  
+	.db	$69
+	.db	$A9
+	.db	$A8
+; Char F5 �  
+	.db	$73
+	.db	$5E
+	.db	$AE
+; Char F6 �  
+	.db	$EA
+	.db	$E4
+	.db	$E4
+; Char F7 �  
+	.db	$6F
+	.db	$96
+	.db	$90
+; Char F8 �  
+	.db	$6F
+	.db	$16
+	.db	$90
+; Char F9 �  
+	.db	$6F
+	.db	$86
+	.db	$90
+; Char FA �  
+	.db	$69
+	.db	$96
+	.db	$90
+; Char FB �  
+	.db	$01
+	.db	$AC
+	.db	$E0
+; Char FC �  
+	.db	$08
+	.db	$53
+	.db	$70
+; Char FD �  
+	.db	$EC
+	.db	$A1
+	.db	$00
+; Char FE �  
+	.db	$73
+	.db	$58
+	.db	$00
+; Char FF �  
+	.db	$A5
+	.db	$A5
+	.db	$A5

BIN
src/fonts/gramfont_fix.mfefont


BIN
src/fonts/gramfont_var.mfefont


+ 2268 - 0
src/fonts/vfont.asm

@@ -0,0 +1,2268 @@
+; FONT METADATA
+; Code Page = ASCII
+; 
+; FONT DATA
+; Height byte
+	.db	7
+; Char 00 �  
+	.db	0 ; width
+; Char 01 �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$B0
+	.db	$48
+	.db	$48
+	.db	$90
+	.db	$90
+; Char 02 �  
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$70
+; Char 03 �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$88
+	.db	$88
+	.db	$50
+	.db	$50
+	.db	$20
+; Char 04 �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$88
+	.db	$88
+	.db	$A8
+	.db	$A8
+	.db	$50
+; Char 05 �  
+	.db	4 ; width
+	.db	$00
+	.db	$80
+	.db	$C0
+	.db	$E0
+	.db	$C0
+	.db	$80
+	.db	$00
+; Char 06 �  
+	.db	6 ; width
+	.db	$20
+	.db	$70
+	.db	$F8
+	.db	$70
+	.db	$70
+	.db	$70
+	.db	$00
+; Char 07 �  
+	.db	6 ; width
+	.db	$00
+	.db	$70
+	.db	$70
+	.db	$70
+	.db	$F8
+	.db	$70
+	.db	$20
+; Char 08 �  
+	.db	6 ; width
+	.db	$10
+	.db	$28
+	.db	$20
+	.db	$20
+	.db	$20
+	.db	$A0
+	.db	$40
+; Char 09 �  
+	.db	6 ; width
+	.db	$00
+	.db	$88
+	.db	$50
+	.db	$20
+	.db	$50
+	.db	$88
+	.db	$00
+; Char 0A �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$A0
+	.db	$E0
+	.db	$00
+	.db	$00
+; Char 0B �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$40
+	.db	$E0
+	.db	$40
+	.db	$00
+	.db	$00
+; Char 0C �  
+	.db	2 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$80
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 0D �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+; Char 0E �  
+	.db	4 ; width
+	.db	$E0
+	.db	$40
+	.db	$20
+	.db	$C0
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 0F �  
+	.db	5 ; width
+	.db	$00
+	.db	$F0
+	.db	$C0
+	.db	$E0
+	.db	$C0
+	.db	$C0
+	.db	$00
+; Char 10 �  
+	.db	5 ; width
+	.db	$38
+	.db	$20
+	.db	$20
+	.db	$20
+	.db	$A0
+	.db	$60
+	.db	$20
+; Char 11 �  
+	.db	5 ; width
+	.db	$30
+	.db	$10
+	.db	$D0
+	.db	$10
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 12 �  
+	.db	4 ; width
+	.db	$C0
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$E0
+	.db	$00
+	.db	$00
+; Char 13 �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$08
+	.db	$10
+	.db	$20
+	.db	$40
+	.db	$F8
+; Char 14 �  
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$60
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 15 �  
+	.db	5 ; width
+	.db	$A0
+	.db	$D0
+	.db	$80
+	.db	$80
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 16 �  
+	.db	4 ; width
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 17 �  
+	.db	6 ; width
+	.db	$08
+	.db	$30
+	.db	$C0
+	.db	$30
+	.db	$08
+	.db	$00
+	.db	$F8
+; Char 18 �  
+	.db	6 ; width
+	.db	$10
+	.db	$10
+	.db	$F8
+	.db	$20
+	.db	$F8
+	.db	$40
+	.db	$40
+; Char 19 �  
+	.db	6 ; width
+	.db	$80
+	.db	$60
+	.db	$18
+	.db	$60
+	.db	$80
+	.db	$00
+	.db	$F8
+; Char 1A �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 1B �  
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$F0
+	.db	$80
+	.db	$E0
+	.db	$80
+	.db	$F0
+; Char 1C �  
+	.db	7 ; width
+	.db	$00
+	.db	$10
+	.db	$08
+	.db	$FC
+	.db	$08
+	.db	$10
+	.db	$00
+; Char 1D �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$B8
+	.db	$A8
+	.db	$A8
+	.db	$A8
+	.db	$B8
+; Char 1E �  
+	.db	6 ; width
+	.db	$20
+	.db	$70
+	.db	$A8
+	.db	$20
+	.db	$20
+	.db	$20
+	.db	$20
+; Char 1F �  
+	.db	6 ; width
+	.db	$20
+	.db	$20
+	.db	$20
+	.db	$20
+	.db	$A8
+	.db	$70
+	.db	$20
+; Char 20     
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 21 ! ! 
+	.db	2 ; width
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$00
+	.db	$80
+; Char 22 " " 
+	.db	5 ; width
+	.db	$50
+	.db	$50
+	.db	$50
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 23 # # 
+	.db	6 ; width
+	.db	$50
+	.db	$50
+	.db	$F8
+	.db	$50
+	.db	$F8
+	.db	$50
+	.db	$50
+; Char 24 $ $ 
+	.db	4 ; width
+	.db	$80
+	.db	$A0
+	.db	$E0
+	.db	$20
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 25 % % 
+	.db	4 ; width
+	.db	$A0
+	.db	$20
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$80
+	.db	$A0
+; Char 26 & & 
+	.db	6 ; width
+	.db	$60
+	.db	$90
+	.db	$80
+	.db	$40
+	.db	$A8
+	.db	$90
+	.db	$68
+; Char 27 ' ' 
+	.db	2 ; width
+	.db	$80
+	.db	$80
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 28 ( ( 
+	.db	3 ; width
+	.db	$40
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$40
+; Char 29 ) ) 
+	.db	3 ; width
+	.db	$80
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$80
+; Char 2A * * 
+	.db	6 ; width
+	.db	$00
+	.db	$20
+	.db	$A8
+	.db	$70
+	.db	$A8
+	.db	$20
+	.db	$00
+; Char 2B + + 
+	.db	6 ; width
+	.db	$00
+	.db	$20
+	.db	$20
+	.db	$F8
+	.db	$20
+	.db	$20
+	.db	$00
+; Char 2C , , 
+	.db	3 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$40
+	.db	$40
+	.db	$80
+; Char 2D - - 
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$F8
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 2E . . 
+	.db	2 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$80
+; Char 2F / / 
+	.db	4 ; width
+	.db	$20
+	.db	$20
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$80
+	.db	$80
+; Char 30 0 0 
+	.db	6 ; width
+	.db	$70
+	.db	$88
+	.db	$98
+	.db	$A8
+	.db	$C8
+	.db	$88
+	.db	$70
+; Char 31 1 1 
+	.db	4 ; width
+	.db	$40
+	.db	$C0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$E0
+; Char 32 2 2 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$10
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$F0
+; Char 33 3 3 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$10
+	.db	$20
+	.db	$10
+	.db	$90
+	.db	$60
+; Char 34 4 4 
+	.db	6 ; width
+	.db	$10
+	.db	$30
+	.db	$50
+	.db	$90
+	.db	$F8
+	.db	$10
+	.db	$10
+; Char 35 5 5 
+	.db	5 ; width
+	.db	$F0
+	.db	$80
+	.db	$E0
+	.db	$10
+	.db	$10
+	.db	$90
+	.db	$60
+; Char 36 6 6 
+	.db	5 ; width
+	.db	$30
+	.db	$40
+	.db	$80
+	.db	$E0
+	.db	$90
+	.db	$90
+	.db	$60
+; Char 37 7 7 
+	.db	5 ; width
+	.db	$F0
+	.db	$10
+	.db	$20
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+; Char 38 8 8 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$60
+; Char 39 9 9 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$70
+	.db	$10
+	.db	$20
+	.db	$40
+; Char 3A : : 
+	.db	2 ; width
+	.db	$00
+	.db	$00
+	.db	$80
+	.db	$00
+	.db	$00
+	.db	$80
+	.db	$00
+; Char 3B ; ; 
+	.db	3 ; width
+	.db	$00
+	.db	$40
+	.db	$00
+	.db	$00
+	.db	$40
+	.db	$40
+	.db	$80
+; Char 3C < < 
+	.db	5 ; width
+	.db	$10
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$40
+	.db	$20
+	.db	$10
+; Char 3D = = 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$F0
+	.db	$00
+	.db	$F0
+	.db	$00
+	.db	$00
+; Char 3E > > 
+	.db	5 ; width
+	.db	$80
+	.db	$40
+	.db	$20
+	.db	$10
+	.db	$20
+	.db	$40
+	.db	$80
+; Char 3F ? ? 
+	.db	6 ; width
+	.db	$70
+	.db	$88
+	.db	$08
+	.db	$10
+	.db	$20
+	.db	$00
+	.db	$20
+; Char 40 @ @ 
+	.db	7 ; width
+	.db	$78
+	.db	$84
+	.db	$B4
+	.db	$AC
+	.db	$BC
+	.db	$80
+	.db	$7C
+; Char 41 A A 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$F0
+	.db	$90
+	.db	$90
+	.db	$90
+; Char 42 B B 
+	.db	5 ; width
+	.db	$E0
+	.db	$90
+	.db	$90
+	.db	$E0
+	.db	$90
+	.db	$90
+	.db	$E0
+; Char 43 C C 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$90
+	.db	$60
+; Char 44 D D 
+	.db	5 ; width
+	.db	$E0
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$E0
+; Char 45 E E 
+	.db	5 ; width
+	.db	$F0
+	.db	$80
+	.db	$80
+	.db	$E0
+	.db	$80
+	.db	$80
+	.db	$F0
+; Char 46 F F 
+	.db	5 ; width
+	.db	$F0
+	.db	$80
+	.db	$80
+	.db	$E0
+	.db	$80
+	.db	$80
+	.db	$80
+; Char 47 G G 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$80
+	.db	$B0
+	.db	$90
+	.db	$90
+	.db	$60
+; Char 48 H H 
+	.db	5 ; width
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$F0
+	.db	$90
+	.db	$90
+	.db	$90
+; Char 49 I I 
+	.db	4 ; width
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$E0
+; Char 4A J J 
+	.db	5 ; width
+	.db	$70
+	.db	$20
+	.db	$20
+	.db	$20
+	.db	$20
+	.db	$A0
+	.db	$40
+; Char 4B K K 
+	.db	5 ; width
+	.db	$90
+	.db	$90
+	.db	$A0
+	.db	$C0
+	.db	$A0
+	.db	$90
+	.db	$90
+; Char 4C L L 
+	.db	4 ; width
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$E0
+; Char 4D M M 
+	.db	6 ; width
+	.db	$88
+	.db	$D8
+	.db	$A8
+	.db	$A8
+	.db	$88
+	.db	$88
+	.db	$88
+; Char 4E N N 
+	.db	5 ; width
+	.db	$90
+	.db	$D0
+	.db	$D0
+	.db	$B0
+	.db	$B0
+	.db	$90
+	.db	$90
+; Char 4F O O 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$60
+; Char 50 P P 
+	.db	5 ; width
+	.db	$E0
+	.db	$90
+	.db	$90
+	.db	$E0
+	.db	$80
+	.db	$80
+	.db	$80
+; Char 51 Q Q 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$60
+	.db	$30
+; Char 52 R R 
+	.db	5 ; width
+	.db	$E0
+	.db	$90
+	.db	$90
+	.db	$E0
+	.db	$90
+	.db	$90
+	.db	$90
+; Char 53 S S 
+	.db	5 ; width
+	.db	$60
+	.db	$90
+	.db	$80
+	.db	$60
+	.db	$10
+	.db	$90
+	.db	$60
+; Char 54 T T 
+	.db	4 ; width
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+; Char 55 U U 
+	.db	5 ; width
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$60
+; Char 56 V V 
+	.db	6 ; width
+	.db	$88
+	.db	$88
+	.db	$88
+	.db	$88
+	.db	$50
+	.db	$50
+	.db	$20
+; Char 57 W W 
+	.db	6 ; width
+	.db	$88
+	.db	$88
+	.db	$88
+	.db	$88
+	.db	$A8
+	.db	$A8
+	.db	$50
+; Char 58 X X 
+	.db	4 ; width
+	.db	$A0
+	.db	$A0
+	.db	$A0
+	.db	$40
+	.db	$A0
+	.db	$A0
+	.db	$A0
+; Char 59 Y Y 
+	.db	5 ; width
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$70
+	.db	$10
+	.db	$10
+	.db	$60
+; Char 5A Z Z 
+	.db	6 ; width
+	.db	$F8
+	.db	$08
+	.db	$10
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$F8
+; Char 5B [ [ 
+	.db	5 ; width
+	.db	$60
+	.db	$D0
+	.db	$90
+	.db	$F0
+	.db	$90
+	.db	$B0
+	.db	$60
+; Char 5C \ \ 
+	.db	4 ; width
+	.db	$80
+	.db	$80
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$20
+	.db	$20
+; Char 5D ] ] 
+	.db	3 ; width
+	.db	$C0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$C0
+; Char 5E ^ ^ 
+	.db	4 ; width
+	.db	$40
+	.db	$A0
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 5F _ _ 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$F0
+; Char 60 ` ` 
+	.db	3 ; width
+	.db	$80
+	.db	$40
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 61 a a 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$60
+	.db	$A0
+	.db	$A0
+	.db	$A0
+	.db	$50
+; Char 62 b b 
+	.db	5 ; width
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$E0
+	.db	$90
+	.db	$90
+	.db	$E0
+; Char 63 c c 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$60
+	.db	$90
+	.db	$80
+	.db	$90
+	.db	$60
+; Char 64 d d 
+	.db	5 ; width
+	.db	$10
+	.db	$10
+	.db	$10
+	.db	$70
+	.db	$90
+	.db	$90
+	.db	$70
+; Char 65 e e 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$60
+	.db	$90
+	.db	$F0
+	.db	$80
+	.db	$60
+; Char 66 f f 
+	.db	5 ; width
+	.db	$20
+	.db	$50
+	.db	$40
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+; Char 67 g g 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$70
+	.db	$90
+	.db	$70
+	.db	$10
+	.db	$60
+; Char 68 h h 
+	.db	5 ; width
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$A0
+	.db	$D0
+	.db	$90
+	.db	$90
+; Char 69 i i 
+	.db	2 ; width
+	.db	$00
+	.db	$80
+	.db	$00
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+; Char 6A j j 
+	.db	4 ; width
+	.db	$00
+	.db	$20
+	.db	$00
+	.db	$20
+	.db	$20
+	.db	$A0
+	.db	$40
+; Char 6B k k 
+	.db	4 ; width
+	.db	$00
+	.db	$80
+	.db	$A0
+	.db	$A0
+	.db	$C0
+	.db	$A0
+	.db	$A0
+; Char 6C l l 
+	.db	3 ; width
+	.db	$00
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$40
+; Char 6D m m 
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$A0
+	.db	$E0
+	.db	$A0
+	.db	$A0
+	.db	$A0
+; Char 6E n n 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$A0
+	.db	$D0
+	.db	$90
+	.db	$90
+	.db	$90
+; Char 6F o o 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$60
+; Char 70 p p 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$90
+	.db	$E0
+	.db	$80
+	.db	$80
+; Char 71 q q 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$70
+	.db	$90
+	.db	$70
+	.db	$10
+	.db	$10
+; Char 72 r r 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$A0
+	.db	$D0
+	.db	$80
+	.db	$80
+	.db	$80
+; Char 73 s s 
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$60
+	.db	$80
+	.db	$40
+	.db	$20
+	.db	$C0
+; Char 74 t t 
+	.db	4 ; width
+	.db	$40
+	.db	$40
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$20
+; Char 75 u u 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$70
+; Char 76 v v 
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$A0
+	.db	$A0
+	.db	$A0
+	.db	$A0
+	.db	$40
+; Char 77 w w 
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$A0
+	.db	$A0
+	.db	$A0
+	.db	$E0
+	.db	$A0
+; Char 78 x x 
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$A0
+	.db	$A0
+	.db	$40
+	.db	$A0
+	.db	$A0
+; Char 79 y y 
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$A0
+	.db	$A0
+	.db	$60
+	.db	$20
+	.db	$C0
+; Char 7A z z 
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$F0
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$F0
+; Char 7B { { 
+	.db	4 ; width
+	.db	$20
+	.db	$40
+	.db	$40
+	.db	$80
+	.db	$40
+	.db	$40
+	.db	$20
+; Char 7C | | 
+	.db	2 ; width
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+; Char 7D } } 
+	.db	4 ; width
+	.db	$80
+	.db	$40
+	.db	$40
+	.db	$20
+	.db	$40
+	.db	$40
+	.db	$80
+; Char 7E ~ ~ 
+	.db	6 ; width
+	.db	$00
+	.db	$40
+	.db	$A8
+	.db	$10
+	.db	$00
+	.db	$00
+	.db	$00
+; Char 7F   
+	.db	6 ; width
+	.db	$F8
+	.db	$F8
+	.db	$88
+	.db	$F8
+	.db	$88
+	.db	$F8
+	.db	$F8
+; Char 80 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$A0
+	.db	$A0
+	.db	$A0
+	.db	$E0
+; Char 81 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$40
+	.db	$C0
+	.db	$40
+	.db	$40
+	.db	$E0
+; Char 82 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$C0
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$E0
+; Char 83 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$C0
+	.db	$20
+	.db	$40
+	.db	$20
+	.db	$C0
+; Char 84 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$A0
+	.db	$A0
+	.db	$E0
+	.db	$20
+	.db	$20
+; Char 85 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$80
+	.db	$C0
+	.db	$20
+	.db	$C0
+; Char 86 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$60
+	.db	$80
+	.db	$E0
+	.db	$A0
+	.db	$E0
+; Char 87 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$20
+	.db	$40
+	.db	$40
+	.db	$40
+; Char 88 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$A0
+	.db	$E0
+	.db	$A0
+	.db	$E0
+; Char 89 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$A0
+	.db	$E0
+	.db	$20
+	.db	$C0
+; Char 8A �  
+	.db	6 ; width
+	.db	$10
+	.db	$20
+	.db	$70
+	.db	$88
+	.db	$F8
+	.db	$88
+	.db	$88
+; Char 8B �  
+	.db	6 ; width
+	.db	$40
+	.db	$20
+	.db	$70
+	.db	$88
+	.db	$F8
+	.db	$88
+	.db	$88
+; Char 8C �  
+	.db	6 ; width
+	.db	$20
+	.db	$50
+	.db	$70
+	.db	$88
+	.db	$F8
+	.db	$88
+	.db	$88
+; Char 8D �  
+	.db	6 ; width
+	.db	$50
+	.db	$00
+	.db	$70
+	.db	$88
+	.db	$F8
+	.db	$88
+	.db	$88
+; Char 8E �  
+	.db	6 ; width
+	.db	$20
+	.db	$40
+	.db	$00
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$68
+; Char 8F �  
+	.db	6 ; width
+	.db	$40
+	.db	$20
+	.db	$00
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$68
+; Char 90 �  
+	.db	6 ; width
+	.db	$20
+	.db	$50
+	.db	$00
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$68
+; Char 91 �  
+	.db	6 ; width
+	.db	$00
+	.db	$50
+	.db	$00
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$68
+; Char 92 �  
+	.db	5 ; width
+	.db	$20
+	.db	$40
+	.db	$F0
+	.db	$80
+	.db	$E0
+	.db	$80
+	.db	$F0
+; Char 93 �  
+	.db	5 ; width
+	.db	$40
+	.db	$20
+	.db	$F0
+	.db	$80
+	.db	$E0
+	.db	$80
+	.db	$F0
+; Char 94 �  
+	.db	5 ; width
+	.db	$20
+	.db	$50
+	.db	$F0
+	.db	$80
+	.db	$E0
+	.db	$80
+	.db	$F0
+; Char 95 �  
+	.db	5 ; width
+	.db	$50
+	.db	$00
+	.db	$F0
+	.db	$80
+	.db	$E0
+	.db	$80
+	.db	$F0
+; Char 96 �  
+	.db	5 ; width
+	.db	$20
+	.db	$40
+	.db	$60
+	.db	$90
+	.db	$E0
+	.db	$80
+	.db	$60
+; Char 97 �  
+	.db	5 ; width
+	.db	$40
+	.db	$20
+	.db	$60
+	.db	$90
+	.db	$E0
+	.db	$80
+	.db	$60
+; Char 98 �  
+	.db	6 ; width
+	.db	$20
+	.db	$50
+	.db	$70
+	.db	$88
+	.db	$F0
+	.db	$80
+	.db	$70
+; Char 99 �  
+	.db	5 ; width
+	.db	$50
+	.db	$00
+	.db	$60
+	.db	$90
+	.db	$E0
+	.db	$80
+	.db	$60
+; Char 9A �  
+	.db	4 ; width
+	.db	$20
+	.db	$40
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$E0
+; Char 9B �  
+	.db	4 ; width
+	.db	$80
+	.db	$40
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$E0
+; Char 9C �  
+	.db	4 ; width
+	.db	$40
+	.db	$A0
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$E0
+; Char 9D �  
+	.db	4 ; width
+	.db	$A0
+	.db	$00
+	.db	$E0
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$E0
+; Char 9E �  
+	.db	2 ; width
+	.db	$40
+	.db	$80
+	.db	$00
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+; Char 9F �  
+	.db	3 ; width
+	.db	$80
+	.db	$40
+	.db	$00
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+; Char A0 �  
+	.db	4 ; width
+	.db	$40
+	.db	$A0
+	.db	$00
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+; Char A1 �  
+	.db	4 ; width
+	.db	$A0
+	.db	$00
+	.db	$00
+	.db	$40
+	.db	$40
+	.db	$40
+	.db	$40
+; Char A2 �  
+	.db	6 ; width
+	.db	$10
+	.db	$20
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$88
+	.db	$70
+; Char A3 �  
+	.db	6 ; width
+	.db	$40
+	.db	$20
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$88
+	.db	$70
+; Char A4 �  
+	.db	6 ; width
+	.db	$20
+	.db	$50
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$88
+	.db	$70
+; Char A5 �  
+	.db	6 ; width
+	.db	$50
+	.db	$00
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$88
+	.db	$70
+; Char A6 �  
+	.db	6 ; width
+	.db	$10
+	.db	$20
+	.db	$00
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$70
+; Char A7 �  
+	.db	6 ; width
+	.db	$40
+	.db	$20
+	.db	$00
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$70
+; Char A8 �  
+	.db	6 ; width
+	.db	$20
+	.db	$50
+	.db	$00
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$70
+; Char A9 �  
+	.db	6 ; width
+	.db	$50
+	.db	$00
+	.db	$00
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$70
+; Char AA �  
+	.db	5 ; width
+	.db	$10
+	.db	$20
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$60
+; Char AB �  
+	.db	5 ; width
+	.db	$80
+	.db	$40
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$60
+; Char AC �  
+	.db	5 ; width
+	.db	$20
+	.db	$50
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$60
+; Char AD �  
+	.db	5 ; width
+	.db	$50
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$60
+; Char AE �  
+	.db	6 ; width
+	.db	$20
+	.db	$40
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$68
+; Char AF �  
+	.db	6 ; width
+	.db	$40
+	.db	$20
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$68
+; Char B0 �  
+	.db	6 ; width
+	.db	$20
+	.db	$50
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$68
+; Char B1 �  
+	.db	6 ; width
+	.db	$50
+	.db	$00
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$68
+; Char B2 �  
+	.db	6 ; width
+	.db	$70
+	.db	$88
+	.db	$80
+	.db	$88
+	.db	$70
+	.db	$20
+	.db	$60
+; Char B3 �  
+	.db	6 ; width
+	.db	$00
+	.db	$70
+	.db	$88
+	.db	$80
+	.db	$88
+	.db	$70
+	.db	$C0
+; Char B4 �  
+	.db	6 ; width
+	.db	$28
+	.db	$50
+	.db	$88
+	.db	$C8
+	.db	$A8
+	.db	$98
+	.db	$88
+; Char B5 �  
+	.db	5 ; width
+	.db	$50
+	.db	$A0
+	.db	$E0
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$90
+; Char B6 �  
+	.db	4 ; width
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char B7 �  
+	.db	4 ; width
+	.db	$80
+	.db	$40
+	.db	$20
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char B8 �  
+	.db	4 ; width
+	.db	$00
+	.db	$A0
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char B9 �  
+	.db	6 ; width
+	.db	$20
+	.db	$00
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$88
+	.db	$70
+; Char BA �  
+	.db	2 ; width
+	.db	$80
+	.db	$00
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+; Char BB �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$68
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$68
+; Char BC �  
+	.db	6 ; width
+	.db	$30
+	.db	$48
+	.db	$48
+	.db	$70
+	.db	$48
+	.db	$48
+	.db	$B0
+; Char BD �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$40
+	.db	$A8
+	.db	$10
+	.db	$10
+	.db	$10
+; Char BE �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$20
+	.db	$50
+	.db	$88
+	.db	$F8
+; Char BF �  
+	.db	6 ; width
+	.db	$30
+	.db	$40
+	.db	$20
+	.db	$10
+	.db	$70
+	.db	$88
+	.db	$70
+; Char C0 �  
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$70
+	.db	$80
+	.db	$F0
+	.db	$80
+	.db	$70
+; Char C1 �  
+	.db	3 ; width
+	.db	$C0
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$C0
+; Char C2 �  
+	.db	6 ; width
+	.db	$00
+	.db	$40
+	.db	$20
+	.db	$10
+	.db	$30
+	.db	$48
+	.db	$88
+; Char C3 �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$E8
+	.db	$80
+; Char C4 �  
+	.db	7 ; width
+	.db	$00
+	.db	$00
+	.db	$FC
+	.db	$48
+	.db	$48
+	.db	$48
+	.db	$84
+; Char C5 �  
+	.db	6 ; width
+	.db	$00
+	.db	$30
+	.db	$48
+	.db	$48
+	.db	$70
+	.db	$40
+	.db	$80
+; Char C6 �  
+	.db	6 ; width
+	.db	$F8
+	.db	$40
+	.db	$20
+	.db	$10
+	.db	$20
+	.db	$40
+	.db	$F8
+; Char C7 �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$78
+	.db	$90
+	.db	$90
+	.db	$90
+	.db	$60
+; Char C8 �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$78
+	.db	$A0
+	.db	$20
+	.db	$20
+	.db	$10
+; Char C9 �  
+	.db	6 ; width
+	.db	$20
+	.db	$20
+	.db	$70
+	.db	$A8
+	.db	$70
+	.db	$20
+	.db	$20
+; Char CA �  
+	.db	6 ; width
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$88
+	.db	$50
+	.db	$50
+	.db	$D8
+; Char CB �  
+	.db	6 ; width
+	.db	$F8
+	.db	$00
+	.db	$88
+	.db	$50
+	.db	$20
+	.db	$50
+	.db	$88
+; Char CC �  
+	.db	5 ; width
+	.db	$F0
+	.db	$00
+	.db	$90
+	.db	$90
+	.db	$70
+	.db	$10
+	.db	$E0
+; Char CD �  
+	.db	4 ; width
+	.db	$A0
+	.db	$40
+	.db	$A0
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char CE �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$A8
+; Char CF �  
+	.db	4 ; width
+	.db	$00
+	.db	$20
+	.db	$60
+	.db	$E0
+	.db	$60
+	.db	$20
+	.db	$00
+; Char D0 �  
+	.db	2 ; width
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char D1 �  
+	.db	4 ; width
+	.db	$20
+	.db	$20
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$80
+	.db	$80
+; Char D2 �  
+	.db	4 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$E0
+	.db	$00
+	.db	$00
+	.db	$00
+; Char D3 �  
+	.db	4 ; width
+	.db	$C0
+	.db	$20
+	.db	$40
+	.db	$80
+	.db	$E0
+	.db	$00
+	.db	$00
+; Char D4 �  
+	.db	4 ; width
+	.db	$E0
+	.db	$A0
+	.db	$E0
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+; Char D5 �  
+	.db	4 ; width
+	.db	$E0
+	.db	$40
+	.db	$20
+	.db	$C0
+	.db	$00
+	.db	$00
+	.db	$00
+; Char D6 �  
+	.db	0 ; width
+; Char D7 �  
+	.db	5 ; width
+	.db	$40
+	.db	$00
+	.db	$C0
+	.db	$40
+	.db	$40
+	.db	$50
+	.db	$20
+; Char D8 �  
+	.db	5 ; width
+	.db	$40
+	.db	$A0
+	.db	$E0
+	.db	$90
+	.db	$E0
+	.db	$80
+	.db	$80
+; Char D9 �  
+	.db	6 ; width
+	.db	$80
+	.db	$48
+	.db	$50
+	.db	$20
+	.db	$50
+	.db	$90
+	.db	$08
+; Char DA �  
+	.db	6 ; width
+	.db	$F8
+	.db	$88
+	.db	$A0
+	.db	$E0
+	.db	$A0
+	.db	$80
+	.db	$80
+; Char DB �  
+	.db	6 ; width
+	.db	$00
+	.db	$00
+	.db	$70
+	.db	$88
+	.db	$F0
+	.db	$80
+	.db	$70
+; Char DC �  
+	.db	3 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$80
+	.db	$80
+	.db	$80
+	.db	$C0
+; Char DD �  
+	.db	6 ; width
+	.db	$88
+	.db	$C8
+	.db	$E8
+	.db	$F8
+	.db	$B8
+	.db	$98
+	.db	$88
+; Char DE �  
+	.db	5 ; width
+	.db	$A0
+	.db	$50
+	.db	$50
+	.db	$50
+	.db	$50
+	.db	$50
+	.db	$A0
+; Char DF �  
+	.db	6 ; width
+	.db	$00
+	.db	$20
+	.db	$F0
+	.db	$F8
+	.db	$F0
+	.db	$20
+	.db	$00
+; Char E0 �  
+	.db	5 ; width
+	.db	$F8
+	.db	$F8
+	.db	$F8
+	.db	$F8
+	.db	$F8
+	.db	$F8
+	.db	$F8
+; Char E1 �  
+	.db	5 ; width
+	.db	$F8
+	.db	$D8
+	.db	$88
+	.db	$50
+	.db	$D8
+	.db	$D8
+	.db	$D8
+; Char E2 �  
+	.db	5 ; width
+	.db	$F8
+	.db	$D8
+	.db	$A8
+	.db	$88
+	.db	$A8
+	.db	$A8
+	.db	$F8
+; Char E3 �  
+	.db	5 ; width
+	.db	$F8
+	.db	$F8
+	.db	$D8
+	.db	$A8
+	.db	$A8
+	.db	$D0
+	.db	$F8
+; Char E4 �  
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$00
+	.db	$F8
+; Char E5 �  
+	.db	5 ; width
+	.db	$20
+	.db	$70
+	.db	$A8
+	.db	$20
+	.db	$20
+	.db	$00
+	.db	$F8
+; Char E6 �  
+	.db	5 ; width
+	.db	$20
+	.db	$50
+	.db	$70
+	.db	$50
+	.db	$50
+	.db	$00
+	.db	$F8
+; Char E7 �  
+	.db	5 ; width
+	.db	$00
+	.db	$20
+	.db	$50
+	.db	$50
+	.db	$28
+	.db	$00
+	.db	$F8
+; Char E8 �  
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$80
+	.db	$40
+	.db	$20
+	.db	$10
+	.db	$00
+; Char E9 �  
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$C0
+	.db	$60
+	.db	$30
+	.db	$10
+	.db	$00
+; Char EA �  
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$F0
+	.db	$70
+	.db	$30
+	.db	$10
+	.db	$00
+; Char EB �  
+	.db	5 ; width
+	.db	$00
+	.db	$00
+	.db	$80
+	.db	$C0
+	.db	$E0
+	.db	$F0
+	.db	$00
+; Char EC �  
+	.db	5 ; width
+	.db	$00
+	.db	$20
+	.db	$50
+	.db	$D0
+	.db	$50
+	.db	$20
+	.db	$00
+; Char ED �  
+	.db	4 ; width
+	.db	$00
+	.db	$40
+	.db	$A0
+	.db	$A0
+	.db	$A0
+	.db	$40
+	.db	$00
+; Char EE �  
+	.db	6 ; width
+	.db	$00
+	.db	$80
+	.db	$00
+	.db	$20
+	.db	$00
+	.db	$08
+	.db	$00
+; Char EF �  
+	.db	6 ; width
+	.db	$20
+	.db	$70
+	.db	$F8
+	.db	$70
+	.db	$70
+	.db	$70
+	.db	$00
+; Char F0 �  
+	.db	6 ; width
+	.db	$00
+	.db	$70
+	.db	$70
+	.db	$70
+	.db	$F8
+	.db	$70
+	.db	$20
+; Char F1 �  
+	.db	5 ; width
+	.db	$A8
+	.db	$50
+	.db	$A8
+	.db	$50
+	.db	$A8
+	.db	$50
+	.db	$A8
+; Char F2 �  
+	.db	6 ; width
+	.db	$20
+	.db	$78
+	.db	$A0
+	.db	$70
+	.db	$28
+	.db	$F0
+	.db	$20
+; Char F3 �  
+	.db	6 ; width
+	.db	$20
+	.db	$70
+	.db	$F8
+	.db	$70
+	.db	$70
+	.db	$00
+	.db	$00
+; Char F4 �  
+	.db	6 ; width
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$B0
+	.db	$88
+	.db	$88
+	.db	$B0
+; Char F5 �  
+	.db	7 ; width
+	.db	$1C
+	.db	$0C
+	.db	$14
+	.db	$60
+	.db	$90
+	.db	$90
+	.db	$60
+; Char F6 �  
+	.db	5 ; width
+	.db	$70
+	.db	$88
+	.db	$88
+	.db	$70
+	.db	$20
+	.db	$70
+	.db	$20
+; Char F7 �  
+	.db	0 ; width
+; Char F8 �  
+	.db	0 ; width
+; Char F9 �  
+	.db	0 ; width
+; Char FA �  
+	.db	0 ; width
+; Char FB �  
+	.db	5 ; width
+	.db	$00
+	.db	$08
+	.db	$90
+	.db	$A0
+	.db	$C0
+	.db	$F0
+	.db	$00
+; Char FC �  
+	.db	5 ; width
+	.db	$00
+	.db	$80
+	.db	$48
+	.db	$28
+	.db	$18
+	.db	$78
+	.db	$00
+; Char FD �  
+	.db	5 ; width
+	.db	$F0
+	.db	$C0
+	.db	$A0
+	.db	$90
+	.db	$08
+	.db	$00
+	.db	$00
+; Char FE �  
+	.db	5 ; width
+	.db	$78
+	.db	$18
+	.db	$28
+	.db	$48
+	.db	$80
+	.db	$00
+	.db	$00
+; Char FF �  
+	.db	5 ; width
+	.db	$50
+	.db	$A8
+	.db	$50
+	.db	$A8
+	.db	$50
+	.db	$A8
+	.db	$50

+ 44 - 0
src/gfx/GetPixelLoc.z80

@@ -0,0 +1,44 @@
+pixLUT:
+  .db $80,$40,$20,$10,$08,$04,$02,$01
+GetPixelLoc:
+;Input:
+;     b is X
+;     c is y
+;Output:
+;     HL points to byte
+;     A is the mask
+;     nc if not computed, c if computed
+;Speed: 192+17{1,2,3,4,5,6,7,8}
+;Avg: 268.5cc
+;185cc
+  ld a,c
+  cp 64
+  ret nc
+  add a,a
+  add a,a
+  ld c,a
+  ld a,b
+  cp 96
+  ret nc
+
+  ld b,0
+  ld hl,(gbuf_temp)
+  add hl,bc
+  add hl,bc
+  add hl,bc
+  ld c,a
+  srl c
+  srl c
+  srl c
+  add hl,bc
+  and 7
+  ld b,pixLUT>>8
+  add a,pixLUT&255
+  ld c,a
+#if pixLUT&255>249
+  jr nc,$+3
+  inc b
+#endif
+  ld a,(bc)
+  scf
+  ret

+ 104 - 0
src/gfx/TileMap1.z80

@@ -0,0 +1,104 @@
+;=====================================================
+TileMap1:
+;=====================================================
+;Inputs:
+;     DE=MapLoc
+;     BC=TileLoc
+;     HL=MapWidth
+;     A=TileLogic
+;     (TempWord2)=Map X
+;     (TempWord3)=Map Y
+;=====================================================
+  and 7
+  ld (TempWord1),a
+  cp 7
+  jr nz,+_
+  ld a,(flags+33)
+  xor 16
+  ld (flags+33),a
+_:
+  push bc
+  push hl
+  push de
+  ld bc,(TempWord3)
+  call HL_Times_BC
+  ld bc,(TempWord2)
+  add hl,bc
+  pop bc \ add hl,bc
+  ex (sp),hl ;edited in 2.50.0.2
+  ld de,-12  ;
+  add hl,de  ;
+  pop de     ;
+  ld (TempWord2),hl
+  xor a
+  ld (TempWord1+1),a
+  pop bc
+;DE points to first Map Element
+;(TempWord2) is the map width thing
+;BC points to the sprite data
+  ld h,12
+TileMap1loop:
+  ld a,(de) \ inc de
+  dec h
+  jr nz,DrawNextTile
+  ld hl,(TempWord2)
+  add hl,de
+  ex de,hl
+  ld h,12
+DrawNextTile:
+  push hl
+  ld h,0 \ ld l,a
+  add hl,hl
+  add hl,hl
+  add hl,hl
+  ld a,(TempWord1)
+  cp 7
+  jr nz,+_
+  add hl,hl
+_:
+  add hl,bc
+  ld a,(TempWord1+1)
+  call DrawTile
+  ld (TempWord1+1),a
+  pop hl
+  jr nz,TileMap1Loop
+  ret
+DrawTile:
+;Input:
+;     A is the tile number to draw
+;     HL points to the sprite data
+;Output:
+;     A is incremented by 1
+;     BC is not changed
+;     DE is not changed
+;     HL is not changed
+;     z flag set if A is 96
+  sub 96
+  ret nc
+  push af
+  push hl
+  push de
+  push bc
+  ex de,hl
+;DE points to sprite
+  ld hl,(gbuf_temp)
+  inc h
+  inc h
+  inc h
+  ld bc,-96
+_:
+  add hl,bc
+  add a,12
+  jr nc,-_
+  ld c,a
+  inc b
+  add hl,bc
+  ld bc,0108h
+  ld a,(TempWord1)
+  call DrawSpriteXxY
+  pop bc
+  pop de
+  pop hl
+  pop af
+  add a,97
+  ret

+ 338 - 0
src/gfx/bigsprite.z80

@@ -0,0 +1,338 @@
+#define spritetmp 8000h
+sprite_width  = spritetmp+0
+sprite_x      = spritetmp+1
+sprite_mask0  = spritetmp+2
+sprite_mask1  = spritetmp+3
+sprite_method = spritetmp+4
+
+
+rshiftHA_7:
+  rr h \ rra
+  rr h \ rra
+  rr h \ rra
+  rr h \ rra
+  rr h \ rra
+  rr h \ rra
+  rr h \ rra
+  ex de,hl
+  ld e,a
+  ret
+spritemask:
+  .db $00,$80,$C0,$E0,$F0,$F8,$FC,$FE
+call_ix:
+  jp (ix)
+
+sprite:
+;Inputs:
+;     A is the method:
+;        0=Overwrite
+;        1=AND
+;        2=XOR
+;        3=OR
+;        5=Erase
+;     B is the X-coordinate
+;     C is the Y-Coordinate
+;     DE points to the sprite
+;     H is the height
+;     L is the width
+;     (gbuf_temp) is the buffer to which to draw
+
+  ld (sprite_method),a
+;First check if the sprite is on-screen in the horizontal direction
+  ld a,c
+  cp 64
+  jr c,+_
+  add a,h
+  ret nc
+  ld h,a
+  push hl
+  xor a
+  ld h,a
+  sub c
+  ex de,hl
+  add hl,de
+  dec a
+  jr nz,$-2
+  ex de,hl
+  pop hl
+  xor a
+  ld c,a
+_:
+;Next check h+c<=64
+  ld a,64
+  sub c
+  cp h
+  jr nc,+_
+  ld h,a
+_:
+
+;Make sure the height is not now 0
+  ld a,h
+  or a
+  ret z
+
+;Save the width and height of the sprite
+  push hl               ;height,width
+  ld h,b
+  ld (sprite_width),hl  ;x,width
+  push de               ;sprite pointer
+
+;Set up a pointer to the routine for shifting the  routine for shifting the sprite data
+  ld ixh,rshiftHA_7>>8
+  ld a,h
+  cpl
+  and 7
+  ld l,a
+  add a,a
+  add a,l
+  add a,rshiftHA_7&255
+  ld ixl,a
+#if (rshiftHA_7&255)>234
+  jr nc,$+4
+  inc ixh
+#endif
+
+
+
+  ld a,b
+  and 7
+  ld de,spritemask
+  add a,e
+  ld e,a
+#if spritemask&255>248
+  jr nc,$+3
+  inc d
+#endif
+  ld a,(de)
+  ld (sprite_mask0),a
+  cpl
+  ld (sprite_mask1),a
+;
+;
+  ld a,c
+  add a,a
+  sbc a,a
+  ld h,a
+  ld a,b
+  ld b,h
+  ld l,c
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  ld c,a
+  add a,a
+  sbc a,a
+  ld b,a
+  ld a,c
+  sra c
+  sra c
+  sra c
+  add hl,bc
+  ld bc,(gbuf_temp)
+  add hl,bc
+
+  pop de
+  pop bc
+  ;B is height
+  ;C is width
+  ex de,hl
+
+_:
+  push bc   ;height,width
+  push de   ;gbuf ptr
+  push hl   ;sprite data pointer
+  ld a,(sprite_x)
+  ld c,a
+  add a,8
+  ld (sprite_x),a
+  call spritemethod
+  pop hl
+  inc hl
+  pop de
+  inc de
+  pop bc
+  dec c
+  jr nz,-_
+  ret
+
+
+spritemethod:
+  ld a,(sprite_method)
+  dec a
+  jp z,spriteloop_AND
+  dec a
+  jp z,spriteloop_XOR
+  dec a
+  jp z,spriteloop_OR
+  sub 2
+  jp z,spriteloop_Erase
+
+
+spriteloop_Overwrite:
+  push bc
+  push hl
+  ld h,(hl)
+  xor a
+  call call_ix
+  ld a,c
+  cp 96
+  jr nc,+_
+  ld a,(sprite_mask0)
+  and (hl)
+  or d
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  add a,8
+  cp 96
+  jr nc,+_
+  ld a,(sprite_mask1)
+  and (hl)
+  or e
+  ld (hl),a
+_:
+  ld bc,11
+  add hl,bc
+  ex de,hl
+  pop hl
+  ld a,(sprite_width)
+  ld c,a
+  add hl,bc
+  pop bc
+  djnz spriteloop_Overwrite
+  ret
+spriteloop_OR:
+  push bc
+  push hl
+  ld h,(hl)
+  xor a
+  call call_ix
+  ld a,c
+  cp 96
+  jr nc,+_
+  ld a,(hl)
+  or d
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  add a,8
+  cp 96
+  jr nc,+_
+  ld a,(sprite_mask1)
+  ld a,(hl)
+  or e
+  ld (hl),a
+_:
+  ld bc,11
+  add hl,bc
+  ex de,hl
+  pop hl
+  ld a,(sprite_width)
+  ld c,a
+  add hl,bc
+  pop bc
+  djnz spriteloop_OR
+  ret
+spriteloop_XOR:
+  push bc
+  push hl
+  ld h,(hl)
+  xor a
+  call call_ix
+  ld a,c
+  cp 96
+  jr nc,+_
+  ld a,(hl)
+  xor d
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  add a,8
+  cp 96
+  jr nc,+_
+  ld a,(sprite_mask1)
+  ld a,(hl)
+  xor e
+  ld (hl),a
+_:
+  ld bc,11
+  add hl,bc
+  ex de,hl
+  pop hl
+  ld a,(sprite_width)
+  ld c,a
+  add hl,bc
+  pop bc
+  djnz spriteloop_XOR
+  ret
+spriteloop_AND:
+  push bc
+  push hl
+  ld h,(hl)
+  scf \ sbc a,a
+  call call_ix
+  ld a,c
+  cp 96
+  jr nc,+_
+  ld a,(hl)
+  and d
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  add a,8
+  cp 96
+  jr nc,+_
+  ld a,(sprite_mask1)
+  ld a,(hl)
+  and e
+  ld (hl),a
+_:
+  ld bc,11
+  add hl,bc
+  ex de,hl
+  pop hl
+  ld a,(sprite_width)
+  ld c,a
+  add hl,bc
+  pop bc
+  djnz spriteloop_AND
+  ret
+spriteloop_Erase:
+  push bc
+  push hl
+  ld h,(hl)
+  xor a
+  call call_ix
+  ld a,c
+  cp 96
+  jr nc,+_
+  ld a,d
+  cpl
+  and (hl)
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  add a,8
+  cp 96
+  jr nc,+_
+  ld a,e
+  cpl
+  and (hl)
+  ld (hl),a
+_:
+  ld bc,11
+  add hl,bc
+  ex de,hl
+  pop hl
+  ld a,(sprite_width)
+  ld c,a
+  add hl,bc
+  pop bc
+  djnz spriteloop_Erase
+  ret

+ 201 - 0
src/gfx/bigtile.z80

@@ -0,0 +1,201 @@
+;===========================================================
+bigtile:
+;===========================================================
+;Inputs:
+;     A is the method:
+;        0=Overwrite
+;        1=AND
+;        2=XOR
+;        3=OR
+;        4=Swap
+;        5=Erase
+;        6=Mask
+;        7=Gray
+;     B is the width (in bytes)
+;     C is the height (in pixels)
+;     DE points to the sprite data
+;     HL points to the output location
+;Outputs:
+;     HL is A*12 larger (next sprite down?)
+;     DE points to the next byte after the sprite data
+;     A is 0
+;     B is not changed
+;     C is 12-B
+;===========================================================
+  push af
+  ld a,c
+  di
+  ex af,af'
+  ld a,12
+  sub b
+  ld c,a
+  pop af
+OverwriteXxY:
+  or a
+  jr nz,ANDXxY
+  ex af,af'
+_:
+  ex de,hl
+  push bc
+  ldi
+  inc bc
+  djnz $-3
+  ex de,hl
+  add hl,bc
+  pop bc
+  dec a
+  jr nz,-_
+  ret
+ANDXxY:
+  dec a
+  jr nz,XORXxY
+  ex af,af'
+_:
+  push bc
+  push af
+  ld a,(de)
+  and (hl)
+  ld (hl),a
+  inc de
+  inc hl
+  djnz $-5
+  add hl,bc
+  pop af
+  pop bc
+  dec a
+  jr nz,-_
+  ret
+XORXxY:
+  dec a
+  jr nz,ORXxY
+  ex af,af'
+_:
+  push bc
+  push af
+  ld a,(de)
+  xor (hl)
+  ld (hl),a
+  inc de
+  inc hl
+  djnz $-5
+  add hl,bc
+  pop af
+  pop bc
+  dec a
+  jr nz,-_
+  ret
+ORXxY:
+  dec a
+  jr nz,SwapXxY
+  ex af,af'
+_:
+  push bc
+  push af
+  ld a,(de)
+  or (hl)
+  ld (hl),a
+  inc de
+  inc hl
+  djnz $-5
+  add hl,bc
+  pop af
+  pop bc
+  dec a
+  jr nz,-_
+  ret
+SwapXxY:
+  dec a
+  jr nz,EraseXxY
+  ex af,af'
+  ld c,12
+_:
+  push bc
+  push af
+  ld a,(de)
+  ldi
+  dec hl
+  ld (hl),a
+  inc hl
+  djnz $-6
+  add hl,bc
+  pop af
+  pop bc
+  dec a
+  jr nz,-_
+  ret
+EraseXxY:
+  dec a
+  jr nz,MaskXxY
+  ex af,af'
+  push bc
+  push af
+_:
+  ld a,(de)
+  cpl
+  and (hl)
+  ld (hl),a
+  inc de
+  inc hl
+  djnz -_
+  add hl,bc
+  pop af
+  pop bc
+  dec a
+  jr nz,-_-2
+  ret
+MaskXxY:
+  dec a
+  jr nz,GrayXxY
+  ex af,af'
+_:
+  push bc
+  push af
+  ex de,hl
+  ld a,(de)
+  and (hl)
+  inc hl
+  or (hl)
+  ld (de),a
+  inc de
+  inc hl
+  djnz $-7
+  ex de,hl
+  add hl,bc
+  pop af
+  pop bc
+  dec a
+  jr nz,-_
+  ret
+GrayXxY:
+  bit grayFlag,(iy+InternalFlag)
+  ld a,55h
+  jr z,$+3
+  rrca
+  ex af,af'
+_:
+  push bc
+  push af
+  ex af,af'
+  ld (hl),a
+  ex de,hl
+  and (hl)
+  inc hl
+  or (hl)
+  inc hl
+  ex de,hl
+  push af
+  ld a,(hl)
+  ex af,af'
+  pop af
+  ld (hl),a
+  inc hl
+  djnz $-14
+  add hl,bc
+  ex af,af'
+  rlca
+  ex af,af'
+  pop af
+  pop bc
+  dec a
+  jr nz,-_
+  ret

+ 110 - 0
src/gfx/circle.z80

@@ -0,0 +1,110 @@
+circle:
+;Input:
+; (B,C) is the center (x,y)
+; E is the radius, unsigned, less than 128 (0 or greater than 128 just quits).
+; IX points to a `plot` routine that takes (B,C)=(x,y) as input.
+
+  ld a,e
+  add a,a
+  ret c
+  ret z
+  ld l,e
+  dec a
+  ld e,a
+  dec a        ;if the pixel is only 1 wide, just plot the point
+  jp z,call_ix ;Jump to the plot routine
+  xor a
+  ld h,-1
+  ld d,1
+  scf     ;skip the first plot
+circleloop:
+  call nc,plot4
+  inc h
+  sub d
+  inc d
+  inc d
+  jr nc,circleloop
+_:
+  dec l
+  call plot4
+  add a,e
+  dec e
+  ret z
+  dec e
+  jr nc,-_
+  jp circleloop
+
+
+plot4:
+;BC is center
+;HL is x,y
+
+  push de
+  push af
+  ld a,(circle_pattern)
+  rlca
+  ld (circle_pattern),a
+  jr c,plot4_end
+  push hl
+  push bc
+
+;If H is 0, or L is 0, we need to draw only half
+  push hl
+
+  ld a,b
+  sub h
+  ld b,a
+  add a,h
+  add a,h
+  ld h,a
+
+  ld a,c
+  sub l
+  ld c,a
+  add a,l
+  add a,l
+  ld l,a
+
+;B is x0-x
+;C is y0-y
+;H is x0+x
+;L is y0+y
+
+
+;plot(x0-x,y0-y)
+;plot(x0+x,y0+y)
+  push bc
+  push hl
+  call call_ix    ;call the plot routine
+  pop bc
+  push bc
+  call call_ix    ;call the plot routine
+
+;now swap the y coords
+  pop hl
+  pop bc
+  ld a,l
+  ld l,c
+  ld c,a
+  pop de
+  xor a
+  cp d
+  jr z,+_
+  cp e
+  jr z,+_
+
+
+;plot(x0-x,y0+y)
+;plot(x0+x,y0-y)
+  push hl
+  call call_ix    ;call the plot routine
+  pop bc
+  call call_ix    ;call the plot routine
+_:
+
+  pop bc
+  pop hl
+plot4_end:
+  pop af
+  pop de
+  ret

+ 868 - 0
src/gfx/drawrect.z80

@@ -0,0 +1,868 @@
+bordermask = TempWord2
+fillmask   = TempWord3
+leftmask   = bordermask
+rightmask  = fillmask
+rect:
+;Inputs:
+;   A is the type of rectangle to draw
+;      0 = White
+;      1 = Black
+;      2 = XOR
+;      3 = Black border
+;      4 = White border
+;      5 = XOR border
+;      6 = Black border, white fill
+;      7 = Black border, invert fill
+;      8 = White border, black fill
+;      9 = White border, invert fill
+;     10 = Shift Up
+;     11 = Shift Down
+;     12 = Shift Right    *Not Implmented
+;     13 = Shift Left     *Not Implemented
+;     14 = Pxl-Test Rect (count the on pixels)
+;     15 = Pxl-Test border (count the on pixels)
+;     16 = Invert border, Black fill
+;     17 = Invert border, White fill
+;   B is the height
+;   C is the Y pixel coordinate
+;   D is the width in pixels
+;   E is is the X pixel coordinate
+;   (gbuf_temp) points to the buffer to draw to.
+;Outputs:
+;   BC is the count for the pixel test methods.
+;Destroys:
+;   AF,BC,DE,HL, TempWord1, TempWord2
+;   IX is destroyed in the pixel count and shifting routines.
+  or a
+  jp z,rect_wbwf
+  dec a
+  jp z,rect_bbbf
+  dec a
+  jp z,rect_xbxf
+  dec a
+  jp z,rect_bbcf
+  dec a
+  jp z,rect_wbcf
+  dec a
+  jp z,rect_xbcf
+  dec a
+  jr z,rect_bbwf
+  dec a
+  jr z,rect_bbxf
+  dec a
+  jr z,rect_wbbf
+  dec a
+  jr z,rect_wbxf
+  dec a
+  jp z,rect_shift_up
+  dec a
+  jp z,rect_shift_down
+  dec a
+  jp z,rect_shift_right
+  dec a
+  jp z,rect_shift_left
+  dec a
+  jp z,pixel_test_rect
+  dec a
+  jp z,pixel_test_border
+  dec a
+  jr z,rect_xbbf
+  dec a
+  ret nz
+
+rect_xbwf:
+  push de
+  push bc
+  call rect_xbcf
+  jr rect_white_fill
+
+rect_bbwf:
+  push de
+  push bc
+  call rect_bbcf
+rect_white_fill:
+  pop bc
+  pop de
+  inc c
+  inc e
+  ld a,b
+  sub 2
+  ret c
+  ld b,a
+  ld a,d
+  sub 2
+  ret c
+  ld d,a
+  jr rect_wbwf
+
+rect_bbxf:
+  push de
+  push bc
+  call rect_bbcf
+  jr rect_x_fill
+
+rect_wbxf:
+  push de
+  push bc
+  call rect_wbcf
+rect_x_fill:
+  pop bc
+  pop de
+  inc c
+  inc e
+  ld a,b
+  sub 2
+  ret c
+  ld b,a
+  ld a,d
+  sub 2
+  ret c
+  ld d,a
+  jr rect_xbxf
+
+rect_wbbf:
+  push de
+  push bc
+  call rect_wbcf
+  jr rect_black_fill
+
+rect_xbbf:
+  push de
+  push bc
+  call rect_xbcf
+rect_black_fill:
+  pop bc
+  pop de
+  inc c
+  inc e
+  ld a,b
+  sub 2
+  ret c
+  ld b,a
+  ld a,d
+  sub 2
+  ret c
+  ld d,a
+  jr rect_bbbf
+
+rect_wbwf:
+  call rectsub
+  ret nc
+_:
+  call horiz_wb
+  djnz -_
+  ret
+rect_bbbf:
+  call rectsub
+  ret nc
+_:
+  call horiz_bb
+  djnz -_
+  ret
+rect_xbxf:
+  call rectsub
+  ret nc
+_:
+  call horiz_xb
+  djnz -_
+  ret
+
+rect_bbcf:
+  call rectsub
+  ret nc
+  rra
+  jr c,+_
+  push af
+  call horiz_bb
+  pop af
+  dec b
+  ret z
+_:
+  ld de,(bordermask)
+  rra
+  push af
+  jr nc,rect_bbcf_loopend
+_:
+  push bc
+  push hl
+  ld a,d
+  or (hl)
+  ld (hl),a
+  ld b,0
+  dec c
+  add hl,bc
+  ld a,e
+  or (hl)
+  ld (hl),a
+  pop hl
+  ld c,12
+  add hl,bc
+  pop bc
+rect_bbcf_loopend:
+  djnz -_
+  pop af
+  ret c
+  ld de,(fillmask)
+  jp horiz_bb
+
+rect_wbcf:
+  call rectsub
+  ret nc
+  rra
+  jr c,+_
+  push af
+  call horiz_wb
+  pop af
+  dec b
+  ret z
+_:
+  ld de,(bordermask)
+  rra
+  push af
+
+  ld de,(bordermask)
+  ld a,d
+  cpl
+  ld d,a
+  ld a,e
+  cpl
+  ld e,a
+  jr nc,rect_wbcf_loopend
+_:
+  push bc
+  push hl
+  ld a,d
+  and (hl)
+  ld (hl),a
+  ld b,0
+  dec c
+  add hl,bc
+  ld a,e
+  and (hl)
+  ld (hl),a
+  pop hl
+  ld c,12
+  add hl,bc
+  pop bc
+rect_wbcf_loopend:
+  djnz -_
+  pop af
+  ret c
+  ld de,(fillmask)
+  jp horiz_wb
+
+rect_xbcf:
+  call rectsub
+  ret nc
+  rra
+  jr c,+_
+  push af
+  call horiz_xb
+  pop af
+  dec b
+  ret z
+_:
+  ld de,(bordermask)
+  rra
+  push af
+  jr nc,rect_xbcf_loopend
+_:
+  push bc
+  push hl
+  ld a,d
+  xor (hl)
+  ld (hl),a
+  ld b,0
+  dec c
+  add hl,bc
+  ld a,e
+  xor (hl)
+  ld (hl),a
+  pop hl
+  ld c,12
+  add hl,bc
+  pop bc
+rect_xbcf_loopend:
+  djnz -_
+  pop af
+  ret c
+  ld de,(fillmask)
+  jp horiz_xb
+
+horizline_white:
+;takes as input E=x, A=y, D=width as input
+  ld b,1
+  ld c,a
+  call rectsub
+  ret nc
+horiz_wb:
+;Draws a horizontal white border
+
+;Save the width and height
+  push bc
+
+;Get the width in B
+  ld b,c
+
+;Check if the width is 1
+  ld a,d
+  dec b
+  jr nz,+_
+  and e
+  cpl
+  and (hl)
+  ld (hl),a
+  jr rect_add12
+_:
+
+;save the pointer so that we can add 12 later
+  push hl
+
+  cpl
+  and (hl)
+  ld (hl),a
+  xor a
+  .db $FE
+_:
+  ld (hl),a
+  inc hl
+  djnz -_
+  ld a,e
+  cpl
+  and (hl)
+  ld (hl),a
+
+;restore the pointer and add 12
+;take advantage of B=0 before restoring
+  jr rect_restadd12
+
+horizline_black:
+;takes as input E=x, A=y, D=width as input
+  ld b,1
+  ld c,a
+  call rectsub
+  ret nc
+horiz_bb:
+;Draws a horizontal black border
+
+;Save the width and height
+  push bc
+
+;Get the width in B
+  ld b,c
+
+;Check if the width is 1
+  ld a,d
+  dec b
+  jr nz,+_
+  and e
+  or (hl)
+  ld (hl),a
+  jr rect_add12
+_:
+
+;save the pointer so that we can add 12 later
+  push hl
+
+  or (hl)
+  ld (hl),a
+  ld a,-1
+  .db $FE
+_:
+  ld (hl),a
+  inc hl
+  djnz -_
+  ld a,e
+  or (hl)
+  ld (hl),a
+
+  jr rect_restadd12
+
+horizline_invert:
+;takes as input E=x, A=y, D=width as input
+  ld b,1
+  ld c,a
+  call rectsub
+  ret nc
+horiz_xb:
+;Draws a horizontal inverted border
+
+;Save the width and height
+  push bc
+
+;Get the width in B
+  ld b,c
+
+;Check if the width is 1
+  ld a,d
+  dec b
+  jr nz,+_
+  and e
+  xor (hl)
+  ld (hl),a
+  jr rect_add12
+_:
+
+;save the pointer so that we can add 12 later
+  push hl
+
+  xor (hl)
+  ld (hl),a
+  jr $+5
+_:
+  ld a,(hl)
+  cpl
+  ld (hl),a
+  inc hl
+  djnz -_
+  ld a,e
+  xor (hl)
+  ld (hl),a
+
+;restore the pointer and add 12
+;take advantage of B=0 before restoring
+rect_restadd12:
+  pop hl
+rect_add12:
+  ld c,12
+  add hl,bc
+  pop bc
+  ret
+
+horiz_count:
+;returns A as the number of set bits.
+;screen is less than 256 pixels wide, so no need to worry about overflow
+  push bc
+  ld b,c
+  ld c,-1
+  dec b
+  jr nz,+_
+  ld a,d
+  and e
+  and (hl)
+  inc c
+  add a,a
+  jr c,$-2
+  jr nz,$-3
+  add ix,bc
+  jr rect_add12
+_:
+  push hl
+  ld a,(hl)
+  and d
+  inc c
+  add a,a
+  jr c,$-2
+  jr nz,$-3
+  jr horiz_count_loop_end
+horiz_count_loop:
+  ld a,(hl)
+  .db $FE
+  inc c
+  add a,a
+  jr c,$-2
+  jr nz,$-3
+horiz_count_loop_end:
+  inc hl
+  djnz horiz_count_loop
+  ld a,(hl)
+  and e
+  .db $FE
+  inc c
+  add a,a
+  jr c,$-2
+  jr nz,$-3
+  add ix,bc
+  jr rect_restadd12
+
+rect_shift_up:
+  call rectsub
+  ret nc
+  dec c
+  jr z,rect_shift_up_1col
+  jr rect_shift_up_end
+rect_shift_up_loop:
+  push bc
+  push hl
+
+  push hl
+  pop ix
+
+  ld a,(ix+12)
+  xor (hl)
+  and d
+  xor (hl)
+  ld (hl),a
+
+  ld b,c
+  jr rect_shift_up_loop_final
+_:
+  ld a,(ix+12)
+  ld (hl),a
+rect_shift_up_loop_final:
+  inc hl
+  inc ix
+  djnz -_
+  ld a,(ix+12)
+  xor (hl)
+  and e
+  xor (hl)
+  ld (hl),a
+
+  pop hl
+  ld c,12
+  add hl,bc
+  pop bc
+rect_shift_up_end:
+  djnz rect_shift_up_loop
+  inc c
+  jp horiz_wb
+
+rect_shift_up_1col:
+  ld a,d
+  and e
+  ld d,a
+  jr rect_shift_up_1col_end
+_:
+  push hl
+  pop ix
+
+  ld a,(ix+12)
+  xor (hl)
+  and d
+  xor (hl)
+  ld (hl),a
+  ld a,l
+  add a,12
+  ld l,a
+  jr nc,rect_shift_up_1col_end
+  inc h
+rect_shift_up_1col_end:
+  djnz -_
+  ld a,d
+  cpl
+  and (hl)
+  ld (hl),a
+  ret
+
+rect_shift_down:
+  call rectsub
+  ret nc
+;need to start at the bottom and work backwards!
+;HL + B*12-1
+  push bc
+  push hl
+  ld a,c
+  dec b
+  ld h,0
+  ld l,b
+  ld b,h
+  ld c,l
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  dec l       ;B is at most 63, B*12 != 0 mod 256, so this is safe
+  ld c,a
+  add hl,bc
+  pop bc
+  add hl,bc
+  pop bc
+
+
+
+  dec c
+  jr z,rect_shift_down_1col
+  jr rect_shift_down_end
+rect_shift_down_loop:
+  push bc
+  push hl
+  push hl
+  pop ix
+
+  ld a,(ix-12)
+  xor (hl)
+  and e
+  xor (hl)
+  ld (hl),a
+
+  ld b,c
+  jr rect_shift_down_loop_final
+_:
+  ld a,(ix-12)
+  ld (hl),a
+rect_shift_down_loop_final:
+  dec hl
+  dec ix
+  djnz -_
+  ld a,(ix-12)
+  xor (hl)
+  and d
+  xor (hl)
+  ld (hl),a
+
+  pop hl
+  ld bc,-12
+  add hl,bc
+  pop bc
+rect_shift_down_end:
+  djnz rect_shift_down_loop
+  or a
+  sbc hl,bc
+  inc c
+  jp horiz_wb
+
+rect_shift_down_1col:
+  ld a,d
+  and e
+  ld d,a
+  jr rect_shift_up_1col_end
+_:
+  push hl
+  pop ix
+
+  ld a,(ix-12)
+  xor (hl)
+  and d
+  xor (hl)
+  ld (hl),a
+  ld a,l
+  sub 12
+  ld l,a
+  jr nc,rect_shift_down_1col_end
+  dec h
+rect_shift_down_1col_end:
+  djnz -_
+  ld a,d
+  cpl
+  and (hl)
+  ld (hl),a
+  ret
+
+rect_shift_right:
+rect_shift_left:
+  ret
+
+setBC_0:
+  ld bc,0
+  ret
+pixel_test_rect:
+  call rectsub
+  jr nc,setBC_0
+  ld ix,0
+_:
+  call horiz_count
+  djnz -_
+  ld b,ixh
+  ld c,ixl
+  ret
+
+pixel_test_border:
+  call rectsub
+  jr nc,setBC_0
+  ld ix,0
+  call horiz_count
+  dec b
+  ret z
+  ld de,(bordermask)
+  jr pixel_test_border_loop_end
+pixel_test_border_loop:
+  push bc
+  push hl
+  ld a,d
+  and (hl)
+  jr z,+_
+  inc ix
+_:
+  ld b,0
+  dec c
+  add hl,bc
+
+  ld a,e
+  and (hl)
+  jr z,+_
+  inc ix
+_:
+  pop hl
+  ld c,12
+  add hl,bc
+  pop bc
+pixel_test_border_loop_end:
+  djnz pixel_test_border_loop
+  ld de,(fillmask)
+  call horiz_count
+  ld b,ixh
+  ld c,ixl
+  ret
+
+
+rectsub:
+;Input:
+;   (B,C) is (height,y)
+;   (D,E) is (width,x)
+  ld a,b
+  ld b,e
+  ld e,a
+;(E,C) = (x,y) signed
+;(D,B) = (w,h) unsigned
+;Output:
+;   Start Mask  D
+;   End Mask    E
+;   Height      B
+;   Byte width  C
+;   buf ptr     HL
+;   bit 0 of A set if top clipped
+;   bit 1 of A set if bottom clipped
+
+;H will temporarily keep track of left and right OOB
+;bit 0 means left OOB, bit 1 means right OOB
+;bit 2 means top OOB, bit 3 means bottom OOB
+  ld hl,0
+  ld (bordermask),hl
+
+  bit 7,b
+  jr z,+_
+  ;Here, b is negative, so we have to add width to x.
+  ;If the result is still negative, the entire box is out of bounds, so return
+  ;otherwise, set width=newvalue,b=0
+  ld a,d
+  add a,b
+  ret nc
+  ld d,a
+  ld b,h
+  inc h
+_:
+  bit 7,c
+  jr z,+_
+  ld a,e
+  add a,c
+  ret nc
+  ld e,a
+  ld c,0
+  set 2,h
+_:
+;We have clipped all negative areas.
+;Now we need to verify that (x,y) are on the screen.
+;If they aren't, then the whole rectangle is off-screen so no need to draw.
+  ld a,b
+  cp 96
+  ret nc
+  ld a,c
+  cp 64
+  ret nc
+;Let's also verfiy that height and width are non-zero:
+  ld a,d
+  or a
+  ret z
+  ld a,e
+  or a
+  ret z
+;Now we need to clip the width and height to be in-bounds
+  add a,c
+  cp 65
+  jr c,+_
+  ;Here we need to set e=64-c
+  ld a,64
+  sub c
+  ld e,a
+  set 3,h
+_:
+  ld a,d
+  add a,b
+  cp 97
+  jr c,+_
+  ;Here we need to set d=96-b
+  ld a,96
+  sub b
+  ld d,a
+  inc h
+  inc h
+_:
+;B is starting X
+;C is starting Y
+;D is width
+;E is height
+;H has info on if the masks need to be adjusted for border vs. fill
+  push bc
+
+;Generate the first mask
+  ld l,b
+  ld a,b
+  and 7
+  ld b,a
+  ld a,-1
+  jr z,+_
+  rra \ djnz $-1
+_:
+
+  inc a
+  cpl
+  ld (fillmask+1),a   ;left mask
+  rr h
+  jr c,+_
+  add a,1
+  rra
+  ld (bordermask+1),a
+_:
+
+
+
+  dec d
+  ld a,l
+  add a,d
+  and 7
+  ld b,a
+  ld a,$7F
+  jr z,+_
+  rrca \ djnz $-1
+_:
+  inc a
+  ld (fillmask),a   ;left mask
+  rr h
+  jr c,+_
+  dec a
+  cpl
+  ld (bordermask),a
+_:
+  ex (sp),hl
+
+  ld a,h
+  ld h,b
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  ld b,a
+  rrca
+  rrca
+  rrca
+  and 31
+  add a,l
+  ld l,a
+  jr nc,+_
+  inc h
+_:
+;B is the starting x, D is width
+;Only A,B,D,E are available
+  ld a,b
+  add a,d
+  and $F8
+  ld d,a
+
+  ld a,b
+  and $F8
+  ld b,a
+  ld a,d
+  sub b
+  rrca
+  rrca
+  rrca
+  ld c,a
+  ld b,e
+  ld de,(gbuf_temp)
+  add hl,de
+  ld de,(fillmask)
+  inc c
+  pop af
+  scf
+  ret

+ 85 - 0
src/gfx/filledcircle.z80

@@ -0,0 +1,85 @@
+;Written by Zeda Thomas, free to use.
+
+;This draws the fill of a circle centered at 8-bit coordinates and with radius
+;up to 127.
+;IX points to a `horizontal line` routine that takes E=x, A=y, D=width as input
+;and does something with it, like plot a horizontal line.
+;
+; For example, on the ti-83+/84+/SE calculators, you might have:
+;     horizontal_line:
+;       ld b,e
+;       ld c,a
+;       ld e,1
+;       ld hl,gbuf
+;       jp rectOR
+
+; Required subroutines:
+;     call_ix_01:
+;       jp (ix)
+
+filledcircle:
+;Input:
+; (B,C) is the center (x,y)
+; E is the radius, unsigned, less than 128 (0 or greater than 128 just quits).
+; IX points to a `plot` routine that takes (B,C)=(x,y) as input.
+  ld a,e
+  add a,a
+  ret c
+  ret z
+  ld l,e
+  dec a
+  ld e,a
+  xor a
+  ld h,-1
+  ld d,1
+filledcircleloop:
+  ; call c,fillcircle_plot
+  inc h
+  sub d
+  inc d
+  inc d
+  jr nc,filledcircleloop
+_:
+  dec l
+  call fillcircle_plot
+  add a,e
+  dec e
+  ret z
+  dec e
+  jr nc,-_
+  jp filledcircleloop
+
+fillcircle_plot:
+  inc h
+  dec h
+  ret z
+  push hl
+  push de
+  push bc
+  push af
+  dec h
+  ld a,b
+  sub h
+  ld e,a
+  ld d,h
+  sll d   ;aka `slia`, undocumented
+
+  ld a,l
+  or a
+  ld h,c
+  jr z,+_
+  add a,h
+  push de
+  push hl
+  call nz,call_ix_01
+  pop hl
+  pop de
+_:
+  ld a,h
+  sub l
+  call call_ix_01
+  pop af
+  pop bc
+  pop de
+  pop hl
+  ret

+ 269 - 0
src/gfx/gbufToLCD.z80

@@ -0,0 +1,269 @@
+GraphToLCD_:
+  ld hl,(BufPtr)
+  ld de,(GrayBufPtr)
+
+BufferToLCD_:
+;Input:
+;     HL points to the buffer to copy to the LCD
+;     DE points to a secondary buffer to use in grayscale
+;     (graymask) has the gray mask
+;     (graymask+1) is the method
+;     expects the LCD to be in X-increment mode
+;       (If you don't know what this means, you probably don't have to worry!)
+;Outputs:
+;     HL is incremented by 12
+;     DE is incremented by 12
+;Destroys:
+;     AF,BC,IX
+;       This might change in the future, but A and C are the gray mask, B is 0,
+;       and IX points to the routine that mixes the pixels from two layers
+  di
+  ld a,(graymask+1)
+  or a
+  ld ix,gray2
+  jr z,+_
+  ld ix,gray3
+  dec a
+  jr z,+_
+gbuftoLCD_4:
+  ld ix,gray4
+  sub 15
+  jr c,+_
+  dec a
+  jp z,mask_buffer_to_LCD
+  ld ix,LCD_buf_OR
+_:
+
+; Expect that the LCD increment mode is already set to increment down
+;
+; We shouldn't need a delay here!
+;  in a,(16) \ rla \ jr c,$-3
+
+; Set the LCD pointer to the top row
+  ld a,$80
+  out (16),a
+
+;We have to wait for the LCD anyways, so may as well do something useful.
+;Get the gray mask and put it in C
+  ld a,(graymask)
+  ld c,a
+
+;Wait for the LCD to be ready for new data
+  in a,(16) \ rla \ jr c,$-3
+
+; Set the LCD pointer to the left-most column of 8 pixels
+  ld a,$20
+
+col:
+;Set the column
+  out (10h),a
+
+;Save the column number
+  push af
+
+;Set B to 64, we'll be writing a whole column, so 64 writes.
+  ld b,64
+_:
+
+;Now wait for the LCD to be ready
+  in a,(16) \ rla \ jr c,$-3
+
+;IX points to our mask routine. It rotates the mask and computes the next byte.
+  call call_ix_01    ;rotate the mask
+  bit InvertLCDFlag,(iy+userflags)
+  jr z,$+3
+  cpl
+  out (17),a
+
+;We are drawing in columns, so we need to advance HL by 12
+  ld a,12
+  add a,l
+  ld l,a
+  jr nc,$+3
+  inc h
+
+;And advance DE by 12
+  ld a,12
+  add a,e
+  ld e,a
+  jr nc,$+3
+  inc d
+
+  djnz -_
+
+;Rotate the mask an extra time. We want to keep it out of phase.
+  dec ix
+  call call_ix_01    ;rotate the mask
+  inc ix
+
+
+;Now point to HL to the start of the next column.
+;If we subtract 768, it is where it started, so we'd need to increment 1 more.
+;Basically, HL-(3*256)+1
+  dec h
+  dec h
+  dec h
+  inc hl
+
+;Same with DE
+  dec d
+  dec d
+  dec d
+  inc de
+
+;Restore A to the column number, then increment. If it hits $2C, we've drawn all
+;12 columns, so no more looping. Otherwise, draw the next column.
+  pop af
+  inc a
+  cp $2C
+  jp nz,col
+
+;Rotate the mask one final time. Our masks are either 2- or 3-cycles, and we
+;want to avoid a static image if possible!
+  call call_ix_01     ;rotate the mask one last time
+  ld a,c
+  ld (graymask),a
+  ret
+
+gray2:
+;This just grabs from the main buffer
+  ld a,(hl)
+  ret
+
+  nop
+gray3:
+;Toggles the mask between %10101010 and %01010101.
+  rlc c
+
+; Now we use C to select pixels from either (DE), or (HL).
+; If a bit in C is 0, the corresponding bit in the output is from (HL),
+; else it is from (DE). There is an explaination of this at the end.
+  ld a,(de)
+  xor (hl)
+  and c
+  xor (hl)
+  ret
+
+gray4:
+  ld a,c  ;\
+  cp $C0  ; | Rotate the graymask
+  rra     ; | Can be efficiently done by rotating left while
+  ld c,a  ;/  shifting in the XOR of the top two bits.
+
+; Now we use C to select pixels from either (DE), or (HL).
+; If a bit in C is 0, the corresponding bit in the output is from (HL),
+; else it is from (DE). There is an explaination of this at the end.
+  ld a,(de)
+  xor (hl)
+  and c
+  xor (hl)
+  ret
+
+LCD_buf_OR:
+  ld a,(de)
+  or (hl)
+  ret
+
+mask_buffer_to_LCD:
+;This will AND the secondary buf on to the tilemap_buf, then OR the primary buf
+;on to that.
+  ld ix,(tilemap_buf)
+
+; Expect that the LCD increment mode is already set to increment down
+;
+; We shouldn't need a delay here!
+;  in a,(16) \ rla \ jr c,$-3
+
+; Set the LCD pointer to the top row
+  ld a,$80
+  out (16),a
+
+;Wait for the LCD to be ready for new data
+  in a,(16) \ rla \ jr c,$-3
+
+; Set the LCD pointer to the left-most column of 8 pixels
+  ld a,$20
+
+maskcol:
+;Set the column
+  out (10h),a
+
+;Save the column number
+  push af
+
+;Set B to 64, we'll be writing a whole column, so 64 writes.
+  ld bc,$400C
+_:
+  push bc
+  ld a,(de)
+  and (ix)
+  xor (hl)
+  bit InvertLCDFlag,(iy+userflags)
+  jr z,$+3
+  cpl
+  push af
+
+  ld b,0
+  add hl,bc
+  ex de,hl
+  add hl,bc
+  ex de,hl
+  add ix,bc
+
+;Now wait for the LCD to be ready
+  in a,(16) \ rla \ jr c,$-3
+  pop af
+  out (17),a
+  pop bc
+  djnz -_
+
+;Now point to HL to the start of the next column.
+;If we subtract 768, it is where it started, so we'd need to increment 1 more.
+;Basically, HL-(3*256)+1
+  dec h
+  dec h
+  dec h
+  inc hl
+
+;Same with DE
+  dec d
+  dec d
+  dec d
+  inc de
+
+;Same with IX
+  dec ixh
+  dec ixh
+  dec ixh
+  inc ix
+
+;Restore A to the column number, then increment. If it hits $2C, we've drawn all
+;12 columns, so no more looping. Otherwise, draw the next column.
+  pop af
+  inc a
+  cp $2C
+  jp nz,maskcol
+  ret
+
+
+; How C can select from two different buffers
+;
+;
+;We'll use this magical formula:
+; ((x^y)&m)^y
+;
+;When m is 0:
+;   ((x^y)&m)^y
+; = ((x^y)&0)^y
+; = (0)^y
+; = y
+;
+;When m is 1:
+;   ((x^y)&m)^y
+; = ((x^y)&1)^y
+; = (x^y)^y
+; = x^(y^y)     ;We can do this when all operations are XOR
+; = x
+;
+;So a 0 in the mask will choose the pixel from (HL) (primary buffer),
+;and a 1 will choose a pixel from (DE) (gray/back/secondary buffer).

+ 88 - 0
src/gfx/gbufToLCD_old.z80

@@ -0,0 +1,88 @@
+;===============================================================
+GraphToLCD:
+;===============================================================
+  ld hl,(BufPtr)
+  ld ix,(GrayBufPtr)
+;===============================================================
+BufferToLCD:
+;===============================================================
+;Input:
+;     HL points to the buffer to copy to the LCD
+;Outputs:
+;
+;===============================================================
+  di
+  LCDDelay()
+  ld a,$80
+  out (16),a
+  exx
+  ld hl,(GrayMask)
+  add hl,hl
+  jr nc,$+4
+  set 4,l
+  ld (GrayMask),hl
+  ld bc,(textmode)
+  ld a,3
+  and c
+  ld c,a
+  exx
+  ld de,12
+
+  LCDDelay()
+  ld a,$20
+col:
+  push af
+  pop af
+  out (10h),a
+  push af
+  ld b,64
+row:
+;(checker AND gray) OR black
+;
+  exx
+  add hl,hl
+  jr nc,$+4
+  set 4,l
+  ld a,h
+  exx
+  ld c,a
+  ld a,(ix)
+  xor (hl)
+  and c
+  xor (hl)
+  add hl,de
+  add ix,de
+  bit InvertLCDFlag,(iy+UserFlags)
+  jr z,$+3
+  cpl
+  ex af,af'
+  LCDDelay()
+  ex af,af'
+  out ($11),a
+  exx
+  ld b,c
+  inc b
+  dec b
+  jr z,RotateDone
+RotateMask:
+  add hl,hl
+  jr nc,$+4
+  set 4,l
+  ld a,h
+  djnz RotateMask
+RotateDone:
+  exx
+  djnz row
+  pop af
+  inc a
+  dec h
+  dec h
+  dec h
+  inc hl
+  dec ixh
+  dec ixh
+  dec ixh
+  inc ix
+  cp $2c
+  jp nz,col
+  ret

+ 415 - 0
src/gfx/gbufToLCD_speed.z80

@@ -0,0 +1,415 @@
+#define lcd_delay()  ex (sp),hl \ ex (sp),hl
+
+GraphToLCD_:
+  ld hl,(BufPtr)
+  ld ix,(GrayBufPtr)
+
+BufferToLCD_:
+;Input:
+;     HL points to the buffer to copy to the LCD
+;     IX points to a secondary buffer to use in grayscale
+;     (graymask) has the gray mask
+;     (graymask+1) is the method
+;     expects the LCD to be in X-increment mode
+;       (If you don't know what this means, you probably don't have to worry!)
+;Outputs:
+;     HL is incremented by 12
+;     DE is incremented by 12
+;Destroys:
+;     AF,BC,IX
+;       This might change in the future, but A and C are the gray mask, B is 0,
+;       and IX points to the routine that mixes the pixels from two layers
+
+; Don't want interrupts interfering
+  di
+
+; Expect that the LCD increment mode is already set to increment down
+;
+; We shouldn't need a delay here!
+;  in a,(16) \ rla \ jr c,$-3
+
+; Set the LCD pointer to the top row
+  ld a,$80
+  out (16),a
+
+  lcd_delay()   ;new calcs seem to ignore the LCD busy bit
+
+;we'll need to increment HL by 12 each iteration anyways, so may as well make
+;DE useful
+  ld de,12
+
+  ld a,(graymode)
+  or a
+  jr z,gray2
+  dec a
+  jp z,gray3
+  dec a
+  jp z,gray4
+  sub 14
+  jp z,LCD_buf_OR
+  dec a
+  jp z,mask_buffer_to_LCD
+
+gray2:
+  ld c,16
+
+; Set the LCD pointer to the left-most column of 8 pixels
+  ld a,$20
+
+gray2_col:
+  lcd_delay()   ;new calcs seem to ignore the LCD busy bit
+
+;Wait for the LCD to be ready for new data
+  in f,(c) \ jp m,$-2
+
+;Set the column
+  out (10h),a
+
+;Save the column number
+  push af
+
+;Set B to 64, we'll be writing a whole column, so 64 writes.
+  ld b,64
+_:
+;Now wait for the LCD to be ready
+  ld a,(hl)
+  add hl,de
+  bit InvertLCDFlag,(iy+userflags)
+  jr z,$+3
+  cpl
+  in f,(c) \ jp m,$-2
+  out (17),a
+  djnz -_
+  dec h
+  dec h
+  dec h
+  inc hl
+
+;Restore A to the column number, then increment. If it hits $2C, we've drawn all
+;12 columns, so no more looping. Otherwise, draw the next column.
+  pop af
+  inc a
+  cp $2C
+  jp nz,gray2_col
+  ret
+
+gray3:
+;We have to wait for the LCD anyways, so may as well do something useful.
+;Get the gray mask and put it in C
+  ld a,(graymask)
+  ld c,a
+
+;Wait for the LCD to be ready for new data
+  in a,(16) \ rla \ jr c,$-3
+
+; Set the LCD pointer to the left-most column of 8 pixels
+  ld a,$20
+
+gray3_col:
+;Set the column
+  out (10h),a
+
+;Save the column number
+  push af
+
+;Set B to 64, we'll be writing a whole column, so 64 writes.
+  ld b,64
+_:
+
+;Toggles the mask between %10101010 and %01010101.
+  rlc c
+
+;Now wait for the LCD to be ready
+  in a,(16) \ rla \ jr c,$-3
+
+; Now we use C to select pixels from either (IX), or (HL).
+; If a bit in C is 0, the corresponding bit in the output is from (HL),
+; else it is from (IX). There is an explaination of this at the bottom.
+  ld a,(ix)
+  xor (hl)
+  and c
+  xor (hl)
+
+  add hl,de
+  add ix,de
+
+  bit InvertLCDFlag,(iy+userflags)
+  jr z,$+3
+  cpl
+  out (17),a
+
+  djnz -_
+
+;Now point to HL to the start of the next column.
+;If we subtract 768, it is where it started, so we'd need to increment 1 more.
+;Basically, HL-(3*256)+1
+  dec h
+  dec h
+  dec h
+  inc hl
+
+;Same with IX
+  dec ixh
+  dec ixh
+  dec ixh
+  inc ix
+
+;Now wait for the LCD to be ready
+  in a,(16) \ rla \ jr c,$-3
+
+;Restore A to the column number, then increment. If it hits $2C, we've drawn all
+;12 columns, so no more looping. Otherwise, draw the next column.
+  pop af
+  inc a
+  cp $2C
+  jp nz,gray3_col
+
+;Rotate the mask one final time. Our masks are either 2- or 3-cycles, and we
+;want to avoid a static image if possible!
+  ld a,c
+  rlca
+  ld (graymask),a
+  ret
+
+gray4:
+;We have to wait for the LCD anyways, so may as well do something useful.
+;Get the gray mask and put it in C
+  ld a,(graymask)
+  ld c,a
+
+;Wait for the LCD to be ready for new data
+  in a,(16) \ rla \ jr c,$-3
+
+; Set the LCD pointer to the left-most column of 8 pixels
+  ld a,$20
+
+gray4_col:
+;Set the column
+  out (10h),a
+
+;Save the column number
+  push af
+
+;Set B to 64, we'll be writing a whole column, so 64 writes.
+  ld b,64
+_:
+
+;Now wait for the LCD to be ready
+  in a,(16) \ rla \ jr c,$-3
+
+  ld a,c  ;\
+  cp $C0  ; | Rotate the graymask
+  rra     ; | Can be efficiently done by rotating left while
+  ld c,a  ;/  shifting in the XOR of the top two bits.
+
+; Now we use C to select pixels from either (IX), or (HL).
+; If a bit in C is 0, the corresponding bit in the output is from (HL),
+; else it is from (IX). There is an explaination of this at the end.
+  ld a,(ix)
+  xor (hl)
+  and c
+  xor (hl)
+
+  add hl,de
+  add ix,de
+
+  bit InvertLCDFlag,(iy+userflags)
+  jr z,$+3
+  cpl
+  out (17),a
+
+  djnz -_
+
+;Now point to HL to the start of the next column.
+;If we subtract 768, it is where it started, so we'd need to increment 1 more.
+;Basically, HL-(3*256)+1
+  dec h
+  dec h
+  dec h
+  inc hl
+
+;Same with IX
+  dec ixh
+  dec ixh
+  dec ixh
+  inc ix
+
+;Now wait for the LCD to be ready
+  in a,(16) \ rla \ jr c,$-3
+
+;Restore A to the column number, then increment. If it hits $2C, we've drawn all
+;12 columns, so no more looping. Otherwise, draw the next column.
+  pop af
+  inc a
+  cp $2C
+  jp nz,gray4_col
+
+;Rotate the mask one final time. Our masks are either 2- or 3-cycles, and we
+;want to avoid a static image if possible!
+  ld a,c
+  cp $C0
+  rra
+  ld (graymask),a
+  ret
+
+
+LCD_buf_OR:
+  ld c,16
+
+; Set the LCD pointer to the left-most column of 8 pixels
+  ld a,$20
+
+LCD_buf_OR_col:
+;Wait for the LCD to be ready for new data
+  in f,(c) \ jp m,$-2
+
+;Set the column
+  out (10h),a
+
+;Save the column number
+  push af
+
+;Set B to 64, we'll be writing a whole column, so 64 writes.
+  ld b,64
+_:
+
+;Now wait for the LCD to be ready
+  ld a,(hl)
+  or (ix)
+
+  add hl,de
+  add ix,de
+
+  bit InvertLCDFlag,(iy+userflags)
+  jr z,$+3
+  cpl
+  in f,(c) \ jp m,$-2
+  out (17),a
+  djnz -_
+  dec h
+  dec h
+  dec h
+  inc hl
+
+  dec ixh
+  dec ixh
+  dec ixh
+  inc ix
+
+  in f,(c) \ jp m,$-2
+
+;Restore A to the column number, then increment. If it hits $2C, we've drawn all
+;12 columns, so no more looping. Otherwise, draw the next column.
+  pop af
+  inc a
+  cp $2C
+  jp nz,LCD_buf_OR_col
+  ret
+
+mask_buffer_to_LCD:
+;This will AND the secondary buf on to the tilemap_buf, then OR the primary buf
+;on to that.
+  ld de,(tilemap_buf)
+
+; Expect that the LCD increment mode is already set to increment down
+;
+; We shouldn't need a delay here!
+;  in a,(16) \ rla \ jr c,$-3
+
+; ; Set the LCD pointer to the top row
+;   ld a,$80
+;   out (16),a
+
+;Wait for the LCD to be ready for new data
+  in a,(16) \ rla \ jr c,$-3
+
+; Set the LCD pointer to the left-most column of 8 pixels
+  ld a,$20
+
+maskcol:
+;Set the column
+  out (10h),a
+
+;Save the column number
+  push af
+
+;Set B to 64, we'll be writing a whole column, so 64 writes.
+  ld bc,$400C
+_:
+  push bc
+  ld a,(de)
+  and (ix)
+  xor (hl)
+  bit InvertLCDFlag,(iy+userflags)
+  jr z,$+3
+  cpl
+  push af
+
+  ld b,0
+  add hl,bc
+  ex de,hl
+  add hl,bc
+  ex de,hl
+  add ix,bc
+
+;Now wait for the LCD to be ready
+  in a,(16) \ rla \ jr c,$-3
+  pop af
+  out (17),a
+  pop bc
+  djnz -_
+
+;Now point to HL to the start of the next column.
+;If we subtract 768, it is where it started, so we'd need to increment 1 more.
+;Basically, HL-(3*256)+1
+  dec h
+  dec h
+  dec h
+  inc hl
+
+;Same with DE
+  dec d
+  dec d
+  dec d
+  inc de
+
+;Same with IX
+  dec ixh
+  dec ixh
+  dec ixh
+  inc ix
+
+;Restore A to the column number, then increment. If it hits $2C, we've drawn all
+;12 columns, so no more looping. Otherwise, draw the next column.
+  pop af
+  inc a
+  cp $2C
+  jp nz,maskcol
+  ret
+
+
+
+
+
+
+; How C can select from two different buffers
+;
+;
+;We'll use this magical formula:
+; ((x^y)&m)^y
+;
+;When m is 0:
+;   ((x^y)&m)^y
+; = ((x^y)&0)^y
+; = (0)^y
+; = y
+;
+;When m is 1:
+;   ((x^y)&m)^y
+; = ((x^y)&1)^y
+; = (x^y)^y
+; = x^(y^y)     ;We can do this when all operations are XOR
+; = x
+;
+;So a 0 in the mask will choose the pixel from (HL) (primary buffer),
+;and a 1 will choose a pixel from (IX) (gray/back/secondary buffer).

+ 33 - 0
src/gfx/getpixelloc_nobound.z80

@@ -0,0 +1,33 @@
+GetPixelLoc_NoBound:
+  ld a,b
+  ld l,c
+  ld h,0
+  bit 7,c
+  jr z,+_
+  dec h
+_:
+  ld b,h
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  ld c,a
+  ld b,0
+  bit 7,c
+  jr z,+_
+  dec b
+_:
+  sra c
+  sra c
+  sra c
+  add hl,bc
+  ld bc,(gbuf_temp)
+  add hl,bc
+  and 7
+  ld b,a
+  ld a,$80
+  ret z
+_:
+  rrca
+  djnz -_
+  ret

+ 136 - 0
src/gfx/line.z80

@@ -0,0 +1,136 @@
+fastline:
+;(H,L) is (x0,y0)
+;(D,E) is (x1,y1)
+;IX points to the pixel plotting routine
+;
+; LICENSING NOTE:
+;     This code is (heavily) modified from Axe's open source code.
+;     There are structural similarities, but the majority of it is rewritten.
+
+  ld a,d
+	sub h
+	jp p,+_
+	ex de,hl
+	neg
+_:
+
+  push hl   ;Save the coordinates
+
+  ld c,a
+	ld a,l
+  ld l,c
+	sub e
+
+  ld c,0
+	jp p,+_
+	dec c
+	neg
+_:
+
+	ld h,a     ; H=DY, L=DX
+	cp l
+	jr nc,+_
+	ld a,l
+_:
+
+  pop de    ;restore coordinates
+	ld b,a    ; Pixel counter
+	inc b
+	cp h
+
+;want to preserve Z
+
+	jr nz,__LineH   ; Line is rather horizontal than vertical
+  ;divide A by 2, given carry is reset
+  rra
+__LineVLoop:
+  call call_ix    ;plot
+  rlc c
+  jr nc,+_
+  inc e
+  .db $FE
+_:
+  dec e
+	sub	l			; Handling gradient
+	jr	nc,+_
+  inc d
+	add	a,h
+_:
+	djnz __LineVLoop
+	ret
+
+__LineH:
+  ;divide A by 2, given carry is set
+	or a
+	rra
+
+__LineHLoop:
+  call call_ix    ;plot
+	inc	d
+	sub	h           ; Handling gradient
+	jr nc,__LineHNext
+  rlc c
+  jr nc,+_
+  inc e
+  .db $FE
+_:
+  dec e
+	add	a,l
+__LineHNext:
+	djnz __LineHLoop
+	ret
+
+pxloff:
+  push hl
+  push bc
+  push af
+
+  ld b,d
+  ld c,e
+  call getPixelLoc
+  jr nc,+_
+  cpl
+  and (hl)
+  ld (hl),a
+_:
+
+  pop af
+  pop bc
+  pop hl
+  ret
+
+pxlon:
+  push hl
+  push bc
+  push af
+
+  ld b,d
+  ld c,e
+  call getPixelLoc
+  jr nc,+_
+  or (hl)
+  ld (hl),a
+_:
+
+  pop af
+  pop bc
+  pop hl
+  ret
+
+pxlchange:
+  push hl
+  push bc
+  push af
+
+  ld b,d
+  ld c,e
+  call getPixelLoc
+  jr nc,+_
+  xor (hl)
+  ld (hl),a
+_:
+
+  pop af
+  pop bc
+  pop hl
+  ret

+ 441 - 0
src/gfx/rect.z80

@@ -0,0 +1,441 @@
+;Issues:
+;  For the ones with border and fill different, need to actually check the top and bottom border weren't clipped
+;  Status is stored at TempWord1+1, just not used yet.
+
+#define rightbordermask TempWord2
+#define leftbordermask TempWord2+1
+#define toprightmask TempWord3
+#define topleftmask TempWord3+1
+rect:
+;Inputs:
+;     A is the type of rectangle to draw
+;        0 =White
+;        1 =Black
+;        2 =XOR
+;        3 =Black border
+;        4 =White border
+;        5 =XOR border
+;        6 =Black border, white inside
+;        7 =Black border, XOR inside
+;        8 =White border, black inside
+;        9 =White border, XOR inside
+;        10=Shift Up
+;        11=Shift Down
+;     B is the height
+;     C is the Y pixel coordinate
+;     D is the width in pixels
+;     E is is the X pixel coordinate
+
+;Need to generate a top/bottom left and right mask
+;Need to generate a left and right mask
+  ld (TempWord1),a    ;saving the method
+  ld a,e
+  and 7
+  ld hl,spritemask
+  add a,l
+  ld l,a
+#if spritemask&255>248
+  jr nc,$+3
+  inc h
+#endif
+  cpl
+  ld (topleftmask),a
+  ld l,a
+  rra
+  xor l
+  ld (leftbordermask),a
+
+  ld a,e
+  add a,d
+  cpl
+  and 7
+#if spritemask&255>248
+  ld hl,spritemask
+  add a,l
+  ld l,a
+  jr nc,$+3
+  inc h
+#else
+  add a,spritemask&255
+  ld l,a
+#endif
+  ld (toprightmask),a
+  ld l,a
+  rra
+  xor l
+  ld (rightbordermask),a
+
+
+;Now we make sure the rect is on-screen is on-screen in the horizontal direction
+  sla l     ;This will hold clipping info
+
+  ld a,c
+  cp 64
+  jr c,+_
+  add a,b
+  ret nc
+  ld c,0
+  ld b,a
+  inc l
+_:
+;Next check b+c<=64 and b>0
+  sla l
+  ld a,64
+  sub c
+  ret z
+  cp b
+  jr nc,+_
+  ld b,a
+  inc l
+_:
+
+;Next check if the rect is on-screen in the vertical direction
+  ld a,e
+  cp 96
+  jr c,+_
+  add a,d
+  ret nc
+  ld d,a
+  xor a
+  ld e,a
+  ld (rightbordermask),a
+
+_:
+;Next check d+e<=64
+  ld a,96
+  sub e
+  cp d
+  jr nc,+_
+  ld d,a
+  xor a
+  ld (leftbordermask),a
+_:
+;B is the height
+;C is the Y pixel coordinate
+;D is the width in pixels
+;E is is the X pixel coordinate
+;L is clipping flags:
+;   bit 0 means bottom-clipped
+;   bit 1 means top-clipped
+  ld a,l
+  ld (TempWord1+1),a    ;Store clipping flags
+;Now We calculate where to begin drawing.
+;Note that this will always start on screen due to how we performed clipping
+  ld a,b
+  ld h,0
+  ld b,h
+  ld l,c
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  ld c,e
+  srl c
+  srl c
+  srl c
+  add hl,bc
+  ld bc,(gbuf_temp)
+  add hl,bc
+  ld b,a
+;Need to calculate how many bytes spanned
+  ld a,e
+  and %11111000
+  ld c,a
+  ld a,e
+  add a,d
+  and %11111000
+  sub c
+  ld d,a
+  inc d
+;B is height
+;HL points to where to start drawing
+;D is bytes spanned
+
+  ld a,(TempWord1)
+  or a
+  jp z,rect_wbwf
+  dec a
+  jp z,rect_bbbf
+  dec a
+  jp z,rect_xbxf
+  dec a
+  jp z,rect_bbcf
+  dec a
+  jp z,rect_wbcf
+  dec a
+  jp z,rect_xbcf
+  dec a
+  jp z,rect_bbwf
+  dec a
+  jp z,rect_bbxf
+  dec a
+  jp z,rect_wbbf
+  dec a
+  jp z,rect_wbxf
+  dec a
+  jp z,rect_shift_up
+  dec a
+  jp z,rect_shift_down
+  dec a
+  jp z,rect_shift_right
+  dec a
+  jp z,rect_shift_left
+  dec a
+  jp z,rect_xbbf
+  dec a
+  ret nz
+rect_xbwf:
+  call horiz_xb
+  dec b
+  ret z
+  dec b
+  jp z,horiz_xb
+  ;Here we need to fill with an inverted border, white fill
+  dec d
+  jr z,rect_xbwf_1byte
+rect_xbwf_loop:
+  push de
+  push hl
+  ld a,(topleftmask)
+  rra
+  cpl
+  and (hl)
+  ld e,a
+  ld a,(leftbordermask)
+  xor e
+  ld (hl),a
+  inc hl
+  dec d
+  jr z,+_
+  ld (hl),0
+  inc hl
+  dec d
+  jr nz,$-4
+_:
+  ld a,(toprightmask)
+  rla
+  cpl
+  and (hl)
+  ld e,a
+  ld a,(rightbordermask)
+  xor e
+  ld (hl),a
+  pop hl
+  ld e,12
+  add hl,de
+  pop de
+  djnz rect_xbwf_loop
+  jp horiz_xb
+rect_xbwf_1byte:
+  ld a,(topleftmask)
+  ld e,a
+  ld a,(toprightmask)
+  and e
+  ld e,a
+  ld a,(leftbordermask)
+  ld d,a
+  ld a,(rightbordermask)
+  or d
+  and e
+  ld d,a
+  ld a,e
+  cpl
+  ld e,a
+_:
+  ld a,(hl)
+  and e
+  xor d
+  ld (hl),a
+  inc hl
+  djnz -_
+rect_wbwf:
+_:
+  call horiz_wb
+  djnz -_
+  ret
+rect_bbbf:
+;B is height
+;HL points to where to start drawing
+;D is bytes spanned
+_:
+  call horiz_bb
+  djnz -_
+  ret
+rect_xbxf:
+_:
+  call horiz_xb
+  djnz -_
+  ret
+rect_bbcf:
+  call horiz_bb
+  dec b
+  ret z
+  dec b
+  jp z,horiz_bb
+  ;Here we need to fill with a black border, clear fill
+  ret
+rect_wbcf:
+  call horiz_wb
+  dec b
+  ret z
+  dec b
+  jp z,horiz_wb
+  ;Here we need to fill with a white border, clear fill
+  ret
+rect_xbcf:
+  call horiz_xb
+  dec b
+  ret z
+  dec b
+  jp z,horiz_xb
+  ;Here we need to fill with a inverted border, clear fill
+  ret
+rect_bbwf:
+  call horiz_bb
+  dec b
+  ret z
+  dec b
+  jp z,horiz_bb
+  ;Here we need to fill with a black border, white fill
+  ret
+rect_bbxf:
+  call horiz_bb
+  dec b
+  ret z
+  dec b
+  jp z,horiz_bb
+  ;Here we need to fill with a black border, inverted fill
+  ret
+rect_wbbf:
+  call horiz_wb
+  dec b
+  ret z
+  dec b
+  jp z,horiz_wb
+  ;Here we need to fill with a white border, black fill
+  ret
+rect_wbxf:
+  call horiz_wb
+  dec b
+  ret z
+  dec b
+  jp z,horiz_wb
+  ;Here we need to fill with a white border, inverted fill
+  ret
+rect_xbbf:
+  call horiz_xb
+  dec b
+  ret z
+  dec b
+  jp z,horiz_xb
+  ;Here we need to fill with a inverted border, black fill
+  ret
+rect_shift_up:
+rect_shift_down:
+rect_shift_right:
+rect_shift_left:
+  ret
+horiz_bb:
+  push de
+  dec d
+  ld a,(topleftmask)
+  jr nz,+_
+  ld e,a
+  ld a,(toprightmask)
+  and e
+  or (hl)
+  ld (hl),a
+  jr endhoriz_bb
+_:
+  push hl
+  or (hl)
+  ld (hl),a
+  inc hl
+  dec d
+  jr z,horizbb_lastiter
+_:
+  ld (hl),-1
+  inc hl
+  dec d
+  jr nz,-_
+horizbb_lastiter:
+  ld a,(toprightmask)
+  or (hl)
+  ld (hl),a
+  pop hl
+endhoriz_bb:
+  ld e,12
+  add hl,de
+  pop de
+  ret
+
+
+horiz_wb:
+  push de
+  dec d
+  ld a,(topleftmask)
+  cpl
+  jr nz,+_
+  ld e,a
+  ld a,(toprightmask)
+  cpl
+  or e
+  and (hl)
+  ld (hl),a
+  jr endhoriz_bb
+_:
+  push hl
+  and (hl)
+  ld (hl),a
+  inc hl
+  dec d
+  jr z,horizwb_lastiter
+_:
+  ld (hl),0
+  inc hl
+  dec d
+  jr nz,-_
+horizwb_lastiter:
+  ld a,(toprightmask)
+  cpl
+  and (hl)
+  ld (hl),a
+  pop hl
+  jp endhoriz_bb
+
+
+horiz_xb:
+  push de
+  dec d
+  ld a,(topleftmask)
+  jr nz,+_
+  ld e,a
+  ld a,(toprightmask)
+  and e
+  xor (hl)
+  ld (hl),a
+  jr endhoriz_bb
+_:
+  push hl
+  xor (hl)
+  ld (hl),a
+  inc hl
+  dec d
+  jr z,horizxb_lastiter
+_:
+  ld a,(hl)
+  cpl
+  ld (hl),a
+  inc hl
+  dec d
+  jr nz,-_
+horizxb_lastiter:
+  ld a,(toprightmask)
+  xor (hl)
+  ld (hl),a
+  pop hl
+  jp endhoriz_bb
+
+
+.echo "rect: ",$-rect
+;Need to beat 796 bytes

+ 313 - 0
src/gfx/sprite.z80

@@ -0,0 +1,313 @@
+#define spritetmp 8000h
+#define sprite_mask0 spritetmp+6
+#define sprite_mask1 spritetmp+7
+sprite:
+;Inputs:
+;     A is the method:
+;        0=Overwrite
+;        1=AND
+;        2=XOR
+;        3=OR
+;        4=DataSwap.......Does nothing
+;        5=Erase
+;     B is the X-coordinate
+;     C is the Y-Coordinate
+;     DE points to the sprite
+;     H is the height
+;     L is the width     ;not added yet
+;     (gbuf_temp) is the buffer to which to draw
+  ld l,a
+;First check if the sprite is on-screen in the horizontal direction
+  ld a,c
+  cp 64
+  jr c,+_
+  add a,h
+  ret nc
+  ld h,a
+  xor a
+  sub c
+  add a,e
+  ld e,a
+  jr nc,$+3
+  inc d
+  xor a
+  ld c,a
+_:
+;Next check h+c<=64
+  ld a,64
+  sub c
+  cp h
+  jr nc,+_
+  ld h,a
+_:
+;Next check if the sprite is on-screen in the vertical direction
+  ld a,b
+  cp 96
+  jr c,+_
+  add a,8
+  ret nc
+  ld a,b
+_:
+;Now we need to get the left part of the mask
+  ld a,h
+  or a
+  ret z
+  ld (spritetmp),hl   ;height
+  ld (spritetmp+2),de   ;sprite pointer
+  ld (spritetmp+4),bc   ;x,y
+  ld a,b
+  and 7
+  ld de,spritemask
+  add a,e
+  ld e,a
+#if spritemask&255>248
+  jr nc,$+3
+  inc d
+#endif
+  ld a,(de)
+  ld (sprite_mask0),a
+  cpl
+  ld (sprite_mask1),a
+;
+;
+  ld a,c
+  add a,a
+  sbc a,a
+  ld h,a
+  ld a,b
+  ld b,h
+  ld l,c
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  ld c,a
+  add a,a
+  sbc a,a
+  ld b,a
+  ld a,c
+  sra c
+  sra c
+  sra c
+  add hl,bc
+  ld bc,(gbuf_temp)
+  add hl,bc
+;
+;
+  and 7
+  ld a,(spritetmp+1)
+  ld b,a
+  ;B is height
+  ld de,(spritetmp+2)
+  ld a,(spritetmp)
+  dec a
+  jp z,spriteloop_AND
+  dec a
+  jp z,spriteloop_XOR
+  dec a
+  jp z,spriteloop_OR
+  sub 2
+  jp z,spriteloop_Erase
+spriteloop_Overwrite:
+  push bc
+  push de
+  ld a,(de)
+  ld d,a
+  ld e,0
+  ld a,(spritetmp+5)
+  ld c,a
+  and 7
+  jr z,+_
+  ld b,a
+  ld a,e
+  srl d \ rra \ djnz $-3
+  ld e,a
+_:
+  ld a,c
+  add a,8
+  jr c,+_
+  ld c,a
+  ld a,(sprite_mask0)
+  and (hl)
+  or d
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  cp 96
+  jr nc,+_
+  ld a,(sprite_mask1)
+  and (hl)
+  or e
+  ld (hl),a
+_:
+  ld de,11
+  add hl,de
+  pop de
+  inc de
+  pop bc
+  djnz spriteloop_Overwrite
+  ret
+spriteloop_OR:
+  push bc
+  push de
+  ld a,(de)
+  ld d,a
+  ld e,0
+  ld a,(spritetmp+5)
+  ld c,a
+  and 7
+  jr z,+_
+  ld b,a
+  ld a,e
+  srl d \ rra \ djnz $-3
+  ld e,a
+_:
+  ld a,c
+  add a,8
+  jr c,+_
+  ld c,a
+  ld a,(hl)
+  or d
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  cp 96
+  jr nc,+_
+  ld a,(sprite_mask1)
+  ld a,(hl)
+  or e
+  ld (hl),a
+_:
+  ld de,11
+  add hl,de
+  pop de
+  inc de
+  pop bc
+  djnz spriteloop_OR
+  ret
+spriteloop_XOR:
+  push bc
+  push de
+  ld a,(de)
+  ld d,a
+  ld e,0
+  ld a,(spritetmp+5)
+  ld c,a
+  and 7
+  jr z,+_
+  ld b,a
+  ld a,e
+  srl d \ rra \ djnz $-3
+  ld e,a
+_:
+  ld a,c
+  add a,8
+  jr c,+_
+  ld c,a
+  ld a,(hl)
+  xor d
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  cp 96
+  jr nc,+_
+  ld a,(sprite_mask1)
+  ld a,(hl)
+  xor e
+  ld (hl),a
+_:
+  ld de,11
+  add hl,de
+  pop de
+  inc de
+  pop bc
+  djnz spriteloop_XOR
+  ret
+spriteloop_AND:
+  push bc
+  push de
+  ld a,(de)
+  ld d,a
+  ld e,-1
+  ld a,(spritetmp+5)
+  ld c,a
+  and 7
+  jr z,+_
+  ld b,a
+  ld a,e
+  scf
+  rr d \ rra \ djnz $-3
+  ld e,a
+_:
+  ld a,c
+  add a,8
+  jr c,+_
+  ld c,a
+  ld a,(hl)
+  and d
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  cp 96
+  jr nc,+_
+  ld a,(sprite_mask1)
+  ld a,(hl)
+  and e
+  ld (hl),a
+_:
+  ld de,11
+  add hl,de
+  pop de
+  inc de
+  pop bc
+  djnz spriteloop_AND
+  ret
+spriteloop_Erase:
+  push bc
+  push de
+  ld a,(de)
+  cpl
+  ld d,a
+  ld e,-1
+  ld a,(spritetmp+5)
+  ld c,a
+  and 7
+  jr z,+_
+  ld b,a
+  ld a,e
+  scf
+  rr d \ rra \ djnz $-3
+  ld e,a
+_:
+  ld a,c
+  add a,8
+  jr c,+_
+  ld c,a
+  ld a,(hl)
+  and d
+  ld (hl),a
+  ld a,c
+_:
+  inc hl
+  cp 96
+  jr nc,+_
+  ld a,(hl)
+  and e
+  ld (hl),a
+_:
+  ld de,11
+  add hl,de
+  pop de
+  inc de
+  pop bc
+  djnz spriteloop_Erase
+  ret
+spritemask:
+  .db $00,$80,$C0,$E0,$F0,$F8,$FC,$FE
+#undefine spritetmp
+#undefine sprite_mask0
+#undefine sprite_mask1

+ 460 - 0
src/gfx/text.z80

@@ -0,0 +1,460 @@
+;===============================================================
+PutSM:
+;===============================================================
+;Inputs:
+;     hl points to the string to display
+;     bc is the size of the string
+;===============================================================
+  ld a,b \ or c \ ret z
+_:
+  push bc
+  push hl
+  ld a,(hl)
+  call PutSC
+  pop hl
+  pop bc
+  cpi
+  jp pe,-_
+  ret
+
+GPutSS:
+  ld (textRow),bc
+  jr GPutS
+
+_:
+  push hl
+  call PutSC
+  pop hl
+GPutS:
+  ld a,(hl)
+  inc hl
+  or a
+  jr nz,-_
+  ret
+
+PutSC:
+;Inputs:
+;     a is the char to draw
+;     (textRow) is the pixel row to draw at
+;     (textCol) is the text column to draw at (0 to 23)
+;===============================================================
+  call +_
+typewriter_delay:
+  bit SlowTextFlag,(iy+InternalFlag)
+  ret z
+  push af
+  push hl
+  call GraphToLCD
+  pop hl
+  ld a,(TextPauseTime)
+  ei
+  halt
+  dec a
+  jr nz,$-2
+  di
+  pop af
+  ret
+_:
+  ld bc,(textmode)
+  ld b,0
+  ld hl,putc_LUT
+  add hl,bc
+  add hl,bc
+  ld e,(hl)
+  inc hl
+  ld d,(hl)
+  ex de,hl
+  jp (hl)
+putc_LUT:
+  .dw PutFS
+  .dw VPutC
+  .dw VPutSC
+  .dw OmniCalcFont
+  .dw VPutC_OS_small
+  .dw VPutC_OS_large
+
+PutFS:
+  push af
+  ld bc,(textRow)
+  ld a,b
+  cp 24
+  ld a,c
+  jr c,+_
+  ld b,0
+  add a,6
+_:
+  cp 3Bh
+  jr c,+_
+  sub 3Ch
+  jr nc,+_
+  add a,6
+_:
+  ld c,a
+  inc b
+  ld (textRow),bc
+  dec b
+  ld hl,(FontPointer)
+  pop af
+  push bc
+  ld b,0
+  ld c,a
+  add hl,bc
+  add hl,bc
+  adc hl,bc
+  jp p,+_
+  ld a,h
+  add a,-$40
+  ld h,a
+_:
+  ld a,(font_ptr_page)
+  ld bc,3
+  adc a,b
+  ld de,$8005
+  call readarc
+  pop bc
+  ld a,b
+  ld b,0
+  ld h,b
+  ld l,c
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  rra
+  push af
+  ld c,a
+  add hl,bc
+  ld bc,(gbuf_temp)
+  add hl,bc
+  ld bc,060Ch
+  pop af
+  ld de,$8005
+  jr c,PutRight
+;===============================================================
+PutLeft:
+;===============================================================
+  ld a,(hl)
+  and 15
+  ld (hl),a
+  ld a,(de)
+  bit InvertTextFlag,(iy+UserFlags)
+  jr z,+_
+  cpl
+_:
+  bit 0,b
+  jr z,+_
+  rlca \ rlca \ rlca \ rlca
+  inc de
+_:
+  and $F0
+  or (hl)
+  ld (hl),a
+  ld a,b
+  ld b,0
+  add hl,bc
+  ld b,a
+  djnz PutLeft
+  ret
+;===============================================================
+PutRight:
+;===============================================================
+  ld a,(hl)
+  and $F0
+  ld (hl),a
+  ld a,(de)
+  bit InvertTextFlag,(iy+UserFlags)
+  jr z,+_
+  cpl
+_:
+  bit 0,b
+  jr nz,+_
+  rlca \ rlca \ rlca \ rlca
+  dec de
+_:
+  inc de
+  and 15
+  or (hl)
+  ld (hl),a
+  ld a,b
+  ld b,0
+  add hl,bc
+  ld b,a
+  djnz PutRight
+  ret
+OmniCalcFont:
+;Inputs:
+;    A is the char to draw
+  ld l,a
+  ld h,0
+  ld b,h
+  ld c,l
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,bc
+  ld bc,(FontPointer)
+  adc hl,bc
+  jp p,+_
+  ld a,h
+  add a,-$40
+  ld h,a
+_:
+  ld a,(font_ptr_page)
+  ld bc,7
+  adc a,b
+  ld de,$8005
+  call readarc
+  ld de,$8005
+  ld b,7
+_:
+  ld a,(hl)
+  rlca
+  rlca
+  rlca
+  ld (de),a
+  inc e
+  inc hl
+  djnz -_
+  ld de,$8005
+  ld hl,0706h
+  jr VputSCStepIn
+VPutSC:
+;Inputs:
+;    A is the char to draw
+  ld hl,(FontPointer)
+  ld c,a
+  ld b,0
+  add hl,bc
+  add hl,bc
+  adc hl,bc ;*3
+  jp p,+_
+  ld a,h
+  add a,-$40
+  ld h,a
+_:
+  ld a,(font_ptr_page)
+  ld bc,3
+  adc a,b
+  ld de,$8005+6
+  call readarc
+  ld hl,$8005+6
+  ld de,$8005
+  ld b,3  ;3*2 Nibbles
+_:
+  ld a,(hl)
+  and $F0
+  ld (de),a
+  inc e
+  ld a,(hl)
+  rrca \ rrca
+  rrca \ rrca
+  and $F0
+  ld (de),a
+  inc e
+  inc hl
+  djnz -_
+  ld de,$8005
+  ld hl,0604h
+  jr VputSCStepIn
+VPutC:
+;Inputs:
+;    A is the char to draw
+  ld hl,(FontPointer)
+
+;The first byte is the height of the font
+  ld e,(hl)
+  inc hl
+  ld d,0
+
+#ifdef INDEX_VFONT
+  sub 32
+  jr c,+_
+  ld b,a
+  ld hl,(vfont_index)
+  sub 16
+  jr c,+_
+  ld b,a
+  ld hl,(vfont_index+2)
+  sub 16
+  jr c,+_
+  ld b,a
+  ld hl,(vfont_index+4)
+  sub 32
+  jr c,+_
+  ld b,a
+  ld hl,(vfont_index+6)
+_:
+  inc b
+  call lookupchar_vfont
+#else
+  ;E is the height, assume non-zero
+  ;HL points to the font data
+  ;B is the char
+  ld b,a
+  inc b
+  jr vputc_loc_loop_end
+vputc_loc_loop:
+  ld a,(hl)
+  inc hl
+  dec a
+  jp m,vputc_loc_loop_end
+_:
+  add hl,de
+  sub 8
+  jr nc,-_
+vputc_loc_loop_end:
+  djnz vputc_loc_loop
+#endif
+  ld d,e
+  ld e,(hl)
+  inc hl
+  ex de,hl
+VputSCStepIn:
+  bit InvertTextFlag,(iy+UserFlags)
+  jr z,VputSCStepIn_postinvert
+  ;need to invert the text data
+  ;DE points to the sprite
+  ;H is height
+  ;L is width
+  push hl
+
+  ld b,h
+  ;get the mask to invert with
+  ld a,l
+  ld hl,spritemask
+  add a,l
+  ld l,a
+  jr nc,+_
+  inc h
+_:
+  ld c,(hl)
+  ld hl,$8005
+_:
+  ld a,(de)
+  xor c
+  ld (hl),a
+  inc hl
+  inc de
+  djnz -_
+  ld de,$8005
+  pop hl
+VputSCStepIn_postinvert:
+  push hl
+  call upd_text_coord
+  pop hl
+  ld a,7
+  add a,l
+  and %11111000
+  ret z
+  rra
+  rra
+  rra
+  ld l,a
+  ld a,(OutputLogic)
+  jp sprite
+
+upd_text_coord:
+  ld bc,(TextRow)
+  ld a,b \ add a,l
+  cp 97
+  jr c,+_
+  ;We need to increment if font is variable-width or OS large font style
+  ;I unintentionally organized the fonts so that odd-numbered fonts need an inc
+  ld a,(textmode)
+  rra
+  ld a,c
+  adc a,h \ ld c,a
+  ld a,l \ ld b,0
+_:
+  ld l,a
+  ld a,c
+  cp 58
+  jr c,+_
+  xor a
+  ld c,a
+_:
+  ld h,l
+  ld l,a
+  ld (TextRow),hl
+  ret
+VPutC_OS_large:
+  sub 1
+  jr c,+_
+  ld b,a
+  ld a,$7F
+  call OS_font_sub
+  inc l
+  inc h
+  jp VputSCStepIn
+_:
+  ld hl,$0700
+  ret
+
+VPutC_OS_small:
+  or a
+  jr z,+_
+  ld b,a
+  ld a,3
+  call OS_font_sub
+  jp VputSCStepIn
+_:
+  ld hl,$0600
+  ret
+
+
+vput_space:
+  call chardim
+  ld h,c
+  ld l,b
+  push bc
+  call upd_text_coord
+  ;C is y
+  ld e,b  ;x
+  pop hl
+  ld d,h  ;width
+  ld b,l  ;height
+
+; If using text mode 0, need to multiply x by 4
+  ld a,(textmode)
+  or a
+  jr nz,+_
+  sla e
+  sla e
+_:
+
+  ld hl,rect_wbwf
+  ld (next_page_call_address),hl
+  jp next_page_call
+
+OS_font_sub:
+  call os_char_ptr
+  ld de,lfont_record
+  ld bc,8
+  call readarc
+  ld hl,lFont_record
+  ld a,8
+  sub (hl)
+  ld c,a
+_:
+  ld hl,lFont_record+7
+  ld b,7
+  sla (hl)
+  dec hl
+  djnz $-3
+  dec c
+  jr nz,-_
+  ld e,(hl)
+  ex de,hl
+  inc de
+  ld h,6
+  ret
+
+os_char_ptr:
+  ld h,0
+  ld l,b
+  add hl,hl
+  add hl,hl
+  add hl,hl
+  ld bc,(FontPointer)
+  add hl,bc
+  ret

+ 877 - 0
src/gfx/tilemap.z80

@@ -0,0 +1,877 @@
+tilemap_new:
+  dec a
+  jp z,tilemap_init
+  ld hl,(parsePtr)
+  dec a
+  jp z,tilemap_fullrender
+  ld c,1
+  dec a
+  jr z,tmap_scroll_down
+  dec a
+  jr z,tmap_scroll_left
+  dec a
+  jr z,tmap_scroll_right
+  dec a
+  jr z,tmap_scroll_up
+  dec a
+  jr z,tmap_scroll
+  dec a
+  jp z,tmap_gettile
+  dec a
+  jp z,tmap_settile
+  dec a
+  jp z,tmap_gettile_pxl
+  jp p1_errbadtoken
+
+tmap_scroll_left:
+  ld a,(hl)
+  cp $2B
+  call z,p1_ParseNextFullArg
+  ld b,c
+tmap_scroll_left_loop:
+_:
+  push bc
+  call tilemap_scroll_left
+  pop bc
+  djnz -_
+  ret
+
+tmap_scroll_right:
+  ld a,(hl)
+  cp $2B
+  call z,p1_ParseNextFullArg
+  ld b,c
+tmap_scroll_right_loop:
+_:
+  push bc
+  call tilemap_scroll_right
+  pop bc
+  djnz -_
+  ret
+
+tmap_scroll_down:
+  ld a,(hl)
+  cp $2B
+  call z,p1_ParseNextFullArg
+  ld b,c
+tmap_scroll_down_loop:
+_:
+  push bc
+  call tilemap_scroll_down
+  pop bc
+  djnz -_
+  ret
+
+tmap_scroll_up:
+  ld a,(hl)
+  cp $2B
+  call z,p1_ParseNextFullArg
+  ld b,c
+tmap_scroll_up_loop:
+_:
+  push bc
+  call tilemap_scroll_up
+  pop bc
+  djnz -_
+  ret
+
+tmap_scroll:
+  call p1_ParseNextFullArg
+  cp $2B
+  ld a,c
+  push af
+  ld c,1
+  call z,p1_ParseNextFullArg
+  pop af
+  ld b,c
+
+  rrca
+  push af
+  push bc
+  call c,tmap_scroll_down_loop
+  pop bc
+  pop af
+
+  rrca
+  push af
+  push bc
+  call c,tmap_scroll_left_loop
+  pop bc
+  pop af
+
+  rrca
+  push af
+  push bc
+  call c,tmap_scroll_right_loop
+  pop bc
+  pop af
+
+  rrca
+  ret nc
+  jp tmap_scroll_up_loop
+
+tmap_gettile_pxl:
+  call p1_ParseNextFullArg
+  ld a,(tilemap_sy)
+  add a,c
+  and %11111000
+  rrca
+  rrca
+  rrca
+  ld c,a
+  ld a,(tilemap_y)
+  add a,c
+  ld c,a
+  push bc
+  call p1_ParseNextFullArg
+  ld a,(tilemap_sx_mask)
+  .db $FE
+_:
+  inc c
+  add a,a
+  jr nc,-_
+  ld a,c
+  and %11111000
+  rrca
+  rrca
+  rrca
+  ld c,a
+  ld a,(tilemap_x)
+  add a,c
+  pop de
+  ld c,a
+  jr +_
+tmap_gettile:
+; This gets the tile number based on the map coordinates
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  pop de
+_:
+  ld b,0
+  ld hl,(tilemap_height)
+  ld a,e
+  cp l
+  jr nc,setC_to_B
+  ld a,d
+  cp h
+  jr nc,setC_to_B
+  ;need tilemap_base+width*e+c
+  ld hl,(tilemap_base)
+  ld b,0
+  add hl,bc
+  ld d,b
+  ld a,(tilemap_width)
+  ld b,a
+  or a
+  jr z,+_
+  add hl,de
+  djnz $-1
+_:
+  ld c,(hl)
+  ld b,d
+  ret
+setC_to_B:
+  ld c,b
+  ret
+tmap_settile:
+  call p1_ParseNextFullArg
+  push bc
+  call p1_ParseNextFullArg
+  pop de
+  ;need tilemap_base+width*e+c
+  ld b,0
+  ld hl,(tilemap_height)
+  ld a,e
+  cp l
+  jr nc,parse_return_0
+  ld a,d
+  cp h
+  jr nc,parse_return_0
+
+  ld hl,(tilemap_base)
+  add hl,bc
+  ld d,b
+  ld a,(tilemap_width)
+  ld b,a
+  or a
+  jr z,+_
+  add hl,de
+  djnz $-1
+_:
+  push hl
+  call p1_ParseNextFullArg
+  pop hl
+  ld a,(hl)
+  ld (hl),c
+  ld c,a
+  ld b,0
+  ret
+parse_return_0:
+  call p1_ParseNextFullArg
+  ld bc,0
+  ret
+
+tilemap_init:
+;Use this routine to initialize a tilemap
+;   (tilemap_base) points to the tilemap base
+;   (tilemap_height) is the height
+;   (tilemap_width) is the width
+;   (sprite_select) points to the routine for selecting the sprite
+;   (tilemap_buf) points to the buffer to draw on
+;   tilemap_flags
+;Need to set
+;   (tilemap_sy) is the y-offset into the sprite
+;   (tilemap_y) is the y-offset into the tilemap
+;   (tilemap_sx_mask) is the column mask for the sprite
+;   (tilemap_x) is the x-offset into the tilemap
+;   (tilemap_top) is the pointer to the upper-left tile in view
+;   (tilemap_bottom) is the pointer to the bottom-left incoming row
+
+  call p1_ParseNextFullArg
+  ld (tilemap_base),bc
+  call p1_ParseNextFullArg
+  ld (spritesheet_ptr),bc
+  call p1_ParseNextFullArg
+  ld a,c
+  ld (tilemap_height),a
+  call p1_ParseNextFullArg
+  cp $2B
+  ld a,c
+  ld (tilemap_width),a
+  ld bc,(bufptr)
+  call z,p1_ParseNextFullArg
+  ld (tilemap_buf),bc
+
+  ld hl,sprite_selector
+  ld (sprite_select),hl
+  xor a
+  ld (tilemap_flags),a
+
+;now generate the rest
+  ld hl,0
+  ld b,h    ;for later
+  ld (tilemap_sy),hl
+  ld l,$80
+  ld (tilemap_sx_mask),hl
+  ld hl,(tilemap_base)
+  ld (tilemap_top),hl
+  ld a,(tilemap_width)
+  add a,a \ rl b
+  add a,a \ rl b
+  add a,a \ rl b
+  ld c,a
+  add hl,bc
+  ld (tilemap_bottom),hl
+  ret
+
+tilemap_fullrender:
+;Inputs:
+;   (D,E) is the offset into the map
+;Set:
+;   (tilemap_sx_mask) is the column mask for the sprite
+;   (tilemap_x) is the x-offset into the tilemap
+;   (tilemap_sy) is the x-offset into the sprite
+;   (tilemap_y) is the y-offset into the tilemap
+;   (tilemap_top) is the pointer to the upper-left tile in view
+;   (tilemap_bottom) is the pointer to the bottom-left incoming row
+
+  ld a,(hl)
+  cp $2B
+  ld c,0
+  call z,p1_ParseNextFullArg
+  push bc
+  cp $2B
+  ld c,0
+  call z,p1_ParseNextFullArg
+  pop de
+
+
+  ld a,e
+  ld (tilemap_y),a
+  ld a,c
+  ld (tilemap_x),a
+  xor a
+  ld d,a  ;for later
+  ld b,a  ; for later
+
+  ld (tilemap_sy),a
+  ld a,$80
+  ld (tilemap_sx_mask),a
+
+
+  ld hl,(tilemap_base)
+  ;top is x+y*w
+  add hl,bc
+  ld a,(tilemap_width)
+  or a
+  jr nc,+_
+  ld b,a
+  add hl,de
+  djnz $-1
+_:
+  ld (tilemap_top),hl
+  ld a,(tilemap_width)
+  ;now add width*8 to HL for tilemap_bottom
+  ld e,a
+  add a,a \ rl d
+  add a,a \ rl d
+  add a,a \ rl d
+  ld e,a
+  add hl,de
+  ld (tilemap_bottom),hl
+
+;Now we need to actually draw the tilemap
+;I'm going to do this the slow and easy way
+  ld hl,(tilemap_top)
+  ld de,(tilemap_buf)
+  ld ix,(sprite_select)
+  ld c,0
+tilemap_y_loop:
+  ld b,0
+  push hl
+tilemap_x_loop:
+  push hl
+  push bc
+  push de
+  ld a,(hl)
+  call tilemap_getsprite_at_BC
+  pop hl
+  push hl
+  ;at HL, draw the tile from DE
+  ld bc,12
+  ld a,8
+_:
+  ex de,hl
+  ldi
+  ex de,hl
+  add hl,bc
+  inc c
+  dec a
+  jr nz,-_
+
+  pop de
+  inc de
+  pop bc
+  pop hl
+  inc hl
+  inc b
+  ld a,b
+  cp 12
+  jr nz,tilemap_x_loop
+  ld hl,7*12
+  add hl,de
+  ex de,hl
+  pop hl
+  ;need to add width to HL
+  ld a,(tilemap_width)
+  add a,l
+  ld l,a
+  jr nc,$+3
+  inc h
+  inc c
+  bit 3,c
+  jr z,tilemap_y_loop
+  ret
+
+tilemap_scroll_left:
+  ld ix,(sprite_select)
+
+  ld hl,(tilemap_top)
+  ld bc,12
+  add hl,bc
+  ld (tempword2),hl ;tilemap pointer
+
+  ld a,(tilemap_x)
+  add a,12
+  ld b,a
+  ld a,(tilemap_y)
+  ld c,a
+  ld (tempword3),bc ;tilemap (x,y)
+
+  ld a,(hl)
+  call tilemap_getsprite
+  ;DE points to the sprite data
+
+  ld hl,(tilemap_buf)
+  ld bc,11
+  add hl,bc
+
+  ld a,(tilemap_sy)
+  cpl
+  and 7
+  inc a
+  ld b,a
+
+  ld a,(tilemap_sy)
+  add a,e
+  ld e,a
+  jr nc,$+3
+  inc d
+  ld a,(tilemap_sx_mask)
+  ld c,a
+tilemap_scroll_left_loop0:
+  push bc
+  ld a,(de)
+  inc de
+  and c
+  add a,255
+  ld b,12
+_:
+  rl (hl)
+  dec hl
+  djnz -_
+  ld c,24
+  add hl,bc
+  pop bc
+  djnz tilemap_scroll_left_loop0
+
+  ld b,7
+tilemap_scroll_left_loop1:
+  ld a,(tempword3)
+  inc a
+  ld (tempword3),a
+  push bc
+  push hl
+  ld hl,(tempword2)
+  ld a,(tilemap_width)
+  ld c,a
+  ld b,0
+  add hl,bc
+  ld (tempword2),hl
+  ld a,(hl)
+  call tilemap_getsprite
+  pop hl
+  ld b,8
+  ld a,(tilemap_sx_mask)
+  ld c,a
+tilemap_scroll_left_loop2:
+  push bc
+  ld a,(de)
+  inc de
+  and c
+  add a,255
+  ld b,12
+_:
+  rl (hl)
+  dec hl
+  djnz -_
+  ld c,24
+  add hl,bc
+  pop bc
+  djnz tilemap_scroll_left_loop2
+  pop bc
+  djnz tilemap_scroll_left_loop1
+
+  ld a,(tempword3)
+  inc a
+  ld (tempword3),a
+
+
+;final iteration
+  push hl
+  ld hl,(tempword2)
+  ld a,(tilemap_width)
+  ld c,a
+  ld b,0
+  add hl,bc
+  ld (tempword2),hl
+  ld a,(hl)
+  call tilemap_getsprite
+  pop hl
+
+  ld a,(tilemap_sy)
+  or a
+  jr z,tilemap_scroll_left_end
+  ld b,a
+
+  ld a,(tilemap_sx_mask)
+  ld c,a
+tilemap_scroll_left_loop3:
+  push bc
+  ld a,(de)
+  inc de
+  and c
+  add a,255
+  ld b,12
+_:
+  rl (hl)
+  dec hl
+  djnz -_
+  ld c,24
+  add hl,bc
+  pop bc
+  djnz tilemap_scroll_left_loop3
+
+tilemap_scroll_left_end:
+  ld hl,tilemap_sx_mask
+  rrc (hl)
+  ret nc
+  inc hl
+  inc (hl)    ;tilemap_x
+  ld hl,(tilemap_top)
+  inc hl
+  ld (tilemap_top),hl
+  ld hl,(tilemap_bottom)
+  inc hl
+  ld (tilemap_bottom),hl
+  ret
+
+
+tilemap_scroll_right:
+  ld ix,(sprite_select)
+
+  ld hl,tilemap_sx_mask
+  rlc (hl)
+  jr nc,+_
+  inc hl
+  dec (hl)    ;tilemap_x
+  ld hl,(tilemap_bottom)
+  dec hl
+  ld (tilemap_bottom),hl
+  ld hl,(tilemap_top)
+  dec hl
+  ld (tilemap_top),hl
+_:
+
+  ld hl,(tilemap_top)
+  ld (tempword2),hl ;tilemap pointer
+
+  ld a,(tilemap_x)
+  ld b,a
+  ld a,(tilemap_y)
+  ld c,a
+  ld (tempword3),bc ;tilemap (x,y)
+
+  ld a,(hl)
+  call tilemap_getsprite
+  ;DE points to the sprite data
+
+  ld hl,(tilemap_buf)
+
+  ld a,(tilemap_sy)
+  cpl
+  and 7
+  inc a
+  ld b,a
+
+  ld a,(tilemap_sy)
+  add a,e
+  ld e,a
+  jr nc,$+3
+  inc d
+  ld a,(tilemap_sx_mask)
+  ld c,a
+tilemap_scroll_right_loop0:
+  push bc
+  ld a,(de)
+  inc de
+  and c
+  add a,255
+  ld b,12
+_:
+  rr (hl)
+  inc hl
+  djnz -_
+  pop bc
+  djnz tilemap_scroll_right_loop0
+
+
+  ld b,7
+tilemap_scroll_right_loop1:
+  ld a,(tempword3)
+  inc a
+  ld (tempword3),a
+  push bc
+  push hl
+  ld hl,(tempword2)
+  ld a,(tilemap_width)
+  add a,l
+  ld l,a
+  jr nc,$+3
+  inc h
+  ld (tempword2),hl
+  ld a,(hl)
+  call tilemap_getsprite
+  pop hl
+  ld b,8
+  ld a,(tilemap_sx_mask)
+  ld c,a
+tilemap_scroll_right_loop2:
+  push bc
+  ld a,(de)
+  inc de
+  and c
+  add a,255
+  ld b,12
+_:
+  rr (hl)
+  inc hl
+  djnz -_
+  pop bc
+  djnz tilemap_scroll_right_loop2
+  pop bc
+  djnz tilemap_scroll_right_loop1
+
+
+  ld a,(tempword3)
+  inc a
+  ld (tempword3),a
+
+;final iteration
+  push hl
+  ld hl,(tempword2)
+  ld a,(tilemap_width)
+  add a,l
+  ld l,a
+  jr nc,$+3
+  inc h
+  ld (tempword2),hl
+  ld a,(hl)
+  call tilemap_getsprite
+  pop hl
+
+  ld a,(tilemap_sy)
+  or a
+  ret z
+  ld b,a
+
+  ld a,(tilemap_sx_mask)
+  ld c,a
+tilemap_scroll_right_loop3:
+  push bc
+  ld a,(de)
+  inc de
+  and c
+  add a,255
+  ld b,12
+_:
+  rr (hl)
+  inc hl
+  djnz -_
+  pop bc
+  djnz tilemap_scroll_right_loop3
+  ret
+
+
+tilemap_scroll_up:
+  ld ix,(sprite_select)
+  ld a,(tilemap_x)
+  ld h,a
+  ld a,(tilemap_y)
+  add a,8
+  ld l,a
+  ld (tempword3),hl ;tilemap (x,y)
+
+  ld de,(tilemap_buf)
+  ld hl,12
+  add hl,de
+  ld bc,756
+  ldir
+
+;Now we need to populate the row of pixels
+;first right the sprite data as if it is supposed to be aligned
+  ld hl,(tilemap_bottom)
+  ld b,12
+;DE points to where to write the sprite data
+;HL points to the tile
+;B is the number of tiles to read
+tilemap_scroll_up_loop_0:
+  push bc
+  push hl
+  push de
+  ld a,(hl)
+  call tilemap_getsprite
+  ld a,(tilemap_sy)
+  add a,e
+  ld e,a
+  jr nc,$+3
+  inc d
+  ld a,(de)
+  pop de
+  ld (de),a
+  inc de
+  pop hl
+  inc hl
+  ld a,(tempword3+1)
+  inc a
+  ld (tempword3+1),a
+  pop bc
+  djnz tilemap_scroll_up_loop_0
+
+;now we need to shift the row left, shifting in the bits from the next tile
+  push de
+  ld a,(hl)
+  call tilemap_getsprite
+  ld a,(tilemap_sy)
+  add a,e
+  ld e,a
+  jr nc,$+3
+  inc d
+  ld a,(de)
+  pop hl
+  ld c,a
+  ld a,(tilemap_sx_mask)
+;need to shift in C until A is $80
+  ld de,12
+  jr tilemap_scroll_up_loop_1_start
+tilemap_scroll_up_loop_1:
+  ld b,e
+  rlc c
+_:
+  dec hl
+  rl (hl)
+  djnz -_
+  add hl,de
+tilemap_scroll_up_loop_1_start:
+  add a,a
+  jr nc,tilemap_scroll_up_loop_1
+
+  ld a,(tilemap_sy)
+  inc a
+  and 7
+  ld (tilemap_sy),a
+  ret nz
+  ld a,(tilemap_y)
+  inc a
+  ld (tilemap_y),a
+
+  ld a,(tilemap_width)
+  ld c,a
+  ld b,0
+  ld hl,(tilemap_top)
+  add hl,bc
+  ld (tilemap_top),hl
+  ld hl,(tilemap_bottom)
+  add hl,bc
+  ld (tilemap_bottom),hl
+
+  ret
+
+tilemap_scroll_down:
+  ld ix,(sprite_select)
+  ld a,(tilemap_x)
+  ld h,a
+  ld a,(tilemap_y)
+  ld l,a
+  ld (tempword3),hl ;tilemap (x,y)
+
+  ld de,(tilemap_buf)
+  inc d
+  inc d
+  inc d
+  dec de
+
+  ld hl,-12
+  add hl,de
+  ld bc,756
+  lddr
+
+  ld a,(tilemap_sy)
+  dec a
+  ld (tilemap_sy),a
+  jp p,+_
+  and 7
+  ld (tilemap_sy),a
+  ld a,(tilemap_y)
+  dec a
+  ld (tilemap_y),a
+  ld (tempword3),a
+  ld a,(tilemap_width)
+  neg
+  ld c,a
+  ld b,-1
+  ld hl,(tilemap_top)
+  add hl,bc
+  ld (tilemap_top),hl
+  ld hl,(tilemap_bottom)
+  add hl,bc
+  ld (tilemap_bottom),hl
+_:
+
+;Now we need to populate the row of pixels
+;first right the sprite data as if it is supposed to be aligned
+  ld de,(tilemap_buf)
+  ld hl,(tilemap_top)
+  ld b,12
+;DE points to where to write the sprite data
+;HL points to the tile
+;B is the number of tiles to read
+tilemap_scroll_down_loop_0:
+  push bc
+  push hl
+  push de
+  ld a,(hl)
+  call tilemap_getsprite
+  ld a,(tilemap_sy)
+  add a,e
+  ld e,a
+  jr nc,$+3
+  inc d
+  ld a,(de)
+  pop de
+  ld (de),a
+  inc de
+  pop hl
+  inc hl
+  ld a,(tempword3+1)
+  inc a
+  ld (tempword3+1),a
+  pop bc
+  djnz tilemap_scroll_down_loop_0
+
+;now we need to shift the row left, shifting in the bits from the next tile
+  push de
+  ld a,(hl)
+  call tilemap_getsprite
+  ld a,(tilemap_sy)
+  add a,e
+  ld e,a
+  jr nc,$+3
+  inc d
+  ld a,(de)
+  pop hl
+  ld c,a
+  ld a,(tilemap_sx_mask)
+;need to shift in C until A is $80
+  ld de,12
+  jr tilemap_scroll_down_loop_1_start
+tilemap_scroll_down_loop_1:
+  ld b,e
+  rlc c
+_:
+  dec hl
+  rl (hl)
+  djnz -_
+  add hl,de
+tilemap_scroll_down_loop_1_start:
+  add a,a
+  jr nc,tilemap_scroll_down_loop_1
+  ret
+
+tilemap_getsprite:
+  ld bc,(tempword3)
+tilemap_getsprite_at_BC:
+  ld hl,(tilemap_height)
+  jp (ix)
+
+sprite_selector:
+  ld e,a
+  ld a,b
+  cp h
+  jr nc,+_
+  ld a,c
+  cp l
+  ld a,e
+_:
+  ld de,(spritesheet_ptr)
+  ret nc
+
+  ld l,a
+  ld h,0
+  add hl,hl
+  add hl,hl
+  add hl,hl
+  add hl,de
+  ex de,hl
+  ret

+ 127 - 0
src/grammer.inc

@@ -0,0 +1,127 @@
+#define db .db
+#define callp(x) call call_previous_page \ .dw x
+#define calln(x) call call_next_page \ .dw x
+
+intmask         = %00001011
+invlogic        = 2
+gflags          = 33
+tok_NegRelPtr   = $EE
+
+
+TextPauseTime=appErr2+4       ;1
+StackCount  = TextPauseTime+1 ;2
+StackLoc    = StackCount+2    ;2
+OutputLogic = StackLoc+2      ;1
+ErrorLoc    = OutputLogic+1   ;2
+SPSave      = ErrorLoc+2      ;2
+
+parseError  = asm_data_ptr1   ;2
+PBufPtr     = 9311h           ;2
+
+
+IntLoc      = g_internal   ;2
+IntCount    = IntLoc+2     ;2  Counts down from IntMax, at zero, executes code at IntLoc, and resets to IntMax
+IntMax      = IntCount+2   ;2
+PBufType    = IntMax+2     ;1
+PBufRule    = PBufType+1   ;2
+GrayMask    = PBufRule+2   ;1
+graymode    = GrayMask+1   ;1
+textmode    = graymode+1   ;1
+ForBackUp   = textmode+1   ;2
+seed1       = ForBackUp+2  ;2
+seed2       = seed1+2      ;2
+k_save      = seed2+2
+k_count     = k_save+1
+k_delay     = k_count+1
+qmarkVar    = k_delay+1
+ddd         = qmarkVar+2   ;0
+
+VATPtr     = ddd        ; Used during the main menu
+VATPtr_next= VATPtr+2   ;
+main_menu_cursor    = VATPtr_next+2
+main_menu_cursor_max= main_menu_cursor+1
+main_menu_index     = main_menu_cursor_max+1
+mode_menu_header_RAM= main_menu_index+2
+mode_menu_scrap     = mode_menu_header_RAM+5
+
+vars        = ddd                 ;used while compiling
+vars_count  = vars+2              ;
+size_of_buffer = vars_count+2     ;
+start_of_prog = size_of_buffer+2  ;
+end_of_src  = start_of_prog+2     ;
+data_top    = end_of_src+2        ;
+end_of_buffer = data_top+2        ;
+buffer_top  = end_of_buffer+2     ;
+in_head     = buffer_top+2        ;
+out_head    = in_head+2           ;
+
+floatstack_ptr    = vars
+floatstack_bottom = vars+2
+floatstack_top    = vars+2+32     ;Give room for 8 floats. I am a generous god.
+seedsingle0 = floatstack_top
+seedsingle1 = seedsingle0+4
+
+stack_base  = seedsingle1+4
+stack_top   = stack_base+2
+stack_ptr   = stack_top+2
+
+input_base  = stack_ptr+2
+input_size  = input_base+2
+
+vfont_index = input_size+2    ;8 bytes
+
+
+module_count= vfont_index+8
+module0     = module_count+1
+module1     = module0+2
+module2     = module1+2
+module3     = module2+2
+module4     = module3+2
+
+buf_end     = module4+2
+buf_top     = buf_end+2
+
+;tilemap RAM
+tilemap_base    = buf_top+2
+tilemap_height  = tilemap_base+2
+tilemap_width   = tilemap_height+1
+sprite_select   = tilemap_width+1
+tilemap_buf     = sprite_select+2
+tilemap_sy      = tilemap_buf+2
+tilemap_y       = tilemap_sy+1
+tilemap_sx_mask = tilemap_y+1
+tilemap_x       = tilemap_sx_mask+1
+tilemap_top     = tilemap_x+2
+tilemap_bottom  = tilemap_top+2
+tilemap_flags   = tilemap_bottom+2
+spritesheet_ptr = tilemap_flags+2
+
+PBuf          = appBackupScreen
+SetLinePix    = ramCode
+TSA           = tempSwapArea
+interruptLoc  = 8A8Ah
+
+
+
+
+#define zlz_vars OP1
+#define ZLZ_MIN_RUN 4
+
+zlz_base      = zlz_vars
+zlz_runstart  = zlz_vars+2
+zlz_match_base= zlz_vars+4
+zlz_match_size= zlz_vars+6
+zlz_top       = zlz_vars+8
+zlz_match_loc = zlz_vars+10
+zlz_head      = zlz_vars+12
+
+zcomp_freq_table  = saveSScreen
+zcomp_keymap      = 8700h
+zcomp_vars        = OP1
+zcomp_input_base  = zcomp_vars
+zcomp_input_size  = zcomp_vars+2
+zcomp_partition_len=zcomp_input_size+2
+zcomp_table_len   = zcomp_partition_len+2
+zcomp_best_size   = zcomp_table_len+2
+zcomp_part0_size  = zcomp_best_size+3
+zcomp_part1_size  = zcomp_part0_size+2

+ 4499 - 0
src/grammer.z80

@@ -0,0 +1,4499 @@
+;Grammer
+;================:
+;\\     /\       :
+; \\   //\\      :
+;  \\ //  \\     :
+;   \\/----\\    :
+;   //\----//\   :
+;  // \\  // \\  :
+; //   \\//   \\ :
+;//     \/     \\:
+;================:
+;Project.........Grammer
+;Program.........Grammer
+;Author..........Zeda Thomas (Xeda112358 / ThunderBolt)
+;[email protected]
+;Size............
+;Language........English
+;Programming.....Assembly
+;Version.........v2.50          ;I rarely update this stuff
+;Last Update.....27 Nov 2019    ;This is not accurate, probably
+
+#define NO_JUMP_TABLE
+#include "grammer2.5.inc"
+#include "grammer.inc"
+
+#define Coord(y,x)     .db 01,y,x
+#define SHELL_BROKEN
+#define speed
+#define K_DELAY_DEFAULT 13
+#define K_DELAY_ACCEL 3
+#define ALIGN_COMMAND_TABLE      ;Comment this to potentially save some bytes, uncomment to save some clock cycles
+#define include_fire
+#define include_ncr
+;#define include_LoadTSA
+;#define include_interrupt
+#define INCLUDE_GRAMPKG
+#define INDEX_VFONT      ;Allows faster font access for key portions of the font
+
+.org $4000
+.db $80,$0F, 0,0,0,0
+.db $80,$12, $01,$04    ;signing key ID
+.db $80,$47, "Grammer" ;change the $47 according to name len.
+.db $80,$81, 2          ;num pages
+.db $80,$90             ;no splash
+.db $03,$22,$09,$00     ;date stamp
+.db $02,$00             ;date stamp signature
+.db $80,$70             ;final field
+
+     jp main
+jumptable:
+#include "jmptable.z80"
+SelectedProg:
+  bcall(_OP5ToOP1)
+;  ld de,OP1
+;  ld hl,OP5
+;  call mov9
+
+SelectedProgOP1:
+  ld hl,gbuf
+  ld (BufPtr),hl
+  bcall(_ChkFindSym)
+  ret c
+  ld hl,cmdShadow+2
+  ld a,$BB
+  cp (hl)
+  jr nz,+_
+  inc l
+  ld a,$6D
+  cp (hl)
+  jp z,EndHook_prepush
+_:
+  ld a,(TempWord3)
+  or a
+  jr z,ExecOP1
+;Here we need to move the code to RAM.
+;  We will perform some minor pre-compiling
+;  Currently it is just:
+;     Convert numbers to raw binary
+#include "precompile.z80"
+  jr ExecOP1
+ProgramAccessStart:
+  bcall(_RclAns)
+  sub 4
+  jr nz,grazh
+  ex de,hl
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+  ld de,OP1
+  ldir
+  ld (de),a
+ExecOP1:
+  ld hl,OP1
+  ld de,basic_prog
+  call mov9
+  bcall(_ChkFindSym)
+  ld a,b
+  ret c
+  or a \ ret nz
+  ex de,hl
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+parse_via_ptr:
+;HL points to code
+;BC is the size
+  ld (parsePtr),hl
+  ld (progStart),hl
+  add hl,bc
+  ld (progEnd),hl
+  ld h,a \ ld l,a
+  ld (parseError),hl
+grazh:
+#ifdef include_interrupt
+  di
+  ld a,11
+  out (3),a
+  ld a,6
+  out (4),a   ;set slowest hardware timer mode
+  ld a,41h
+  ld i,a
+  im 2
+  ei
+#endif
+  call SetUpData
+;  call progmeta
+  ld hl,BreakProgram
+  push hl
+ParserNext:
+  ld de,ParserNext
+  push de
+ParseArg:
+  bit IntActiveFlag,(iy+InternalFlag)
+  call z,parser_interrupt
+  bit OnBlockFlag,(iy+UserFlags)
+  call z,onbreak
+  ld hl,(parsePtr)
+ParseArg2:
+  ld a,(hl)
+  inc hl
+  ld (parsePtr),hl
+#ifdef ALIGN_COMMAND_TABLE
+  ld h,CommandJumpTable>>8
+  add a,a
+  ld l,a
+  jr nc,+_
+  inc h
+_:
+  rra
+  ld e,(hl)
+  inc l
+#else
+  ld e,a
+  ld hl,CommandJumpTable
+  ld d,0
+  add hl,de
+  add hl,de
+  ld e,(hl)
+  inc hl
+#endif
+  ld d,(hl)
+  push de
+  ld hl,(parsePtr)
+  ret
+OutputToken:
+  ld a,(hl)
+  cp 11
+  jr nz,+_
+  call ParseNextFullArg
+  ld a,c
+  ld (OutputLogic),a
+  ret
+_:
+  call ParseFullArg
+  ld hl,textmode
+  ld (hl),c
+  ld e,a
+  ld a,c
+#ifdef INDEX_VFONT
+  push af
+#endif
+  ld bc,FontSet
+  or a
+  jr z,+_
+  ld bc,vFont
+  dec a
+  jr z,+_
+  ld bc,FontSet
+  dec a
+  jr z,+_
+  dec a
+  ld c,a
+  ;this part is based on E37's fasttext routine
+  push de
+  ld a,(iy+hookflags3)               ;Need to disable font hooks flag while we
+  push af                            ;try to locate the font data, or we might
+  res fontHookActive,(iy+hookflags3) ;get a pointer to the custom font table.
+  dec c
+  call z,sfont_ptr
+  call nz,lfont_ptr
+  pop af
+  ld (iy+hookflags3),a
+  ld b,d
+  ld c,e
+  pop de
+_:
+  ld a,e
+  cp 2Bh
+  call z,ParseNextFullArg
+  ld (FontPointer),bc
+  ld c,0
+  cp $2B
+  call z,ParseNextFullArg
+  ld a,c
+  ld (font_ptr_page),a
+
+#ifdef INDEX_VFONT
+  pop af
+  dec a
+  ret nz
+  ;need to find chars 32, 48, 64, and 96
+
+  ld hl,(FontPointer)
+;HL points to the font
+;The first byte is the height of the font
+  ld e,(hl)
+  ld d,0
+  inc hl
+
+  ld b,33
+  call lookupchar_vfont
+  ld (vfont_index),hl
+  ld b,17
+  call lookupchar_vfont
+  ld (vfont_index+2),hl
+  ld b,17
+  call lookupchar_vfont
+  ld (vfont_index+4),hl
+  ld b,33
+  call lookupchar_vfont
+  ld (vfont_index+6),hl
+  ld bc,(FontPointer)
+  ret
+
+
+
+vputc_loc_loop:
+  ld a,(hl)
+  inc hl
+  dec a
+  jp m,vputc_loc_loop_end
+_:
+  add hl,de
+  sub 8
+  jr nc,-_
+vputc_loc_loop_end:
+lookupchar_vfont:
+;DE is the height
+;HL points to the font data
+;B is the char+1
+  djnz vputc_loc_loop
+
+#endif
+  ret
+
+sfont_ptr:
+  bcall(_SFont_Len)
+  xor a
+  ret
+lfont_ptr:
+  ld hl,$6D81
+  call is_start_lfont
+  ret z
+
+  ld hl,$7184
+  call is_start_lfont
+  ret z
+  jp err_fatal
+
+
+is_start_lfont:
+  push hl
+  ld de,lFont_record
+  ld a,$7F    ;bootcode
+  ld bc,3
+  call readarc
+  pop de
+  ld hl,lFont_record
+  ld a,(hl)
+  sub 5
+  ret nz
+  inc hl
+  or (hl)
+  ret nz
+  inc hl
+  or (hl)
+  ret
+
+NewLine:
+  ld hl,(BufPtr)
+  ld (gbuf_temp),hl
+  ld (Ans),bc
+IncPtr:
+_Ret:
+  ret
+
+augment:
+  call ParseFullArg
+  ld h,b \ ld l,c
+  bcall(_EnoughMem)
+  jp c,ErrMem
+  push de
+  call ParseNextFullArg
+  push bc
+  ld hl,(parsePtr)
+  inc hl
+  ld (parsePtr),hl
+  call GetVarInfo
+  jp c,Pop2Exit
+  or a \ jp nz,Pop2Exit
+  ld hl,(parsePtr)
+  ld (parsePtr),hl
+  ex de,hl
+  ld c,(hl) \ inc hl
+  ld b,(hl)
+  ld (TempWord1),hl
+  pop de \ pop hl
+InsertData:
+  push hl
+  add hl,bc
+  ld b,h \ ld c,l
+  ld hl,(TempWord1)
+  ld (hl),b \ dec hl
+  ld (hl),c \ inc hl \ inc hl
+  add hl,de
+  pop de
+;hl points to where to insert data
+;de is the number of bytes to insert
+  push de \ push hl
+  ld a,h \ or l
+  jr z,+_
+  ex de,hl
+  bcall(_InsertMem)
+_:
+  ld hl,(parsePtr)
+  ld (parsePtr),hl
+  pop hl \ pop bc
+  ld d,h \ ld e,l
+ZeroMem:
+  ld a,b \ or c \ ld a,0
+  push de
+  call nz,SetMem
+  pop bc
+  ret
+
+_:
+  ld hl,tilemap_new
+  ld (next_page_call_address),hl
+  jp next_page_call
+
+PtChange:
+  call ParseFullArg       ;To get the tilemap routine correct
+  ld a,c
+  or a
+  jr nz,-_
+  call ParseNextFullArg   ;Map Data
+  push bc
+  call ParseNextFullArg   ;Tile Data
+  push bc
+  call ParseNextFullArg   ;MapWidth
+  push bc
+  call ParseNextFullArg   ;MapX offset
+  ld (TempWord2),bc
+  call ParseNextFullArg   ;MapY offset
+  ld (TempWord3),bc
+  call ParseNextFullArg   ;Sprite Method
+  push bc
+
+
+  cp 2Bh
+  call z,ParseNextFullArg_Buffer
+  pop bc
+  ld a,c
+  pop hl
+  pop bc
+  pop de
+  jp TileMap1
+
+solveSet:
+  call ParseFullArg
+  ld a,c
+  sub 3
+  jr z,ErrorHandle
+  dec a
+  jr z,CallError
+  ld hl,solveSet_p1
+  ld (next_page_call_address),hl
+  jp next_page_call
+_:
+ErrorHandle:
+  call ParseNextFullArg
+  ld (ParseError),bc
+  ret
+CallError:
+  call ParseNextFullArg
+  ld a,c
+  cp 2
+  jr nz,HandleError
+  call ParseNextFullArg
+  ld h,b \ ld l,c
+  call GetGrammerText
+  ld hl,13
+  or a
+  sbc hl,bc
+  jr nc,+_
+CustomError:
+  ld bc,12
+_:
+  ex de,hl
+  ld de,appErr1
+  ldir
+  xor a
+  ld (de),a
+  ld a,2
+HandleError:
+  jp GramHandl
+
+DSToken:
+  ld a,(hl) \ inc hl
+  call VarP
+  ret nc
+  ld (parsePtr),de
+  ld e,(hl) \ inc hl \ ld d,(hl)
+  ld a,(de) \ ld c,a
+  dec de \ ld (hl),d \ dec hl \ ld (hl),e
+  ld b,0 \ ret
+
+ISToken:
+  ld a,(hl) \ inc hl
+  call VarP
+  ret nc
+  ld (parsePtr),de
+g_ReadByte:
+  ld e,(hl) \ inc (hl) \ inc hl \ ld d,(hl)
+  jr nz,+_
+  inc (hl)
+_:
+  ex de,hl
+  ld c,(hl)
+  ld b,0
+  dec de
+  ex de,hl
+  ret
+AnsToken:
+  ld bc,(Ans) \ ret
+seqToken:
+CopyHex:
+  ex de,hl
+  ld h,b \ ld l,c
+_:
+  call PutHexFromDE
+  jr z,+_
+  call PutHexFromDE
+  inc hl
+  jr nz,-_
+  dec hl
+  xor a
+  rld
+_:
+  ld (parsePtr),de
+  ld b,h \ ld c,l
+  ret
+PutHexFromDE:
+  inc de
+  ld a,(de)
+  cp 3Fh
+  ret z
+  cp 3Ah
+  jr c,+_
+  sub 7
+_:
+  rld
+  ret
+SetData:
+;[
+  ld a,(hl)
+  cp 16
+  jr z,CopyHex      ;[(
+  cp 6
+  jr z,+_           ;[[
+  dec hl
+  ld (parsePtr),hl
+  scf
+_:
+  sbc a,a
+  ld e,a
+  ld h,b \ ld l,c
+
+SetData_loop:
+  push hl
+  push de
+  call ParseNextFullArg
+  pop de
+  rlc e
+  jr nc,+_
+  dec hl
+  ld a,(hl)
+  cp 11
+  inc hl
+_:
+  ld a,(hl)
+  pop hl
+  ld (hl),c \ inc hl
+  jr nz,+_
+  ld (hl),b \ inc hl
+_:
+  cp 2Bh
+  jr z,SetData_loop
+  ld b,h
+  ld c,l
+  ret
+VarName:
+   ld e,a
+   ld d,(hl)
+   inc d
+   call GetNextVarNum
+   dec d
+   ld (parsePtr),hl
+   ld (OP1+1),de
+   xor a
+   ld (OP1+3),a
+   rst rFindSym
+   jp VarTokenStepIn
+FuncToken:
+  call ParseFullArg
+  ld (IntLoc),bc
+  ld bc,80h
+  cp 2Bh
+  call z,ParseNextFullArg
+  dec bc \ inc b \ inc c
+  ld (IntMax),bc
+  ld (IntCount),bc
+  ret
+SendToken:
+  ld a,(hl)
+  cp $AE
+  jr nz,NotSendByte
+;timer,byte
+;success or fail
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+  pop de
+#include "subroutines/sendbyte.z80"
+NotSendByte:
+  call ParseFullArg
+  push bc               ;Size of the var
+  inc hl \ ld (parsePtr),hl
+  call GetVarName
+  ex de,hl
+  ld de,OP1
+  ldir
+  xor a
+  ld (de),a
+  bcall(_ChkFindSym)
+  pop hl
+  jr nc,+_
+  ld a,(OP1)
+  and 1fh
+  bcall(_EnoughMem)
+  jp c,ErrMEM
+  ex de,hl
+  bcall(_CreateVar)
+  ex de,hl
+  ld a,b
+  or c
+  inc hl
+  inc hl
+  push hl
+  call nz,ZeroMem
+  pop bc
+  ret
+_:
+  inc de \ inc de
+  ld c,e \ ld b,d
+  ret
+FixToken:
+  ld a,(hl)
+  cp 93h
+  jr nz,SetMode
+  call ParseNextFullArg
+  ld a,c
+  ld (TextPauseTime),a
+  ret
+SetMode:
+  ld a,(flags+UserFlags)
+  ld b,0      ; not needed, per se, but nice for output
+  ld c,a
+  call ParseFullArg
+  ld a,c
+  ld (flags+UserFlags),a
+  ret
+
+FloatModeToggle:
+;Toggles float mode.
+;In float mode, operations default to float operations.
+  ld a,(flags+ModeFlags2)
+  xor 1<<floatmode
+  ld (flags+ModeFlags2),a
+  ret
+
+OSVarToken:
+  ld a,(hl)
+  inc hl
+  ld (parsePtr),hl
+  ld hl,0
+  ld (OP1+2),hl
+  ld (OP1+1),a
+  rst rFindSym
+  jr c,return_BC_0
+  ex de,hl
+  call convFloat
+  ld b,d \ ld c,e
+  ret
+return_BC_0:
+  ld bc,0
+  ret
+TangentToken:
+  call ParseFullArg
+  xor a \ ld b,a
+  or c
+  ret z
+  push bc
+  call ParseNextFullArg
+  ld a,c
+  pop bc
+  or a \ ret z
+  push af
+  push bc
+  ld a,(hl)
+  cp 2Bh
+  ld bc,(BufPtr)
+  call z,ParseNextFullArg
+  ld (TempWord1),bc
+  pop bc
+  pop af
+ShiftGraphBuf:
+  ld b,4
+  push bc
+  rrca
+  push af
+  ld a,c
+  call c,ShiftGraphDownA
+  pop af
+  pop bc
+  push bc
+  rrca
+  push af
+  ld a,c
+  call c,ShiftGraphLeftA
+  pop af
+  pop bc
+  push bc
+  rrca
+  push af
+  ld a,c
+  call c,ShiftGraphRightA
+  pop af
+  pop bc
+  rrca
+  ld a,c
+  ret nc
+ShiftGraphUpA:
+  ld e,a
+  ld l,a
+  ld h,0
+  ld d,h
+  add hl,hl
+  add hl,de
+  add hl,hl
+  add hl,hl
+  push hl
+  ld a,h
+  inc a
+  cpl
+  and 3
+  ld b,a
+  ld a,l
+  dec a
+  cpl
+  ld c,a
+  ld de,(TempWord1)
+  add hl,de
+  ldir
+  pop bc
+ZeroMemF:
+  xor a
+SetMemF:
+  ld (de),a
+  ld h,d \ ld l,e
+  inc de
+ReadRAM:
+  ldir
+  ret
+ShiftGraphRightA:
+  rrca
+  push af
+  call c,ShiftRight1
+  pop af
+  rrca
+  push af
+  call c,ShiftRight2
+  pop af
+  rrca
+  push af
+  call c,ShiftRight4
+  pop af
+  rrca
+  push af
+  call c,ShiftRight8
+  pop af
+  rrca
+  push af
+  call c,ShiftRight16
+  pop af
+  rrca
+  push af
+  call c,ShiftRight32
+  pop af
+  rrca
+  ret nc
+ShiftRight64:
+  ld hl,(TempWord1)
+  ld a,l
+  sub 9
+  jr nc,+_
+  dec h
+_:
+  ld l,a
+  ld a,4
+  jr ShiftRight8OrMore
+ShiftRight32:
+  ld hl,(TempWord1)
+  ld a,l
+  sub 5
+  jr nc,+_
+  dec h
+_:
+  ld l,a
+  ld a,8
+  jr ShiftRight8OrMore
+ShiftRight16:
+  ld hl,(TempWord1)
+  dec hl \ dec hl \ dec hl
+  ld a,10
+ShiftRight8OrMore:
+  inc h
+  inc h
+  inc h
+  ld b,0
+  ld c,a
+  ld (TempWord3),bc
+  sub 13
+  cpl
+  ld (TempWord2+1),a
+  ld b,64
+  ld de,(TempWord1)
+  inc d \ inc d \ inc d
+  dec de
+SR8OMLoop:
+;TempWord2==number of bytes to clear
+;TempWord3==number of bytes to shift
+;b=64
+  push bc
+  ld bc,(TempWord3)
+  lddr
+  ld bc,(TempWord2)
+  xor a
+_:
+  ld (de),a
+  dec de
+  dec hl
+  djnz -_
+  pop bc
+  djnz SR8OMLoop
+  ret
+ShiftRight8:
+  ld hl,(TempWord1)
+  ld d,64
+ShiftRight8_loop:
+  xor a
+  ld b,12
+_:
+  ld c,(hl)
+  ld (hl),a
+  inc hl
+  ld a,c
+  djnz -_
+  dec d
+  jr nz,ShiftRight8_loop
+  ret
+ShiftRight2:
+  call ShiftRight1
+ShiftRight1:
+  ld hl,(TempWord1)
+  ld c,64
+ShiftRight1_loop:
+  xor a
+  ld b,12
+_:
+  rr (hl)
+  inc hl
+  djnz -_
+  dec c
+  jr nz,ShiftRight1_loop
+  ret
+ShiftRight4:
+  ld hl,(TempWord1)
+  ld c,64
+ShiftRight4_loop:
+  xor a
+  ld b,12
+_:
+  rrd
+  inc hl
+  djnz -_
+  dec c
+  jr nz,ShiftRight4_loop
+  ret
+ShiftGraphLeftA:
+  rrca
+  push af
+  call c,ShiftLeft1
+  pop af
+  rrca
+  push af
+  call c,ShiftLeft2
+  pop af
+  rrca
+  push af
+  call c,ShiftLeft4
+  pop af
+  rrca
+  push af
+  call c,ShiftLeft8
+  pop af
+  rrca
+  push af
+  call c,ShiftLeft16
+  pop af
+  rrca
+  push af
+  call c,ShiftLeft32
+  pop af
+  rrca
+  ret nc
+ShiftLeft64:
+  ld hl,(TempWord1)
+  ld a,8
+  add a,l
+  jr c,+_
+  inc hl
+_:
+  ld l,a
+  ld a,4
+  jr ShiftLeft8OrMore
+ShiftLeft32:
+  ld hl,(TempWord1)
+  inc hl \ inc hl
+  inc hl \ inc hl
+  ld a,8
+  jr ShiftLeft8OrMore
+ShiftLeft16:
+  ld hl,(TempWord1)
+  inc hl \ inc hl
+  ld a,10
+ShiftLeft8OrMore:
+  ld b,0
+  ld c,a
+  ld (TempWord3),bc
+  sub 13
+  cpl
+  ld (TempWord2+1),a
+  ld b,64
+  ld de,(TempWord1)
+SL8OMLoop:
+  push bc
+  ld bc,(TempWord3)
+  ldir
+  ld bc,(TempWord2)
+  xor a
+_:
+  ld (de),a
+  inc de
+  inc hl
+  djnz -_
+  pop bc
+  djnz SL8OMLoop
+  ret
+ShiftLeft8:
+  ld hl,(TempWord1)
+  inc h \ inc h \ inc h
+  dec hl
+  ld d,64
+ShiftLeft8_loop:
+  xor a
+  ld b,12
+_:
+  ld c,(hl)
+  ld (hl),a
+  dec hl
+  ld a,c
+  djnz -_
+  dec d
+  jr nz,ShiftLeft8_loop
+  ret
+ShiftLeft2:
+  call ShiftLeft1
+ShiftLeft1:
+  ld hl,(TempWord1)
+  inc h
+  inc h
+  inc h
+  dec hl
+  ld c,64
+ShiftLeft1_loop:
+  xor a
+  ld b,12
+_:
+  rl (hl)
+  dec hl
+  djnz -_
+  dec c
+  jr nz,ShiftLeft1_loop
+  ret
+ShiftLeft4:
+  ld hl,(TempWord1)
+  inc h \ inc h \ inc h
+  dec hl
+  ld c,64
+ShiftLeft4_loop:
+  xor a
+  ld b,12
+_:
+  rld
+  dec hl
+  djnz -_
+  dec c
+  jr nz,ShiftLeft4_loop
+  ret
+ShiftGraphDownA:
+  ld e,a
+  ld l,a
+  ld h,0
+  ld d,h
+  add hl,hl
+  add hl,de
+  add hl,hl
+  add hl,hl
+  push hl
+  ld a,h
+  inc a
+  cpl
+  and 3
+  ld b,a
+  ld a,l
+  dec a
+  cpl
+  ld c,a
+  ld hl,(TempWord1)
+  dec hl
+  add hl,bc
+  ld de,(TempWord1)
+  inc d \ inc d \ inc d
+  dec de
+  lddr
+  pop bc
+ZeroMemE:
+  xor a
+SetMemE:
+  ld (de),a
+  ld h,d \ ld l,e
+  dec de
+  lddr
+  ret
+PiToken:
+; Check if the next char is a hex digit. If yes, convert as hexadecimal, else return the float value for pi
+  ld a,(hl)
+  sub '0'
+  sub 10
+  jr c,ConvHexStr
+  sub 7
+  sub 6
+  jr nc,floatpi
+ConvHexStr:
+  xor a
+  ex de,hl
+  ld h,a
+  ld l,a
+_:
+  add hl,hl
+  add hl,hl
+  add hl,hl
+  add hl,hl
+  or l
+  ld l,a
+  call IsHexTok
+  jr nc,-_
+_:
+  dec de
+  ld (parsePtr),de
+  ld b,h \ ld c,l
+  ex de,hl
+  ret
+floatpi:
+  call floatstackpush
+  push hl
+  ld de,float_pi
+  ex de,hl
+  call mov4_page0
+  pop bc
+  ret
+#ifdef include_ncr
+#include "cmd/ncr.z80"
+#endif
+ForToken:
+  ld a,(hl)
+  inc hl
+  push bc
+  call VarP
+  jr c,+_
+for_constant:
+  ;Save ForBackUp for nesting
+  ld hl,(ForBackUp)
+  ex (sp),hl
+  ld bc,for_const_ret
+  push bc
+  push hl
+
+  ld hl,ForBackUp
+  push hl
+  xor a
+  ld (hl),a
+  inc l
+  ld (hl),a
+  call ParseFullArg
+  dec bc
+  jr preStartForLoop
+for_const_ret:
+  pop hl
+  ld (ForBackUp),hl
+  ret
+_:
+  ld a,(de)
+  cp $2B
+  jr nz,for_constant
+  ld (parsePtr),de
+  push hl
+  call ParseNextFullArg
+  pop hl
+  push hl
+  ld (hl),c
+  inc hl
+  ld (hl),b
+  call ParseNextFullArg
+preStartForLoop:
+  ld e,c
+  ld d,b
+  pop hl
+  pop bc
+StartForLoop:
+  push de             ;UpperBound
+  push hl             ;varPointer
+  ld hl,(parsePtr)
+  push hl             ;save parsePtr
+  call ParserNext
+  pop hl
+  ld (TempWord2),hl
+  pop hl              ;points to var data
+  pop de              ;upper bound
+  ;check DE <= (var)
+  ld a,(hl)
+  cp e
+  inc hl
+  ld a,(hl)
+  sbc a,d
+
+;Now increment
+  dec hl
+  inc (hl)
+  jr nz,+_
+  inc hl
+  inc (hl)
+_:
+  ret nc
+
+  push hl
+  ld hl,(TempWord2)
+  ld (parsePtr),hl
+  pop hl
+  jr StartForLoop
+
+FullToken:
+  ld a,(hl)
+  ld c,1
+  call EndOArg
+  call nz,isop
+  call nz,ParseFullArg
+SetSpeed:
+  in a,(20h)
+  ld b,a
+  bit 1,c
+  jr z,+_
+  cpl
+  and 1
+  ld c,a
+_:
+  in a,(2)
+  rlca
+  and c
+  out (20h),a
+  ld c,b
+  ld b,0
+  ret
+ClrDrawToken:
+  ld a,(hl)
+  call EndOArg
+  call nz,isop
+  jr z,g_ClrDraw
+  call ParseFullArg
+  ld h,b \ ld l,c
+  ld d,b \ ld e,c
+  jp ZeroMem768
+g_ClrDraw:
+  ld de,0
+  ld (textRow),de
+  push bc
+  ld hl,(BufPtr)
+  pop de
+ZeroMem768:
+  xor a
+  ld b,a
+  ld c,a
+  ld (textRow),bc
+  ld b,3    ;BC is now 768
+  jp SetMem
+
+ClrHomeToken:
+g_ClrHome:
+  ld hl,0
+  ld (CurRow),hl
+  push bc
+  ld b,128
+  ld hl,textShadow
+  ld a,' '
+  call SetSmallMem
+  pop bc
+  ret
+minToken:
+maxToken:
+  push af
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  pop hl
+  pop af
+g_max:
+  or a
+  sbc hl,bc
+  adc a,0
+  rra
+  ret nc
+  add hl,bc
+  ld b,h
+  ld c,l
+  ret
+factorialToken:
+  ld a,(hl)
+  call IsConditional \ jr z,+_
+  ld de,0 \ push de
+  jp factorialStepIn
+_:
+  set invlogic,(iy+gflags)
+  ret
+FillToken:
+  call ParseFullArg
+  ld hl,(BufPtr)
+  ld a,c
+  ld bc,300h
+  ld e,-1
+FillBufOR:
+  or a \ jr nz,FillBufInv
+_:
+  ld a,e \ or (hl) \ ld (hl),a
+  cpi
+  jp pe,-_
+  ret
+FillBufInv:
+  dec a \ jr nz,Checker1
+_:
+  ld a,e \ xor (hl) \ ld (hl),a
+  cpi
+  jp pe,-_
+  ret
+Checker1:
+  dec a \ jr nz,Checker2
+  ld a,$AA
+Checker:
+  ld c,64
+Checker1_loop:
+  ld b,12
+_:
+  ld (hl),a
+  inc hl
+  djnz -_
+  cpl \ dec c
+  jr nz,Checker1_loop
+  ret
+Checker2:
+  dec a \ jr nz,LoadBytePatternOR
+  ld a,55h \ jr Checker
+LoadBytePatternOR:
+  cp 22 \ jr nc,NotArg
+  push af \ push bc \ push hl
+  call ParseNextFullArg
+  ld d,b \ ld e,c \ pop hl \ pop bc \ pop af
+NotArg:
+  dec a \ jr z,FillBufOR+3
+LoadBytePatternXOR:
+  dec a \ jr z,FillBufInv+3
+LoadBytePatternAND:
+  dec a \ jr nz,LoadBytePatternErase
+FillBufAND:
+  ld a,e \ and (hl) \ ld (hl),a
+  cpi
+  jp pe,FillBufAND
+  ret
+LoadBytePatternErase:
+  dec a \ jr nz,BufCopy
+FillBufErase:
+  ld a,e \ cpl \ and (hl) \ ld (hl),a
+  cpi
+  jp pe,FillBufErase
+  ret
+BufCopy:
+  dec a \ jr nz,BufOR
+  jp mov768
+BufOR:
+  dec a \ jr nz,BufAND
+  ld a,(de) \ inc de
+  or (hl) \ ld (hl),a
+  cpi \ jp pe,BufOR+3
+  ret
+BufAND:
+  dec a \ jr nz,BufXOR
+  ld a,(de) \ inc de
+  and (hl) \ ld (hl),a
+  cpi \ jp pe,BufAND+3
+  ret
+BufXOR:
+  dec a \ jr nz,BufErase
+_:
+  ld a,(de) \ inc de
+  xor (hl) \ ld (hl),a
+  cpi \ jp pe,-_
+  ret
+BufErase:
+  dec a \ jr nz,BufSwap
+  ld a,(de) \ inc de
+  cpl \ and (hl) \ ld (hl),a
+  cpi \ jp pe,BufErase+3
+  ret
+BufSwap:
+  dec a \ jr nz,CopyDown
+  ld a,(de)
+  push af \ ld a,(hl) \ ld (de),a
+  pop af \ ld (hl),a
+  inc de
+  cpi \ jp pe,BufSwap+3
+  ret
+CopyDown:
+;If Copy Down
+  cp 5 \ jr nc,CopyDownOR
+  add hl,bc \ dec hl
+  push hl
+  ld h,d \ ld l,e
+  add hl,hl \ add hl,de
+  add hl,hl \ add hl,hl
+  pop de \ push de \ push hl \ ex de,hl
+  sbc hl,de \ ex de,hl
+  ld h,b \ ld l,c \ pop bc \ sbc hl,bc
+  ld b,h \ ld c,l
+  pop hl
+CopyDownOR:
+  dec a \ jr nz,CopyDownAND
+_:
+  ld a,(de)
+  or (hl)
+  ld (hl),a
+  dec de \ cpd
+  jp pe,-_
+  ret
+CopyDownAND:
+  dec a \ jr nz,CopyDownXOR
+_:
+  ld a,(de)
+  and (hl)
+  ld (hl),a
+  dec de \ cpd
+  jp pe,-_
+  ret
+CopyDownXOR:
+  dec a \ jr nz,CopyDownErase
+_:
+  ld a,(de)
+  xor (hl)
+  ld (hl),a
+  dec de \ cpd
+  jp pe,-_
+  ret
+CopyDownErase:
+  dec a \ jr nz,CopyUp
+_:
+  ld a,(de)
+  cpl
+  and (hl)
+  ld (hl),a
+  dec de \ cpd
+  jp pe,-_
+  ret
+CopyUp:
+;If Copy Up
+  cp 5 \ jr nc,CopyUpOr
+;de is number of pixels down to copy to
+;bc is 768
+;hl points to the buffer
+  push hl
+  ld h,d \ ld l,e
+  add hl,de \ add hl,de
+  add hl,hl \ add hl,hl
+  ld b,h \ ld c,l
+  pop de \ add hl,de
+;DE points to main buffer
+;HL points to offset
+  push hl
+  ld hl,768 \ sbc hl,bc
+  ld b,h \ ld c,l
+  pop hl
+  ex de,hl
+CopyUpOR:
+  dec a \ jr nz,CopyUpAND
+_:
+  ld a,(de)
+  or (hl)
+  ld (hl),a
+  inc de \ cpi
+  jp pe,-_
+  ret
+CopyUpAND:
+  dec a \ jr nz,CopyUpXOR
+_:
+  ld a,(de)
+  and (hl)
+  ld (hl),a
+  inc de \ cpi
+  jp pe,-_
+  ret
+CopyUpXOR:
+  dec a \ jr nz,CopyUpErase
+_:
+  ld a,(de)
+  xor (hl)
+  ld (hl),a
+  inc de \ cpi
+  jp pe,-_
+  ret
+CopyUpErase:
+#ifdef include_fire
+  dec a \ jr nz,fire
+#else
+  dec a \ ret nz
+#endif
+_:
+  ld a,(de)
+  cpl
+  and (hl)
+  ld (hl),a
+  inc de \ cpi
+  jp pe,-_
+  ret
+fire:
+#ifdef include_fire
+#include "cmd/fire.z80"
+#endif
+HorizontalToken:
+  call ParseFullArg
+
+  ld a,b \ or a \ ret nz
+  ld a,c
+  cp 64
+  ret nc
+  push bc
+  ld c,1
+  ld a,(hl)
+  cp 2Bh
+  call z,ParseNextFullArg
+  ld d,c
+  cp 2Bh
+  push de
+  ld bc,(BufPtr)
+  call z,ParseNextFullArg
+  pop de
+  pop hl
+  push bc
+  ld b,h
+  ld c,l
+  add hl,hl \ add hl,bc
+  add hl,hl \ add hl,hl
+  ld a,d
+  pop bc
+  add hl,bc
+  ld b,12
+  or a
+  jr z,SetSmallMem
+  dec a
+  jr nz,InvertMem
+  dec a
+SetSmallMem:
+  ld (hl),a
+  inc hl
+  djnz SetSmallMem
+  ret
+InvertMem:
+  ld a,(hl)
+  cpl
+  ld (hl),a
+  inc hl
+  djnz InvertMem
+  ret
+VerticalToken:
+  call ParseFullArg
+  push bc
+  ld c,1
+  cp $2B
+  call z,ParseNextFullArg
+  pop hl
+  push bc
+  push hl
+  cp 2Bh
+  call z,ParseNextFullArg_Buffer
+  pop bc
+  ld b,c
+  ld c,0
+  call getPixelLoc
+  pop bc      ;C is the method
+  ret nc
+
+;it is in-bounds
+  ld de,12
+  ld b,64
+  dec c
+  jr nz,draw_vert_toggle
+  ld c,a
+_:
+  ld a,(hl)
+  or c
+  ld (hl),a
+  add hl,de
+  djnz -_
+  ret
+
+draw_vert_toggle:
+  dec c
+  jr nz,draw_vert_off
+  ld c,a
+_:
+  ld a,(hl)
+  xor c
+  ld (hl),a
+  add hl,de
+  djnz -_
+  ret
+
+draw_vert_off:
+  cpl
+  ld c,a
+_:
+  ld a,(hl)
+  and c
+  ld (hl),a
+  add hl,de
+  djnz -_
+  ret
+
+ShadeToken:
+  call ParseFullArg
+  ld a,c
+  add a,$D9
+  jr nc,+_
+  xor a
+_:
+  dec a
+  out (16),a
+  ret
+StorePicToken:
+  call ParseFullArg
+  ld b,c
+  ld c,60h
+  push bc
+  cp 2Bh
+  ld bc,(BufPtr)
+  call z,ParseNextFullArg
+  pop hl
+  push bc
+  ld (OP1+1),hl
+  xor a
+  ld (OP1+3),a
+  rst rFindSym
+  jr c,+_
+  bcall(_DelVarArc)
+_:
+  ld hl,768
+  ld a,7
+  bcall(_CreateVar)   ;_CreatePict only stores 756 bytes.
+  inc de
+  inc de
+  pop hl
+mov768:
+;14656cc vs 16123cc
+  ld bc,768
+_:
+  call mov12
+  jp pe,-_
+  ret
+RecallPicToken:
+  call ParseFullArg
+  push bc
+  cp 2Bh
+  ld c,0
+  call z,ParseNextFullArg
+  ld b,c
+  push bc
+  ld bc,(BufPtr)
+  cp 2Bh
+  call z,ParseNextFullArg
+  pop af
+
+;A is the copy method
+;{stack} is the pic num
+  ld h,b
+  ld l,c
+;42
+  ex (sp),hl
+  push af
+  ld h,0
+  ;L is the pic num
+  ld (OP1+2),hl
+  ld a,$60
+  ld (OP1+1),a
+  rst rFindSym
+  jp c,pop2exit
+;stack={loc,method}
+  ld a,b
+  ld b,0
+  push af
+  call GetVarInfoVarFound
+  dec bc
+  ld a,b
+  inc bc
+  sub 3
+  jr c,+_
+  ld bc,768
+_:
+  pop af
+  ld de,saveSScreen
+  push bc
+  push de
+  call ReadArc
+  pop hl
+  pop bc
+  pop af
+  pop de
+  or a
+  jp z,BufCopy+3
+  ex de,hl
+  dec a
+  jp z,BufAND+3
+  dec a
+  jp z,BufXOR+3
+  dec a
+  jp z,BufOR+3
+  dec a
+  ret z
+  dec a
+  jp z,BufErase+3
+  ret
+BBTokens:
+  ld a,(hl)
+  inc hl
+  cp $64    ;the G-T token
+  jr nz,lowercasetokens
+  ld a,(hl)
+  ld bc,plotSScreen
+  cp $AE
+  jr nz,+_
+  inc hl
+  ld bc,appBackUpScreen
+_:
+  ld (parsePtr),hl
+  ret
+lowercasetokens:
+  ld (parsePtr),hl
+  cp $31      ;the `e` token
+  jr nz,+_
+  call floatstackpush
+  push hl
+  ld de,float_e
+  ex de,hl
+  call mov4_page0
+  pop bc
+  ret
+_:
+  cp $4B        ;Pmt_End
+  jr nz,+_
+  ld bc,(stack_top)
+  ret
+_:
+  cp $4C        ;Pmt_Bgn
+  jr nz,+_
+  ld bc,(stack_base)
+  ret
+_:
+  cp $B0
+  jr c,length
+  cp $CB
+  jr nc,length
+  cp $BB
+  jr c,+_
+  dec a
+_:
+  sub $AC
+  add a,a
+  inc a
+  ex de,hl
+  ld l,a
+  ld h,91h
+  ld c,(hl)
+  inc l
+  ld b,(hl)
+  ex de,hl
+  ld a,(hl)
+  inc hl
+  call VarP
+  ret nc
+  ld (parsePtr),de
+  ld d,b
+  ld e,c
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  set FactorialFlag,(iy+InternalFlag)
+  ret
+length:
+  cp 2Bh \ jr nz,inString
+  ld a,(hl)
+  cp $AE  ;'
+  jr nz,FindVarInfo
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+  push bc
+  ld bc,3Fh
+  cp 2Bh \ call z,ParseNextFullArg
+  ld a,c
+  pop de
+  pop bc
+  pop hl
+  call SearchLine_00
+  ld (ThetaPrimeVar),hl
+  ld b,d \ ld c,e
+  ret
+;HL is start address
+;BC is the line number
+;E is the NewLine byte
+FindvarInfo:
+  call GetVarInfo2
+  ld (ThetaPrimeVar),hl
+  ret nc
+  ld bc,-1
+  ret
+inString:
+  cp 15 \ jr nz,conj
+  call ParseFullArg
+  push bc
+
+  call ParseNextFullArg
+  pop hl
+  push bc   ;second arg
+  push hl   ;first arg
+  push af
+  ld h,b
+  ld l,c
+  call GetGrammerStr
+  pop af
+  pop hl
+  push bc   ;size of second arg string
+
+  cp 2Bh        ;If there is another argument, then it is to put a limit on how many bytes to compare
+  push hl
+  jr z,+_
+  call nz,GetGrammerStr
+  scf
+_:
+  call nc,ParseNextFullArg
+  ld (ThetaPrimeVar),bc
+  pop hl
+  pop ix
+  pop de
+
+  call SearchString
+  jp nc,return_BC_0
+  ld b,h \ ld c,l
+  ret
+conj:
+;n = f(x) = 440*(12th root (2^(x-48))
+;A=1, B=3, C=4, D=6, E=8, F=9, and G=11
+;Sharp is add 1
+;flat is minus 1
+  cp 37
+  jp nz,subToken
+  ld a,(hl)
+  cp $AE
+  jr nz,GrammerSound
+  call ParseNextFullArg
+  push bc
+  inc hl \ ld a,(hl)
+  cp $AE \ push af
+  call ParseNextFullArg
+  pop af
+  jr nz,SoundData
+  ld hl,freqout
+  ld (next_page_call_address),hl
+  ld h,b \ ld l,c \ pop bc
+  jp next_page_call
+
+
+SoundData:
+  push bc
+  call ParseNextFullArg
+  ld hl,SoundLoop
+  ld (next_page_call_address),hl
+  pop hl \ pop de
+  ld a,b \ or c
+  jp nz,next_page_call
+  ret
+
+GrammerSound:
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+;Octave*12
+  ld h,b
+  ld l,c
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+
+;Now add in the note
+  pop bc
+  add hl,bc
+
+;get offset into the LUT
+  add hl,hl
+
+;get the frequency
+  ld bc,FrequencyLUT
+  add hl,bc
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+
+  push bc
+  call ParseNextFullArg
+  ;multiply BC by 34483, then divide by 32
+
+  ld de,34483
+  call DE_Times_BC
+  xor a
+  add hl,hl \ rl e \ rl d \ rla
+  add hl,hl \ rl e \ rl d \ rla
+  add hl,hl \ rl e \ rl d \ rla
+  ld l,h \ ld h,e \ ld e,d \ ld d,a
+  ;DEHL is how long to run it
+
+  ld bc,noteloop_begin
+  ld (next_page_call_address),bc
+  pop bc
+  jp next_page_call
+
+subToken:
+  cp 12 \ jr nz,ANOVAsubset
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  push bc
+  ld hl,(parsePtr)
+  inc hl
+  ld (parsePtr),hl
+  call GetVarInfo
+  jp c,Pop2Exit
+  or a \ jp nz,Pop2Exit
+  ld hl,(parsePtr)
+  ld (parsePtr),hl
+  ex de,hl
+  ld c,(hl) \ inc hl
+  ld b,(hl) \ inc hl
+  ld (TempWord1),hl
+  ld h,b \ ld l,c
+  pop bc
+  sbc hl,bc
+  pop de
+  ret c
+  sbc hl,de
+  jr nc,DelGoodSize
+  ex de,hl
+  add hl,de
+  ld h,a \ cp l \ ret z
+  ex de,hl
+  ld hl,0
+DelGoodSize:
+  add hl,bc
+  push de
+  ld de,(TempWord1)
+  ex de,hl
+  dec hl \ ld (hl),d
+  dec hl \ ld (hl),e
+  inc hl \ inc hl
+  add hl,bc
+  pop de
+  push hl
+  ld a,d \ or e
+  jr z,+_
+  bcall(_DelMem)
+_:
+  ld hl,(parsePtr)
+;  ld (parsePtr),hl   ;seems redundant, I probably messed up when I was cleaning the code.
+  pop bc
+  ret
+ANOVAsubset:
+DelvarToken:
+  cp 54h \ jr nz,UnArchiveToken
+  call GetVarInfo \ ret c
+  bcall(_DelVarArc)
+  ret
+UnArchiveToken:
+  cp 69h \ jr nz,ArchiveToken
+  call GetVarInfo \ ret c
+  or a \ ret z
+  bcall(_Arc_Unarc)
+  call setup_readarc
+  bcall(_ChkFindSym)
+  ex de,hl
+  ld e,(hl) \ inc hl
+  ld d,(hl) \ inc hl
+  ex de,hl \ ld c,e \ ld b,d
+  ld (ThetaPrimeVar),hl
+  ret
+ArchiveToken:
+  cp 68h \ jr nz,AsmToken
+  call GetVarInfo \ ret c
+  or a
+  ret nz
+  bcall(_Arc_Unarc)
+setup_readarc:
+  call setupRAMdata
+#ifndef include_TSA
+  ld hl,ReadArcData
+  ld de,TSA
+;mov 71 bytes
+  call mov14
+  call mov14
+  call mov14
+  call mov14
+  call mov15
+  in a,(6)
+  ld (page_restore),a
+  ld (bincomparepagerestore),a
+#ifdef include_interrupt
+  dec a
+  ld (interrupt_page),a
+#endif
+#endif
+  ret
+AsmToken:
+  cp 6Ah \ jr nz,expr
+; jr $
+  push bc
+  call GetVarName
+  ex de,hl
+  ld de,OP1
+  ldir
+  xor a
+  ld (de),a
+  ld hl,9D95h ;start VarRAM
+  ld (TempWord1),hl
+  pop hl \ ld (TempWord2),hl
+  bcall(_ChkFindSym)
+  ld a,b
+  ld (TempWord3),a
+  ex de,hl
+  ld c,(hl) \ inc hl
+  ld b,(hl) \ inc hl
+  ld a,(hl) \ inc hl \ cp $BB
+  ret nz
+NotASMHeader:
+  ld a,(hl) \ inc hl \ cp $6D
+  jr nz,CheckUnsquishedHex
+StartASMProg:
+  dec bc \ dec bc
+;BC is size of the data
+;HL points to the bytes to copy
+;(TempWord3) is the flash page
+  push hl \ push bc
+  ld h,b \ ld l,c
+  bcall(_EnoughMem)
+  jp c,ErrMEM
+  ex de,hl
+;HL # bytes
+;DE addr
+  ld de,9D95h ;start VarRAM
+  push de
+  bcall(_InsertMem)
+  pop de \ pop bc \ pop hl
+  ld a,(TempWord3) \ or a
+  jr nz,+_
+  add hl,bc
+_:
+  push bc
+  call ReadArc
+  pop de
+  jr +_
+CheckUnsquishedHex:
+  cp 6Ch \ jr nz,NotASMHeader
+  jr NotASMHeader
+_:
+  ld hl,(parsePtr)
+  add hl,de
+  ld (parsePtr),hl
+;===============================================================
+CallProg:
+  ld bc,(TempWord2)
+  push de
+  ld de,AfterRet \ push de
+  ld de,(TempWord1) \ push de
+  ret
+AfterRET:
+  ld hl,(parsePtr)
+  pop de
+  or a
+  sbc hl,de
+  ld (parsePtr),hl
+  ld hl,9D95h ;start VarRAM
+;Delmem: HL address
+;        DE # of bytes
+  bcall(_DelMem)
+  ret
+expr:
+  cp 2Ah \ jr nz,AsmPrgm
+  call ParseFullArg
+g_expr:
+  ld hl,(parsePtr) \ push hl
+  ld (parsePtr),bc
+  call ParseCondition
+  pop hl
+  ld (parsePtr),hl
+  ret
+AsmPrgm:
+  cp 6Ch \ jr nz,OMNom
+  push bc
+  ld b,h \ ld c,l
+  call ConvHexTo86ECh
+  ex de,hl
+  ld (parsePtr),hl
+  pop bc
+  jp 86ECh
+OMNom:
+;Note from Future Zeda: "I love you Past Zeda."
+  cp 5 \ jr nz,BBrandInt
+#include "cmd/nom.z80"
+BBrandInt:
+  cp 10 \ jr nz,BBLCM
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  push bc
+  call prng16
+  ld b,h
+  ld c,l
+  pop hl
+  pop de
+  or a \ sbc hl,de
+  push de
+  call HL_Times_BC
+  pop hl \ add hl,de
+  ld b,h \ ld c,l
+  ret
+BBLCM:
+  cp 8
+  jr nz,BBGCD
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  pop de
+LCM_BC_DE:
+  push de
+  call DE_Times_BC
+  ex (sp),hl
+  call GCDHL_BC
+  pop hl
+  call HL_Div_BC
+  ld b,h
+  ld c,l
+  ret
+BBGCD:
+  cp 9
+  ret nz
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  pop hl
+GCDHL_BC:
+  ld d,b
+  ld e,c
+#include "math/gcdHL_DE.z80"
+
+CircleToken:
+#define circle_pattern TempWord1
+  call ParseFullArg     ;Y
+  push bc
+  call ParseNextFullArg ;X
+  pop de
+  ld d,c
+  push de
+  call ParseNextFullArg ;R
+  push bc
+  cp 2Bh
+  ld c,1
+  call z,ParseNextFullArg ;Method
+  ld b,c
+  push bc
+  ld c,0
+  cp 2Bh
+  call z,ParseNextFullArg ;pattern
+  push bc
+  cp 2Bh
+  call z,ParseNextFullArg_Buffer  ;buffer
+
+  pop hl
+  ld a,l
+  ld (circle_pattern),a
+  pop af    ;method in A
+  pop de    ;radius in E
+  pop bc
+
+  dec a
+  jr z,circle_bbcf
+  dec a
+  jr z,circle_wbcf
+  dec a
+  jr z,circle_xbcf
+
+  dec a
+  jr z,circle_wbwf
+  dec a
+  jr z,circle_bbbf
+  dec a
+  jr z,circle_xbxf
+
+  dec a
+  jr z,circle_wbbf
+  dec a
+  jr z,circle_wbxf
+
+  dec a
+  jr z,circle_bbwf
+  dec a
+  jr z,circle_bbxf
+
+  dec a
+  jr z,circle_xbwf
+  dec a
+  ret nz
+
+circle_xbbf:
+  push de
+  push bc
+  call circle_xbcf
+  pop bc
+  pop de
+  jr circle_bf
+
+circle_wbcf:
+  ld ix,pixelOff_pattern
+  jr circle_p0
+circle_bbcf:
+  ld ix,pixelOn_pattern
+  jr circle_p0
+circle_xbcf:
+  ld ix,pixelToggle_pattern
+  jr circle_p0
+
+circle_wbwf:
+  push de
+  push bc
+  call circle_wbcf
+  pop bc
+  pop de
+circle_wf:
+  ld ix,horizline_white
+  jp drawfilledcircle
+
+circle_bbbf:
+  push de
+  push bc
+  call circle_bbcf
+  pop bc
+  pop de
+circle_bf:
+  ld ix,horizline_black
+  jp drawfilledcircle
+
+circle_xbxf:
+  push de
+  push bc
+  call circle_xbcf
+  pop bc
+  pop de
+circle_xf:
+  ld ix,horizline_invert
+  jp drawfilledcircle
+
+circle_wbbf:
+  push de
+  push bc
+  call circle_wbcf
+  pop bc
+  pop de
+  jr circle_bf
+
+circle_wbxf:
+  push de
+  push bc
+  call circle_wbcf
+  pop bc
+  pop de
+  jr circle_xf
+
+circle_bbwf:
+  push de
+  push bc
+  call circle_bbcf
+  pop bc
+  pop de
+  jr circle_wf
+
+circle_bbxf:
+  push de
+  push bc
+  call circle_bbcf
+  pop bc
+  pop de
+  jr circle_xf
+
+circle_xbwf:
+  push de
+  push bc
+  call circle_xbcf
+  pop bc
+  pop de
+  jr circle_wf
+
+
+
+circle_p0:
+  push hl
+  ld hl,circle
+  ld (next_page_call_address),hl
+  pop hl
+  jp next_page_call
+
+drawfilledcircle:
+  push hl
+  ld hl,filledcircle
+  ld (next_page_call_address),hl
+  pop hl
+  jp next_page_call
+
+PauseToken:
+  ld a,(hl)
+  call EndOArg
+  call nz,isop
+  push bc
+  jr nz,NotBASICPause
+_:
+  bit OnBlockFlag,(iy+UserFlags)
+  call z,onbreak
+  call GetKeyDebounce
+  cp 9
+  jr nz,-_
+_:
+  bit OnBlockFlag,(iy+UserFlags)
+  call z,onbreak
+  call GetKeyDebounce
+  or a
+  jr nz,-_
+  pop bc
+  ret
+NotBASICPause:
+  ld a,(hl) \ cp $CE \ jr nz,Pause
+  bit invlogic,(iy+gflags)
+  res invlogic,(iy+gflags)
+  inc hl
+  jr z,Pauseif
+  jr PauseNotIf
+Pause:
+  call ParseFullArg
+  pop de
+g_Pause:
+  push de
+  ei
+_:
+  bit OnBlockFlag,(iy+UserFlags)
+  call z,onbreak
+  halt
+  dec bc
+  ld a,b
+  or c
+  jr nz,-_
+  pop bc
+  ret
+PauseIf:
+  call PauseIfLoop
+  jr nz,PauseIf
+  pop bc \ ret
+PauseNotIf:
+  call PauseIfLoop
+  jr z,PauseNotIf
+  pop bc \ ret
+PauseIfLoop:
+  ld (parsePtr),hl
+  push hl
+  call ParseCondition
+  ld a,b
+  or c
+  pop hl
+  ret
+PxlTokens:
+  sub $A0
+PxlTestToken:
+  push af
+  ld a,(hl)
+  cp $AE
+  ;jr z,PxlTestBox
+  jp z,ErrBadToken
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  cp 2Bh
+  ld a,c
+  push af
+  call z,ParseNextFullArg_Buffer
+  pop af
+  pop bc
+  ld b,a
+  pop de
+PlotPixel:
+  call GetPixelLoc
+  ld bc,0
+  jr c,+_
+  bit pxlBoundsRes,(iy+UserFlags)
+  ret z
+  inc c
+  ret
+_:
+  ld e,a
+  and (hl)
+  jr z,+_
+  inc c
+_:
+  dec d
+  jr nz,+_
+  ld a,e \ or (hl) \ ld (hl),a \ ret
+_:
+  dec d
+  jr z,+_
+  dec d
+  ret nz
+  ld a,e
+_:
+  xor (hl) \ ld (hl),a \ ret
+prgmToken:
+  ld (TempWord1),bc
+  ld a,(hl) \ inc hl
+  cp $10
+  jr nz,+_
+  ld (parsePtr),hl
+  ld a,(hl)
+  inc hl
+_:
+  push af
+  call VarP
+  ex (sp),hl
+  push af
+  push hl
+  call ParseFullArg
+  pop af
+  jr nz,g_Call
+  inc hl
+  ld (qmarkVar),hl
+  .db $C2   ;start of jp nz,*, basically skips the 'or 1'
+g_Call:
+  or 1
+  push af
+  ld de,(progStart)
+  ld hl,(parsePtr)
+  or a
+  sbc hl,de
+  push hl
+  ex de,hl
+  sbc hl,bc
+  push hl
+  ld (parsePtr),bc
+  ld bc,(TempWord1)
+  call ParserNext
+  pop hl
+  pop de
+  push hl
+  ld hl,(progStart)
+  add hl,de
+  ld (parsePtr),hl
+  pop de
+  ld hl,(progStart)
+  sbc hl,de
+  ex de,hl
+  pop af
+  jr nz,+_
+  pop af
+  pop hl
+  ld hl,(qmarkVar)
+  ld (parsePtr),hl
+  ret
+_:
+  pop af \ pop hl
+  ret nc
+  ld (hl),e \ inc hl
+  ld (hl),d
+  ret
+DispToken:
+  ld a,(hl)
+  cp 11
+  jr z,GrayBufOnly
+  cp $AE
+  jr z,BlackBufOnly
+  call ParseFullArg
+  ld (BufPtr),bc
+  ld (GrayBufPtr),bc
+  ret
+GrayBufOnly:
+  call ParseNextFullArg
+  ld (GrayBufPtr),bc
+  ret
+BlackBufOnly:
+  call ParseNextFullArg
+  ld (BufPtr),bc
+  ret
+TextToken:
+  ld a,(hl)
+  cp 4 \ jr z,+_
+  cp 3Eh \ jr z,+_
+  cp 3Fh \ jr nz,NoRC
+_:
+  ld bc,(textRow)
+  ld l,b \ ld b,0
+  ld h,b
+  ld (ThetaPrimeVar),hl
+  ret
+NoRC:
+  res SlowTextFlag,(iy+InternalFlag)
+  cp 10
+  jr nz,+_
+SlowText:
+  set SlowTextFlag,(iy+InternalFlag)
+  inc hl
+  ld (parsePtr),hl
+  ld a,(hl)
+_:
+  cp $AE
+  jp nz,FindingTextStr
+  inc hl
+  ld (parsePtr),hl
+  call LoadTextCoordinates
+  call ParseNextFullArg
+  push bc
+  push de
+  ld a,(hl)
+  cp 2Bh
+  ld c,10
+  call z,ParseNextFullArg+3
+
+  pop hl
+  pop de
+  bit SignedText,(iy+UserFlags)
+  jr z,+_
+  bit 7,d
+  jr z,+_
+  xor a \ sub e \ ld e,a
+  sbc a,a \ sub d \ ld d,a
+;  ld a,b \ sbc a,e \ ld e,a
+;  ld a,b \ sbc a,d \ ld d,a
+  push de \ push hl \ push bc
+  ld a,1Ah \ call PutSC
+  pop bc \ pop hl \ pop de
+_:
+  dec c
+  ret z
+  inc c
+  ret z
+  push de
+  pop ix
+  ld de,OP2
+  xor a
+  ld (de),a
+DispNumBase32:
+;Inputs:
+;     C is the base (use 2 to 36)
+;     HLIX is the number to display
+;     IX points to where to write the string
+  call HLIX_Div_C
+  add a,30h
+  cp 3Ah
+  jr c,+_
+  add a,7
+_:
+  dec de
+  ld (de),a
+  ld a,ixh
+  or ixl \ or h \ or l
+  jr nz,DispNumBase32
+  ex de,hl
+  jp GPutS
+
+FindingTextStr:
+  call LoadTextCoordinates
+  ret nz
+  inc hl
+  ld a,(hl)
+  cp 3Ah      ;. displays a float
+  jr nz,+_
+  ld (parsePtr),hl
+  call ParseNextFullArg
+  ld hl,single2str
+  ld (next_page_call_address),hl
+  ld h,b
+  ld l,c
+  ld bc,OP1
+  call next_page_call
+  ld h,b
+  ld l,c
+  jp GPutS
+_:
+  cp $AE
+  jr nz,+_
+  ld (parsePtr),hl
+  call ParseNextFullArg
+  ld a,c
+  jp PutSC
+_:
+  cp 11
+  jr nz,+_
+  ld (parsePtr),hl
+  call ParseNextFullArg
+  ld h,b \ ld l,c
+  jp GPutS
+_:
+  call ParseNextFullArg
+  push bc
+  cp 2Bh
+  jr nz,+_
+  call ParseNextFullArg
+  set Xis0,(iy+ParticleFlag)
+  xor a
+_:
+  pop hl
+  jr z,TokenTextLoop
+PutTokenText:
+;    HL points to the string
+  res Xis0,(iy+ParticleFlag)
+  ld bc,-1
+TokenTextLoop:
+  ld a,(hl)
+  bit Xis0,(iy+ParticleFlag)
+  jr nz,+_
+  or a
+  ret z
+  cp 4
+  ret z
+  cp 3Fh
+  ret z
+  cp 2Ah
+  ret z
+_:
+  push  hl
+  push bc
+  bcall(_Get_Tok_Strng)
+  pop hl
+  or a
+  sbc hl,bc
+  jr nc,+_
+  add hl,bc
+  ld b,h
+  ld c,l
+  ld l,0
+_:
+  ex (sp),hl
+  ld a,(hl)
+  call Is_2_Byte
+  jr nz,+_
+  inc hl
+_:
+  push hl
+  ld hl,OP3
+  call PutSM
+  pop hl
+  pop bc
+  inc bc
+  cpi
+  jp pe,TokenTextLoop
+  ret
+;===============================================================
+LoadTextCoordinates:
+;===============================================================
+  ld a,(hl)
+  cp 11
+  jr nz,+_
+  ld (parsePtr),hl
+  ret
+_:
+  ld bc,(textRow)
+  call ParseFullArg
+  ld a,c
+  ld (textRow),a
+  ld bc,(textCol)
+  call ParseNextFullArg
+  ld a,c
+  ld (textCol),a
+  ld a,(hl)
+  cp 2Bh
+  ret
+;===============================================================
+PtOff:
+  call ParseFullArg
+  ld a,c
+  and 7
+  push af
+  bit 3,c
+  push af
+  call ParseNextFullArg
+  pop af
+  jr z,+_
+  call ConvHexTo86ECh
+  ld bc,86ECh
+_:
+  push bc
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+  pop de
+  ld d,c
+  push de
+  cp 2Bh
+  ld c,1
+  call z,ParseNextFullArg
+  push bc
+  cp 2Bh
+  ld c,8
+  call z,ParseNextFullArg
+  pop hl
+  ld h,c
+  push hl
+  ld hl,(parsePtr)
+  ld a,(hl)
+  cp $2B
+  call z,ParseNextFullArg_Buffer
+  pop hl
+  pop bc
+  pop de
+  pop af
+  jr sprite
+#include "gfx/bigsprite.z80"
+
+
+LineToken:
+  ld a,(hl)
+  cp $AE
+  jp z,gfx_line
+
+
+;     A is the type of rectangle to draw
+;        0 =White
+;        1 =Black
+;        2 =XOR
+;        3 =Black border
+;        4 =White border
+;        5 =XOR border
+;        6 =Black border, white inside
+;        7 =Black border, XOR inside
+;        8 =White border, black inside
+;        9 =White border, XOR inside
+;        10=Shift Up
+;        11=Shift Down
+;     B is the height
+;     C is the Y pixel coordinate
+;     D is the width in pixels
+;     E is is the X pixel coordinate
+
+;So we get E,C,B,D,A
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+  pop hl
+  ld h,c
+  push hl
+  call ParseNextFullArg
+  push bc
+  cp 2Bh
+  ld c,1
+  call z,ParseNextFullArg
+  push bc
+  cp 2Bh
+  call z,ParseNextFullArg_Buffer
+  pop bc    ;method in C
+  ld a,c
+  pop hl    ;L is what needs to be the D value
+  pop bc
+  pop de
+  ld d,l
+  jp DrawRectToGraph
+gfx_line:
+;x1,y1,x2,y2[,method[,buffer
+;
+
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+  pop de
+  ld b,e
+  push bc
+
+  call ParseNextFullArg
+  push bc
+  call ParseNextFullArg
+  pop de
+  ld b,e
+  push bc
+
+  ld c,1
+  cp $2B
+  call z,ParseNextFullArg
+
+;Now get the pointer to the plotting function
+  ld b,a    ;save A
+  ld a,c
+  cp 3
+  sbc a,a
+  and c
+  add a,a
+  add a,plotLUT&255
+  ld l,a
+  ld a,plotLUT>>8
+  adc a,0
+  ld h,a
+  ld c,(hl)
+  inc hl
+  ld a,b    ;restore A
+  ld b,(hl)
+
+  push bc
+  cp $2B
+  call z,ParseNextFullArg_Buffer
+  pop ix
+  pop de
+  pop hl
+#include "gfx/line.z80"
+plotLUT:
+  .dw pxloff
+  .dw pxlon
+  .dw pxlchange
+
+LeftParantheses:
+;Read a byte
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  ld c,(hl)
+  ld b,0
+  ret
+LeftBracket:
+;Read a word (little endian)
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  ret
+iPart:
+;Write a word (little endian)
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  pop hl
+  ld e,(hl)
+  ld (hl),c
+  inc hl
+  ld d,(hl)
+  ld (hl),b
+  ld b,d
+  ld c,e
+  ret
+
+int:
+;Write byte
+  ld a,(hl)
+  cp $3A
+  jr z,intf
+  cp $AE      ;checks for '
+  push af
+  call ParseFullArg
+  push bc
+  call ParseNextFullArg
+  pop hl
+  pop af
+  jr nz,+_ ;Write a byte
+  ld a,(bc)
+  ld e,(hl)
+  ld (hl),a
+  ld a,e
+  ld (bc),a
+  ret
+_:
+  ld e,(hl)
+  ld (hl),c
+  ld c,e
+  ld b,$00
+  ret
+intf:
+  call ParseNextFullArg
+  ld hl,singleTo_int16
+  ld (next_page_call_address),hl
+  ld h,b
+  ld l,c
+  call next_page_call
+  ld b,h
+  ld c,l
+  ret
+GetToken:
+  ld a,(hl)
+  cp $AE
+  jp z,GetByte
+  call GetVarName
+  ex de,hl
+  ld de,OP1
+  ldir
+  xor a
+  ld (de),a
+  bcall(_ChkFindSym)
+VarTokenStepIn:
+  jp c,return_BC_0
+  inc de
+  inc de
+  ld c,a
+  ld (ThetaPrimeVar),bc
+  ld b,d
+  ld c,e
+  ret
+RepeatToken:
+  push hl
+  ex de,hl
+  pop hl
+  call EndOfLine
+  ld (parsePtr),hl
+  bit invlogic,(iy+gflags)
+  res invlogic,(iy+gflags)
+  jr nz,NotRepeatLoop
+RepeatLoop:
+  call RepeatLooper
+  jr z,RepeatLoop
+ExitRepeat:
+  ld (parsePtr),hl
+  ret
+NotRepeatLoop:
+  call RepeatLooper
+  jr nz,NotRepeatLoop
+  jr ExitRepeat
+RepeatLooper:
+  push de
+  call ParserNext
+  ld hl,(parsePtr)
+  pop de
+  push de
+  push hl
+  ld (parsePtr),de
+  push bc
+  call ParseCondition
+  ld a,b \ or c
+Pop3Exit:
+  pop bc
+Pop2Exit:
+  pop hl
+Pop1Exit:
+  pop de
+  ret
+WhileToken:
+  bit invlogic,(iy+gflags)
+  res invlogic,(iy+gflags)
+  jr nz,NotWhileLoop
+WhileLoop:
+  push hl
+  ld (parsePtr),hl
+  call ParseCondition
+  ld a,b
+  or c
+  jr z,EndWhileLoop
+  call ParserNext
+  pop hl
+  jr WhileLoop
+NotWhileLoop:
+  push hl
+  ld (parsePtr),hl
+  call ParseCondition
+  ld a,b
+  or c
+  jr nz,EndWhileLoop
+  call ParserNext
+  pop hl
+  jr NotWhileLoop
+EndWhileLoop:
+  pop de
+  call FindEndToken
+  ld (parsePtr),hl
+  ret
+EndToken:
+  pop de
+  ret
+ErrorJump:
+  ; If we are currently parsing an errorthen we don't want to be stuck in an infinite loop !
+  bit errorChecking,(iy+InternalFlag)
+  ret nz
+  set errorChecking,(iy+InternalFlag)
+
+  push de
+  push hl
+  push bc
+  ld hl,(parsePtr)
+  ld (ErrorLoc),hl
+  ld hl,(parseError)
+  ld a,h
+  or l
+  ld a,(cxErrorEP)
+  call z,GramHandl
+  jr z,L5c05
+  ld c,a
+  ld b,0
+  ld de,(parsePtr)
+  ld (qmarkVar),de
+  ld (parsePtr),hl
+  ld hl,(ThetaPrimeVar)
+  push hl
+  ld hl,(Ans)
+  ld (Ans),bc
+  push hl
+  call ParserNext
+  ld a,(hl)
+  ld hl,(qmarkVar)
+  ld (parsePtr),hl
+  cp $11
+  jr nz,+_
+  pop hl
+  pop hl
+  pop hl
+  jr L5c06
+_:
+  pop hl
+  ld (Ans),hl
+  pop hl
+  ld (ThetaPrimeVar),hl
+L5c05:
+  pop bc
+L5c06:
+  pop hl
+  pop de
+  res errorChecking,(iy+InternalFlag)
+  ret
+PtOn:
+  call ParseFullArg
+  ld a,c \ and 7
+  res SlowTextFlag,(iy+InternalFlag)
+  bit 3,c
+  jr z,+_
+  set SlowTextFlag,(iy+InternalFlag)
+_:
+  push af
+  cp 7 \ jr nz,+_
+  ld hl,flags+33
+  ld a,16
+  xor (hl)
+  ld (hl),a
+_:
+  call ParseNextFullArg
+  bit SlowTextFlag,(iy+InternalFlag)
+  jr z,+_
+  call ConvHexTo86ECh
+  ld bc,saveSScreen
+_:
+  push bc
+  call ParseNextFullArg
+  ld (TempWord2),bc
+  ld b,0
+  ld h,b
+  ld l,c
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  push hl
+  call ParseNextFullArg
+  pop hl
+  add hl,bc
+  push hl
+  cp 2Bh
+  ld c,1
+  call z,ParseNextFullArg
+  ld b,c
+  push bc
+  cp 2Bh
+  ld c,$08
+  call z,ParseNextFullArg
+  pop af
+  ld b,a
+  ld a,(TempWord2)
+  add a,c \ dec a \ sub 64
+  jr c,HeightIsFinePtOn
+  ld d,a \ ld a,c \ sub d \ ld c,a \ dec c
+HeightIsFinePtOn:
+  push bc
+  ld bc,(BufPtr)
+  ld hl,(parsePtr)
+  ld a,(hl)
+  cp 2Bh
+  call z,ParseNextFullArg
+  ld d,b \ ld e,c
+  pop bc
+  pop hl
+  add hl,de
+  pop de
+  ld a,(TempWord2) \ inc a \ sub 64 \ jp nc,pop1exit
+  pop af
+DrawSpriteXxY:
+  push hl
+  ld hl,bigtile
+  ld (next_page_call_address),hl
+  pop hl
+  jp next_page_call
+QuoteToken:
+  push hl
+  call GetGrammerStr
+  ld (parsePtr),hl
+  ld (ThetaPrimeVar),bc
+  pop bc
+  ret
+GetKeyToken:
+  ld a,(hl)
+  cp 16
+  jr nz,GetKey
+  call ParseNextFullArg+3
+  ld a,c
+CheckKey:
+;46 bytes:
+;Input:
+;     A is the key to test for
+;Output:
+;     BC is 1 if the key is pressed, 0 if it is not
+;     z if the key is pressed, nz if not
+  cp 41 ;on-key
+  jr z,check_for_ON_key
+  di
+_:
+  dec a \ and 63
+  ld b,a
+  and 7
+  srl b \ srl b \ srl b
+  inc b \ inc a
+;b = 2; a = 1
+  ld c,a
+  ld a,7Fh
+_:
+  rlca
+  djnz -_
+  out (1),a
+  ld b,c
+  ld a,80h
+_:
+  rlca
+  djnz -_
+  ld c,a
+  in a,(1)
+  and c
+CheckKey_End:
+  ld c,b
+  ret nz
+  inc c
+  ret
+check_for_ON_key:
+  in a,(4)
+  and 8
+  ld bc,0
+  ret nz
+  inc c
+  ret
+
+GetKeyDebounce:
+  ei
+  halt
+  call GetKey
+  ld hl,k_save
+  cp (hl)
+  jr nz,newkeypress
+;if the keys match, decrement k_count
+  inc hl
+  dec (hl)
+  jr z,+_
+  xor a
+  ret
+_:
+  inc hl
+  ld a,(hl)
+  sub K_DELAY_ACCEL+1
+  jr nc,+_
+  xor a
+_:
+  inc a
+  ld (hl),a
+  dec hl
+  ld (hl),a
+  dec hl
+  ld a,(hl)
+  ret
+newkeypress:
+  ld (hl),a
+  inc hl
+  ld (hl),K_DELAY_DEFAULT
+  inc hl
+  ld (hl),K_DELAY_DEFAULT
+  ret
+;===============================================================
+GetKey:
+;===============================================================
+;Outputs:
+;     a is a value from 0 to 56 that is the keypress
+;    bc is also the key press
+;     d has a bit reset, the rest are set (this is the last key group tested)
+;     e is a with a mask of %11111000
+;    hl is not modified
+;===============================================================
+  di
+  ld de,$FE00
+  ld a,d
+  out (1),a
+  push af \ pop af
+  in a,(1)
+  ld b,e
+  xor $FF \ jr z,+_
+  ld d,a
+  ld c,16 \ cp 15 \ ret z
+  ld c,5
+  ld a,3 \ and d \ cp 3 \ ret z \ inc c
+  ld a,5 \ and d \ cp 5 \ ret z \ inc c
+  ld a,10 \ and d \ cp 10 \ ret z \ inc c
+  ld a,12 \ and d \ cp 12 \ ret z
+  ld a,d
+  cpl
+  ld c,e
+  jp key_add
+_:
+  ld c,a
+_:
+  rlc d
+  ld a,d
+  out (1),a
+  inc e
+  sub 7Fh
+  jp z,CheckOnPress
+  in a,(1)
+  inc a
+  jr z,-_
+  dec a
+key_add:
+  inc c
+  rra
+  jr c,key_add
+  ld a,e
+  rlca \ rlca \ rlca
+  add a,c
+  ld c,a
+  ret
+CheckOnPress:
+  in a,(4)
+  and 8
+  sub 1
+  sbc a,a
+  and 41
+  ld c,a
+  ret
+ElseToken:
+;Check for an If token, maybe?
+  push bc
+  call FindEndToken
+  ld (parsePtr),hl
+  pop bc
+  pop af
+  ret
+IfToken:
+  push bc
+  call ParseCondition
+  ld a,b
+  or c
+  jr z,+_
+  scf
+_:
+  pop bc
+  ld hl,flags+gflags
+  bit invlogic,(hl)
+  jr z,+_
+  res invlogic,(hl)
+  ccf
+_:
+  ret c
+  ld hl,(parsePtr)
+  inc hl
+  ld a,(hl)
+  push bc
+  cp $CF    ;Then token
+  jr z,nothen
+  call EndOfLine
+_:
+  ld (parsePtr),hl
+  pop bc
+  ret
+nothen:
+
+  call z,FindElseEnd
+  cp $D0  ;Check if it was an Else token
+  jr nz,-_
+  ld (parsePtr),hl
+  pop bc
+  jp ParserNext
+VarToken:
+  call VarP
+  ld (parsePtr),de
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  ex de,hl
+  ld a,(hl)
+  inc hl
+  call VarP
+  ret nc
+  ld (parsePtr),de
+  ld e,c
+  ld d,b
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  set FactorialFlag,(iy+InternalFlag)
+  ret
+ParseNextFullArg_Buffer:
+;Input: z flag
+;Result:
+;  z  : Parse the next argument, result in BC
+;  nz : Returns BC as the pointer to the main buffer
+  ld bc,(BufPtr)
+  call z,ParseNextFullArg
+  ld (gbuf_temp),bc
+  ret
+ParseNextFullArg:
+  ld hl,(parsePtr)
+ParseNextFullArg_Inc:
+  inc hl
+ParseNextFullArg_HL:
+  ld (parsePtr),hl
+ParseFullArg:
+  bit FactorialFlag,(iy+InternalFlag)
+  jr nz,+_
+  ld de,0
+_:
+  res FactorialFlag,(iy+InternalFlag)
+  ld hl,(parsePtr)
+  ld a,(hl)
+  call EndOArg
+  ret z
+  cp 29h
+  ret z
+  call ParseArg
+  jr ParseFullArg
+ParseCondition:
+  call ParseArg
+  ld hl,(parsePtr)
+  ld a,3Fh
+  cp (hl)
+  jr nz,ParseCondition
+  ret
+GetNextVarNum:
+  inc hl
+  ld a,(hl)
+  cp $AE
+  jr nz,+_
+  set Mod2nd,(iy+InternalFlag)
+  ret
+_:
+  sub 3Ah
+  add a,10
+  ret nc
+  ld a,d
+  add a,a
+  add a,a
+  add a,d
+  add a,a
+  ld d,a
+  ld a,(hl)
+  and 15
+  add a,d
+  ld d,a
+  jr GetNextVarNum
+StoString:
+  ld e,a
+  ld d,(hl)
+  inc d
+  call GetNextVarNum
+  dec d
+  ld (parsePtr),hl
+  ld h,b
+  ld l,c
+  push bc   ;Data in Grammer prg
+  push de   ;D= Str Nr; E=AA
+  call GetGrammerStr
+  pop hl
+  bit Mod2nd,(iy+InternalFlag)
+  jr z,+_
+  inc bc
+_:
+  push bc
+  ld b,h
+  ld c,l
+  ld (OP1+1),hl
+  xor a
+  ld (OP1+3),a
+  ld (OP1+1),bc
+  rst rFindSym
+  jr c,+_
+;HL = pointer to the variable's Symbol Table entry
+;DE = pointer to the variable's data structure
+;B  = 0 for Ram, or Flashpage
+;OP1=.db StrngObj,tVarStrng,tStr1,0,0; not all n�tig
+  bcall(_DelVarArc)
+_:
+  pop hl  ;length
+  push hl
+  bcall(_CreateStrng)
+  inc de
+  inc de
+  pop bc
+  pop hl
+  ldir
+  bit Mod2nd,(iy+InternalFlag)
+  ret z
+  res Mod2nd,(iy+InternalFlag)
+  dec de
+  ld a,3Fh
+  ld (de),a
+  ret
+StoDisp:
+  ld (parsePtr),hl
+  ld h,c
+  ld l,c
+  ld a,c
+  cp 16
+  jr nc,+_
+  inc c
+  dec c
+  jr z,+_
+  ld l,%10101010
+  dec c
+  jr z,+_
+
+setgray4:
+  ld hl,%0000001011011011     ;H is 2
+_:
+  ld (graymask),hl
+  ret
+StoToken:
+  ld a,(hl)
+  inc hl
+  cp $AA \ jp z,StoString
+  cp $DC \ jp z,StoInput
+  cp $DE \ jr z,StoDisp
+  cp $01 \ jp z,StoModule
+  cp $3A \ jr z,StoFloat
+  cp $2C \ jr nz,NotOSVar
+;Save Grammer's Ans
+  push bc
+
+;Make sure it is a valid name
+  ld a,(hl)
+  cp 72h    ;Ans
+  jr z,+_
+  cp 'A'
+  jp c,ErrBadTOken
+  cp 'Z'+2
+  jp nc,ErrBadTOken
+_:
+
+;It is valid, so update parsePtr
+  inc hl
+  ld (parsePtr),hl
+
+;Now write the name to OP1
+
+  ld (OP1+1),a
+  ld hl,0
+  ld (OP1+2),hl
+
+;Convert BC to a float in OP2
+  ld h,b
+  ld l,c
+  bcall(_SetXXXXOP2)
+
+;Find the var
+  rst rFindSym
+  jr c,create_OS_real
+
+;If it is a non-real, delete it and create it as a real var
+  and $1F
+  jr nz,delete_create_OS_real
+
+;If it is archived, just delete it and start anew
+  or b
+  jr z,sto_real
+delete_create_OS_real:
+  bcall(_DelVarArc)
+create_OS_real:
+  bcall(_CreateReal)
+
+sto_real:
+;Copy OP2 to the number
+  ld hl,OP2
+  call mov9
+
+;restore Grammer's Ans
+  pop bc
+  ret
+
+NotAVar:
+  ld (parsePtr),hl
+  ret
+StoFloat:
+  ld a,(hl)
+  call VarP
+  jr nc,NotAVar
+  ld (parsePtr),de
+  ld e,(hl)
+  inc hl
+  ld d,(hl)
+  ld h,b
+  ld l,c
+  jp mov4_page0
+NotOSVar:
+  call VarP
+  jr nc,NotAVar
+
+  push hl
+  push bc
+  ld bc,stack_base
+  or a
+  sbc hl,bc
+  add hl,bc
+  pop bc
+  jr nz,+_
+  ld (stack_ptr),bc
+_:
+  ld a,(de)
+  ex de,hl
+  inc hl
+  call VarP
+  jr c,+_
+  dec hl
+  ex de,hl \ pop hl
+_:
+  ld (hl),c
+  inc hl
+  ld (hl),b
+  ld (parsePtr),de
+  ret nc
+  pop hl
+  ld de,(ThetaPrimeVar)
+  ld (hl),e
+  inc hl
+  ld (hl),d
+  ret
+StoModule:
+  inc hl
+  ld (parsePtr),hl
+  ld hl,module_count
+  ld a,(hl)
+  cp 5
+  jp nc,ErrPkgNotFound
+;now should verify the module
+
+  inc (hl)
+  adc a,a
+  add a,l
+  ld l,a
+  ld (hl),c
+  inc hl
+  ld (hl),b
+
+;Check if BC points to the name of a valid module.
+  call GetVarName_BC
+  call GetVarInfo_
+  jp c,module_not_found
+  call GetVarInfoVarFound
+
+  push hl
+  ld hl,verify_package
+  ld (next_page_call_address),hl
+  pop hl
+  call next_page_call
+  ret nc
+  jp module_not_found
+
+StoInput:
+  ld a,(hl)
+  cp $AE
+  jr z,sto_input_size
+  ld (parsePtr),hl
+  ld (input_base),bc
+  ret
+sto_input_size:
+  inc hl
+  ld (parsePtr),hl
+  ld (input_size),bc
+  ret
+Return:
+  call EndOfLine
+  ld c,l
+  ld b,h
+  ret
+
+GotoToken:
+  push bc
+  call ParseFullArg
+  ld (parsePtr),bc
+  pop bc
+  ret
+DispGraph:
+  ld a,(hl)
+  call EndOArg
+  call nz,isop
+  jp z,GraphToLCD
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  ld ixh,b
+  ld ixl,c
+  jp BufferToLCD
+EndOArg:
+  cp 4 \ ret z  ;->
+EndOArgNotSto:
+  cp 2Bh \ ret z ;,
+EndOfLine_newcol:
+  cp 3Fh \ ret z ;NL
+;  cp 3Ah \ ret z
+  cp 3Eh \ ret z ;:
+  or a
+  ret
+isop:
+  cp $82  ;*
+  ret z
+  cp $83  ;/
+  ret z
+  cp $95  ; nCr
+  cp 1    ;>Frac
+  ret z
+  cp 2    ;>Dec
+  ret z
+  cp $6A
+  ret c
+  cp $72
+  jr nc,+_
+  cp a
+  ret
+_:
+  or a
+  ret
+;===============================================================
+FindEndToken:
+;===============================================================
+;Input:
+;     HL is an address
+;Outputs:
+;     HL points to the byte after the proper End token
+;===============================================================
+  ld b,0
+SearchEnd_inc:
+  inc b
+SearchEndLoop:
+  inc hl
+  ld a,(hl)
+; Make sure it isn't >Nom(
+  cp $BB
+  jr nz,+_
+  inc hl
+  ld a,(hl)
+  cp 5
+  jr z,SearchEnd_inc
+  jr SearchEndLoop
+_:
+  call Is_2_Byte
+  jr nz,+_
+  inc hl
+  jr SearchEndLoop
+_:
+  ld a,(hl)
+  sub $CF                  ;Then
+  jr c,SearchEndLoop       ;**Just to save time
+  jr z,SearchEnd_inc
+  dec a
+  dec a \ jr z,SearchEnd_inc   ;While
+  dec a \ jr z,SearchEnd_inc   ;Repeat
+  dec a \ jr z,SearchEnd_inc   ;For
+  dec a \ jr nz,SearchEndLoop ;End
+  djnz SearchEndLoop
+  inc hl
+  ret
+FindElseEnd:
+;Input:
+;     HL is an address
+;Outputs:
+;     HL points to the byte after the proper Else or End token
+;     A is the last token checked
+  ld b,0
+FindElseEnd_:
+  inc b
+FindElseEndLoop:
+  inc hl
+  ld a,(hl)
+; Make sure it isn't >Nom(
+  cp $BB
+  jr nz,+_
+  inc hl
+  ld a,(hl)
+  cp 5
+  jr z,FindElseEnd_
+  jr FindElseEndLoop
+_:
+  call Is_2_Byte
+  jr nz,+_
+  inc hl
+  jr FindElseEndLoop
+_:
+  ld a,(hl)
+  sub $CF           ;Then
+  jr c,FindElseEndLoop
+  jr z,FindElseEnd_ ;Then
+  dec a \ jr z,check_else
+  dec a \ jr z,FindElseEnd_   ;While
+  dec a \ jr z,FindElseEnd_   ;Repeat
+  dec a \ jr z,FindElseEnd_   ;For
+  dec a \ jr nz,FindElseEndLoop
+_:
+  djnz FindElseEndLoop
+  ld a,(hl)
+  inc hl
+  ret
+
+check_else:
+;If this isn't THE `Else`, then we don't want to decrement the counter
+  djnz FindElseEnd_
+  ld a,(hl)
+  inc hl
+  ret
+
+;===============================================================
+GetGrammerText:
+;===============================================================
+;Input:
+;    HL points to the start of the string
+;Outputs:
+;     A is the value of the ending byte of the string
+;    BC is the size of the string
+;    DE points to the start of the converted string
+;    HL points to the ending byte of the string
+;     z flag is set
+;===============================================================
+  ld de,saveSScreen
+GetGrammerText_DE:
+  ld bc,0
+  push de
+TextConvert:
+  ld a,(hl)
+  cp 4   ;->
+  jr z,TextConvertEnd
+  cp 3Fh    ;newline
+  jr z,TextConvertEnd
+  cp 2Ah  ;"
+  jr z,TextConvertEnd
+  call TokToASCII+3
+  jp TextConvert
+  ld de,OP3
+TokToASCII:
+;Inputs:
+;     HL points to the token
+;     DE points to where the token should get converted to
+;Outputs:
+;     HL is incremented
+;     DE points to the byte after the string
+;     BC is the size of the string
+  ld bc,0
+  push hl
+  push bc
+  push de
+  bcall(_Get_Tok_Strng)
+  pop de
+  pop hl
+  add hl,bc
+  push hl
+  ld hl,OP3
+  ldir
+  pop bc
+  pop hl
+  ld a,(hl)
+  call Is_2_Byte
+  inc hl
+  ret nz
+  inc hl
+  ret
+TextConvertEnd:
+  inc hl
+  pop de
+  ret
+;===============================================================
+GetGrammerStr:
+;===============================================================
+;Input:
+;    HL points to the start of the string
+;Outputs:
+;     A is the value of the ending byte of the string
+;    BC is the size of the string
+;    HL points to the ending byte of the string
+;     z flag is set
+;===============================================================
+  ld bc,-1
+;  inc hl
+_:
+  ld a,(hl)
+  inc bc
+  or a \ ret z
+  cp 4 \ ret z
+  cp 3Fh \ ret z
+  inc hl
+  cp 2Ah \ jr nz,-_
+  ret
+VarP:
+  cp $AF    ;? token
+  jr nz,VarPointer
+  ex de,hl
+  scf
+  ld hl,qmarkVar
+  ret
+;===============================================================
+VarPointer:
+;===============================================================
+;Inputs:
+;     A is the var to return the pointer of
+;     hl points to the next byte
+;Outputs:
+;     A is the lower 8-bits of the pointer
+;     BC is not affected
+;     DE should be used to update (parsePtr)
+;     HL points to the var data
+;     c flag is reset if A was not a var token
+  cp $BB
+  jr nz,NotBBvar
+  ld d,h
+  ld e,l
+  ld a,(hl)
+  cp $4B     ;Pmt_End
+  jr z,Pmt_End_ptr
+  cp $4C     ;Pmt_Bgn
+  jr z,Pmt_Bgn_ptr
+  sub 203
+  ret nc
+  sub -16
+  adc a,10
+  cp 26
+  ret nc
+  add a,a
+  ld hl,pvars+54
+  add a,l
+  ld l,a
+#if (pvars+54)&255>=204
+  jr nc,+_
+  inc h
+_:
+#endif
+  inc de
+  scf
+  ret
+Pmt_End_ptr:
+  ld hl,stack_top
+  inc de
+  scf
+  ret
+Pmt_Bgn_ptr:
+  ld hl,stack_base
+  inc de
+  scf
+  ret
+NotBBVar:
+  cp 'A'
+  ccf
+  ret nc
+  cp 'Z'+2
+  ret nc
+  sub 'A'
+  rlca
+  ld d,pvars>>8
+  ld e,a
+  ld a,(hl)
+  cp $AE
+  jr nz,+_
+  ld a,54
+  add a,e
+  ld e,a
+  inc hl
+_:
+  ld a,e
+  add a,pvars&255
+  ld e,a
+#if pvars&255>=202
+  jr nc,+_
+  inc d
+_:
+#endif
+  ex de,hl
+  scf
+  ret
+;===============================================================
+EndOfLine:
+;===============================================================
+;Input:
+;     HL is a pointer
+;Output:
+;     HL points to the next line
+;===============================================================
+  ld a,3Fh
+  push bc
+  ld bc,0
+  cpir
+  pop bc
+  ret
+;===============================================================
+IsHexTok:
+;===============================================================
+;Input:
+;     DE points to the byte
+;Output:
+;     DE is incremented by 1
+;      A is the hex value if A is a hex token
+;     nc if A is a hex token
+;      c if A is not a hex token
+;===============================================================
+  ld a,(de)
+  inc de
+  cp 47h
+  ccf
+  ret c
+  cp 'A'
+  jr nc,+_
+  cp 3Ah
+  ccf
+  ret c
+  .db $DA ;start of jp c,**
+_:
+  sub 7
+  sub 30h
+  ret
+;===============================================================
+ConvRStr:
+;===============================================================
+;Input:
+;     DE points to the base 10 number string in RAM.
+;Outputs:
+;     HL is the 16-bit value of the number
+;     DE points to the byte after the number
+;     BC is HL/10
+;     z flag reset (nz)
+;     c flag reset (nc)
+;Destroys:
+;     A (actually, add 30h and you get the ending token)
+;Size:  41 bytes
+;Speed: 134+(106+{0,9})n
+;       n is the number of digits
+;       c is at most n-2
+;       at most 691 cycles for any 16-bit decimal value
+;===============================================================
+  dec hl
+  bit baseInput,(iy+UserFlags)
+  jp nz,ConvHexStr
+
+  bit floatmode,(iy+ModeFlags2)
+  jr nz,ConvRStr_Float
+
+  ex de,hl
+  ld hl,0
+  push de   ;save in case we encounter a float
+_:
+  ld a,(de)
+  sub 30h
+  cp 10
+  jr nc,+_
+  inc de
+  ld b,h
+  ld c,l
+  add hl,hl
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add a,l
+  ld l,a
+  jr nc,-_
+  inc h
+  jp -_
+_:
+  jr z,+_   ;means it was a decimal point
+  pop bc
+  ld (parsePtr),de
+  ld b,h
+  ld c,l
+  ret
+_:
+  pop hl
+
+ConvRStr_Float:
+  ;HL points to the string
+  dec hl
+  ld a,(hl)
+  cp $B0     ;neg sign token
+  jr nz,+_
+  ;Need to pop off the return address; not returning to the neg routine
+  pop de
+  pop de
+  .db $FE   ;start of cp *, causes the inc hl to be ignored
+_:
+  inc hl
+  ;HL points to the float
+  push hl
+  call floatstackpush
+  ld b,h
+  ld c,l
+  ld hl,str2single
+  ld (next_page_call_address),hl
+  pop hl
+  call next_page_call
+  ld hl,(ptr_sto)
+  ld (parsePtr),hl
+  ret
+SetMem:
+  ld (hl),a
+  ld d,h
+  ld e,l
+  cpi
+  ret po
+  ex de,hl
+  ldir
+  ret
+;===============================================================
+Is_2_Byte:
+;===============================================================
+  cp $EF \ ret z
+  cp $BB \ ret z
+  cp $7E \ ret z
+Is_Var_Name:
+  sub $AA \ ret z     ;AA
+  add a,$47 \ ret z   ;63
+  inc a \ ret z
+  inc a \ ret z
+  inc a \ ret z
+  add a,2 \ ret z
+  inc a \ ret z
+  inc a \ ret
+ConvHexTo86ECh:
+;max: 174n+91
+;min: 128n+56
+;avg: 145.25x+79    (typical avg, assuming most end in newline)
+;An 8x8 sprite is now 6% faster on avg. than versions <2.50
+  ld d,b
+  ld e,c
+  ld hl,86ECh
+  ld bc,$0A30
+ConvHexLoop7:
+;  HL points to where to convert
+;  DE is where to convert from
+  ld a,(de)
+  inc de
+  sub c
+  ret c
+  cp b
+  jr c,+_
+  sub 17
+  ret c
+  cp 6
+  ret nc
+  add a,b
+_:
+  rld
+  ld a,(de)
+  inc de
+  sub c
+  ret c
+  cp b
+  jr c,+_
+  sub 17
+  ret c
+  cp 6
+  ret nc
+  add a,b
+_:
+  rld
+  inc hl
+  jp ConvHexLoop7
+IsConditional:
+  cp $D8 \ ret z      ;pause
+  cp $CE \ ret z      ;if
+  cp $D1 \ ret z      ;while
+  cp $D2 \ ret        ;repeat
+EraseParticle:
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+;pixel off
+  push bc
+  call GetPixelLoc
+  pop bc
+  ret
+isStartMenu_valid:
+  ld a,(OP1+1)
+  cp $23
+  jr z,StartMenu_invalid
+  cp $21
+  jr z,StartMenu_invalid
+  ld hl,(VATPtr)
+  ld a,(hl)
+  cp 1        ;don't want lists
+  jr nz,+_
+StartMenu_invalid:
+  or a
+  ret
+_:
+  cp 13       ;don't want complex lists
+  jr z,StartMenu_invalid
+  cp 17h      ;don't want GroupVars
+  jr z,StartMenu_invalid
+
+  bit 6,(iy+UserFlags)     ;must be AppV
+  jr z,+_
+  cp 15h
+  ret nz
+_:
+;need to pull in six bytes
+#ifdef include_LoadTSA
+  call LoadReadArc
+#endif
+  ld bc,-3
+  add hl,bc
+  ld e,(hl)
+  dec hl
+  ld d,(hl)
+  dec hl
+  ld a,(hl)
+  or a
+  jr z,+_
+  ld b,a
+  dec hl
+  ld a,(hl)
+  add a,10
+  add a,e
+  ld e,a
+  ld a,b
+  jr nc,+_
+  inc d
+  jp po,+_
+  inc a
+  ld d,$40
+_:
+  ex de,hl
+  ld de,cmdShadow
+  ld bc,2
+  call ReadArc
+  ld bc,(cmdShadow)
+  ;need to save A:HL, BC
+  ld (TempWord3),a
+  ld (TempWord4),bc
+  ld (TempWord5),hl
+_:
+  ld bc,4
+  call ReadArc
+  ld hl,cmdShadow+2
+  bit OnBlockFlag,(iy+UserFlags)   ;ASM only
+  jp nz,asm_header_only
+;non-ASM and ASM alike
+  bit baseInput,(iy+UserFlags)
+  ret z   ;doesn't have any special filters
+;must be a Grammer Var
+;header is either $BB,$6D,$55,$C9 or $3A,$30,$3E
+  ld a,(hl) \ cp $BB \ jr z,+_
+  cp $3A \ ret nz
+  inc hl \ ld a,(hl) \ cp $30 \ ret nz
+  inc hl \ ld a,(hl) \ cp $3E \ ret
+_:
+  inc hl \ ld a,(hl) \ cp $6D \ ret nz
+  inc hl \ ld a,(hl) \ cp $55 \ ret nz
+  inc hl \ ld a,(hl) \ cp $C9
+  ret
+asm_header_only:
+;first two bytes must be $BB,$6D
+;
+  ld a,(hl) \ cp $BB \ ret nz
+  inc hl \ ld a,(hl) \ cp $6D \ ret nz
+  bit baseInput,(iy+UserFlags)
+  ret z
+;next two bytes must be $55,$C9
+;
+  inc hl \ ld a,(hl) \ cp $55 \ ret nz
+  inc hl \ ld a,(hl) \ cp $C9
+  ret
+
+#ifdef include_LoadTSA
+ReadArc:
+  call LoadReadArc
+  jp TSA
+#else
+ReadArc = TSA
+#endif
+ReadArcData:
+#ifdef include_loadTSA
+  .dw ReadArcEnd-ReadArc-2
+#endif
+#include "readarc.z80"
+ReadArcEnd:
+FindGVarData:
+  ld hl,GVarData
+  rst rMov9ToOP1
+  bcall(_ChkFindSym)
+  ret nc
+  ld hl,3
+  bcall(_CreateAppVar)
+  ret
+GetVarName:
+  call ParseFullArg
+GetVarName_BC:
+  ld h,b
+  ld l,c
+GetVarName_:
+  ld a,(hl)
+  and 1Fh
+  ld de,OP1
+  sub 5 \ jp z,GetGrammerText_DE
+  dec a \ jp z,GetGrammerText_DE
+  sub 15 \ jp z,GetGrammerText_DE
+  dec a \ jp z,GetGrammerText_DE
+  ld bc,3
+  ld d,h \ ld e,l
+  add hl,bc
+  cp a
+  ret
+GetVarInfo:
+;Returns name in OP1
+;A is the flashpage
+;HL points to SymEntry
+;DE points to size bytes
+;BC is the length of the name (for use when finding archived data)
+;nc if it exists
+;z if it is in RAM
+  call GetVarName
+GetVarInfo_:
+  ex de,hl
+  ld de,OP1
+  push bc
+  ldir
+  xor a
+  ld (de),a
+  bcall(_ChkFindSym)
+  ld a,b
+  pop bc
+  ret c
+  or a
+  ret
+GetvarInfo2:
+;Inputs:
+;     The next argument to parse points to the name of the var to get info about
+;Outputs:
+;     A is the ending page (start of data)
+;     BC is the size of the var
+;     DE points to the SymEntry
+;     HL points to the data
+;     c is set if the var does not exist
+#ifdef include_LoadTSA
+  call LoadReadArc
+#endif
+  call GetVarInfo
+  ret c
+GetVarInfoVarFound:
+  ex de,hl
+  or a
+  jr nz,+_
+  ld c,(hl) \ inc hl
+  ld b,(hl) \ inc hl
+  ret
+_:
+  add hl,bc
+  ld c,9
+  add hl,bc
+  bit 7,h
+  jr z,+_
+  ld h,40h
+  inc a
+_:
+  push de
+  ld de,OP2
+  ld bc,2
+  call ReadArc
+  ld bc,(OP2)
+  pop de
+  or a
+  ret
+
+GPutSI:
+;     The string to display immediately follows the call
+;       The string is zero terminated
+;Outputs:
+;     All registers are preserved
+  ex (sp),hl
+  push de
+  push bc
+  push af
+  call GPutS
+  pop af
+  pop bc
+  pop de
+  ex (sp),hl
+  ret
+
+DrawRectToGraphI:
+  ex (sp),hl
+;  push de \ push bc \ push af
+  ld e,(hl) \ inc hl
+  ld c,(hl) \ inc hl
+  ld b,(hl) \ inc hl
+  ld d,(hl) \ inc hl
+  ld a,(hl) \ inc hl
+  ex (sp),hl
+  jp DrawRectToGraph
+ExecLine_:
+  ld a,(hl)
+  inc hl
+  call VarP
+  ret nc
+parse_by_ptr_to_ptr:
+  push de
+  push hl
+  ld a,(hl)
+  inc hl
+  ld h,(hl)
+  ld l,a
+  call ParseNextFullArg_HL
+  ld de,(parsePtr)
+  pop hl
+  inc de
+  ld (hl),e
+  inc hl
+  ld (hl),d
+  pop hl
+  ld (parsePtr),hl
+  ret
+ExecLine:
+  call ParseFullArg
+  push bc
+  cp 2Bh
+  ld bc,(ProgStart)
+  call z,ParseNextFullArg
+  push bc
+  ld bc,32768
+  cp 2Bh
+  call z,ParseNextFullArg
+  push bc
+  cp 2Bh
+  ld bc,63
+  call z,ParseNextFullArg
+  ld a,c
+  pop bc
+  pop hl
+  pop de
+  call SearchLine_00
+  ld b,d
+  ld c,e
+  jp g_expr
+Byte:
+  ld b,0
+  ld c,(hl)
+  inc hl
+  ld (parsePtr),hl
+  ret
+Word:
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+  ld (parsePtr),hl
+  ret
+NegRelPtr:
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+  ld (parsePtr),hl
+  ld hl,(progEnd)
+  or a
+  sbc hl,bc
+  ld b,h
+  ld c,l
+  ret
+Base2Num:
+  ld bc,0
+  ld d,b
+  ld e,c
+_:
+  ld a,(hl)
+  sub '2'
+  add a,2
+  jr nc,+_
+  rrca
+  rl c
+  rl b
+  rl e
+  rl d
+  inc hl
+  jp -_      ;It saves 2 cycles using JP D:
+_:
+  set FactorialFlag,(iy+InternalFlag)
+  ld (parsePtr),hl
+  ret
+_:
+  ld hl,lnSingle
+  jp float_stepin_1
+LnToken:
+  ld a,(hl)
+  cp 3Ah
+  jr z,-_
+  cp $B0
+  push bc
+  jr z,JumpBack
+  call ParseFullArg
+  dec bc
+  inc b
+  inc c
+  ld d,b \ ld e,c
+  ld bc,0
+_:
+  ld a,3Fh
+  cpir
+  dec e
+  jr nz,-_
+  dec d
+  jr nz,-_
+  ld (parsePtr),hl
+  pop bc
+  ret
+JumpBack:
+  call ParseNextFullArg
+  inc b
+  inc c
+  ld d,b \ ld e,c
+  dec hl
+  ld bc,0
+_:
+  ld a,3Fh
+  cpdr
+  dec e
+  jr nz,-_
+  dec d
+  jr nz,-_
+  ld (parsePtr),hl
+  pop bc
+  ret
+cmdJmp:
+#ifdef ALIGN_COMMAND_TABLE
+  ld h,CommandJumpTable>>8
+  add a,a
+  jr nc,+_
+  inc h
+_:
+  ld l,a
+#else
+  ld hl,CommandJumpTable
+  add a,a
+  jr nc,+_
+  inc h
+_:
+  add a,l
+  ld l,a
+  jr nc,+_
+  inc h
+_:
+#endif
+  ld a,(hl)
+  inc hl
+  ld h,(hl)
+  ld l,a
+  push hl
+  ld hl,(parsePtr)
+  ret
+menu:
+  ld hl,menu_code_start
+  ld (next_page_call_address),hl
+  jp next_page_call
+
+
+pushvars_00:
+  ld de,pushvars
+  ld (next_page_call_address),de
+  jp next_page_call
+
+FracToken_00:
+  ld de,FracToken
+  ld (next_page_call_address),de
+  jp next_page_call
+
+ParamToken_00:
+  ld de,ParamToken
+  ld (next_page_call_address),de
+  jp next_page_call
+
+LblToken:
+  ld hl,LblToken_01
+  ld (next_page_call_address),hl
+  jp next_page_call
+
+FS_createvar_max:
+  push hl
+  ld hl,FS_createvar_max_01
+  jr jp_next_page_call
+
+FS_delvar:
+  push hl
+  ld hl,FS_delvar_01
+  jr jp_next_page_call
+
+FS_resize:
+  push hl
+  ld hl,FS_resize_01
+  jr jp_next_page_call
+
+FS_findvar:
+  push hl
+  ld hl,FS_findvar_01
+  jr jp_next_page_call
+
+SearchString:
+  push hl
+  ld hl,searchstring_routine
+  jr jp_next_page_call
+
+SearchLine_00:
+  push hl
+  ld hl,SearchLine
+  jr jp_next_page_call
+
+DrawRectToGraph:
+  push hl
+  ld hl,drawrect
+jp_next_page_call:
+  ld (next_page_call_address),hl
+  pop hl
+  jp next_page_call
+
+DegreeToken:
+  call ParseFullArg
+  ld (gbuf_temp),bc
+  inc hl
+  jp ParseArg2
+
+todectoken:
+;Takes a pointer to a string and converts it to a float
+  ld hl,str2single
+  ld (next_page_call_address),hl
+  push bc
+  call floatstackpush
+  ld b,h
+  ld c,l
+  pop hl
+  jp next_page_call
+InputToken:
+  ld de,s_null
+  ld a,(hl)
+  call EndOArg
+  call nz,isop
+  jr z,+_
+  call ParseFullArg
+  ld h,b
+  ld l,c
+  ld de,OP1
+  call GetGrammerText_DE
+  ld h,b
+  ld l,c
+  add hl,de
+  ld (hl),0
+_:
+  ld hl,input
+  ld (next_page_call_address),hl
+  call next_page_call
+  ld b,h
+  ld c,l
+  ret
+
+GraphToLCD:
+  ld hl,GraphToLCD_
+  ld (next_page_call_address),hl
+  jp next_page_call
+
+BufferToLCD:
+  ld ix,BufferToLCD_
+  ld (next_page_call_address),ix
+  jp next_page_call
+
+#include "main.z80"
+#include "module.z80"
+#include "ramcode.z80"
+#include "routines.z80"
+#include "SetUpData.z80"
+#include "parserhook.z80"
+#include "cmd/particle.z80"
+#ifdef include_LoadTSA
+#include "cmd/loadtsa.z80"
+#endif
+#include "gfx/text.z80"
+#include "gfx/getpixelloc_nobound.z80"
+#include "gfx/GetPixelLoc.z80"
+#include "gfx/TileMap1.z80"
+#include "math/mul16.z80"
+#include "math/HL_Div_C.z80"
+#include "math/DEHL_Div_C.z80"
+#include "math/HL_Div_BC.z80"
+#include "subroutines/getbyte.z80"
+#include "grammerdata.z80"
+#include "math.z80"
+#include "subroutines/chardim.z80"
+#include "subroutines/ConvOP1.z80"
+#include "parserinterrupt.z80"
+#include "err.z80"
+#include "commandtable.z80"
+
+.echo "Page 0: ",$8000-$," bytes remaining"
+
+#if $>$8000
+.error "ERR!! Page 1 is over by ",$-$8000," bytes!"
+#else
+.fill $8000-$,255
+#endif
+#include "01.z80"
+
+
+.echo "RamCode : ",RamCodeEnd-RamCodeStart

+ 225 - 0
src/grammer2.5.inc

@@ -0,0 +1,225 @@
+;===============================================================================
+; Useful TI-OS Equates
+;===============================================================================
+#define bcall(x) rst 28h \ .dw x
+#define rMov9ToOP1    20h
+#define rFindSym    10h
+
+_FindAlphaDn    = 4A47h
+_FindAlphaUp    = 4A44h
+_RclAns         = 4AD7h
+_ChkFindSym     = 42F1h
+_DispHL         = 4507h
+_CreateTempStr  = 4324h
+_SetParserHook  = 5026h
+_CreateVar      = 4E70h
+_CreateAppVar   = 4E6Ah
+_CreatePict     = 4333h
+_EnoughMem      = 42FDh
+_InsertMem      = 42F7h
+_Get_Tok_Strng  = 4594h
+_DelMem         = 4357h
+_JForceCmdNoChar= 4027h
+_JError         = 44D7h
+_DelVarArc      = 4FC6h
+_CreateStrng    = 4327h
+_CreateReal     = 430Fh
+_SetXXXXOP2     = 4792h
+_Arc_Unarc      = 4FD8h
+_ConvKeyToTok   = 4A02h
+_GetKeyRetOff   = 500Bh
+_RunIndicOff    = 4570h
+_DeleteTempPrograms = 5041h
+_MemChk         = 42E5h
+_clrTxtShd      = 454Ch
+_saveCmdShadow  = 4573h
+_PutS           = 450Ah
+_OP5ToOP1       = 413Bh
+_OP1ToOP5       = 4153h
+_VPutMap        = 455Eh
+_Load_LFontV    = 806Fh
+_SFont_Len      = 4786h
+appErr1         = 984Dh
+appErr2         = 985Ah
+cxErrorEP       = 8595h
+curRow          = 844Bh
+curCol          = 844Ch
+kbdScanCode     = 843Fh
+basic_prog      = 9652h
+progStart       = 965Bh
+parsePtr        = 965Dh
+progEnd         = 965Fh
+parserHookPtr   = 9BACh
+tokenHookPtr    = 9BC8h
+OP1             = 8478h
+OP2             = 8483h
+OP3             = 848Eh
+OP4             = 8499h
+OP5             = 84A4h
+OP6             = 84AFh
+flags           = 89F0h
+saveSScreen     = 86ECh
+textShadow      = 8508h
+plotSScreen     = 9340h
+progPtr         = 9830h
+FPS             = 9824h
+OPS             = 9828h
+smallEditRAM    = 90D3h  ;108 bytes
+iMathPtr1       = 84D3h  ;10 bytes
+iMathPtr2       = 84D5h
+iMathPtr3       = 84D7h
+iMathPtr4       = 84D9h
+iMathPtr5       = 84DBh
+asm_data_ptr1   = 84EBh
+asm_data_ptr2   = 84EDh
+cmdShadow       = 966Eh  ;128 bytes
+pTemp           = 982Eh  ;bottom of named vars VAT
+appBackUpScreen = 9872h
+ramCode         = 8100h
+tempSwapArea    = 82A5h
+penCol          = 86D7h
+penRow          = 86D8h
+lFont_record    = 845Ah
+
+;==============================
+;Flags
+;==============================
+CursorFlags     = 12
+CursorActive    =   3
+
+onFlags         = 9        ;on key flags
+onInterrupt     =   4      ;1=on key interrupt request
+
+curFlags        = 12       ;Cursor
+fmtEdit         =   0      ;1=format number for editing
+curAble         =   2      ;1=cursor flash is enabled
+curOn           =   3      ;1=cursor is showing
+curLock         =   4      ;1=cursor is locked off
+cmdVirgin       =   5      ;1=nothing has been typed in cmd bfr
+;----------------------------------------------------------------------
+indicFlags        = 18         ;Indicator flags
+indicRun          =   0        ;1=run indicator ON
+shiftFlags        = 18         ;[2nd] and [ALPHA] flags
+shift2nd          =   3        ;1=[2nd] has been pressed
+shiftAlpha        =   4        ;1=[ALPHA] has been pressed
+shiftLwrAlph      =   5        ;1=lower case, 0=upper case
+shiftALock        =   6        ;1=alpha lock has been pressed
+shiftKeepAlph     =   7        ;1=cannot cancel alpha shift
+
+sGrFlags          = 14h
+textWrite         = 7
+
+fontFlags         = 32h
+fracDrawLFont     = 2
+
+hookflags3        = 35h
+tokenHookActive   = 0		;1 = token hook active
+fontHookActive    = 5		;1 = font hook active
+hookflags4        = 36h ;also sysHookFlag2
+parserHookActive  = 1		;1 = parser hook active
+
+appLwrCaseFlag    = 24h
+lwrCaseActive     = 3
+
+;===============================================================================
+
+
+
+;===============================================================================
+; Grammer Equates
+;===============================================================================
+#define MODULE_VERSION 3
+moduleExec      = saveSScreen
+gbuf            = plotSScreen
+pvars           = smallEditRAM
+ThetaPrimeVar   = pvars+106
+TempWord1   = OP6-1       ;2       2
+TempWord2   = TempWord1+2 ;2       4
+TempWord3   = TempWord2+2 ;2       6
+TempWord4   = TempWord3+2 ;2       8
+TempWord5   = TempWord4+2 ;2      10
+textRow     = TempWord5+2 ;1      11
+textCol     = textRow+1   ;1      12
+
+g_ram       = 8020h
+
+FS_begin  = iMathPtr4
+FS_end    = FS_begin+2
+
+BufPtr      = g_ram        ;2
+GrayBufPtr  = BufPtr+2     ;2
+gbuf_temp   = GrayBufPtr+2 ;2
+FontPointer = gbuf_temp+2  ;2
+font_ptr_page=FontPointer+2;1
+g_internal  = font_ptr_page+1
+Ans         = appErr2      ;2
+
+
+;==============================
+; Grammer Flags
+;==============================
+InternalFlag    = 33
+SlowTextFlag    =   0
+IntActiveFlag   =   1
+FactorialFlag   =   2
+errorChecking   =   3
+grayFlag        =   4   ;this determines the checker pattern for the next gray object drawn
+bit32           =   5   ;This determines if the output was 32-bit or not
+Mod2nd          =   6
+nogrampkg       =   7   ;This determines the checker pattern for grayscale mode
+
+UserFlags       = 34
+InvertTextFlag  =   0
+InvertLCDFlag   =   1
+OnBlockFlag     =   2
+baseInput       =   3
+pxlBoundsRes    =   4
+SignedText      =   5
+;    =   6
+;    =   7
+
+ParticleFlag    = 35
+Xis0            = 0
+Xis95           = 1
+Yis0            = 2
+Yis63           = 3
+OffScrn         = 4
+
+InternalFlag2   = 35
+inputflag       = 0
+
+ModeFlags2      = 35
+floatmode       = 5
+
+
+FS_uint8        = 0
+FS_str          = 3
+FS_array        = 4
+;===============================================================================
+; Grammer Jump Table
+;===============================================================================
+#ifndef NO_JUMP_TABLE
+cmdJmp              = $4023
+ProgramAccessStart  = $4026
+CompatCall          = $4029
+SelectedProg        = $402C
+ExecOP1             = $402F
+ParseFullArg        = $4032
+ParseNextFullArg    = $4035
+ParseNextFullArg_Inc= $4038
+ParseCondition      = $403B
+DrawRectToGraph     = $403E
+GraphToLCD          = $4041
+VPutSC              = $4044
+GetKey              = $4047
+GetGrammerText      = $404A
+GetGrammerText_DE   = $404D
+GetGrammerStr       = $4050
+GetKeyDebounce      = $4053
+SearchString        = $4056
+FS_createvar_max    = $4059
+FS_delvar           = $405C
+FS_resize           = $405F
+FS_findvar          = $4062
+ErrMem              = $4065
+#endif

+ 51 - 0
src/grammerdata.z80

@@ -0,0 +1,51 @@
+sinTable:
+.db 0,3,6,9,13,16,19,22,25,28,31,34,37,40,43,46
+.db 49,52,55,58,60,63,66,68,71,74,76,79,81,84,86,88
+.db 91,93,95,97,99,101,103,105,106,108,110,111,113,114,116,117
+.db 118,119,121,122,122,123,124,125,126,126,127,127,127,128,128,128
+StrVersion:
+ .db "Grammer v2.50.9.6",0
+FrequencyLUT:
+.dw 2508,2367,2234,2109,1990,1879,1773,1674,1580,1491,1407,1328
+.dw 1254,1184,1117,1054,995,939,887,837,790,746,704,664
+.dw 627,592,559,527,498,470,443,418,395,373,352,332
+.dw 313,296,279,264,249,235,222,209,197,186,176,166
+.dw 157,148,140,132,124,117,111,105,99,93,88,83
+.dw 78,74,70,66,62,59,55,52,49,47,44,42
+.dw 39,37,35,33,31,29,28,26,25,23,22,21
+.dw 20,18,17,16,16,15,14,13,12,12,11,10
+
+FontSet:
+;fixed-width font
+#include "fonts/ffont.asm"
+
+vFont:
+;variable-width font
+#include "fonts/vfont.asm"
+
+float_pi:     .db $DB,$0F,$49,$81
+float_e:      .db $54,$f8,$2d,$81
+GramTempName:
+ .db 16h,"GramTemp"
+GVarData:
+ .db 15h,"GVarData"
+StrMirage:
+ .db "MirageOS prg",0
+StrION:
+ .db "ION program",0
+StrDCS:
+ .db "DCS program",0
+StrGram:
+  .db "Broken Shell",0
+s_PkgNotFound:
+  .db "PkgNotFound",0
+s_StackOverflow_pop:
+s_StackOverflow_push:
+  .db "StackOverflw",0
+#ifndef INCLUDE_GRAMPKG
+s_grampkg: .db 15h,"Grampkg",0
+#endif
+s_appv:    .db "appv",0
+s_prog:    .db "prgm"
+s_null:
+  .db 0

+ 10 - 0
src/grampkg.z80

@@ -0,0 +1,10 @@
+;All routines must be 768 bytes or less
+;They get copied to saveSScreen
+#ifndef EXCLUDE_GRAMPKG_INC
+#include "grammer.inc"
+#include "grammer2.5.inc"
+#endif
+  .db "Gram"
+  .dw MODULE_VERSION    ;minimum version
+  .dw (+_-2-$)/2
+_:

+ 42 - 0
src/interrupt.z80

@@ -0,0 +1,42 @@
+; Grammer's Interrupt Service Routine (ISR)
+Interrupt:
+  push af
+  push bc
+  push de
+  push hl
+  in a, (4)
+  cpl
+  out (3),a
+  cpl
+  out (3),a
+
+  rra     ;bit 0
+  call c,interruptON
+  rra     ;bit 1
+  call c,interruptTimer1
+  rra     ;bit 2
+  call c,interruptTimer2
+  rra     ;bit 3
+  rra     ;bit 4
+;    call c,interruptLink
+  call getKey_interrupt
+
+;  bit inthook,(iy+34)
+;  call z,gHook
+  pop hl
+  pop de
+  pop bc
+  pop af
+  ei
+  ret
+;gHook:
+;runs the Grammer code set to interrupt
+;  ret
+interruptON:
+  ret
+interruptTimer1:
+  ret
+interruptTimer2:
+  ret
+getKey_interrupt:
+  ret

+ 161 - 0
src/io/getKeyChar.z80

@@ -0,0 +1,161 @@
+getKeyChar:
+;converts a key press to a char
+;returns c flag set if not a valid key
+    cp 54 \ jr nz,+_
+    ;If previous state was [2nd], set normal, else set [2nd]
+    ld a,(keyflags+flags)
+    res shift,(iy+keyflags)
+    res alpha,(iy+keyflags)
+    and 3
+    dec a
+    scf
+    ret z
+    set shift,(iy+keyflags)
+    ret
+_:
+    cp 48 \ jr z,mod_alpha
+    sub 1
+    ret c
+    bit alpha,(iy+keyflags)
+    jr nz,chkalphakey
+    cp 47
+    ccf
+    ret c
+    bit shift,(iy+keyflags)
+    res shift,(iy+keyflags)
+    ld hl,shiftkeyLUT
+    jr nz,+_
+    ld hl,regkeyLUT
+_:
+    add a,l
+    ld l,a
+    jr nc,+_
+    inc h
+_:
+    ld a,(hl)
+    sub 1
+    ret
+chkalphakey:
+;either uppercase or lowercase
+    call toAlpha
+    ret c
+
+    bit shift,(iy+keyflags)
+    jp z,mod_reset
+    call mod_reset
+    cp 'Z'+1
+    ret z
+    cp 22h \ jr nz,+_ \ ld a,27h \ ret
+_:
+    cp '?' \ jr nz,+_ \ ld a,'!' \ ret
+_:
+    cp ' ' \ jr nz,+_ \ ld a,$EE \ ret    ;EE is triple space
+_:
+    cp ':' \ jr nz,+_ \ ld a,';' \ ret
+_:
+    add a,20h
+    ret
+mod_alpha:
+    ld a,(keyflags+flags)
+    ;if previous state was [ALPHA], switch to [alpha]
+    ;If previous state was [alpha], switch to normal
+    ;If previous state was [2nd], set the holdmod bit and set [ALPHA]
+    and $FC
+    ld b,a
+    ld a,(keyflags+flags)
+    and 3
+    jr nz,+_
+    set alpha,b
+_:
+    dec a
+    jr nz,+_
+    set holdmod,b
+    set alpha,b
+_:
+    dec a
+    jr nz,+_
+    set shift,b
+    set alpha,b
+_:
+    ld a,b
+    ld (flags+keyflags),a
+    scf
+    ret
+toAlpha:
+    cp 9
+    ret c
+    jr nz,+_
+    ld a,22h
+    ret
+_:
+    cp 47
+    ccf
+    ret c
+    ld c,a
+    cpl
+    and 7
+    ld b,a
+    rla
+    rla
+    add a,b
+    srl c
+    srl c
+    srl c
+    sub c
+    cp 3
+    jr c,+_
+    cp 5
+    ret c
+    sub 2
+_:
+    cp 27
+    ret z
+    jr nc,+_
+    add a,'A'
+    ret
+_:
+    sub 29
+    jr nz,+_
+    ld a,' '
+    ret
+_:
+    dec a
+    jr nz,+_
+    ld a,':'
+    ret
+_:
+    ld a,'?'
+    ret
+mod_reset:
+  bit holdmod,(iy+keyflags)
+  ret nz
+  res shift,(iy+keyflags)
+  res alpha,(iy+keyflags)
+  ret
+
+regKeyLUT:
+.db $20,0,0,$1F     ;down,left,right,up
+.db 0,0,0,0,$D7
+.db $2C,$2E,$2B,$30,$5F   ;+-*/^
+.db 0,0
+.db $1B,$34,$37,$3A,$2A   ;neg369)
+.db 0,0,0
+.db $2F,$33,$36,$39,$29   ;.258(
+.db 0,0,0
+.db $31,$32,$35,$38,$2D   ;0147,
+.db 0,0,0,0
+.db $1D          ;sto
+.db 0,0
+.db $13,$12           ;sqrd, inv
+
+shiftKeyLUT:
+.db $08,$D0,$06,$07
+.db 0,0,0,0,0,$61
+.db $5E,$C2,$DC,$C5
+.db 0,0,0,0,0
+.db $05,$7D
+.db 0,0,0
+.db $D8,0,0,$04,$7C
+.db 0,0,$DD
+.db $60,0,0,$03,$1C,0,$14,0
+.db 0,0,0,$1E,$11,$17

+ 167 - 0
src/io/getKeyTok.z80

@@ -0,0 +1,167 @@
+getKeyTok:
+;converts a key press to a token
+;Takes key value in A
+;returns DE as token, c flag set if not a valid key else nc.
+
+;Check mod tokens
+;Check [2nd]
+    cp 54 \ jr nz,+_
+    ;If previous state was [2nd], set normal, else set [2nd]
+    ld a,(keyflags+flags)
+    res shift,(iy+keyflags)
+    res alpha,(iy+keyflags)
+    and 3
+    dec a
+    scf
+    ret z
+    set shift,(iy+keyflags)
+    ret
+_:
+
+;Check [Alpha]
+    cp 48 \ jp z,mod_alpha
+
+;Any other keys bigger should return c
+    ccf
+    ret c
+
+;Check for no key pressed, or arrows
+    sub 9
+    ret c
+
+;If [ALPHA] or [alpha] mode, check those LUTs
+    bit alpha,(iy+keyflags)
+    jr nz,chkalphakey_tok
+
+;Else we have normal or [shift] mode
+;Check if shift or normal, reset either way
+    bit shift,(iy+keyflags)
+    res shift,(iy+keyflags)
+
+;get the LUT pointer for the mode
+    ld hl,shiftkeytokLUT
+    jr nz,+_
+    ld hl,regkeytokLUT
+_:
+
+;Now get the offset into the LUT
+    add a,a
+    add a,l
+    ld l,a
+    jr nc,+_
+    inc h
+_:
+
+;Load the value into DE
+    ld e,(hl)
+    inc hl
+    ld d,(hl)
+
+;Return c if output is null
+    ld a,d
+    or e
+    sub 1
+    ret
+
+chkalphakey_tok:
+;either uppercase or lowercase
+    call toAlpha_tok
+    ld e,a
+    ld d,0
+    ret c
+;Get [ALPHA] or [alpha] mode
+    bit shift,(iy+keyflags)
+
+;Do mod_reset. If [ALPHA], no need to modify further so exit
+    jp z,mod_reset
+    call mod_reset
+
+
+    cp 'Z'+1
+    ret nc
+    cp 2Ah \ jr nz,+_ \ ld e,$AE \ ret    ;Quote --> apostrophe
+_:
+    cp $AF \ jr nz,+_ \ ld e,$2D \ ret    ;? --> !
+_:
+    cp $3E \ jr nz,+_ \ ld de,$BBD6 \ ret    ;: --> ;
+_:
+    cp $29 \ jr nz,+_ \ ld de,$BBD9 \ ret    ;space --> underscore
+_:
+    cp 'A'
+    ccf
+    ret nc
+    ld d,$BB
+    cp 'L'
+    ccf
+    adc a,$B0-'A'
+    ld e,a
+    ret
+toAlpha_tok:
+  or a
+  jr nz,+_
+  ld a,$3F  ;newline
+  ret
+_:
+  cp 1
+  jr nz,+_
+  ld a,2Ah    ;Quote
+  ret
+_:
+;38 -> 0   30->1   22->2
+;37 -> 5   29->6   21->7
+;36 -> 10
+;35 -> 15
+;34 -> 20
+;33 -> 25
+;32 -> 30
+;y=5*((-x-1)&7)-(x>>3) - 1
+; =5*((~x)&7)-(x>>3) - 1
+  ld c,a
+  cpl
+  and 7
+  ld b,a
+  add a,a
+  add a,a
+  add a,b
+  srl c
+  srl c
+  srl c
+  sub c
+  dec a
+  cp 3
+  jr c,+_
+  sub 2
+_:
+    cp 27
+    jr nc,+_
+    add a,'A'
+    ret
+_:
+    sub 29
+    jr nz,+_
+    ld a,29h    ;space token
+    ret
+_:
+    dec a
+    jr nz,+_
+    ld a,$3E    ;Colon token
+    ret
+_:
+    ld a,$AF
+    ret
+
+regKeyTokLUT:
+;.dw 0,0,0,0,0,0,0,0               ;down,left,right,up
+.dw $3F,$70,$71,$82,$83,$F0,0,0   ;Enter,+-*/^
+.dw $B0,$33,$36,$39,$11,$C6,0,0   ;neg369)
+.dw $3A,$32,$35,$38,$10,$C4,0,0   ;.258(
+.dw $30,$31,$34,$37,$2B,$C2,0,0   ;0147,
+.dw $00,$04,$BE,$C0,$0D,$0C,0,0   ;sto
+
+shiftKeyTokLUT:
+;.dw 0,0,0,0,0,0,0,0                    ;down,left,right,up
+.dw $00,$00,$07,$06,$BB31,$AC,0,0       ;Enter,+-*/^
+.dw $72,$5D02,$5D05,$5E82,$09,$C7,0,0   ;neg369)
+.dw $2C,$5D01,$5D04,$5E81,$08,$C5,0,0   ;.258(
+.dw $00,$5D00,$5D03,$5E80,$3B,$C3,0,0   ;0147,
+.dw $00,$00,$BF,$C1,$BC,$00,0,0         ;sto

+ 357 - 0
src/io/input.z80

@@ -0,0 +1,357 @@
+#define CUR_COUNT_RESET 23
+_IsA2ByteTok  = 42A3h
+keyflags    = 35
+shift     = 0
+alpha     = 1
+shiftprev = 2
+alphaprev = 3
+holdmod   = 4
+cursorblink = 7
+
+curcount    = scrap+8
+penTemp     = curcount+1
+textRow_base= penTemp+2
+input_end_text = textRow_base+2
+input_head  = input_end_text+2
+input_top   = input_head+2
+input_curptr= input_top+2
+
+
+input:
+;Inputs: DE points to the ending string
+;Save the location of the ending string
+  ld (input_end_text),de
+
+;Save the text pointer for when we clear input.
+  ld hl,(textRow)
+  ld (textRow_base),hl
+
+;set up the input buffer
+  ld hl,(input_base)
+  ld (input_head),hl
+  ld (input_curptr),hl
+  xor a
+  ld (hl),a
+  ld bc,(input_size)
+  add hl,bc
+  dec hl    ;make room for ending NULL
+  ld (input_top),hl
+
+;Clear the input
+  call input_clear
+
+;clear input mode
+  xor a
+  ld (flags+keyflags),a
+
+;Set text mode to overwrite, but save original settings
+  ld a,(OutputLogic)
+  push af
+  xor a
+  ld (OutputLogic),a
+
+;Clear out any keypresses
+  out (1),a
+_:
+  in a,(1)
+  inc a
+  jr nz,-_
+
+;write 0xFF to the key port to flush
+;  dec a
+;  out (1),a
+
+; ;Save the user flags since we'll be modifying them for text
+;   ld a,(flags+UserFlags)
+;   push af
+
+;Print the current input
+  call inp_dispstr
+
+; ;Restore the user flags
+;   pop af
+;   ld (flags+UserFlags),a
+
+;Restore text coords
+  ld hl,(penTemp)
+  ld (textRow),hl
+
+;Get input
+  call inputloop
+
+;Restore text logic
+  pop af
+  ld (OutputLogic),a
+
+;redraw the screen to show cursor removed and modebox removed
+  call inp_disp
+
+;append a null byte to end the input string.
+  ld hl,(input_head)
+;  ld (hl),0
+  ld (hl),$3F       ;Grammer needs a newline token
+  ld hl,(input_base)
+  ret
+inputloop:
+  ld hl,(textRow)
+  ld (penTemp),hl
+  res cursorblink,(iy+keyflags)
+  ld a,CUR_COUNT_RESET>>1
+  ld (curcount),a
+input_key_loop:
+  in a,(4)
+  and 8
+  jp z,input_ON
+
+;blink the cursor
+  ld hl,curcount
+  dec (hl)
+  jr nz,+_
+  ld (hl),CUR_COUNT_RESET
+  ld a,(flags+keyflags)
+  xor 1<<cursorblink
+  ld (flags+keyflags),a
+  and 1<<cursorblink
+  ld a,' '
+  call nz,getcursorchar
+  call inp_VPutMap
+;  res InvertTextFlag,(iy+UserFlags)
+  call inp_disp
+  ld hl,(penTemp)
+  ld (textRow),hl
+_:
+  ld hl,getKeyDebounce
+  ld (prev_page_call_address),hl
+  call prev_page_call
+  or a
+  jr z,input_key_loop
+  push af
+  ld a,' '
+  call inp_VPutMap
+  ld hl,(penTemp)
+  ld (textRow),hl
+  pop af
+  cp 9
+  ret z
+  call +_
+  jr inputloop
+_:
+  ; dec a
+  ; jr z,input_cursor_down
+  ; dec a
+  ; jr z,input_cursor_left
+  ; dec a
+  ; jr z,input_cursor_right
+  ; dec a
+  ; jr z,input_cursor_up
+  ; add a,4
+  cp 15
+  jr z,input_clear
+  cp 56
+  jr z,input_del
+  call getKeyTok
+  ret c
+  ld a,d
+  ld c,e
+  sub 1
+  inc a
+  ccf
+  ld de,(input_head)
+  ld hl,(input_top)
+  sbc hl,de
+  ret z
+  ret c
+
+  ex de,hl
+  or a
+  jr z,+_
+  ld (hl),a
+  inc hl
+_:
+  ld (hl),c
+  inc hl
+  ld (hl),0
+  ld (input_head),hl
+  call inp_dispstr
+  call inp_disp
+
+;Restore text coords
+  ld hl,(penTemp)
+  ld (textRow),hl
+  ret
+; input_cursor_down:
+;   ret
+; input_cursor_up:
+;   ret
+; input_cursor_left:
+;   ret
+; input_cursor_right:
+; ;make sure we aren't at the end of input
+;   ld hl,(input_curptr)
+;   ld a,(hl)
+;   or a
+;   ret z
+;
+; ;Advance to the next tokem
+;   call VPutTok  ;advances text, sets HL to point to the next token
+;   ld (input_curptr),hl
+;
+; ;Save the new text coordinates
+;   ld hl(textRow)
+;   ld (penTemp),hl
+;   ret
+
+input_clear:
+  call +_
+  jr c,input_clear
+  jp inp_disp
+input_del:
+  call +_
+  jp inp_disp
+_:
+  ld de,(input_head)
+  ld hl,(input_base)
+  or a
+  sbc hl,de
+  ret z
+  ;jp nc,fatal_error
+  ex de,hl
+  dec hl
+  ld (input_head),hl
+  ld e,(hl)
+  ld d,0
+  dec hl
+  ld a,(hl)
+  bcall(_IsA2ByteTok)
+  jr nz,+_
+  ld d,a
+  ld (input_head),hl
+  .db $FE     ;start of `cp *`, skips the `inc hl`
+_:
+  inc hl
+  ld (hl),0
+  ;DE is the token to erase
+
+  ;redraw the input so that we know where to start drawing spaces!
+  push de
+  call inp_dispstr
+  pop de
+
+  ld hl,OP3
+  ld a,d
+  or a
+  jr z,+_
+  ld (hl),d
+  inc hl
+_:
+  ld (hl),e
+  ld l,OP3&255
+  bcall(_Get_Tok_Strng)
+;BC is the length of the string
+  ld a,b
+  or c
+  jr z,input_del_finish
+
+;Now draw spaces for each char
+  ld hl,OP3
+_:
+  push bc
+  push hl
+  ld a,(hl)
+  call vput_space_p1
+  pop hl
+  pop bc
+  cpi
+  jp pe,-_
+input_del_finish:
+  ld hl,(penTemp)
+  ld (textRow),hl
+  scf
+  ret
+
+inp_disp = p1_GraphToLCD
+
+input_ON:
+  ld hl,ONErr
+  ld (prev_page_call_address),hl
+  call prev_page_call
+  jp inp_disp
+inp_dispstr:
+;Reset text coords
+  ld hl,(textRow_base)
+  ld (textRow),hl
+
+;Draw the current input
+  ld hl,(input_base)
+  call inp_VPutTokS
+
+;Save the text coordinate
+  ld hl,(textRow)
+  ld (penTemp),hl
+
+;Draw a blank space:
+;  xor a      ;already zero from VPutS
+  call inp_VPutMap
+
+;Draw the end text
+  ld hl,(input_end_text)
+  call inp_VPutS
+
+
+;Draw another blank space:
+;  xor a
+  jp inp_VPutMap
+_:
+  push hl
+  bcall(_IsA2ByteTok)
+  push af
+  bcall(_Get_Tok_Strng)
+  ; ld hl,OP3+1
+  ; add hl,bc
+  ; ld (hl),0
+  ld hl,OP3
+  call inp_VPutS
+  pop af
+  pop hl
+  inc hl
+  jr nz,$+3
+  inc hl
+inp_VPutTokS:
+  ld a,(hl)
+  or a
+  jr nz,-_
+  ret
+inp_VPutS:
+  push hl
+  ld hl,GPutS
+  ld (prev_page_call_address),hl
+  pop hl
+  jp prev_page_call
+inp_VPutMap:
+  push hl
+  ld hl,PutSC
+  ld (prev_page_call_address),hl
+  pop hl
+  jp prev_page_call
+vput_space_p1:
+  ld hl,vput_space
+  ld (prev_page_call_address),hl
+  jp prev_page_call
+
+input_mode_LUT:
+.db $E0,$1E,"Aa"
+
+getcursorchar:
+  ; set InvertTextFlag,(iy+UserFlags)
+  ld a,(flags+keyflags)
+  ld hl,input_mode_LUT
+  and 3
+  add a,l
+  ld l,a
+#if input_mode_LUT&255>252
+  jr nc,+_
+  inc h
+_:
+#endif
+  ld a,(hl)
+  ret

+ 473 - 0
src/io/menu.z80

@@ -0,0 +1,473 @@
+#define Text() call p1_PutTokenText
+#define FONT_HEIGHT 6
+;#define TEXT_PAD_TOP    ;comment if there is not a row of padding above the text
+;#define TEXTCOORD_YX      ;define if textcoord is Y then X (TI-OS is Y then X for small font, large font and some custom text routines use the opposite)
+textcoord = textRow
+
+#macro LCD_Update()
+  di
+  call p1_GraphToLCD
+#endmacro
+
+#macro rect_OR()
+  ;Draw a black rectangle
+  ld a,b
+  ld b,e
+  ld e,a
+  ld a,1
+  call drawrect
+#endmacro
+
+#macro rect_XOR()
+  ;Draw an inverted rectangle
+  ld a,b
+  ld b,e
+  ld e,a
+  ld a,2
+  call drawrect
+#endmacro
+
+#macro rect_Erase()
+  ;Draw a white rectangle
+  ld a,b
+  ld b,e
+  ld e,a
+  xor a
+  call drawrect
+#endmacro
+
+
+
+menuroutine:
+;Input:
+;   (B,C) = (x,y)
+;   (D,E) = (width,height)
+;   HL points to the header
+;   IX points to the get/select code
+;     If you are using the TI-OS VPutS routine, you'll need to have the textWrite flag set in sGrFlags
+;Notes:
+;   The header is set up as follows:
+;       .db number_of_titles
+;       .db "title 0",0
+;       .db "title 1",0
+;       .db "title 2",0
+;       ...
+;
+;   The get/select code is passed the following information:
+;       A is the index of the current title (0 is the first, 1 is the second, etc.)
+;       BC is the index of the currently highlighted item
+;       carry flag is reset if it needs to return a pointer to the string for the element
+;           Return carry flag as set if the element is out-of-bounds.
+;       carry flag is set if it needs to return a pointer to the data for the element
+  ld (menucallptr),ix
+
+;save box dimensions
+  push bc
+
+;Save the pointer to the menu headers field
+  ld (menuheader_ptr),hl
+
+;Set the menu header to header 0
+  xor a
+  ld (menuheader_cur),a
+
+;establish the bottom and right edges of the textbox
+  ld a,c
+  add a,e
+  ld (textbox_bottom),a
+  ld a,b
+  add a,d
+  ld (textbox_right),a
+
+; Draw the rectangle for the menu. Black border, white fill.
+  rect_OR()
+
+; Display the header
+; get coords
+  pop hl
+  inc h
+  inc h
+  inc l
+  push hl
+#ifdef TEXTCOORD_YX
+  ;need to swap the coords order
+  ld a,h
+  ld h,l
+  ld l,a
+#endif
+  ld (menuheader_coord),hl
+  call draw_header
+  pop bc
+
+
+;Before we do too much, let's establish the top-left textbox boundaries.
+  ld a,FONT_HEIGHT+2
+  add a,c
+  ld c,a
+  ld (textbox_top),bc
+
+
+  ld hl,(menutopinit)
+  ld (menutop),hl
+  ex de,hl
+  ld hl,(menudefault)
+  ld (menucur),hl
+
+  ;need t set menu selection to:
+  ;   (textbox_top-1)+(menucur-menutop)*fontheight
+  ;  =(textbox_top-1)+(HL-DE)*fontheight
+  ; or a
+  sbc hl,de
+  ld a,l
+  add a,a
+  add a,l
+  add a,a
+  ld hl,(textbox_top)
+  dec h
+  add a,l
+  ld l,a
+  ld (menuselection),hl
+
+
+;===============================================================================
+; Now we have drawn the menu box, we have to populate it.
+; We'll call a routine to get the n-th string to be displayed.
+; Stop fetching once the next item would go at or past textbox_bottom.
+; Draw at least one item.
+
+menu_render:
+
+
+;Restore the text coordinates top
+  ld hl,(textbox_top)
+#ifndef TEXT_PAD_TOP
+  inc l
+#endif
+#ifdef TEXTCOORD_YX
+  ;need to swap the coords order
+  ld a,h
+  ld h,l
+  ld l,a
+#endif
+  ld (textcoord),hl
+
+;rerender the items
+  call menu_render_sub
+menu_render_0:
+;highlight the current option
+  ld bc,(menuselection)
+  ld hl,(textbox_bottom)
+  ld a,h
+  sub b
+  ld d,a
+  ld e,FONT_HEIGHT+1
+  dec d
+  push de
+  push bc
+  rect_XOR()
+  LCD_Update()
+  pop bc
+  pop de
+  rect_XOR()
+;wait for a keypress
+_:
+  in a,(4)
+  and 8
+  jr z,menu_get_select_err
+
+  call p1_getKeyDebounce
+  or a
+  jr z,-_
+  cp 9
+  scf
+  jr z,menu_get_select
+  cp 15
+  jr z,menu_get_select_err
+
+  call menu_arrow
+  jr c,menu_render_0
+  jr menu_render
+
+menu_get_select:
+  ld hl,(menucallptr)
+  ld a,(menuheader_cur)
+  jp (hl)
+
+menu_render_sub:
+; need to clear out the textbox
+  ld bc,(textbox_top)
+  ld hl,(textbox_bottom)
+  ld a,h
+  sub b
+  ld d,a
+  ld a,l
+  sub c
+  ld e,a
+  dec e
+  dec b
+  rect_Erase()
+  xor a
+  ld bc,(menutop)
+menu_render_sub_loop:
+  push bc
+  call menu_get_select
+  pop bc
+  ret c
+  ld de,(textcoord)
+  push de
+  push bc
+  Text()
+  pop bc
+  pop de
+#ifdef TEXTCOORD_YX
+  ld a,FONT_HEIGHT
+  add a,d
+  ld d,a
+  ld a,(textbox_bottom)
+#ifdef TEXT_PAD_TOP
+  sub FONT_HEIGHT+2
+#else
+  sub FONT_HEIGHT+1
+#endif
+  cp d
+#else
+  ld a,FONT_HEIGHT
+  add a,e
+  ld e,a
+  ld a,(textbox_bottom)
+#ifdef TEXT_PAD_TOP
+  sub FONT_HEIGHT+2
+#else
+  sub FONT_HEIGHT+1
+#endif
+  cp e
+#endif
+  ld (textcoord),de
+  inc bc
+  jr nc,menu_render_sub_loop
+  ret
+
+menu_get_select_err:
+;return a null pointer.
+;A=0, HL=0
+  xor a
+  ld b,a
+  ld c,a
+  ret
+
+menu_arrow:
+;check arrow keys
+  dec a
+  jr z,menu_down
+  sub 3
+  scf
+  ret nz
+  ; dec a
+  ; jr z,menu_left
+  ; dec a
+  ; jr z,menu_right
+  ; add a,-1      ;sets the carry flag if it is not a keypress
+  ; ret nz
+
+;if would select oob
+;   if next element exists
+;       increment the menutop and rerender the menu
+;else
+;   move menuselection
+menu_up:
+  or a
+  ld bc,(menucur)
+  dec bc
+  push bc
+  call menu_get_select
+  ld (menu_temp),hl
+  pop hl
+  ret c
+  ld (menucur),hl
+
+  ld a,(menuselection)
+  ld hl,(textbox_top)
+  cp l
+  jr z,+_
+  sub FONT_HEIGHT
+  ld (menuselection),a
+  scf
+  ret
+_:
+;now we need to scroll the textbox down FONT_HEIGHT pixels, then draw the top element
+  ld a,11
+;decrement the menutop
+  ld hl,(menutop)
+  dec hl
+  jr menu_scroll
+
+menu_down:
+  or a
+  ld bc,(menucur)
+  inc bc
+  push bc
+  call menu_get_select
+  ld (menu_temp),hl
+  pop hl
+  ret c
+  ld (menucur),hl
+
+  ld a,(menuselection)
+  add a,FONT_HEIGHT+FONT_HEIGHT+1
+  ld hl,(textbox_bottom)
+  cp l
+  jr nc,+_
+  sub FONT_HEIGHT+1
+  ld (menuselection),a
+  scf
+  ret
+_:
+;now we need to scroll the textbox up FONT_HEIGHT pixels, then draw the top element
+
+  ld a,10
+;decrement the menutop
+  ld hl,(menutop)
+  inc hl
+menu_scroll:
+  ld (menutop),hl
+
+  push af
+  call gettextbox
+  ld h,FONT_HEIGHT
+  pop af
+_:
+  push af
+  push bc
+  push de
+  push hl
+  call drawrect
+  pop hl
+  pop de
+  pop bc
+  pop af
+  dec h
+  jr nz,-_
+
+;Set the textcoord
+  ld hl,(menuselection)
+  inc h
+  inc l
+#ifdef TEXTCOORD_YX
+  ;need to swap the coords order
+  ld b,l
+  ld c,h
+  ld (textcoord),bc
+#else
+  ld (textcoord),hl
+#endif
+
+  ld hl,(menu_temp)
+  Text()
+
+  scf
+  ret
+
+gettextbox:
+  ld bc,(textbox_top)
+  ld e,b
+  ld hl,(textbox_bottom)
+  ld a,h
+  sub b
+  ld d,a
+  ld a,l
+  sub c
+  ld b,a
+  dec d
+  dec b
+  ret
+;These change to the next menu header
+; menu_left:
+
+  ; ld a,(menuheader_cur)
+  ; dec a
+  ; jr +_
+; menu_right:
+;   ld a,(menuheader_cur)
+;   inc a
+; _:
+;   ld (menuheader_cur),a
+;   call reset_menu_cursor
+
+draw_header:
+;Set up textcoord
+  ld hl,(menuheader_coord)
+#ifndef TEXT_PAD_TOP
+#ifdef TEXTCOORD_YX
+  inc h
+#else
+  inc l
+#endif
+#endif
+  ld (textcoord),hl
+
+
+;Need to erase the current header area
+#ifdef TEXTCOORD_YX
+  ;need to swap the coords order
+  ld b,l
+  ld c,h
+#else
+  ld b,h
+  ld c,l
+#endif
+#ifndef TEXT_PAD_TOP
+  dec c
+#endif
+
+  ld de,(textbox_bottom)
+  ld a,d
+  sub b
+  ld d,a
+  dec b
+  ld e,FONT_HEIGHT+1
+  rect_Erase()
+
+
+;Verify that the header element is valid, wrap if needed
+  ld hl,(menuheader_ptr)
+;   ld a,(menuheader_cur)
+;   cp (hl)
+;   jr c,+_
+;   inc a
+;   jr nz,$+5
+;   ;cycle to the last header
+;   ld a,(hl)
+;   dec a
+;   .db $FE
+;   ;cycle to the first header
+;   xor a
+;   ld (menuheader_cur),a
+; _:
+;
+; ;A is the header to seek
+;   ld bc,0   ;using CPIR, want to make sure it doesn't exit too soon!
+;   inc hl    ;point to the first header
+;   or a
+;   jr draw_header_loopend
+; draw_header_loop:
+;   push af
+;   xor a
+;   cpir
+;   pop af
+;   dec a
+; draw_header_loopend:
+;   jr nz,draw_header_loop
+
+;now draw the header
+  Text()
+  or a
+  ret
+
+reset_menu_cursor:
+  ld hl,0
+  ld (menutop),hl
+  ld (menucur),hl
+  ld hl,(textbox_top)
+  dec h
+  ld (menuselection),hl
+  ret

+ 53 - 0
src/io/sound.z80

@@ -0,0 +1,53 @@
+NoteLoop:
+;If the CPU is exactly 6MHz, then we are .000004666... seconds short for every .950272 seconds.
+  dec de
+NoteLoop_begin:
+  push de
+  call freqout
+  pop de
+  ld a,d
+  or e
+  dec hl
+  jr nz,NoteLoop
+  ret
+freqout:
+;HL*87-11cc
+  ld d,b
+  ld e,c
+  jr freqoutEntry
+freqoutLoop:
+;add 46cc
+  ex (sp),hl
+  ex (sp),hl
+  nop
+  nop
+freqoutLoop1:
+  ld a,h
+  or l
+  jr z,+_
+  cpd
+  jp pe,freqoutLoop
+freqoutEntry:
+  in a,(0)
+  scf
+_:
+
+  ld b,d
+  ld c,e
+  out (0),a
+  jr c,freqoutLoop
+  ret
+
+;HL points to the data:
+;DE is the time
+;BC is the number of elements
+SoundLoop:
+  push de \ push bc
+  ld c,(hl) \ inc hl
+  ld b,(hl) \ push hl
+  ex de,hl
+  call freqout
+  pop hl \ pop bc \ pop de
+  cpi
+  jp pe,SoundLoop
+  ret

+ 237 - 0
src/isort.z80

@@ -0,0 +1,237 @@
+;uses 19 bytes of RAM, 4 bytes of stack space
+;#define speed
+#define tmp OP1+14
+#define head tmp+1
+#define head_lag tmp+3
+#macro advanceVAT()
+#ifdef speed
+;17cc saved per iteration
+;8 bytes vs a 3 byte call (but no 8-byte subroutine)
+  ld bc,-6
+  add hl,bc
+  sbc a,a   ;HL<=FE66, so carry flag is set
+  sub (hl)
+  ld c,a
+  add hl,bc
+#else
+  call advance_VAT    ;preserves DE
+#endif
+#endmacro
+
+
+sortVAT:
+#ifdef nointerrupt
+  di
+#endif
+  ld hl,(progPtr)
+isort_main:
+_:
+  ld (head_lag),hl
+  ld d,h
+  ld e,l
+  advanceVAT()
+  ld (head),hl
+#ifdef speed
+;11 bytes, 29cc or 46cc. avg=29.06640625cc
+  ld a,(pTemp)
+  cp l
+  jr nz,$+7
+  ld a,(pTemp+1)
+  cp h
+  ret z
+#else
+;adds 8 bytes, 55cc
+  ld bc,(pTemp) ;Need to verify that we haven't reached the end of the progVAT
+  or a          ;
+  sbc hl,bc     ;
+  ret z         ;
+  add hl,bc     ;
+#endif
+  call cmpVAT
+  ld hl,(head)
+  jr nc,-_
+;if it makes it here, then (head) needs to be inserted into the previous part of the VAT
+;We might be able to speed it up a little more if I also grab the next element
+;  If (head_advance) is bigger than (head), then no need to start the search from the beginning
+  ld de,tmp
+#ifdef speed
+  ldd
+  ldd
+  ldd
+  ldd
+  ldd
+  ldd
+  ld b,0
+  ld c,(hl)
+  lddr
+  ldd
+#else
+  ld bc,6
+  lddr
+  ld c,(hl)
+  inc c
+  lddr
+#endif
+  ld hl,(progPtr)
+_:
+  push hl
+#ifdef speed
+;+5 bytes, -11cc
+  ld bc,-6
+  add hl,bc
+  ld de,tmp-6
+  call cmpVAT_stepin
+#else
+  ex de,hl
+  ld hl,tmp
+  call cmpVAT
+#endif
+  pop hl
+  jr c,+_
+  advanceVAT()
+  jp -_
+_:
+;HL is where to insert
+  ld de,(head)
+  or a
+  sbc hl,de
+  ld b,h
+  ld c,l
+  ld hl,-6
+  add hl,de
+  ld a,l
+  sub a,(hl)
+  ld l,a
+  jr nc,$+4
+  dec h
+  or a
+  inc de
+  ex de,hl
+#ifdef speed
+  call fastldir
+#else
+  ldir
+#endif
+  ;begin at DE, copy tmp. First need size of tmp
+  ld hl,tmp-6
+  ld c,(hl)
+  sbc hl,bc
+  ld a,c
+  ldir
+#ifdef speed
+  ldi
+  ldi
+  ldi
+  ldi
+  ldi
+  ldi
+  ldi
+  add a,7
+#else
+  ld c,7
+  add a,c
+  ldir
+#endif
+  ld hl,(head_lag)
+  ld c,a
+  ld a,l
+  sub c
+  ld l,a
+  jp nc,isort_main
+  dec h
+  jp isort_main
+#ifndef speed
+advance_VAT:
+  ld bc,-6
+  add hl,bc
+  sbc a,a   ;HL<=FE66, so carry flag is set
+  sub (hl)
+  ld c,a
+  add hl,bc
+  ret
+#endif
+cmpVAT:
+;if @HL>=@DE, return nc
+  ld bc,-6
+  add hl,bc
+  ex de,hl
+  add hl,bc
+cmpVAT_stepin:
+  ld a,(de)
+  cp (hl)
+  jr nc,first_longer
+;the second name is longer.
+  ld c,a
+_:
+  dec hl
+  dec de
+  ld a,(de)
+  cp (hl)
+  ret nz
+  dec c
+  jr nz,-_
+  scf
+  ret
+first_longer:
+;the first name is longer, so load c with the size of the second name
+  ld c,(hl)
+_:
+  dec hl
+  dec de
+  ld a,(de)
+  cp (hl)
+  ret nz
+  dec c
+  jr nz,-_
+  ret
+#ifdef speed
+fastldir:
+;copy BC bytes from HL to DE
+;breaks even at 26 bytes
+; 5% faster than LDIR with 35 bytes
+;10% faster than LDIR with 48 bytes
+;15% faster than LDIR with 91 bytes
+;20% faster than LDIR with 635 bytes
+;max is ~ 20.8% faster than LDIR
+;Cost: 104+16N+10ceiling(N/16)
+    push hl
+;    push af
+    xor a
+    sub c
+    and 15               ;change to n-1
+    add a,a
+    ld hl,ldirloop
+    add a,l
+    ld l,a
+#if (ldirloop>>8)!=(_ldirloop_end>>8)
+    jr nc,$+3  ;these aren't needed if the ldirloop doesn't cross a 256 byte boundary. Can save 12cc on the above timings and 3 bytes.
+    inc h       ;
+#endif
+;    pop af
+    ex (sp),hl
+    ret
+ldirloop:
+;n=16, (number of LDI instructions, use qty of 4,8,16,32,64)
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+    ldi
+_ldirloop_end:
+    ldi
+    jp pe,ldirloop
+    ret
+#endif
+#undefine tmp
+#undefine head
+#undefine head_lag1

+ 147 - 0
src/jmptable.z80

@@ -0,0 +1,147 @@
+;start=0x4023
+
+#if $!=$4023
+.echo "Update gramPkg.z80 with new cmdJmp : ",$-$4000
+#endif
+  jp cmdJmp
+  jp ProgramAccessStart
+  jp CompatCall
+  jp SelectedProg
+  jp ExecOP1
+  jp ParseFullArg
+  jp ParseNextFullArg
+  jp ParseNextFullArg_Inc
+  jp ParseCondition
+  jp DrawRectToGraph
+  jp GraphToLCD
+  jp VPutSC
+  jp GetKey
+  jp GetGrammerText
+  jp GetGrammerText_DE
+  jp GetGrammerStr
+  jp GetKeyDebounce
+  jp SearchString
+  jp FS_createvar_max
+  jp FS_delvar
+  jp FS_resize
+  jp FS_findvar
+  jp ErrMem
+;Original jump table
+;  jp ParserNext
+;  jp ParseArg
+;  jp g_ReadByte
+;  jp g_Input
+;  jp g_ParticleCycle
+;  jp DefaultBuffer
+;  jp PBufInfoDef
+;  jp PBufInfo
+;  jp NextParticle
+;  jp AddParticle
+;  jp ShiftGraphBuf
+;  jp ShiftGraphUpA
+;  jp ShiftGraphRightA
+;  jp ShiftGraphLeftA
+;  jp ShiftGraphDownA
+;  jp ZeroMemF
+;  jp SetMemF
+;  jp ZeroMemE
+;  jp SetMemE
+;  jp nCrAlgorithm
+;  jp SetSpeed
+;  jp ZeroMem
+;  jp g_ClrDraw
+;  jp g_ClrHome
+;  jp g_Max
+;  jp SetSmallMem
+;  jp InvertMem
+;  jp g_Rand
+;  jp expr
+;  jp LCM_BC_DE
+;  jp gcdHL_BC
+;  jp Pause
+;  jp PlotPixel
+;  jp g_Call
+;  jp PutSM
+;  jp DrawPixelCoordSprite
+;  jp BreakProgram
+;  jp ErrorJump
+;  jp DrawSpriteXxY
+;  jp CheckKey
+;  jp GetKey
+;  jp ParseFullArg
+;  jp ParseNextFullArg
+;  jp ParseCondition
+;  jp Sine
+;  jp EndOfCommand
+;  jp EndOArg
+;  jp EndOArgNotSto
+;  jp FindEndToken
+;  jp GetGrammerText
+;  jp GetGrammerStr
+;  jp VarP
+;  jp EndOfLine
+;  jp IsOP1HeaderMatch
+;  jp ret
+;  jp IsHexTok
+;  jp ConvRStr
+;  jp HL_Times_BC
+;  jp DE_Times_BC
+;  jp DE_Div_BC
+;  jp HL_Div_BC
+;  jp HL_Times_A
+;  jp DE_Times_A
+;  jp IsHLAtEOF
+;  jp SearchString
+;  jp CheckStatus
+;  jp GraphToLCD
+;  jp BufferToLCD-4
+;  jp DrawRectToGraph
+;  jp PutSS
+;  jp GPutSS
+;  jp GPutS
+;  jp PutSC
+;  jp PutFS
+;  jp SqrtHL
+;  jp Circle
+;  jp SetMem
+;  jp ConvNumBase
+;  jp PrimeTest
+;  jp HL_Div_C
+;  jp Is_2_Byte
+;  jp Is_Var_Name
+;  jp DrawLine
+;  jp IncHLMem1
+;  jp Conv_OP1
+;  jp ConvDecAtHL
+;  jp GetPixelLoc
+;  jp HexTok
+;  jp DEHL_Mul_IXBC
+;  jp BufferToLCD
+;  jp IsOP1GrammerProg
+;  jp ReadArc
+;  jp CallError
+;  jp ONErr
+;  jp ErrMem
+;  jp C_Div_L
+;  jp TileMap1
+;  jp HL_SDiv_BC
+;  jp VPutC
+;  jp RoundHL_Div_C
+;  jp SearchLine
+;  jp p_SendByte
+;  jp p_GetByte
+;  jp PutIM
+;  jp GPutSI
+;  jp DrawRectToGraphI
+;  jp ParseFullArgI
+;  jp CallI
+;  jp DEHL_Mul_32Stack
+;  jp CopyZStr
+;  jp CreateZVar
+;  jp ChkFindVar
+;  jp ChkFindVarAtDE
+;  jp SearchVarBC
+;  jp FindVarSymAtHL
+;  jp FindVarSymAtDE
+;  jp FindSym
+;  jp FindVar

+ 41 - 0
src/jt.py

@@ -0,0 +1,41 @@
+import sys
+#This reads the jumptable.z80 and generates an include file
+hexd="0123456789ABCDEF"
+def hexify(x,n):
+  s=''
+  while n>0:
+    s=hexd[x&15]+s
+    x>>=4
+    n-=1
+  return s
+def makejt(l):
+  s=''
+  base=0
+  for i in l.split('\n'):
+    if i[0:7]==";start=":
+      base=int(i[7:],16)
+    i=i.strip(" ").strip("\t")
+    if i[0:3]=="jp ":
+      if base==0:
+        print("WARNING! Jumptable has ';start=0'")
+      t=i[3:]
+      s+=t+" "*(20-len(t))+"= $"+hexify(base,4)+"\n"
+      base+=3
+  return s
+if len(sys.argv)<3:
+  print("Too few arguments!\n  python "+sys.argv[0]+" <input file> <output file>")
+else:
+  f=open(sys.argv[1],'r')
+  j=f.read()
+  f.close()
+  f=open(sys.argv[2],'r')
+  s = f.read()
+  f.close()
+  t = "#ifndef NO_JUMP_TABLE\n"
+  s = s.split(t)[0]
+  s += t
+  s += makejt(j)
+  s += "#endif"
+  f=open(sys.argv[2],'w')
+  f.write(s)
+  f.close()

+ 24 - 0
src/main.z80

@@ -0,0 +1,24 @@
+main:
+  call StartMenu
+  xor a
+  ld (kbdScanCode),a
+_:
+  call GetKey
+  or a
+  jr nz,-_
+	bcall(_clrTxtShd)
+  bcall(_saveCmdShadow)
+  bcall(_JForceCmdNoChar)
+StartMenu:
+  ld bc,0
+  ld (TempWord3),a
+  ld (TempWord4),bc
+  ld (TempWord5),hl
+  call FindGVarData
+  ld a,b \ or a
+  jr nz,+_
+_:
+  in a,(6)
+  ld hl,GrammerHook
+  bcall(_SetParserHook)
+#include "startmenu.z80"

+ 598 - 0
src/math.z80

@@ -0,0 +1,598 @@
+Sqrt:
+  ld a,(hl)
+  cp 3Ah
+  jr z,floatsqrt
+  inc hl
+  cp $AE
+  push af
+  jr nz,+_
+  ld (parsePtr),hl
+_:
+  call ParseFullArg
+  ld hl,sqrtHL
+  ld (next_page_call_address),hl
+  ld h,b
+  ld l,c
+  call next_page_call
+
+  ld (ThetaPrimeVar),hl
+  ld c,a
+  ld b,0
+  pop af
+  ret nz
+  ;if HL<=BC, increment BC
+  sbc hl,bc
+  ret c
+  ret z
+  inc bc
+  ret
+floatsqrt:
+  ld hl,sqrtSingle
+  jr float_stepin_1
+sinefloat:
+  pop af
+  ld hl,sinSingle
+  jr float_stepin_1
+_:
+  ld hl,cosSingle
+float_stepin_1:
+  push hl     ;the call to make
+  call ParseNextFullArg
+float_stepin_1_:
+  push bc     ;the second argument
+  call floatstackpush
+  ld b,h
+  ld c,l
+  pop de
+  pop hl
+  ld (next_page_call_address),hl
+  ex de,hl
+  jp next_page_call
+Cos:
+  ld a,(hl)
+  cp 3Ah
+  jr z,-_
+  ld a,64
+  .db $FE
+Sin:
+  xor a
+  push af
+  ld a,(hl)
+  cp 3Ah
+  jr z,sinefloat
+  call ParseFullArg
+  pop af
+  add a,c
+Sine:
+  ld d,a
+  rlca
+  rlca
+  sbc a,a
+  xor d
+  and 63
+  ld b,0
+#if (sinTable&255)<192
+#if (sintable&255)==0
+  ld h,sinTable>>8
+  ld l,a
+#else
+  ld hl,sinTable
+  add a,l
+  ld l,a
+#endif
+#else
+  ld c,a
+  ld hl,sinTable
+  add hl,bc
+#endif
+  ld c,(hl)
+  rlc d
+  jr c,NegateBC
+  ret
+_:
+  ld hl,absSingle
+  jp float_stepin_1
+absToken:
+  ld a,(hl)
+  cp 3Ah
+  jr z,-_
+  call ParseFullArg
+  bit 7,b
+  ret z
+  jr negateBC
+Negative:
+  ld a,(hl)
+  cp 3Ah
+  jr z,+_
+  call ParseFullArg
+negateBC:
+  xor a \ sub c \ ld c,a
+  sbc a,a \ sub b \ ld b,a
+  ret
+_:
+  ld hl,negSingle
+  jp float_stepin_1
+logToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  call ParseNextFullArg
+  cp 2Bh
+  ld hl,logSingle
+  jp z,float_stepin_2_
+  ld hl,log10Single
+  push hl
+  jr float_stepin_1_
+Add:
+  push bc
+  ld a,(hl)
+  cp 3Ah
+  jr z,+_
+  call ParseFullArg
+  pop hl
+  xor a
+  add hl,bc
+  ld b,h
+  ld c,l
+  ld h,a
+  adc a,a
+  ld l,a
+  ld (ThetaPrimeVar),hl
+  ret
+_:
+  ld hl,addSingle
+  jp float_stepin
+SubtractToken:
+  push bc
+  ld a,(hl)
+  cp 3Ah
+  jr z,+_
+  call ParseFullArg
+  pop hl
+  xor a
+  sbc hl,bc
+  ld b,h
+  ld c,l
+  ld h,a
+  ld l,a
+  ld (ThetaPrimeVar),hl
+  ret
+_:
+  ld hl,subSingle
+  jp float_stepin
+Cubed:
+  ld d,b
+  ld e,c
+  call DE_Times_BC
+  ex de,hl
+  jr mul_stepin
+Squared:
+  ld d,b
+  ld e,c
+  jr mul_stepin
+Multiply:
+  push bc
+  ld a,(hl)
+  cp 3Ah
+  jr z,+_
+  call ParseFullArg
+  pop de
+mul_stepin:
+  call DE_Times_BC
+  ld b,h
+  ld c,l
+  ld (ThetaPrimeVar),de
+  ret
+_:
+  ld hl,mulSingle
+float_stepin:
+  push hl
+  call ParseNextFullArg
+  push bc
+  call floatstackpush
+  ld b,h
+  ld c,l
+  pop de
+  pop hl
+  ld (next_page_call_address),hl
+  pop hl
+  jp next_page_call
+floatstackpush:
+  ld hl,(floatstack_ptr)
+  ld bc,4
+  add hl,bc
+  ld (floatstack_ptr),hl
+  ld a,l \ cp floatstack_top&255
+  ret nz
+#if (floatstack_top>>8)!=(floatstack_bottom>>8)
+  ld a,h \ cp floatstack_top>>8
+  ret nz
+#endif
+  ld hl,floatstack_bottom
+  ld (floatstack_ptr),hl
+  ret
+Comment:
+SkipLine:
+  bit floatmode,(iy+ModeFlags2)
+  jp nz,ConvRStr_Float
+  call EndOfLine
+  jp ParseArg2
+SkipLineDiv:
+  ld a,(hl)
+  cp 93h \ jp z,SlowText
+  cp 83h
+  jr z,SkipLine
+  cp 29h
+  jr nz,Divide
+  push bc
+  call ParseNextFullArg
+  pop hl
+;1366cc+6cc for every 0 bit in the result (up to +90cc
+;+48cc unless HL and BC are both positive
+;min: 1366cc
+;max: 1504cc
+;avg: 1447cc
+  ld a,h
+  xor b
+  push af
+  xor b
+  jp p,+_
+  xor a
+  sub l
+  ld l,a
+  sbc a,a
+  sub h
+  ld h,a
+_:
+  xor b
+  jp p,+_
+  xor a
+  sub c
+  ld c,a
+  sbc a,a
+  sub b
+  ld b,a
+_:
+  call HL_Div_BC
+  pop af
+  jp p,+_
+  xor a
+  sub l
+  ld l,a
+  sbc a,a
+  sub h
+  ld h,a
+_:
+  ld b,h
+  ld c,l
+  ld (ThetaPrimeVar),de
+  ret
+Divide:
+  push bc
+  ld a,(hl)
+  cp 3Ah
+  jr z,+_
+  call ParseFullArg
+  pop hl
+  call HL_Div_BC
+  ld b,h
+  ld c,l
+  ld (ThetaPrimeVar),de
+  ret
+_:
+  ld hl,divSingle
+  jp float_stepin
+PowToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadTOken
+  push bc
+  ld hl,powSingle
+  jp float_stepin
+
+_:
+  ld hl,expSingle
+  jp float_stepin_1
+PowerOf2:
+  ld a,(hl)
+  cp 3Ah
+  jr z,-_
+  call ParseFullArg
+  ld a,c
+  ld hl,0
+  ld d,h
+  ld e,h
+  cp 32
+  jr nc,Po2End
+  inc l
+  or a
+  jr z,Po2End
+  ld b,a
+_:
+  add hl,hl
+  rl e
+  rl d
+  djnz -_
+Po2End:
+  ld b,h
+  ld c,l
+  ret
+
+Logic:
+Equals:
+  ld a,(hl)
+  cp $3A
+  jr z,feq
+  push bc
+factorialStepIn:
+  call ParseFullArg
+  pop hl
+  xor a
+  sbc hl,bc
+  ld b,a
+  ld c,a
+  ret nz
+  inc c
+  ret
+feq:
+  call fcmp
+  ld bc,0
+  ret nz
+  inc c
+  ret
+fcmp:
+  push bc
+  call ParseNextFullArg
+  ld hl,cmpSingle
+  ld (next_page_call_address),hl
+  pop hl
+  ld d,b
+  ld e,c
+  jp next_page_call
+moreLogic:
+  push af
+  push bc
+  call ParseFullArg
+  pop hl
+  pop af
+  ret
+notLogic:
+  call MoreLogic
+  ld a,b \ cpl \ ld b,a
+  ld a,c \ cpl \ ld c,a
+  ret
+andLogic:
+  call MoreLogic
+  ld a,h \ and b \ ld b,a
+  ld a,l \ and c \ ld c,a
+  ret
+orLogic:
+  call MoreLogic
+  ld a,h \ or b \ ld b,a
+  ld a,l \ or c \ ld c,a
+  ret
+xorLogic:
+  call MoreLogic
+  ld a,h \ xor b \ ld b,a
+  ld a,l \ xor c \ ld c,a
+  ret
+Less:
+  ld a,(hl)
+  cp $3A
+  jr z,flt
+  call MoreLogic
+  xor a
+  sbc hl,bc
+  ld b,a
+  adc a,a
+  ld c,a
+  ret
+flt:
+  call fcmp
+  ld bc,0
+  ret nc
+  inc c
+  ret
+Greater:
+  ld a,(hl)
+  cp $3A
+  jr z,fgt
+  call MoreLogic
+  xor a
+  scf
+  sbc hl,bc
+  ccf
+  ld b,a
+  adc a,a
+  ld c,a
+  ret
+fgt:
+  call fcmp
+  ld bc,0
+  ret z
+  ret c
+  inc c
+  ret
+LessOrEqual:
+  ld a,(hl)
+  cp $3A
+  jr z,fle
+  call MoreLogic
+  xor a
+  scf
+  sbc hl,bc
+  ld b,a
+  adc a,a
+  ld c,a
+  ret
+fle:
+  call fcmp
+  ld bc,1
+  ret c
+  ret z
+  dec c
+  ret
+MoreOrEqual:
+  ld a,(hl)
+  cp $3A
+  jr z,fge
+  call MoreLogic
+  xor a
+  sbc hl,bc
+  ccf
+  ld b,a
+  adc a,a
+  ld c,a
+  ret
+fge:
+  call fcmp
+  ld bc,0
+  ret c
+  inc c
+  ret
+NotEqual:
+  ld a,(hl)
+  cp $3A
+  jr z,fne
+  call MoreLogic
+  xor a
+  sbc hl,bc
+  ld b,a
+  ld c,a
+  ret z
+  inc c
+  ret
+fne:
+  call fcmp
+  ld bc,0
+  ret z
+  inc c
+  ret
+
+RandToken:
+  ld a,(hl)
+  cp 3Ah
+  jr z,+_
+  call prng16
+  ld b,h
+  ld c,l
+  ret
+_:
+  inc hl
+  ld (parsePtr),hl
+  ld hl,randSingle
+float_stepin_0:
+  push hl
+  call floatstackpush
+  ld b,h
+  ld c,l
+  pop hl
+  ld (next_page_call_address),hl
+  jp next_page_call
+
+
+
+
+tanToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,tanSingle
+  jp float_stepin_1
+atanToken:
+  ld a,(hl)
+  cp 3Ah
+  jr z,atan_float
+  call ParseFullArg
+  push bc
+  ld bc,128
+  cp 2Bh
+  call z,ParseNextFullArg
+  pop de
+  ld hl,atanbin
+  ld (next_page_call_address),hl
+  jp next_page_call
+
+atan_float:
+  ld hl,atanSingle
+  jp float_stepin_1
+
+acosToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,acosSingle
+  jp float_stepin_1
+asinToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,asinSingle
+  jp float_stepin_1
+
+
+tanhToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,tanhSingle
+  jp float_stepin_1
+coshToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,coshSingle
+  jp float_stepin_1
+sinhToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,sinhSingle
+  jp float_stepin_1
+atanhToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,atanhSingle
+  jp float_stepin_1
+acoshToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,acoshSingle
+  jp float_stepin_1
+asinhToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,asinhSingle
+  jp float_stepin_1
+pow10Token:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,pow10Single
+  jp float_stepin_1
+
+meanToken:
+  ld a,(hl)
+  cp 3Ah
+  jp nz,ErrBadToken
+  ld hl,ameanSingle
+float_stepin_2:
+  push hl
+  call ParseNextFullArg
+  pop hl
+float_stepin_2_:
+  push bc
+  push hl
+  call ParseNextFullArg
+  push bc
+  call floatstackpush
+  ld b,h
+  ld c,l
+  pop de
+  pop hl
+  ld (next_page_call_address),hl
+  pop hl
+  jp next_page_call

+ 16 - 0
src/math/DEHL_Div_BC_special.z80

@@ -0,0 +1,16 @@
+DEHL_Div_BC_special:
+;DEHL/BC ==> DEHL
+;Given that it should error if DE is non-zero and remainder is guaranteed 0.
+
+;First, if DE>=BC, then the output will exceed 16 bits, so we should error
+  ex de,hl
+  xor a
+  sbc hl,bc
+  jr c,+_
+  ld de,-1
+  ret
+_:
+  add hl,bc
+
+;Now enter into a normal DE/BC
+  jp DE_Div_BC_continue

+ 26 - 0
src/math/DEHL_Div_C.z80

@@ -0,0 +1,26 @@
+DEHL_Div_C:
+  ex de,hl
+  push de
+  jr $+4
+HLIX_Div_C:
+;HLIX/C, C<=128 (yes, 128 is allowed)
+;26 bytes
+  push ix
+  call HL_Div_C_limited
+  ex (sp),hl
+  call HL_Div_C_limited+1
+  ex (sp),hl
+  pop ix
+  ret
+HL_Div_C_limited:
+  xor a
+  ld b,16
+_:
+  add hl,hl
+  rla
+  cp c
+  jr c,$+4
+  sub c
+  inc l
+  djnz -_
+  ret

+ 56 - 0
src/math/HL_Div_BC.z80

@@ -0,0 +1,56 @@
+;===============================================================
+HL_Div_BC:
+;===============================================================
+;Performs HL/BC
+;Speed:   1182cc (+6cc for every 0bit in the result)
+;Size:    29 bytes
+;Inputs:
+;     DE is the numerator
+;     BC is the denominator
+;Outputs:
+;     HL is the quotient
+;     DE is the remainder
+;     BC is not changed
+;     z flag is set
+;     c flag is reset
+;===============================================================
+  ex de,hl
+;===============================================================
+DE_Div_BC:
+;===============================================================
+;Performs DE/BC
+;Speed:   1178cc (+6cc for every 0bit in the result)
+;Size:    28 bytes
+;Inputs:
+;     HL is the numerator
+;     BC is the denominator
+;Outputs:
+;     HL is the quotient
+;     DE is the remainder
+;     BC is not changed
+;     z flag is set
+;     c flag is reset
+;===============================================================
+  ld hl,0
+DE_Div_BC_continue:
+  ld a,e
+  ld e,16
+Div16Loop:
+  rla
+  rl d
+  adc hl,hl
+  sbc hl,bc
+  jr nc,+_
+  add hl,bc
+_:
+  dec e
+  jr nz,Div16Loop
+  rla
+  cpl
+  ld e,a
+  ld a,d
+  rla
+  cpl
+  ld d,a
+  ex de,hl
+  ret

+ 13 - 0
src/math/HL_Div_C.z80

@@ -0,0 +1,13 @@
+HL_Div_C:
+  xor a
+  ld b,16
+_:
+  add hl,hl
+  rla
+  jr c,$+5
+  cp c
+  jr c,$+4
+  sub c
+  inc l
+  djnz -_
+  ret

+ 126 - 0
src/math/atanbin.z80

@@ -0,0 +1,126 @@
+atanbin:
+  ;compute atan(DE/BC)
+  ;make DE and BC positive, adjust angle later
+  ld a,b
+  rlc d
+  rra
+  rrc d
+  push af
+  jr nc,+_
+  xor a
+  sub e
+  ld e,a
+  sbc a,a
+  sub d
+  ld d,a
+_:
+  bit 7,b
+  jr z,+_
+  xor a
+  sub c
+  ld c,a
+  sbc a,a
+  sub b
+  ld b,a
+_:
+
+  call atanbin_sub
+  pop af
+  ;bit 7 set means y was negative
+  ;bit 6 set means x was negative
+  add a,a
+  jr nc,+_
+  push af
+  xor a
+  sub c
+  ld c,a
+  pop af
+_:
+  ret p
+  ld a,128
+  sub c
+  ld c,a
+  ret
+
+atanbin_sub:
+;compute DE/BC as a fixed-point number
+;if DE>=BC, swap and make the final result 256-atan(BC/DE)
+  ld h,b
+  ld l,c
+  or a
+  sbc hl,de
+  jr nz,+_
+atan_return_32:
+  ld bc,32
+  ret
+_:
+  add hl,de
+  push af
+  jr nc,+_
+  ld b,d
+  ld c,e
+  .db $FE
+_:
+  ex de,hl
+  ;now do HL/BC, given that BC>HL
+  ;We also made sure all were positive at this point
+  xor a
+  sub c
+  ld c,a
+  sbc a,a
+  sub b
+  ld b,a
+  add hl,hl \ add hl,bc \ jr c,$+4 \ sbc hl,bc \ rla
+  add hl,hl \ add hl,bc \ jr c,$+4 \ sbc hl,bc \ rla
+  add hl,hl \ add hl,bc \ jr c,$+4 \ sbc hl,bc \ rla
+  add hl,hl \ add hl,bc \ jr c,$+4 \ sbc hl,bc \ rla
+  add hl,hl \ add hl,bc \ jr c,$+4 \ sbc hl,bc \ rla
+  add hl,hl \ add hl,bc \ jr c,$+4 \ sbc hl,bc \ rla
+  add hl,hl \ add hl,bc \ jr c,$+4 \ sbc hl,bc \ rla
+  add hl,hl \ add hl,bc \ jr c,$+4 \ sbc hl,bc \ rla
+
+;round step
+  add hl,hl \ add hl,bc \ adc a,0
+  jr c,atan_return_32
+  ;if overflowed, this means we are essentially doing atan(1)
+
+;If A<128
+;   return ((32+19A)>>7)
+;Else
+;   return ((32+13A)>>7)+6
+  ld l,a
+  ld h,0
+  ld c,l
+  ld b,h
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  ld d,h
+  ld e,l
+  add hl,hl
+  add hl,bc
+;HL is 13A
+;DE is 6A
+  add a,a
+  jr nc,+_
+  inc h
+  inc h
+  inc h
+  .db $FE
+_:
+  add hl,de
+  ld c,32
+  add hl,bc
+  add hl,hl
+  sla l
+  ld a,h
+  adc a,b
+  ld c,a
+
+;Now do pi/2-x if needed (pi/2 = 64, here)
+  pop af
+  ret nc
+  ld a,64
+  sub c
+  ld c,a
+  ret

+ 31 - 0
src/math/gcdHL_DE.z80

@@ -0,0 +1,31 @@
+gcdHL_DE:
+;gcd(HL,DE)->HL
+;binary GCD algorithm
+    ld a,h \ or l \ ret z
+    ex de,hl
+    ld a,h \ or l \ ret z
+    sbc hl,de
+    jr z,step4
+    add hl,de
+    ld b,1
+    ld a,e \ or l \ rra \ jr c,+_
+    inc b
+    rr h \ rr l
+    rr d \ rr e
+    ld a,e \ or l \ rra \ jr nc,$-12
+_:
+    srl h \ rr l \ jr nc,$-4 \ adc hl,hl
+    ex de,hl
+_:
+    srl h \ rr l \ jr nc,$-4 \ adc hl,hl
+    xor a \ sbc hl,de
+    jr z,step4
+    jr nc,-_ \ sub l \ ld l,a \ sbc a,a \ sub h \ ld h,a
+    jp -_-1
+step4:
+    ex de,hl
+    dec b
+    ret z
+    add hl,hl
+    djnz $-1
+    ret

+ 171 - 0
src/math/mul16.z80

@@ -0,0 +1,171 @@
+HL_Times_BC:
+;Inputs:
+;     HL and BC are factors
+;Outputs:
+;     DEHL is the 32-bit value of the product
+;     BC is unchanged
+;     A is 0
+  ex de,hl
+DE_Times_BC:
+
+;This was made by Runer112
+;Tested by jacobly
+mul16:
+;BC*DE --> DEHL
+; ~544.887cc as calculated in jacobly's test
+;min: 214cc  (DE = 1)
+;max: 667cc
+;avg: 544.4507883cc   however, deferring to jacobly's result as mine may have math issues ?
+;177 bytes
+	ld	a,d
+	ld	d,0
+	ld	h,b
+	ld	l,c
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit14
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit13
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit12
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit11
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit10
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit9
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit8
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit7
+	ld	a,e
+ 	and	%11111110
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit6
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit5
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit4
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit3
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit2
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit1
+	add	a,a
+	jr	c,Mul_BC_DE_DEHL_Bit0
+	rr	e
+	ret	c
+	ld	h,d
+	ld	l,e
+	ret
+
+Mul_BC_DE_DEHL_Bit14:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit13
+	add	hl,bc
+	adc	a,d
+Mul_BC_DE_DEHL_Bit13:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit12
+	add	hl,bc
+	adc	a,d
+Mul_BC_DE_DEHL_Bit12:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit11
+	add	hl,bc
+	adc	a,d
+Mul_BC_DE_DEHL_Bit11:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit10
+	add	hl,bc
+	adc	a,d
+Mul_BC_DE_DEHL_Bit10:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit9
+	add	hl,bc
+	adc	a,d
+Mul_BC_DE_DEHL_Bit9:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit8
+	add	hl,bc
+	adc	a,d
+Mul_BC_DE_DEHL_Bit8:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit7
+	add	hl,bc
+	adc	a,d
+Mul_BC_DE_DEHL_Bit7:
+	ld	d,a
+	ld	a,e
+	and	%11111110
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit6
+	add	hl,bc
+	adc	a,0
+Mul_BC_DE_DEHL_Bit6:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit5
+	add	hl,bc
+	adc	a,0
+Mul_BC_DE_DEHL_Bit5:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit4
+	add	hl,bc
+	adc	a,0
+Mul_BC_DE_DEHL_Bit4:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit3
+	add	hl,bc
+	adc	a,0
+Mul_BC_DE_DEHL_Bit3:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit2
+	add	hl,bc
+	adc	a,0
+Mul_BC_DE_DEHL_Bit2:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit1
+	add	hl,bc
+	adc	a,0
+Mul_BC_DE_DEHL_Bit1:
+	add	hl,hl
+	adc	a,a
+	jr	nc,Mul_BC_DE_DEHL_Bit0
+	add	hl,bc
+	adc	a,0
+Mul_BC_DE_DEHL_Bit0:
+	add	hl,hl
+	adc	a,a
+	jr	c,Mul_BC_DE_DEHL_FunkyCarry
+	rr	e
+	ld	e,a
+	ret	nc
+	add	hl,bc
+	ret	nc
+	inc	e
+	ret	nz
+	inc	d
+	ret
+
+Mul_BC_DE_DEHL_FunkyCarry:
+	inc	d
+	rr	e
+	ld	e,a
+	ret	nc
+	add	hl,bc
+	ret	nc
+	inc	e
+	ret

+ 75 - 0
src/math/ncr_HL_DE.z80

@@ -0,0 +1,75 @@
+;Written by Zeda
+
+; Requires
+;    mul16          ;BC*DE ==> DEHL
+;    DEHL_Div_BC    ;DEHL/BC ==> DEHL
+
+ncr_HL_DE:
+;"n choose r", defined as n!/(r!(n-r)!)
+;Computes "HL choose DE"
+;Inputs: HL,DE
+;Outputs:
+;   HL is the result
+;       "HL choose DE"
+;   carry flag reset means overflow
+;Destroys:
+;   A,BC,DE,IX
+;Notes:
+;   Overflow is returned as 0
+;   Overflow happens if HL choose DE exceeds 65535
+;   This algorithm is constructed in such a way that intermediate
+;   operations won't erroneously trigger overflow.
+;66 bytes
+  ld bc,1
+  or a
+  sbc hl,de
+  jr c,ncr_oob
+  jr z,ncr_exit
+  sbc hl,de
+  add hl,de
+  jr c,$+3
+  ex de,hl
+  ld a,h
+  or l
+  push hl
+  pop ix
+ncr_exit:
+  ld h,b
+  ld l,c
+  scf
+  ret z
+ncr_loop:
+  push bc \ push de
+  push hl \ push bc
+  ld b,h
+  ld c,l
+  call mul16          ;BC*DE ==> DEHL
+  pop bc
+  call DEHL_Div_BC    ;result in DEHL
+  ld a,d
+  or e
+  pop bc
+  pop de
+  jr nz,ncr_overflow
+  add hl,bc
+  jr c,ncr_overflow
+  pop bc
+  inc bc
+  ld a,b
+  cp ixh
+  jr c,ncr_loop
+  ld a,ixl
+  cp c
+  jr nc,ncr_loop
+  ret
+ncr_overflow:
+  pop bc
+  xor a
+  ld b,a
+ncr_oob:
+  ld h,b
+  ld l,b
+  ret
+
+DEHL_Div_BC:
+#include "math/DEHL_Div_BC_special.z80"

+ 51 - 0
src/math/rand_single.z80

@@ -0,0 +1,51 @@
+#ifndef included_rand
+#define included_rand
+randinit:
+  ld a,r
+  ld hl,seedsingle0
+  xor (hl) \ ld (hl),a \ inc hl
+  xor (hl) \ ld (hl),a \ inc hl
+  xor (hl) \ ld (hl),a \ inc hl
+  xor (hl) \ ld (hl),a \ inc hl
+  xor (hl) \ ld (hl),a \ inc hl
+  xor (hl) \ ld (hl),a \ inc hl
+  xor (hl) \ ld (hl),a \ inc hl
+  or 97   ;no particular reason
+  or (hl) \ ld (hl),a
+  ret
+rand:
+;Tested and passes all CAcert tests
+;Uses a very simple 32-bit LCG and 32-bit LFSR
+;it has a period of 18,446,744,069,414,584,320
+;roughly 18.4 quintillion.
+;LFSR taps: 0,2,6,7  = 11000101
+;323cc
+;Thanks to Runer112 for his help on optimizing the LCG and suggesting to try the much simpler LCG. On their own, the two are terrible, but together they are great.
+;Uses 64 bits of state
+  ld hl,(seedsingle0)
+  ld de,(seedsingle0+2)
+  ld b,h
+  ld c,l
+  add hl,hl \ rl e \ rl d
+  add hl,hl \ rl e \ rl d
+  inc l
+  add hl,bc
+  ld (seedsingle0),hl
+  ld hl,(seedsingle0+2)
+  adc hl,de
+  ld (seedsingle0+2),hl
+  ex de,hl
+;lfsr
+  ld hl,(seedsingle1)
+  ld bc,(seedsingle1+2)
+  add hl,hl \ rl c \ rl b
+  ld (seedsingle1+2),bc
+  sbc a,a
+  and %11000101
+  xor l
+  ld l,a
+  ld (seedsingle1),hl
+  ex de,hl
+  add hl,bc
+  ret
+#endif

+ 123 - 0
src/modemenu.z80

@@ -0,0 +1,123 @@
+modemenu:
+
+;Set the font to the pixel-aligned font
+  ld a,2
+  ld (textmode),a
+
+  ld hl,modemenu_header
+  ld de,mode_menu_header_RAM
+  ld bc,6
+  ldir
+
+  ld (menutopinit),bc
+  ld (menudefault),bc
+
+  ld bc,$120D
+  ld de,$3B27
+  ld hl,mode_menu_header_RAM
+  ld ix,modemenu_getselect
+
+  call menuroutine
+
+;Set the font to the grid-aligned
+  xor a
+  ld (textmode),a
+  ret
+
+modemenu_getselect:
+  jr nc,modemenu_opt
+; If the user pressed [Enter], then we need to re-enter!
+  ld a,(k_save)
+  sub 9
+  ret nz
+  call +_
+  jp menu_render
+_:
+  ld a,(menucur)
+  dec a
+  jp z,toggle_token_hook
+  ld a,(flags+appLwrCaseFlag)
+  xor 1<<lwrCaseActive
+  ld (flags+appLwrCaseFlag),a
+  ret
+modemenu_opt:
+  ld a,c
+  cp 2
+  ccf
+  ret c
+  dec a
+  jr nz,+_
+  ld hl,s_Token_Hook
+  ld de,mode_menu_scrap
+  ld bc,11
+  ldir
+
+
+  bit tokenHookActive,(iy+hookflags3)
+  jr z,s_onoff
+  ;verify it is the same page as Grammer
+  ld hl,(tokenHookPtr+2)
+  in a,(6)
+  cp l
+  ld hl,s_Off
+  jr nz,$+5
+  ld hl,s_On
+  call mov4
+  ld hl,mode_menu_scrap
+  or a
+  ret
+
+_:
+  ld hl,s_Lowercase
+  ld de,mode_menu_scrap
+  ld bc,10
+  ldir
+  bit lwrCaseActive,(iy+appLwrCaseFlag)
+s_onoff:
+; z means OFF, nz means ON
+  ld hl,s_On
+  jr nz,$+5
+  ld hl,s_Off
+  call mov4
+  ld hl,mode_menu_scrap
+  ret
+
+toggle_token_hook:
+;Gotta toggle the token hook
+;Point to the page and load the token hook page in A
+  ld hl,tokenHookPtr+2
+  in a,(6)
+
+;If token hook is inactive, we need to set it to Grammer's
+  bit tokenHookActive,(iy+hookflags3)
+  jr z,tokenhook_on
+
+;The token hook is active.
+;If it is Grammer's, need to reset
+  cp (hl)
+  jr z,resetTokenHook
+
+tokenhook_on:
+;Now we have to actually set the hook
+;We'll do it manually, I still have flashbacks to thepenguin77's April Fools Joke of 2011
+;HL already points to where the page should be written, and A is the page
+  ld (hl),a
+  ld hl,TokenHook
+  ld (tokenHookPtr),hl
+  set tokenHookActive,(iy+hookflags3)
+  ret
+resetTokenHook:
+  res tokenHookActive,(iy+hookflags3)
+  ret
+
+
+modemenu_header:
+  .db "MODES",0
+s_Lowercase:
+  .db "LOWERCASE",$29,0
+s_Token_Hook:
+  .db "TOKEN",$29,"HOOK",$29,0
+s_On:
+  .db "ON",0
+s_Off:
+  .db "OFF",0

+ 150 - 0
src/module.z80

@@ -0,0 +1,150 @@
+;This is the code to open up and execute code from a module.
+#define binmin    TempWord4
+#define binmax    TempWord5
+#define baseptr   TempWord2
+#define basepage  TempWord3
+
+
+module:
+#ifndef INCLUDE_GRAMPKG
+  bit nogrampkg,(iy+InternalFlags)
+  jr z,skipgrampkg
+  ld hl,s_grampkg
+  rst rMov9ToOP1
+  bcall(_ChkFindSym)
+  ld a,b
+  ld b,0
+  call module_locate+6
+#else
+  in a,(6)
+  dec a
+  ld hl,grampkg_start
+  ld bc,grampkg_end-grampkg_start
+  call module_located
+#endif
+  ret c
+skipgrampkg:
+  ld hl,module_count
+  ld a,(hl)
+  or a
+  jr z,no_module_loc
+_:
+  inc hl
+  ld e,(hl)
+  inc hl
+  ld d,(hl)
+  push hl
+  push af
+  ex de,hl
+  call module_locate
+  pop hl
+  ld a,h
+  pop hl
+  ret c
+  dec a
+  jr nz,-_
+no_module_loc:
+  jp nc,ErrPkgNotFound
+  ret
+module_locate:
+  call GetVarName_
+  call GetVarInfo_
+  ccf
+  ret nc
+;  jp c,module_not_found
+  call GetVarInfoVarFound
+  ;now HL points to data, DE points to VAT entry, BC is size, A is page
+module_located:
+;We already know the header is valid. We can advance HL by 6 then read 2 bytes
+  ld bc,8
+  ld de,cmdShadow
+  call ReadArc
+  ex de,hl
+;table size. Make sure it doesn't exceed 384 entries, make sure not 0
+  ld hl,(cmdShadow+6)
+  ld c,a
+  ld a,h
+  or l
+  ret z
+  ld a,c
+  ld bc,385     ;
+  sbc hl,bc
+  jr nc,module_not_found
+  add hl,bc
+  add hl,hl
+  ld b,h
+  ld c,l
+  ld hl,moduleExec
+  ld (binmin),hl
+  ex de,hl
+  call ReadArc
+  ld (baseptr),hl   ;This is the base address of the data
+  ld (basepage),a   ;
+  ld (binmax),de
+  ;Now we need to search for the string at (parsePtr)
+binsearchloop:
+  ld hl,(binmax)
+  ld de,(binmin)
+  or a
+  sbc hl,de
+  jr z,nomatch
+  rr h
+  rr l
+  res 0,l
+  add hl,de
+  push hl
+  ld e,(hl)
+  inc hl
+  ld d,(hl)
+  ld a,d
+
+  rlca
+  rlca
+  and 3
+  ld hl,basepage
+  add a,(hl)
+  ld hl,(baseptr)
+  res 7,d
+  res 6,d
+  adc hl,de
+  jp po,+_
+  res 7,h
+  set 6,h
+  inc a
+_:
+  call bincompare
+  jr z,binmatch
+  pop hl
+  jr c,+_
+  inc hl
+  inc hl
+  ld (binmin),hl
+  jr binsearchloop
+_:
+  ld (binmax),hl
+  jr binsearchloop
+binmatch:
+;a match was found
+  pop bc
+  inc de
+  ld (parsePtr),de
+  ld bc,3
+  ld de,cmdShadow
+  call ReadArc
+  ld bc,(cmdShadow+1)
+  ld de,moduleExec
+  call ReadArc
+  call moduleExec
+  scf
+  ret
+nomatch:
+module_not_found:
+  or a
+  ret
+
+#undefine binmin    TempWord4
+#undefine binmax    TempWord5
+#undefine baseptr   TempWord2
+#undefine basepage  TempWord3
+
+;852 bytes left up to here

+ 92 - 0
src/module_old.z80

@@ -0,0 +1,92 @@
+  ld a,b
+  or a
+  jp nz,ErrPkgNotFound
+  ex de,hl
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+  inc b
+  dec b
+  jr nz,+_
+  ld a,c
+  cp 4
+  jp c,ErrBadToken
+_:
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+  ld a,b
+  or c
+  jp z,ErrBadToken
+  ld de,(parsePtr)
+  call binSearch
+  jp nz,ErrBadToken
+  ld (parsePtr),de
+  ld c,(hl)
+  inc hl
+  ld b,(hl)
+  inc hl
+  ld de,moduleExec
+  ldir
+  jp moduleExec
+binSearch:
+;HL points to the binLUT
+;BC is the size
+;DE points to the token to find
+  ld (binLUT),hl
+  ld (binmax),bc
+  ld hl,0
+  ld (binmin),hl
+;binsearchloop:
+  ld hl,(binmax)
+  ld bc,(binmin)
+  or a
+  sbc hl,bc
+  ret c
+  rr h \ rr l
+  add hl,bc
+  call bincompare
+  ret z
+  jr c,+_   ;means input<compare
+  ld (binmin),hl
+  jp binsearchloop
+_:
+  ld (binmax),hl
+  jp binsearchloop+3
+bincompare:
+;z returned if a match, DE needs to point to new parsePtr, HL points to byte after ending byte in teh matched code
+;nz returned if no match, return HL unchanged.
+  push hl
+  add hl,hl
+  ld bc,(binLUT)
+  add hl,bc
+  ld a,(hl)
+  inc hl
+  ld h,(hl)
+  ld l,a
+  add hl,bc
+  push de
+_:
+  ld a,(de) \ cp (hl)
+  inc de \ inc hl
+  jr nz,+_
+  call isEOT
+  jr nz,-_
+  pop af
+  pop af
+  cp a
+  ret
+_:
+  pop de
+  pop hl    
+  ret
+isEOT:
+;End Of Token includes (, ' ', {, [, \n, :
+  or a \ ret z
+  cp $3E \ ret z  ;:
+  cp $3F \ ret z  ;\n
+  cp $10 \ ret z  ;(
+  cp $29 \ ret z  ;space
+  cp $3A \ ret    ;.

+ 177 - 0
src/parserhook.z80

@@ -0,0 +1,177 @@
+GrammerHook:
+  .db 83h
+  or a
+  jr nz,exithook3
+  di
+  push hl
+  push de
+  push bc
+  push af
+  ld de,(progstart)
+  ld a,(de)
+  cp $5F      ;make sure it is the prgm Token. I just realized that in older versions, you could have any 1-byte token instead of the prgm token!
+  jr z,+_
+exithook1:
+  pop af
+  pop bc
+  pop de
+  pop hl
+exithook3:
+  cp a
+  ret
+_:
+  ld hl,(progend)
+  sbc hl,de
+  inc de
+  ld b,h
+  ld c,l
+  ld a,h
+  or a
+  jr z,+_
+  ld bc,8
+_:
+  ld a,c
+  or a
+  jr z,exithook1
+  cp 9
+  jr c,+_
+  ld c,8
+_:
+  ex de,hl
+  ld de,OP1
+  ld a,5
+  ld (de),a
+  inc de
+  ldir
+  xor a
+  ld (de),a
+  call SetUpData
+  call IsOP1GrammerProg
+  jr nz,+_
+;  ld hl,OP1
+;  ld de,OP5
+;  call mov9
+  bcall(_OP1ToOP5)
+  pop af
+  pop bc
+  pop de
+  pop hl
+  call SelectedProg
+  or 1
+  ret
+_:
+  ld hl,cmdShadow+2             ;location of header
+; ION =BB6DC918
+; MOS =BB6DC901
+; DCS7=BB6DAAC9
+; Gram=BB6D55C9
+  ld a,(hl) \ cp $BB \ jp nz,HookEnd
+  inc hl \ ld a,(hl) \ cp $6D \ jp nz,HookEnd
+  inc hl \ ld a,(hl) \ cp $C9 \ jp z,MOSIONErr
+  ld c,a
+  inc hl \ ld a,(hl) \ cp $C9 \ jp nz,HookEnd
+  ld a,c \ cp $AA \ jp z,DCSErr
+#ifdef SHELL_BROKEN
+  jp GramErr
+#endif
+HomeRunASM:
+
+  ld hl,(TempWord5) \ ld bc,(TempWord4)
+  jr nz,+_
+  inc hl \ inc hl \ dec bc \ dec bc
+_:
+  inc hl \ inc hl \ dec bc \ dec bc
+  ld de,9D94h
+  or a \ sbc hl,de
+  add hl,de
+  ld de,OP1
+  jr nz,+_
+  pop hl \ pop hl \ pop hl \ pop hl
+  xor a
+  ret
+_:
+  ldir
+  xor a
+  ld (de),a
+  ld a,5
+  ld (OP1),a
+  call SetUpData+3
+  call IsOP1GrammerProg
+  jr nz,EndHook
+
+;  ld hl,OP1
+;  ld de,OP5
+;  call mov9
+  bcall(_OP1ToOP5)
+  pop af
+  pop bc
+  pop de
+  pop hl
+  call SelectedProg
+  or 1
+  ret
+EndHook_prepush:
+  push af
+  push af
+  push af
+  push af
+EndHook:
+  ld hl,cmdShadow+2             ;location of header
+; ION =BB6DC918
+; MOS =BB6DC901
+; DCS7=BB6DAAC9
+; Gram=BB6D55C9
+  ld a,(hl) \ cp $BB \ jr nz,HookEnd
+  inc hl \ ld a,(hl) \ cp $6D \ jr nz,HookEnd
+  inc hl \ ld a,(hl) \ cp $C9
+  jr z,HookEnd
+  ld a,55h
+  cp (hl)
+  jr nz,HookEnd
+  inc hl \ ld a,(hl) \ cp $C9
+  jr c,+_
+  add hl,bc
+_:
+  push hl \ push bc
+  ld h,b \ ld l,c
+  bcall(_EnoughMem)
+  jp c,ErrMEM
+  ex de,hl
+;HL # bytes
+;DE addr
+  ld de,9D95h ;start VarRAM
+  push de
+  bcall(_InsertMem)
+  pop de \ pop bc \ pop hl
+  ld a,(TempWord3)
+  push de \ push bc
+  call ReadArc
+  ld hl,0
+  add hl,sp
+  ld (SPSave),hl
+  call 9D95h ;start VarRAM
+  pop de \ pop hl
+;Delmem: HL address
+;        DE # of bytes
+  bcall(_DelMem)
+;===============================================================
+  .db $F6   ;start of `or *`. Since `xor a`=AF !=0, this will result in the z flag reset, always.
+HookEnd:
+  xor a
+  pop hl
+  ld a,h
+  pop bc
+  pop de
+  pop hl
+  ret
+
+
+CompatCall:
+  call setupRAMdata
+IsOP1GrammerProg:
+  ld (iy+UserFlags),8
+  bcall(_ChkFindSym)
+  ld (VATPtr),hl
+  jp nc,isStartMenu_valid
+  or 1
+  ret

+ 30 - 0
src/parserinterrupt.z80

@@ -0,0 +1,30 @@
+parser_interrupt:
+;First check the interrupt pointer. If it is NULL, then return
+  ld hl,(IntLoc)
+  ld a,h \ or l
+  ret z
+  ex de,hl
+
+;Decrement the counter. If it hits zero, fire the interrupt.
+  ld hl,(IntCount)
+  dec l
+  jr nz,+_
+  dec h
+  jr nz,+_
+
+;Need to save the current parser pointer and BC
+  ld hl,(parsePtr)
+  push hl
+  ld (parsePtr),de
+  set IntActiveFlag,(iy+InternalFlag)
+  push bc
+  call ParserNext
+  pop bc
+  pop hl
+  ld (parsePtr),hl
+  ld hl,(IntMax)
+
+_:
+  ld (IntCount),hl
+  res IntActiveFlag,(iy+InternalFlag)
+  ret

+ 149 - 0
src/precompile.z80

@@ -0,0 +1,149 @@
+;Put the name in OP1
+  ld hl,GramTempName
+  rst rMov9ToOP1
+
+;Now we create the var
+  ld a,16h
+  ld hl,(TempWord4)
+  bcall(_CreateVar)
+  inc de
+  inc de
+
+;Copy the source to RAM
+;If size is 0, just exit.
+  ld bc,(TempWord4)
+  ld a,b
+  or c
+  jr nz,+_
+  pop hl
+  ret
+_:
+
+  ld hl,(TempWord5)
+  ld a,(TempWord3)
+  call nz,ReadArc
+
+;Now we copy the temp var's name back to OP1 and call it good :)
+  ld hl,OP4
+  rst rMov9ToOP1
+
+
+; ;Here is our pre-compiling code
+; ;If the size is 0, exit
+;   ld hl,(TempWord4)
+;   ld a,h \ or l
+;   ret z
+;
+; ;Put the name in OP1
+;   ld hl,GramTempName
+;   rst rMov9ToOP1
+;
+; ;How much RAM do we have that we can allocate?
+;  bcall(_MemChk)
+;
+; ;Take off some bytes to make room for the VAT entry and size bytes
+;  ld bc,-20     ;at some point I have to actually calculate this. It might be -19.
+;  add hl,bc
+;  jp nc,err_LowMem   ;Not even enough room for a new VAT pointer !
+;
+; ;Now we create the var, occupying all of RAM
+;   ld a,16h
+;   ld (size_of_buffer),hl
+;   bcall(_CreateVar)
+;
+; ;Keep the pointer to the start of the buffer safe
+;   inc de \ inc de
+;   ld (start_of_prog),de
+;
+; ;Copy the source code to the buffer
+;   ld a,(TempWord3)
+;   ld bc,(TempWord4)
+;   ld hl,(TempWord5)
+;   call ReadArc
+;
+; ;Now we set up for parsing
+;   ld (end_of_src),de
+; ;  ld hl,(start_of_prog)
+; ;  ld (in_head),hl
+; ;  ld (out_head),hl
+; ;  ex de,hl
+;   ld de,(start_of_prog)
+;   ld hl,(size_of_buffer)
+;   add hl,de
+;   ld (buffer_top),hl
+;   ld (data_top),hl
+;   ld h,d
+;   ld l,e
+; ;HL points to the head of the input
+; ;DE points to the head of the output
+;
+;
+; ;  ld de,(end_of_src)
+; ;  jp compile_dealloc
+;
+; _:
+;   ld a,(hl)
+;   call compile
+;
+; ;Make sure that HL<end_of_src
+;   ld a,(end_of_src)
+;   sub l
+;   ld a,(end_of_src+1)
+;   sbc a,h
+;   jr nc,-_
+;
+; ;Now we need to merge the output and data sections
+; ;DE points to the top of the output
+;   ld hl,(buffer_top)
+;   ld bc,(data_top)
+;   or a
+;   sbc hl,bc
+;   jr z,+_
+; ;Need to copy HL bytes at BC to DE.
+; ;Swap HL and BC to use LDIR
+;   ld a,h
+;   ld h,b
+;   ld b,a
+;   ld a,l
+;   ld l,c
+;   ld c,a
+;   ldir
+; _:
+;
+; compile_dealloc:
+; ;Now we need to deallocate unused RAM
+; ;DE points to the end of the parsed code
+;  ld hl,(start_of_prog)
+;  ex de,hl
+;  or a
+;  sbc hl,de
+;  ex de,hl
+; ;DE is the actual size, HL points to the start of data
+;
+; ;Replace the size bytes
+;  dec hl
+;  ld b,(hl)
+;  ld (hl),d
+;  dec hl
+;  ld c,(hl)
+;  ld (hl),e
+;
+; ;Now we need to get rid of BC-DE bytes at HL+DE+2
+;  add hl,de
+;  inc hl
+;  inc hl
+;
+; ;Now we need to get rid of BC-DE bytes at HL
+;  ld a,c
+;  sub e
+;  ld e,a
+;  ld a,b
+;  sbc a,d
+;  ld d,a
+;
+; ;Now we need to get rid of DE bytes at HL
+;   bcall(_DelMem)
+;
+; ;Now we copy the temp var's name back to OP1 and call it good :)
+;   ld hl,OP4
+;   rst rMov9ToOP1

+ 95 - 0
src/progmeta.z80

@@ -0,0 +1,95 @@
+#define label_index_size OP1
+;This code sets up data for the program to execute
+;It indexes labels, and sets up space for variables.
+progmeta:
+;Set first byte to $FF to indicate the start of the labels index.
+;  Next two bytes are size
+;  Need to verify at least five bytes.
+;
+  ld hl,(OPS)
+  ld de,(FPS)
+  or a
+  sbc hl,de
+  ld de,5
+  sbc hl,de
+  ret c   ;not enough RAM
+  ld b,h
+  ld c,l
+  ld hl,(OPS)
+  srl b
+  rr c
+  inc bc
+;BC is the number entries available
+  ld (hl),$FF
+  dec hl
+  dec hl
+  dec hl
+;  ld (label_index_ptr),hl
+  ld (label_index_size),bc
+;
+  ex de,hl      ;points to where to write the pointers
+  ld bc,(progStart)
+  ld hl,(progEnd)
+  xor a
+  sbc hl,bc
+  ld b,h
+  ld c,l
+  ld hl,(progStart)
+;HL points to the start of the program
+;BC is the size of the program
+  call +_
+;gotta update pointers and such
+;((OPS)-DE-3)/2 is number of entries
+  ld hl,(OPS)
+  or a
+  sbc hl,de
+  srl h
+  rr l
+  dec hl
+  ex de,hl
+  ld hl,(OPS)
+  dec hl
+  ld (hl),d
+  dec hl
+  ld (hl),e
+  ret
+_:
+  ld a,$3A    ;decimal point token
+  cpir
+  ret nz
+  ret po
+  ex de,hl
+  ld (hl),d
+  dec hl
+  ld (hl),e
+  dec hl
+  ex de,hl
+  push hl
+  ld hl,(label_index_size)
+  dec hl
+  ld (label_index_size),hl
+  ld a,h
+  or l
+  pop hl
+  jr nz,-_
+  ret
+#undefine label_index_size
+
+pushlabel:
+;write the label string to the stack, null-terminated, followed by the address
+  ret
+findlabel:
+;Check if the next byte is "
+;   - if not, then just exit
+;   - Otherwise, look for the label in the label stack
+;     - if found
+;       - If the pointer is not zero, write to the output
+;         stream .db $ED \ .dw addr
+;       - If the pointer is zero, increment the size field
+;         and add the address to the list.
+;     - Otherwise, write the label string to the stack,
+;       null-terminated, followed by 0x0000, then a
+;       16-bit word for the number of references (in this case,
+;       initialize to 0x0001 the address), followed by the
+;       address where to write when found
+  ret

+ 98 - 0
src/ramcode.z80

@@ -0,0 +1,98 @@
+RAMCodeStart:
+
+_:
+IncHLMem1 = -_-RAMCodeStart+ramCode
+  inc h
+  ret po
+  ld h,a
+  in a,(6)
+  inc a
+  out (6),a
+  ld a,h
+  ld h,40h
+  ret
+
+_:
+next_page_call = -_-RAMCodeStart+ramCode
+;121cc
+  push af
+  in a,(6)
+  dec a
+  out (6),a
+  pop af
+next_page_call_address = $-RAMCodeStart+ramCode+1
+  call 0
+  push af
+  in a,(6)
+  inc a
+  out (6),a
+  pop af
+  ret
+_:
+prev_page_call = -_-RAMCodeStart+ramCode
+;121cc
+  push af
+  in a,(6)
+  inc a
+  out (6),a
+  pop af
+prev_page_call_address = $-RAMCodeStart+ramCode+1
+  call 0
+  push af
+  in a,(6)
+  dec a
+  out (6),a
+  pop af
+  ret
+_:
+bincompare = -_-RAMCodeStart+ramCode
+  ld de,(parsePtr)
+  out (6),a
+  .db $FE   ;start of cp *
+_:
+  inc de
+  ld a,(de)
+  cp (hl)
+  jr nz,+_
+  call isEOT
+  jr z,+_
+  inc l \ call z,incHLMem1
+  ld a,(hl)
+  or a
+  jr nz,-_
+_:
+  in a,(6)
+  ld b,a
+;  push af
+_:
+bincomparepagerestore = -_-RAMCodeStart+ramCode+1
+  ld a,0
+  out (6),a
+;  pop af
+  ld a,b
+  ret
+
+isEOT    = $-RAMCodeStart+ramCode
+;End Of Token includes (, ' ', {, [, \n, :
+  or a \ ret z
+  cp $10 \ ret z  ;(
+  cp $29 \ ret  ;space
+
+#ifdef include_interrupt
+.fill $8181-$+RAMCodeStart-ramCode,0
+interrupt_main = $-RAMCodeStart+ramCode
+  push af
+  in a,(6)
+  ld (interrupt_return_page),a
+interrupt_page = $-RAMCodeStart+ramCode+1
+  ld a,0
+  out (6),a
+  call Interrupt
+interrupt_return_page = $-RAMCodeStart+ramCode+1
+  ld a,0
+  out (6),a
+  pop af
+  ret
+#endif
+
+RamCodeEnd:

+ 57 - 0
src/readarc.z80

@@ -0,0 +1,57 @@
+;RAM: 21+21n
+;ARC, but no boundary: 114+21n
+;Arc, on two pages: 21n+269
+;Arc, on three pages: 21n+355
+  or a
+  jp z,ReadRAM    ;different routine in the App,
+  out (6),a
+  adc hl,bc
+;  jr c,read_from_Arc_blocks   ;if you need this, you probably need a different routine. this will write on page 0.
+  jp p,read_from_ARC_noboundary
+read_from_Arc_blocks = $-ReadArcData+TSA
+;If we make it here, we know that we cross a page boundary (or in one case, we just reach it and need to return on the next page).
+;We will read in blocks to avoid checking page boundaries
+;To do so, we first read up to 0x8000 - HL bytes
+  xor a
+  sbc hl,bc
+  sub l \ ld l,a
+  ld a,$80 \ sbc a,h \ ld h,a
+  ;now we will subtract BC-HL  -> BC
+  ld a,c \ sub l \ ld c,a
+  ld a,b \ sbc a,h \ ld b,a
+  push bc
+  ld b,h
+  ld c,l
+  xor a \ sub l \ ld l,a
+  ld a,$80 \ sbc a,h \ ld h,a
+  ;now we read the first block
+block_loop = $-ReadArcData+TSA
+  ldir
+  ;now we increment the page and continue reading from $4000
+  in a,(6)
+  inc a
+  out (6),a
+  ld h,40h
+  pop bc
+  ;if BC<$4000, just LDIR the rest
+  ld a,b
+  sub h
+  jr c,read_from_RAM
+  ld b,a
+  push bc
+  ld b,h
+  ld c,l
+  jp block_loop
+read_from_ARC_noboundary  = $-ReadArcData+TSA
+;  or a     ;already reset
+  sbc hl,bc
+read_from_RAM:
+  ldir
+  in a,(6)
+  ld b,a
+page_restore = $-ReadArcData+TSA+1
+  ld a,0
+  out (6),a
+  ld a,b
+  ld b,c
+  ret

+ 147 - 0
src/routines.z80

@@ -0,0 +1,147 @@
+;mov104:
+;  call mov52
+;mov52:
+;  call mov26
+;mov26:
+;  call mov13
+mov15: ;250cc
+  ldi
+mov14: ;234cc
+  ldi
+mov13: ;218cc
+  ldi
+mov12: ;202cc
+  ldi
+mov11:
+  ldi
+  ldi
+mov9: ;154cc
+  ldi
+mov8: ;138cc
+  ldi
+  ldi
+  ldi
+  ldi
+mov4_page0: ;74cc
+  ldi
+mov3: ;58cc
+  ldi
+  ldi
+  ldi
+  ret
+NextVAT:
+;VATptr is the ptr
+;returns z flag if no more entries
+
+  call NextVat_
+  jp VATPtrToOP1_
+NextVat_:
+  ld hl,(VATptr)
+  ld bc,-6
+  add hl,bc
+  sbc a,a   ;HL>6, so carry flag is set
+  sub (hl)
+  ld c,a
+  add hl,bc
+
+  ld a,(pTemp)
+  cp l
+  jr nz,+_
+  ld a,(pTemp+1)
+  cp h
+  jr nz,+_
+  ld hl,(VATptr)
+_:
+  ;need to verify ptr
+  ld (VATptr),hl
+  ret
+PrevVAT_valid:
+;We need to start from the bottom and search until the previous one
+  call PrevVAT_
+VATPtrToOP1_:
+  jr nz,VATPtrToOP1
+  ld hl,0
+  ld (OP1),hl
+  scf
+  ret
+VATPtrToOP1:
+  ld bc,-6
+  ld a,(hl)
+  add hl,bc
+  ld de,OP1
+  ld (de),a
+  ld b,(hl)
+_:
+  dec hl
+  inc de
+  ld a,(hl)
+  ld (de),a
+  djnz -_
+  inc de
+  xor a
+  ld (de),a
+  ret
+
+PrevVAT_:
+  ld hl,(progPtr)
+  ld de,(VATptr)
+PrevVAT_valid_with_start:
+;returns z flag is no variable is found.
+;First, set the last valid to 0
+  xor a
+  ld (TempWord2),a
+  ld (TempWord2+1),a
+  call +_
+  ld hl,(TempWord2)
+  ld a,h
+  or l
+  ld (VATPtr),hl
+  ret
+_:
+;Make sure there are previous entries
+  sbc hl,de
+  ret z
+  add hl,de
+;Check if the first entry is valid
+  push de
+  push hl
+  ld (VATPtr),hl
+  call VATPtrToOP1
+  call isStartMenu_valid
+  pop hl
+  pop de
+  jr nz,$+5
+_:
+  ld (TempWord2),hl
+  push de
+  call NextVAT_valid
+  ld hl,(VATPtr)
+  pop de
+  or a
+  sbc hl,de
+  add hl,de
+  ret z
+  jr nc,-_
+  ret
+prng16:
+;collaboration by Zeda with Runer112
+;160cc
+;26 bytes
+;cycle: 4,294,901,760 (almost 4.3 billion)
+  ld hl,(seed1)
+  ld b,h
+  ld c,l
+  add hl,hl
+  add hl,hl
+  inc l
+  add hl,bc
+  ld (seed1),hl
+  ld hl,(seed2)
+  add hl,hl
+  sbc a,a
+  and %00101101
+  xor l
+  ld l,a
+  ld (seed2),hl
+  add hl,bc
+  ret

+ 397 - 0
src/startmenu.z80

@@ -0,0 +1,397 @@
+startmenu__:
+;need to add in the options at the bottom
+;add title at the top
+;Need to set the filter flags
+;Need to draw the menu box
+;Need to show <status><name><type>
+;Show 7 programs at a time
+
+;First we set up the initial data and pointers
+  call SetUpData
+
+;Delete temp programs (archived progs are copied to temp programs)
+  bcall(_DeleteTempPrograms)
+
+;Sort the VAT, but put the calc in 15MHz mode if possible in order to speed it up
+  ld c,1
+  call SetSpeed
+
+;Set up some pointers for VAT traversal
+  ld hl,sortVAT
+  ld (next_page_call_address),hl
+  call next_page_call
+
+;Set the default gbuf to appBackUpScreen and clear it
+  ld hl,appBackUpScreen
+  ld (gbuf_temp),hl
+  ld (BufPtr),hl
+  ld (GrayBufPtr),hl
+  call ZeroMem768
+
+;Set speed to 6MHz, take advantage of A=0 fom ZeroMem768
+  out (20h),a
+
+;now we are going to draw the top and bottom fields
+;Top line
+  ;ld a,-1
+  dec a   ;A is zero from ZeroMem768
+  ld hl,appBackUpScreen+672
+  ld b,12
+  call SetSmallMem
+;bottom line
+  ld hl,appBackUpScreen+96
+  ld b,12
+  call SetSmallMem
+
+;Header text (version number)
+  ld hl,StrVersion
+  ld bc,$0301
+  call GPutSS
+;Options
+  ld hl,58
+  ld (TextRow),hl
+  call GPutSI
+  .db "Gram AppV Asm  Exit More",0
+;draw the bars between the options
+  ld de,$0111
+_:
+  ld bc,0838h
+  push de
+  ld a,d
+  call DrawRectToGraph
+  pop de
+  ld a,e
+  add a,20
+  ld e,a
+  cp 96
+  jr c,-_
+;highlight the 'Grammer' filter option
+  call highlight_Gram
+
+;Need to set the filter flags.
+  ld (iy+34),8
+
+;Draw the menu box
+  call DrawRectToGraphI \ .db 16,10,44,64,1
+  call DrawRectToGraphI \ .db 15,11,42,66,2
+redraw_menu:
+; Erase contents of the menu box
+  call DrawRectToGraphI \ .db 16,11,42,64,0
+
+;Reset the menu data
+  ld hl,(progPtr)
+  ld (VATptr),hl
+;  ld (VATptr_next),hl
+  call VATPtrToOP1
+  ld hl,0
+  ld (main_menu_cursor),hl   ;L=cursor, h=cursor_max
+  ld (main_menu_index),hl
+
+;Load the first seven entries (if possible)
+_:
+  call isStartMenu_valid
+  jr nz,+_
+  ld hl,(VATPtr)
+  ld (VATPtr_next),hl   ;just a safe place to store it
+  call NextVAT_valid_draw_advance_stepin
+  jr startVATloop
+_:
+  call NextVAT_valid_draw
+  jr c,main_menu_loop
+  ld hl,(VATPtr)
+  ld (VATPtr_next),hl   ;just a safe place to store it
+startVATloop:
+  call NextVAT_valid_draw
+  jr c,+_
+  ld a,(main_menu_cursor_max)
+  cp 7
+  jr nz,startVATloop
+_:
+  ld de,(VATPtr_next)
+  ld hl,(VATPtr)
+  ld (VATPtr_next),hl
+  ld (VATPtr),de
+main_menu_loop:
+;here we need to draw the cursor highlight
+  ld a,(main_menu_cursor)
+  ld l,a
+  add a,a
+  add a,l
+  add a,a
+  add a,11    ;y coord
+  ld b,6
+  ld c,a
+  ld de,$4010
+  push bc
+  ld a,2
+  call DrawRectToGraph
+  call GraphToLCD
+  pop bc
+  ld de,$4010
+  ld a,2
+  call DrawRectToGraph
+
+main_menu_ui_loop:
+  in a,(4)
+  and 8
+  ret z
+  call GetKeyDebounce
+  or a
+  jr z,main_menu_ui_loop
+  cp 15 \ ret z ;clear
+  cp 50 \ ret z ;F4 (Exit)
+  cp 49
+  jr z,$+6
+  cp 55
+  jr nz,+_
+  ld hl,modemenu
+  ld (next_page_call_address),hl
+  call next_page_call
+  jp startmenu__
+_:
+  cp 53 \ jr nz,+_  ;F1 (Gram)
+  ld a,(flags+34)
+  xor 8
+  ld (flags+34),a
+  ld de,$1100
+  jr highlight_option
+_:
+  cp 52 \ jr nz,+_  ;F2 (AppV)
+  ld a,(flags+34)
+  xor 64
+  ld (flags+34),a
+  ld de,1312h
+highlight_option:
+  call highlight
+  jp redraw_menu
+_:
+  cp 51 \ jr nz,+_ ;F3
+  ld a,(flags+34)
+  xor 4
+  ld (flags+34),a
+  ld de,1326h
+  jr highlight_option
+_:
+
+  ld hl,main_menu_cursor
+  cp 54     ;[2nd]
+  jr z,+_
+  cp 12     ;[*]
+  jp z,main_menu_archunarch
+  dec a \ jr z,cur_dn   ;down
+  sub 3 \ jp z,cur_up   ;up
+  cp 5      ;[Enter]-4
+  jp nz,main_menu_ui_loop
+_:
+;here ENTER is pressed
+;need to load the variable name into OP1
+  call main_menu_get_var_name
+  call isStartMenu_valid
+  call z,SelectedProgOP1
+  jp startmenu__
+
+main_menu_get_var_name:
+  ld a,(hl)
+  or a
+  jr z,selected_entry
+_:
+  push af
+  call NextVAT_valid
+  pop af
+  dec a
+  jr nz,-_
+selected_entry:
+  ld hl,(VATPtr)
+  jp VATPtrToOP1
+
+cur_dn:
+  ld a,(hl)
+  inc a
+  inc hl
+  cp (hl)
+  jr nc,+_
+  dec hl
+  ld (hl),a
+  jp main_menu_loop
+_:
+  cp 7
+  jp nz,main_menu_ui_loop
+;here we need to scroll down.
+;This means we need to advance VATPtr and VATPtr_next
+;draw VATPtr_next
+
+;first, advance VATPtr_next
+  ld hl,(VATPtr)
+  push hl
+  ld hl,(VATPtr_next)
+  ld (VATPtr),hl
+  call NextVAT_valid
+  pop hl
+  ld de,(VATPtr)
+  ld (VATPtr),hl
+  jp c,main_menu_ui_loop
+_:
+  ld (VATPtr_next),de
+;now we know there are more entries
+;shift the menu up, then draw the entry, then advance VATPtr
+  ld de,appBackUpScreen+134
+  ld hl,appBackUpScreen+206
+  ld a,36
+_:
+  call mov8
+  inc l \ inc hl
+  inc l \ inc hl
+  inc e \ inc de
+  inc e \ inc de
+  dec a
+  jr nz,-_
+;We need to clear the bottom 6 rows of pixels
+  call DrawRectToGraphI \ .db 16,47,6,64,0
+  ld a,6
+  call draw_var_name
+  call NextVAT_valid
+  ld hl,(main_menu_index)
+  inc hl
+  ld (main_menu_index),hl
+  jp main_menu_loop
+cur_up:
+  ld a,(hl)
+  or a
+  jr z,+_
+  dec (hl)
+  jp main_menu_loop
+_:
+;now we need to scroll up. Verify that main_menu_index!=0
+  ld hl,(main_menu_index)
+  ld a,h
+  or l
+  jp z,main_menu_ui_loop
+  dec hl
+  ld (main_menu_index),hl
+  ld hl,(VATPtr)
+  push hl
+  ld de,(VATPtr_next)
+  call PrevVAT_valid_with_start
+;  call PrevVAT_with_start
+  ld hl,(VATPtr)
+  ld (VATPtr_next),hl
+  pop hl
+  ld (VATPtr),hl
+  call PrevVAT_valid
+;need to shift the screen up
+  ld hl,appBackUpScreen+561
+  ld de,appBackUpScreen+633
+  ld a,36
+_:
+  ldd \ ldd \ ldd \ ldd
+  ldd \ ldd \ ldd \ ldd
+  dec l \ dec hl
+  dec l \ dec hl
+  dec e \ dec de
+  dec e \ dec de
+  dec a
+  jr nz,-_
+  call DrawRectToGraphI \ .db 16,11,6,64,0
+  call draw_var_name
+  jp main_menu_loop
+
+highlight_Gram:
+  ld de,$1100
+highlight:
+  ld bc,0739h
+  ld a,2
+  jp DrawRectToGraph
+NextVAT_valid_draw:
+  call NextVAT_valid
+  ret c
+NextVAT_valid_draw_advance_stepin:
+  ld hl,main_menu_cursor_max
+  ld a,(hl)
+  inc (hl)
+  call draw_var_name
+  or a
+  ret
+NextVAT_valid:
+  ld hl,(VATPtr)
+  push hl
+  call +_
+  pop hl
+  ret nc
+  ld (VATPtr),hl
+  ret
+_:
+  call NextVAT
+  ret c
+  call isStartMenu_valid
+  jr nz,-_
+  or a
+  ret
+draw_var_name:
+  push af
+  bcall(_ChkFindSym)
+  pop af
+  ld h,b
+  call calculate_text_coord
+  xor a
+  ld (OP1+9),a
+  or h
+  ld a,' '
+  jr z,+_
+  ld a,'*'
+_:
+  call PutSC
+  ld hl,OP1+1
+  call GPutS
+  ld a,16
+  ld (textCol),a
+  ld a,(OP1)
+  cp 15h
+  ld hl,s_appv
+  jr z,+_
+  ld hl,s_prog
+_:
+  jp GPutS
+
+main_menu_archunarch:
+; Calculate the text text coord for the archive status symbol
+  ld a,(hl)
+  push af
+  call calculate_text_coord
+  pop af
+
+  call main_menu_get_var_name
+  call isStartMenu_valid
+  jp nz,main_menu_loop
+  ; ld a,(OP1)
+  ; push af
+  bcall(_Arc_Unarc)
+
+; Need to fix the RAM code after archiving/unarchiving.
+  call setup_readarc
+
+;   pop af
+;   ld (OP1),a
+;
+; ; Need to overwrite the archive status symbol
+;   bcall(_ChkFindSym)
+;   inc b
+;   dec b
+;   ld a,' '
+;   jr z,+_
+;   ld a,'*'
+; _:
+;   call PutSC
+
+  jp redraw_menu
+
+
+calculate_text_coord:
+  ld c,a
+  add a,a
+  add a,c
+  add a,a
+  add a,11    ;y coord
+  ld c,a
+  ld b,4
+  ld (textRow),bc
+  ret

+ 97 - 0
src/subroutines/ConvOP1.z80

@@ -0,0 +1,97 @@
+ConvOP1:
+  ld hl,OP1
+convFloat:
+;Inputs: HL points to the TI Float.
+;Outputs: The float is converted to a 16-bit integer held in DE, or LSB in A.
+;68cc if not a number
+;93cc          on (0,1)
+;154.140625cc  on [1,10) or 0
+;324.5159375cc on [10,100)
+;435.6565625cc on [100,1000)
+;540.031875cc  on [1000,10000)
+;651.1725cc    on [10000,100000)
+;118cc         if >=100000
+;Average for integers on [0,65535]: ~632.43cc
+  call +_
+  ld a,e
+  ret
+_:
+  xor a
+  ld d,a
+  ld e,a
+  or (hl)
+  and 31
+  ret nz
+  inc hl
+  ld a,(hl)
+  sub 80h
+  ret c
+  inc hl
+  jr z,lastdigit2
+  cp 5
+  ret nc
+  ld b,a
+
+_:
+  ;multiply DE by 100
+  ex de,hl
+  ld a,b
+  sla l
+  add hl,hl
+  ld b,h
+  ld c,l
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  add hl,hl
+  add hl,hl
+  add hl,bc
+  ex de,hl
+  ld b,a
+  call convBCDbyte
+  inc hl
+  dec b
+  ret z
+  djnz -_
+lastdigit:
+  ex de,hl
+  ld b,h
+  ld c,l
+  add hl,hl
+  add hl,hl
+  add hl,bc
+  add hl,hl
+  ex de,hl
+lastdigit2:
+;49+{0,8
+;min: 49cc
+;max: 57cc
+;avg: 49+8*4.5/256 = 49.140625
+  ld a,(hl)
+  rrca
+  rrca
+  rrca
+  rrca
+  and 15
+  add a,e
+  ld e,a
+  ret nc
+  inc d
+  ret
+convBCDbyte:
+;min: 60cc
+;max: 68cc
+;avg: 60+8*(99*98/2/100)/256 = 61.5159375cc
+  ld a,(hl)   ;\ I feel particularly proud of this code, so feel free to use it ^~^
+  and $F0     ; |It converts a byte of BCD to an 8-bit int.
+  rra         ; |The catch is, I only have A and C to use, and (hl) is the BCD
+  ld c,a      ; |number.
+  rra         ; |If you come up with faster, please let me know and post it in
+  rra         ; |the optimized routines thread on popular TI forums.
+  sub a,c     ; |Algo: Multiply upper digit by -6, add the original byte.
+  add a,(hl)  ;/ Result is upper_digit*(-6+16)+lower_digit. Ha, repost.
+  add a,e
+  ld e,a
+  ret nc
+  inc d
+  ret

+ 56 - 0
src/subroutines/chardim.z80

@@ -0,0 +1,56 @@
+chardim:
+;Get the height and width of a char in the current font.
+;Input: A is the char
+;Output: B is the width, C is height
+;Destroys: A
+  ld b,a
+  ld a,(textmode)
+  dec a
+  jr z,var_width_size
+  dec a
+  jr z,OS_large_size
+  dec a
+  jr z,grammer_small_size
+  dec a
+  jr z,OS_small_size
+OS_large_size:
+  ld bc,$0608
+  ret
+grammer_small_size:
+  ld bc,$0406
+  ret
+
+OS_small_size:
+  call os_char_ptr
+  ld a,3
+  ld de,lfont_record
+  ld bc,1
+  call readarc
+  ld bc,(lFont_record-1)
+  ld c,6
+  ret
+
+var_width_size:
+  push hl
+  push de
+  ld hl,(FontPointer)
+  ld d,a
+  .db $C2  ;start of `jp nz,*`
+_:
+  add a,2
+  ld e,a
+  add hl,de
+  ld a,(hl)
+  ;a is w,h in nibbles
+  and 15
+  djnz -_
+  ld c,a
+  xor (hl)
+  rrca
+  rrca
+  rrca
+  rrca
+  ld b,a
+  pop de
+  pop hl
+  ret

+ 24 - 0
src/subroutines/diRestore.z80

@@ -0,0 +1,24 @@
+diRestore:
+;Disables interrupts and sets up a return function to restore them
+    ex (sp),hl
+    push hl
+    push af
+    ld hl,restoreei
+    ld a,r
+    jp pe,+_
+    ld hl,restoredi
+_:
+    di
+    pop af
+    inc sp
+    inc sp
+    ex (sp),hl
+    dec sp
+    dec sp
+    ret
+restoredi:
+    di
+    ret
+restoreei:
+    ei
+    ret

+ 18 - 0
src/subroutines/getbyte.z80

@@ -0,0 +1,18 @@
+GetByte:
+  ld d,3
+  ld bc,-1
+  xor a
+  out (0),a
+  in a,(0)
+  xor d
+  ret z
+  ld bc,0800h
+_:
+  in a,(0)
+  bit 1,a
+  jr nz,-_
+  out (0),a
+  rra
+  rl c
+  djnz -_
+  ret

+ 121 - 0
src/subroutines/heapsort.z80

@@ -0,0 +1,121 @@
+heapsort:
+;BC is the number of elements
+;IX points to the compare/swap routine
+  ld a,b
+  or c
+  ret z
+  push bc
+  call heapify
+  pop bc
+
+_:
+  dec bc
+  push bc
+  call heap_popswap
+  pop bc
+  ld a,b
+  or c
+  jr nz,-_
+  ret
+
+heap_popswap:
+  ld hl,0
+  call heap_swap
+  ld h,b
+  ld l,c
+  xor a
+  ld b,a
+  ld c,a
+heap_propogate:
+;If (BC+1)*2 == number of elements, then need to do check_prop_special
+;If (BC+1)*2 > number of elements, then we are done
+  inc bc
+  sbc hl,bc
+  ret c
+  sbc hl,bc
+  ret c
+  add hl,bc
+  add hl,bc
+  dec bc
+  jr z,heap_check_prop_special
+  push hl
+  call heap_check_prop
+  pop hl
+  jr c,heap_propogate
+  ret
+
+heap_check_prop:
+;returns BC as the index of the largest child
+;returns c flag set if still need to propogate
+;First, compare BC's children
+  push bc
+  ld h,b
+  ld l,c
+  add hl,hl
+  inc hl
+  ld b,h
+  ld c,l
+  inc hl
+  call heap_cmp
+  ;nc means HL is the bigger child
+  jr c,$+4
+  ld b,h
+  ld c,l
+  pop hl
+  push bc   ;the child node that was bigger
+  call heap_cmp
+  ;nc means the parent is bigger than the children, good
+  call c,heap_swap
+  pop bc
+  ret
+
+heap_check_prop_special:
+;There are an even number of elements, so this parent has only one child.
+;We'll do a special-case heap_check_prop
+  ld h,b
+  ld l,c
+  add hl,hl
+  inc hl
+  call heap_cmp
+  ;nc means the parent is bigger than the children, good
+  jr c,heap_swap
+  ret
+
+
+heap_swap:
+  push bc
+  push af
+  scf
+  call call_ix_01
+  pop af
+  pop bc
+  ret
+
+heap_cmp:
+  push hl
+  push bc
+  or a
+  call call_ix_01
+  pop bc
+  pop hl
+  ret
+
+
+heapify:
+  ld h,b
+  ld l,c
+  srl b
+  rr c
+  jr heapify_start
+_:
+  push hl
+  push bc
+  call heap_propogate
+  pop bc
+  pop hl
+heapify_start:
+  ld a,b
+  or c
+  dec bc
+  jr nz,-_
+  ret

+ 137 - 0
src/subroutines/insertdelmem.z80

@@ -0,0 +1,137 @@
+;These routines were made by Zeda Thomas, feel free to use them!
+;
+;These utility routines are for resizing data within an edit buffer.
+;The routines intended for use are:
+;   delmem
+;   insertmem
+;
+;These require the following variables:
+;   (buf_end) points to the end of the data in the buffer
+;   (buf_top) points to the end of the edit buffer itself
+;
+;Both routines take a pointer in HL, and a signed number of bytes in BC.
+;For example, if you try to insert -3 bytes at HL, 3 bytes will be removed.
+;Useful for when you just want to resize but don't know if you'll be inserting
+;or removing.
+;
+;Also, though these routines are tested, there might be bugs. Since this messes
+;with potentially large portions of RAM, if something does go wrong, there will
+;be data loss. I made efforts to detect errors and exit with the carry flag set
+;if an error was detected, but just know that I'm not perfect. (yet?)
+;
+;Credit me if you want; I'm not your mom (unless I am). But realistically, you
+;will want to redirect potential bug reports to me, unless you feel like you can
+;fix it. But if you can, I'll want you to redirect the fixes to me, please!
+
+insertmem_negate:
+  xor a
+  sub c
+  ld c,a
+  sbc a,a
+  sub b
+  ld b,a
+  jr insertmem_pos
+insertmem:
+;Input:
+;   HL points to where the mem needs to be inserted
+;   BC is the number of bytes to insert, signed
+;Outputs:
+;   carry flag set if it failed
+;   carry flag is reset on success
+;   If BC was negative, bytes deleted, else inserted
+;   preserves HL
+;Destroys:
+;   A,DE
+;   BC is 0 on success, else destroyed
+  ld a,b
+  add a,a
+  jr c,delmem_negate
+insertmem_pos:
+  or c
+  ret z
+  push hl
+  ld h,b
+  ld l,c
+  ld de,(buf_end)
+  add hl,de
+  push de
+  ex de,hl
+  ld hl,(buf_top)
+  or a
+  sbc hl,de
+  jr c,insertmem_fail
+  pop hl
+  ld (buf_end),de
+  pop bc
+  push hl
+  or a
+  sbc hl,bc
+  ld b,h
+  ld c,l
+  pop hl
+  ret z
+  dec hl
+  dec de
+  lddr
+  ex de,hl
+  ret
+
+delmem_negate:
+  xor a
+  sub c
+  ld c,a
+  sbc a,a
+  sub b
+  ld b,a
+  jr delmem_pos
+delmem:
+;Input:
+;   HL points to where the mem needs to be removed
+;   BC is the number of bytes to remove, signed
+;Outputs:
+;   carry flag set if it failed
+;   carry flag is reset on success
+;   If BC was negative, bytes inserted, else deleted
+;   preserves HL
+;Destroys:
+;   A,DE
+;   BC is 0 on success, else destroyed
+  ld a,b
+  add a,a
+  jr c,delmem_negate
+delmem_pos:
+  or c
+  ret z
+
+
+;save HL to return
+  push hl
+
+;need to move (buf_end)-(HL+BC) bytes from HL+BC to HL
+  ld d,h
+  ld e,l
+  add hl,bc
+  ex de,hl
+
+;need to move (buf_end)-DE bytes from DE to HL
+  push hl
+  ld hl,(buf_end)
+  or a
+  sbc hl,de
+  jr c,delmem_fail ;don't want to delete more bytes than are left in the buffer!
+  ld b,h
+  ld c,l
+  pop hl
+  ex de,hl
+
+;need to move BC bytes from HL to DE
+  jr z,deledmem     ;don't need to move any bytes
+  ldir
+deledmem:
+  ld (buf_end),de   ;update buf_end
+
+delmem_fail:
+insertmem_fail:
+;restore HL
+  pop hl
+  ret

+ 26 - 0
src/subroutines/searchline.z80

@@ -0,0 +1,26 @@
+SearchLine:
+;Inputs:
+;     HL points to the start
+;     BC is the number of bytes to search
+;     DE is the line number
+;     A is the line byte
+;Outputs:
+;     A is not changed
+;     BC is the number of bytes left for the search
+;     DE points to the line
+;     HL is the length of the line
+;===============================================================
+  inc bc
+  dec de \ inc d \ inc e
+;  or a
+_:
+  ld (TempWord1),hl
+  cpir
+  jp po,+_
+  dec e \ jr nz,-_
+  dec d \ jr nz,-_
+_:
+  scf
+  ld de,(TempWord1)
+  sbc hl,de
+  ret

+ 32 - 0
src/subroutines/sendbyte.z80

@@ -0,0 +1,32 @@
+SendByte:
+;E is the byte to send
+;BC is the wait length
+  ld a,3
+  out (0),a
+  ld d,a
+_:
+  in a,(0)
+  and d
+  jr nz,+_
+  dec bc
+  ld a,b
+  or c
+  jr nz,-_
+  dec bc
+  ret
+_:
+  ld b,8
+SendByteLoop:
+;E is the byte to send
+;D is the mask
+  xor a
+  rlc e
+  jr c,+_    ;could use rla
+  inc a
+_:
+  out (0),a
+  djnz SendByteLoop
+  xor a
+  out (0),a
+  ld c,a
+  ret

+ 349 - 0
src/subroutines/zcomp.z80

@@ -0,0 +1,349 @@
+zcomp:
+  ld (zcomp_input_base),hl
+  ld (zcomp_input_size),bc
+  push de
+
+;initialize the frequency table
+  ld hl,zcomp_freq_table
+  ld bc,0
+_:
+  ld (hl),c
+  inc hl
+  ld (hl),c
+  inc hl
+  ld (hl),b
+  inc hl
+  inc b
+  jr nz,-_
+
+;Now count the frequencies
+  ld hl,(zcomp_input_base)
+  ld bc,(zcomp_input_size)
+zcomp_freq_loop:
+  push hl
+  push bc
+  ld b,0
+  ld c,(hl)
+  ld hl,zcomp_freq_table
+  add hl,bc
+  add hl,bc
+  add hl,bc
+  inc (hl)
+  jr nz,$+4
+  inc hl
+  inc (hl)
+  pop bc
+  pop hl
+  cpi
+  jp pe,zcomp_freq_loop
+
+;Now sort by frequency
+  ld ix,zcomp_sort
+  ld bc,256
+  call heapsort
+
+;Count the number of unique bytes
+  ld c,0
+  ld hl,zcomp_freq_table+766
+_:
+  ld a,(hl)
+  dec hl
+  or (hl)
+  jr z,+_
+  dec hl
+  dec hl
+  inc c
+  jr nz,-_
+_:
+  ld a,c
+  ld (zcomp_table_len),a
+
+;count the size of the first partition
+  ld hl,(zcomp_freq_table+765)
+  ld (zcomp_part0_size),hl
+  ex de,hl
+  ld hl,(zcomp_input_size)
+  ;or a
+  sbc hl,de
+  ld (zcomp_part1_size),hl
+
+;Set up the partitions
+  ld hl,-1
+  ld (zcomp_best_size),hl
+  ld (zcomp_best_size+1),hl
+  ld a,1
+  ld (zcomp_partition_len),a
+  ld hl,zcomp_freq_table+765
+  push hl
+partition_loop:
+  call zcomp_getsize
+  ld a,(zcomp_partition_len)
+  ld b,a
+  add a,a
+  ld (zcomp_partition_len),a
+  ld hl,(zcomp_best_size)
+  ld a,(zcomp_best_size+2)
+  ;or a
+  sbc hl,de
+  sbc a,c
+  jr c,zcomp_partition_found
+  or h
+  or l
+  jr z,zcomp_partition_found
+
+  ld a,c
+  ld (zcomp_best_size),de
+  ld (zcomp_best_size+2),a
+  ex (sp),hl
+  push bc
+_:
+  push bc
+  dec hl
+  dec hl
+  ld b,(hl)
+  dec hl
+  ld c,(hl)
+  push hl
+
+  ld hl,(zcomp_part0_size)
+  add hl,bc
+  ld (zcomp_part0_size),hl
+
+  ld hl,(zcomp_part1_size)
+  ;or a
+  sbc hl,bc
+  ld (zcomp_part1_size),hl
+
+  pop hl
+  pop bc
+  djnz -_
+  pop af
+  ex (sp),hl
+  ;check if 2a<zcomp_table_len
+  add a,a
+  jr c,zcomp_partition_found
+  ld hl,zcomp_table_len
+  sub (hl)
+  jr c,partition_loop
+
+zcomp_partition_found:
+  pop hl
+  pop hl
+
+;Now we write the key to the output
+;first is the size of the key
+  ld a,(zcomp_table_len)
+  ld b,a
+  ld (hl),a
+  inc hl
+
+;next is the size of the first partition
+  ld a,(zcomp_partition_len)
+  rrca
+  ld (hl),a
+  push hl
+  inc hl
+
+;Now we write the actual key
+  ld de,zcomp_freq_table+767
+_:
+  ld a,(de)
+  ld (hl),a
+  inc hl
+  dec de
+  dec de
+  dec de
+  djnz -_
+
+;Before we continue, let's make an LUT to map each byte to its code
+  pop hl
+  ld a,(hl)
+  inc hl
+  push af
+  ld b,a
+  ld c,0
+  dec a
+  jr z,+_
+  inc c
+  srl a
+  jr nz,$-3
+_:
+  sla c
+  ld d,zcomp_keymap>>8
+zcomp_keymap_loop_0:
+  ld e,(hl)
+  inc hl
+  ex de,hl
+  ld (hl),c
+  inc h
+  ld (hl),a
+  dec h
+  ex de,hl
+  inc a
+  djnz zcomp_keymap_loop_0
+
+  pop bc    ;B is the size of the first partition
+  ld a,(zcomp_table_len)
+  sub b
+  ld b,a
+  ld c,0
+  dec a
+  jr z,+_
+  inc c
+  srl a
+  jr nz,$-3
+_:
+  sla c
+  inc c
+zcomp_keymap_loop_1:
+  ld e,(hl)
+  inc hl
+  ex de,hl
+  ld (hl),c
+  inc h
+  ld (hl),a
+  dec h
+  ex de,hl
+  inc a
+  djnz zcomp_keymap_loop_1
+
+;Write the size of the uncompressed data
+  ld bc,(zcomp_input_size)
+  ld (hl),c
+  inc hl
+  ld (hl),b
+  inc hl
+
+;Now start compressing and writing out the data
+  ld de,(zcomp_input_base)
+  ld (hl),1
+zcomp_output_loop:
+  ld a,(de)
+  inc de
+  push de
+  push bc
+  ld d,zcomp_keymap>>8
+  ld e,a
+  ld a,(de)
+  srl a
+  rl (hl)
+  jr nc,+_
+  inc hl
+  ld (hl),1
+_:
+;A is the number of bits in the code
+  or a
+  jr z,zcomp_output_loop_end
+  inc d
+  ld b,a
+  ld a,8
+  sub b
+  ld c,a
+  ld a,(de)
+  jr z,+_
+  add a,a
+  dec c
+  jr nz,$-2
+_:
+
+  add a,a
+  rl (hl)
+  jr nc,$+5
+  inc hl
+  ld (hl),1
+  djnz -_
+
+zcomp_output_loop_end:
+  pop bc
+  pop de
+  dec bc
+  ld a,b
+  or c
+  jr nz,zcomp_output_loop
+_:
+  sla (hl)
+  jr nc,-_
+  inc hl
+  ex de,hl
+  ret
+
+zcomp_getsize:
+;zcomp_part0_size*log2(zcomp_partition_len);+zcomp_part1_size*log2(zcomp_table_len-zcomp_partition_len)
+  ld a,(zcomp_partition_len)
+  ld b,a
+  ld c,a
+  xor a
+  ld h,a
+  ld l,a
+  ld de,(zcomp_part0_size)
+_:
+  add hl,de
+  adc a,0
+  srl b
+  jr nz,-_
+
+  ld b,a
+  inc b
+  ld a,(zcomp_table_len)
+  sub c
+  ld c,a
+  ld a,b
+  ld de,(zcomp_part1_size)
+_:
+  add hl,de
+  adc a,0
+  srl c
+  jr nz,-_
+  add hl,de
+  adc a,c
+  ex de,hl
+  ld c,a
+  ret
+
+zcomp_sort:
+  rla
+  ex de,hl
+  ld hl,zcomp_freq_table
+  add hl,de
+  add hl,de
+  add hl,de
+  ;HL points to the first element
+  ex de,hl
+  ld hl,zcomp_freq_table
+  add hl,bc
+  add hl,bc
+  add hl,bc
+  rra
+  jr c,zcomp_sort_swap
+zcomp_sort_cmp:
+  ;compare the element at DE to the element at HL
+  inc hl
+  inc de
+  ld a,(de)
+  cp (hl)
+  ret nz
+  dec hl
+  dec de
+  ld a,(de)
+  cp (hl)
+  ret
+
+zcomp_sort_swap:
+;swap the 3 bytes at HL with the 3 bytes at DE
+  ld a,(de)
+  ldi
+  dec hl
+  ld (hl),a
+  inc hl
+
+  ld a,(de)
+  ldi
+  dec hl
+  ld (hl),a
+  inc hl
+
+  ld a,(de)
+  ldi
+  dec hl
+  ld (hl),a
+  ret

+ 240 - 0
src/subroutines/zlz_comp.z80

@@ -0,0 +1,240 @@
+zlz_comp:
+;Inputs:
+;   HL points to the input data
+;   DE points to the output
+;   BC is the size of the input
+;Outputs:
+;   HL points to the byte after the input
+;   DE points to the byte afterthe compressed data
+;   BC is 0
+;Destroys:
+;   AF,IX
+;
+;This routine has input and output like LDIR,
+;except if LDIR as compressing as it goes.
+;
+  ld a,ZLZ_MIN_RUN
+  inc b
+  dec b
+  jr nz,+_
+  cp c
+  jr z,$+4
+  jr c,+_
+  ld a,c
+  ld (de),a
+  inc de
+  inc c
+  dec c
+  ret z
+  ldir
+  ret
+_:
+  ld (zlz_base),hl
+  ld (zlz_runstart),hl
+  add a,l
+  ld l,a
+  jr nc,$+3
+  inc h
+
+  ld a,c
+  sub ZLZ_MIN_RUN
+  ld c,a
+  jr nc,$+3
+  dec b
+
+zlz_comp_loop:
+  push bc
+  ld (zlz_head),hl
+  call zlz_findmatch
+  inc b
+  dec b
+  jr nz,zlz_matched
+  ld a,c
+  cp ZLZ_MIN_RUN
+  jr nc,zlz_matched
+  ld hl,(zlz_head)
+  pop bc
+  cpi
+  jp pe,zlz_comp_loop
+
+zlz_write_run:
+;need to write the run from (zlz_head), size HL-(zlz_head)
+  push hl
+  push bc
+  ld hl,(zlz_head)
+  ld bc,(zlz_runstart)
+  or a
+  sbc hl,bc
+  jr z,zlz_write_run_done
+  ld b,h
+  ld c,l
+
+  ld a,l
+  add a,a \ rl h
+  add a,a \ rl h
+  jr z,+_
+  scf
+_:
+  rra
+  rra
+  ld (de),a
+  inc de
+  jr z,+_
+  ld a,h
+  ld (de),a
+  inc de
+_:
+  ld hl,(zlz_runstart)
+  ldir
+zlz_write_run_done:
+  pop bc
+  pop hl
+  ld (zlz_runstart),hl
+  ret
+
+
+zlz_matched:
+  push bc
+  call zlz_write_run
+  pop bc
+  push bc
+
+;size then pointer
+;Make sure the size doesn't exceed 13 bits
+  ld a,c
+  add a,a \ rl b
+  add a,a \ rl b
+  jr z,+_
+  scf
+_:
+  rra
+  scf
+  rra
+  ld (de),a
+  inc de
+  jr z,+_
+  ld a,b
+  ld (de),a
+  inc de
+_:
+
+;Now we need to write the pointer
+;this is an offset back from the data
+;we want (zlz_head)-HL
+  ld b,h
+  ld c,l
+  ld hl,(zlz_head)
+  ;or a   ;the rra above will reset the carry since the bottom bit of A was 0
+  sbc hl,bc
+  ld a,l
+  add a,a \ rl h
+  jr z,+_
+  scf
+_:
+  rra
+  ld (de),a
+  inc de
+  jr z,+_
+  ld a,h
+  ld (de),a
+  inc de
+_:
+
+  pop bc
+  ld hl,(zlz_head)
+  add hl,bc
+  ex (sp),hl
+  ;or a
+  sbc hl,bc
+  ld b,h
+  ld c,l
+  pop hl
+  ld (zlz_runstart),hl
+  jp nz,zlz_comp_loop
+  ret
+
+zlz_findmatch:
+  push de
+  ld (zlz_match_base),hl
+  add hl,bc
+  ld (zlz_top),hl
+  sbc hl,bc
+  ld de,(zlz_base)
+  xor a
+  ld (zlz_match_size),a
+  ld (zlz_match_size+1),a
+  sbc hl,de
+  ld bc,1-ZLZ_MIN_RUN
+  add hl,bc
+  ld b,h
+  ld c,l
+  ex de,hl
+  jr zlz_findmatch_loop_begin
+zlz_findmatch_loop:
+  push hl
+  push bc
+  call +_
+  pop bc
+  pop hl
+zlz_findmatch_loop_begin:
+;DE points to the data to find
+;HL points to the data to search
+;BC is the size of the data to search
+  ld de,(zlz_match_base)
+  ld a,(de)
+  cpir
+  jp pe,zlz_findmatch_loop
+zlz_findmatch_done:
+  ld bc,(zlz_match_size)
+  ld hl,(zlz_match_loc)
+  pop de
+  ret
+_:
+;now we compare the rest of the string
+  push hl
+  inc de
+  ld hl,(zlz_top)
+  or a
+  sbc hl,de
+  ld b,h
+  ld c,l
+  pop hl
+  jr z,zlz_match_complete
+  push hl
+_:
+  ld a,(de)
+  inc de
+  cpi
+  jp po,+_
+  jr z,-_
+_:
+  ld hl,(zlz_match_base)
+  ex de,hl
+  ;or a
+  sbc hl,de
+  ld bc,(zlz_match_size)
+  ;if HL>=BC, save the new match (if it is the same size as the previous match, then this one is closer, which can be better)
+  scf
+  sbc hl,bc
+  pop de
+  ret c
+  add hl,bc
+  ld (zlz_match_size),hl
+  dec de
+  ld (zlz_match_loc),de
+  ret
+
+
+zlz_match_complete:
+;can't get better than this, so we'll exit early
+  ld hl,(zlz_match_base)
+  ex de,hl
+  ;or a
+  sbc hl,de
+  ld b,h
+  ld c,l
+  pop af  ;return address
+  pop af  ;size left
+  pop hl  ;pointer to match
+  pop de  ;saved DE
+  ret

+ 102 - 0
src/subroutines/zlz_decomp.z80

@@ -0,0 +1,102 @@
+inloc   = tempword1
+incnt   = tempword2
+
+zlz_decomp:
+;Input:
+;   HL points to the zlz compressed data
+;   DE points to the output stream
+;   BC is the size of the data
+;Notes:
+;   While the format that this accepts uses arbitrary numbers of bits for
+;   sizes and offsets, this Z80 algorithm only works on 13-bit or 14-bit
+;   values (context dependent)
+;
+    ld a,(hl)
+    inc hl
+    add a,a
+    ld (incnt),bc
+    jr c,cpindex
+;from here, read the size in, then copy the data
+    add a,a
+    ld b,0
+    ld c,a
+    jr nc,+_
+    ld a,(hl)
+    inc hl
+    add a,a
+    ret c
+    rrca
+    ld b,a
+    call deccnt
+_:
+    srl b
+    rr c
+    srl b
+    rr c
+    push hl
+    ld hl,(incnt)
+    sbc hl,bc
+    ld (incnt),hl
+    pop hl
+    ldir
+    dec hl
+    ld bc,(incnt)
+    cpi
+    jp pe,zlz_decomp
+    ret
+cpindex:
+    add a,a
+    ld b,0
+    ld c,a
+    jr nc,+_
+    ld a,(hl)
+    inc hl
+    add a,a
+    ret c
+    rrca
+    ld b,a
+    call deccnt
+_:
+    srl b
+    rr c
+    srl b
+    rr c
+    ;BC is the new size
+    ;Now we need to grab the index
+    push bc
+    ld a,(hl)
+    add a,a
+    ld b,0
+    ld c,a
+    jr nc,+_
+    inc hl
+    ld a,(hl)
+    add a,a
+    jp c,pop_exit
+    rrca
+    ld b,a
+    call deccnt
+_:
+    srl b
+    rr c
+    ld (inloc),hl
+    ld h,d
+    ld l,e
+    or a
+    sbc hl,bc
+    pop bc
+    ldir
+    ld hl,(inloc)
+    ld bc,(incnt)
+    dec bc
+    cpi
+    jp pe,zlz_decomp
+    ret
+deccnt:
+    push hl
+    ld hl,(incnt)
+    dec hl
+    ld (incnt),hl
+pop_exit:
+    pop hl
+    ret

+ 91 - 0
src/tokenhook.z80

@@ -0,0 +1,91 @@
+TokenHook:
+  .db $83
+  inc b
+  dec b
+  ret nz
+  push hl
+  ld hl,(iMathPtr1)
+  inc hl
+  inc hl
+  ld a,3Ah
+  cp (hl)
+  jr nz,tokenhook_pop1exit
+  inc hl
+  ld a,30h
+  cp (hl)
+  jr nz,tokenhook_pop1exit
+  inc hl
+  ld a,3Eh
+  cp (hl)
+  jr nz,tokenhook_pop1exit
+  ld b,0
+  dec d
+  inc d
+  ld hl,TokenTable_0
+  jr z,TokenSearchLoop
+  ld hl,TokenTable_1
+TokenSearchLoop:
+  ld a,e
+  cp (hl)
+  inc hl
+  jr z,ChkByte2
+NotTokenMatch:
+  inc hl
+  ld c,(hl)
+  inc c
+  add hl,bc
+  ld a,(hl)
+  or a
+  jr nz,TokenSearchLoop
+tokenhook_pop1exit:
+  pop hl
+  ret
+ChkByte2:
+  ld a,d
+  cp (hl)
+  jr nz,NotTokenMatch
+  pop de
+  ld de,OP1
+  inc hl
+  ld c,(hl)
+  inc c
+  ldir
+  ld hl,OP1-1
+  ret
+NoChange:
+TokenTable:
+TokenTable_0:
+; .db $02,0,7,"module."
+ .db $02,0,1,$F2    ;$
+ .db $04,0,6,$05,"Float"
+ .db $06,0,8,5,"lFactor"
+ .db $28,0,7,"Insert("
+ .db $36,0,7,"ClrPart"
+ .db $38,0,7,"RunPart"
+ .db $3A,0,8,"AddPart("
+ .db $3C,0,9,"PartType("
+ .db $44,0,5,"Misc("
+ .db $58,0,1,5Fh
+ .db $BE,0,5,"call "
+ .db 0
+
+TokenTable_1:
+ .db $38,1,5,"Rect("
+ .db $3C,1,5,"Tile("
+ .db $3E,1,7,"Sprite("
+ .db $40,1,8,"TileMap("
+ .db $48,1,9,"Contrast("
+ .db $4E,1,9,"ShiftBuf("
+ .db $62,1,7,"WriteB("
+ .db $70,1,4,"Inv("
+ .db $72,1,7,"WriteW("
+; .db $7E,1,2,"2^"
+ .db $A6,1,4,"For "
+ .db $B4,1,7,"GetInc("
+ .db $B6,1,7,"GetDec("
+ .db $BC,1,7,"SetBuf("
+ .db $C0,1,8,"SetFont("
+ .db $CE,1,8,"MakeVar("
+ .db $D0,1,8,"FindVar("
+ .db $72,4,4,"gbuf"
+ .db 0

+ 1 - 0
z80float

@@ -0,0 +1 @@
+Subproject commit 8c4f87367cbf3d3be4c6982976b360663da8bd8d