mirror of
https://git.sr.ht/~rabbits/uxn
synced 2024-11-01 03:52:39 +00:00
986 lines
23 KiB
Tal
986 lines
23 KiB
Tal
( devices )
|
|
|
|
|00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 &debug $1 &halt $1 ]
|
|
|10 @Console [ &pad $8 &write $1 ]
|
|
|a0 @File [ &vector $2 &success $2 &offset $2 &pad $2 &name $2 &length $2 &load $2 &save $2 ]
|
|
|
|
( vectors )
|
|
|
|
(
|
|
Asma - an in-Uxn assembler
|
|
|
|
This assembler aims to be binary compatible with the output from
|
|
src/uxnasm.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.
|
|
)
|
|
|
|
|0100 @reset
|
|
(
|
|
Set the log level for helping to debug stuff.
|
|
Its value is the bitwise OR of all the following output types:
|
|
#01 prints the number of lines in the source code,
|
|
#04 dumps all defined labels at end, and
|
|
#08 prints the heap usage.
|
|
)
|
|
#09 ;asma/log-level STA
|
|
|
|
(
|
|
Assemble the source code into an output ROM file.
|
|
|
|
If all you want is to use asma.tal to assemble files, insert a BRK
|
|
after this statement.
|
|
)
|
|
;&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
|
|
|
|
&source-file
|
|
"projects/examples/demos/piano.tal 00
|
|
&dest-file
|
|
"bin/asma-boot.rom 00
|
|
|
|
(
|
|
Common macros for use later on.
|
|
)
|
|
|
|
%asma-IF-ERROR { ;asma/error LDA2 ORA }
|
|
|
|
(
|
|
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
|
|
;asma-flush-ignore ;asma/flush-fn STA2
|
|
;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2
|
|
asma-IF-ERROR ,&error JCN
|
|
|
|
;asma-init-next-pass JSR2
|
|
;asma-flush-to-file ;asma/flush-fn STA2
|
|
;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2
|
|
asma-IF-ERROR ,&error JCN
|
|
|
|
;asma-trees/labels ;asma-print-labels JSR2 ( DEBUG )
|
|
;asma-print-line-count JSR2 ( DEBUG )
|
|
;asma-print-heap-usage JSR2 ( DEBUG )
|
|
JMP2r
|
|
|
|
&error
|
|
;asma-print-error JSR2 ( DEBUG )
|
|
JMP2r
|
|
|
|
(
|
|
Debugging routines. These all output extra information to the Console.
|
|
These can be stripped out to save space, once the references to them are
|
|
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
|
|
cleanly.
|
|
)
|
|
|
|
@asma-print-error ( -- )
|
|
;asma/error LDA2 ;asma-print-string JSR2
|
|
#3a .Console/write DEO
|
|
#20 .Console/write DEO
|
|
;asma/orig-token LDA2 ;asma-print-string JSR2
|
|
;&line ;asma-print-string JSR2
|
|
;asma/line LDA2 ;asma-print-short JSR2
|
|
#2e .Console/write DEO
|
|
#0a .Console/write DEO
|
|
JMP2r
|
|
|
|
&line 20 "on 20 "line 20 00
|
|
|
|
@asma-print-line-count ( -- )
|
|
;asma/log-level LDA #01 AND #00 EQU ,&skip JCN
|
|
;asma/line LDA2 ;asma-print-short JSR2
|
|
;&lines ;asma-print-string JSR2
|
|
&skip
|
|
JMP2r
|
|
|
|
&lines [ 20 "lines 20 "of 20 "source 20 "code. 0a 00 ]
|
|
|
|
@asma-print-heap-usage ( -- )
|
|
;asma/log-level LDA #08 AND #00 EQU ,&skip JCN
|
|
;asma/heap LDA2 ;asma-heap SUB2 ;asma-print-short JSR2
|
|
;&str1 ;asma-print-string JSR2
|
|
;asma-heap/end ;asma/heap LDA2 SUB2 ;asma-print-short JSR2
|
|
;&str2 ;asma-print-string JSR2
|
|
&skip
|
|
JMP2r
|
|
|
|
&str1 [ 20 "bytes 20 "of 20 "heap 20 "used, 20 00 ]
|
|
&str2 [ 20 "bytes 20 "free. 0a 00 ]
|
|
|
|
@asma-print-sublabels ( incoming-ptr* -- )
|
|
LDA2
|
|
ORAk ,&valid-incoming-ptr JCN
|
|
POP2 JMP2r
|
|
|
|
&valid-incoming-ptr
|
|
( left node )
|
|
DUP2 ,asma-print-sublabels JSR
|
|
( here )
|
|
#09 .Console/write DEO
|
|
DUP2 #0004 ADD2
|
|
&loop
|
|
DUP2 #0001 ADD2 SWP2 LDA
|
|
DUP #00 EQU ,&end JCN
|
|
.Console/write DEO
|
|
,&loop JMP
|
|
&end
|
|
POP
|
|
#09 .Console/write DEO
|
|
LDA2 ;asma-print-short JSR2
|
|
#0a .Console/write DEO
|
|
|
|
( right node )
|
|
#0002 ADD2 ,asma-print-sublabels JSR
|
|
JMP2r
|
|
|
|
@asma-print-labels ( incoming-ptr* -- )
|
|
;asma/log-level LDA #04 AND #00 EQU ,&skip JCN
|
|
LDA2
|
|
ORAk ,&valid-incoming-ptr JCN
|
|
&skip
|
|
POP2 JMP2r
|
|
|
|
&valid-incoming-ptr
|
|
( left node )
|
|
DUP2 ,asma-print-labels JSR
|
|
( here )
|
|
DUP2 #0004 ADD2
|
|
&loop
|
|
DUP2 #0001 ADD2 SWP2 LDA
|
|
DUP #00 EQU ,&end JCN
|
|
.Console/write DEO
|
|
,&loop JMP
|
|
&end
|
|
POP
|
|
#09 .Console/write DEO
|
|
LDA2k ;asma-print-short JSR2
|
|
#0a .Console/write DEO
|
|
( subtree )
|
|
#0002 ADD2 ;asma-print-sublabels JSR2
|
|
|
|
( right node )
|
|
#0002 ADD2 ,asma-print-labels JSR
|
|
JMP2r
|
|
|
|
@asma-print-string ( ptr* -- )
|
|
LDAk DUP ,&keep-going JCN
|
|
POP POP2 JMP2r
|
|
|
|
&keep-going
|
|
.Console/write DEO
|
|
#0001 ADD2
|
|
,asma-print-string JMP
|
|
|
|
@asma-print-short ( short* -- )
|
|
LIT '0 .Console/write DEO
|
|
LIT 'x .Console/write DEO
|
|
OVR #04 SFT ,&hex JSR
|
|
SWP #0f AND ,&hex JSR
|
|
DUP #04 SFT ,&hex JSR
|
|
#0f AND ,&hex JMP
|
|
|
|
&hex
|
|
#30 ADD DUP #39 GTH #27 MUL ADD .Console/write DEO
|
|
JMP2r
|
|
|
|
(
|
|
Initialise the assembler state before loading a file or chunk.
|
|
)
|
|
|
|
@asma-init-first-pass ( -- )
|
|
#ff ;asma/pass STA
|
|
#0000 DUP2k
|
|
;asma/error STA2
|
|
;asma-trees/labels STA2
|
|
;asma-trees/macros STA2
|
|
;asma-heap ;asma/heap STA2
|
|
;asma-opcodes/_entry ;asma-trees/opcodes STA2
|
|
( fall through )
|
|
|
|
@asma-init-next-pass ( -- )
|
|
;asma/pass LDA #01 ADD ;asma/pass STA
|
|
;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
|
|
JMP2r
|
|
|
|
(
|
|
Divide a file up into chunks, and pass each chunk to asma-assemble-chunk.
|
|
)
|
|
|
|
@asma-assemble-file-pass ( filename-ptr* -- )
|
|
#0000
|
|
|
|
&loop
|
|
OVR2 .File/name DEO2
|
|
DUP2 .File/offset DEO2
|
|
;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
|
|
,asma-assemble-chunk JSR asma-IF-ERROR ,&error JCN
|
|
SUB2 SUB2
|
|
,&loop JMP
|
|
|
|
&last-one
|
|
ADD2k #00 ROT ROT STA
|
|
#0001 ADD2
|
|
,asma-assemble-chunk JSR asma-IF-ERROR ,&error JCN
|
|
|
|
( flush output buffer )
|
|
;asma-output/ptr LDA2 ;asma-write-buffer SUB2 ;asma/flush-fn LDA2 JSR2
|
|
|
|
POP2
|
|
&error
|
|
POP2 POP2 POP2
|
|
JMP2r
|
|
|
|
(
|
|
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.
|
|
)
|
|
|
|
@asma-assemble-chunk ( ptr* len* -- assembled-up-to-ptr* )
|
|
OVR2 ADD2 #0001 SUB2 SWP2 STH2k
|
|
,&loop JMP
|
|
|
|
&next-char-pop
|
|
POP
|
|
&next-char
|
|
#0001 ADD2
|
|
&loop ( last-ptr* ptr* / start-of-token* )
|
|
OVR2 OVR2 LTH2 ,&end JCN
|
|
LDAk ( last-ptr* ptr* char / start-of-token* )
|
|
DUP #20 GTH ,&next-char-pop JCN
|
|
|
|
#00 OVR2 ( last-ptr* ptr* char 00 ptr* / start-of-token* )
|
|
STA
|
|
STH2r ,asma-assemble-token JSR asma-IF-ERROR ,&error JCN
|
|
|
|
#0a NEQ ,¬-newline JCN
|
|
;asma/line LDA2 #0001 ADD2 ;asma/line STA2
|
|
¬-newline
|
|
|
|
DUP2 #0001 ADD2 STH2 ,&next-char JMP
|
|
|
|
&end
|
|
POP2 POP2 STH2r
|
|
JMP2r
|
|
|
|
&error
|
|
POP POP2 POP2
|
|
JMP2r
|
|
|
|
@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 &log-level $1
|
|
]
|
|
@asma-trees [ &labels $2 ¯os $2 &opcodes $2 &scope $2 ]
|
|
|
|
(
|
|
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.
|
|
)
|
|
|
|
@asma-assemble-token ( string-ptr* -- )
|
|
DUP2 ;asma/token STA2
|
|
DUP2 ;asma/orig-token STA2
|
|
LDAk ,¬-empty JCN
|
|
POP2
|
|
JMP2r
|
|
|
|
¬-empty ( token* / )
|
|
( truncate to one char long )
|
|
#0001 ADD2 ( end* / )
|
|
STH2k LDAkr ( end* / end* char )
|
|
STH2k ( end* / end* char end* )
|
|
LITr 00 STH2 ( / end* char end* 00 end* )
|
|
STAr ( / end* char end* )
|
|
|
|
#00 ;asma/state LDA SUBk AND ( tree-offset* / end* )
|
|
DUP2 ;&first-char-trees ADD2 ( tree-offset* incoming-ptr* / end* )
|
|
;asma-traverse-tree JSR2
|
|
|
|
( restore truncated char )
|
|
STAr
|
|
|
|
,¬-found JCN
|
|
|
|
( tree-offset* token-routine-ptr* / end* )
|
|
STH2r ;asma/token STA2
|
|
NIP2 LDA2
|
|
JMP2 ( tail call )
|
|
|
|
¬-found ( tree-offset* dummy* / end* )
|
|
POP2 POP2r
|
|
;&body-routines ADD2 LDA2
|
|
JMP2 ( tail call )
|
|
|
|
&first-char-trees
|
|
:asma-first-char-normal/_entry
|
|
:asma-first-char-comment/_entry
|
|
:asma-first-char-macro/_entry
|
|
|
|
&body-routines
|
|
:asma-normal-body
|
|
:asma-ignore
|
|
:asma-macro-body
|
|
|
|
@asma-parse-hex-digit ( charcode -- 00-0f if valid hex
|
|
OR 10-ff otherwise )
|
|
DUP #3a LTH ,&digit JCN
|
|
DUP #60 GTH ,&letter JCN
|
|
JMP2r
|
|
|
|
&digit
|
|
#30 SUB
|
|
JMP2r
|
|
|
|
&letter
|
|
#57 SUB
|
|
JMP2r
|
|
|
|
@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
|
|
|
|
&loop
|
|
LDAk
|
|
DUP ,¬-end JCN
|
|
POP POP2
|
|
STH2r ROT #01 ADD DUPk ADD ADD
|
|
JMP2r
|
|
|
|
¬-end
|
|
,asma-parse-hex-digit JSR
|
|
DUP #f0 AND ,&fail JCN
|
|
LITr 40 SFT2r
|
|
#00 STH STH ADD2r
|
|
#0001 ADD2
|
|
,&loop JMP
|
|
|
|
&fail
|
|
POP POP2 POP2r
|
|
DUP EOR
|
|
JMP2r
|
|
|
|
@asma-strlen ( string-ptr* -- length )
|
|
LITr 00
|
|
|
|
&loop
|
|
LDAk
|
|
,¬-end JCN
|
|
POP2 STHr
|
|
JMP2r
|
|
|
|
¬-end
|
|
LITr 01 ADDr
|
|
#0001 ADD2
|
|
,&loop JMP
|
|
|
|
%asma-SHORT-FLAG { #20 }
|
|
%asma-RETURN-FLAG { #40 }
|
|
%asma-KEEP-FLAG { #80 }
|
|
|
|
@asma-parse-opcode ( -- byte 00 if valid opcode
|
|
OR 01 otherwise )
|
|
;asma/token LDA2
|
|
DUP2 ,asma-strlen JSR #03 LTH ,&too-short JCN
|
|
|
|
( truncate to three chars long )
|
|
#0003 ADD2 ( end* / )
|
|
STH2k LDAkr ( end* / end* char )
|
|
STH2k ( end* / end* char end* )
|
|
LITr 00 STH2 ( / end* char end* 00 end* )
|
|
STAr ( / end* char end* )
|
|
|
|
;asma-trees/opcodes ;asma-traverse-tree JSR2
|
|
STAr
|
|
,¬-found JCN
|
|
|
|
;asma-opcodes/_disasm SUB2 #03 SFT2 ( 00 byte / end* )
|
|
&loop
|
|
LDAkr STHr LIT2r 0001 ADD2r ( 00 byte char / end* )
|
|
DUP ,¬-end JCN
|
|
POP POP2r
|
|
SWP
|
|
JMP2r
|
|
|
|
¬-end
|
|
DUP LIT '2 NEQ ,¬-two JCN
|
|
POP asma-SHORT-FLAG ORA ,&loop JMP
|
|
|
|
¬-two
|
|
DUP LIT 'r NEQ ,¬-return JCN
|
|
POP asma-RETURN-FLAG ORA ,&loop JMP
|
|
|
|
¬-return
|
|
LIT 'k NEQ ,¬-keep JCN
|
|
asma-KEEP-FLAG ORA ,&loop JMP
|
|
|
|
¬-keep ( 00 byte / end* )
|
|
¬-found ( incoming-ptr* / end* )
|
|
POP2r
|
|
&too-short ( token* / )
|
|
POP2 #01
|
|
JMP2r
|
|
|
|
@asma-write-short ( short -- )
|
|
SWP
|
|
,asma-write-byte JSR
|
|
,asma-write-byte JMP ( tail call )
|
|
|
|
@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
|
|
|
|
&rewound
|
|
;asma-msg-rewound ;asma/error STA2
|
|
POP2 POP2 POP JMP2r
|
|
|
|
&ready
|
|
POP2 #0001 ADD2
|
|
DUP2 ;asma/addr STA2
|
|
;asma/written-addr STA2
|
|
|
|
&write
|
|
,asma-output/ptr LDR2
|
|
DUP2 ;asma-write-buffer/end EQU2 ,&flush JCN
|
|
&after-flush
|
|
STH2k STA
|
|
STH2r #0001 ADD2 ,asma-output/ptr STR2
|
|
JMP2r
|
|
|
|
&flush ( ptr* -- start-of-buffer* )
|
|
;asma-write-buffer SUB2k ( ptr* start* len* )
|
|
;asma/flush-fn LDA2 JSR2
|
|
NIP2 ( start* )
|
|
,&after-flush JMP
|
|
|
|
@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
|
|
|
|
@asma-append-heap-byte ( dummy byte -- dummy )
|
|
;asma/heap LDA2
|
|
OVR2 OVR2 STA POP
|
|
#0001 ADD2 ;asma/heap STA2
|
|
POP
|
|
JMP2r
|
|
|
|
@asma-append-heap-short ( dummy short* -- dummy )
|
|
SWP
|
|
,asma-append-heap-byte JSR
|
|
,asma-append-heap-byte JMP ( tail call )
|
|
|
|
@asma-append-heap-string ( string* -- )
|
|
LDAk
|
|
DUP ,asma-append-heap-byte JSR
|
|
,&keep-going JCN
|
|
POP2 JMP2r
|
|
|
|
&keep-going
|
|
#0001 ADD2
|
|
,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* )
|
|
LDA2k ORA ,&valid-node JCN
|
|
#01 JMP2r
|
|
|
|
&valid-node
|
|
LDA2 STH2k
|
|
#0004 ADD2 ,asma-strcmp-tree JSR
|
|
DUP ,&nomatch JCN
|
|
POP2r JMP2r
|
|
|
|
&nomatch
|
|
#06 SFT #02 AND #00 SWP
|
|
STH2r ADD2
|
|
,&loop JMP
|
|
|
|
( &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
|
|
|
|
&loop ( node-key* / token* )
|
|
DUP2 #0001 ADD2 SWP2 LDA LDAkr STHr
|
|
ORAk ,¬-end JCN
|
|
|
|
( end of C strings, match found )
|
|
POP2r POP
|
|
JMP2r
|
|
|
|
¬-end
|
|
SUB
|
|
DUP ,&nomatch JCN
|
|
POP
|
|
LIT2r 0001 ADD2r
|
|
,&loop JMP
|
|
|
|
&nomatch
|
|
POP2r ROT ROT POP2
|
|
JMP2r
|
|
|
|
(
|
|
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.
|
|
)
|
|
|
|
%asma-STATE-SET { ;asma/state LDA ORA ;asma/state STA }
|
|
%asma-STATE-CLEAR { #ff EOR ;asma/state LDA AND ;asma/state STA }
|
|
|
|
@asma-comment-start
|
|
#02 asma-STATE-SET
|
|
@asma-ignore
|
|
JMP2r
|
|
|
|
@asma-comment-end
|
|
#02 asma-STATE-CLEAR
|
|
JMP2r
|
|
|
|
@asma-macro-define
|
|
;asma/pass LDA ,&ignore-macro JCN
|
|
|
|
;asma-trees/macros ;asma-traverse-tree JSR2 ,¬-exist JCN
|
|
POP2
|
|
;asma-msg-macro ;asma/error STA2
|
|
JMP2r
|
|
|
|
¬-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
|
|
|
|
&ignore-macro
|
|
#0c asma-STATE-SET
|
|
JMP2r
|
|
|
|
@asma-macro-body
|
|
;asma/state LDA #08 AND ,&skip JCN
|
|
;asma/token LDA2 ;asma-append-heap-string JSR2
|
|
&skip
|
|
JMP2r
|
|
|
|
@asma-macro-end
|
|
#00 ;asma-append-heap-byte JSR2
|
|
#0c asma-STATE-CLEAR
|
|
JMP2r
|
|
|
|
@asma-label-define
|
|
;asma-trees/labels ,asma-label-helper JSR
|
|
,&already-existed JCN
|
|
|
|
#0000 ;asma-append-heap-short JSR2 ( data2: subtree incoming ptr )
|
|
|
|
&already-existed
|
|
#0002 ADD2 ;asma-trees/scope STA2
|
|
JMP2r
|
|
|
|
@asma-sublabel-define
|
|
;asma-trees/scope LDA2 ,asma-label-helper JSR
|
|
POP POP2
|
|
JMP2r
|
|
|
|
@asma-label-helper ( incoming-ptr* -- binary-ptr* 00 if label existed already
|
|
OR binary-ptr* 01 if label was created )
|
|
;asma-traverse-tree JSR2
|
|
,&new-label JCN
|
|
|
|
( label already exists )
|
|
( FIXME check label address hasn't changed (label defined twice) )
|
|
#01 JMP2r
|
|
|
|
&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 )
|
|
|
|
;asma/heap LDA2
|
|
|
|
;asma/addr LDA2 ;asma-append-heap-short JSR2 ( data1: address )
|
|
#00 JMP2r
|
|
|
|
@asma-pad-absolute
|
|
#0000 ,asma-pad-helper JMP
|
|
|
|
@asma-pad-relative
|
|
;asma/addr LDA2
|
|
( fall through )
|
|
|
|
@asma-pad-helper ( offset* -- )
|
|
;asma-parse-hex-string JSR2
|
|
,&valid JCN
|
|
|
|
;asma-msg-hex ;asma/error STA2
|
|
JMP2r
|
|
|
|
&valid
|
|
ADD2 ;asma/addr STA2
|
|
JMP2r
|
|
|
|
@asma-raw-char
|
|
;asma/token LDA2 LDA
|
|
;asma-write-byte JMP2 ( tail call )
|
|
|
|
@asma-raw-word
|
|
;asma/token LDA2
|
|
|
|
&loop
|
|
LDAk
|
|
DUP ,¬-end JCN
|
|
|
|
POP POP2
|
|
JMP2r
|
|
|
|
¬-end
|
|
;asma-write-byte JSR2
|
|
#0001 ADD2
|
|
,&loop JMP
|
|
|
|
@asma-literal-abs-addr
|
|
LIT LIT2 ;asma-write-byte JSR2
|
|
( fall through )
|
|
|
|
@asma-abs-addr
|
|
,asma-addr-helper JSR
|
|
;asma-write-short JMP2 ( tail call )
|
|
|
|
@asma-literal-zero-addr
|
|
LIT LIT ;asma-write-byte JSR2
|
|
,asma-addr-helper JSR
|
|
;asma-write-byte JSR2
|
|
|
|
,¬-zero-page JCN
|
|
JMP2r
|
|
|
|
¬-zero-page
|
|
;asma-msg-zero-page ;asma/error STA2
|
|
JMP2r
|
|
|
|
@asma-literal-rel-addr
|
|
LIT LIT ;asma-write-byte JSR2
|
|
,asma-addr-helper JSR ;asma/addr LDA2 SUB2 #0002 SUB2
|
|
|
|
DUP2 #0080 LTH2 STH
|
|
DUP2 #ff7f GTH2 STHr ORA ,&in-bounds JCN
|
|
|
|
POP2
|
|
;asma-msg-relative ;asma/error STA2
|
|
JMP2r
|
|
|
|
&in-bounds
|
|
;asma-write-byte JSR2
|
|
POP
|
|
JMP2r
|
|
|
|
@asma-addr-helper ( -- addr* )
|
|
;asma/token LDA2 LDAk #26 NEQ ,¬-local JCN
|
|
#0001 ADD2 ;asma/token STA2
|
|
;asma-trees/scope LDA2
|
|
,&final-lookup JMP
|
|
|
|
¬-local ( token* )
|
|
LDAk
|
|
DUP ,¬-end JCN
|
|
POP POP2
|
|
;asma-trees/labels
|
|
,&final-lookup JMP
|
|
|
|
¬-end ( token* char )
|
|
#2f EQU ,&found-slash JCN
|
|
#0001 ADD2
|
|
,¬-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 ,¬-found2 JCN
|
|
( token* binary-ptr* )
|
|
#0001 ADD2 ;asma/token STA2
|
|
#0002 ADD2
|
|
|
|
&final-lookup ( addr-offset* incoming-ptr* )
|
|
;asma-traverse-tree JSR2
|
|
,¬-found JCN
|
|
LDA2
|
|
JMP2r
|
|
|
|
¬-found2 ( dummy* dummy* )
|
|
POP2
|
|
¬-found ( dummy* )
|
|
POP2
|
|
|
|
;asma/pass LDA #00 EQU ,&ignore-error JCN
|
|
;asma-msg-label ;asma/error STA2
|
|
&ignore-error
|
|
|
|
;asma/addr LDA2
|
|
JMP2r
|
|
|
|
@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
|
|
|
|
&invalid
|
|
;asma-msg-hex ;asma/error STA2
|
|
JMP2r
|
|
|
|
@asma-byte-helper ( dummy value -- )
|
|
LIT LIT ;asma-write-byte JSR2
|
|
&raw
|
|
;asma-write-byte JSR2
|
|
POP
|
|
JMP2r
|
|
|
|
@asma-short-helper ( value* -- )
|
|
LIT LIT2 ;asma-write-byte JSR2
|
|
&raw
|
|
;asma-write-short JMP2 ( tail call )
|
|
|
|
@asma-normal-body
|
|
;asma-parse-opcode JSR2 ,¬-opcode JCN
|
|
;asma-write-byte JMP2 ( tail call )
|
|
|
|
¬-opcode
|
|
;asma-parse-hex-string JSR2 JMP
|
|
( hex invalid ) ,¬-hex JMP
|
|
( hex byte ) ,asma-byte-helper/raw JMP
|
|
( hex short ) ,asma-short-helper/raw JMP
|
|
|
|
¬-hex
|
|
;asma-trees/macros ;asma-traverse-tree JSR2 ,¬-macro JCN
|
|
|
|
.System/rst DEI #e0 GTH ,&too-deep JCN
|
|
|
|
¯o-loop
|
|
LDAk ,&keep-going JCN
|
|
POP2
|
|
JMP2r
|
|
|
|
&keep-going
|
|
DUP2k ;asma-strlen JSR2 #00 SWP #0001 ADD2 ADD2
|
|
SWP2 ;asma-assemble-token JSR2 asma-IF-ERROR ,&error JCN
|
|
,¯o-loop JMP
|
|
|
|
¬-macro
|
|
;asma-msg-label ;asma/error STA2
|
|
&error
|
|
POP2
|
|
JMP2r
|
|
|
|
&too-deep
|
|
;asma-msg-too-deep ;asma/error STA2
|
|
POP2
|
|
JMP2r
|
|
|
|
( Error messages )
|
|
|
|
@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
|
|
@asma-msg-too-deep "Macro 20 "expansion 20 "level 20 "too 20 "deep 00
|
|
|
|
( trees )
|
|
|
|
( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )
|
|
( automatically generated code below )
|
|
( see etc/asma.moon for instructions )
|
|
|
|
( label less greater key binary
|
|
than than string data )
|
|
|
|
@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
|
|
&_entry :&EQU :&ROT "LIT 00
|
|
&POP $2 $2 "POP 00
|
|
&DUP :&DIV :&EOR "DUP 00
|
|
&NIP :&MUL :&OVR "NIP 00
|
|
&SWP $2 $2 "SWP 00
|
|
&OVR :&ORA :&POP "OVR 00
|
|
&ROT :&NIP :&STR "ROT 00
|
|
&EQU :&DEO :&JSR "EQU 00
|
|
&NEQ $2 $2 "NEQ 00
|
|
>H $2 $2 "GTH 00
|
|
<H $2 $2 "LTH 00
|
|
&JMP $2 $2 "JMP 00
|
|
&JCN :>H :&JMP "JCN 00
|
|
&JSR :&JCN :&LDR "JSR 00
|
|
&STH $2 $2 "STH 00
|
|
&LDZ $2 $2 "LDZ 00
|
|
&STZ $2 $2 "STZ 00
|
|
&LDR :&LDA :&LDZ "LDR 00
|
|
&STR :&STA :&SUB "STR 00
|
|
&LDA $2 $2 "LDA 00
|
|
&STA :&SFT :&STH "STA 00
|
|
&DEI $2 $2 "DEI 00
|
|
&DEO :&BRK :&DUP "DEO 00
|
|
&ADD $2 $2 "ADD 00
|
|
&SUB :&STZ :&SWP "SUB 00
|
|
&MUL :<H :&NEQ "MUL 00
|
|
&DIV $2 $2 "DIV 00
|
|
&AND :&ADD $2 "AND 00
|
|
&ORA $2 $2 "ORA 00
|
|
&EOR $2 $2 "EOR 00
|
|
&SFT $2 $2 "SFT 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.
|
|
)
|
|
|
|
@asma-heap
|
|
|
|
|e000 &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
|
|
|
|
|f800 &end
|
|
|
|
(
|
|
Buffer for use with writing output.
|
|
The minimum size is 1, and larger sizes are more efficient.
|
|
)
|
|
|
|
@asma-write-buffer
|
|
|
|
|ffff &end
|
|
|