uxn

Varvara Ordinator, written in ANSI C(SDL2)
git clone https://git.eamoncaddigan.net/uxn.git
Log | Files | Refs | README | LICENSE

commit 4d6fc067782b105687225d92f84d597f6c2048b3
parent 532c1959dc55f3fd23c841b5fb33123980b20a7d
Author: Andrew Alderwick <andrew@alderwick.co.uk>
Date:   Thu,  7 Oct 2021 21:08:18 +0100

Splitted asma into library and piano demo.

Diffstat:
Aprojects/examples/demos/asma-piano.tal | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aprojects/library/asma.tal | 858+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dprojects/software/asma.tal | 957-------------------------------------------------------------------------------
3 files changed, 959 insertions(+), 957 deletions(-)

diff --git a/projects/examples/demos/asma-piano.tal b/projects/examples/demos/asma-piano.tal @@ -0,0 +1,101 @@ +( 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-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ] + +( vectors ) + +|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. + ) + #0d ;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-ls 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 + +include projects/library/asma.tal + +( + 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 + diff --git a/projects/library/asma.tal b/projects/library/asma.tal @@ -0,0 +1,858 @@ +( + 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. +) + +( + 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 + + ( flush output buffer ) + ;asma-output/ptr LDA2 ;asma-write-buffer SUB2 ;asma/flush-fn LDA2 JSR2 + + ;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 + ;heap LDA2 ;asma-heap SUB2 ;asma-print-short JSR2 + ;&str1 ;asma-print-string JSR2 + ;asma-heap/end ;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 INC2 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 INC2 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 + INC2 + ,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 #3a LTH ,&not-alpha JCN + #27 ADD + &not-alpha + .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 ;heap STA2 + ;asma-opcodes/_entry ;asma-trees/opcodes STA2 + ( fall through ) + +@asma-init-next-pass ( -- ) + ;asma/pass LDA INC ;asma/pass STA + ;asma-write-buffer ;asma-output/ptr STA2 + #0000 DUP2k + ;asma-output/offset STA2 + ;asma/addr STA2 + ;asma/state STA + #01 SWP ( 0100 ) ;asma/written-addr STA2 + ;&preamble-end ;&preamble SUB2k ,asma-assemble-chunk JSR POP2 POP2 + JMP2r + + &preamble + "%BRK 20 '{ 20 "00 20 '} 20 + &preamble-end + +( + Divide a file up into chunks, and pass each chunk to asma-assemble-chunk. +) + +@asma-assemble-file-pass ( filename-ptr* -- ) + ;asma-assemble-chunk #0000 ROT2 ( func* line^ filename* ) + ;asma-read-buffer DUP2 ;asma-read-buffer/end ROT2 SUB2 ( func* line^ filename* buf* size^ ) + ROT2 ( func* line^ buf* size^ filename* ) + ,file-read-chunks JSR + + asma-IF-ERROR ,&error JCN + + &error + POP2 POP2 POP2 POP2 POP2 + JMP2r + +include projects/library/file-read-chunks.tal + +( + 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 ( line^ chunk* len^ -- line^ assembled-up-to-chunk* ) + ROT2 STH2 ( chunk* len^ / line^ ) + OVR2 ADD2 ( chunk* end-chunk* / line^ ) + OVR2 ;asma-read-buffer EQU2 STH + DUP2 ;asma-read-buffer/end NEQ2 + STHr AND ;asma/eof STA + SWP2 STH2k ( end-chunk* chunk* / line^ start-of-token* ) + + &loop ( end-chunk* char* / line^ start-of-token* ) + LDAk #21 LTH ,&whitespace JCN + INC2 ,&loop JMP + + &whitespace ( end-chunk* ws-char* / line^ start-of-token* ) + GTH2k ,&within-chunk JCN + ;asma/eof LDA ,&eof JCN + + ( reached the end of the chunk, start-of-token* is where we assembled up to ) + POP2 POP2 STH2r STH2r SWP2 JMP2r + + &within-chunk ( end-chunk* ws-char* / line^ start-of-token* ) + LDAk #0a NEQ ( end-chunk* ws-char* not-newline / line^ start-of-token* ) + #00 OVR2 STA + STH2r ,asma-assemble-token JSR ( end-chunk* ws-char* not-newline / line^ ) + asma-IF-ERROR ,&error JCN + JMP INC2r ( end-chunk* ws-char* / line^ ) + ;asma/break LDA ,&break JCN + INC2 STH2k ( end-chunk* start-of-token* / line^ start-of-token* ) + ,&loop JMP + + &break ( end-chunk* ws-char* / line^ ) + ( the read buffer has been invalidated, ws-char* plus one is where we assembled up to ) + ;asma/break LDA #01 SUB ;asma/break STA + INC2 NIP2 ( assembled-up-to-ptr* / line^ ) + STH2r SWP2 JMP2r + + &error ( end-chunk* ws-char* not-newline / line^ ) + ( return no progress with assembly to make file-read-chunks exit ) + POP POP2 POP2 + STH2kr ;asma/line STA2 + STH2r ;asma-read-buffer + JMP2r + + &eof ( end-chunk* ws-char* / line^ start-of-token* ) + ( reached the end of file, end-chunk* is safe to write since the buffer is bigger ) + ( return no progress with assembly to make file-read-chunks exit ) + POP2 ( end-chunk* / line^ start-of-token* ) + #00 ROT ROT STA ( / line^ start-of-token* ) + STH2r ,asma-assemble-token JSR ( / line^ ) + STH2r ;asma-read-buffer JMP2r + +@asma [ + &pass $1 &state $1 &line $2 &break $1 &eof $1 + &token $2 &orig-token $2 + &addr $2 &written-addr $2 &flush-fn $2 + &src-filename $2 &dest-filename $2 + &error $2 &log-level $1 +] +@asma-trees [ &labels $2 &macros $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, + 0x08 we are expecting an include filename, and + 0x10 we are in a macro body that we are ignoring + (because the macro was already defined in a previous pass). + Since 0x10 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 ,&not-empty JCN + POP2 + JMP2r + + &not-empty ( token* / ) + ( truncate to one char long ) + INC2 ( 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 + + ,&not-found JCN + + ( tree-offset* token-routine-ptr* / end* ) + STH2r ;asma/token STA2 + NIP2 LDA2 + JMP2 ( tail call ) + + &not-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 + $2 ( invalid position ) + $2 ( empty tree for include ) + + &body-routines + :asma-normal-body + :asma-ignore + :asma-macro-body + $2 ( invalid position ) + :asma-include-filename + +@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 ,strlen JSR #0002 GTH2 ROT ROT + LIT2r 0000 + + &loop + LDAk + DUP ,&not-end JCN + POP POP2 + STH2r ROT INC DUPk ADD ADD + JMP2r + + &not-end + ,asma-parse-hex-digit JSR + DUP #f0 AND ,&fail JCN + LITr 40 SFT2r + #00 STH STH ADD2r + INC2 + ,&loop JMP + + &fail + POP POP2 POP2r + DUP EOR + JMP2r + +%asma-SHORT-FLAG { #20 } +%asma-RETURN-FLAG { #40 } +%asma-KEEP-FLAG { #80 } + +@asma-traverse-tree ( incoming-ptr* -- binary-ptr* 00 if key found + OR node-incoming-ptr* 01 if key not found ) + ;asma/token LDA2 + ( fall through to traverse-tree ) + +include projects/library/binary-tree.tal +include projects/library/string.tal + +@asma-parse-opcode ( -- byte 00 if valid opcode + OR 01 otherwise ) + ;asma/token LDA2 + DUP2 ,strlen JSR #0003 LTH2 ,&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 + ,&not-found JCN + + ;asma-opcodes/_disasm SUB2 #03 SFT2 ( 00 byte / end* ) + &loop + LDAkr STHr LIT2r 0001 ADD2r ( 00 byte char / end* ) + DUP ,&not-end JCN + POP POP2r + DUP ,&not-zero JCN #80 NIP ( LIT by itself needs keep flag, to distinguish from BRK ) + &not-zero + SWP + JMP2r + + &not-end + DUP LIT '2 NEQ ,&not-two JCN + POP asma-SHORT-FLAG ORA ,&loop JMP + + &not-two + DUP LIT 'r NEQ ,&not-return JCN + POP asma-RETURN-FLAG ORA ,&loop JMP + + &not-return + LIT 'k NEQ ,&not-keep JCN + asma-KEEP-FLAG ORA ,&loop JMP + + &not-keep ( 00 byte / end* ) + &not-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 + INC2 + ,&loop JMP + + &rewound + ;asma-msg-rewound ;asma/error STA2 + POP2 POP2 POP JMP2r + + &ready + POP2 INC2 + 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 INC2 ,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-ls DEO2 ADD2 ,asma-output/offset STR2 + ;asma/dest-filename LDA2 .File/name DEO2 + ;asma-write-buffer .File/save DEO2 + JMP2r + +include projects/library/heap.tal + +( + 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 ,&not-exist JCN + POP2 + ;asma-msg-macro ;asma/error STA2 + JMP2r + + &not-exist ( incoming-ptr* ) + ( define macro by creating new node ) + ;heap LDA2 SWP2 STA2 + #0000 ;append-heap-short JSR2 ( less-than pointer ) + #0000 ;append-heap-short JSR2 ( greater-than pointer ) + ;asma/token LDA2 ;append-heap-string JSR2 ( key ) + #04 asma-STATE-SET + JMP2r + + &ignore-macro + #14 asma-STATE-SET + JMP2r + +@asma-macro-body + ;asma/state LDA #10 AND ,&skip JCN + ;asma/token LDA2 ;append-heap-string JSR2 + &skip + JMP2r + +@asma-macro-end + #00 ;append-heap-byte JSR2 + #14 asma-STATE-CLEAR + JMP2r + +@asma-label-define + ;asma-trees/labels ,asma-label-helper JSR + ,&already-existed JCN + + #0000 ;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 ) + ;heap LDA2 SWP2 STA2 + #0000 ;append-heap-short JSR2 ( less-than pointer ) + #0000 ;append-heap-short JSR2 ( greater-than pointer ) + ;asma/token LDA2 ;append-heap-string JSR2 ( key ) + + ;heap LDA2 + + ;asma/addr LDA2 ;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 + POP2 + 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 ,&not-end JCN + + POP POP2 + JMP2r + + &not-end + ;asma-write-byte JSR2 + INC2 + ,&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 + + ,&not-zero-page JCN + JMP2r + + &not-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 ,&not-local JCN + INC2 ;asma/token STA2 + ;asma-trees/scope LDA2 + ,&final-lookup JMP + + &not-local ( token* ) + LDAk + DUP ,&not-end JCN + POP POP2 + ;asma-trees/labels + ,&final-lookup JMP + + &not-end ( token* char ) + #2f EQU ,&found-slash JCN + INC2 + ,&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 + ( token* binary-ptr* ) + INC2 ;asma/token STA2 + #0002 ADD2 + + &final-lookup ( addr-offset* incoming-ptr* ) + ;asma-traverse-tree JSR2 + ,&not-found JCN + LDA2 + JMP2r + + &not-found2 ( dummy* dummy* ) + POP2 + &not-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 ,&not-opcode JCN + ;asma-write-byte JMP2 ( tail call ) + + &not-opcode + ;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 + ;asma-trees/macros ;asma-traverse-tree JSR2 ,&not-macro JCN + + .System/rst DEI #e0 GTH ,&too-deep JCN + + &macro-loop + LDAk ,&keep-going JCN + POP2 + JMP2r + + &keep-going + DUP2k ;strlen JSR2 INC2 ADD2 + SWP2 ;asma-assemble-token JSR2 asma-IF-ERROR ,&error JCN + ,&macro-loop JMP + + &not-macro + POP2 + ;&include-string ;asma/token LDA2 + ;strcmp JSR2 NIP2 NIP2 NIP ,&not-include JCN + #08 asma-STATE-SET + JMP2r + + &not-include + ;asma-msg-label ;asma/error STA2 + &error + JMP2r + + &too-deep + POP2 + ;asma-msg-too-deep ;asma/error STA2 + JMP2r + + &include-string "include 00 + +@asma-include-filename + #08 asma-STATE-CLEAR + ;heap LDA2 + ;asma/token LDA2 ;append-heap-string JSR2 + ;asma-assemble-file-pass JSR2 + ;asma/break LDAk INC ROT ROT STA + 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 + &_entry :&GTH :&ROT &_disasm "LIT 00 + &INC $2 $2 "INC 00 + &POP $2 $2 "POP 00 + &DUP $2 $2 "DUP 00 + &NIP :&MUL :&OVR "NIP 00 + &SWP $2 $2 "SWP 00 + &OVR :&ORA :&POP "OVR 00 + &ROT :&NIP :&STR "ROT 00 + &EQU $2 $2 "EQU 00 + &NEQ $2 $2 "NEQ 00 + &GTH :&DIV :&JSR "GTH 00 + &LTH $2 $2 "LTH 00 + &JMP $2 $2 "JMP 00 + &JCN :&INC :&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 :&AND :&DEO "DEI 00 + &DEO $2 $2 "DEO 00 + &ADD $2 $2 "ADD 00 + &SUB :&STZ :&SWP "SUB 00 + &MUL :&LTH :&NEQ "MUL 00 + &DIV :&DEI :&EOR "DIV 00 + &AND :&ADD $2 "AND 00 + &ORA $2 $2 "ORA 00 + &EOR :&DUP :&EQU "EOR 00 + &SFT $2 $2 "SFT 00 + diff --git a/projects/software/asma.tal b/projects/software/asma.tal @@ -1,957 +0,0 @@ -( 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-hs $2 &offset-ls $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-ls 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 - - ( flush output buffer ) - ;asma-output/ptr LDA2 ;asma-write-buffer SUB2 ;asma/flush-fn LDA2 JSR2 - - ;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 - ;heap LDA2 ;asma-heap SUB2 ;asma-print-short JSR2 - ;&str1 ;asma-print-string JSR2 - ;asma-heap/end ;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 INC2 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 INC2 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 - INC2 - ,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 #3a LTH ,&not-alpha JCN - #27 ADD - &not-alpha - .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 ;heap STA2 - ;asma-opcodes/_entry ;asma-trees/opcodes STA2 - ( fall through ) - -@asma-init-next-pass ( -- ) - ;asma/pass LDA INC ;asma/pass STA - ;asma-write-buffer ;asma-output/ptr STA2 - #0000 DUP2k - ;asma-output/offset STA2 - ;asma/addr STA2 - ;asma/state STA - #01 SWP ( 0100 ) ;asma/written-addr STA2 - ;&preamble-end ;&preamble SUB2k ,asma-assemble-chunk JSR POP2 POP2 - JMP2r - - &preamble - "%BRK 20 '{ 20 "00 20 '} 20 - &preamble-end - -( - Divide a file up into chunks, and pass each chunk to asma-assemble-chunk. -) - -@asma-assemble-file-pass ( filename-ptr* -- ) - ;asma-assemble-chunk #0000 ROT2 ( func* line^ filename* ) - ;asma-read-buffer DUP2 ;asma-read-buffer/end ROT2 SUB2 ( func* line^ filename* buf* size^ ) - ROT2 ( func* line^ buf* size^ filename* ) - ,file-read-chunks JSR - - asma-IF-ERROR ,&error JCN - - &error - POP2 POP2 POP2 POP2 POP2 - JMP2r - -include projects/library/file-read-chunks.tal - -( - 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 ( line^ chunk* len^ -- line^ assembled-up-to-chunk* ) - ROT2 STH2 ( chunk* len^ / line^ ) - OVR2 ADD2 ( chunk* end-chunk* / line^ ) - OVR2 ;asma-read-buffer EQU2 STH - DUP2 ;asma-read-buffer/end NEQ2 - STHr AND ;asma/eof STA - SWP2 STH2k ( end-chunk* chunk* / line^ start-of-token* ) - - &loop ( end-chunk* char* / line^ start-of-token* ) - LDAk #21 LTH ,&whitespace JCN - INC2 ,&loop JMP - - &whitespace ( end-chunk* ws-char* / line^ start-of-token* ) - GTH2k ,&within-chunk JCN - ;asma/eof LDA ,&eof JCN - - ( reached the end of the chunk, start-of-token* is where we assembled up to ) - POP2 POP2 STH2r STH2r SWP2 JMP2r - - &within-chunk ( end-chunk* ws-char* / line^ start-of-token* ) - LDAk #0a NEQ ( end-chunk* ws-char* not-newline / line^ start-of-token* ) - #00 OVR2 STA - STH2r ,asma-assemble-token JSR ( end-chunk* ws-char* not-newline / line^ ) - asma-IF-ERROR ,&error JCN - JMP INC2r ( end-chunk* ws-char* / line^ ) - ;asma/break LDA ,&break JCN - INC2 STH2k ( end-chunk* start-of-token* / line^ start-of-token* ) - ,&loop JMP - - &break ( end-chunk* ws-char* / line^ ) - ( the read buffer has been invalidated, ws-char* plus one is where we assembled up to ) - ;asma/break LDA #01 SUB ;asma/break STA - INC2 NIP2 ( assembled-up-to-ptr* / line^ ) - STH2r SWP2 JMP2r - - &error ( end-chunk* ws-char* not-newline / line^ ) - ( return no progress with assembly to make file-read-chunks exit ) - POP POP2 POP2 - STH2kr ;asma/line STA2 - STH2r ;asma-read-buffer - JMP2r - - &eof ( end-chunk* ws-char* / line^ start-of-token* ) - ( reached the end of file, end-chunk* is safe to write since the buffer is bigger ) - ( return no progress with assembly to make file-read-chunks exit ) - POP2 ( end-chunk* / line^ start-of-token* ) - #00 ROT ROT STA ( / line^ start-of-token* ) - STH2r ,asma-assemble-token JSR ( / line^ ) - STH2r ;asma-read-buffer JMP2r - -@asma [ - &pass $1 &state $1 &line $2 &break $1 &eof $1 - &token $2 &orig-token $2 - &addr $2 &written-addr $2 &flush-fn $2 - &src-filename $2 &dest-filename $2 - &error $2 &log-level $1 -] -@asma-trees [ &labels $2 &macros $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, - 0x08 we are expecting an include filename, and - 0x10 we are in a macro body that we are ignoring - (because the macro was already defined in a previous pass). - Since 0x10 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 ,&not-empty JCN - POP2 - JMP2r - - &not-empty ( token* / ) - ( truncate to one char long ) - INC2 ( 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 - - ,&not-found JCN - - ( tree-offset* token-routine-ptr* / end* ) - STH2r ;asma/token STA2 - NIP2 LDA2 - JMP2 ( tail call ) - - &not-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 - $2 ( invalid position ) - $2 ( empty tree for include ) - - &body-routines - :asma-normal-body - :asma-ignore - :asma-macro-body - $2 ( invalid position ) - :asma-include-filename - -@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 ,strlen JSR #0002 GTH2 ROT ROT - LIT2r 0000 - - &loop - LDAk - DUP ,&not-end JCN - POP POP2 - STH2r ROT INC DUPk ADD ADD - JMP2r - - &not-end - ,asma-parse-hex-digit JSR - DUP #f0 AND ,&fail JCN - LITr 40 SFT2r - #00 STH STH ADD2r - INC2 - ,&loop JMP - - &fail - POP POP2 POP2r - DUP EOR - JMP2r - -%asma-SHORT-FLAG { #20 } -%asma-RETURN-FLAG { #40 } -%asma-KEEP-FLAG { #80 } - -@asma-traverse-tree ( incoming-ptr* -- binary-ptr* 00 if key found - OR node-incoming-ptr* 01 if key not found ) - ;asma/token LDA2 - ( fall through to traverse-tree ) - -include projects/library/binary-tree.tal -include projects/library/string.tal - -@asma-parse-opcode ( -- byte 00 if valid opcode - OR 01 otherwise ) - ;asma/token LDA2 - DUP2 ,strlen JSR #0003 LTH2 ,&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 - ,&not-found JCN - - ;asma-opcodes/_disasm SUB2 #03 SFT2 ( 00 byte / end* ) - &loop - LDAkr STHr LIT2r 0001 ADD2r ( 00 byte char / end* ) - DUP ,&not-end JCN - POP POP2r - DUP ,&not-zero JCN #80 NIP ( LIT by itself needs keep flag, to distinguish from BRK ) - &not-zero - SWP - JMP2r - - &not-end - DUP LIT '2 NEQ ,&not-two JCN - POP asma-SHORT-FLAG ORA ,&loop JMP - - &not-two - DUP LIT 'r NEQ ,&not-return JCN - POP asma-RETURN-FLAG ORA ,&loop JMP - - &not-return - LIT 'k NEQ ,&not-keep JCN - asma-KEEP-FLAG ORA ,&loop JMP - - &not-keep ( 00 byte / end* ) - &not-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 - INC2 - ,&loop JMP - - &rewound - ;asma-msg-rewound ;asma/error STA2 - POP2 POP2 POP JMP2r - - &ready - POP2 INC2 - 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 INC2 ,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-ls DEO2 ADD2 ,asma-output/offset STR2 - ;asma/dest-filename LDA2 .File/name DEO2 - ;asma-write-buffer .File/save DEO2 - JMP2r - -include projects/library/heap.tal - -( - 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 ,&not-exist JCN - POP2 - ;asma-msg-macro ;asma/error STA2 - JMP2r - - &not-exist ( incoming-ptr* ) - ( define macro by creating new node ) - ;heap LDA2 SWP2 STA2 - #0000 ;append-heap-short JSR2 ( less-than pointer ) - #0000 ;append-heap-short JSR2 ( greater-than pointer ) - ;asma/token LDA2 ;append-heap-string JSR2 ( key ) - #04 asma-STATE-SET - JMP2r - - &ignore-macro - #14 asma-STATE-SET - JMP2r - -@asma-macro-body - ;asma/state LDA #10 AND ,&skip JCN - ;asma/token LDA2 ;append-heap-string JSR2 - &skip - JMP2r - -@asma-macro-end - #00 ;append-heap-byte JSR2 - #14 asma-STATE-CLEAR - JMP2r - -@asma-label-define - ;asma-trees/labels ,asma-label-helper JSR - ,&already-existed JCN - - #0000 ;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 ) - ;heap LDA2 SWP2 STA2 - #0000 ;append-heap-short JSR2 ( less-than pointer ) - #0000 ;append-heap-short JSR2 ( greater-than pointer ) - ;asma/token LDA2 ;append-heap-string JSR2 ( key ) - - ;heap LDA2 - - ;asma/addr LDA2 ;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 - POP2 - 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 ,&not-end JCN - - POP POP2 - JMP2r - - &not-end - ;asma-write-byte JSR2 - INC2 - ,&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 - - ,&not-zero-page JCN - JMP2r - - &not-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 ,&not-local JCN - INC2 ;asma/token STA2 - ;asma-trees/scope LDA2 - ,&final-lookup JMP - - &not-local ( token* ) - LDAk - DUP ,&not-end JCN - POP POP2 - ;asma-trees/labels - ,&final-lookup JMP - - &not-end ( token* char ) - #2f EQU ,&found-slash JCN - INC2 - ,&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 - ( token* binary-ptr* ) - INC2 ;asma/token STA2 - #0002 ADD2 - - &final-lookup ( addr-offset* incoming-ptr* ) - ;asma-traverse-tree JSR2 - ,&not-found JCN - LDA2 - JMP2r - - &not-found2 ( dummy* dummy* ) - POP2 - &not-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 ,&not-opcode JCN - ;asma-write-byte JMP2 ( tail call ) - - &not-opcode - ;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 - ;asma-trees/macros ;asma-traverse-tree JSR2 ,&not-macro JCN - - .System/rst DEI #e0 GTH ,&too-deep JCN - - &macro-loop - LDAk ,&keep-going JCN - POP2 - JMP2r - - &keep-going - DUP2k ;strlen JSR2 INC2 ADD2 - SWP2 ;asma-assemble-token JSR2 asma-IF-ERROR ,&error JCN - ,&macro-loop JMP - - &not-macro - POP2 - ;&include-string ;asma/token LDA2 - ;strcmp JSR2 NIP2 NIP2 NIP ,&not-include JCN - #08 asma-STATE-SET - JMP2r - - &not-include - ;asma-msg-label ;asma/error STA2 - &error - JMP2r - - &too-deep - POP2 - ;asma-msg-too-deep ;asma/error STA2 - JMP2r - - &include-string "include 00 - -@asma-include-filename - #08 asma-STATE-CLEAR - ;heap LDA2 - ;asma/token LDA2 ;append-heap-string JSR2 - ;asma-assemble-file-pass JSR2 - ;asma/break LDAk INC ROT ROT STA - 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 - &_entry :&GTH :&ROT &_disasm "LIT 00 - &INC $2 $2 "INC 00 - &POP $2 $2 "POP 00 - &DUP $2 $2 "DUP 00 - &NIP :&MUL :&OVR "NIP 00 - &SWP $2 $2 "SWP 00 - &OVR :&ORA :&POP "OVR 00 - &ROT :&NIP :&STR "ROT 00 - &EQU $2 $2 "EQU 00 - &NEQ $2 $2 "NEQ 00 - &GTH :&DIV :&JSR "GTH 00 - &LTH $2 $2 "LTH 00 - &JMP $2 $2 "JMP 00 - &JCN :&INC :&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 :&AND :&DEO "DEI 00 - &DEO $2 $2 "DEO 00 - &ADD $2 $2 "ADD 00 - &SUB :&STZ :&SWP "SUB 00 - &MUL :&LTH :&NEQ "MUL 00 - &DIV :&DEI :&EOR "DIV 00 - &AND :&ADD $2 "AND 00 - &ORA $2 $2 "ORA 00 - &EOR :&DUP :&EQU "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 -