diff --git a/femto.tal b/femto.tal index a35523c..50703ca 100644 --- a/femto.tal +++ b/femto.tal @@ -22,10 +22,10 @@ %cr { #0d18 DEO } %crlf { cr nl } %ansi { #1b18 DEO #5b18 DEO } -%alternate-buffer-on { ( \e[?1049h ) - ansi #3f18 DEO #3118 DEO #3018 DEO #3418 DEO #3918 DEO #6818 DEO } -%alternate-buffer-off { ( \e[?1049l ) - ansi #3f18 DEO #3118 DEO #3018 DEO #3418 DEO #3918 DEO #6c18 DEO } +( \e[?1049h ) +%alternate-buffer-on { ansi #3f18 DEO #3118 DEO #3018 DEO #3418 DEO #3918 DEO #6818 DEO } +( \e[?1049l ) +%alternate-buffer-off { ansi #3f18 DEO #3118 DEO #3018 DEO #3418 DEO #3918 DEO #6c18 DEO } ( emit macros ) ( ) @@ -732,6 +732,7 @@ ( execute a search, using the given search string ) @do-search ( -> ) + ;tmp LDA ?{ !return } ( ensure non-empty search string ) .cursor/row LDZ2 .searching/orig-row STZ2 .cursor/col LDZ2 .searching/orig-col STZ2 #0000 .searching/regex STZ2 @@ -752,6 +753,7 @@ ( ) ( TODO: handle invalid regular expressions that fail to compile ) @do-regex-search ( -> ) + ;tmp LDA ?{ !return } ( ensure non-empty search string ) cur-pos DUP2 .searching/start STZ2 .searching/end STZ2 .cursor/row LDZ2 .searching/orig-row STZ2 .cursor/col LDZ2 .searching/orig-col STZ2 diff --git a/tar.tal b/tar.tal index b031b15..ac0356e 100644 --- a/tar.tal +++ b/tar.tal @@ -10,7 +10,6 @@ ( - handle 'L' entries ) ( - support creating archives ) ( - arg validation should depend on mode ) -( - validate checksums ) ( - better error messages on unsupported files, e.g. symlinks ) ( - better usage message ) ( - support using "-" for stdin/stdout? ) @@ -28,24 +27,33 @@ @panic ( -> $exit ) #010e DEO #010f DEO BRK +@print-usage ( -> ) + ;usage1 print ;usage2 !print + ( handle all provided command-line arguments ) @arg-callback ( -> ) ;arg/count LDA - DUP #00 EQU ?&missing-mode - DUP #01 EQU ?&missing-file - #02 GTH ?&toomany !run - &missing-mode ;missing-mode !&error - &missing-file ;missing-filename !&error - &toomany ;too-many-arguments - &error print ;usage print #01 !exit + DUP #00 GTH ?{ POP ;missing-mode !handle-error } + DUP #01 GTH ?{ POP ;missing-filename !handle-error } + POP !run + +@error-toomany ( -> BRK ) + ;too-many-arguments !handle-error + +@error-noinput ( -> BRK ) + ;no-input-arguments !handle-error + +@handle-error ( ;msg -> BRK ) + print print-usage #01 !exit ( run the program ) @run ( -> BRK ) #01 arg/read .File1/name DEO2 #00 arg/read LDA - DUP LIT "t NEQ ?{ list-entries #00 !exit } - DUP LIT "x NEQ ?{ expand-entries #00 !exit } - POP ;invalid-mode print ;usage print #00 !exit + DUP LIT "c NEQ ?{ POP create-archive #00 !exit } + DUP LIT "t NEQ ?{ POP list-entries #00 !exit } + DUP LIT "x NEQ ?{ POP expand-entries #00 !exit } + POP ;invalid-mode print print-usage #00 !exit ( exit normally ) @exit ( code^ -> BRK ) @@ -67,20 +75,72 @@ LDAk #18 DEO INC2 GTH2k ?&loop ( limit* s+1* ) &done POP2 POP2 JMP2r ( ) +@print-filename ( -> ) + ;header/filename sanitize-path #0064 lprint #0a18 DEO JMP2r + +@print-long ( hi* lo* -> ) + dump-long #0a18 DEO JMP2r + ( read 512 bytes of header for the next tar entry. ) ( assumes .File1/name is already set. ) @read-header ( -> ok^ ) #0200 .File1/len DEO2 ;header .File1/r DEO2 - ( TODO validate checksum ) .File1/ok DEI2 #0200 EQU2 JMP2r +@validate-checksum ( -> ok^ ) + ;header/checksum load-octal6 ( chi* clo* ) + STH2k SWP2 STH2k SWP2 ( chi* clo* [clo* chi*] ) + ;u-sum compute-sum ( chi* clo* uhi* ulo* [clo* chi*] ) + u32-eq ?&ok1 ( [clo* chi*] ) + STH2r STH2r ;s-sum compute-sum ( chi* clo* shi* slo* ) + u32-eq ?&ok2 ( ) + ;invalid-checksum print ( ; error message ) + print-filename ( ; filename of affected entry ) + ;expected print ( ; "expected: " ) + ;header/checksum load-octal6 print-long ( ; expected checksum ) + ;found print ( ; "found: " ) + ;u-sum compute-sum print-long ( ; found checksum ) + #00 JMP2r ( 0^ ) + &ok1 POP2r POP2r &ok2 #01 JMP2r ( 1^ ) + +( maximum checksum is 0001fe00 but in practice ) +( almost all checksums will fit in 16-bits ) +@compute-sum ( fn* -> sum0* sum1* ) + STH2 ;header/checksum ;header STH2kr JSR2 ( n0* [fn*] ) + #0100 ADD2 ;uheader/end ;header/type STH2r JSR2 ( n1* n2* ) + OVR2 ADD2 GTH2k #00 SWP ( n1* sum* carry* ) + ROT2 POP2 SWP2 JMP2r ( carry* sum* ) + +@u32-eq ( xhi* xlo* yhi* ylo* -> bool^ ) + ROT2 EQU2 STH EQU2 STHr AND JMP2r + +( return 16-bit checksum ) +( technically it should be 17-bit. for simplicity we'll ) +( just check the lower 16-bits. ) +@u-sum ( limit* start* -> sum* ) + LIT2r 0000 ( limit* start* [sum*] ) + &loop LDAk LITr 00 STH ( limit* start* [sum* n*] ) + ADD2r INC2 GTH2k ?&loop ( limit* pos+1* [sum+n*] ) + POP2 POP2 STH2r JMP2r ( sum* ) + +( similar to unsigned-sum but treats 8-bit ascii differently ) +( mostly only used for compatibility with old tar files ) +@s-sum ( limit* start* -> sum* ) + LIT2r 0000 ( limit* start* [sum*] ) + &loop LDAk ( limit* start* c^ [sum*] ) + DUP #07 SFT #ff MUL SWP STH2 ( limit* start* [sum* n*] ) + ADD2r INC2 GTH2k ?&loop ( limit* pos+1* [sum+n*] ) + POP2 POP2 STH2r JMP2r ( sum* ) + ( list all the entries in the tar archive ) @list-entries ( -> ) + ;arg/count LDA #02 GTH ?error-toomany read-header ?{ JMP2r } ;header/filename LDA ?&non-null #800f DEO BRK &non-null + validate-checksum ( ) ;header/type LDA ( type^ ) DUP #00 EQU ?list-file ( type^ ) DUP LIT "0 EQU ?list-file ( type^ ) @@ -104,8 +164,7 @@ ;unsupported print #18 DEO #2018 DEO ;header/size load-octal11 dump-longer #2018 DEO - ;header/filename sanitize-path - #0064 lprint #0a18 DEO + print-filename ;header/size load-octal11 round-up-to-512 skip !list-entries ( verbose file entry listing ) @@ -113,7 +172,7 @@ POP LIT "f #18 DEO #2018 DEO ;header/size load-octal11 dump-longer #2018 DEO - ;header/filename #0064 lprint #0a18 DEO + print-filename ;header/size load-octal11 round-up-to-512 skip !list-entries ( verbose directory entry listing ) @@ -121,11 +180,12 @@ POP LIT "d #18 DEO #2018 DEO ;header/size load-octal11 dump-longer #2018 DEO - ;header/filename #0064 lprint #0a18 DEO + print-filename !list-entries ( expand a .tar archive in the current working directory ) @expand-entries ( -> ) + ;arg/count LDA #02 GTH ?error-toomany read-header ?{ JMP2r } ;header/filename LDA ?&non-null #800f DEO BRK @@ -146,16 +206,14 @@ @expand-file ( type^ -> ) POP - ;header/filename sanitize-path - DUP2 #0064 lprint #0a18 DEO + print-filename .File2/name DEO2 ;header/size load-octal11 STH2k write STH2r remainder-512 skip-lo !expand-entries @expand-dir ( type^ -> ) POP - ;header/filename sanitize-path - DUP2 #0064 lprint #0a18 DEO + print-filename .File2/name DEO2 #0004 .File2/len DEO2 #0001 .File2/w DEO2 @@ -164,13 +222,130 @@ @expand-unsupported ( type^ -> ) ;unsupported print #18 DEO LIT2 ": 18 DEO #2018 DEO - ;header/filename sanitize-path - #0064 lprint #0a18 DEO + print-filename ;header/size load-octal11 round-up-to-512 skip !expand-entries -( src and dst should be paths ) -@compress-entries ( src* dst* -> ) - POP2 POP2 JMP2r +@create-archive ( -> ) + ;arg/count LDA #03 LTH ?error-noinput + validate-inputs ?{ print-usage #01 !exit } + ( ; we know that all input files exist ) + #01 arg/read DUP2 path-exists ?&dest-exists + + .File1/name DEO2 + #00 .File1/append DEO + ;arg/count LDA #02 + &loop DUP arg/read archive-path INC GTHk ?&loop + POP2 JMP2r + + &dest-exists ;destination-exists print + print #0a18 DEO print-usage #01 !exit + +@validate-inputs ( -> ok^ ) + ;arg/count LDA #02 LITr 01 ( count^ 2^ [1^] ) + &loop DUP validate-input ( count^ i^ ok1^ [ok0^] ) + STH ANDr INC GTHk ?&loop ( count^ i+1^ [ok2^] ) + POP2 STHr JMP2r ( ok^ ) + +@validate-input ( i^ -> ok^ ) + arg/read DUP2 path-exists ?&ok1 + ;missing-input print print #0a18 DEO #00 JMP2r + &ok1 ;long-size LDA LIT "? NEQ ?&ok2 + ;input-toobig print print #0a18 DEO #00 JMP2r + &ok2 POP2 #01 JMP2r + +@path-exists ( path* -> ) + path-read-size ;long-size LDA LIT "! NEQ JMP2r + +@path-read-size ( path* -> ) + .File2/name DEO2 + #0008 .File2/len DEO2 + ;long-size .File2/stat DEO2 + JMP2r + +@archive-dir ( path* -> ) + POP2 JMP2r + +@archive-path ( path* -> ) + zero-header DUP2 path-read-size ( path* ) + ;long-size LDA LIT "- EQU ?archive-dir ( path* ) + LIT2r =header ( path* [h*] ) + STH2kr LDA LIT "/ NEQ ?&rel-path ( path* [h*] ) + LIT ". STH2kr STA INC2r ( path* [h+1*] ) + &rel-path STH2r copy-str ( ; write file name ) + ;default-mode ;header/mode copy-str ( ; write file permissions ) + ;default-id ;header/owner copy-str ( ; write file owner ) + ;default-id ;header/group copy-str ( ; write file group ) + size-to-octal ( ; write file size ) + #010e DEO + ;default-mtime ;header/mtime copy-str ( ; write mtime ) + LIT "0 ;header/type STA ( ; write '0' for normal file ) + ;u-sum compute-sum ( checksum* ) + +@ascii-to-short ( s* -> n* ) + #0000 SWP2 LITr c0 ( sum* s* [shift^] ) + &loop LDAk #30 SUB ( sum0* s* digit^ [shift^] ) + #00 SWP ( sum0* s* digit* [shift^] ) + STHkr SFT2 ( sum0* s* digit< ) + ;long-size ascii-to-short ( hi* ) + ;long-size/mid ascii-to-short ( hi* lo* ) + ;scratch ( hi* lo* addr* ) + render-octal32 ( ) + #000b ;header/size save-octal ( ) + JMP2r ( ) + +@render-octal32 ( hi* lo* addr* -> ) + short-to-octal STH2 STH ( aaaaaaaa bbbbbbbb [addr+5* 0000000x] ) + #0000 ROT ( aaaaaaaa 00000000 00000000 bbbbbbbb [addr+5* 0000000x] ) + #10 SFT2 ( aaaaaaaa 00000000 0000000b bbbbbbb0 [addr+5* 0000000x] ) + SWP2 #07 SFT2 ( 0000000b bbbbbbb0 0000000a aaaaaaa0 [addr+5* 0000000x] ) + SWP2 STH ( 0000000a aaaaaaa0 0000000b [addr+5* 0000000x bbbbbbb0] ) + ORA ORAr STHr ( 0000000a aaaaaaab bbbbbbbx [addr+5*] ) + STH2r short-to-octal ( 0000000a 0000000z addr+10* ) + STH2 SWP #10 SFT ORA ( 000000az [addr+10*] ) + LIT "0 ADD STH2kr STA ( [addr+10*] ) + STH2r INC2 JMP2r ( addr+11* ) + +@short-to-octal ( n* addr* -> n>>15^ addr+5* ) + byte-to-octal STH2 SWP ( lo>>6^ hi^ [addr+2*] ) + DUP #01 AND #20 SFT ROT ORA ( hi^ [[hi&1]<<2]|lo>>6 [addr+2*] ) + LIT "0 ADD STH2kr STA ( hi^ [addr+2*] ) + #01 SFT INC2r ( hi>>1^ [addr+3*] ) + STH2r !byte-to-octal ( hi>>7^ addr+5* ) + +@byte-to-octal ( n^ addr* -> n>>6^ addr+2* ) + STH2 DUP #07 AND LIT "0 ADD ( n^ digit1^ [addr*] ) + STH2kr STA #03 SFT INC2r ( n>>3^ [addr+1*] ) + DUP #07 AND LIT "0 ADD ( n>>3^ digit2^ [addr+1*] ) + STH2kr STA #03 SFT INC2r ( n>>6^ [addr+2*] ) + STH2r JMP2r ( n>>6^ addr+2* ) + +@save-octal ( count* addr* -> ) + LIT2r ffff ( count* addr* [ffff*] ) + OVR2 ADD2 ( count* addr+count* [ffff*] ) + STH2 ( count* [ffff* addr+count*] ) + OVR2r ADD2r ( count* [ffff* h=addr+count-1*] ) + ;scratch SWP2 ( s* count* [ffff* h*] ) + OVR2 ADD2 SWP2 ( limit=count+s* s* [ffff* h*] ) + &loop LDAk STH2kr STA ( limit* s* [ffff* h*] ; h<-s ) + INC2 OVR2r ADD2r GTH2k ?&loop ( limit* s+1* [ffff* h-1*] ) + POP2 POP2 POP2r POP2r #010e DEO JMP2r ( ) + +@copy-str ( s* addr* -> ) + STH2 + &loop LDAk DUP ?&next POP POP2 POP2r JMP2r + &next STH2kr STA INC2 INC2r !&loop + +( we know header is exactly 512 bytes, an even number ) +@zero-header ( -> ) + ;uheader/end ;header LIT2r 0000 + &loop STH2kr OVR2 STA2 INC2 INC2 GTH2k ?&loop + POP2r POP2 POP2 JMP2r ( writes `n` bytes from File1 to File2 ) ( uses a 32k internal buffer ) @@ -275,6 +450,14 @@ #10 SFT #01 SFT2 STH2r ( hi* lo* ) JMP2r ( hi* lo* ) +( returns values between #0000 #0000 and #0003 #ffff ) +@load-octal6 ( addr* -> hi* lo* ) + STH2k LDA octal-digit ( o^ [addr*] ) + #0001 SFT2 ( o1^ o2^ [addr*] ) + #0000 ROT SWP2 SWP SWP2 ( o1* o2* [addr*] ) + STH2r INC2 load-octal5 ( o1* o2* n* ) + ORA2 JMP2r ( o1* o2|n* ) + ( returns values between #0000 and #7fff ) ( ) ( octal5 of 77777 = #7fff, max value ) @@ -350,15 +533,26 @@ JMP2r ( some handy string constants ) -@usage "usage: 20 "uxncli 20 "tar.rom 20 "t|x 20 "FILENAME 0a 00 +@usage1 "usage: 20 "uxncli 20 "tar.rom 20 "t|x 20 "TARFILE 0a 00 +@usage2 20 20 20 20 20 20 20 "uxncli 20 "tar.rom 20 "c 20 "TARFILE 20 "FILE1 20 "... 0a 00 @missing-mode "error: 20 "missing 20 "mode 0a 00 @missing-filename "error: 20 "missing 20 "filename 0a 00 @too-many-arguments "error: 20 "too 20 "many 20 "arguments 0a 00 +@no-input-arguments "error: 20 "no 20 "input 20 "files 0a 00 @invalid-mode "error: 20 "invalid 20 "mode 0a 00 @read-error "error 20 "reading 20 "data 0a 00 @write-error "error 20 "writing 20 "data 0a 00 @unsupported "skipped 20 "unsupported 20 "type 20 00 @meta-too-big "extended 20 "metadata 20 "field 20 "too 20 "big: 20 00 +@invalid-checksum "error: 20 "invalid 20 "checksum 0a 00 +@expected "expected: 20 00 +@found "found: 20 20 20 20 00 +@missing-input "error: 20 "missing 20 "input 20 "file: 20 00 +@input-toobig "error: 20 "input 20 "file 20 "too 20 "large: 20 00 +@destination-exists "error: 20 "destination 20 "already 20 "exists: 20 00 +@default-mode "0000755 00 +@default-id "0000000 00 +@default-mtime "07033241577 00 ( load argument parser ) ~arg.tal @@ -429,8 +623,11 @@ &pad $c ( 0x1f4: padding, 12 bytes ) &end ( 0x200: end of header ) +( small scratch buffer ) +|77e8 @scratch $10 + ( up to 8 bytes for long size ) -|77f8 @long-size $8 +|77f8 @long-size $4 &mid $4 ( buffer for up to 2048 characters of long names/paths ) |7800 @long-buf $800 diff --git a/test-regex.tal b/test-regex.tal index 6ce4800..f1bd414 100644 --- a/test-regex.tal +++ b/test-regex.tal @@ -1,45 +1,43 @@ -%dbg { #ff #0e DEO } -%sp { #20 #18 DEO } -%nl { #0a #18 DEO } -%exit { #01 #0f DEO BRK } +%sp { #2018 DEO } +%nl { #0a18 DEO } |0100 - ;expr1 ;compile JSR2 dbg nl - ;emit-stack JSR2 nl - ;emit-arena JSR2 nl + ;expr1 compile #010e DEO nl + emit-stack nl + emit-arena nl - LIT '= ;emit JSR2 sp - #01 ;emit-bool JSR2 sp - #01 ;emit-bool JSR2 sp - #00 ;emit-bool JSR2 sp - #01 ;emit-bool JSR2 sp - #01 ;emit-bool JSR2 sp - #00 ;emit-bool JSR2 sp - #00 ;emit-bool JSR2 sp - #00 ;emit-bool JSR2 nl + LIT "= emit sp + #01 emit-bool sp + #01 emit-bool sp + #00 emit-bool sp + #01 emit-bool sp + #01 emit-bool sp + #00 emit-bool sp + #00 emit-bool sp + #00 emit-bool nl - LIT 'A ;emit JSR2 sp - ;test1 OVR2k ;match JSR2 ;emit-bool JSR2 sp - ;test2 OVR2k ;match JSR2 ;emit-bool JSR2 sp - ;test3 OVR2k ;match JSR2 ;emit-bool JSR2 sp - ;test4 OVR2k ;match JSR2 ;emit-bool JSR2 sp - ;test5 OVR2k ;match JSR2 ;emit-bool JSR2 sp - ;test6 OVR2k ;match JSR2 ;emit-bool JSR2 sp - ;test7 OVR2k ;match JSR2 ;emit-bool JSR2 sp - ;test8 OVR2k ;match JSR2 ;emit-bool JSR2 nl + LIT "A emit sp + ;test1 OVR2k rx-match emit-bool sp + ;test2 OVR2k rx-match emit-bool sp + ;test3 OVR2k rx-match emit-bool sp + ;test4 OVR2k rx-match emit-bool sp + ;test5 OVR2k rx-match emit-bool sp + ;test6 OVR2k rx-match emit-bool sp + ;test7 OVR2k rx-match emit-bool sp + ;test8 OVR2k rx-match emit-bool nl - LIT 'B ;emit JSR2 sp - ;test1 ;graph1 ;match JSR2 ;emit-bool JSR2 sp - ;test2 ;graph1 ;match JSR2 ;emit-bool JSR2 sp - ;test3 ;graph1 ;match JSR2 ;emit-bool JSR2 sp - ;test4 ;graph1 ;match JSR2 ;emit-bool JSR2 sp - ;test5 ;graph1 ;match JSR2 ;emit-bool JSR2 sp - ;test6 ;graph1 ;match JSR2 ;emit-bool JSR2 sp - ;test7 ;graph1 ;match JSR2 ;emit-bool JSR2 sp - ;test8 ;graph1 ;match JSR2 ;emit-bool JSR2 nl + LIT "B emit sp + ;test1 ;graph1 rx-match emit-bool sp + ;test2 ;graph1 rx-match emit-bool sp + ;test3 ;graph1 rx-match emit-bool sp + ;test4 ;graph1 rx-match emit-bool sp + ;test5 ;graph1 rx-match emit-bool sp + ;test6 ;graph1 rx-match emit-bool sp + ;test7 ;graph1 rx-match emit-bool sp + ;test8 ;graph1 rx-match emit-bool nl - ;reset-arena JSR2 - exit + reset-arena + #010f DEO BRK ( corresponds to regex: a(b|c)d* ) @expr1 "a(b|c)d* 00 @@ -47,12 +45,12 @@ ( corresponds to regex: a(b|c)d* ) ( accepts "ab" or "ac" followd by any number of d's ) @graph1 - 03 'a :x1 - @x1 04 :x2 :x3 - @x2 03 'b :x4 - @x3 03 'c :x4 - @x4 05 :x5 0000 - @x5 03 'd :x4 + 03 "a =x1 + @x1 04 =x2 =x3 + @x2 03 "b =x4 + @x3 03 "c =x4 + @x4 05 =x5 0000 + @x5 03 "d =x4 ( test case strings to try matching ) @test1 "ab 00 ( yes ) @@ -67,50 +65,50 @@ ~regex.tal @emit ( c^ -- ) - emit JMP2r + #18 DEO JMP2r @emit-short ( short* -- ) - SWP ;emit-byte JSR2 ;emit-byte JSR2 JMP2r + SWP emit-byte emit-byte JMP2r @emit-byte ( byte^ -- ) - DUP #04 SFT ,&hex JSR #0f AND ,&hex JMP + DUP #04 SFT ,&hex JSR #0f AND !&hex &hex #30 ADD DUP #39 GTH #27 MUL ADD emit JMP2r @emit-bool ( byte^ -- ) - LIT '0 ADD emit JMP2r + LIT "0 ADD emit JMP2r ( print stack size, followed by contents ) @emit-stack ( -> ) - space LIT 'n emit LIT '= emit ;stack-pos LDA2 ;stack-bot SUB2 #0004 DIV2 ;emit-short JSR2 LIT ': emit + sp LIT "n emit LIT "= emit ;stack-pos LDA2 ;stack-bot SUB2 #0004 DIV2 emit-short LIT ": emit ;stack-bot &loop - DUP2 ;stack-pos LDA2 LTH2 ,&ok JCN - POP2 newline JMP2r + DUP2 ;stack-pos LDA2 LTH2 ?&ok + POP2 nl JMP2r &ok - space LDA2k ;emit-short JSR2 - #0002 ADD2 ,&loop JMP + sp LDA2k emit-short + #0002 ADD2 !&loop ( emit n bytes from the given address ) @emit-n ( addr* count^ -> addr2* ) - DUP #00 GTH ( addr count count>0? ) ,&ok JCN ( addr count ) POP newline JMP2r + DUP #00 GTH ( addr count count>0? ) ?&ok ( addr count ) POP nl JMP2r &ok - STH ( addr [count] ) space LDAk ;emit-byte JSR2 INC2 ( addr+1 [count] ) + STH ( addr [count] ) sp LDAk emit-byte INC2 ( addr+1 [count] ) STHr #01 SUB ( addr+1 count-1 ) - ;emit-n JMP2 + !emit-n ( emit the arena, with one line per node ) ( parses node type, since node size is dynamic (3-5). ) @emit-arena ( -> ) ;arena-bot &loop - DUP2 ;arena-pos LDA2 LTH2 ,&ok JCN POP2 JMP2r + DUP2 ;arena-pos LDA2 LTH2 ?&ok POP2 JMP2r &ok - DUP2 ;emit-short JSR2 - LIT ': emit space - LDAk #01 NEQ ,&!1 JCN #03 ;emit-n JSR2 ,&loop JMP - &!1 LDAk #02 NEQ ,&!2 JCN #03 ;emit-n JSR2 ,&loop JMP - &!2 LDAk #03 NEQ ,&!3 JCN #04 ;emit-n JSR2 ,&loop JMP - &!3 LDAk #04 NEQ ,&!4 JCN #05 ;emit-n JSR2 ,&loop JMP - &!4 LDAk #05 NEQ ,&!5 JCN #05 ;emit-n JSR2 ,&loop JMP - &!5 ;unknown-node-type ;error! JSR2 + DUP2 emit-short + LIT ": emit sp + LDAk #01 NEQ ?&c1 #03 emit-n !&loop + &c1 LDAk #02 NEQ ?&c2 #03 emit-n !&loop + &c2 LDAk #03 NEQ ?&c3 #04 emit-n !&loop + &c3 LDAk #04 NEQ ?&c4 #05 emit-n !&loop + &c4 LDAk #05 NEQ ?&c5 #05 emit-n !&loop + &c5 ;unknown-node-type errorm diff --git a/uxnrepl.py b/uxnrepl.py index 848a46f..0771ab0 100644 --- a/uxnrepl.py +++ b/uxnrepl.py @@ -21,7 +21,7 @@ template = ''' ;wst print @dump-wst - #04 DEI #01 GTH ?&next !emit-wst &next STH !dump-wst + #04 DEI #00 GTH ?&next !emit-wst &next STH !dump-wst @emit-wst #05 DEI LIT [ &n $1 ] GTH ?&next #0a18 DEO !start-rst @@ -34,7 +34,7 @@ template = ''' #05 DEI #00 GTH ?&next !emit-rst &next STHr !dump-rst @emit-rst - #04 DEI #01 GTH ?&next #0a18 DEO #800f DEO BRK + #04 DEI #00 GTH ?&next #0a18 DEO #800f DEO BRK &next emit #2018 DEO !emit-rst @print ( addr* -> ) diff --git a/varvara.7 b/varvara.7 new file mode 100644 index 0000000..0b87e51 --- /dev/null +++ b/varvara.7 @@ -0,0 +1,88 @@ +.\" Manpage reference for varvara. +.\" by Eiríkr Åsheim +.\" Contact d_m@plastic-idolatry.com to correct errors or typos. +.TH varvara 7 "14 Nov 2024" "1.0" "Varvara Reference Guide" +.SH NAME +varvara \- virtual machine for the Uxn CPU +.SH DESCRIPTION +Varvara is a virtual machine for the Uxn CPU. It provides devices that allow +ROMs to perform effects such as I/O, drawing to the screen, playing sounds, +and more. + +.SH DEVICES +Each device consists of 16 ports, each of which are one byte of device memory. Data can be read from ports with \fBDEI\fP and written to them with \fBDEO\fP. + +.SH TERMS + +.SS Devices + +.SS Ports + +.SS Vectors + +.SS Banks + +.SH DEVICE LAYOUT + 0x00 \fBSystem\fP 0x80 \fBController\fP + 0x10 \fBConsole\fP 0x90 \fBMouse\fP + 0x20 \fBScreen\fP 0xa0 \fBFile 0\fP + 0x30 \fBAudio 0\fP 0xb0 \fBFile 1\fP + 0x40 \fBAudio 1\fP 0xc0 \fBDateTime\fP + 0x50 \fBAudio 2\fP 0xd0 \fB(reserved)\fP + 0x60 \fBAudio 3\fP 0xe0 \fB(reserved)\fP + 0x70 \fB(unused)\fP 0xf0 \fB(unused)\fP + +.SH SYSTEM (0x00) + + 0x00 \fBvector*\fP 0x08 \fBred*\fP + 0x01 0x09 + 0x02 \fBexpansion*\fP 0x0a \fBgreen*\fP + 0x03 0x0b + 0x04 \fBwst\fP 0x0c \fBblue*\fP + 0x05 \fBrst\fP 0x0d + 0x06 \fBmetadata*\fP 0x0e \fBdebug\fP + 0x07 0x0f \fBstate\fP + +.SS System/vector +Currently unused. + +.SS System/expansion +Values written to the expansion port will be interpreted as an absolute address pointing to memory containing an expansion command. + + \fBCODE NAME DATA\fP + 00 \fBfill\fP 00 length* bank* addr* const + 01 \fBcpyl\fP 01 length* src-bank* src-addr* dst-bank* dst-addr* + 02 \fBcpyr\fP 02 length* src-bank* src-addr* dst-bank* dst-addr* + + \fBCODE NAME DESC\fP + 00 \fBfill\fP fill a range of memory with a constant value. + 01 \fBcpyl\fP copy a range of memory starting from the first byte. + 02 \fBcpyr\fP copy a range of memory starting from the last byte. + +Each bank contains 64k (65536 bytes) of data. Bank 0 is main memory. Banks are optional but emulators are encouraged to support at least 16 of them when possible. + +.SH CONSOLE (0x10) + +.SH SCREEN (0x20) + +.SH AUDIO (0x30, 0x40, 0x50, 0x60) + +.SH CONTROLLER (0x80) + +.SH MOUSE (0x90) + +.SH FILE (0xa0, 0xb0) + +.SH DATETIME (0xc0) + +.SH RESERVED (0xd0, 0xe0) + +.SH UNUSED (0x70, 0xf0) + +.SH SEE ALSO + + https://wiki.xxiivv.com/site/uxntal_opcodes.html \fIUxntal Opcodes\fP + https://wiki.xxiivv.com/site/uxntal_syntax.html \fIUxntal Syntax\fP + https://wiki.xxiivv.com/site/uxntal_modes.html \fIUxntal Modes\fP + https://wiki.xxiivv.com/site/uxntal_immediate.html \fIImmediate opcodes\fP + https://wiki.xxiivv.com/site/varvara.html \fIVarvara\fP