From acddb045a5d4f73590c06090b203d15183a329e9 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Sun, 19 May 2019 13:22:14 -0400 Subject: [PATCH] zasm: add support for .org directive --- apps/zasm/directive.asm | 24 ++++++++++++------------ apps/zasm/instr.asm | 7 +++++-- apps/zasm/main.asm | 25 +++++++++++++++++++++++-- apps/zasm/parse.asm | 11 +++++++---- apps/zasm/symbol.asm | 15 ++++++++++++++- tools/tests/zasm/test8.asm | 6 ++++++ 6 files changed, 67 insertions(+), 21 deletions(-) create mode 100644 tools/tests/zasm/test8.asm diff --git a/apps/zasm/directive.asm b/apps/zasm/directive.asm index fee826e..e4b65ba 100644 --- a/apps/zasm/directive.asm +++ b/apps/zasm/directive.asm @@ -3,7 +3,8 @@ .equ D_DB 0x00 .equ D_DW 0x01 .equ D_EQU 0x02 -.equ D_INC 0x03 +.equ D_ORG 0x03 +.equ D_INC 0x04 .equ D_BAD 0xff ; *** Variables *** @@ -16,6 +17,7 @@ directiveNames: .db ".DB", 0 .db ".DW", 0 .db ".EQU" + .db ".ORG" .db "#inc" ; This is a list of handlers corresponding to indexes in directiveNames @@ -23,6 +25,7 @@ directiveHandlers: .dw handleDB .dw handleDW .dw handleEQU + .dw handleORG .dw handleINC handleDB: @@ -67,14 +70,6 @@ handleDW: ret handleEQU: - call zasmIsFirstPass - jr nz, .begin - ; first pass? .equ are noops Consume args and return - call readWord - call readWord - xor a - ret -.begin: push hl push de push bc @@ -90,12 +85,10 @@ handleEQU: call readWord ld hl, scratchpad call parseExpr - jr nz, .error + jr nz, .end ld hl, DIREC_SCRATCHPAD push ix \ pop de call symRegister - jr .end -.error: .end: xor a ; 0 bytes written pop bc @@ -103,6 +96,13 @@ handleEQU: pop hl ret +handleORG: + call readWord + call parseExpr + ret nz + push ix \ pop hl + jp zasmSetOrg + handleINC: call readWord jr nz, .end diff --git a/apps/zasm/instr.asm b/apps/zasm/instr.asm index e92540e..b7a94e2 100644 --- a/apps/zasm/instr.asm +++ b/apps/zasm/instr.asm @@ -675,7 +675,7 @@ getUpcode: bit 7, (ix+3) jr z, .absoluteValue ; bit not set? regular byte value, ; Our argument is a relative address ("e" type in djnz and jr). We have - ; to subtract (IO_PC) from it. + ; to subtract PC from it. ; First, check whether we're on first pass. If we are, skip processing ; below because not having real symbol value makes relative address @@ -686,7 +686,10 @@ getUpcode: ; We're on second pass push de ; Don't let go of this, that's our dest - ld de, (IO_PC) + push hl + call zasmGetPC ; --> HL + ex de, hl + pop hl call intoHL dec hl ; what we write is "e-2" dec hl diff --git a/apps/zasm/main.asm b/apps/zasm/main.asm index b3e36d5..177a789 100644 --- a/apps/zasm/main.asm +++ b/apps/zasm/main.asm @@ -11,7 +11,9 @@ .equ ZASM_LOCAL_PASS ZASM_FIRST_PASS+1 ; What IO_PC was when we started our context .equ ZASM_CTX_PC ZASM_LOCAL_PASS+1 -.equ ZASM_RAMEND ZASM_CTX_PC+2 +; current ".org" offset, that is, what we must offset all our label by. +.equ ZASM_ORG ZASM_CTX_PC+2 +.equ ZASM_RAMEND ZASM_ORG+2 ; Read file through blockdev ID in H and outputs its upcodes through blockdev ; ID in L. @@ -27,6 +29,8 @@ zasmMain: ; Init modules xor a ld (ZASM_LOCAL_PASS), a + ld (ZASM_ORG), a + ld (ZASM_ORG+1), a call ioInit call symInit @@ -54,6 +58,20 @@ zasmIsLocalPass: cp 1 ret +; Set ZASM_ORG to specified number in HL +zasmSetOrg: + ld (ZASM_ORG), hl + ret + +; Return current PC (properly .org offsetted) in HL +zasmGetPC: + push de + ld hl, (ZASM_ORG) + ld de, (IO_PC) + add hl, de + pop de + ret + ; Repeatedly reads lines from IO, assemble them and spit the binary code in ; IO. Z is set on success, unset on error. DE contains the last line number to ; be read (first line is 1). @@ -135,7 +153,10 @@ _parseLabel: call _endLocalPass jr .success .registerLabel: - ld de, (IO_PC) + push hl + call zasmGetPC + ex de, hl + pop hl call symRegister jr nz, .error ; continue to .success diff --git a/apps/zasm/parse.asm b/apps/zasm/parse.asm index 5b0c3cb..f3bf07d 100644 --- a/apps/zasm/parse.asm +++ b/apps/zasm/parse.asm @@ -226,13 +226,10 @@ parseLiteral: parseNumberOrSymbol: call parseLiteral ret z - call zasmIsFirstPass - ret z ; first pass? we don't care about the value, - ; return success. ; Not a number. Try symbol call symSelect call symFind - ret nz ; not found + jr nz, .notfound ; Found! let's fetch value push de call symGetVal @@ -241,3 +238,9 @@ parseNumberOrSymbol: pop de cp a ; ensure Z ret +.notfound: + ; If not found, check if we're in first pass. If we are, it doesn't + ; matter that we didn't find our symbol. Return success anyhow. + ; Otherwise return error. Z is already unset, so in fact, this is the + ; same as jumping to zasmIsFirstPass + jp zasmIsFirstPass diff --git a/apps/zasm/symbol.asm b/apps/zasm/symbol.asm index 6aa4136..2b09336 100644 --- a/apps/zasm/symbol.asm +++ b/apps/zasm/symbol.asm @@ -155,9 +155,13 @@ symNamesEnd: ; If successful, Z is set and A is the symbol index. Otherwise, Z is unset and ; A is an error code (SYM_ERR_*). symRegister: + call symFind + jr z, .alreadyThere + push hl ; will be used during processing. it's the symbol to add push de ; will be used during processing. it's our value. + ; First, let's get our strlen call strlen ld c, a ; save that strlen for later @@ -201,11 +205,20 @@ symRegister: ret .error: - ; Z already unset + call unsetZ pop de pop hl ret +.alreadyThere: + push hl + ld hl, (SYM_CTX_PTR) + ex de, hl + call writeHLinDE + pop hl + cp a ; ensure Z + ret + ; Select global or local registry according to label name in (HL) symSelect: call symIsLabelLocal diff --git a/tools/tests/zasm/test8.asm b/tools/tests/zasm/test8.asm new file mode 100644 index 0000000..9962b8e --- /dev/null +++ b/tools/tests/zasm/test8.asm @@ -0,0 +1,6 @@ +; test .org directive +.equ foo 1234 +.org foo +label1: + jp label1 + jr label1