uxn/projects/software/asma.usm

947 lines
23 KiB
Plaintext
Raw Normal View History

2021-03-31 18:55:02 -04:00
( devices )
2021-05-03 14:15:06 -04:00
|10 @Console [ &pad $8 &char $1 &byte $1 &short $2 &string $2 ]
|a0 @File [ &vector $2 &success $2 &offset $2 &pad $2 &name $2 &length $2 &load $2 &save $2 ]
2021-03-31 18:55:02 -04:00
( vectors )
(
Asma - an in-Uxn assembler
This assembler aims to be binary compatible with the output from
src/assembler.c, but unlike that assembler this one can be run inside Uxn
itself!
Asma is designed to be able to be copy-pasted inside another project, so
all its routines are prefixed with "asma-" to prevent clashes with labels
used in the incorporating project. The reset vector contains a couple of
examples of asma's usage and can be discarded.
)
2021-05-15 14:58:50 -04:00
|0100 @reset
(
Assemble the source code into an output ROM file.
If all you want is to use asma.usm to assemble files, insert a BRK
after this statement.
)
2021-05-15 14:58:50 -04:00
;&source-file ;&dest-file ;asma-assemble-file JSR2
(
If an error has occurred, BRK here, otherwise continue. (The error
message will already have been printed to the Console in
asma-assemble-file.)
)
;asma/error LDA2 #0000 EQU2 JMP BRK
(
Load the output ROM over the currently running program, almost as if
we loaded the ROM with uxnemu directly!
It's not a totally pristine environment, as File/load doesn't zero out
memory beyond the end of the file. So if the assembled program assumes
that all memory above it is zero, it may misbehave.
Asma itself doesn't use the zero page, but this example code writes a
DEO2 instruction to 0x00ff. In order to execute File/load and have the
CPU continue at memory location 0x0100, we write the final DEO2
instruction there and jump there as our final act.
Just in case the assembled code is zero-length (which can occur when
assembling an empty source file), we write a BRK to the reset vector so
that will prevent an infinite loop.
)
;&dest-file .File/name DEO2
#0000 .File/offset DEO2
#ff00 .File/length DEO2
#0100 .File/load
LIT DEO2 #00ff STA
LIT BRK #0100 STA
#00ff JMP2
2021-05-03 14:15:06 -04:00
2021-05-15 14:58:50 -04:00
&source-file
"projects/demos/piano.usm 00
&dest-file
"bin/asma-boot.rom 00
2021-05-15 13:08:08 -04:00
(
Common macros for use later on.
)
2021-05-03 14:15:06 -04:00
%asma-IF-ERROR { ;asma/error LDA2 ORA }
%asma-LOG { #01 }
(
asma-LOG is a log-level parameter for helping to debug stuff.
It's value is the bitwise OR of all the following output types:
#01 prints the number of lines in the source code,
#02 prints tokens as they are processed, and
#04 dumps all defined labels at end.
)
%asma-DEO2 { asma-LOG AND #00 EQU JMP DEO2k POP POP2 }
%asma-DEO { asma-LOG AND #00 EQU JMP DEOk POP2 }
2021-05-03 14:15:06 -04:00
2021-05-15 14:58:50 -04:00
(
Asma's public interface.
These routines are what are expected to be called from programs that bundle
Asma into bigger projects.
)
@asma-assemble-file ( src-filename* dest-filename* -- )
;asma/dest-filename STA2 ;asma/src-filename STA2
;asma-init-first-pass JSR2
2021-05-15 16:02:33 -04:00
;asma-flush-ignore ;asma/flush-fn STA2
2021-05-15 14:58:50 -04:00
;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2
asma-IF-ERROR ,&error JCN
;asma-init-next-pass JSR2
2021-05-15 16:02:33 -04:00
;asma-flush-to-file ;asma/flush-fn STA2
2021-05-15 14:58:50 -04:00
;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2
asma-IF-ERROR ,&error JCN
;asma-trees/labels ;asma-print-labels JSR2 ( DEBUG )
;asma-print-linecount JSR2 ( DEBUG )
JMP2r
&error
;asma-print-error JSR2 ( DEBUG )
JMP2r
2021-05-15 13:08:08 -04:00
(
Debugging routines. These all output extra information to the Console.
These can be stripped out to save space, once the references to them are
2021-05-15 14:58:50 -04:00
removed. Look for the word DEBUG above to find these references: the lines
that contain that word can be deleted to strip out the functionality
2021-05-15 13:08:08 -04:00
cleanly.
)
2021-05-15 14:58:50 -04:00
@asma-print-error ( -- )
;asma/error LDA2 .Console/string DEO2
#3a .Console/char DEO
#20 .Console/char DEO
;asma/orig-token LDA2 .Console/string DEO2
;&line .Console/string DEO2
( FIXME it would be nicer if line numbers were in decimal )
2021-05-15 14:58:50 -04:00
;asma/line LDA2 .Console/short DEO2
#2e .Console/char DEO
#0a .Console/char DEO
BRK
&line 20 "on 20 "line 20 00
@asma-print-linecount ( -- )
( FIXME it would be nicer if line numbers were in decimal )
;asma/line LDA2 .Console/short #01 asma-DEO2
;&lines .Console/string #01 asma-DEO2
2021-05-15 14:58:50 -04:00
JMP2r
&lines [ 20 "lines 20 "in 20 "total. 0a 00 ]
@asma-print-sublabels ( incoming-ptr* -- )
2021-05-14 03:09:55 -04:00
LDA2
ORAk ,&valid-incoming-ptr JCN
POP2 JMP2r
&valid-incoming-ptr
( left node )
2021-05-15 14:58:50 -04:00
DUP2 ,asma-print-sublabels JSR
2021-05-14 03:09:55 -04:00
( here )
#09 .Console/char #04 asma-DEO
2021-05-14 03:09:55 -04:00
DUP2 #0004 ADD2
&loop
DUP2 #0001 ADD2 SWP2 LDA
DUP #00 EQU ,&end JCN
.Console/char #04 asma-DEO
2021-05-14 03:09:55 -04:00
,&loop JMP
&end
POP
#09 .Console/char #04 asma-DEO
LDA2 .Console/short #04 asma-DEO2
#0a .Console/char #04 asma-DEO
2021-05-14 03:09:55 -04:00
( right node )
2021-05-15 14:58:50 -04:00
#0002 ADD2 ,asma-print-sublabels JSR
2021-05-14 03:09:55 -04:00
JMP2r
2021-05-15 14:58:50 -04:00
@asma-print-labels ( incoming-ptr* -- )
2021-05-14 03:09:55 -04:00
LDA2
ORAk ,&valid-incoming-ptr JCN
POP2 JMP2r
&valid-incoming-ptr
( left node )
2021-05-15 14:58:50 -04:00
DUP2 ,asma-print-labels JSR
2021-05-14 03:09:55 -04:00
( here )
DUP2 #0004 ADD2
&loop
DUP2 #0001 ADD2 SWP2 LDA
DUP #00 EQU ,&end JCN
.Console/char #04 asma-DEO
2021-05-14 03:09:55 -04:00
,&loop JMP
&end
POP
#09 .Console/char #04 asma-DEO
LDA2k .Console/short #04 asma-DEO2
#0a .Console/char #04 asma-DEO
2021-05-14 03:09:55 -04:00
( subtree )
2021-05-15 14:58:50 -04:00
#0002 ADD2 ;asma-print-sublabels JSR2
2021-05-14 03:09:55 -04:00
( right node )
2021-05-15 14:58:50 -04:00
#0002 ADD2 ,asma-print-labels JSR
2021-05-14 03:09:55 -04:00
JMP2r
2021-05-15 14:58:50 -04:00
(
Initialise the assembler state before loading a file or chunk.
)
2021-05-03 14:15:06 -04:00
2021-05-15 14:58:50 -04:00
@asma-init-first-pass ( -- )
#ff ;asma/pass STA
2021-05-15 16:02:33 -04:00
#0000 DUP2k
;asma/error STA2
;asma-trees/labels STA2
;asma-trees/macros STA2
2021-05-15 14:58:50 -04:00
;asma-heap ;asma/heap STA2
;asma-opcodes/_entry ;asma-trees/opcodes STA2
( fall through )
2021-05-14 03:09:55 -04:00
2021-05-15 14:58:50 -04:00
@asma-init-next-pass ( -- )
;asma/pass LDA #01 ADD ;asma/pass STA
2021-05-15 16:02:33 -04:00
;asma-write-buffer ;asma-output/ptr STA2
#0000 DUP2k
;asma-output/offset STA2
;asma/addr STA2
;asma/state STA
#01 ( 0001 )
SWPk ( 0001 0100 ) ;asma/written-addr STA2
;asma/line STA2
2021-05-15 14:58:50 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
2021-05-15 14:58:50 -04:00
(
Divide a file up into chunks, and pass each chunk to asma-assemble-chunk.
)
2021-05-03 14:15:06 -04:00
@asma-assemble-file-pass ( filename-ptr* -- )
2021-04-18 07:48:49 -04:00
#0000
2021-04-24 05:50:21 -04:00
&loop
OVR2 .File/name DEO2
DUP2 .File/offset DEO2
2021-05-15 16:02:33 -04:00
;asma-read-buffer/end ;asma-read-buffer SUB2 STH2k .File/length DEO2
;asma-read-buffer DUP2k .File/load DEO2
.File/success DEI2
DUP2 STH2r SUB2 ORA ,&last-one JCN
2021-05-11 14:12:07 -04:00
,asma-assemble-chunk JSR asma-IF-ERROR ,&error JCN
2021-04-18 07:48:49 -04:00
SUB2 SUB2
2021-04-24 05:50:21 -04:00
,&loop JMP
2021-04-18 07:48:49 -04:00
&last-one
ADD2k #00 ROT ROT STA
#0001 ADD2
,asma-assemble-chunk JSR asma-IF-ERROR ,&error JCN
2021-05-15 16:02:33 -04:00
( flush output buffer )
;asma-output/ptr LDA2 ;asma-write-buffer SUB2 ;asma/flush-fn LDA2 JSR2
POP2
&error
POP2 POP2 POP2
JMP2r
2021-05-15 14:58:50 -04:00
(
Assemble a chunk of source code, which begins with whitespace or the start
of a token and is divided up into tokens separated by whitespace. If the
chunk ends with whitespace, assembled-up-to-ptr* will equal ptr* + len* and
every token in the chunk will have been assembled. If the chunk ends with a
non-whitespace character, assembled-up-to-ptr* will point to the beginning
of the last token in the chunk.
)
2021-04-12 16:01:36 -04:00
2021-05-03 14:15:06 -04:00
@asma-assemble-chunk ( ptr* len* -- assembled-up-to-ptr* )
2021-05-13 17:51:36 -04:00
OVR2 ADD2 #0001 SUB2 SWP2 STH2k
2021-05-03 14:15:06 -04:00
,&loop JMP
2021-04-12 16:01:36 -04:00
2021-05-03 14:15:06 -04:00
&next-char-pop
POP
&next-char
2021-04-12 16:01:36 -04:00
#0001 ADD2
2021-05-03 14:15:06 -04:00
&loop ( last-ptr* ptr* / start-of-token* )
2021-05-11 14:12:07 -04:00
OVR2 OVR2 LTH2 ,&end JCN
2021-05-13 17:51:36 -04:00
LDAk ( last-ptr* ptr* char / start-of-token* )
2021-05-11 14:12:07 -04:00
DUP #20 GTH ,&next-char-pop JCN
2021-04-12 16:01:36 -04:00
2021-05-03 14:15:06 -04:00
#00 OVR2 ( last-ptr* ptr* char 00 ptr* / start-of-token* )
STA
2021-05-11 14:12:07 -04:00
STH2r ,asma-assemble-token JSR asma-IF-ERROR ,&error JCN
2021-04-12 16:01:36 -04:00
2021-05-11 14:12:07 -04:00
#0a NEQ ,&not-newline JCN
2021-05-03 14:15:06 -04:00
;asma/line LDA2 #0001 ADD2 ;asma/line STA2
&not-newline
2021-04-12 16:01:36 -04:00
2021-05-03 14:15:06 -04:00
DUP2 #0001 ADD2 STH2 ,&next-char JMP
2021-04-12 16:01:36 -04:00
2021-04-24 05:50:21 -04:00
&end
2021-05-03 14:15:06 -04:00
POP2 POP2 STH2r
2021-04-12 16:01:36 -04:00
JMP2r
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
&error
POP POP2 POP2
2021-03-31 18:55:02 -04:00
JMP2r
2021-05-15 14:58:50 -04:00
@asma [ &pass $1 &state $1 &line $2 &token $2 &orig-token $2 &heap $2 &addr $2 &written-addr $2 &flush-fn $2 &src-filename $2 &dest-filename $2 &error $2 ]
2021-05-03 14:15:06 -04:00
@asma-trees [ &labels $2 &macros $2 &opcodes $2 &scope $2 ]
2021-03-31 18:55:02 -04:00
2021-05-15 13:08:08 -04:00
(
The main routine to assemble a single token.
asma/state contains several meaningful bits:
0x02 we are in a comment,
0x04 we are in a macro body, and
0x08 we are in a macro body that we are ignoring
(because the macro was already defined in a previous pass).
Since 0x08 never appears without 0x04, the lowest bit set in asma/state is
always 0x00, 0x02, or 0x04, which is very handy for use with jump tables.
The lowest bit set can be found easily by #00 (n) SUBk AND.
)
2021-05-03 14:15:06 -04:00
@asma-assemble-token ( string-ptr* -- )
DUP2 .Console/string #02 asma-DEO2
#0a .Console/char #02 asma-DEO
2021-05-03 14:15:06 -04:00
DUP2 ;asma/token STA2
DUP2 ;asma/orig-token STA2
2021-05-13 17:51:36 -04:00
LDAk ,&not-empty JCN
2021-05-03 14:15:06 -04:00
POP2
2021-03-31 18:55:02 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
&not-empty ( token* / )
( truncate to one char long )
#0001 ADD2 ( end* / )
2021-05-13 17:51:36 -04:00
STH2k LDAkr ( end* / end* char )
STH2k ( end* / end* char end* )
2021-05-03 14:15:06 -04:00
LITr 00 STH2 ( / end* char end* 00 end* )
STAr ( / end* char end* )
2021-03-31 18:55:02 -04:00
2021-05-13 17:51:36 -04:00
#00 ;asma/state LDA SUBk AND ( tree-offset* / end* )
2021-05-03 14:15:06 -04:00
DUP2 ;&first-char-trees ADD2 ( tree-offset* incoming-ptr* / end* )
;asma-traverse-tree JSR2
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
( restore truncated char )
STAr
2021-03-31 18:55:02 -04:00
2021-05-11 14:12:07 -04:00
,&not-found JCN
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
( tree-offset* token-routine-ptr* / end* )
STH2r ;asma/token STA2
SWP2 POP2 LDA2
JMP2 ( tail call )
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
&not-found ( tree-offset* dummy* / end* )
POP2 POP2r
2021-05-15 13:08:08 -04:00
;&body-routines ADD2 LDA2
2021-05-03 14:15:06 -04:00
JMP2 ( tail call )
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
&first-char-trees
:asma-first-char-normal/_entry
:asma-first-char-comment/_entry
:asma-first-char-macro/_entry
2021-03-31 18:55:02 -04:00
2021-05-15 13:08:08 -04:00
&body-routines
2021-05-03 14:15:06 -04:00
:asma-normal-body
:asma-ignore
:asma-macro-body
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
@asma-parse-hex-digit ( charcode -- 00-0f if valid hex
OR 10-ff otherwise )
2021-05-11 14:12:07 -04:00
DUP #3a LTH ,&digit JCN
DUP #60 GTH ,&letter JCN
2021-05-03 14:15:06 -04:00
JMP2r
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
&digit
#30 SUB
JMP2r
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
&letter
#57 SUB
2021-03-31 18:55:02 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
@asma-parse-hex-string ( -- value* 06 if valid hex and length > 2
OR value* 03 if valid hex and length <= 2
OR 00 otherwise )
;asma/token LDA2 DUP2 ,asma-strlen JSR #02 GTH ROT ROT
LIT2r 0000
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
&loop
2021-05-13 17:51:36 -04:00
LDAk
2021-05-11 14:12:07 -04:00
DUP ,&not-end JCN
2021-05-03 14:15:06 -04:00
POP POP2
STH2r ROT #01 ADD #03 MUL
2021-03-31 18:55:02 -04:00
JMP2r
2021-04-24 05:50:21 -04:00
&not-end
2021-05-03 14:15:06 -04:00
,asma-parse-hex-digit JSR
2021-05-11 14:12:07 -04:00
DUP #f0 AND ,&fail JCN
2021-05-03 14:15:06 -04:00
LIT2r 0010 MUL2r
#00 STH STH ADD2r
#0001 ADD2
2021-04-24 05:50:21 -04:00
,&loop JMP
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
&fail
POP POP2 POP2r
DUP EOR
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
@asma-strlen ( string-ptr* -- length )
LITr 00
2021-03-31 18:55:02 -04:00
2021-04-24 05:50:21 -04:00
&loop
2021-05-13 17:51:36 -04:00
LDAk
2021-05-11 14:12:07 -04:00
,&not-end JCN
2021-05-03 14:15:06 -04:00
POP2 STHr
2021-03-31 18:55:02 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
&not-end
LITr 01 ADDr
2021-03-31 18:55:02 -04:00
#0001 ADD2
2021-05-03 14:15:06 -04:00
,&loop JMP
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
%asma-SHORT-FLAG { #20 }
%asma-RETURN-FLAG { #40 }
2021-05-12 18:51:34 -04:00
%asma-KEEP-FLAG { #80 }
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
@asma-parse-opcode ( -- byte 00 if valid opcode
OR 01 otherwise )
;asma/token LDA2
2021-05-11 14:12:07 -04:00
DUP2 ,asma-strlen JSR #03 LTH ,&too-short JCN
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
( truncate to three chars long )
#0003 ADD2 ( end* / )
2021-05-13 17:51:36 -04:00
STH2k LDAkr ( end* / end* char )
STH2k ( end* / end* char end* )
2021-05-03 14:15:06 -04:00
LITr 00 STH2 ( / end* char end* 00 end* )
STAr ( / end* char end* )
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
;asma-trees/opcodes ;asma-traverse-tree JSR2
STAr
2021-05-11 14:12:07 -04:00
,&not-found JCN
2021-04-14 17:00:10 -04:00
2021-05-03 14:15:06 -04:00
;asma-opcodes/_disasm SUB2 #0003 SFT2 ( 00 byte / end* )
&loop
2021-05-13 17:51:36 -04:00
LDAkr STHr LIT2r 0001 ADD2r ( 00 byte char / end* )
2021-05-11 14:12:07 -04:00
DUP ,&not-end JCN
2021-05-03 14:15:06 -04:00
POP POP2r
SWP
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
&not-end
2021-05-11 14:12:07 -04:00
DUP LIT '2 NEQ ,&not-two JCN
2021-05-03 14:15:06 -04:00
POP asma-SHORT-FLAG ORA ,&loop JMP
2021-04-11 18:45:31 -04:00
2021-05-03 14:15:06 -04:00
&not-two
2021-05-12 18:51:34 -04:00
DUP LIT 'r NEQ ,&not-return JCN
POP asma-RETURN-FLAG ORA ,&loop JMP
2021-04-24 05:50:21 -04:00
2021-05-12 18:51:34 -04:00
&not-return
LIT 'k NEQ ,&not-keep JCN
asma-KEEP-FLAG ORA ,&loop JMP
&not-keep ( 00 byte / end* )
2021-05-03 14:15:06 -04:00
&not-found ( incoming-ptr* / end* )
POP2r
&too-short ( token* / )
POP2 #01
2021-04-11 18:45:31 -04:00
JMP2r
2021-05-15 16:02:33 -04:00
@asma-write-short ( short -- )
SWP
,asma-write-byte JSR
,asma-write-byte JMP ( tail call )
2021-05-03 14:15:06 -04:00
@asma-write-byte ( byte -- )
;asma/addr LDA2 ;asma/written-addr LDA2
LTH2k ,&rewound JCN
&loop
EQU2k ,&ready JCN
#00 ,&write JSR
#0001 ADD2
,&loop JMP
2021-05-15 16:02:33 -04:00
&rewound
;asma-msg-rewound ;asma/error STA2
POP2 POP2 POP JMP2r
&ready
POP2 #0001 ADD2
DUP2 ;asma/addr STA2
;asma/written-addr STA2
&write
2021-05-15 16:02:33 -04:00
,asma-output/ptr LDR2
DUP2 ;asma-write-buffer/end EQU2 ,&flush JCN
&after-flush
STH2k STA
STH2r #0001 ADD2 ,asma-output/ptr STR2
( #3e .Console/char ;asma/pass LDA asma-DEO
#20 .Console/char ;asma/pass LDA asma-DEO
2021-05-15 16:02:33 -04:00
#00 .Console/byte ;asma/pass LDA asma-DEO
#0a .Console/char ;asma/pass LDA asma-DEO )
2021-04-11 18:45:31 -04:00
JMP2r
2021-05-15 16:02:33 -04:00
&flush ( ptr* -- start-of-buffer* )
;asma-write-buffer SUB2k ( ptr* start* len* )
;asma/flush-fn LDA2 JSR2
SWP2 POP2 ( start* )
,&after-flush JMP
2021-05-15 16:02:33 -04:00
@asma-output [ &ptr $2 &offset $2 &filename $2 ]
@asma-flush-ignore ( len* -- )
POP2
JMP2r
@asma-flush-to-file ( len* -- )
DUP2 .File/length DEO2
,asma-output/offset LDR2 DUP2 .File/offset DEO2 ADD2 ,asma-output/offset STR2
;asma/dest-filename LDA2 .File/name DEO2
;asma-write-buffer .File/save DEO2
JMP2r
2021-04-11 18:45:31 -04:00
2021-05-03 14:15:06 -04:00
@asma-append-heap-byte ( dummy byte -- dummy )
;asma/heap LDA2
OVR2 OVR2 STA POP
#0001 ADD2 ;asma/heap STA2
POP
2021-04-11 18:45:31 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
@asma-append-heap-short ( dummy short* -- dummy )
SWP
,asma-append-heap-byte JSR
,asma-append-heap-byte JMP ( tail call )
2021-04-11 18:45:31 -04:00
2021-05-03 14:15:06 -04:00
@asma-append-heap-string ( string* -- )
2021-05-13 17:51:36 -04:00
LDAk
2021-05-03 14:15:06 -04:00
DUP ,asma-append-heap-byte JSR
2021-05-11 14:12:07 -04:00
,&keep-going JCN
2021-05-03 14:15:06 -04:00
POP2 JMP2r
2021-04-11 18:45:31 -04:00
2021-04-24 05:50:21 -04:00
&keep-going
2021-04-11 18:45:31 -04:00
#0001 ADD2
2021-05-03 14:15:06 -04:00
,asma-append-heap-string JMP
@asma-traverse-tree ( incoming-ptr* -- binary-ptr* 00 if key found
OR node-incoming-ptr* 01 if key not found )
&loop ( incoming-ptr* )
2021-05-13 17:51:36 -04:00
LDA2k ORA ,&valid-node JCN
2021-05-03 14:15:06 -04:00
#01 JMP2r
&valid-node
2021-05-13 17:51:36 -04:00
LDA2 STH2k
2021-05-03 14:15:06 -04:00
#0004 ADD2 ,asma-strcmp-tree JSR
2021-05-11 14:12:07 -04:00
DUP ,&nomatch JCN
2021-05-03 14:15:06 -04:00
POP2r JMP2r
&nomatch
#06 SFT #02 AND #00 SWP
STH2r ADD2
2021-04-24 05:50:21 -04:00
,&loop JMP
2021-04-11 18:45:31 -04:00
2021-05-03 14:15:06 -04:00
( &help-str "Looking 20 "up 20 00 )
@asma-strcmp-tree ( node-key* -- order if strings differ
OR after-node-key* 00 if strings match )
;asma/token LDA2 STH2
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
&loop ( node-key* / token* )
2021-05-13 17:51:36 -04:00
DUP2 #0001 ADD2 SWP2 LDA LDAkr STHr
ORAk ,&not-end JCN
2021-04-24 05:50:21 -04:00
2021-05-03 14:15:06 -04:00
( end of C strings, match found )
POP2r POP
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
&not-end
SUB
2021-05-11 14:12:07 -04:00
DUP ,&nomatch JCN
2021-04-11 04:40:26 -04:00
POP
2021-05-03 14:15:06 -04:00
LIT2r 0001 ADD2r
,&loop JMP
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
&nomatch
POP2r ROT ROT POP2
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-15 13:08:08 -04:00
(
First character routines.
The following routines (that don't have a FORTH-like signature) are called
to deal with tokens that begin with particular first letters, or (for
-body routines) tokens that fail to match any first letter in their tree.
)
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
%asma-STATE-SET { ;asma/state LDA ORA ;asma/state STA }
%asma-STATE-CLEAR { #ff EOR ;asma/state LDA AND ;asma/state STA }
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
@asma-comment-start
#02 asma-STATE-SET
@asma-ignore
JMP2r
2021-04-24 05:50:21 -04:00
2021-05-03 14:15:06 -04:00
@asma-comment-end
#02 asma-STATE-CLEAR
JMP2r
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
@asma-macro-define
2021-05-11 14:12:07 -04:00
;asma/pass LDA ,&ignore-macro JCN
2021-04-11 04:40:26 -04:00
2021-05-11 14:12:07 -04:00
;asma-trees/macros ;asma-traverse-tree JSR2 ,&not-exist JCN
2021-05-03 14:15:06 -04:00
POP2
;asma-msg-macro ;asma/error STA2
JMP2r
2021-04-24 05:50:21 -04:00
2021-05-03 14:15:06 -04:00
&not-exist
( define macro by creating new node )
;asma/heap LDA2 SWP2 STA2
#0000 ;asma-append-heap-short JSR2 ( less-than pointer )
#0000 ;asma-append-heap-short JSR2 ( greater-than pointer )
;asma/token LDA2 ;asma-append-heap-string JSR2 ( key )
#04 asma-STATE-SET
JMP2r
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
&ignore-macro
#0c asma-STATE-SET
JMP2r
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
@asma-macro-body
2021-05-15 13:08:08 -04:00
;asma/state LDA #08 AND ,&skip JCN
2021-05-03 14:15:06 -04:00
;asma/token LDA2 ;asma-append-heap-string JSR2
2021-05-15 13:08:08 -04:00
&skip
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
@asma-macro-end
#00 ;asma-append-heap-byte JSR2
#0c asma-STATE-CLEAR
JMP2r
2021-04-24 05:50:21 -04:00
2021-05-03 14:15:06 -04:00
@asma-label-define
;asma-trees/labels ,asma-label-helper JSR
2021-05-11 14:12:07 -04:00
,&already-existed JCN
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
#0000 ;asma-append-heap-short JSR2 ( data2: subtree incoming ptr )
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
&already-existed
#0002 ADD2 ;asma-trees/scope STA2
JMP2r
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
@asma-sublabel-define
;asma-trees/scope LDA2 ,asma-label-helper JSR
POP POP2
JMP2r
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
@asma-label-helper ( incoming-ptr* -- binary-ptr* 00 if label existed already
OR binary-ptr* 01 if label was created )
;asma-traverse-tree JSR2
2021-05-11 14:12:07 -04:00
,&new-label JCN
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
( label already exists )
( FIXME check label address )
#01 JMP2r
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
&new-label ( incoming-ptr* )
( define label by creating new node )
;asma/heap LDA2 SWP2 STA2
#0000 ;asma-append-heap-short JSR2 ( less-than pointer )
#0000 ;asma-append-heap-short JSR2 ( greater-than pointer )
;asma/token LDA2 ;asma-append-heap-string JSR2 ( key )
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
;asma/heap LDA2
2021-04-24 05:50:21 -04:00
;asma/addr LDA2 ;asma-append-heap-short JSR2 ( data1: address )
2021-05-03 14:15:06 -04:00
#00 JMP2r
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
@asma-pad-absolute
#0000 ,asma-pad-helper JMP
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
@asma-pad-relative
;asma/addr LDA2
( fall through )
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
@asma-pad-helper ( offset* -- )
;asma-parse-hex-string JSR2
2021-05-11 14:12:07 -04:00
,&valid JCN
2021-04-11 04:40:26 -04:00
2021-05-14 03:09:55 -04:00
;asma-msg-hex ;asma/error STA2
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
&valid
ADD2 ;asma/addr STA2
2021-04-11 18:45:31 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
@asma-raw-char
;asma/token LDA2 LDA
;asma-write-byte JMP2 ( tail call )
2021-04-11 18:45:31 -04:00
2021-05-03 14:15:06 -04:00
@asma-raw-word
;asma/token LDA2
2021-04-11 18:45:31 -04:00
2021-04-24 05:50:21 -04:00
&loop
2021-05-13 17:51:36 -04:00
LDAk
2021-05-11 14:12:07 -04:00
DUP ,&not-end JCN
2021-05-03 14:15:06 -04:00
POP POP2
2021-04-11 18:45:31 -04:00
JMP2r
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
&not-end
;asma-write-byte JSR2
#0001 ADD2
,&loop JMP
@asma-literal-abs-addr
LIT LIT2 ;asma-write-byte JSR2
( fall through )
2021-04-24 05:50:21 -04:00
2021-05-03 14:15:06 -04:00
@asma-abs-addr
,asma-addr-helper JSR
;asma-write-short JMP2 ( tail call )
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
@asma-literal-zero-addr
LIT LIT ;asma-write-byte JSR2
,asma-addr-helper JSR
;asma-write-byte JSR2
2021-04-11 04:40:26 -04:00
2021-05-11 14:12:07 -04:00
,&not-zero-page JCN
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
&not-zero-page
;asma-msg-zero-page ;asma/error STA2
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
@asma-literal-rel-addr
LIT LIT ;asma-write-byte JSR2
,asma-addr-helper JSR ;asma/addr LDA2 SUB2 #0002 SUB2
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
DUP2 #0080 LTH2 STH
2021-05-11 14:12:07 -04:00
DUP2 #ff7f GTH2 STHr ORA ,&in-bounds JCN
2021-04-11 04:40:26 -04:00
POP2
2021-05-03 14:15:06 -04:00
;asma-msg-relative ;asma/error STA2
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
&in-bounds
;asma-write-byte JSR2
POP
2021-04-11 04:40:26 -04:00
JMP2r
2021-05-03 14:15:06 -04:00
@asma-addr-helper ( -- addr* )
2021-05-13 17:51:36 -04:00
;asma/token LDA2 LDAk #26 NEQ ,&not-local JCN
2021-05-03 14:15:06 -04:00
#0001 ADD2 ;asma/token STA2
;asma-trees/scope LDA2
2021-05-03 14:15:06 -04:00
,&final-lookup JMP
&not-local ( token* )
2021-05-13 17:51:36 -04:00
LDAk
2021-05-11 14:12:07 -04:00
DUP ,&not-end JCN
2021-05-03 14:15:06 -04:00
POP POP2
;asma-trees/labels
2021-05-03 14:15:06 -04:00
,&final-lookup JMP
&not-end ( token* char )
2021-05-11 14:12:07 -04:00
#2f EQU ,&found-slash JCN
2021-05-03 14:15:06 -04:00
#0001 ADD2
,&not-local JMP
&found-slash ( token* )
DUP2 #00 ROT ROT STA
;asma-trees/labels ;asma-traverse-tree JSR2 STH
SWP2 DUP2 #2f ROT ROT STA
STHr ,&not-found2 JCN
2021-05-03 14:15:06 -04:00
( token* binary-ptr* )
#0001 ADD2 ;asma/token STA2
#0002 ADD2
2021-04-11 04:40:26 -04:00
2021-05-03 14:15:06 -04:00
&final-lookup ( addr-offset* incoming-ptr* )
;asma-traverse-tree JSR2
,&not-found JCN
LDA2
2021-04-11 04:40:26 -04:00
JMP2r
&not-found2 ( dummy* dummy* )
POP2
&not-found ( dummy* )
POP2
2021-05-03 14:15:06 -04:00
2021-05-11 14:12:07 -04:00
;asma/pass LDA #00 EQU ,&ignore-error JCN
2021-05-03 14:15:06 -04:00
;asma-msg-label ;asma/error STA2
&ignore-error
;asma/addr LDA2
2021-04-11 04:40:26 -04:00
JMP2r
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
@asma-literal-hex
;asma-parse-hex-string JSR2 JMP
( hex invalid ) ,&invalid JMP
( hex byte ) ,asma-byte-helper JMP
( hex short ) ,asma-short-helper JMP
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
&invalid
POP2
2021-04-24 05:50:21 -04:00
2021-05-03 14:15:06 -04:00
;asma-msg-hex ;asma/error STA2
JMP2r
@asma-byte-helper ( dummy value -- )
LIT LIT ;asma-write-byte JSR2
&raw
;asma-write-byte JSR2
2021-04-12 16:01:36 -04:00
POP
JMP2r
2021-05-03 14:15:06 -04:00
@asma-short-helper ( value* -- )
LIT LIT2 ;asma-write-byte JSR2
&raw
;asma-write-short JMP2 ( tail call )
@asma-normal-body
2021-05-11 14:12:07 -04:00
;asma-parse-opcode JSR2 ,&not-opcode JCN
2021-05-03 14:15:06 -04:00
;asma-write-byte JMP2 ( tail call )
2021-04-24 05:50:21 -04:00
&not-opcode
2021-05-03 14:15:06 -04:00
;asma-parse-hex-string JSR2 JMP
( hex invalid ) ,&not-hex JMP
( hex byte ) ,asma-byte-helper/raw JMP
( hex short ) ,asma-short-helper/raw JMP
&not-hex
2021-05-11 14:12:07 -04:00
;asma-trees/macros ;asma-traverse-tree JSR2 ,&not-macro JCN
2021-05-03 14:15:06 -04:00
&macro-loop
2021-05-13 17:51:36 -04:00
LDAk ,&keep-going JCN
2021-05-03 14:15:06 -04:00
&error
2021-04-12 16:01:36 -04:00
POP2
2021-05-03 14:15:06 -04:00
JMP2r
&keep-going
2021-05-13 17:51:36 -04:00
DUP2k ;asma-strlen JSR2 #00 SWP #0001 ADD2 ADD2
2021-05-11 14:12:07 -04:00
SWP2 ;asma-assemble-token JSR2 asma-IF-ERROR ,&error JCN
2021-05-03 14:15:06 -04:00
,&macro-loop JMP
2021-04-12 16:01:36 -04:00
2021-04-24 05:50:21 -04:00
&not-macro
2021-04-12 16:01:36 -04:00
POP2
2021-03-31 18:55:02 -04:00
2021-05-03 14:15:06 -04:00
;asma-msg-label ;asma/error STA2
JMP2r
2021-05-15 13:08:08 -04:00
( Error messages )
2021-05-03 14:15:06 -04:00
@asma-msg-hex "Invalid 20 "hexadecimal 00
@asma-msg-zero-page "Address 20 "not 20 "in 20 "zero 20 "page 00
@asma-msg-relative "Address 20 "outside 20 "range 00
@asma-msg-label "Label 20 "not 20 "found 00
@asma-msg-macro "Macro 20 "already 20 "exists 00
@asma-msg-rewound "Memory 20 "overwrite 00
2021-05-03 14:15:06 -04:00
( trees )
( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )
( automatically generated code below )
( see etc/asma.moon for instructions )
2021-05-15 13:08:08 -04:00
( label less greater key binary
than than string data )
2021-05-03 14:15:06 -04:00
@asma-first-char-comment
&_entry $2 $2 ') 00 :asma-comment-end
@asma-first-char-macro
&28 $2 $2 '( 00 :asma-comment-start
&29 :&28 $2 ') 00 :asma-comment-end
&_entry :&29 :&7d '{ 00 :asma-ignore
&7d $2 $2 '} 00 :asma-macro-end
@asma-first-char-normal
&22 $2 $2 '" 00 :asma-raw-word
&23 :&22 $2 '# 00 :asma-literal-hex
&24 :&23 :&25 '$ 00 :asma-pad-relative
&25 $2 $2 '% 00 :asma-macro-define
&26 :&24 :&29 26 00 ( & ) :asma-sublabel-define
&27 $2 $2 '' 00 :asma-raw-char
&28 :&27 $2 '( 00 :asma-comment-start
&29 :&28 :&2c ') 00 :asma-comment-end
&2c $2 $2 ', 00 :asma-literal-rel-addr
&_entry :&26 :&5d '. 00 :asma-literal-zero-addr
&3a $2 $2 ': 00 :asma-abs-addr
&3b :&3a $2 '; 00 :asma-literal-abs-addr
&40 :&3b :&5b '@ 00 :asma-label-define
&5b $2 $2 '[ 00 :asma-ignore
&5d :&40 :&7c '] 00 :asma-ignore
&7b $2 $2 '{ 00 :asma-ignore
&7c :&7b :&7d '| 00 :asma-pad-absolute
&7d $2 $2 '} 00 :asma-ignore
@asma-opcodes
&BRK :&AND :&DEI &_disasm "BRK 00
2021-05-12 18:15:11 -04:00
&_entry :&EQU :&ROT "LIT 00
&NOP :&MUL :&OVR "NOP 00
&POP $2 $2 "POP 00
2021-05-03 14:15:06 -04:00
&DUP :&DIV :&EOR "DUP 00
&SWP $2 $2 "SWP 00
2021-05-12 18:15:11 -04:00
&OVR :&ORA :&POP "OVR 00
&ROT :&NOP :&STR "ROT 00
2021-05-03 14:15:06 -04:00
&EQU :&DEO :&JSR "EQU 00
2021-05-12 18:15:11 -04:00
&NEQ $2 $2 "NEQ 00
2021-05-03 14:15:06 -04:00
&GTH $2 $2 "GTH 00
2021-05-12 18:15:11 -04:00
&LTH $2 $2 "LTH 00
&JMP $2 $2 "JMP 00
&JCN :&GTH :&JMP "JCN 00
&JSR :&JCN :&LDR "JSR 00
&STH $2 $2 "STH 00
&LDZ $2 $2 "LDZ 00
2021-05-11 14:14:52 -04:00
&STZ $2 $2 "STZ 00
2021-05-12 18:15:11 -04:00
&LDR :&LDA :&LDZ "LDR 00
&STR :&STA :&SUB "STR 00
2021-05-03 14:15:06 -04:00
&LDA $2 $2 "LDA 00
2021-05-12 18:15:11 -04:00
&STA :&SFT :&STH "STA 00
2021-05-03 14:15:06 -04:00
&DEI $2 $2 "DEI 00
&DEO :&BRK :&DUP "DEO 00
&ADD $2 $2 "ADD 00
2021-05-12 18:15:11 -04:00
&SUB :&STZ :&SWP "SUB 00
&MUL :&LTH :&NEQ "MUL 00
2021-05-03 14:15:06 -04:00
&DIV $2 $2 "DIV 00
&AND :&ADD $2 "AND 00
2021-05-12 18:15:11 -04:00
&ORA $2 $2 "ORA 00
2021-05-03 14:15:06 -04:00
&EOR $2 $2 "EOR 00
2021-05-12 18:15:11 -04:00
&SFT $2 $2 "SFT 00
2021-05-03 14:15:06 -04:00
2021-05-15 13:08:08 -04:00
(
Heap, a large temporary area for keeping track of labels. More complex
programs need more of this space. If there's insufficient space then the
assembly process will fail, but having extra space above what the most
complex program needs provides no benefit.
This heap, and the buffers below, are free to be used to hold temporary
data between assembly runs, and do not need to be initialized with any
particular contents to use the assembler.
)
2021-05-03 14:15:06 -04:00
@asma-heap
2021-03-31 18:55:02 -04:00
2021-05-15 13:08:08 -04:00
|ff00 &end
(
Buffer for use with loading source code.
The minimum size is the length of the longest token plus one, which is
0x21 to keep the same capability of the C assembler.
Larger sizes are more efficient, provided there is enough
heap space to keep track of all the labels.
)
@asma-read-buffer
|ff80 &end
(
Buffer for use with writing output.
The minimum size is 1, and larger sizes are more efficient.
)
@asma-write-buffer
|ffff &end