diff --git a/apps/zasm/README.md b/apps/zasm/README.md index ac678db..3a3cb08 100644 --- a/apps/zasm/README.md +++ b/apps/zasm/README.md @@ -1,8 +1,7 @@ # z80 assembler -This is probably the most critical part of the Collapse OS project. If this app -can be brought to completion, it pretty much makes the project a success because -it ensures self-reproduction. +This is probably the most critical part of the Collapse OS project because it +ensures its self-reproduction. ## Running on a "modern" machine @@ -92,6 +91,12 @@ The `$` is a special symbol that can be placed in any expression and evaluated as the current output offset. That is, it's the value that a label would have if it was placed there. +## The Last Value + +Whenever a `.equ` directive is evaluated, its resulting value is saved in a +special "last value" register that can then be used in any expression. This +is very useful for variable definitions and for jump tables. + ## Includes The `#inc` directive is special. It takes a string literal as an argument and diff --git a/apps/zasm/directive.asm b/apps/zasm/directive.asm index 4bf8afc..4150990 100644 --- a/apps/zasm/directive.asm +++ b/apps/zasm/directive.asm @@ -11,7 +11,9 @@ .equ D_BAD 0xff ; *** Variables *** -.equ DIREC_SCRATCHPAD DIREC_RAMSTART +; Result of the last .equ evaluation. Used for "@" symbol. +.equ DIREC_LASTVAL DIREC_RAMSTART +.equ DIREC_SCRATCHPAD DIREC_LASTVAL+2 .equ DIREC_RAMEND DIREC_SCRATCHPAD+SCRATCHPAD_SIZE ; *** CODE *** @@ -148,6 +150,8 @@ handleEQU: jr nz, .badarg ld hl, DIREC_SCRATCHPAD push ix \ pop de + ; Save value in "@" special variable + ld (DIREC_LASTVAL), de call symRegisterConst ; A and Z set jr z, .end ; success ; register ended up in error. We need to figure which error. If it's diff --git a/apps/zasm/glue.asm b/apps/zasm/glue.asm index 45bbdb5..0171de3 100644 --- a/apps/zasm/glue.asm +++ b/apps/zasm/glue.asm @@ -76,12 +76,12 @@ jp zasmMain .equ TOK_RAMSTART IO_RAMEND #include "zasm/tok.asm" #include "lib/parse.asm" -#include "zasm/parse.asm" -#include "zasm/expr.asm" .equ INS_RAMSTART TOK_RAMEND #include "zasm/instr.asm" .equ DIREC_RAMSTART INS_RAMEND #include "zasm/directive.asm" +#include "zasm/parse.asm" +#include "zasm/expr.asm" .equ SYM_RAMSTART DIREC_RAMEND #include "zasm/symbol.asm" .equ ZASM_RAMSTART SYM_RAMEND diff --git a/apps/zasm/parse.asm b/apps/zasm/parse.asm index 41769c2..b133886 100644 --- a/apps/zasm/parse.asm +++ b/apps/zasm/parse.asm @@ -168,13 +168,19 @@ parseLiteral: parseNumberOrSymbol: call parseLiteral ret z - ; Not a number. Try PC - push de ; --> lvl 1 - ld de, .sDollar - call strcmp - pop de ; <-- lvl 1 + ; Not a number. + ; Is str a single char? If yes, maybe it's a special symbol. + call strIs1L + jr nz, .symbol ; nope + ld a, (hl) + cp '$' jr z, .returnPC - ; Not PC either, try symbol + cp '@' + jr nz, .symbol + ; last val + ld ix, (DIREC_LASTVAL) + ret +.symbol: push de ; --> lvl 1 call symFindVal ; --> DE jr nz, .notfound @@ -197,5 +203,3 @@ parseNumberOrSymbol: push hl \ pop ix pop hl ret -.sDollar: - .db '$', 0 diff --git a/apps/zasm/util.asm b/apps/zasm/util.asm index 7cabb84..1c3bc44 100644 --- a/apps/zasm/util.asm +++ b/apps/zasm/util.asm @@ -52,6 +52,16 @@ strlen: pop bc ret +; Sets Z if string at (HL) is one character long +strIs1L: + xor a + cp (hl) + jp z, unsetZ ; empty string + inc hl + cp (hl) ; Z has proper value + dec hl ; doesn't touch Z + ret + ; Compares strings pointed to by HL and DE up to A count of characters in a ; case-insensitive manner. ; If equal, Z is set. If not equal, Z is reset. diff --git a/tools/emul/Makefile b/tools/emul/Makefile index c59d361..69511f3 100644 --- a/tools/emul/Makefile +++ b/tools/emul/Makefile @@ -43,15 +43,6 @@ updatebootstrap: $(ZASMBIN) $(INCCFS) $(ZASMSH) $(KERNEL) < zasm/glue.asm > zasm/kernel.bin $(ZASMSH) $(KERNEL) $(APPS) zasm/user.h < $(APPS)/zasm/glue.asm > zasm/zasm.bin -# Sometimes, when developing zasm, stuff get messed up and it's hard to unmess -# because zasm's brake-up ends up in its bootstrap bins. Sure, we can revert -# from git, but if we're in the middle of some work, it's inconvenient. As long -# as we don't diverge from scas's syntax, it can come to the recue! -.PHONY: rescue -rescue: - scas -o zasm/kernel.bin -I $(KERNEL) zasm/glue.asm - scas -o zasm/zasm.bin -I $(APPS) -I $(KERNEL) -I zasm $(APPS)/zasm/glue.asm - .PHONY: clean clean: rm -f $(TARGETS) $(SHELLAPPS) {zasm,shell}/*-bin.h diff --git a/tools/emul/zasm/zasm.bin b/tools/emul/zasm/zasm.bin index 1dfc0c9..e6cae9d 100644 Binary files a/tools/emul/zasm/zasm.bin and b/tools/emul/zasm/zasm.bin differ diff --git a/tools/tests/unit/test_expr.asm b/tools/tests/unit/test_expr.asm index fe37b14..c7e5971 100644 --- a/tools/tests/unit/test_expr.asm +++ b/tools/tests/unit/test_expr.asm @@ -4,6 +4,9 @@ .equ ZASM_REG_BUFSZ 0x1000 .equ ZASM_LREG_BUFSZ 0x200 +; declare DIREC_LASTVAL manually so that we don't have to include directive.asm +.equ DIREC_LASTVAL RAMSTART + jp test #include "core.asm" @@ -13,7 +16,7 @@ jp test #include "zasm/const.asm" #include "lib/parse.asm" #include "zasm/parse.asm" -.equ SYM_RAMSTART RAMSTART +.equ SYM_RAMSTART DIREC_LASTVAL+2 #include "zasm/symbol.asm" #include "zasm/expr.asm" diff --git a/tools/tests/unit/test_parse_z.asm b/tools/tests/unit/test_parse_z.asm index f6a8023..a4b2232 100644 --- a/tools/tests/unit/test_parse_z.asm +++ b/tools/tests/unit/test_parse_z.asm @@ -1,3 +1,7 @@ +.equ RAMSTART 0x4000 +; declare DIREC_LASTVAL manually so that we don't have to include directive.asm +.equ DIREC_LASTVAL RAMSTART + jp test #include "core.asm" @@ -80,6 +84,13 @@ test: jp nz, fail call nexttest +.equ FOO 0x42 +.equ BAR @+1 + ld a, BAR + cp 0x43 + jp nz, fail + call nexttest + ; success xor a halt