mirror of
https://github.com/hsoft/collapseos.git
synced 2025-02-17 17:46:01 +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
|
kernel.h: glue.asm
|
||||||
scas -o - -I ../../../parts/z80 $< | ./bin2c.sh KERNEL | tee $@ > /dev/null
|
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
|
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
|
; size in bytes of each row in the primary instructions table
|
||||||
INSTR_TBL_ROWSIZE .equ 9
|
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'
|
; Checks whether A is 'N' or 'M'
|
||||||
checkNOrM:
|
checkNOrM:
|
||||||
cp 'N'
|
cp 'N'
|
||||||
@ -772,13 +705,11 @@ processArg:
|
|||||||
call JUMP_UNSETZ
|
call JUMP_UNSETZ
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Parse line at (HL) and write resulting opcode(s) in curUpcode. Returns the
|
; Parse tokens in (tokInstr), (tokArg1) and (tokArg2) and write resulting
|
||||||
; number of bytes written in A.
|
; opcode(s) in (curUpcode). Returns the number of bytes written in A.
|
||||||
parseLine:
|
parseTokens:
|
||||||
push hl
|
push hl
|
||||||
push de
|
push de
|
||||||
call tokenize
|
|
||||||
jr nz, .error
|
|
||||||
ld a, (tokInstr)
|
ld a, (tokInstr)
|
||||||
cp 0
|
cp 0
|
||||||
jr z, .error ; for now, we treat blank lines as errors
|
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)
|
TMPFILE=$(mktemp)
|
||||||
SCAS=scas
|
SCAS=scas
|
||||||
ZASM=../emul/zasm
|
ZASM=../emul/zasm
|
||||||
ASMFILE=../zasm.asm
|
ASMFILE=../instr.asm
|
||||||
|
|
||||||
./geninstrs.py $ASMFILE | \
|
cmpas() {
|
||||||
while read line; do
|
EXPECTED=$($SCAS -o - "$1" | xxd)
|
||||||
echo $line | tee "${TMPFILE}"
|
ACTUAL=$(cat $1 | $ZASM | xxd)
|
||||||
EXPECTED=$($SCAS -o - "${TMPFILE}" | xxd)
|
|
||||||
ACTUAL=$(echo $line | $ZASM | xxd)
|
|
||||||
if [ "$ACTUAL" == "$EXPECTED" ]; then
|
if [ "$ACTUAL" == "$EXPECTED" ]; then
|
||||||
echo ok
|
echo ok
|
||||||
else
|
else
|
||||||
@ -21,4 +19,15 @@ while read line; do
|
|||||||
echo $EXPECTED
|
echo $EXPECTED
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
done
|
||||||
|
@ -30,25 +30,31 @@ tokenize:
|
|||||||
ld de, tokArg2
|
ld de, tokArg2
|
||||||
call readWord
|
call readWord
|
||||||
.end:
|
.end:
|
||||||
cp a ; ensure Z
|
xor a ; ensure Z
|
||||||
pop de
|
pop de
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Sets Z is A is ';', CR, LF, or null.
|
; Sets Z is A is ';', CR, LF, or null.
|
||||||
isLineEnd:
|
isLineEndOrComment:
|
||||||
cp ';'
|
cp ';'
|
||||||
ret z
|
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
|
ret z
|
||||||
cp 0x0d
|
cp 0x0d
|
||||||
ret z
|
ret z
|
||||||
cp 0x0a
|
cp 0x0a
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; Sets Z is A is ' ' or ','
|
; Sets Z is A is ' ' '\t' or ','
|
||||||
isSep:
|
isSep:
|
||||||
cp ' '
|
cp ' '
|
||||||
ret z
|
ret z
|
||||||
|
cp 0x09
|
||||||
|
ret z
|
||||||
cp ','
|
cp ','
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@ -56,7 +62,7 @@ isSep:
|
|||||||
isSepOrLineEnd:
|
isSepOrLineEnd:
|
||||||
call isSep
|
call isSep
|
||||||
ret z
|
ret z
|
||||||
call isLineEnd
|
call isLineEndOrComment
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; read word in (HL) and put it in (DE), null terminated, for a maximum of A
|
; read word in (HL) and put it in (DE), null terminated, for a maximum of A
|
||||||
@ -92,7 +98,7 @@ readWord:
|
|||||||
toWord:
|
toWord:
|
||||||
.loop:
|
.loop:
|
||||||
ld a, (hl)
|
ld a, (hl)
|
||||||
call isLineEnd
|
call isLineEndOrComment
|
||||||
jr z, .error
|
jr z, .error
|
||||||
call isSep
|
call isSep
|
||||||
jr nz, .success
|
jr nz, .success
|
||||||
@ -109,6 +115,38 @@ toWord:
|
|||||||
cp a
|
cp a
|
||||||
ret
|
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 ***
|
; *** Variables ***
|
||||||
|
|
||||||
tokInstr:
|
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
|
; add the value of A into DE
|
||||||
addDE:
|
addDE:
|
||||||
|
push af
|
||||||
add a, e
|
add a, e
|
||||||
jr nc, .end ; no carry? skip inc
|
jr nc, .end ; no carry? skip inc
|
||||||
inc d
|
inc d
|
||||||
.end:
|
.end:
|
||||||
ld e, a
|
ld e, a
|
||||||
|
pop af
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; copy (DE) into DE, little endian style (addresses in z80 are always have
|
; 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
|
; add the value of A into HL
|
||||||
addHL:
|
addHL:
|
||||||
|
push af
|
||||||
add a, l
|
add a, l
|
||||||
jr nc, .end ; no carry? skip inc
|
jr nc, .end ; no carry? skip inc
|
||||||
inc h
|
inc h
|
||||||
.end:
|
.end:
|
||||||
ld l, a
|
ld l, a
|
||||||
|
pop af
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user