0
0
Fork 0
mirror of https://git.sr.ht/~rabbits/uxn synced 2024-11-27 08:13:01 +00:00
uxn/projects/library/asma.tal

963 lines
24 KiB
Tal
Raw Normal View History

(
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.
)
2021-05-15 18:58:50 +00: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* -- )
2021-11-05 22:48:04 +00:00
#01 .File/append DEO
DUP2 .File/name DEO2
#01 .File/delete DEO
2021-05-15 18:58:50 +00:00
;asma/dest-filename STA2 ;asma/src-filename STA2
;asma-init-first-pass JSR2
2021-05-15 20:02:33 +00:00
;asma-flush-ignore ;asma/flush-fn STA2
2021-05-15 18:58:50 +00:00
;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2
2022-11-20 22:50:19 +00:00
;asma/error LDA2 ORA ,&error JCN
2021-05-15 18:58:50 +00:00
;asma-init-next-pass JSR2
2021-05-15 20:02:33 +00:00
;asma-flush-to-file ;asma/flush-fn STA2
;asma/dest-filename LDA2 ORA ,&filename-present JCN
;asma-flush-to-console ;asma/flush-fn STA2
&filename-present
2021-05-15 18:58:50 +00:00
;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2
2022-11-20 22:50:19 +00:00
;asma/error LDA2 ORA ,&error JCN
2021-05-15 18:58:50 +00:00
2021-10-06 05:14:18 +00:00
( flush output buffer )
;asma-output/ptr LDA2 ;asma-write-buffer SUB2 ;asma/flush-fn LDA2 JSR2
2021-05-15 18:58:50 +00:00
;asma-trees/labels ;asma-print-labels JSR2 ( DEBUG )
2021-05-16 08:27:06 +00:00
;asma-print-line-count JSR2 ( DEBUG )
;asma-print-heap-usage JSR2 ( DEBUG )
2021-05-15 18:58:50 +00:00
JMP2r
&error
;asma-print-error JSR2 ( DEBUG )
JMP2r
2021-05-15 17:08:08 +00: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 18:58:50 +00: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 17:08:08 +00:00
cleanly.
)
2021-05-15 18:58:50 +00:00
@asma-print-error ( -- )
.File/name DEI2 ;asma-print-string JSR2
;&line ;asma-print-string JSR2
;asma/line LDA2 ;asma-print-short JSR2
#3a .Console/error DEO
#20 .Console/error DEO
;asma/error LDA2 ;asma-print-string JSR2
2021-10-07 20:57:54 +00:00
#3a .Console/error DEO
#20 .Console/error DEO
;asma/orig-token LDA2 ;asma-print-string JSR2
2021-10-07 20:57:54 +00:00
#2e .Console/error DEO
#0a .Console/error DEO
2021-05-16 09:20:04 +00:00
JMP2r
2021-05-15 18:58:50 +00:00
&line 20 "line 20 00
2021-05-15 18:58:50 +00:00
2021-05-16 08:27:06 +00:00
@asma-print-line-count ( -- )
;asma/log-level LDA #01 AND #00 EQU ,&skip JCN
2021-10-07 20:58:54 +00:00
;asma/lines LDA2 ;asma-print-short JSR2
;&lines ;asma-print-string JSR2
&skip
2021-05-15 18:58:50 +00:00
JMP2r
2021-05-16 08:27:06 +00:00
&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
2021-10-06 05:42:19 +00:00
;heap LDA2 ;asma-heap SUB2 ;asma-print-short JSR2
;&str1 ;asma-print-string JSR2
2021-10-06 05:42:19 +00:00
;asma-heap/end ;heap LDA2 SUB2 ;asma-print-short JSR2
;&str2 ;asma-print-string JSR2
&skip
2021-05-16 08:27:06 +00:00
JMP2r
&str1 [ 20 "bytes 20 "of 20 "heap 20 "used, 20 00 ]
&str2 [ 20 "bytes 20 "free. 0a 00 ]
2021-05-15 18:58:50 +00:00
@asma-print-sublabels ( incoming-ptr* -- )
2021-05-14 07:09:55 +00:00
LDA2
ORAk ,&valid-incoming-ptr JCN
POP2 JMP2r
&valid-incoming-ptr
( left node )
2021-05-15 18:58:50 +00:00
DUP2 ,asma-print-sublabels JSR
2021-05-14 07:09:55 +00:00
( here )
2021-10-07 20:57:54 +00:00
#09 .Console/error DEO
2021-05-14 07:09:55 +00:00
DUP2 #0004 ADD2
&loop
2021-08-26 22:27:18 +00:00
DUP2 INC2 SWP2 LDA
2021-05-14 07:09:55 +00:00
DUP #00 EQU ,&end JCN
2021-10-07 20:57:54 +00:00
.Console/error DEO
2021-05-14 07:09:55 +00:00
,&loop JMP
&end
POP
2021-10-07 20:57:54 +00:00
#09 .Console/error DEO
LDA2 ;asma-print-short JSR2
2021-10-07 20:57:54 +00:00
#0a .Console/error DEO
2021-05-14 07:09:55 +00:00
( right node )
2021-05-15 18:58:50 +00:00
#0002 ADD2 ,asma-print-sublabels JSR
2021-05-14 07:09:55 +00:00
JMP2r
2021-05-15 18:58:50 +00:00
@asma-print-labels ( incoming-ptr* -- )
;asma/log-level LDA #04 AND #00 EQU ,&skip JCN
2021-05-14 07:09:55 +00:00
LDA2
ORAk ,&valid-incoming-ptr JCN
&skip
2021-05-14 07:09:55 +00:00
POP2 JMP2r
&valid-incoming-ptr
( left node )
2021-05-15 18:58:50 +00:00
DUP2 ,asma-print-labels JSR
2021-05-14 07:09:55 +00:00
( here )
DUP2 #0004 ADD2
2022-08-14 19:06:23 +00:00
LDAk LIT "A LTH ,&loop JCN
LDAk LIT "Z GTH ,&loop JCN
POP2
,&skip-device-label JMP
2021-05-14 07:09:55 +00:00
&loop
2021-08-26 22:27:18 +00:00
DUP2 INC2 SWP2 LDA
2021-05-14 07:09:55 +00:00
DUP #00 EQU ,&end JCN
2021-10-07 20:57:54 +00:00
.Console/error DEO
2021-05-14 07:09:55 +00:00
,&loop JMP
&end
POP
2021-10-07 20:57:54 +00:00
#09 .Console/error DEO
LDA2k ;asma-print-short JSR2
2021-10-07 20:57:54 +00:00
#0a .Console/error DEO
2021-05-14 07:09:55 +00:00
( subtree )
2021-05-15 18:58:50 +00:00
#0002 ADD2 ;asma-print-sublabels JSR2
2021-05-14 07:09:55 +00:00
&skip-device-label
2021-05-14 07:09:55 +00:00
( right node )
2021-05-15 18:58:50 +00:00
#0002 ADD2 ,asma-print-labels JSR
2021-05-14 07:09:55 +00:00
JMP2r
@asma-print-string ( ptr* -- )
LDAk DUP ,&keep-going JCN
POP POP2 JMP2r
&keep-going
2021-10-07 20:57:54 +00:00
.Console/error DEO
2021-08-26 22:27:18 +00:00
INC2
,asma-print-string JMP
@asma-print-short ( short* -- )
2022-08-14 19:06:23 +00:00
LIT "0 .Console/error DEO
LIT "x .Console/error 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
2021-10-07 20:57:54 +00:00
.Console/error DEO
JMP2r
2021-05-15 18:58:50 +00:00
(
Initialise the assembler state before loading a file or chunk.
)
2021-05-03 18:15:06 +00:00
2021-05-15 18:58:50 +00:00
@asma-init-first-pass ( -- )
2021-11-22 07:05:07 +00:00
LIT2 POP2 POP EOR ;asma-parse-opcode/short-flag STA
LIT2 POPr POP EOR ;asma-parse-opcode/return-flag STA
LIT2 POPk POP EOR ;asma-parse-opcode/keep-flag STA
2021-05-15 18:58:50 +00:00
#ff ;asma/pass STA
2021-05-15 20:02:33 +00:00
#0000 DUP2k
;asma/error STA2
;asma-trees/labels STA2
;asma-trees/macros STA2
2021-05-15 18:58:50 +00:00
;asma-opcodes/_entry ;asma-trees/opcodes STA2
( fall through )
2021-05-14 07:09:55 +00:00
2021-05-15 18:58:50 +00:00
@asma-init-next-pass ( -- )
2021-08-26 22:27:18 +00:00
;asma/pass LDA INC ;asma/pass STA
2021-05-15 20:02:33 +00:00
;asma-write-buffer ;asma-output/ptr STA2
2023-01-14 19:46:54 +00:00
#0100 DUP2 DUP ( 0100 0100 00 )
2021-05-15 20:02:33 +00:00
;asma/state STA
2023-01-14 19:46:54 +00:00
;asma/addr STA2
2022-06-07 23:53:14 +00:00
;asma/written-addr STA2
;&preamble-end ;&preamble SUB2k ;asma-assemble-chunk JSR2 POP2 POP2
2021-05-15 18:58:50 +00:00
JMP2r
2021-05-03 18:15:06 +00:00
2021-08-18 06:33:53 +00:00
&preamble
2022-08-15 16:28:02 +00:00
"%BRK 20 "{ 20 "00 20 "} 20
"%[ 20 "{ 20 "} 20
"%] 20 "{ 20 "} 20
"@on-reset 20
2021-08-18 06:33:53 +00:00
&preamble-end
2021-05-15 18:58:50 +00:00
(
Divide a file up into chunks, and pass each chunk to asma-assemble-chunk.
)
2021-05-03 18:15:06 +00:00
@asma-assemble-file-pass ( filename-ptr* -- )
;asma-assemble-chunk #0000 ROT2 ( func* line^ filename* )
2021-10-04 21:28:13 +00:00
;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
2021-04-18 11:48:49 +00:00
2022-11-20 22:50:19 +00:00
;asma/error LDA2 ORA ,&error JCN
2021-05-15 20:02:33 +00:00
&error
2021-10-04 21:28:13 +00:00
POP2 POP2 POP2 POP2 POP2
JMP2r
@file-read-chunks ( func* udata* buf* size* filename* -- func* udata'* buf* size* filename* )
#0000 DUP2 ( F* U* B* SZ* FN* OL* OH* / )
&resume
ROT2 STH2 ( F* U* B* SZ* OL* OH* / FN* )
ROT2 ( F* U* B* OL* OH* SZ* / FN* )
&loop
STH2kr .File/name DEO2 ( F* U* B* OL* OH* SZ* / FN* )
STH2k ,ffwd/length STR2 ( F* U* B* OL* OH* / FN* SZ* )
STH2 ( F* U* B* OL* / FN* SZ* OH* )
STH2k ,ffwd/offset STR2 ( F* U* B* / FN* SZ* OH* OL* )
DUP2 ,ffwd/addr STR2
,ffwd JSR
SWP2 ( F* B* U* / FN* SZ* OH* OL* )
ROT2k NIP2 ( F* B* U* B* F* / FN* SZ* OH* OL* )
OVR2 .File/read DEO2 ( F* B* U* B* F* / FN* SZ* OH* OL* )
.File/success DEI2 SWP2 ( F* B* U* B* length* F* / FN* SZ* OH* OL* )
JSR2 ( F* B* U'* done-up-to* / FN* SZ* OH* OL* )
ROT2 SWP2 ( F* U'* B* done-up-to* / FN* SZ* OH* OL* )
SUB2k NIP2 ( F* U'* B* -done-length* / FN* SZ* OH* OL* )
ORAk ,&not-end JCN ( F* U'* B* -done-length* / FN* SZ* OH* OL* )
POP2 POP2r POP2r ( F* U'* B* / FN* SZ* )
STH2r STH2r ( F* U'* B* SZ* FN* / )
JMP2r
&not-end
STH2r SWP2 ( F* U'* B* OL* -done-length* / FN* SZ* OH* )
LTH2k JMP INC2r ( F* U'* B* OL* -done-length* / FN* SZ* OH'* )
SUB2 ( F* U'* B* OL'* / FN* SZ* OH'* )
STH2r STH2r ( F* U'* B* OL'* OH'* SZ* / FN* )
,&loop JMP
@ffwd
LIT2 &length $2
LIT2 &offset $2
&coarse ( length* offset* )
GTH2k ,&fine JCN
OVR2 .File/length DEO2
,&addr LDR2 .File/read DEO2
OVR2 SUB2
,&coarse JMP
&fine ( length* offset* )
.File/length DEO2 ( length* )
,&addr LDR2 .File/read DEO2
.File/length DEO2 ( )
JMP2r
&addr $2
2021-10-04 21:28:13 +00:00
2021-05-15 18:58:50 +00: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 20:01:36 +00:00
2021-10-06 05:14:18 +00:00
@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^ )
2022-11-20 22:50:19 +00:00
;asma/error LDA2 ORA ,&error JCN
2021-10-07 20:58:54 +00:00
,&not-newline JCN
,asma/lines LDR2 INC2 ,asma/lines STR2
&not-newline ( end-chunk* ws-char* / line^ )
2021-10-06 05:14:18 +00:00
;asma/break LDA ,&break JCN
INC2 STH2k ( end-chunk* start-of-token* / line^ start-of-token* )
2021-10-04 21:28:13 +00:00
,&loop JMP
2021-04-12 20:01:36 +00:00
2021-10-06 05:14:18 +00:00
&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
2021-03-31 22:55:02 +00:00
&error ( end-chunk* ws-char* not-newline / line^ )
2021-10-06 05:14:18 +00:00
( return no progress with assembly to make file-read-chunks exit )
POP POP2 POP2
STH2kr ;asma/line STA2
STH2r ;asma-read-buffer
2021-03-31 22:55:02 +00:00
JMP2r
2021-10-06 05:14:18 +00:00
&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 [
2021-10-07 20:58:54 +00:00
&pass $1 &state $1 &line $2 &lines $2 &break $1 &eof $1
2021-12-29 11:59:20 +00:00
&comment-level $1
&token $2 &orig-token $2
2021-10-06 05:42:19 +00:00
&addr $2 &written-addr $2 &flush-fn $2
&src-filename $2 &dest-filename $2
&error $2 &log-level $1
]
2021-05-03 18:15:06 +00:00
@asma-trees [ &labels $2 &macros $2 &opcodes $2 &scope $2 ]
2021-03-31 22:55:02 +00:00
2021-05-15 17:08:08 +00:00
(
The main routine to assemble a single token.
asma/state contains several meaningful bits:
0x02 we are in a comment,
2021-10-06 05:14:18 +00:00
0x04 we are in a macro body,
2022-11-20 22:50:19 +00:00
0x08 we are in a macro body that we are ignoring
2021-05-15 17:08:08 +00:00
(because the macro was already defined in a previous pass).
2022-11-20 22:50:19 +00:00
Since 0x08 never appears without 0x04, the lowest bit set in asma/state is
2021-05-15 17:08:08 +00:00
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 18:15:06 +00:00
@asma-assemble-token ( string-ptr* -- )
DUP2 ;asma/token STA2
DUP2 ;asma/orig-token STA2
2021-05-13 21:51:36 +00:00
LDAk ,&not-empty JCN
2021-05-03 18:15:06 +00:00
POP2
2021-03-31 22:55:02 +00:00
JMP2r
2021-05-03 18:15:06 +00:00
&not-empty ( token* / )
( truncate to one char long )
2021-08-26 22:27:18 +00:00
INC2 ( end* / )
2021-05-13 21:51:36 +00:00
STH2k LDAkr ( end* / end* char )
STH2k ( end* / end* char end* )
2021-05-03 18:15:06 +00:00
LITr 00 STH2 ( / end* char end* 00 end* )
STAr ( / end* char end* )
2021-03-31 22:55:02 +00:00
2021-05-13 21:51:36 +00:00
#00 ;asma/state LDA SUBk AND ( tree-offset* / end* )
2021-05-03 18:15:06 +00:00
DUP2 ;&first-char-trees ADD2 ( tree-offset* incoming-ptr* / end* )
;asma-traverse-tree JSR2
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
( restore truncated char )
STAr
2021-03-31 22:55:02 +00:00
2021-05-11 18:12:07 +00:00
,&not-found JCN
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
( tree-offset* token-routine-ptr* / end* )
STH2r ;asma/token STA2
2021-08-15 20:25:58 +00:00
NIP2 LDA2
2021-05-03 18:15:06 +00:00
JMP2 ( tail call )
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
&not-found ( tree-offset* dummy* / end* )
POP2 POP2r
2021-05-15 17:08:08 +00:00
;&body-routines ADD2 LDA2
2021-05-03 18:15:06 +00:00
JMP2 ( tail call )
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
&first-char-trees
:asma-first-char-normal/_entry
:asma-first-char-comment/_entry
:asma-first-char-macro/_entry
2021-03-31 22:55:02 +00:00
2021-05-15 17:08:08 +00:00
&body-routines
2021-05-03 18:15:06 +00:00
:asma-normal-body
:asma-ignore
:asma-macro-body
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
@asma-parse-hex-digit ( charcode -- 00-0f if valid hex
OR 10-ff otherwise )
2021-05-11 18:12:07 +00:00
DUP #3a LTH ,&digit JCN
DUP #60 GTH ,&letter JCN
2021-05-03 18:15:06 +00:00
JMP2r
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
&digit
#30 SUB
JMP2r
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
&letter
#57 SUB
2021-03-31 22:55:02 +00:00
JMP2r
@asma-parse-hex-string ( strict -- value* 06 if valid hex and (length == 4 or (length == 3 and not strict))
OR value* 03 if valid hex and (length == 2 or (length == 1 and not strict))
OR 00 otherwise )
STH
;asma/token LDA2 DUP2 ,strlen JSR ( token* length^ )
DUP STHr AND ,&fail2 JCN
DUP2 #0004 GTH2 ,&fail2 JCN
ORAk #00 EQU ,&fail2 JCN
#0002 GTH2 ROT ROT
2021-05-03 18:15:06 +00:00
LIT2r 0000
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
&loop
2021-05-13 21:51:36 +00:00
LDAk
2021-05-11 18:12:07 +00:00
DUP ,&not-end JCN
2021-05-03 18:15:06 +00:00
POP POP2
2021-08-26 22:27:18 +00:00
STH2r ROT INC DUPk ADD ADD
2021-03-31 22:55:02 +00:00
JMP2r
2021-04-24 09:50:21 +00:00
&not-end
2021-05-03 18:15:06 +00:00
,asma-parse-hex-digit JSR
2021-05-11 18:12:07 +00:00
DUP #f0 AND ,&fail JCN
2021-05-24 21:52:11 +00:00
LITr 40 SFT2r
LITr 00 STH ADD2r
2021-08-26 22:27:18 +00:00
INC2
2021-04-24 09:50:21 +00:00
,&loop JMP
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
&fail
POP2r
&fail2
POP2 POP2
#00
2021-04-11 08:40:26 +00:00
JMP2r
~projects/library/string.tal
2021-10-06 05:54:03 +00:00
@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 )
~projects/library/binary-tree.tal
2021-10-06 05:54:03 +00:00
2021-05-03 18:15:06 +00:00
@asma-parse-opcode ( -- byte 00 if valid opcode
OR 01 otherwise )
;asma/token LDA2
2021-10-06 05:54:03 +00:00
DUP2 ,strlen JSR #0003 LTH2 ,&too-short JCN
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
( truncate to three chars long )
#0003 ADD2 ( end* / )
2021-05-13 21:51:36 +00:00
STH2k LDAkr ( end* / end* char )
STH2k ( end* / end* char end* )
2021-05-03 18:15:06 +00:00
LITr 00 STH2 ( / end* char end* 00 end* )
STAr ( / end* char end* )
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
;asma-trees/opcodes ;asma-traverse-tree JSR2
STAr
2021-05-11 18:12:07 +00:00
,&not-found JCN
2021-04-14 21:00:10 +00:00
;asma-opcodes/_disasm SUB2 #03 SFT2 ( 00 byte / end* )
2021-10-29 23:28:33 +00:00
DUP #00 EQU ,&set-keep JCN ( force keep flag for LIT )
2021-05-03 18:15:06 +00:00
&loop
2021-05-13 21:51:36 +00:00
LDAkr STHr LIT2r 0001 ADD2r ( 00 byte char / end* )
2021-05-11 18:12:07 +00:00
DUP ,&not-end JCN
2021-05-03 18:15:06 +00:00
POP POP2r
SWP
2021-04-11 08:40:26 +00:00
JMP2r
2021-05-03 18:15:06 +00:00
&not-end
2022-08-14 19:06:23 +00:00
DUP LIT "2 NEQ ,&not-two JCN
2021-11-22 07:05:07 +00:00
POP LIT &short-flag $1 ORA ,&loop JMP
2021-04-11 22:45:31 +00:00
2021-05-03 18:15:06 +00:00
&not-two
2022-08-14 19:06:23 +00:00
DUP LIT "r NEQ ,&not-return JCN
2021-11-22 07:05:07 +00:00
POP LIT &return-flag $1 ORA ,&loop JMP
2021-04-24 09:50:21 +00:00
2021-05-12 22:51:34 +00:00
&not-return
2022-08-14 19:06:23 +00:00
LIT "k NEQ ,&not-keep JCN
2021-11-22 07:05:07 +00:00
&set-keep LIT &keep-flag $1 ORA ,&loop JMP
2021-05-12 22:51:34 +00:00
&not-keep ( 00 byte / end* )
2021-05-03 18:15:06 +00:00
&not-found ( incoming-ptr* / end* )
POP2r
&too-short ( token* / )
POP2 #01
2021-04-11 22:45:31 +00:00
JMP2r
2021-11-28 01:29:39 +00:00
@asma-write-lit ( byte -- )
LIT LIT ,asma-write-byte JSR
,asma-write-byte JSR
2021-11-28 01:29:39 +00:00
JMP2r
2022-06-07 23:38:55 +00:00
@asma-advance-addr ( delta* -- )
;asma/addr LDA2k ( delta* ptr* value* )
ROT2 ADD2 ( ptr* new-value* )
SWP2 STA2
JMP2r
2022-06-07 23:53:14 +00:00
@asma-write-short ( short -- )
SWP
,asma-write-byte JSR
( fall through )
2021-05-03 18:15:06 +00:00
@asma-write-byte ( byte -- )
;asma/addr LDA2 ;asma/written-addr LDA2
LTH2k ,&rewound JCN
&loop
EQU2k ,&ready JCN
#00 ,&write JSR
2021-08-26 22:27:18 +00:00
INC2
,&loop JMP
2021-05-15 20:02:33 +00:00
&rewound
;asma-msg-rewound ;asma/error STA2
POP2 POP2 POP JMP2r
&ready
2021-08-26 22:27:18 +00:00
POP2 INC2
DUP2 ;asma/addr STA2
;asma/written-addr STA2
&write
2021-05-15 20:02:33 +00:00
,asma-output/ptr LDR2
DUP2 ;asma-write-buffer/end EQU2 ,&flush JCN
&after-flush
STH2k STA
2021-08-26 22:27:18 +00:00
STH2r INC2 ,asma-output/ptr STR2
2021-04-11 22:45:31 +00:00
JMP2r
2021-05-15 20:02:33 +00:00
&flush ( ptr* -- start-of-buffer* )
;asma-write-buffer SUB2k ( ptr* start* len* )
;asma/flush-fn LDA2 JSR2
2021-08-15 20:25:58 +00:00
NIP2 ( start* )
2021-05-15 20:02:33 +00:00
,&after-flush JMP
@asma-output [ &ptr $2 ]
2021-05-15 20:02:33 +00:00
@asma-flush-ignore ( len* -- )
POP2
JMP2r
@asma-flush-to-file ( len* -- )
.File/length DEO2
2021-05-15 20:02:33 +00:00
;asma/dest-filename LDA2 .File/name DEO2
2021-11-07 19:10:30 +00:00
;asma-write-buffer .File/write DEO2
2021-05-15 20:02:33 +00:00
JMP2r
2021-04-11 22:45:31 +00:00
@asma-flush-to-console ( len* -- )
ORAk ,&not-empty JCN
POP2 JMP2r
&not-empty
;asma-write-buffer DUP2 ROT2 ADD2 SWP2 ( end* ptr* )
&loop ( end* ptr* )
LDAk .Console/write DEO
INC2
GTH2k ,&loop JCN
POP2 POP2
JMP2r
~projects/library/heap.tal
2021-05-03 18:15:06 +00:00
2021-05-15 17:08:08 +00: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 08:40:26 +00:00
2021-12-29 11:59:20 +00:00
@asma-comment-more
;asma/token LDA2 ;strlen JSR2 ORA ,asma-ignore JCN
2021-05-03 18:15:06 +00:00
@asma-comment-start
2021-12-29 11:59:20 +00:00
;asma/comment-level LDAk INC ROT ROT STA
2022-11-20 22:50:19 +00:00
;asma/state LDA #02 ORA ;asma/state STA
2021-05-03 18:15:06 +00:00
@asma-ignore
JMP2r
2021-04-24 09:50:21 +00:00
2021-12-29 11:59:20 +00:00
@asma-comment-less
;asma/token LDA2 ;strlen JSR2 ORA ,asma-ignore JCN
;asma/comment-level LDAk #01 SUB DUP SWP2 STA ,asma-ignore JCN
2021-05-03 18:15:06 +00:00
@asma-comment-end
2022-11-20 22:50:19 +00:00
;asma/state LDA #0c AND ;asma/state STA
2021-05-03 18:15:06 +00:00
JMP2r
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
@asma-macro-define
2021-05-11 18:12:07 +00:00
;asma/pass LDA ,&ignore-macro JCN
2021-04-11 08:40:26 +00:00
2021-05-11 18:12:07 +00:00
;asma-trees/macros ;asma-traverse-tree JSR2 ,&not-exist JCN
2021-05-03 18:15:06 +00:00
POP2
;asma-msg-macro ;asma/error STA2
JMP2r
2021-04-24 09:50:21 +00:00
2021-10-06 05:42:19 +00:00
&not-exist ( incoming-ptr* )
2021-05-03 18:15:06 +00:00
( define macro by creating new node )
2021-10-06 05:42:19 +00:00
;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 )
2022-11-20 22:50:19 +00:00
;asma/state LDA #04 ORA ;asma/state STA
2021-05-03 18:15:06 +00:00
JMP2r
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
&ignore-macro
2022-11-20 22:50:19 +00:00
;asma/state LDA #0c ORA ;asma/state STA
2021-05-03 18:15:06 +00:00
JMP2r
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
@asma-macro-body
2022-11-20 22:50:19 +00:00
;asma/state LDA #08 AND ,&skip JCN
2021-10-06 05:42:19 +00:00
;asma/token LDA2 ;append-heap-string JSR2
2021-05-15 17:08:08 +00:00
&skip
2021-04-11 08:40:26 +00:00
JMP2r
2021-05-03 18:15:06 +00:00
@asma-macro-end
2021-10-06 05:42:19 +00:00
#00 ;append-heap-byte JSR2
2022-11-20 22:50:19 +00:00
;asma/state LDA #02 AND ;asma/state STA
2021-05-03 18:15:06 +00:00
JMP2r
2021-04-24 09:50:21 +00:00
2021-05-03 18:15:06 +00:00
@asma-label-define
;asma-trees/labels ,asma-label-helper JSR
2021-05-11 18:12:07 +00:00
,&already-existed JCN
2021-04-11 08:40:26 +00:00
2021-10-06 05:42:19 +00:00
#0000 ;append-heap-short JSR2 ( data2: subtree incoming ptr )
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
&already-existed
#0002 ADD2 ;asma-trees/scope STA2
JMP2r
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
@asma-sublabel-define
;asma-trees/scope LDA2 ,asma-label-helper JSR
POP POP2
JMP2r
2021-04-11 08:40:26 +00:00
2021-10-20 16:35:06 +00:00
@asma-label-helper ( incoming-ptr* -- binary-ptr* 01 if label existed already
OR binary-ptr* 00 if label was created )
2021-05-03 18:15:06 +00:00
;asma-traverse-tree JSR2
2021-05-11 18:12:07 +00:00
,&new-label JCN
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
( label already exists )
LDA2k ;asma/addr LDA2 EQU2 ,&address-match JCN
;asma-msg-redefined ;asma/error STA2
&address-match
2021-05-03 18:15:06 +00:00
#01 JMP2r
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
&new-label ( incoming-ptr* )
( define label by creating new node )
2021-10-06 05:42:19 +00:00
;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 )
2021-04-11 08:40:26 +00:00
2021-10-06 05:42:19 +00:00
;heap LDA2
2021-04-24 09:50:21 +00:00
2021-10-06 05:42:19 +00:00
;asma/addr LDA2 ;append-heap-short JSR2 ( data1: address )
2021-05-03 18:15:06 +00:00
#00 JMP2r
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
@asma-pad-absolute
2022-06-07 23:38:55 +00:00
#0000 ;asma/addr STA2
2021-05-03 18:15:06 +00:00
( fall through )
2021-04-11 08:40:26 +00:00
@asma-pad-relative
#00 ;asma-parse-hex-string JSR2
2021-05-11 18:12:07 +00:00
,&valid JCN
2021-04-11 08:40:26 +00:00
2021-05-14 07:09:55 +00:00
;asma-msg-hex ;asma/error STA2
2021-04-11 08:40:26 +00:00
JMP2r
2021-05-03 18:15:06 +00:00
&valid
2022-06-07 23:38:55 +00:00
;asma-advance-addr JMP2 ( tail call )
2021-04-11 22:45:31 +00:00
2021-05-03 18:15:06 +00:00
@asma-raw-word
;asma/token LDA2
2021-04-11 22:45:31 +00:00
2021-04-24 09:50:21 +00:00
&loop
2021-05-13 21:51:36 +00:00
LDAk
2021-05-11 18:12:07 +00:00
DUP ,&not-end JCN
2021-05-03 18:15:06 +00:00
POP POP2
2021-04-11 22:45:31 +00:00
JMP2r
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
&not-end
;asma-write-byte JSR2
2021-08-26 22:27:18 +00:00
INC2
2021-05-03 18:15:06 +00:00
,&loop JMP
@asma-literal-abs-addr
LIT LIT2 ;asma-write-byte JSR2
( fall through )
2021-04-24 09:50:21 +00:00
2021-05-03 18:15:06 +00:00
@asma-abs-addr
,asma-addr-helper JSR
;asma-write-short JMP2 ( tail call )
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
@asma-literal-zero-addr
2022-11-10 21:59:14 +00:00
LIT LIT ;asma-write-byte JSR2
( fall through )
@asma-zero-addr
2021-05-03 18:15:06 +00:00
,asma-addr-helper JSR
2022-11-10 21:59:14 +00:00
;asma-write-byte JSR2
2021-04-11 08:40:26 +00:00
2021-05-11 18:12:07 +00:00
,&not-zero-page JCN
2021-04-11 08:40:26 +00:00
JMP2r
2021-05-03 18:15:06 +00:00
&not-zero-page
;asma/pass LDA #00 EQU
;asma/error LDA2 ORA
ORA ,&ignore-error JCN
2021-05-03 18:15:06 +00:00
;asma-msg-zero-page ;asma/error STA2
&ignore-error
2021-04-11 08:40:26 +00:00
JMP2r
@asma-jci
#20 ,asma-jxi JMP ( tail call )
@asma-jmi
#40
( fall through )
@asma-jxi
;asma-write-byte JSR2
,asma-addr-helper JSR
;asma/addr LDA2 SUB2
#0002 SUB2
;asma-write-short JMP2 ( tail call )
2021-05-03 18:15:06 +00:00
@asma-literal-rel-addr
2022-11-11 08:55:44 +00:00
LIT LIT ;asma-write-byte JSR2
( fall through )
@asma-rel-addr
2021-11-28 17:45:02 +00:00
,asma-addr-helper JSR
;asma/addr LDA2 SUB2
2022-11-11 08:55:44 +00:00
#0002 SUB2
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
DUP2 #0080 LTH2 STH
2021-05-11 18:12:07 +00:00
DUP2 #ff7f GTH2 STHr ORA ,&in-bounds JCN
2021-04-11 08:40:26 +00:00
POP2
2021-05-03 18:15:06 +00:00
;asma-msg-relative ;asma/error STA2
2021-04-11 08:40:26 +00:00
JMP2r
2021-05-03 18:15:06 +00:00
&in-bounds
2022-11-11 08:55:44 +00:00
;asma-write-byte JSR2
2021-05-03 18:15:06 +00:00
POP
2021-04-11 08:40:26 +00:00
JMP2r
2021-05-03 18:15:06 +00:00
@asma-addr-helper ( -- addr* )
2021-05-13 21:51:36 +00:00
;asma/token LDA2 LDAk #26 NEQ ,&not-local JCN
2021-08-26 22:27:18 +00:00
INC2 ;asma/token STA2
;asma-trees/scope LDA2
2021-05-03 18:15:06 +00:00
,&final-lookup JMP
&not-local ( token* )
2021-05-13 21:51:36 +00:00
LDAk
2021-05-11 18:12:07 +00:00
DUP ,&not-end JCN
2021-05-03 18:15:06 +00:00
POP POP2
;asma-trees/labels
2021-05-03 18:15:06 +00:00
,&final-lookup JMP
&not-end ( token* char )
2021-05-11 18:12:07 +00:00
#2f EQU ,&found-slash JCN
2021-08-26 22:27:18 +00:00
INC2
2021-05-03 18:15:06 +00:00
,&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 18:15:06 +00:00
( token* binary-ptr* )
2021-08-26 22:27:18 +00:00
INC2 ;asma/token STA2
#0002 ADD2
2021-04-11 08:40:26 +00:00
2021-05-03 18:15:06 +00:00
&final-lookup ( addr-offset* incoming-ptr* )
;asma-traverse-tree JSR2
,&not-found JCN
LDA2
2021-04-11 08:40:26 +00:00
JMP2r
&not-found2 ( dummy* dummy* )
POP2
&not-found ( dummy* )
POP2
2021-05-03 18:15:06 +00:00
2021-05-11 18:12:07 +00:00
;asma/pass LDA #00 EQU ,&ignore-error JCN
2021-05-03 18:15:06 +00:00
;asma-msg-label ;asma/error STA2
&ignore-error
;asma/addr LDA2
2021-04-11 08:40:26 +00:00
JMP2r
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
@asma-literal-hex
#01 ;asma-parse-hex-string JSR2 JMP
2021-05-03 18:15:06 +00:00
( hex invalid ) ,&invalid JMP
( hex byte ) ,asma-byte-helper JMP
( hex short ) ,asma-short-helper JMP
2021-03-31 22:55:02 +00:00
2021-05-03 18:15:06 +00:00
&invalid
;asma-msg-hex ;asma/error STA2
JMP2r
@asma-byte-helper ( dummy value -- )
2021-11-28 01:29:39 +00:00
;asma-write-lit JSR2
POP
JMP2r
2021-05-03 18:15:06 +00:00
&raw
;asma-write-byte JSR2
2021-04-12 20:01:36 +00:00
POP
JMP2r
2021-05-03 18:15:06 +00:00
@asma-short-helper ( value* -- )
LIT LIT2 ;asma-write-byte JSR2
&raw
;asma-write-short JMP2 ( tail call )
@asma-normal-body
2021-05-11 18:12:07 +00:00
;asma-parse-opcode JSR2 ,&not-opcode JCN
2021-05-03 18:15:06 +00:00
;asma-write-byte JMP2 ( tail call )
2021-04-24 09:50:21 +00:00
&not-opcode
#01 ;asma-parse-hex-string JSR2 JMP
2021-05-03 18:15:06 +00:00
( 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
2021-05-03 18:15:06 +00:00
&macro-loop
2021-05-13 21:51:36 +00:00
LDAk ,&keep-going JCN
2021-04-12 20:01:36 +00:00
POP2
2021-05-03 18:15:06 +00:00
JMP2r
&keep-going
2021-10-06 05:54:03 +00:00
DUP2k ;strlen JSR2 INC2 ADD2
2022-11-20 22:50:19 +00:00
SWP2 ;asma-assemble-token JSR2 ;asma/error LDA2 ORA ,&macro-error JCN
2021-05-03 18:15:06 +00:00
,&macro-loop JMP
2021-04-12 20:01:36 +00:00
&macro-error
POP2
JMP2r
2021-04-24 09:50:21 +00:00
&not-macro
2021-10-06 05:14:18 +00:00
POP2
#60 ;asma-jxi JMP2 ( tail call )
2021-03-31 22:55:02 +00:00
@asma-include
2021-10-06 05:42:19 +00:00
;heap LDA2
;asma/token LDA2 ;append-heap-string JSR2
2021-10-06 05:14:18 +00:00
;asma-assemble-file-pass JSR2
;asma/break LDAk INC ROT ROT STA
2021-05-03 18:15:06 +00:00
JMP2r
2021-05-15 17:08:08 +00:00
( Error messages )
2021-05-03 18:15:06 +00: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
@asma-msg-redefined "Label 20 "redefined 00
2021-05-03 18:15:06 +00:00
( trees )
( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )
( automatically generated code below )
( see etc/asma.moon for instructions )
2021-05-15 17:08:08 +00:00
( label less greater key binary
than than string data )
2021-05-03 18:15:06 +00:00
@asma-first-char-comment
2022-08-15 16:28:02 +00:00
&28 $2 $2 "( 00 :asma-comment-more
&_entry :&28 $2 ") 00 :asma-comment-less
2021-05-03 18:15:06 +00:00
@asma-first-char-macro
2022-08-15 16:28:02 +00:00
&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
2021-05-03 18:15:06 +00:00
@asma-first-char-normal
&21 $2 $2 "! 00 :asma-jmi
&22 :&21 $2 "" 00 :asma-raw-word
2023-01-14 21:13:18 +00:00
&23 :&22 :&25 "# 00 :asma-literal-hex
&24 $2 $2 "$ 00 :asma-pad-relative
&25 :&24 $2 "% 00 :asma-macro-define
&26 :&23 :&2c 26 00 ( & ) :asma-sublabel-define
&28 $2 $2 "( 00 :asma-comment-start
2022-11-10 23:47:14 +00:00
&29 :&28 $2 ") 00 :asma-comment-end
&2c :&29 :&2d ", 00 :asma-literal-rel-addr
2022-11-10 21:59:14 +00:00
&2d $2 $2 "- 00 :asma-zero-addr
2022-11-11 08:55:44 +00:00
&_entry :&26 :&5f ". 00 :asma-literal-zero-addr
2022-08-15 16:28:02 +00:00
&3a $2 $2 ": 00 :asma-abs-addr
2022-11-10 23:47:14 +00:00
&3b :&3a $2 "; 00 :asma-literal-abs-addr
&3d :&3b :&40 "= 00 :asma-abs-addr
&3f $2 $2 "? 00 :asma-jci
&40 :&3f $2 "@ 00 :asma-label-define
2022-11-11 08:55:44 +00:00
&5f :&3d :&7d "_ 00 :asma-rel-addr
&7b $2 $2 "{ 00 :asma-ignore
&7c :&7b $2 "| 00 :asma-pad-absolute
2022-08-15 16:28:02 +00:00
&7d :&7c :&7e "} 00 :asma-ignore
&7e $2 $2 "~ 00 :asma-include
2021-05-03 18:15:06 +00:00
@asma-opcodes
2021-08-18 06:33:53 +00:00
&_entry :&GTH :&ROT &_disasm "LIT 00
&INC $2 $2 "INC 00
2021-05-12 22:15:11 +00:00
&POP $2 $2 "POP 00
2021-08-15 20:34:33 +00:00
&NIP :&MUL :&OVR "NIP 00
2021-05-03 18:15:06 +00:00
&SWP $2 $2 "SWP 00
2021-08-15 20:22:01 +00:00
&ROT :&NIP :&STR "ROT 00
2022-04-18 08:45:33 +00:00
&DUP $2 $2 "DUP 00
&OVR :&ORA :&POP "OVR 00
2021-08-18 06:33:53 +00:00
&EQU $2 $2 "EQU 00
2021-05-12 22:15:11 +00:00
&NEQ $2 $2 "NEQ 00
2021-08-18 06:33:53 +00:00
&GTH :&DIV :&JSR "GTH 00
2021-05-12 22:15:11 +00:00
&LTH $2 $2 "LTH 00
&JMP $2 $2 "JMP 00
2021-08-18 06:33:53 +00:00
&JCN :&INC :&JMP "JCN 00
2021-05-12 22:15:11 +00:00
&JSR :&JCN :&LDR "JSR 00
&STH $2 $2 "STH 00
&LDZ $2 $2 "LDZ 00
2021-05-11 18:14:52 +00:00
&STZ $2 $2 "STZ 00
2021-05-12 22:15:11 +00:00
&LDR :&LDA :&LDZ "LDR 00
&STR :&STA :&SUB "STR 00
2021-05-03 18:15:06 +00:00
&LDA $2 $2 "LDA 00
2021-05-12 22:15:11 +00:00
&STA :&SFT :&STH "STA 00
2021-08-18 06:33:53 +00:00
&DEI :&AND :&DEO "DEI 00
&DEO $2 $2 "DEO 00
2021-05-03 18:15:06 +00:00
&ADD $2 $2 "ADD 00
2021-05-12 22:15:11 +00:00
&SUB :&STZ :&SWP "SUB 00
&MUL :&LTH :&NEQ "MUL 00
2021-08-18 06:33:53 +00:00
&DIV :&DEI :&EOR "DIV 00
2021-05-03 18:15:06 +00:00
&AND :&ADD $2 "AND 00
2021-05-12 22:15:11 +00:00
&ORA $2 $2 "ORA 00
2021-08-18 06:33:53 +00:00
&EOR :&DUP :&EQU "EOR 00
2021-05-12 22:15:11 +00:00
&SFT $2 $2 "SFT 00
2021-05-03 18:15:06 +00:00