mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-23 16:08:06 +11:00
zasm: assemble multiple lines at once
This commit is contained in:
parent
2653826dff
commit
57c3dfece8
@ -8,5 +8,5 @@ libz80/libz80.o: libz80/z80.c
|
||||
kernel.h: glue.asm
|
||||
scas -o - -I ../../../parts/z80 $< | ./bin2c.sh KERNEL | tee $@ > /dev/null
|
||||
|
||||
zasm.h: ../main.asm ../instr.asm ../tok.asm
|
||||
zasm.h: $(addprefix ../, main.asm instr.asm tok.asm util.asm)
|
||||
scas -o - -I.. $< | ./bin2c.sh ZASM | tee $@ > /dev/null
|
||||
|
@ -6,73 +6,6 @@ INSTR_TBL_CNT .equ 135
|
||||
; size in bytes of each row in the primary instructions table
|
||||
INSTR_TBL_ROWSIZE .equ 9
|
||||
|
||||
; run RLA the number of times specified in B
|
||||
rlaX:
|
||||
; first, see if B == 0 to see if we need to bail out
|
||||
inc b
|
||||
dec b
|
||||
ret z ; Z flag means we had B = 0
|
||||
.loop: rla
|
||||
djnz .loop
|
||||
ret
|
||||
|
||||
; Copy BC bytes from (HL) to (DE).
|
||||
copy:
|
||||
; first, let's see if BC is zero. if it is, we have nothing to do.
|
||||
; remember: 16-bit inc/dec don't modify flags. that's why we check B
|
||||
; and C separately.
|
||||
inc b
|
||||
dec b
|
||||
jr nz, .proceed
|
||||
inc c
|
||||
dec c
|
||||
ret z ; zero? nothing to do
|
||||
.proceed:
|
||||
push bc
|
||||
push de
|
||||
push hl
|
||||
ldir
|
||||
pop hl
|
||||
pop de
|
||||
pop bc
|
||||
ret
|
||||
|
||||
callHL:
|
||||
jp (hl)
|
||||
ret
|
||||
|
||||
; If string at (HL) starts with ( and ends with ), "enter" into the parens
|
||||
; (advance HL and put a null char at the end of the string) and set Z.
|
||||
; Otherwise, do nothing and reset Z.
|
||||
enterParens:
|
||||
ld a, (hl)
|
||||
cp '('
|
||||
ret nz ; nothing to do
|
||||
push hl
|
||||
ld a, 0 ; look for null char
|
||||
; advance until we get null
|
||||
.loop:
|
||||
cpi
|
||||
jp z, .found
|
||||
jr .loop
|
||||
.found:
|
||||
dec hl ; cpi over-advances. go back to null-char
|
||||
dec hl ; looking at the last char before null
|
||||
ld a, (hl)
|
||||
cp ')'
|
||||
jr nz, .doNotEnter
|
||||
; We have parens. While we're here, let's put a null
|
||||
xor a
|
||||
ld (hl), a
|
||||
pop hl ; back at the beginning. Let's advance.
|
||||
inc hl
|
||||
cp a ; ensure Z
|
||||
ret ; we're good!
|
||||
.doNotEnter:
|
||||
pop hl
|
||||
call JUMP_UNSETZ
|
||||
ret
|
||||
|
||||
; Checks whether A is 'N' or 'M'
|
||||
checkNOrM:
|
||||
cp 'N'
|
||||
@ -772,13 +705,11 @@ processArg:
|
||||
call JUMP_UNSETZ
|
||||
ret
|
||||
|
||||
; Parse line at (HL) and write resulting opcode(s) in curUpcode. Returns the
|
||||
; number of bytes written in A.
|
||||
parseLine:
|
||||
; Parse tokens in (tokInstr), (tokArg1) and (tokArg2) and write resulting
|
||||
; opcode(s) in (curUpcode). Returns the number of bytes written in A.
|
||||
parseTokens:
|
||||
push hl
|
||||
push de
|
||||
call tokenize
|
||||
jr nz, .error
|
||||
ld a, (tokInstr)
|
||||
cp 0
|
||||
jr z, .error ; for now, we treat blank lines as errors
|
||||
|
48
apps/zasm/main.asm
Normal file
48
apps/zasm/main.asm
Normal file
@ -0,0 +1,48 @@
|
||||
#include "user.inc"
|
||||
|
||||
; *** Code ***
|
||||
.org USER_CODE
|
||||
|
||||
; Parse asm file in (HL) and outputs its upcodes in (DE). Returns the number
|
||||
; of bytes written in C.
|
||||
main:
|
||||
ld bc, 0 ; C is our written bytes counter
|
||||
.loop:
|
||||
call parseLine
|
||||
or a ; is zero? stop
|
||||
jr z, .stop
|
||||
add a, c
|
||||
ld c, a
|
||||
call gotoNextLine
|
||||
jr nz, .stop ; error? stop
|
||||
jr .loop
|
||||
.stop:
|
||||
ret
|
||||
|
||||
; Parse line in (HL), write the resulting opcode(s) in (DE) and returns the
|
||||
; number of written bytes in A. Advances HL where tokenization stopped and DE
|
||||
; to where we should write the next upcode.
|
||||
parseLine:
|
||||
push bc
|
||||
call tokenize
|
||||
jr nz, .error
|
||||
call parseTokens
|
||||
or a ; is zero?
|
||||
jr z, .error
|
||||
ld b, 0
|
||||
ld c, a ; written bytes
|
||||
push hl
|
||||
ld hl, curUpcode
|
||||
call copy
|
||||
pop hl
|
||||
call JUMP_ADDDE
|
||||
jr .end
|
||||
.error:
|
||||
xor a
|
||||
.end:
|
||||
pop bc
|
||||
ret
|
||||
|
||||
#include "util.asm"
|
||||
#include "tok.asm"
|
||||
#include "instr.asm"
|
@ -5,13 +5,11 @@ set -e
|
||||
TMPFILE=$(mktemp)
|
||||
SCAS=scas
|
||||
ZASM=../emul/zasm
|
||||
ASMFILE=../zasm.asm
|
||||
ASMFILE=../instr.asm
|
||||
|
||||
./geninstrs.py $ASMFILE | \
|
||||
while read line; do
|
||||
echo $line | tee "${TMPFILE}"
|
||||
EXPECTED=$($SCAS -o - "${TMPFILE}" | xxd)
|
||||
ACTUAL=$(echo $line | $ZASM | xxd)
|
||||
cmpas() {
|
||||
EXPECTED=$($SCAS -o - "$1" | xxd)
|
||||
ACTUAL=$(cat $1 | $ZASM | xxd)
|
||||
if [ "$ACTUAL" == "$EXPECTED" ]; then
|
||||
echo ok
|
||||
else
|
||||
@ -21,4 +19,15 @@ while read line; do
|
||||
echo $EXPECTED
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
./geninstrs.py $ASMFILE | \
|
||||
while read line; do
|
||||
echo $line | tee "${TMPFILE}"
|
||||
cmpas ${TMPFILE}
|
||||
done
|
||||
|
||||
for fn in *.asm; do
|
||||
echo "Comparing ${fn}"
|
||||
cmpas $fn
|
||||
done
|
||||
|
@ -30,25 +30,31 @@ tokenize:
|
||||
ld de, tokArg2
|
||||
call readWord
|
||||
.end:
|
||||
cp a ; ensure Z
|
||||
xor a ; ensure Z
|
||||
pop de
|
||||
ret
|
||||
|
||||
; Sets Z is A is ';', CR, LF, or null.
|
||||
isLineEnd:
|
||||
isLineEndOrComment:
|
||||
cp ';'
|
||||
ret z
|
||||
cp 0
|
||||
; Continues onto isLineEnd...
|
||||
|
||||
; Sets Z is A is CR, LF, or null.
|
||||
isLineEnd:
|
||||
or a ; same as cp 0
|
||||
ret z
|
||||
cp 0x0d
|
||||
ret z
|
||||
cp 0x0a
|
||||
ret
|
||||
|
||||
; Sets Z is A is ' ' or ','
|
||||
; Sets Z is A is ' ' '\t' or ','
|
||||
isSep:
|
||||
cp ' '
|
||||
ret z
|
||||
cp 0x09
|
||||
ret z
|
||||
cp ','
|
||||
ret
|
||||
|
||||
@ -56,7 +62,7 @@ isSep:
|
||||
isSepOrLineEnd:
|
||||
call isSep
|
||||
ret z
|
||||
call isLineEnd
|
||||
call isLineEndOrComment
|
||||
ret
|
||||
|
||||
; read word in (HL) and put it in (DE), null terminated, for a maximum of A
|
||||
@ -92,7 +98,7 @@ readWord:
|
||||
toWord:
|
||||
.loop:
|
||||
ld a, (hl)
|
||||
call isLineEnd
|
||||
call isLineEndOrComment
|
||||
jr z, .error
|
||||
call isSep
|
||||
jr nz, .success
|
||||
@ -109,6 +115,38 @@ toWord:
|
||||
cp a
|
||||
ret
|
||||
|
||||
; Advance HL to the beginning of the next line, that is, right after the next
|
||||
; 0x10 or 0x13 or both. If we reach null, we stop and error out.
|
||||
; Sets Z on success, unsets it on error.
|
||||
gotoNextLine:
|
||||
dec hl ; a bit weird, but makes the looping easier
|
||||
.loop:
|
||||
inc hl
|
||||
ld a, (hl)
|
||||
call isLineEnd
|
||||
jr nz, .loop
|
||||
; (HL) is 0x10, 0x13 or 0
|
||||
or a ; is 0?
|
||||
jr z, .error
|
||||
; we might have 0x13 followed by 0x10, let's account for this.
|
||||
; Yes, 0x10 followed by 0x10 will make us skip two lines, but this is of
|
||||
; no real consequence in our context.
|
||||
inc hl
|
||||
ld a, (hl)
|
||||
call isLineEnd
|
||||
jr nz, .success
|
||||
or a ; is 0?
|
||||
jr z, .error
|
||||
; There was another line sep. Skip this char
|
||||
inc hl
|
||||
; Continue on to .success
|
||||
.success:
|
||||
xor a ; ensure Z
|
||||
ret
|
||||
.error:
|
||||
call JUMP_UNSETZ
|
||||
ret
|
||||
|
||||
; *** Variables ***
|
||||
|
||||
tokInstr:
|
||||
|
68
apps/zasm/util.asm
Normal file
68
apps/zasm/util.asm
Normal file
@ -0,0 +1,68 @@
|
||||
; run RLA the number of times specified in B
|
||||
rlaX:
|
||||
; first, see if B == 0 to see if we need to bail out
|
||||
inc b
|
||||
dec b
|
||||
ret z ; Z flag means we had B = 0
|
||||
.loop: rla
|
||||
djnz .loop
|
||||
ret
|
||||
|
||||
; Copy BC bytes from (HL) to (DE).
|
||||
copy:
|
||||
; first, let's see if BC is zero. if it is, we have nothing to do.
|
||||
; remember: 16-bit inc/dec don't modify flags. that's why we check B
|
||||
; and C separately.
|
||||
inc b
|
||||
dec b
|
||||
jr nz, .proceed
|
||||
inc c
|
||||
dec c
|
||||
ret z ; zero? nothing to do
|
||||
.proceed:
|
||||
push bc
|
||||
push de
|
||||
push hl
|
||||
ldir
|
||||
pop hl
|
||||
pop de
|
||||
pop bc
|
||||
ret
|
||||
|
||||
callHL:
|
||||
jp (hl)
|
||||
ret
|
||||
|
||||
; If string at (HL) starts with ( and ends with ), "enter" into the parens
|
||||
; (advance HL and put a null char at the end of the string) and set Z.
|
||||
; Otherwise, do nothing and reset Z.
|
||||
enterParens:
|
||||
ld a, (hl)
|
||||
cp '('
|
||||
ret nz ; nothing to do
|
||||
push hl
|
||||
ld a, 0 ; look for null char
|
||||
; advance until we get null
|
||||
.loop:
|
||||
cpi
|
||||
jp z, .found
|
||||
jr .loop
|
||||
.found:
|
||||
dec hl ; cpi over-advances. go back to null-char
|
||||
dec hl ; looking at the last char before null
|
||||
ld a, (hl)
|
||||
cp ')'
|
||||
jr nz, .doNotEnter
|
||||
; We have parens. While we're here, let's put a null
|
||||
xor a
|
||||
ld (hl), a
|
||||
pop hl ; back at the beginning. Let's advance.
|
||||
inc hl
|
||||
cp a ; ensure Z
|
||||
ret ; we're good!
|
||||
.doNotEnter:
|
||||
pop hl
|
||||
call JUMP_UNSETZ
|
||||
ret
|
||||
|
||||
|
@ -15,11 +15,13 @@ P_NULL: .db 0
|
||||
|
||||
; add the value of A into DE
|
||||
addDE:
|
||||
push af
|
||||
add a, e
|
||||
jr nc, .end ; no carry? skip inc
|
||||
inc d
|
||||
.end:
|
||||
ld e, a
|
||||
pop af
|
||||
ret
|
||||
|
||||
; copy (DE) into DE, little endian style (addresses in z80 are always have
|
||||
@ -46,11 +48,13 @@ intoHL:
|
||||
|
||||
; add the value of A into HL
|
||||
addHL:
|
||||
push af
|
||||
add a, l
|
||||
jr nc, .end ; no carry? skip inc
|
||||
inc h
|
||||
.end:
|
||||
ld l, a
|
||||
pop af
|
||||
ret
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user