From a3133c35ec924c9b911ffd008f354b472f05ef92 Mon Sep 17 00:00:00 2001 From: d_m Date: Fri, 17 Nov 2023 20:37:58 -0500 Subject: [PATCH] initial commit --- .gitignore | 16 +++++ arg.tal | 82 ++++++++++++++++++++++ icn_to_bmp.tal | 186 +++++++++++++++++++++++++++++++++++++++++++++++++ test/test.bmp | Bin 0 -> 128 bytes test/test.icn | Bin 0 -> 72 bytes 5 files changed, 284 insertions(+) create mode 100644 .gitignore create mode 100644 arg.tal create mode 100644 icn_to_bmp.tal create mode 100644 test/test.bmp create mode 100644 test/test.icn diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..968b2cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# use glob syntax. +syntax: glob +*.pyc +*.pyo +*~ +TAGS +*.rom +img +etc +test-roms +junk +img +.theme +.snarf +*.sym +wave diff --git a/arg.tal b/arg.tal new file mode 100644 index 0000000..879a3a6 --- /dev/null +++ b/arg.tal @@ -0,0 +1,82 @@ +( arg.tal ) +( ) +( by d_m ) +( ) +( by calling arg/init during the reset vector ) +( the author can skip all the details of reading ) +( and detecting command-line arguments. ) +( ) +( instead they can "wait" until the arguments ) +( are all read before accessing the argument ) +( count and argument string values in a more ) +( ergonomic way. ) +( ) +( when using arg/init authors provide two things: ) +( - callback to run when all args are read ) +( - stdin vector to use once args are read ) +( ) +( the callback can load arg/count to see how many ) +( arguments were given, and run arg/read to get ) +( the address of a particular argument as a ) +( null-terminated string. ) + +@arg ( arg namespace ) + +( initialize the arg library. ) +( call this during the reset vector. ) +&init ( callback* stdin* -> ) + ;arg/stdin STA2 + ;arg/callback STA2 + #00 ;arg/count STA + ;arg/buffer ;arg/pos STA2 + ;arg/on-read #10 DEO2 + #17 DEI #00 EQU ?&no-args JMP2r + &no-args !arg/complete + +( read the nth argument, starting with n=0. ) +( call this during the callback. ) +&read ( n^ -> s* ) + LITr 00 STH SUBr + ;arg/buffer ( buf* [-n^] ) + &loop STHkr ?&ok POPr JMP2r ( pos* [-i^] ) + &ok LDAk ?¬null INCr ( pos* [-i+1^] ) + ¬null INC2 !&loop ( pos+1* [-j] ) + +( internal: console vector to use during argument parsing ) +&on-read ( -> BRK ) + #17 DEI + DUP #02 NEQ ?&b POP arg/store BRK ( 2: arg data ) + &b DUP #03 NEQ ?&c POP arg/next BRK ( 3: next arg ) + &c DUP #04 NEQ ?&d POP arg/finish BRK ( 4: finished with args ) + &d #0000 DIV BRK ( 0/1 are unexpected, error ) + +( internal: read a character ) +&store ( -> ) + #12 DEI !arg/save + +( internal: finish an argument and store null ) +&next ( -> ) + ;arg/count LDAk INC ROT ROT STA + #00 ( fall-through to save ) + +( internal: store character c in the buffer and update position ) +&save ( c^ -> ) + LIT2r :arg/pos LDA2kr STH2r ( c^ addr* [pos*] ) + STA LDA2kr INC2r SWP2r ( [addr1* pos*] ; addr<-c ) + STA2r JMP2r ( ; pos<-addr+1 ) + +( internal: called when last argument is complete ) +&finish ( -> ) + arg/next ( fall-through to complete ) + +( internal: called when arg parsing is done ) +&complete ( -> ) + ;arg/stdin LDA2 #10 DEO2 + ;arg/callback LDA2 JMP2 + +( some handy variables ) +&stdin $2 ( f: -> BRK ) +&callback $2 ( f: -> ) +&count $1 ( number of args given ) +&pos $2 ( position in buffer ) +&buffer $200 ( argument buffer ) diff --git a/icn_to_bmp.tal b/icn_to_bmp.tal new file mode 100644 index 0000000..646a0f4 --- /dev/null +++ b/icn_to_bmp.tal @@ -0,0 +1,186 @@ +( icn_to_bmp.tal ) +( ) +( converts ICN files to BMP files. ) +( ) +( USAGE: icn_to_bmp.rom $tile-w $tile-h $in-file $out-file ) +( ) +( EXAMPLE: icn_to_bmp.rom 8 8 icon.icn icon.bmp # convert a 64x64 pixel image ) + +@System [ |0f &state $1 ] +@Console [ |18 &w $1 ] +|a0 @File1 [ &vec $2 &ok $2 &stat $2 &del $1 &append $1 &name $2 &len $2 &r $2 &w $2 ] +|b0 @File2 [ &vec $2 &ok $2 &stat $2 &del $1 &append $1 &name $2 &len $2 &r $2 &w $2 ] + +|0000 + @tile-w $2 + @adj-tile-w $2 + @tile-h $2 + @icn-size $2 + @in-file $2 + @out-file $2 + @row-size-bytes $2 + @adj-row-size-bytes $2 + +|0100 + ;after-args #0000 arg/init BRK + +( load argument parsing ) +~arg.tal + +( exit immediately ) +@exit ( -> BRK ) + #01 .System/state DEO BRK + +( write null-terminated string to stdout ) +@emit ( buf* -> ) + LITr -Console/w ( buf* [dev^] ) + &loop LDAk ?&ok POP2 POPr JMP2r ( ) + &ok LDAk STHkr DEO INC2 !&loop ( buf+1* [dev^] ) + +@msg + &wrote "wrote 20 00 + &bytes-to 20 "bytes 20 "to 20 00 + &invalid-width "Invalid 20 "tile 20 "width 00 + &invalid-height "Invalid 20 "tile 20 "height 00 + &invalid-size "Invalid 20 "size: 20 "ICN 20 "too 20 "large + &write-error "Failed 20 "to 20 "write 20 "data 00 + &wrong-number-of-args "Wrong 20 "number 20 "of 20 "args; 20 "expected 20 "four 00 + +@usage ( reason* -> ) + ;usage/error emit emit ;usage/message emit !exit + &error "ERROR: 20 00 + &message + 0a 0a "USAGE: 20 "icn_to_bmp.rom 20 "WIDTH 20 "HEIGHT 20 "ICN 20 "BMP 0a + 20 20 "WIDTH 20 "and 20 "HEIGHT 20 "are 20 "given 20 "in 20 "tiles 20 "(each 20 "tile 20 "is 20 "8x8 20 "pixels) 0a + 20 20 "maximum 20 "WIDTH/HEIGHT 20 "is 20 "255 20 "tiles 0a + 20 20 "ICN/BMP 20 "should 20 "be 20 "paths 20 "(that 20 "are 20 "readable/writable) 0a + 20 20 "maximum 20 "ICN 20 "size 20 "is 20 "49152 20 "bytes 0a + 0a 00 + +@str-to-int ( s* -> n* ) + LIT2r 0000 + &loop LDAk ?&non-null POP2 STH2r JMP2r + &non-null LDAk LIT "0 SUB DUP #09 GTH ?&bad + LIT2r 000a MUL2r LITr 00 STH ADD2r INC2 !&loop + &bad POP2 POP2r #0000 JMP2r + +( emit a short as a decimal ) +@emit-dec2 ( n* -> ) + LITr 00 ( n [0] ) + &read ( n [k] ) + #000a DIV2k STH2k MUL2 SUB2 STH2r INCr ( n%10 n/10 [k+1] ) + DUP2 ORA ,&read JCN + POP2 ( top element was 0000 ) + &write ( n0 n1 ... nk [k+1] ) + NIP #30 ADD #18 DEO LITr 01 SUBr ( n0 ... n{k-1} [k] ) + STHkr ,&write JCN + POPr JMP2r + +@after-args ( -> ) + ;arg/count LDA #04 EQU ?{ ;msg/wrong-number-of-args !usage } + #00 arg/read str-to-int .tile-w STZ2 + #01 arg/read str-to-int .tile-h STZ2 + #02 arg/read .in-file STZ2 + #03 arg/read .out-file STZ2 + .tile-w LDZ2 .tile-h LDZ2 MUL2 #30 SFT2 .icn-size STZ2 + .tile-w LDZ2 #30 SFT2 .row-size-bytes STZ2 + .tile-w LDZ2 #0008 MUL2 #001f ADD2 #0020 DIV2 #0004 MUL2 .adj-tile-w STZ2 + .adj-tile-w LDZ2 #30 SFT2 .adj-row-size-bytes STZ2 + validate + write-header + read-icn + write-body + ;msg/wrote emit + ;bmp-header/total-size LDA2 SWP emit-dec2 + ;msg/bytes-to emit .out-file LDZ2 emit + #0a .Console/w DEO + !exit + +@read-icn ( -> ok^ ) + .in-file LDZ2 .File1/name DEO2 + .icn-size LDZ2 STH2k .File1/len DEO + ;icn-dat .File1/r DEO2 + .File1/ok DEI2 STH2r EQU2 JMP2r + +@convert-tile-row ( src* -> ) + .row-size-bytes LDZ2 ( src* size* ) + OVR2 ADD2 SWP2 LIT2r =bmp-buf ( limit* src* [dst*] ) + &loop ( limit* src* [dst*] ) + DUP2 STH2kr convert-row ( limit* src* [dst*] ) + #0008 ADD2 INC2r ( limit* src+8* [dst+1*] ) + GTH2k ?&loop ( limit* src+8* [dst+1*] ) + POP2 POP2 POP2r JMP2r ( ) + +@convert-row ( src* dst* -> ) + LITr -adj-tile-w LDZ2r STH2 ( src* [w* dst*] ) + #0001 SUB2 DUP2 #0008 ADD2 ( lim* src+7* [w* dst*] ) + &loop ( lim* pos* [w* dst*] ) + LDAk STH2kr STA OVR2r ADD2r ( src* pos* [w* dst+w*] ; dst<-pos ) + #0001 SUB2 LTH2k ?&loop ( src* pos-1* [w* dst+w*] ) + POP2 POP2 POP2r POP2r JMP2r ( ) + +@write-tile-row ( -> ok^ ) + .adj-row-size-bytes LDZ2 STH2k .File2/len DEO2 + ;bmp-buf .File2/w DEO2 + .File2/ok DEI2 STH2r EQU2 JMP2r + +@validate ( -> ) + .tile-w LDZ2 #0001 SUB2 #00ff LTH2 ?&tile-w-ok ;msg/invalid-width !usage &tile-w-ok + .tile-h LDZ2 #0001 SUB2 #00ff LTH2 ?&tile-h-ok ;msg/invalid-height !usage &tile-h-ok + .icn-size LDZ2 #c001 LTH2 ?&size-ok ;msg/invalid-size !usage &size-ok + JMP2r + +( colors are provided in RGB order, written to BMP header in reverse ) +@write-color ( r^ g^ b^ addr* -> ) + STH2k STA INC2r ( ; addr+0<-b ) + STH2kr STA INC2r ( ; addr+1<-g ) + STH2r STA JMP2r ( ; addr+2<-r ) + +@write-header ( -> ) + ( NOTE: you'll see some swaps just before stores ) + ( this is because the BMP header uses a little-endian byte order ) + .adj-tile-w LDZ2 .tile-h LDZ2 MUL2 ( aw*h ) + #30 SFT2 #0020 ADD2 ( 32+aw*h*8 ) + SWP ;bmp-header/total-size STA2 ( ; write total-size ) + .tile-h LDZ2 #30 SFT2 SWP ;bmp-header/pixel-h STA2 ( ; write height ) + .tile-w LDZ2 #30 SFT2 SWP ;bmp-header/pixel-w STA2 ( ; write width ) + + ( these colors are specified in RGB order ) + #ff #ff #ff ;bmp-header/color0 write-color ( ; write color 0 ) + #00 #00 #00 ;bmp-header/color1 write-color ( ; write color 1 ) + + ( actually write out the BMP header now ) + .out-file LDZ2 .File2/name DEO2 + #0020 .File2/len DEO2 + ;bmp-header .File2/w DEO2 + .File2/ok DEI2 #0020 EQU2 ?&ok ;msg/write-error !usage + &ok JMP2r + +@write-body ( -> ) + ;icn-dat ( dat* ) + .icn-size LDZ2 OVR2 ADD2 ( dat* dat+size* ) + .row-size-bytes LDZ2 STH2k SUB2 ( dat* dat+size-row* [row*] ) + &loop + DUP2 convert-tile-row + write-tile-row ?&ok2 ;msg/write-error !usage &ok2 + STH2kr SUB2 GTH2k ?&done !&loop + &done POP2r POP2 POP2 JMP2r + +( fields marked "MOD" will be updated; others will stay the same ) +@bmp-header + "BM ( 0: identify bitmap ) + &total-size 00 00 00 00 ( 2: total file size in bytes, includes header, MOD ) + 00 00 ( 6: reserved, zero ) + 00 00 ( 8: reserved, zero ) + 20 00 00 00 ( 10: pixel data offset, 32 bytes ) + 0c 00 00 00 ( 14: header size, 12 bytes ) + &pixel-w 00 00 ( 18: width in pixels, MOD ) + &pixel-h 00 00 ( 20: height in pixels, MOD ) + 01 00 ( 22: color planes, 1 ) + 01 00 ( 24: bits per pixel, 1 ) + &color0 ff ff ff ( 26: color 0, blue/green/red MOD ) + &color1 00 00 00 ( 29: color 1, blue/green/red MOD ) + ( 32: start of pixel data MOD ) + +@bmp-buf $7f8 ( 2040 bytes: buffer for one BMP row ) +@icn-dat $c000 ( 49152 bytes: buffer for the entire ICN file ) diff --git a/test/test.bmp b/test/test.bmp new file mode 100644 index 0000000000000000000000000000000000000000..25ba9a067257fa94d498b46f9099b0546e968800 GIT binary patch literal 128 zcmZ?rZD4=^1t7%(#1cTr2!#Lt{|EByn13+TxBp?NKmU&*{X8Fo^LaJ~$MzNm_QyvU z`2V*s$p7EKU{L>qfr0%81M`Oh5XHb#bATa1{s6-d_B#wenEM#Y8`v4DKd>`c{^w^f S1e%)s{U1 literal 0 HcmV?d00001 diff --git a/test/test.icn b/test/test.icn new file mode 100644 index 0000000000000000000000000000000000000000..ca2f52353712e9d998896d9762ff7f53861ccd71 GIT binary patch literal 72 zcmV-O0Jr}D17k5cdw2N2@b~}!@PGpxe*XUt2M3P$U(Ez`y`- e`1r672SGz;e}6vz