collapseos/apps/zasm/directive.asm

337 lines
5.6 KiB
NASM
Raw Normal View History

2019-05-01 11:40:22 +10:00
; *** CONSTS ***
.equ D_DB 0x00
.equ D_DW 0x01
2019-05-12 12:11:05 +10:00
.equ D_EQU 0x02
2019-05-20 03:22:14 +10:00
.equ D_ORG 0x03
2019-05-20 22:20:00 +10:00
.equ D_FIL 0x04
2019-06-04 01:13:31 +10:00
.equ D_OUT 0x05
.equ D_INC 0x06
.equ D_BIN 0x07
.equ D_BAD 0xff
2019-05-01 11:40:22 +10:00
2019-05-12 12:11:05 +10:00
; *** Variables ***
2019-10-05 10:26:21 +10:00
; Result of the last .equ evaluation. Used for "@" symbol.
.equ DIREC_LASTVAL DIREC_RAMSTART
.equ DIREC_SCRATCHPAD DIREC_LASTVAL+2
2019-05-12 12:11:05 +10:00
.equ DIREC_RAMEND DIREC_SCRATCHPAD+SCRATCHPAD_SIZE
2019-05-01 11:40:22 +10:00
; *** CODE ***
; 3 bytes per row, fill with zero
2019-11-16 00:59:26 +11:00
dirNames:
.db "DB", 0
.db "DW", 0
.db "EQU"
.db "ORG"
.db "FIL"
.db "OUT"
.db "INC"
.db "BIN"
2019-05-01 11:40:22 +10:00
2019-11-16 00:59:26 +11:00
; This is a list of handlers corresponding to indexes in dirNames
dirHandlers:
2019-05-02 01:26:41 +10:00
.dw handleDB
.dw handleDW
2019-05-12 12:11:05 +10:00
.dw handleEQU
2019-05-20 03:22:14 +10:00
.dw handleORG
2019-05-20 22:20:00 +10:00
.dw handleFIL
2019-06-04 01:13:31 +10:00
.dw handleOUT
2019-05-17 11:15:00 +10:00
.dw handleINC
.dw handleBIN
2019-05-02 01:26:41 +10:00
handleDB:
2019-12-24 09:16:46 +11:00
push de
2019-05-02 01:26:41 +10:00
push hl
.loop:
2019-05-02 01:26:41 +10:00
call readWord
jr nz, .badfmt
2019-05-02 01:26:41 +10:00
ld hl, scratchpad
call enterDoubleQuotes
jr z, .stringLiteral
2019-12-24 11:13:44 +11:00
call parseExpr
jr nz, .badarg
2019-12-24 09:16:46 +11:00
ld a, d
or a ; cp 0
jr nz, .overflow ; not zero? overflow
2019-12-24 09:16:46 +11:00
ld a, e
call ioPutB
jr nz, .ioError
.stopStrLit:
call readComma
jr z, .loop
cp a ; ensure Z
2019-12-24 09:16:46 +11:00
.end:
pop hl
2019-12-24 09:16:46 +11:00
pop de
ret
.ioError:
ld a, SHELL_ERR_IO_ERROR
jr .error
.badfmt:
ld a, ERR_BAD_FMT
jr .error
.badarg:
ld a, ERR_BAD_ARG
jr .error
.overflow:
ld a, ERR_OVFL
.error:
2019-12-24 09:16:46 +11:00
or a ; unset Z
jr .end
.stringLiteral:
ld a, (hl)
inc hl
or a ; when we encounter 0, that was what used to
jr z, .stopStrLit ; be our closing quote. Stop.
; Normal character, output
call ioPutB
jr nz, .ioError
jr .stringLiteral
2019-05-02 01:26:41 +10:00
handleDW:
2019-12-24 09:16:46 +11:00
push de
push hl
.loop:
call readWord
jr nz, .badfmt
ld hl, scratchpad
2019-12-24 11:13:44 +11:00
call parseExpr
jr nz, .badarg
2019-12-24 09:16:46 +11:00
ld a, e
call ioPutB
jr nz, .ioError
2019-12-24 09:16:46 +11:00
ld a, d
call ioPutB
jr nz, .ioError
call readComma
jr z, .loop
cp a ; ensure Z
2019-12-24 09:16:46 +11:00
.end:
pop hl
2019-12-24 09:16:46 +11:00
pop de
ret
.ioError:
ld a, SHELL_ERR_IO_ERROR
jr .error
.badfmt:
ld a, ERR_BAD_FMT
jr .error
.badarg:
ld a, ERR_BAD_ARG
.error:
2019-12-24 09:16:46 +11:00
or a ; unset Z
jr .end
2019-05-02 01:26:41 +10:00
2019-05-12 12:11:05 +10:00
handleEQU:
call zasmIsLocalPass ; Are we in local pass? Then ignore all .equ.
jr z, .skip ; they mess up duplicate symbol detection.
; We register constants on both first and second pass for one little
; reason: .org. Normally, we'd register constants on second pass only
; so that we have values for forward label references, but we need .org
; to be effective during the first pass and .org needs to support
; expressions. So, we double-parse .equ, clearing the const registry
; before the second pass.
2019-05-12 12:11:05 +10:00
push hl
push de
push bc
; Read our constant name
call readWord
jr nz, .badfmt
2019-05-12 12:11:05 +10:00
; We can't register our symbol yet: we don't have our value!
; Let's copy it over.
ld de, DIREC_SCRATCHPAD
ld bc, SCRATCHPAD_SIZE
ldir
2019-05-12 12:11:05 +10:00
; Now, read the value associated to it
call readWord
jr nz, .badfmt
2019-05-12 12:11:05 +10:00
ld hl, scratchpad
2019-12-24 11:13:44 +11:00
call parseExpr
jr nz, .badarg
2019-05-12 12:11:05 +10:00
ld hl, DIREC_SCRATCHPAD
2019-10-05 10:26:21 +10:00
; 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
; a duplicate error, we ignore it and return success because, as per
; ".equ" policy, it's fine to define the same const twice. The first
; value has precedence.
cp ERR_DUPSYM
; whatever the value of Z, it's the good one, return
jr .end
.badfmt:
ld a, ERR_BAD_FMT
jr .error
.badarg:
ld a, ERR_BAD_ARG
.error:
call unsetZ
2019-05-12 12:11:05 +10:00
.end:
pop bc
pop de
pop hl
ret
.skip:
; consume args and return
call readWord
jp readWord
2019-05-12 12:11:05 +10:00
2019-05-20 03:22:14 +10:00
handleORG:
2019-12-24 09:16:46 +11:00
push de
2019-05-20 03:22:14 +10:00
call readWord
jr nz, .badfmt
2019-12-24 11:13:44 +11:00
call parseExpr
jr nz, .badarg
2019-12-24 09:16:46 +11:00
ex de, hl
2019-11-16 00:59:26 +11:00
ld (DIREC_LASTVAL), hl
call zasmSetOrg
cp a ; ensure Z
2019-12-24 09:16:46 +11:00
.end:
pop de
ret
.badfmt:
ld a, ERR_BAD_FMT
jr .error
.badarg:
ld a, ERR_BAD_ARG
.error:
2019-12-24 09:16:46 +11:00
or a ; unset Z
jr .end
2019-05-20 03:22:14 +10:00
2019-05-20 22:20:00 +10:00
handleFIL:
call readWord
jr nz, .badfmt
2019-12-24 11:13:44 +11:00
call parseExpr
jr nz, .badarg
2019-12-24 09:16:46 +11:00
ld a, d
cp 0xd0
jr nc, .overflow
2019-05-20 22:20:00 +10:00
.loop:
2019-12-24 09:16:46 +11:00
ld a, d
or e
jr z, .loopend
xor a
call ioPutB
jr nz, .ioError
2019-12-24 09:16:46 +11:00
dec de
jr .loop
.loopend:
cp a ; ensure Z
ret
.ioError:
ld a, SHELL_ERR_IO_ERROR
jp unsetZ
.badfmt:
ld a, ERR_BAD_FMT
jp unsetZ
.badarg:
ld a, ERR_BAD_ARG
jp unsetZ
.overflow:
ld a, ERR_OVFL
jp unsetZ
2019-05-20 22:20:00 +10:00
2019-06-04 01:13:31 +10:00
handleOUT:
2019-12-24 09:16:46 +11:00
push de
2019-06-04 01:13:31 +10:00
push hl
; Read our expression
call readWord
jr nz, .badfmt
call zasmIsFirstPass ; No .out during first pass
jr z, .end
ld hl, scratchpad
2019-12-24 11:13:44 +11:00
call parseExpr
2019-06-04 01:13:31 +10:00
jr nz, .badarg
2019-12-24 09:16:46 +11:00
ld a, d
2019-06-04 01:13:31 +10:00
out (ZASM_DEBUG_PORT), a
2019-12-24 09:16:46 +11:00
ld a, e
2019-06-04 01:13:31 +10:00
out (ZASM_DEBUG_PORT), a
jr .end
.badfmt:
ld a, ERR_BAD_FMT
jr .error
.badarg:
ld a, ERR_BAD_ARG
.error:
2019-12-24 09:16:46 +11:00
or a ; unset Z
2019-06-04 01:13:31 +10:00
.end:
pop hl
2019-12-24 09:16:46 +11:00
pop de
2019-06-04 01:13:31 +10:00
ret
2019-05-17 11:15:00 +10:00
handleINC:
call readWord
jr nz, .badfmt
2019-05-17 11:15:00 +10:00
; HL points to scratchpad
call enterDoubleQuotes
jr nz, .badfmt
2019-05-17 11:15:00 +10:00
call ioOpenInclude
jr nz, .badfn
cp a ; ensure Z
ret
.badfmt:
ld a, ERR_BAD_FMT
jr .error
.badfn:
ld a, ERR_FILENOTFOUND
.error:
call unsetZ
2019-05-17 11:15:00 +10:00
ret
handleBIN:
call readWord
jr nz, .badfmt
; HL points to scratchpad
call enterDoubleQuotes
jr nz, .badfmt
call ioSpitBin
jr nz, .badfn
cp a ; ensure Z
ret
.badfmt:
ld a, ERR_BAD_FMT
jr .error
.badfn:
ld a, ERR_FILENOTFOUND
.error:
call unsetZ
ret
2019-05-01 11:40:22 +10:00
; Reads string in (HL) and returns the corresponding ID (D_*) in A. Sets Z if
; there's a match.
getDirectiveID:
ld a, (hl)
cp '.'
ret nz
push hl
2019-05-01 11:40:22 +10:00
push bc
push de
inc hl
ld b, D_BIN+1 ; D_BIN is last
ld c, 3
2019-11-16 00:59:26 +11:00
ld de, dirNames
2019-05-01 11:40:22 +10:00
call findStringInList
pop de
pop bc
pop hl
2019-05-01 11:40:22 +10:00
ret
; Parse directive specified in A (D_* const) with args in I/O and act in
2019-05-02 01:26:41 +10:00
; an appropriate manner. If the directive results in writing data at its
; current location, that data is directly written through ioPutB.
; Each directive has the same return value pattern: Z on success, not-Z on
; error, A contains the error number (ERR_*).
2019-05-01 11:40:22 +10:00
parseDirective:
2019-05-02 01:26:41 +10:00
push de
2019-11-16 00:59:26 +11:00
; double A to have a proper offset in dirHandlers
2019-05-02 01:26:41 +10:00
add a, a
2019-11-16 00:59:26 +11:00
ld de, dirHandlers
call addDE
call intoDE
push de \ pop ix
2019-05-02 01:26:41 +10:00
pop de
jp (ix)