commit fbc0b762c966860e2682d9dd587334cd0572e231 parent d5b2bd98954677e7c8d8cd4fc56c5488f1318771 Author: neauoire <aliceffekt@gmail.com> Date: Mon, 31 May 2021 14:50:36 -0700 Renamed USM to TAL files Diffstat:
41 files changed, 1535 insertions(+), 1677 deletions(-)
diff --git a/README.md b/README.md @@ -31,10 +31,10 @@ Begin by building the assembler and emulator by running the build script. The as ./build.sh ``` -The following command will create an Uxn-compatible rom from an [uxambly file](https://wiki.xxiivv.com/site/uxambly.html), point to a different usm file in `/projects` to assemble a different rom. +The following command will create an Uxn-compatible rom from an [uxntal file](https://wiki.xxiivv.com/site/uxntal.html), point to a different .tal file in `/projects` to assemble a different rom. ``` -bin/uxnasm projects/examples/demos/life.usm bin/life.rom +bin/uxnasm projects/examples/demos/life.tal bin/life.rom ``` To start the rom, point the emulator to the newly created rom: diff --git a/build.sh b/build.sh @@ -43,7 +43,7 @@ then fi echo "Assembling.." -./bin/uxnasm projects/examples/demos/piano.usm bin/piano.rom +./bin/uxnasm projects/examples/demos/piano.tal bin/piano.rom echo "Running.." ./bin/uxnemu bin/piano.rom diff --git a/etc/asma-test.sh b/etc/asma-test.sh @@ -6,22 +6,22 @@ mkdir asma-test cd asma-test build_asma() { - sed -ne '/^( devices )/,/^( vectors )/p' ../projects/software/asma.usm + sed -ne '/^( devices )/,/^( vectors )/p' ../projects/software/asma.tal cat <<EOD |0100 @reset ;&source-file ;&dest-file ;asma-assemble-file JSR2 ;asma/error LDA2 #0000 NEQ2 JMP BRK #0000 DIV - &source-file "in.usm 00 + &source-file "in.tal 00 &dest-file "out.rom 00 EOD - sed -ne '/%asma-IF-ERROR/,$p' ../projects/software/asma.usm + sed -ne '/%asma-IF-ERROR/,$p' ../projects/software/asma.tal } expect_failure() { - cat > 'in.usm' + cat > 'in.tal' if ../bin/uxncli asma.rom > asma.log 2>/dev/null || ! grep -qF "${1}" asma.log; then echo "error: asma didn't report error ${1} in faulty code" tail asma.log @@ -30,11 +30,11 @@ expect_failure() { } echo 'Assembling asma with uxnasm' -build_asma > asma.usm -../bin/uxnasm asma.usm asma.rom > uxnasm.log -find ../projects -type f -name '*.usm' -not -name 'blank.usm' | sort | while read F; do +build_asma > asma.tal +../bin/uxnasm asma.tal asma.rom > uxnasm.log +find ../projects -type f -name '*.tal' -not -name 'blank.tal' | sort | while read F; do echo "Comparing assembly of ${F}" - BN="$(basename "${F%.usm}")" + BN="$(basename "${F%.tal}")" if ! ../bin/uxnasm "${F}" "uxnasm-${BN}.rom" > uxnasm.log; then echo "error: uxnasm failed to assemble ${F}" @@ -43,7 +43,7 @@ find ../projects -type f -name '*.usm' -not -name 'blank.usm' | sort | while rea fi xxd "uxnasm-${BN}.rom" > "uxnasm-${BN}.hex" - cp "${F}" 'in.usm' + cp "${F}" 'in.tal' if ! ../bin/uxncli asma.rom > asma.log; then echo "error: asma failed to assemble ${F}, while uxnasm succeeded" tail asma.log diff --git a/etc/asma.lua b/etc/asma.lua @@ -147,8 +147,8 @@ fmt = function(...) return (('\t%-11s %-10s %-12s %-14s %s '):format(...):gsub(' +$', '\n')) end do - local _with_0 = assert(io.open('projects/software/asma.usm.tmp', 'w')) - for l in assert(io.lines('projects/software/asma.usm')) do + local _with_0 = assert(io.open('projects/software/asma.tal.tmp', 'w')) + for l in assert(io.lines('projects/software/asma.tal')) do if l:match('--- cut here ---') then break end @@ -228,4 +228,4 @@ do ]]) _with_0:close() end -return os.execute('mv projects/software/asma.usm.tmp projects/software/asma.usm') +return os.execute('mv projects/software/asma.tal.tmp projects/software/asma.tal') diff --git a/etc/asma.moon b/etc/asma.moon @@ -1,7 +1,7 @@ -- -- Asma tree helper script -- --- This script updates the trees at the end of projects/software/asma.usm when +-- This script updates the trees at the end of projects/software/asma.tal when -- Uxn's opcode set changes or new runes (first character of tokens) are -- created, so that new changes in the C assembler can be incorporated rapidly -- into asma. @@ -122,8 +122,8 @@ printout = true fmt = (...) -> ('\t%-11s %-10s %-12s %-14s %s '\format(...)\gsub ' +$', '\n') -with assert io.open 'projects/software/asma.usm.tmp', 'w' - for l in assert io.lines 'projects/software/asma.usm' +with assert io.open 'projects/software/asma.tal.tmp', 'w' + for l in assert io.lines 'projects/software/asma.tal' if l\match '--- cut here ---' break \write l @@ -193,5 +193,5 @@ with assert io.open 'projects/software/asma.usm.tmp', 'w' ]] \close! -os.execute 'mv projects/software/asma.usm.tmp projects/software/asma.usm' +os.execute 'mv projects/software/asma.tal.tmp projects/software/asma.tal' diff --git a/etc/usm.sublime-syntax b/etc/usm.sublime-syntax @@ -2,11 +2,11 @@ --- # See http://www.sublimetext.com/docs/3/syntax.html name: Uxn Assembly -scopeName: usm. -fileTypes: [usm] +scopeName: tal. +fileTypes: [tal] file_extensions: - - usm -scope: source.usm + - tal +scope: source.tal contexts: main: diff --git a/etc/uxambly-translate.moon b/etc/uxambly-translate.moon @@ -1,4 +1,4 @@ --- Used for porting Uxambly code for use with the old assembler +-- Used for porting Uxntal code for use with the old assembler -- in commit 82f7103a55c21b13f898b20e5d1e174e501bc825 with the -- assembler that replaced it straight afterwards. @@ -93,11 +93,11 @@ translate = (_filename) -> f\close! os.exit 0 -translate 'attic/software/assembler.usm' +translate 'attic/software/assembler.tal' os.exit 0 -translate 'attic/tests/opcodes.usm' -translate 'attic/tests/basics.usm' +translate 'attic/tests/opcodes.tal' +translate 'attic/tests/basics.tal' -- for k, v in pairs t -- print k diff --git a/mkfile b/mkfile @@ -1,8 +1,8 @@ </$objtype/mkfile TARG=bin/uxncli bin/uxnasm bin/uxnemu -USM=`{walk -f projects/ | grep '\.usm$' | grep -v blank.usm} -ROM=${USM:%.usm=%.rom} +USM=`{walk -f projects/ | grep '\.tal$' | grep -v blank.tal} +ROM=${USM:%.tal=%.rom} CFLAGS=$CFLAGS -I/sys/include/npe HFILES=\ /sys/include/npe/stdio.h\ @@ -26,8 +26,8 @@ bin: mk install && rm -r npe-master -%.rom:Q: %.usm bin/uxnasm - bin/uxnasm $stem.usm $target >/dev/null +%.rom:Q: %.tal bin/uxnasm + bin/uxnasm $stem.tal $target >/dev/null bin/uxncli: uxncli.$O uxn.$O $LD $LDFLAGS -o $target $prereq diff --git a/projects/examples/blank.usm b/projects/examples/blank.tal diff --git a/projects/examples/demos/automata.usm b/projects/examples/demos/automata.tal diff --git a/projects/examples/demos/bifurcan.usm b/projects/examples/demos/bifurcan.tal diff --git a/projects/examples/demos/darena.tal b/projects/examples/demos/darena.tal @@ -0,0 +1,550 @@ +( darena.tal ) +( an open-ended game of rocks and sand ) +( contributed by and cc0 sejo 12021 ) + +%DEBUG { .Console/byte DEO #0a .Console/char DEO } +%DEBUG2 { .Console/short DEO2 #0a .Console/char DEO } + +( parameters ) +%nrocks { #1f } +%nrocks-1 { #1e } +%nrocks_mask { #1f } +%minposx { #0f } +%minposy { #0f } +%maxposx { #f1 } +%maxposy { #f1 } +%anispeedmask_normal { #03 } +%anispeedmask_slow { #07 } + +%c_color_normal { #33 } +%c_color_flipx { #73 } +%index_norock { #ff } + +( output macros ) +%out_screen_x { LDA #00 SWP .Screen/x DEO2 } ( ;addr ) +%out_screen_y { LDA #00 SWP .Screen/y DEO2 } ( ;addr ) + +( helper macros ) +%get_bit_n { SFT #01 AND } +%get_nibble_h { #04 SFT #0f AND } +%get_nibble_l { #0f AND } + +%is_bit_n_set { get_bit_n #01 EQU } + +%set_animate { #01 ;c_state LDA ORA ;c_state STA } +%rst_animate { #00 ;c_state STA } + +( devices ) + +|00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 ] +|10 @Console [ &pad $8 &char $1 &byte $1 &short $2 &string $2 ] +|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ] +|80 @Controller [ &vector $2 &button $1 &key $1 ] + +( variables ) + +|0000 + +@c_pos [ &x $1 &y $1 ] ( character position ) +@c_speed [ &x $1 &y $1 ] ( character speed ) +@c_color [ $1 ] ( character color ) +@c_sprite [ $2 ] ( character sprite addr ) +@c_state [ $1 ] ( high_nibble: animation pointer, bit0: is_animated ) + +@f_count [ $1 ] ( frame counter ) +@ani_speedmask [ $1 ] ( animation speed mask ) + +@r_speed_x [ $f ] +@r_speed_y [ $f ] + +@tog [ &x $1 &y $1 &state $1 ] ( toggle station state ) + +( program ) + +|0100 @reset ( -> ) + #f396 .System/r DEO2 + #e263 .System/g DEO2 + #9030 .System/b DEO2 + + ;on_frame .Screen/vector DEO2 + + ( init character ) + #50 ;c_pos/x STA + #10 ;c_pos/y STA + #00 ;c_speed/x STA + #00 ;c_speed/y STA + c_color_normal ;c_color STA + ;s_monitx_stepfront0 ;c_sprite STA2 + rst_animate + + anispeedmask_normal ;ani_speedmask STA + + ( init toggler ) + #27 ;tog/x STA + #27 ;tog/y STA + #00 ;tog/state STA + + + ( init background ) + ;init_bg JSR2 +BRK + + +@on_frame ( -> ) + ;f_count LDA #01 ADD DUP ;f_count STA ( increase frame counter ) + ;ani_speedmask LDA ( mask with animation speed mask ) + AND #00 EQU ,update_frame JCN ( jump to update if it's time ) +BRK + +@update_frame + ( check keyboard ) + ;check_keys JSR2 + + ( animate character sprite ) + ;animate_c JSR2 + + ( clear sprites ) + ;clear JSR2 + + ( update character vars ) + ;update_c/run JSR2 + + ( update rocks + stand ) + ;update_r/run JSR2 + + ( draw ) + ;draw JSR2 + +BRK + +@clear + ( clear rocks ) + ;s_clear .Screen/addr DEO2 + + nrocks #00 + &rocks_loop + DUP ( get rocks_x[i] ) + ;rocks_x ROT #00 SWP ADD2 out_screen_x + + DUP ( get rocks_y[i] ) + ;rocks_y ROT #00 SWP ADD2 out_screen_y + + #30 .Screen/color DEO + + #01 ADD + DUP2 + NEQ ,&rocks_loop JCN + POP2 + + ( clear character ) + ;clear_c JSR2 +JMP2r + +@draw + ( draw toggler ) + + ;tog/x out_screen_x + ;tog/x out_screen_y + ;s_stand .Screen/addr DEO2 + #23 .Screen/color DEO + + ( draw rocks ) + ;s_bola .Screen/addr DEO2 + + nrocks #00 + + &rocks_loop + DUP ( get rocks_x[i] ) + ;rocks_x ROT #00 SWP ADD2 out_screen_x + + DUP ( get rocks_y[i] ) + ;rocks_y ROT #00 SWP ADD2 out_screen_y + + ( DUP ( get color bitwise ) ) + ( ;r_color LDA SWP get_bit_n #31 ADD .Screen/color DEO ) + + DUP + ;r_color ROT #00 SWP ADD2 LDA #31 ADD .Screen/color DEO + + #01 ADD + + DUP2 + NEQ ,&rocks_loop JCN + POP2 + + ( draw character ) + ;draw_c JSR2 +JMP2r + +@check_keys + #00 ;c_speed/x STA + #00 ;c_speed/y STA + + .Controller/button DEI #07 is_bit_n_set ,&der JCN + .Controller/button DEI #06 is_bit_n_set ,&izq JCN + .Controller/button DEI #05 is_bit_n_set ,&aba JCN + .Controller/button DEI #04 is_bit_n_set ,&arr JCN + + rst_animate + + JMP2r + + &der + #01 ;c_speed/x STA + set_animate + c_color_normal ;c_color STA + ;s_monitx_stepside0 ;c_sprite STA2 + JMP2r + + &izq + #ff ;c_speed/x STA + set_animate + c_color_flipx ;c_color STA + ;s_monitx_stepside0 ;c_sprite STA2 + JMP2r + + &aba + #01 ;c_speed/y STA + set_animate + c_color_normal ;c_color STA + ;s_monitx_stepfront0 ;c_sprite STA2 + JMP2r + + &arr + #ff ;c_speed/y STA + set_animate + c_color_normal ;c_color STA + ;s_monitx_stepback0 ;c_sprite STA2 + JMP2r + + &end +JMP2r + +( sub-routines ) + +( in: sourcex, source y, index, rangex, rangey ) +( puts in the stack the index of rock collisioned with ) +@collision_rocks + &range_y $1 + &range_x $1 + &src_i $1 + &src_x $1 + &src_y $1 + + &rock_x $1 + &rock_y $1 + + &run + ,&range_y STR + ,&range_x STR + ,&src_i STR + ,&src_y STR + ,&src_x STR + + ( check collision with rocks ) + ( nrocks #00 ) + ,&src_i LDR nrocks_mask AND DUP #01 ADD nrocks_mask AND + + &rocks_loop + DUP ( get rocks_x[i] ) + ;rocks_x ROT #00 SWP ADD2 LDA ,&rock_x STR + + DUP ( get rocks_y[i] ) + ;rocks_y ROT #00 SWP ADD2 LDA ,&rock_y STR + + ,&src_x LDR ,&rock_x LDR ,&range_x LDR SUB GTH ( if sx > rx - 8 ) + ,&src_x LDR ,&rock_x LDR ,&range_x LDR ADD LTH ( if sx < rx + 8 ) + ,&src_y LDR ,&rock_y LDR ,&range_y LDR SUB GTH ( if sy > ry - 8 ) + ,&src_y LDR ,&rock_y LDR ,&range_y LDR ADD LTH ( if sy < ry + 8 ) + ADD ADD ADD #04 EQU ,&found JCN + + #01 ADD nrocks_mask AND + DUP2 + NEQ ,&rocks_loop JCN + POP2 + #ff + JMP2r + &found + SWP POP ( remove loop limit ) + DUP ;&src_i LDA NEQ ,&end JCN ( check if result is the same as index ) + POP #ff + JMP2r + + &end + +JMP2r + +@update_c ( update character position ) + &new_x $1 + &new_y $1 + + &rock_i $1 + &rock_x $1 + &rock_y $1 + + + &run + ;c_speed/x LDA ;c_pos/x LDA ADD + ,&new_x STR + ;c_speed/y LDA ;c_pos/y LDA ADD + ,&new_y STR + + anispeedmask_normal ;ani_speedmask STA + + &check_x + ( check collision with borders ) + ,&new_x LDR minposx EQU ;&noup_x JCN2 + ,&new_x LDR maxposx EQU ;&noup_x JCN2 + + + ( check collision with rocks ) + ,&new_x LDR ,&new_y LDR index_norock #09 #06 + ;collision_rocks/run JSR2 + + ( if it is colliding with rock, check further ) + DUP #ff NEQ ,&check_x_collision JCN + POP + ,&update_x JMP + + &check_x_collision + ( DUP DEBUG ) + ( slow down and save rock index ) + anispeedmask_slow ;ani_speedmask STA + ,&rock_i STR + + ( check if rock collides with others ) + ;rocks_x #00 ,&rock_i LDR ADD2 LDA ,&rock_x STR + ;rocks_y #00 ,&rock_i LDR ADD2 LDA ,&rock_y STR + + ,&rock_x LDR ,&rock_y LDR ,&rock_i LDR #09 #06 + ;collision_rocks/run JSR2 + + ( DUP DEBUG ) + + ( if it is colliding, then skip adding x ) + DUP #ff NEQ ,&check_y JCN + POP + + + ( if not, check for borders ) + ;&rock_x LDA minposx EQU ;&noup_x JCN2 + ;&rock_x LDA maxposx EQU ;&noup_x JCN2 + + ( move rock with same speed as c ) + ;&rock_x LDA ;c_speed/x LDA ADD + ;rocks_x #00 ;&rock_i LDA ADD2 + STA + + + &update_x + ;&new_x LDA ;c_pos/x STA + + ,&check_y JMP + + &noup_x + + &check_y + ( check collision with borders ) + ;&new_y LDA minposy EQU ;&noup_y JCN2 + ;&new_y LDA maxposy EQU ;&noup_y JCN2 + + ( check collision with rocks ) + ;&new_x LDA ;&new_y LDA index_norock #06 #09 + ;collision_rocks/run JSR2 + + ( if it is colliding with rock, check further ) + DUP #ff NEQ ,&check_y_collision JCN + POP + ,&update_y JMP + + &check_y_collision + ( DUP DEBUG ) + anispeedmask_slow ;ani_speedmask STA + ;&rock_i STA + + ( check if rock collides with others ) + ;rocks_x #00 ;&rock_i LDA ADD2 LDA ;&rock_x STA + ;rocks_y #00 ;&rock_i LDA ADD2 LDA ;&rock_y STA + + ;&rock_x LDA ;&rock_y LDA ;&rock_i LDA #06 #09 + ;collision_rocks/run JSR2 + + ( DUP DEBUG ) + + ( if it is colliding, then skip adding y ) + DUP #ff NEQ ,&noup_y JCN + POP + + ( if not, check for borders ) + ;&rock_y LDA minposx EQU ;&noup_y JCN2 + ;&rock_y LDA maxposx EQU ;&noup_y JCN2 + + ( if not colliding, then move rock with same speed as c ) + ;&rock_y LDA ;c_speed/y LDA ADD + ;rocks_y #00 ;&rock_i LDA ADD2 + STA + + + &update_y + ;&new_y LDA ;c_pos/y STA + JMP2r + + &noup_y +JMP2r + +@update_r + &rock_i $1 + + &run + + ( check collision with rocks ) + ;tog/x LDA ;tog/y LDA index_norock #02 #02 + ;collision_rocks/run JSR2 + + ( if it is colliding with rock, check if it needs to change state ) + DUP #ff NEQ ,&change_state JCN + + ( DUP DEBUG ) + + ( if there's no collision, reset toggler ) + POP + #00 ;tog/state STA + JMP2r + + &change_state + ( DUP DEBUG ) + ,&rock_i STR + ;tog/state LDA ,&done JCN ( don't toggle if state is active ) + + ;r_color #00 ,&rock_i LDR ADD2 DUP2 STH2 + LDA #01 EOR STH2r STA + #01 ;tog/state STA + &done + +JMP2r + +@animate_c + ( is bit0 -animate- on? ) + ;c_state LDA DUP #00 get_bit_n #01 NEQ ,&s_no_animate JCN + + ( increment and save animation pointer ) + &s_animate + DUP + get_nibble_h #01 ADD #03 AND #40 SFT + SWP get_nibble_l ORA + ;c_state STA + JMP2r + + &s_no_animate + get_nibble_h #0f AND ;c_state STA +JMP2r + +@draw_c ( draw character ) + #00 ;c_state LDA get_nibble_h #08 MUL + ;c_sprite LDA2 ADD2 .Screen/addr DEO2 + ;c_pos/x out_screen_x + ;c_pos/y out_screen_y + ;c_color LDA .Screen/color DEO +JMP2r + +@clear_c ( clear character ) + ;s_clear .Screen/addr DEO2 + ;c_pos/x out_screen_x + ;c_pos/y out_screen_y + #30 .Screen/color DEO +JMP2r + +@init_bg + ( init bg ) + ;s_border .Screen/addr DEO2 + + .Screen/height DEI2 #0000 STH2 + &vertical0loop + DUP2 + STH2r + DUP2 .Screen/y DEO2 + + + .Screen/width DEI2 #0000 STH2 + &horizontal0loop + DUP2 + STH2r + DUP2 .Screen/x DEO2 + + #23 .Screen/color DEO + + #0008 ADD2 DUP2 STH2 + GTH2 ,&horizontal0loop JCN + + STH2r POP2 POP2 + + + #0008 ADD2 DUP2 STH2 + GTH2 ,&vertical0loop JCN + STH2r + POP2 POP2 + + ( arena ) + + ;s_clear .Screen/addr DEO2 + + #00 maxposy #00 minposy STH2 + &vertical0loop_clear + DUP2 + STH2r + DUP2 .Screen/y DEO2 + + + #00 maxposx #00 minposx STH2 + &horizontal0loop_clear + DUP2 + STH2r + DUP2 .Screen/x DEO2 + + #20 .Screen/color DEO + + #0008 ADD2 DUP2 STH2 + GTH2 ,&horizontal0loop_clear JCN + + STH2r POP2 POP2 + + #0008 ADD2 DUP2 STH2 GTH2 ,&vertical0loop_clear JCN + STH2r + POP2 POP2 + +JMP2r + +( rocks ) +@rocks_x [ 25 30 42 50 67 90 98 e8 20 43 43 57 5a 7f bc a5 + e5 dd a2 20 b7 9b 38 e8 33 43 63 b7 aa cf bc ] +@rocks_y [ 60 48 34 56 23 65 65 65 ba e9 24 22 72 91 22 c5 + 25 30 42 50 67 90 98 e8 20 43 43 57 5a 7f bc ] +@r_color [ 00 01 01 00 00 00 01 01 01 01 00 00 01 01 00 00 + 01 00 01 00 00 01 00 01 01 01 01 01 00 00 00 ] + +( sprites ) + +@s_clear [ 0000 0000 0000 0000 ] +@s_border [ 3288 7e83 780d e013 ] +@s_bola [ 3c4e 9ffd f962 3c00 ] +@s_stand [ 0000 0000 0024 7eff ] +@s_stand_original [ 0000 0000 0000 3c7e ] + +@s_monitx [ 3c7e 5a7f 1b3c 5a18 ] +@s_monitx_back [ 3c7e 7efe d83c 5a18 ] + +@s_monitx_stepfront0 [ 3c7e 5a7f 1b3c 5a18 ] +@s_monitx_stepfront1 [ 3c7e 5a7f 1b3c 5a10 ] +@s_monitx_stepfront2 [ 3c7e 5a7f 1b3c 5a18 ] +@s_monitx_stepfront3 [ 3c7e 5a7f 1b3c 5a08 ] + +@s_monitx_stepback0 [ 3c7e 7efe d83c 5a18 ] +@s_monitx_stepback1 [ 3c7e 7efe d83c 5a10 ] +@s_monitx_stepback2 [ 3c7e 7efe d83c 5a18 ] +@s_monitx_stepback3 [ 3c7e 7efe d83c 5a08 ] + +@s_monitx_stepside0 [ 1c3c 7afc d81c 1818 ] +@s_monitx_stepside1 [ 1c3c 7afc d81c 1828 ] +@s_monitx_stepside2 [ 1c3c 7afc d81c 3810 ] +@s_monitx_stepside3 [ 1c3c 7afc d81c 1814 ] + diff --git a/projects/examples/demos/darena.usm b/projects/examples/demos/darena.usm @@ -1,550 +0,0 @@ -( darena.usm ) -( an open-ended game of rocks and sand ) -( contributed by and cc0 sejo 12021 ) - -%DEBUG { .Console/byte DEO #0a .Console/char DEO } -%DEBUG2 { .Console/short DEO2 #0a .Console/char DEO } - -( parameters ) -%nrocks { #1f } -%nrocks-1 { #1e } -%nrocks_mask { #1f } -%minposx { #0f } -%minposy { #0f } -%maxposx { #f1 } -%maxposy { #f1 } -%anispeedmask_normal { #03 } -%anispeedmask_slow { #07 } - -%c_color_normal { #33 } -%c_color_flipx { #73 } -%index_norock { #ff } - -( output macros ) -%out_screen_x { LDA #00 SWP .Screen/x DEO2 } ( ;addr ) -%out_screen_y { LDA #00 SWP .Screen/y DEO2 } ( ;addr ) - -( helper macros ) -%get_bit_n { SFT #01 AND } -%get_nibble_h { #04 SFT #0f AND } -%get_nibble_l { #0f AND } - -%is_bit_n_set { get_bit_n #01 EQU } - -%set_animate { #01 ;c_state LDA ORA ;c_state STA } -%rst_animate { #00 ;c_state STA } - -( devices ) - -|00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 ] -|10 @Console [ &pad $8 &char $1 &byte $1 &short $2 &string $2 ] -|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ] -|80 @Controller [ &vector $2 &button $1 &key $1 ] - -( variables ) - -|0000 - -@c_pos [ &x $1 &y $1 ] ( character position ) -@c_speed [ &x $1 &y $1 ] ( character speed ) -@c_color [ $1 ] ( character color ) -@c_sprite [ $2 ] ( character sprite addr ) -@c_state [ $1 ] ( high_nibble: animation pointer, bit0: is_animated ) - -@f_count [ $1 ] ( frame counter ) -@ani_speedmask [ $1 ] ( animation speed mask ) - -@r_speed_x [ $f ] -@r_speed_y [ $f ] - -@tog [ &x $1 &y $1 &state $1 ] ( toggle station state ) - -( program ) - -|0100 @reset ( -> ) - #f396 .System/r DEO2 - #e263 .System/g DEO2 - #9030 .System/b DEO2 - - ;on_frame .Screen/vector DEO2 - - ( init character ) - #50 ;c_pos/x STA - #10 ;c_pos/y STA - #00 ;c_speed/x STA - #00 ;c_speed/y STA - c_color_normal ;c_color STA - ;s_monitx_stepfront0 ;c_sprite STA2 - rst_animate - - anispeedmask_normal ;ani_speedmask STA - - ( init toggler ) - #27 ;tog/x STA - #27 ;tog/y STA - #00 ;tog/state STA - - - ( init background ) - ;init_bg JSR2 -BRK - - -@on_frame ( -> ) - ;f_count LDA #01 ADD DUP ;f_count STA ( increase frame counter ) - ;ani_speedmask LDA ( mask with animation speed mask ) - AND #00 EQU ,update_frame JCN ( jump to update if it's time ) -BRK - -@update_frame - ( check keyboard ) - ;check_keys JSR2 - - ( animate character sprite ) - ;animate_c JSR2 - - ( clear sprites ) - ;clear JSR2 - - ( update character vars ) - ;update_c/run JSR2 - - ( update rocks + stand ) - ;update_r/run JSR2 - - ( draw ) - ;draw JSR2 - -BRK - -@clear - ( clear rocks ) - ;s_clear .Screen/addr DEO2 - - nrocks #00 - &rocks_loop - DUP ( get rocks_x[i] ) - ;rocks_x ROT #00 SWP ADD2 out_screen_x - - DUP ( get rocks_y[i] ) - ;rocks_y ROT #00 SWP ADD2 out_screen_y - - #30 .Screen/color DEO - - #01 ADD - DUP2 - NEQ ,&rocks_loop JCN - POP2 - - ( clear character ) - ;clear_c JSR2 -JMP2r - -@draw - ( draw toggler ) - - ;tog/x out_screen_x - ;tog/x out_screen_y - ;s_stand .Screen/addr DEO2 - #23 .Screen/color DEO - - ( draw rocks ) - ;s_bola .Screen/addr DEO2 - - nrocks #00 - - &rocks_loop - DUP ( get rocks_x[i] ) - ;rocks_x ROT #00 SWP ADD2 out_screen_x - - DUP ( get rocks_y[i] ) - ;rocks_y ROT #00 SWP ADD2 out_screen_y - - ( DUP ( get color bitwise ) ) - ( ;r_color LDA SWP get_bit_n #31 ADD .Screen/color DEO ) - - DUP - ;r_color ROT #00 SWP ADD2 LDA #31 ADD .Screen/color DEO - - #01 ADD - - DUP2 - NEQ ,&rocks_loop JCN - POP2 - - ( draw character ) - ;draw_c JSR2 -JMP2r - -@check_keys - #00 ;c_speed/x STA - #00 ;c_speed/y STA - - .Controller/button DEI #07 is_bit_n_set ,&der JCN - .Controller/button DEI #06 is_bit_n_set ,&izq JCN - .Controller/button DEI #05 is_bit_n_set ,&aba JCN - .Controller/button DEI #04 is_bit_n_set ,&arr JCN - - rst_animate - - JMP2r - - &der - #01 ;c_speed/x STA - set_animate - c_color_normal ;c_color STA - ;s_monitx_stepside0 ;c_sprite STA2 - JMP2r - - &izq - #ff ;c_speed/x STA - set_animate - c_color_flipx ;c_color STA - ;s_monitx_stepside0 ;c_sprite STA2 - JMP2r - - &aba - #01 ;c_speed/y STA - set_animate - c_color_normal ;c_color STA - ;s_monitx_stepfront0 ;c_sprite STA2 - JMP2r - - &arr - #ff ;c_speed/y STA - set_animate - c_color_normal ;c_color STA - ;s_monitx_stepback0 ;c_sprite STA2 - JMP2r - - &end -JMP2r - -( sub-routines ) - -( in: sourcex, source y, index, rangex, rangey ) -( puts in the stack the index of rock collisioned with ) -@collision_rocks - &range_y $1 - &range_x $1 - &src_i $1 - &src_x $1 - &src_y $1 - - &rock_x $1 - &rock_y $1 - - &run - ,&range_y STR - ,&range_x STR - ,&src_i STR - ,&src_y STR - ,&src_x STR - - ( check collision with rocks ) - ( nrocks #00 ) - ,&src_i LDR nrocks_mask AND DUP #01 ADD nrocks_mask AND - - &rocks_loop - DUP ( get rocks_x[i] ) - ;rocks_x ROT #00 SWP ADD2 LDA ,&rock_x STR - - DUP ( get rocks_y[i] ) - ;rocks_y ROT #00 SWP ADD2 LDA ,&rock_y STR - - ,&src_x LDR ,&rock_x LDR ,&range_x LDR SUB GTH ( if sx > rx - 8 ) - ,&src_x LDR ,&rock_x LDR ,&range_x LDR ADD LTH ( if sx < rx + 8 ) - ,&src_y LDR ,&rock_y LDR ,&range_y LDR SUB GTH ( if sy > ry - 8 ) - ,&src_y LDR ,&rock_y LDR ,&range_y LDR ADD LTH ( if sy < ry + 8 ) - ADD ADD ADD #04 EQU ,&found JCN - - #01 ADD nrocks_mask AND - DUP2 - NEQ ,&rocks_loop JCN - POP2 - #ff - JMP2r - &found - SWP POP ( remove loop limit ) - DUP ;&src_i LDA NEQ ,&end JCN ( check if result is the same as index ) - POP #ff - JMP2r - - &end - -JMP2r - -@update_c ( update character position ) - &new_x $1 - &new_y $1 - - &rock_i $1 - &rock_x $1 - &rock_y $1 - - - &run - ;c_speed/x LDA ;c_pos/x LDA ADD - ,&new_x STR - ;c_speed/y LDA ;c_pos/y LDA ADD - ,&new_y STR - - anispeedmask_normal ;ani_speedmask STA - - &check_x - ( check collision with borders ) - ,&new_x LDR minposx EQU ;&noup_x JCN2 - ,&new_x LDR maxposx EQU ;&noup_x JCN2 - - - ( check collision with rocks ) - ,&new_x LDR ,&new_y LDR index_norock #09 #06 - ;collision_rocks/run JSR2 - - ( if it is colliding with rock, check further ) - DUP #ff NEQ ,&check_x_collision JCN - POP - ,&update_x JMP - - &check_x_collision - ( DUP DEBUG ) - ( slow down and save rock index ) - anispeedmask_slow ;ani_speedmask STA - ,&rock_i STR - - ( check if rock collides with others ) - ;rocks_x #00 ,&rock_i LDR ADD2 LDA ,&rock_x STR - ;rocks_y #00 ,&rock_i LDR ADD2 LDA ,&rock_y STR - - ,&rock_x LDR ,&rock_y LDR ,&rock_i LDR #09 #06 - ;collision_rocks/run JSR2 - - ( DUP DEBUG ) - - ( if it is colliding, then skip adding x ) - DUP #ff NEQ ,&check_y JCN - POP - - - ( if not, check for borders ) - ;&rock_x LDA minposx EQU ;&noup_x JCN2 - ;&rock_x LDA maxposx EQU ;&noup_x JCN2 - - ( move rock with same speed as c ) - ;&rock_x LDA ;c_speed/x LDA ADD - ;rocks_x #00 ;&rock_i LDA ADD2 - STA - - - &update_x - ;&new_x LDA ;c_pos/x STA - - ,&check_y JMP - - &noup_x - - &check_y - ( check collision with borders ) - ;&new_y LDA minposy EQU ;&noup_y JCN2 - ;&new_y LDA maxposy EQU ;&noup_y JCN2 - - ( check collision with rocks ) - ;&new_x LDA ;&new_y LDA index_norock #06 #09 - ;collision_rocks/run JSR2 - - ( if it is colliding with rock, check further ) - DUP #ff NEQ ,&check_y_collision JCN - POP - ,&update_y JMP - - &check_y_collision - ( DUP DEBUG ) - anispeedmask_slow ;ani_speedmask STA - ;&rock_i STA - - ( check if rock collides with others ) - ;rocks_x #00 ;&rock_i LDA ADD2 LDA ;&rock_x STA - ;rocks_y #00 ;&rock_i LDA ADD2 LDA ;&rock_y STA - - ;&rock_x LDA ;&rock_y LDA ;&rock_i LDA #06 #09 - ;collision_rocks/run JSR2 - - ( DUP DEBUG ) - - ( if it is colliding, then skip adding y ) - DUP #ff NEQ ,&noup_y JCN - POP - - ( if not, check for borders ) - ;&rock_y LDA minposx EQU ;&noup_y JCN2 - ;&rock_y LDA maxposx EQU ;&noup_y JCN2 - - ( if not colliding, then move rock with same speed as c ) - ;&rock_y LDA ;c_speed/y LDA ADD - ;rocks_y #00 ;&rock_i LDA ADD2 - STA - - - &update_y - ;&new_y LDA ;c_pos/y STA - JMP2r - - &noup_y -JMP2r - -@update_r - &rock_i $1 - - &run - - ( check collision with rocks ) - ;tog/x LDA ;tog/y LDA index_norock #02 #02 - ;collision_rocks/run JSR2 - - ( if it is colliding with rock, check if it needs to change state ) - DUP #ff NEQ ,&change_state JCN - - ( DUP DEBUG ) - - ( if there's no collision, reset toggler ) - POP - #00 ;tog/state STA - JMP2r - - &change_state - ( DUP DEBUG ) - ,&rock_i STR - ;tog/state LDA ,&done JCN ( don't toggle if state is active ) - - ;r_color #00 ,&rock_i LDR ADD2 DUP2 STH2 - LDA #01 EOR STH2r STA - #01 ;tog/state STA - &done - -JMP2r - -@animate_c - ( is bit0 -animate- on? ) - ;c_state LDA DUP #00 get_bit_n #01 NEQ ,&s_no_animate JCN - - ( increment and save animation pointer ) - &s_animate - DUP - get_nibble_h #01 ADD #03 AND #40 SFT - SWP get_nibble_l ORA - ;c_state STA - JMP2r - - &s_no_animate - get_nibble_h #0f AND ;c_state STA -JMP2r - -@draw_c ( draw character ) - #00 ;c_state LDA get_nibble_h #08 MUL - ;c_sprite LDA2 ADD2 .Screen/addr DEO2 - ;c_pos/x out_screen_x - ;c_pos/y out_screen_y - ;c_color LDA .Screen/color DEO -JMP2r - -@clear_c ( clear character ) - ;s_clear .Screen/addr DEO2 - ;c_pos/x out_screen_x - ;c_pos/y out_screen_y - #30 .Screen/color DEO -JMP2r - -@init_bg - ( init bg ) - ;s_border .Screen/addr DEO2 - - .Screen/height DEI2 #0000 STH2 - &vertical0loop - DUP2 - STH2r - DUP2 .Screen/y DEO2 - - - .Screen/width DEI2 #0000 STH2 - &horizontal0loop - DUP2 - STH2r - DUP2 .Screen/x DEO2 - - #23 .Screen/color DEO - - #0008 ADD2 DUP2 STH2 - GTH2 ,&horizontal0loop JCN - - STH2r POP2 POP2 - - - #0008 ADD2 DUP2 STH2 - GTH2 ,&vertical0loop JCN - STH2r - POP2 POP2 - - ( arena ) - - ;s_clear .Screen/addr DEO2 - - #00 maxposy #00 minposy STH2 - &vertical0loop_clear - DUP2 - STH2r - DUP2 .Screen/y DEO2 - - - #00 maxposx #00 minposx STH2 - &horizontal0loop_clear - DUP2 - STH2r - DUP2 .Screen/x DEO2 - - #20 .Screen/color DEO - - #0008 ADD2 DUP2 STH2 - GTH2 ,&horizontal0loop_clear JCN - - STH2r POP2 POP2 - - #0008 ADD2 DUP2 STH2 GTH2 ,&vertical0loop_clear JCN - STH2r - POP2 POP2 - -JMP2r - -( rocks ) -@rocks_x [ 25 30 42 50 67 90 98 e8 20 43 43 57 5a 7f bc a5 - e5 dd a2 20 b7 9b 38 e8 33 43 63 b7 aa cf bc ] -@rocks_y [ 60 48 34 56 23 65 65 65 ba e9 24 22 72 91 22 c5 - 25 30 42 50 67 90 98 e8 20 43 43 57 5a 7f bc ] -@r_color [ 00 01 01 00 00 00 01 01 01 01 00 00 01 01 00 00 - 01 00 01 00 00 01 00 01 01 01 01 01 00 00 00 ] - -( sprites ) - -@s_clear [ 0000 0000 0000 0000 ] -@s_border [ 3288 7e83 780d e013 ] -@s_bola [ 3c4e 9ffd f962 3c00 ] -@s_stand [ 0000 0000 0024 7eff ] -@s_stand_original [ 0000 0000 0000 3c7e ] - -@s_monitx [ 3c7e 5a7f 1b3c 5a18 ] -@s_monitx_back [ 3c7e 7efe d83c 5a18 ] - -@s_monitx_stepfront0 [ 3c7e 5a7f 1b3c 5a18 ] -@s_monitx_stepfront1 [ 3c7e 5a7f 1b3c 5a10 ] -@s_monitx_stepfront2 [ 3c7e 5a7f 1b3c 5a18 ] -@s_monitx_stepfront3 [ 3c7e 5a7f 1b3c 5a08 ] - -@s_monitx_stepback0 [ 3c7e 7efe d83c 5a18 ] -@s_monitx_stepback1 [ 3c7e 7efe d83c 5a10 ] -@s_monitx_stepback2 [ 3c7e 7efe d83c 5a18 ] -@s_monitx_stepback3 [ 3c7e 7efe d83c 5a08 ] - -@s_monitx_stepside0 [ 1c3c 7afc d81c 1818 ] -@s_monitx_stepside1 [ 1c3c 7afc d81c 1828 ] -@s_monitx_stepside2 [ 1c3c 7afc d81c 3810 ] -@s_monitx_stepside3 [ 1c3c 7afc d81c 1814 ] - diff --git a/projects/examples/demos/drum-rack.usm b/projects/examples/demos/drum-rack.tal diff --git a/projects/examples/demos/life.usm b/projects/examples/demos/life.tal diff --git a/projects/examples/demos/musictracker.usm b/projects/examples/demos/musictracker.tal diff --git a/projects/examples/demos/neralie.usm b/projects/examples/demos/neralie.tal diff --git a/projects/examples/demos/piano.usm b/projects/examples/demos/piano.tal diff --git a/projects/examples/demos/polycat.usm b/projects/examples/demos/polycat.tal diff --git a/projects/examples/demos/theme.usm b/projects/examples/demos/theme.tal diff --git a/projects/examples/devices/audio.channels.usm b/projects/examples/devices/audio.channels.tal diff --git a/projects/examples/devices/audio.usm b/projects/examples/devices/audio.tal diff --git a/projects/examples/devices/console.lib.usm b/projects/examples/devices/console.lib.tal diff --git a/projects/examples/devices/console.usm b/projects/examples/devices/console.tal diff --git a/projects/examples/devices/controller.buttons.usm b/projects/examples/devices/controller.buttons.tal diff --git a/projects/examples/devices/controller.keys.usm b/projects/examples/devices/controller.keys.tal diff --git a/projects/examples/devices/datetime.usm b/projects/examples/devices/datetime.tal diff --git a/projects/examples/devices/file.load.usm b/projects/examples/devices/file.load.tal diff --git a/projects/examples/devices/file.save.usm b/projects/examples/devices/file.save.tal diff --git a/projects/examples/devices/file.usm b/projects/examples/devices/file.tal diff --git a/projects/examples/devices/mouse.usm b/projects/examples/devices/mouse.tal diff --git a/projects/examples/devices/screen.usm b/projects/examples/devices/screen.tal diff --git a/projects/examples/gui/animation.usm b/projects/examples/gui/animation.tal diff --git a/projects/examples/gui/hover.usm b/projects/examples/gui/hover.tal diff --git a/projects/examples/gui/label.usm b/projects/examples/gui/label.usm @@ -1,141 +0,0 @@ -( GUI Labels ) - -%RTN { JMP2r } -%2// { #01 SFT2 } -%8** { #30 SFT2 } - -( devices ) - -|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ] -|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ] - -( variables ) - -|0000 - -@label [ &x $2 &y $2 &color $1 &addr $2 ] -@center [ &x $2 &y $2 ] - -( program ) - -|0100 - - ( theme ) #0f0f .System/r DEO2 #0fff .System/g DEO2 #0ff0 .System/b DEO2 - - ;draw JSR2 - -BRK - -@draw ( -- ) - - ( find screen center ) - .Screen/width DEI2 2// .center/x STZ2 - .Screen/height DEI2 2// .center/y STZ2 - - ( draw ver line ) - .center/x LDZ2 .Screen/x DEO2 #0000 .Screen/y DEO2 - &draw-ver - ( draw ) #02 .Screen/color DEO - ( incr ) .Screen/y DEI2 #0002 ADD2 .Screen/y DEO2 - .Screen/y DEI2 .Screen/height DEI2 LTH2 ,&draw-ver JCN - - .center/x LDZ2 .center/y LDZ2 #0010 SUB2 #2c ;text1 ;draw-label-left JSR2 - .center/x LDZ2 .center/y LDZ2 #2c ;text2 ;draw-label-middle JSR2 - .center/x LDZ2 .center/y LDZ2 #0010 ADD2 #2c ;text3 ;draw-label-right JSR2 - .center/x LDZ2 .center/y LDZ2 #0020 ADD2 #2c ;text4 ;draw-label-middle JSR2 - .center/x LDZ2 .center/y LDZ2 #0030 ADD2 #2c ;text5 ;draw-label-middle JSR2 - -RTN - -@draw-label-left ( x y color addr -- ) - - ( load ) .label/addr STZ2 .label/color STZ .Screen/y DEO2 .Screen/x DEO2 - .label/addr LDZ2 - &loop - ( draw ) DUP2 LDA #00 SWP 8** ;font ADD2 .Screen/addr DEO2 .label/color LDZ .Screen/color DEO - ( incr ) #0001 ADD2 - ( incr ) .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2 - DUP2 LDA ,&loop JCN - POP2 - -RTN - -@draw-label-middle ( x y color addr -- ) - - ( load ) .label/addr STZ2 .label/color STZ .Screen/y DEO2 - ( align ) .label/addr LDZ2 ;get-text-length JSR2 8** 2// SUB2 .Screen/x DEO2 - .label/addr LDZ2 - &loop - ( draw ) DUP2 LDA #00 SWP 8** ;font ADD2 .Screen/addr DEO2 .label/color LDZ .Screen/color DEO - ( incr ) #0001 ADD2 - ( incr ) .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2 - DUP2 LDA ,&loop JCN - POP2 - -RTN - -@draw-label-right ( x y color addr -- ) - - ( load ) .label/addr STZ2 .label/color STZ .Screen/y DEO2 - ( align ) .label/addr LDZ2 ;get-text-length JSR2 8** SUB2 .Screen/x DEO2 - .label/addr LDZ2 - &loop - ( draw ) DUP2 LDA #00 SWP 8** ;font ADD2 .Screen/addr DEO2 .label/color LDZ .Screen/color DEO - ( incr ) #0001 ADD2 - ( incr ) .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2 - DUP2 LDA ,&loop JCN - POP2 - -RTN - -@get-text-length ( label* -- length ) - - #0000 ( counter ) - &loop - ( incr ) #0001 ADD2 OVR2 OVR2 ADD2 - LDA ,&loop JCN - SWP2 POP2 - -RTN - -@font ( spectrum-zx font ) -[ - 0000 0000 0000 0000 0000 2400 7e3c 0000 0000 2400 3c42 0000 0000 6c7c 7c38 1000 - 0010 387c 7c38 1000 0038 387c 6c10 3800 0010 387c 7c10 3800 0000 0018 1800 0000 - 007e 4242 4242 7e00 0000 1824 2418 0000 0018 2442 4224 1800 001e 063a 4a48 3000 - 0038 446c 107c 1000 000c 0808 0838 3800 003e 2222 2266 6600 0000 0822 0022 0800 - 0000 1018 1c18 1000 0000 0818 3818 0800 0008 1c00 001c 0800 0028 2828 2800 2800 - 003e 4a4a 3a0a 0a00 000c 3046 620c 3000 0000 0000 0000 ffff 0010 3800 3810 0038 - 0008 1c2a 0808 0800 0008 0808 2a1c 0800 0000 0804 7e04 0800 0000 1020 7e20 1000 - 0000 4040 7e00 0000 0000 0024 6624 0000 0000 1038 7c00 0000 0000 007c 3810 0000 - 0000 0000 0000 0000 0008 0808 0800 0800 0014 1400 0000 0000 0024 7e24 247e 2400 - 0008 1e28 1c0a 3c08 0042 0408 1020 4200 0030 4832 4c44 3a00 0008 1000 0000 0000 - 0004 0808 0808 0400 0010 0808 0808 1000 0000 1408 3e08 1400 0000 0808 3e08 0800 - 0000 0000 0008 0810 0000 0000 3c00 0000 0000 0000 0000 0800 0000 0204 0810 2000 - 003c 464a 5262 3c00 0018 2808 0808 3e00 003c 4202 3c40 7e00 003c 421c 0242 3c00 - 0008 1828 487e 0800 007e 407c 0242 3c00 003c 407c 4242 3c00 007e 0204 0810 1000 - 003c 423c 4242 3c00 003c 4242 3e02 3c00 0000 0008 0000 0800 0000 0800 0008 0810 - 0000 0810 2010 0800 0000 003e 003e 0000 0000 1008 0408 1000 003c 4202 0c00 0800 - 003c 425a 5442 3c00 0018 2442 7e42 4200 007c 427c 4242 7c00 003c 4240 4042 3c00 - 0078 4442 4244 7800 007e 407c 4040 7e00 003e 4040 7c40 4000 003c 4240 4e42 3c00 - 0042 427e 4242 4200 003e 0808 0808 3e00 0002 0202 4242 3c00 0044 4870 4844 4200 - 0040 4040 4040 7e00 0042 665a 4242 4200 0042 6252 4a46 4200 003c 4242 4242 3c00 - 007c 4242 7c40 4000 003c 4242 524a 3c00 007c 4242 7c44 4200 003c 403c 0242 3c00 - 00fe 1010 1010 1000 0042 4242 4242 3c00 0042 4242 4224 1800 0042 4242 5a66 4200 - 0042 2418 1824 4200 0082 4428 1010 1000 007e 0408 1020 7e00 000c 0808 0808 0c00 - 0040 2010 0804 0200 0018 0808 0808 1800 0008 1422 0000 0000 0000 0000 0000 7e00 - 0008 0400 0000 0000 0000 1c02 1e22 1e00 0020 203c 2222 3c00 0000 1e20 2020 1e00 - 0002 021e 2222 1e00 0000 1c22 3c20 1e00 000c 101c 1010 1000 0000 1c22 221e 021c - 0020 202c 3222 2200 0008 0018 0808 0400 0008 0008 0808 4830 0020 2428 3028 2400 - 0010 1010 1010 0c00 0000 6854 5454 5400 0000 5864 4444 4400 0000 3844 4444 3800 - 0000 7844 4478 4040 0000 3c44 443c 0406 0000 2c30 2020 2000 0000 3840 3804 7800 - 0010 103c 1010 0c00 0000 4444 4444 3800 0000 4444 2828 1000 0000 4454 5454 2800 - 0000 4428 1028 4400 0000 4444 443c 0438 0000 7c08 1020 7c00 000c 0810 1008 0c00 - 0008 0808 0808 0800 0030 1008 0810 3000 0000 0032 4c00 0000 3c42 99a1 a199 423c -] - -@text1 [ "Left 20 "Aligned 00 ] -@text2 [ "Middle 20 "Aligned 00 ] -@text3 [ "Right 20 "Aligned 00 ] -@text4 [ "even 00 ] -@text5 [ "odd 00 ] -\ No newline at end of file diff --git a/projects/examples/gui/picture.usm b/projects/examples/gui/picture.tal diff --git a/projects/examples/gui/proportional-font.usm b/projects/examples/gui/proportional-font.tal diff --git a/projects/examples/gui/shapes.usm b/projects/examples/gui/shapes.tal diff --git a/projects/examples/gui/wallpaper.usm b/projects/examples/gui/wallpaper.tal diff --git a/projects/software/asma.tal b/projects/software/asma.tal @@ -0,0 +1,954 @@ +( devices ) + +|10 @Console [ &pad $8 &char $1 &byte $1 &short $2 &string $2 ] +|a0 @File [ &vector $2 &success $2 &offset $2 &pad $2 &name $2 &length $2 &load $2 &save $2 ] + +( vectors ) + +( + Asma - an in-Uxn assembler + + This assembler aims to be binary compatible with the output from + src/uxnasm.c, but unlike that assembler this one can be run inside Uxn + itself! + + Asma is designed to be able to be copy-pasted inside another project, so + all its routines are prefixed with "asma-" to prevent clashes with labels + used in the incorporating project. The reset vector contains a couple of + examples of asma's usage and can be discarded. +) + +|0100 @reset + ( + Assemble the source code into an output ROM file. + + If all you want is to use asma.tal to assemble files, insert a BRK + after this statement. + ) + ;&source-file ;&dest-file ;asma-assemble-file JSR2 + + ( + If an error has occurred, BRK here, otherwise continue. (The error + message will already have been printed to the Console in + asma-assemble-file.) + ) + ;asma/error LDA2 #0000 EQU2 JMP BRK + + ( + Load the output ROM over the currently running program, almost as if + we loaded the ROM with uxnemu directly! + + It's not a totally pristine environment, as File/load doesn't zero out + memory beyond the end of the file. So if the assembled program assumes + that all memory above it is zero, it may misbehave. + + Asma itself doesn't use the zero page, but this example code writes a + DEO2 instruction to 0x00ff. In order to execute File/load and have the + CPU continue at memory location 0x0100, we write the final DEO2 + instruction there and jump there as our final act. + + Just in case the assembled code is zero-length (which can occur when + assembling an empty source file), we write a BRK to the reset vector so + that will prevent an infinite loop. + ) + ;&dest-file .File/name DEO2 + #0000 .File/offset DEO2 + #ff00 .File/length DEO2 + #0100 .File/load + LIT DEO2 #00ff STA + LIT BRK #0100 STA + #00ff JMP2 + + &source-file + "projects/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-LOG { #09 } +( + asma-LOG is a log-level parameter 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, + #02 prints tokens as they are processed, + #04 dumps all defined labels at end, and + #08 prints the heap usage. +) +%asma-DEO2 { asma-LOG AND #00 EQU JMP DEO2k POP POP2 } +%asma-DEO { asma-LOG AND #00 EQU JMP DEOk POP2 } + +( + Asma's public interface. + These routines are what are expected to be called from programs that bundle + Asma into bigger projects. +) + +@asma-assemble-file ( src-filename* dest-filename* -- ) + ;asma/dest-filename STA2 ;asma/src-filename STA2 + + ;asma-init-first-pass JSR2 + ;asma-flush-ignore ;asma/flush-fn STA2 + ;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2 + asma-IF-ERROR ,&error JCN + + ;asma-init-next-pass JSR2 + ;asma-flush-to-file ;asma/flush-fn STA2 + ;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2 + asma-IF-ERROR ,&error JCN + + ;asma-trees/labels ;asma-print-labels JSR2 ( DEBUG ) + ;asma-print-line-count JSR2 ( DEBUG ) + ;asma-print-heap-usage JSR2 ( DEBUG ) + JMP2r + + &error + ;asma-print-error JSR2 ( DEBUG ) + JMP2r + +( + Debugging routines. These all output extra information to the Console. + These can be stripped out to save space, once the references to them are + removed. Look for the word DEBUG above to find these references: the lines + that contain that word can be deleted to strip out the functionality + cleanly. +) + +@asma-print-error ( -- ) + ;asma/error LDA2 .Console/string DEO2 + #3a .Console/char DEO + #20 .Console/char DEO + ;asma/orig-token LDA2 .Console/string DEO2 + ;&line .Console/string DEO2 + ;asma/line LDA2 .Console/short DEO2 + #2e .Console/char DEO + #0a .Console/char DEO + JMP2r + + &line 20 "on 20 "line 20 00 + +@asma-print-line-count ( -- ) + ;asma/line LDA2 .Console/short #01 asma-DEO2 + ;&lines .Console/string #01 asma-DEO2 + JMP2r + + &lines [ 20 "lines 20 "of 20 "source 20 "code. 0a 00 ] + +@asma-print-heap-usage ( -- ) + ;asma/heap LDA2 ;asma-heap SUB2 .Console/short #08 asma-DEO2 + ;&str1 .Console/string #08 asma-DEO2 + ;asma-heap/end ;asma/heap LDA2 SUB2 .Console/short #08 asma-DEO2 + ;&str2 .Console/string #08 asma-DEO2 + 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/char #04 asma-DEO + DUP2 #0004 ADD2 + &loop + DUP2 #0001 ADD2 SWP2 LDA + DUP #00 EQU ,&end JCN + .Console/char #04 asma-DEO + ,&loop JMP + &end + POP + #09 .Console/char #04 asma-DEO + LDA2 .Console/short #04 asma-DEO2 + #0a .Console/char #04 asma-DEO + + ( right node ) + #0002 ADD2 ,asma-print-sublabels JSR + JMP2r + +@asma-print-labels ( incoming-ptr* -- ) + LDA2 + ORAk ,&valid-incoming-ptr JCN + POP2 JMP2r + + &valid-incoming-ptr + ( left node ) + DUP2 ,asma-print-labels JSR + ( here ) + DUP2 #0004 ADD2 + &loop + DUP2 #0001 ADD2 SWP2 LDA + DUP #00 EQU ,&end JCN + .Console/char #04 asma-DEO + ,&loop JMP + &end + POP + #09 .Console/char #04 asma-DEO + LDA2k .Console/short #04 asma-DEO2 + #0a .Console/char #04 asma-DEO + ( subtree ) + #0002 ADD2 ;asma-print-sublabels JSR2 + + ( right node ) + #0002 ADD2 ,asma-print-labels JSR + JMP2r + +( + Initialise the assembler state before loading a file or chunk. +) + +@asma-init-first-pass ( -- ) + #ff ;asma/pass STA + #0000 DUP2k + ;asma/error STA2 + ;asma-trees/labels STA2 + ;asma-trees/macros STA2 + ;asma-heap ;asma/heap STA2 + ;asma-opcodes/_entry ;asma-trees/opcodes STA2 + ( fall through ) + +@asma-init-next-pass ( -- ) + ;asma/pass LDA #01 ADD ;asma/pass STA + ;asma-write-buffer ;asma-output/ptr STA2 + #0000 DUP2k + ;asma-output/offset STA2 + ;asma/addr STA2 + ;asma/state STA + #01 ( 0001 ) + SWPk ( 0001 0100 ) ;asma/written-addr STA2 + ;asma/line STA2 + JMP2r + +( + Divide a file up into chunks, and pass each chunk to asma-assemble-chunk. +) + +@asma-assemble-file-pass ( filename-ptr* -- ) + #0000 + + &loop + OVR2 .File/name DEO2 + DUP2 .File/offset DEO2 + ;asma-read-buffer/end ;asma-read-buffer SUB2 STH2k .File/length DEO2 + ;asma-read-buffer DUP2k .File/load DEO2 + .File/success DEI2 + DUP2 STH2r SUB2 ORA ,&last-one JCN + ,asma-assemble-chunk JSR asma-IF-ERROR ,&error JCN + SUB2 SUB2 + ,&loop JMP + + &last-one + ADD2k #00 ROT ROT STA + #0001 ADD2 + ,asma-assemble-chunk JSR asma-IF-ERROR ,&error JCN + + ( flush output buffer ) + ;asma-output/ptr LDA2 ;asma-write-buffer SUB2 ;asma/flush-fn LDA2 JSR2 + + POP2 + &error + POP2 POP2 POP2 + JMP2r + +( + Assemble a chunk of source code, which begins with whitespace or the start + of a token and is divided up into tokens separated by whitespace. If the + chunk ends with whitespace, assembled-up-to-ptr* will equal ptr* + len* and + every token in the chunk will have been assembled. If the chunk ends with a + non-whitespace character, assembled-up-to-ptr* will point to the beginning + of the last token in the chunk. +) + +@asma-assemble-chunk ( ptr* len* -- assembled-up-to-ptr* ) + OVR2 ADD2 #0001 SUB2 SWP2 STH2k + ,&loop JMP + + &next-char-pop + POP + &next-char + #0001 ADD2 + &loop ( last-ptr* ptr* / start-of-token* ) + OVR2 OVR2 LTH2 ,&end JCN + LDAk ( last-ptr* ptr* char / start-of-token* ) + DUP #20 GTH ,&next-char-pop JCN + + #00 OVR2 ( last-ptr* ptr* char 00 ptr* / start-of-token* ) + STA + STH2r ,asma-assemble-token JSR asma-IF-ERROR ,&error JCN + + #0a NEQ ,¬-newline JCN + ;asma/line LDA2 #0001 ADD2 ;asma/line STA2 + ¬-newline + + DUP2 #0001 ADD2 STH2 ,&next-char JMP + + &end + POP2 POP2 STH2r + JMP2r + + &error + POP POP2 POP2 + JMP2r + +@asma [ &pass $1 &state $1 &line $2 &token $2 &orig-token $2 &heap $2 &addr $2 &written-addr $2 &flush-fn $2 &src-filename $2 &dest-filename $2 &error $2 ] +@asma-trees [ &labels $2 ¯os $2 &opcodes $2 &scope $2 ] + +( + The main routine to assemble a single token. + asma/state contains several meaningful bits: + 0x02 we are in a comment, + 0x04 we are in a macro body, and + 0x08 we are in a macro body that we are ignoring + (because the macro was already defined in a previous pass). + Since 0x08 never appears without 0x04, the lowest bit set in asma/state is + always 0x00, 0x02, or 0x04, which is very handy for use with jump tables. + The lowest bit set can be found easily by #00 (n) SUBk AND. +) + +@asma-assemble-token ( string-ptr* -- ) + DUP2 .Console/string #02 asma-DEO2 + #0a .Console/char #02 asma-DEO + DUP2 ;asma/token STA2 + DUP2 ;asma/orig-token STA2 + LDAk ,¬-empty JCN + POP2 + JMP2r + + ¬-empty ( token* / ) + ( truncate to one char long ) + #0001 ADD2 ( end* / ) + STH2k LDAkr ( end* / end* char ) + STH2k ( end* / end* char end* ) + LITr 00 STH2 ( / end* char end* 00 end* ) + STAr ( / end* char end* ) + + #00 ;asma/state LDA SUBk AND ( tree-offset* / end* ) + DUP2 ;&first-char-trees ADD2 ( tree-offset* incoming-ptr* / end* ) + ;asma-traverse-tree JSR2 + + ( restore truncated char ) + STAr + + ,¬-found JCN + + ( tree-offset* token-routine-ptr* / end* ) + STH2r ;asma/token STA2 + SWP2 POP2 LDA2 + JMP2 ( tail call ) + + ¬-found ( tree-offset* dummy* / end* ) + POP2 POP2r + ;&body-routines ADD2 LDA2 + JMP2 ( tail call ) + + &first-char-trees + :asma-first-char-normal/_entry + :asma-first-char-comment/_entry + :asma-first-char-macro/_entry + + &body-routines + :asma-normal-body + :asma-ignore + :asma-macro-body + +@asma-parse-hex-digit ( charcode -- 00-0f if valid hex + OR 10-ff otherwise ) + DUP #3a LTH ,&digit JCN + DUP #60 GTH ,&letter JCN + JMP2r + + &digit + #30 SUB + JMP2r + + &letter + #57 SUB + JMP2r + +@asma-parse-hex-string ( -- value* 06 if valid hex and length > 2 + OR value* 03 if valid hex and length <= 2 + OR 00 otherwise ) + ;asma/token LDA2 DUP2 ,asma-strlen JSR #02 GTH ROT ROT + LIT2r 0000 + + &loop + LDAk + DUP ,¬-end JCN + POP POP2 + STH2r ROT #01 ADD #03 MUL + JMP2r + + ¬-end + ,asma-parse-hex-digit JSR + DUP #f0 AND ,&fail JCN + LITr 40 SFT2r + #00 STH STH ADD2r + #0001 ADD2 + ,&loop JMP + + &fail + POP POP2 POP2r + DUP EOR + JMP2r + +@asma-strlen ( string-ptr* -- length ) + LITr 00 + + &loop + LDAk + ,¬-end JCN + POP2 STHr + JMP2r + + ¬-end + LITr 01 ADDr + #0001 ADD2 + ,&loop JMP + +%asma-SHORT-FLAG { #20 } +%asma-RETURN-FLAG { #40 } +%asma-KEEP-FLAG { #80 } + +@asma-parse-opcode ( -- byte 00 if valid opcode + OR 01 otherwise ) + ;asma/token LDA2 + DUP2 ,asma-strlen JSR #03 LTH ,&too-short JCN + + ( truncate to three chars long ) + #0003 ADD2 ( end* / ) + STH2k LDAkr ( end* / end* char ) + STH2k ( end* / end* char end* ) + LITr 00 STH2 ( / end* char end* 00 end* ) + STAr ( / end* char end* ) + + ;asma-trees/opcodes ;asma-traverse-tree JSR2 + STAr + ,¬-found JCN + + ;asma-opcodes/_disasm SUB2 #03 SFT2 ( 00 byte / end* ) + &loop + LDAkr STHr LIT2r 0001 ADD2r ( 00 byte char / end* ) + DUP ,¬-end JCN + POP POP2r + SWP + JMP2r + + ¬-end + DUP LIT '2 NEQ ,¬-two JCN + POP asma-SHORT-FLAG ORA ,&loop JMP + + ¬-two + DUP LIT 'r NEQ ,¬-return JCN + POP asma-RETURN-FLAG ORA ,&loop JMP + + ¬-return + LIT 'k NEQ ,¬-keep JCN + asma-KEEP-FLAG ORA ,&loop JMP + + ¬-keep ( 00 byte / end* ) + ¬-found ( incoming-ptr* / end* ) + POP2r + &too-short ( token* / ) + POP2 #01 + JMP2r + +@asma-write-short ( short -- ) + SWP + ,asma-write-byte JSR + ,asma-write-byte JMP ( tail call ) + +@asma-write-byte ( byte -- ) + ;asma/addr LDA2 ;asma/written-addr LDA2 + LTH2k ,&rewound JCN + &loop + EQU2k ,&ready JCN + #00 ,&write JSR + #0001 ADD2 + ,&loop JMP + + &rewound + ;asma-msg-rewound ;asma/error STA2 + POP2 POP2 POP JMP2r + + &ready + POP2 #0001 ADD2 + DUP2 ;asma/addr STA2 + ;asma/written-addr STA2 + + &write + ,asma-output/ptr LDR2 + DUP2 ;asma-write-buffer/end EQU2 ,&flush JCN + &after-flush + STH2k STA + STH2r #0001 ADD2 ,asma-output/ptr STR2 + + ( #3e .Console/char ;asma/pass LDA asma-DEO + #20 .Console/char ;asma/pass LDA asma-DEO + #00 .Console/byte ;asma/pass LDA asma-DEO + #0a .Console/char ;asma/pass LDA asma-DEO ) + JMP2r + + &flush ( ptr* -- start-of-buffer* ) + ;asma-write-buffer SUB2k ( ptr* start* len* ) + ;asma/flush-fn LDA2 JSR2 + SWP2 POP2 ( start* ) + ,&after-flush JMP + +@asma-output [ &ptr $2 &offset $2 &filename $2 ] + +@asma-flush-ignore ( len* -- ) + POP2 + JMP2r + +@asma-flush-to-file ( len* -- ) + DUP2 .File/length DEO2 + ,asma-output/offset LDR2 DUP2 .File/offset DEO2 ADD2 ,asma-output/offset STR2 + ;asma/dest-filename LDA2 .File/name DEO2 + ;asma-write-buffer .File/save DEO2 + JMP2r + +@asma-append-heap-byte ( dummy byte -- dummy ) + ;asma/heap LDA2 + OVR2 OVR2 STA POP + #0001 ADD2 ;asma/heap STA2 + POP + JMP2r + +@asma-append-heap-short ( dummy short* -- dummy ) + SWP + ,asma-append-heap-byte JSR + ,asma-append-heap-byte JMP ( tail call ) + +@asma-append-heap-string ( string* -- ) + LDAk + DUP ,asma-append-heap-byte JSR + ,&keep-going JCN + POP2 JMP2r + + &keep-going + #0001 ADD2 + ,asma-append-heap-string JMP + +@asma-traverse-tree ( incoming-ptr* -- binary-ptr* 00 if key found + OR node-incoming-ptr* 01 if key not found ) + &loop ( incoming-ptr* ) + LDA2k ORA ,&valid-node JCN + #01 JMP2r + + &valid-node + LDA2 STH2k + #0004 ADD2 ,asma-strcmp-tree JSR + DUP ,&nomatch JCN + POP2r JMP2r + + &nomatch + #06 SFT #02 AND #00 SWP + STH2r ADD2 + ,&loop JMP + + ( &help-str "Looking 20 "up 20 00 ) + +@asma-strcmp-tree ( node-key* -- order if strings differ + OR after-node-key* 00 if strings match ) + ;asma/token LDA2 STH2 + + &loop ( node-key* / token* ) + DUP2 #0001 ADD2 SWP2 LDA LDAkr STHr + ORAk ,¬-end JCN + + ( end of C strings, match found ) + POP2r POP + JMP2r + + ¬-end + SUB + DUP ,&nomatch JCN + POP + LIT2r 0001 ADD2r + ,&loop JMP + + &nomatch + POP2r ROT ROT POP2 + JMP2r + +( + First character routines. + The following routines (that don't have a FORTH-like signature) are called + to deal with tokens that begin with particular first letters, or (for + -body routines) tokens that fail to match any first letter in their tree. +) + +%asma-STATE-SET { ;asma/state LDA ORA ;asma/state STA } +%asma-STATE-CLEAR { #ff EOR ;asma/state LDA AND ;asma/state STA } + +@asma-comment-start + #02 asma-STATE-SET +@asma-ignore + JMP2r + +@asma-comment-end + #02 asma-STATE-CLEAR + JMP2r + +@asma-macro-define + ;asma/pass LDA ,&ignore-macro JCN + + ;asma-trees/macros ;asma-traverse-tree JSR2 ,¬-exist JCN + POP2 + ;asma-msg-macro ;asma/error STA2 + JMP2r + + ¬-exist + ( define macro by creating new node ) + ;asma/heap LDA2 SWP2 STA2 + #0000 ;asma-append-heap-short JSR2 ( less-than pointer ) + #0000 ;asma-append-heap-short JSR2 ( greater-than pointer ) + ;asma/token LDA2 ;asma-append-heap-string JSR2 ( key ) + #04 asma-STATE-SET + JMP2r + + &ignore-macro + #0c asma-STATE-SET + JMP2r + +@asma-macro-body + ;asma/state LDA #08 AND ,&skip JCN + ;asma/token LDA2 ;asma-append-heap-string JSR2 + &skip + JMP2r + +@asma-macro-end + #00 ;asma-append-heap-byte JSR2 + #0c asma-STATE-CLEAR + JMP2r + +@asma-label-define + ;asma-trees/labels ,asma-label-helper JSR + ,&already-existed JCN + + #0000 ;asma-append-heap-short JSR2 ( data2: subtree incoming ptr ) + + &already-existed + #0002 ADD2 ;asma-trees/scope STA2 + JMP2r + +@asma-sublabel-define + ;asma-trees/scope LDA2 ,asma-label-helper JSR + POP POP2 + JMP2r + +@asma-label-helper ( incoming-ptr* -- binary-ptr* 00 if label existed already + OR binary-ptr* 01 if label was created ) + ;asma-traverse-tree JSR2 + ,&new-label JCN + + ( label already exists ) + ( FIXME check label address hasn't changed (label defined twice) ) + #01 JMP2r + + &new-label ( incoming-ptr* ) + ( define label by creating new node ) + ;asma/heap LDA2 SWP2 STA2 + #0000 ;asma-append-heap-short JSR2 ( less-than pointer ) + #0000 ;asma-append-heap-short JSR2 ( greater-than pointer ) + ;asma/token LDA2 ;asma-append-heap-string JSR2 ( key ) + + ;asma/heap LDA2 + + ;asma/addr LDA2 ;asma-append-heap-short JSR2 ( data1: address ) + #00 JMP2r + +@asma-pad-absolute + #0000 ,asma-pad-helper JMP + +@asma-pad-relative + ;asma/addr LDA2 + ( fall through ) + +@asma-pad-helper ( offset* -- ) + ;asma-parse-hex-string JSR2 + ,&valid JCN + + ;asma-msg-hex ;asma/error STA2 + JMP2r + + &valid + ADD2 ;asma/addr STA2 + JMP2r + +@asma-raw-char + ;asma/token LDA2 LDA + ;asma-write-byte JMP2 ( tail call ) + +@asma-raw-word + ;asma/token LDA2 + + &loop + LDAk + DUP ,¬-end JCN + + POP POP2 + JMP2r + + ¬-end + ;asma-write-byte JSR2 + #0001 ADD2 + ,&loop JMP + +@asma-literal-abs-addr + LIT LIT2 ;asma-write-byte JSR2 + ( fall through ) + +@asma-abs-addr + ,asma-addr-helper JSR + ;asma-write-short JMP2 ( tail call ) + +@asma-literal-zero-addr + LIT LIT ;asma-write-byte JSR2 + ,asma-addr-helper JSR + ;asma-write-byte JSR2 + + ,¬-zero-page JCN + JMP2r + + ¬-zero-page + ;asma-msg-zero-page ;asma/error STA2 + JMP2r + +@asma-literal-rel-addr + LIT LIT ;asma-write-byte JSR2 + ,asma-addr-helper JSR ;asma/addr LDA2 SUB2 #0002 SUB2 + + DUP2 #0080 LTH2 STH + DUP2 #ff7f GTH2 STHr ORA ,&in-bounds JCN + + POP2 + ;asma-msg-relative ;asma/error STA2 + JMP2r + + &in-bounds + ;asma-write-byte JSR2 + POP + JMP2r + +@asma-addr-helper ( -- addr* ) + ;asma/token LDA2 LDAk #26 NEQ ,¬-local JCN + #0001 ADD2 ;asma/token STA2 + ;asma-trees/scope LDA2 + ,&final-lookup JMP + + ¬-local ( token* ) + LDAk + DUP ,¬-end JCN + POP POP2 + ;asma-trees/labels + ,&final-lookup JMP + + ¬-end ( token* char ) + #2f EQU ,&found-slash JCN + #0001 ADD2 + ,¬-local JMP + + &found-slash ( token* ) + DUP2 #00 ROT ROT STA + ;asma-trees/labels ;asma-traverse-tree JSR2 STH + SWP2 DUP2 #2f ROT ROT STA + STHr ,¬-found2 JCN + ( token* binary-ptr* ) + #0001 ADD2 ;asma/token STA2 + #0002 ADD2 + + &final-lookup ( addr-offset* incoming-ptr* ) + ;asma-traverse-tree JSR2 + ,¬-found JCN + LDA2 + JMP2r + + ¬-found2 ( dummy* dummy* ) + POP2 + ¬-found ( dummy* ) + POP2 + + ;asma/pass LDA #00 EQU ,&ignore-error JCN + ;asma-msg-label ;asma/error STA2 + &ignore-error + + ;asma/addr LDA2 + JMP2r + +@asma-literal-hex + ;asma-parse-hex-string JSR2 JMP + ( hex invalid ) ,&invalid JMP + ( hex byte ) ,asma-byte-helper JMP + ( hex short ) ,asma-short-helper JMP + + &invalid + ;asma-msg-hex ;asma/error STA2 + JMP2r + +@asma-byte-helper ( dummy value -- ) + LIT LIT ;asma-write-byte JSR2 + &raw + ;asma-write-byte JSR2 + POP + JMP2r + +@asma-short-helper ( value* -- ) + LIT LIT2 ;asma-write-byte JSR2 + &raw + ;asma-write-short JMP2 ( tail call ) + +@asma-normal-body + ;asma-parse-opcode JSR2 ,¬-opcode JCN + ;asma-write-byte JMP2 ( tail call ) + + ¬-opcode + ;asma-parse-hex-string JSR2 JMP + ( hex invalid ) ,¬-hex JMP + ( hex byte ) ,asma-byte-helper/raw JMP + ( hex short ) ,asma-short-helper/raw JMP + + ¬-hex + ;asma-trees/macros ;asma-traverse-tree JSR2 ,¬-macro JCN + + ¯o-loop + LDAk ,&keep-going JCN + &error + POP2 + JMP2r + + &keep-going + DUP2k ;asma-strlen JSR2 #00 SWP #0001 ADD2 ADD2 + SWP2 ;asma-assemble-token JSR2 asma-IF-ERROR ,&error JCN + ,¯o-loop JMP + + ¬-macro + POP2 + + ;asma-msg-label ;asma/error STA2 + 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 + +( trees ) + +( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- ) +( automatically generated code below ) +( see etc/asma.moon for instructions ) + +( label less greater key binary + than than string data ) + +@asma-first-char-comment + &_entry $2 $2 ') 00 :asma-comment-end + +@asma-first-char-macro + &28 $2 $2 '( 00 :asma-comment-start + &29 :&28 $2 ') 00 :asma-comment-end + &_entry :&29 :&7d '{ 00 :asma-ignore + &7d $2 $2 '} 00 :asma-macro-end + +@asma-first-char-normal + &22 $2 $2 '" 00 :asma-raw-word + &23 :&22 $2 '# 00 :asma-literal-hex + &24 :&23 :&25 '$ 00 :asma-pad-relative + &25 $2 $2 '% 00 :asma-macro-define + &26 :&24 :&29 26 00 ( & ) :asma-sublabel-define + &27 $2 $2 '' 00 :asma-raw-char + &28 :&27 $2 '( 00 :asma-comment-start + &29 :&28 :&2c ') 00 :asma-comment-end + &2c $2 $2 ', 00 :asma-literal-rel-addr + &_entry :&26 :&5d '. 00 :asma-literal-zero-addr + &3a $2 $2 ': 00 :asma-abs-addr + &3b :&3a $2 '; 00 :asma-literal-abs-addr + &40 :&3b :&5b '@ 00 :asma-label-define + &5b $2 $2 '[ 00 :asma-ignore + &5d :&40 :&7c '] 00 :asma-ignore + &7b $2 $2 '{ 00 :asma-ignore + &7c :&7b :&7d '| 00 :asma-pad-absolute + &7d $2 $2 '} 00 :asma-ignore + +@asma-opcodes + &BRK :&AND :&DEI &_disasm "BRK 00 + &_entry :&EQU :&ROT "LIT 00 + &NOP :&MUL :&OVR "NOP 00 + &POP $2 $2 "POP 00 + &DUP :&DIV :&EOR "DUP 00 + &SWP $2 $2 "SWP 00 + &OVR :&ORA :&POP "OVR 00 + &ROT :&NOP :&STR "ROT 00 + &EQU :&DEO :&JSR "EQU 00 + &NEQ $2 $2 "NEQ 00 + >H $2 $2 "GTH 00 + <H $2 $2 "LTH 00 + &JMP $2 $2 "JMP 00 + &JCN :>H :&JMP "JCN 00 + &JSR :&JCN :&LDR "JSR 00 + &STH $2 $2 "STH 00 + &LDZ $2 $2 "LDZ 00 + &STZ $2 $2 "STZ 00 + &LDR :&LDA :&LDZ "LDR 00 + &STR :&STA :&SUB "STR 00 + &LDA $2 $2 "LDA 00 + &STA :&SFT :&STH "STA 00 + &DEI $2 $2 "DEI 00 + &DEO :&BRK :&DUP "DEO 00 + &ADD $2 $2 "ADD 00 + &SUB :&STZ :&SWP "SUB 00 + &MUL :<H :&NEQ "MUL 00 + &DIV $2 $2 "DIV 00 + &AND :&ADD $2 "AND 00 + &ORA $2 $2 "ORA 00 + &EOR $2 $2 "EOR 00 + &SFT $2 $2 "SFT 00 + +( + Heap, a large temporary area for keeping track of labels. More complex + programs need more of this space. If there's insufficient space then the + assembly process will fail, but having extra space above what the most + complex program needs provides no benefit. + + This heap, and the buffers below, are free to be used to hold temporary + data between assembly runs, and do not need to be initialized with any + particular contents to use the assembler. +) + +@asma-heap + +|e000 &end + +( + Buffer for use with loading source code. + The minimum size is the length of the longest token plus one, which is + 0x21 to keep the same capability of the C assembler. + Larger sizes are more efficient, provided there is enough + heap space to keep track of all the labels. +) + +@asma-read-buffer + +|f800 &end + +( + Buffer for use with writing output. + The minimum size is 1, and larger sizes are more efficient. +) + +@asma-write-buffer + +|ffff &end + diff --git a/projects/software/asma.usm b/projects/software/asma.usm @@ -1,954 +0,0 @@ -( devices ) - -|10 @Console [ &pad $8 &char $1 &byte $1 &short $2 &string $2 ] -|a0 @File [ &vector $2 &success $2 &offset $2 &pad $2 &name $2 &length $2 &load $2 &save $2 ] - -( vectors ) - -( - Asma - an in-Uxn assembler - - This assembler aims to be binary compatible with the output from - src/uxnasm.c, but unlike that assembler this one can be run inside Uxn - itself! - - Asma is designed to be able to be copy-pasted inside another project, so - all its routines are prefixed with "asma-" to prevent clashes with labels - used in the incorporating project. The reset vector contains a couple of - examples of asma's usage and can be discarded. -) - -|0100 @reset - ( - Assemble the source code into an output ROM file. - - If all you want is to use asma.usm to assemble files, insert a BRK - after this statement. - ) - ;&source-file ;&dest-file ;asma-assemble-file JSR2 - - ( - If an error has occurred, BRK here, otherwise continue. (The error - message will already have been printed to the Console in - asma-assemble-file.) - ) - ;asma/error LDA2 #0000 EQU2 JMP BRK - - ( - Load the output ROM over the currently running program, almost as if - we loaded the ROM with uxnemu directly! - - It's not a totally pristine environment, as File/load doesn't zero out - memory beyond the end of the file. So if the assembled program assumes - that all memory above it is zero, it may misbehave. - - Asma itself doesn't use the zero page, but this example code writes a - DEO2 instruction to 0x00ff. In order to execute File/load and have the - CPU continue at memory location 0x0100, we write the final DEO2 - instruction there and jump there as our final act. - - Just in case the assembled code is zero-length (which can occur when - assembling an empty source file), we write a BRK to the reset vector so - that will prevent an infinite loop. - ) - ;&dest-file .File/name DEO2 - #0000 .File/offset DEO2 - #ff00 .File/length DEO2 - #0100 .File/load - LIT DEO2 #00ff STA - LIT BRK #0100 STA - #00ff JMP2 - - &source-file - "projects/demos/piano.usm 00 - &dest-file - "bin/asma-boot.rom 00 - -( - Common macros for use later on. -) - -%asma-IF-ERROR { ;asma/error LDA2 ORA } -%asma-LOG { #09 } -( - asma-LOG is a log-level parameter 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, - #02 prints tokens as they are processed, - #04 dumps all defined labels at end, and - #08 prints the heap usage. -) -%asma-DEO2 { asma-LOG AND #00 EQU JMP DEO2k POP POP2 } -%asma-DEO { asma-LOG AND #00 EQU JMP DEOk POP2 } - -( - Asma's public interface. - These routines are what are expected to be called from programs that bundle - Asma into bigger projects. -) - -@asma-assemble-file ( src-filename* dest-filename* -- ) - ;asma/dest-filename STA2 ;asma/src-filename STA2 - - ;asma-init-first-pass JSR2 - ;asma-flush-ignore ;asma/flush-fn STA2 - ;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2 - asma-IF-ERROR ,&error JCN - - ;asma-init-next-pass JSR2 - ;asma-flush-to-file ;asma/flush-fn STA2 - ;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2 - asma-IF-ERROR ,&error JCN - - ;asma-trees/labels ;asma-print-labels JSR2 ( DEBUG ) - ;asma-print-line-count JSR2 ( DEBUG ) - ;asma-print-heap-usage JSR2 ( DEBUG ) - JMP2r - - &error - ;asma-print-error JSR2 ( DEBUG ) - JMP2r - -( - Debugging routines. These all output extra information to the Console. - These can be stripped out to save space, once the references to them are - removed. Look for the word DEBUG above to find these references: the lines - that contain that word can be deleted to strip out the functionality - cleanly. -) - -@asma-print-error ( -- ) - ;asma/error LDA2 .Console/string DEO2 - #3a .Console/char DEO - #20 .Console/char DEO - ;asma/orig-token LDA2 .Console/string DEO2 - ;&line .Console/string DEO2 - ;asma/line LDA2 .Console/short DEO2 - #2e .Console/char DEO - #0a .Console/char DEO - JMP2r - - &line 20 "on 20 "line 20 00 - -@asma-print-line-count ( -- ) - ;asma/line LDA2 .Console/short #01 asma-DEO2 - ;&lines .Console/string #01 asma-DEO2 - JMP2r - - &lines [ 20 "lines 20 "of 20 "source 20 "code. 0a 00 ] - -@asma-print-heap-usage ( -- ) - ;asma/heap LDA2 ;asma-heap SUB2 .Console/short #08 asma-DEO2 - ;&str1 .Console/string #08 asma-DEO2 - ;asma-heap/end ;asma/heap LDA2 SUB2 .Console/short #08 asma-DEO2 - ;&str2 .Console/string #08 asma-DEO2 - 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/char #04 asma-DEO - DUP2 #0004 ADD2 - &loop - DUP2 #0001 ADD2 SWP2 LDA - DUP #00 EQU ,&end JCN - .Console/char #04 asma-DEO - ,&loop JMP - &end - POP - #09 .Console/char #04 asma-DEO - LDA2 .Console/short #04 asma-DEO2 - #0a .Console/char #04 asma-DEO - - ( right node ) - #0002 ADD2 ,asma-print-sublabels JSR - JMP2r - -@asma-print-labels ( incoming-ptr* -- ) - LDA2 - ORAk ,&valid-incoming-ptr JCN - POP2 JMP2r - - &valid-incoming-ptr - ( left node ) - DUP2 ,asma-print-labels JSR - ( here ) - DUP2 #0004 ADD2 - &loop - DUP2 #0001 ADD2 SWP2 LDA - DUP #00 EQU ,&end JCN - .Console/char #04 asma-DEO - ,&loop JMP - &end - POP - #09 .Console/char #04 asma-DEO - LDA2k .Console/short #04 asma-DEO2 - #0a .Console/char #04 asma-DEO - ( subtree ) - #0002 ADD2 ;asma-print-sublabels JSR2 - - ( right node ) - #0002 ADD2 ,asma-print-labels JSR - JMP2r - -( - Initialise the assembler state before loading a file or chunk. -) - -@asma-init-first-pass ( -- ) - #ff ;asma/pass STA - #0000 DUP2k - ;asma/error STA2 - ;asma-trees/labels STA2 - ;asma-trees/macros STA2 - ;asma-heap ;asma/heap STA2 - ;asma-opcodes/_entry ;asma-trees/opcodes STA2 - ( fall through ) - -@asma-init-next-pass ( -- ) - ;asma/pass LDA #01 ADD ;asma/pass STA - ;asma-write-buffer ;asma-output/ptr STA2 - #0000 DUP2k - ;asma-output/offset STA2 - ;asma/addr STA2 - ;asma/state STA - #01 ( 0001 ) - SWPk ( 0001 0100 ) ;asma/written-addr STA2 - ;asma/line STA2 - JMP2r - -( - Divide a file up into chunks, and pass each chunk to asma-assemble-chunk. -) - -@asma-assemble-file-pass ( filename-ptr* -- ) - #0000 - - &loop - OVR2 .File/name DEO2 - DUP2 .File/offset DEO2 - ;asma-read-buffer/end ;asma-read-buffer SUB2 STH2k .File/length DEO2 - ;asma-read-buffer DUP2k .File/load DEO2 - .File/success DEI2 - DUP2 STH2r SUB2 ORA ,&last-one JCN - ,asma-assemble-chunk JSR asma-IF-ERROR ,&error JCN - SUB2 SUB2 - ,&loop JMP - - &last-one - ADD2k #00 ROT ROT STA - #0001 ADD2 - ,asma-assemble-chunk JSR asma-IF-ERROR ,&error JCN - - ( flush output buffer ) - ;asma-output/ptr LDA2 ;asma-write-buffer SUB2 ;asma/flush-fn LDA2 JSR2 - - POP2 - &error - POP2 POP2 POP2 - JMP2r - -( - Assemble a chunk of source code, which begins with whitespace or the start - of a token and is divided up into tokens separated by whitespace. If the - chunk ends with whitespace, assembled-up-to-ptr* will equal ptr* + len* and - every token in the chunk will have been assembled. If the chunk ends with a - non-whitespace character, assembled-up-to-ptr* will point to the beginning - of the last token in the chunk. -) - -@asma-assemble-chunk ( ptr* len* -- assembled-up-to-ptr* ) - OVR2 ADD2 #0001 SUB2 SWP2 STH2k - ,&loop JMP - - &next-char-pop - POP - &next-char - #0001 ADD2 - &loop ( last-ptr* ptr* / start-of-token* ) - OVR2 OVR2 LTH2 ,&end JCN - LDAk ( last-ptr* ptr* char / start-of-token* ) - DUP #20 GTH ,&next-char-pop JCN - - #00 OVR2 ( last-ptr* ptr* char 00 ptr* / start-of-token* ) - STA - STH2r ,asma-assemble-token JSR asma-IF-ERROR ,&error JCN - - #0a NEQ ,¬-newline JCN - ;asma/line LDA2 #0001 ADD2 ;asma/line STA2 - ¬-newline - - DUP2 #0001 ADD2 STH2 ,&next-char JMP - - &end - POP2 POP2 STH2r - JMP2r - - &error - POP POP2 POP2 - JMP2r - -@asma [ &pass $1 &state $1 &line $2 &token $2 &orig-token $2 &heap $2 &addr $2 &written-addr $2 &flush-fn $2 &src-filename $2 &dest-filename $2 &error $2 ] -@asma-trees [ &labels $2 ¯os $2 &opcodes $2 &scope $2 ] - -( - The main routine to assemble a single token. - asma/state contains several meaningful bits: - 0x02 we are in a comment, - 0x04 we are in a macro body, and - 0x08 we are in a macro body that we are ignoring - (because the macro was already defined in a previous pass). - Since 0x08 never appears without 0x04, the lowest bit set in asma/state is - always 0x00, 0x02, or 0x04, which is very handy for use with jump tables. - The lowest bit set can be found easily by #00 (n) SUBk AND. -) - -@asma-assemble-token ( string-ptr* -- ) - DUP2 .Console/string #02 asma-DEO2 - #0a .Console/char #02 asma-DEO - DUP2 ;asma/token STA2 - DUP2 ;asma/orig-token STA2 - LDAk ,¬-empty JCN - POP2 - JMP2r - - ¬-empty ( token* / ) - ( truncate to one char long ) - #0001 ADD2 ( end* / ) - STH2k LDAkr ( end* / end* char ) - STH2k ( end* / end* char end* ) - LITr 00 STH2 ( / end* char end* 00 end* ) - STAr ( / end* char end* ) - - #00 ;asma/state LDA SUBk AND ( tree-offset* / end* ) - DUP2 ;&first-char-trees ADD2 ( tree-offset* incoming-ptr* / end* ) - ;asma-traverse-tree JSR2 - - ( restore truncated char ) - STAr - - ,¬-found JCN - - ( tree-offset* token-routine-ptr* / end* ) - STH2r ;asma/token STA2 - SWP2 POP2 LDA2 - JMP2 ( tail call ) - - ¬-found ( tree-offset* dummy* / end* ) - POP2 POP2r - ;&body-routines ADD2 LDA2 - JMP2 ( tail call ) - - &first-char-trees - :asma-first-char-normal/_entry - :asma-first-char-comment/_entry - :asma-first-char-macro/_entry - - &body-routines - :asma-normal-body - :asma-ignore - :asma-macro-body - -@asma-parse-hex-digit ( charcode -- 00-0f if valid hex - OR 10-ff otherwise ) - DUP #3a LTH ,&digit JCN - DUP #60 GTH ,&letter JCN - JMP2r - - &digit - #30 SUB - JMP2r - - &letter - #57 SUB - JMP2r - -@asma-parse-hex-string ( -- value* 06 if valid hex and length > 2 - OR value* 03 if valid hex and length <= 2 - OR 00 otherwise ) - ;asma/token LDA2 DUP2 ,asma-strlen JSR #02 GTH ROT ROT - LIT2r 0000 - - &loop - LDAk - DUP ,¬-end JCN - POP POP2 - STH2r ROT #01 ADD #03 MUL - JMP2r - - ¬-end - ,asma-parse-hex-digit JSR - DUP #f0 AND ,&fail JCN - LITr 40 SFT2r - #00 STH STH ADD2r - #0001 ADD2 - ,&loop JMP - - &fail - POP POP2 POP2r - DUP EOR - JMP2r - -@asma-strlen ( string-ptr* -- length ) - LITr 00 - - &loop - LDAk - ,¬-end JCN - POP2 STHr - JMP2r - - ¬-end - LITr 01 ADDr - #0001 ADD2 - ,&loop JMP - -%asma-SHORT-FLAG { #20 } -%asma-RETURN-FLAG { #40 } -%asma-KEEP-FLAG { #80 } - -@asma-parse-opcode ( -- byte 00 if valid opcode - OR 01 otherwise ) - ;asma/token LDA2 - DUP2 ,asma-strlen JSR #03 LTH ,&too-short JCN - - ( truncate to three chars long ) - #0003 ADD2 ( end* / ) - STH2k LDAkr ( end* / end* char ) - STH2k ( end* / end* char end* ) - LITr 00 STH2 ( / end* char end* 00 end* ) - STAr ( / end* char end* ) - - ;asma-trees/opcodes ;asma-traverse-tree JSR2 - STAr - ,¬-found JCN - - ;asma-opcodes/_disasm SUB2 #03 SFT2 ( 00 byte / end* ) - &loop - LDAkr STHr LIT2r 0001 ADD2r ( 00 byte char / end* ) - DUP ,¬-end JCN - POP POP2r - SWP - JMP2r - - ¬-end - DUP LIT '2 NEQ ,¬-two JCN - POP asma-SHORT-FLAG ORA ,&loop JMP - - ¬-two - DUP LIT 'r NEQ ,¬-return JCN - POP asma-RETURN-FLAG ORA ,&loop JMP - - ¬-return - LIT 'k NEQ ,¬-keep JCN - asma-KEEP-FLAG ORA ,&loop JMP - - ¬-keep ( 00 byte / end* ) - ¬-found ( incoming-ptr* / end* ) - POP2r - &too-short ( token* / ) - POP2 #01 - JMP2r - -@asma-write-short ( short -- ) - SWP - ,asma-write-byte JSR - ,asma-write-byte JMP ( tail call ) - -@asma-write-byte ( byte -- ) - ;asma/addr LDA2 ;asma/written-addr LDA2 - LTH2k ,&rewound JCN - &loop - EQU2k ,&ready JCN - #00 ,&write JSR - #0001 ADD2 - ,&loop JMP - - &rewound - ;asma-msg-rewound ;asma/error STA2 - POP2 POP2 POP JMP2r - - &ready - POP2 #0001 ADD2 - DUP2 ;asma/addr STA2 - ;asma/written-addr STA2 - - &write - ,asma-output/ptr LDR2 - DUP2 ;asma-write-buffer/end EQU2 ,&flush JCN - &after-flush - STH2k STA - STH2r #0001 ADD2 ,asma-output/ptr STR2 - - ( #3e .Console/char ;asma/pass LDA asma-DEO - #20 .Console/char ;asma/pass LDA asma-DEO - #00 .Console/byte ;asma/pass LDA asma-DEO - #0a .Console/char ;asma/pass LDA asma-DEO ) - JMP2r - - &flush ( ptr* -- start-of-buffer* ) - ;asma-write-buffer SUB2k ( ptr* start* len* ) - ;asma/flush-fn LDA2 JSR2 - SWP2 POP2 ( start* ) - ,&after-flush JMP - -@asma-output [ &ptr $2 &offset $2 &filename $2 ] - -@asma-flush-ignore ( len* -- ) - POP2 - JMP2r - -@asma-flush-to-file ( len* -- ) - DUP2 .File/length DEO2 - ,asma-output/offset LDR2 DUP2 .File/offset DEO2 ADD2 ,asma-output/offset STR2 - ;asma/dest-filename LDA2 .File/name DEO2 - ;asma-write-buffer .File/save DEO2 - JMP2r - -@asma-append-heap-byte ( dummy byte -- dummy ) - ;asma/heap LDA2 - OVR2 OVR2 STA POP - #0001 ADD2 ;asma/heap STA2 - POP - JMP2r - -@asma-append-heap-short ( dummy short* -- dummy ) - SWP - ,asma-append-heap-byte JSR - ,asma-append-heap-byte JMP ( tail call ) - -@asma-append-heap-string ( string* -- ) - LDAk - DUP ,asma-append-heap-byte JSR - ,&keep-going JCN - POP2 JMP2r - - &keep-going - #0001 ADD2 - ,asma-append-heap-string JMP - -@asma-traverse-tree ( incoming-ptr* -- binary-ptr* 00 if key found - OR node-incoming-ptr* 01 if key not found ) - &loop ( incoming-ptr* ) - LDA2k ORA ,&valid-node JCN - #01 JMP2r - - &valid-node - LDA2 STH2k - #0004 ADD2 ,asma-strcmp-tree JSR - DUP ,&nomatch JCN - POP2r JMP2r - - &nomatch - #06 SFT #02 AND #00 SWP - STH2r ADD2 - ,&loop JMP - - ( &help-str "Looking 20 "up 20 00 ) - -@asma-strcmp-tree ( node-key* -- order if strings differ - OR after-node-key* 00 if strings match ) - ;asma/token LDA2 STH2 - - &loop ( node-key* / token* ) - DUP2 #0001 ADD2 SWP2 LDA LDAkr STHr - ORAk ,¬-end JCN - - ( end of C strings, match found ) - POP2r POP - JMP2r - - ¬-end - SUB - DUP ,&nomatch JCN - POP - LIT2r 0001 ADD2r - ,&loop JMP - - &nomatch - POP2r ROT ROT POP2 - JMP2r - -( - First character routines. - The following routines (that don't have a FORTH-like signature) are called - to deal with tokens that begin with particular first letters, or (for - -body routines) tokens that fail to match any first letter in their tree. -) - -%asma-STATE-SET { ;asma/state LDA ORA ;asma/state STA } -%asma-STATE-CLEAR { #ff EOR ;asma/state LDA AND ;asma/state STA } - -@asma-comment-start - #02 asma-STATE-SET -@asma-ignore - JMP2r - -@asma-comment-end - #02 asma-STATE-CLEAR - JMP2r - -@asma-macro-define - ;asma/pass LDA ,&ignore-macro JCN - - ;asma-trees/macros ;asma-traverse-tree JSR2 ,¬-exist JCN - POP2 - ;asma-msg-macro ;asma/error STA2 - JMP2r - - ¬-exist - ( define macro by creating new node ) - ;asma/heap LDA2 SWP2 STA2 - #0000 ;asma-append-heap-short JSR2 ( less-than pointer ) - #0000 ;asma-append-heap-short JSR2 ( greater-than pointer ) - ;asma/token LDA2 ;asma-append-heap-string JSR2 ( key ) - #04 asma-STATE-SET - JMP2r - - &ignore-macro - #0c asma-STATE-SET - JMP2r - -@asma-macro-body - ;asma/state LDA #08 AND ,&skip JCN - ;asma/token LDA2 ;asma-append-heap-string JSR2 - &skip - JMP2r - -@asma-macro-end - #00 ;asma-append-heap-byte JSR2 - #0c asma-STATE-CLEAR - JMP2r - -@asma-label-define - ;asma-trees/labels ,asma-label-helper JSR - ,&already-existed JCN - - #0000 ;asma-append-heap-short JSR2 ( data2: subtree incoming ptr ) - - &already-existed - #0002 ADD2 ;asma-trees/scope STA2 - JMP2r - -@asma-sublabel-define - ;asma-trees/scope LDA2 ,asma-label-helper JSR - POP POP2 - JMP2r - -@asma-label-helper ( incoming-ptr* -- binary-ptr* 00 if label existed already - OR binary-ptr* 01 if label was created ) - ;asma-traverse-tree JSR2 - ,&new-label JCN - - ( label already exists ) - ( FIXME check label address hasn't changed (label defined twice) ) - #01 JMP2r - - &new-label ( incoming-ptr* ) - ( define label by creating new node ) - ;asma/heap LDA2 SWP2 STA2 - #0000 ;asma-append-heap-short JSR2 ( less-than pointer ) - #0000 ;asma-append-heap-short JSR2 ( greater-than pointer ) - ;asma/token LDA2 ;asma-append-heap-string JSR2 ( key ) - - ;asma/heap LDA2 - - ;asma/addr LDA2 ;asma-append-heap-short JSR2 ( data1: address ) - #00 JMP2r - -@asma-pad-absolute - #0000 ,asma-pad-helper JMP - -@asma-pad-relative - ;asma/addr LDA2 - ( fall through ) - -@asma-pad-helper ( offset* -- ) - ;asma-parse-hex-string JSR2 - ,&valid JCN - - ;asma-msg-hex ;asma/error STA2 - JMP2r - - &valid - ADD2 ;asma/addr STA2 - JMP2r - -@asma-raw-char - ;asma/token LDA2 LDA - ;asma-write-byte JMP2 ( tail call ) - -@asma-raw-word - ;asma/token LDA2 - - &loop - LDAk - DUP ,¬-end JCN - - POP POP2 - JMP2r - - ¬-end - ;asma-write-byte JSR2 - #0001 ADD2 - ,&loop JMP - -@asma-literal-abs-addr - LIT LIT2 ;asma-write-byte JSR2 - ( fall through ) - -@asma-abs-addr - ,asma-addr-helper JSR - ;asma-write-short JMP2 ( tail call ) - -@asma-literal-zero-addr - LIT LIT ;asma-write-byte JSR2 - ,asma-addr-helper JSR - ;asma-write-byte JSR2 - - ,¬-zero-page JCN - JMP2r - - ¬-zero-page - ;asma-msg-zero-page ;asma/error STA2 - JMP2r - -@asma-literal-rel-addr - LIT LIT ;asma-write-byte JSR2 - ,asma-addr-helper JSR ;asma/addr LDA2 SUB2 #0002 SUB2 - - DUP2 #0080 LTH2 STH - DUP2 #ff7f GTH2 STHr ORA ,&in-bounds JCN - - POP2 - ;asma-msg-relative ;asma/error STA2 - JMP2r - - &in-bounds - ;asma-write-byte JSR2 - POP - JMP2r - -@asma-addr-helper ( -- addr* ) - ;asma/token LDA2 LDAk #26 NEQ ,¬-local JCN - #0001 ADD2 ;asma/token STA2 - ;asma-trees/scope LDA2 - ,&final-lookup JMP - - ¬-local ( token* ) - LDAk - DUP ,¬-end JCN - POP POP2 - ;asma-trees/labels - ,&final-lookup JMP - - ¬-end ( token* char ) - #2f EQU ,&found-slash JCN - #0001 ADD2 - ,¬-local JMP - - &found-slash ( token* ) - DUP2 #00 ROT ROT STA - ;asma-trees/labels ;asma-traverse-tree JSR2 STH - SWP2 DUP2 #2f ROT ROT STA - STHr ,¬-found2 JCN - ( token* binary-ptr* ) - #0001 ADD2 ;asma/token STA2 - #0002 ADD2 - - &final-lookup ( addr-offset* incoming-ptr* ) - ;asma-traverse-tree JSR2 - ,¬-found JCN - LDA2 - JMP2r - - ¬-found2 ( dummy* dummy* ) - POP2 - ¬-found ( dummy* ) - POP2 - - ;asma/pass LDA #00 EQU ,&ignore-error JCN - ;asma-msg-label ;asma/error STA2 - &ignore-error - - ;asma/addr LDA2 - JMP2r - -@asma-literal-hex - ;asma-parse-hex-string JSR2 JMP - ( hex invalid ) ,&invalid JMP - ( hex byte ) ,asma-byte-helper JMP - ( hex short ) ,asma-short-helper JMP - - &invalid - ;asma-msg-hex ;asma/error STA2 - JMP2r - -@asma-byte-helper ( dummy value -- ) - LIT LIT ;asma-write-byte JSR2 - &raw - ;asma-write-byte JSR2 - POP - JMP2r - -@asma-short-helper ( value* -- ) - LIT LIT2 ;asma-write-byte JSR2 - &raw - ;asma-write-short JMP2 ( tail call ) - -@asma-normal-body - ;asma-parse-opcode JSR2 ,¬-opcode JCN - ;asma-write-byte JMP2 ( tail call ) - - ¬-opcode - ;asma-parse-hex-string JSR2 JMP - ( hex invalid ) ,¬-hex JMP - ( hex byte ) ,asma-byte-helper/raw JMP - ( hex short ) ,asma-short-helper/raw JMP - - ¬-hex - ;asma-trees/macros ;asma-traverse-tree JSR2 ,¬-macro JCN - - ¯o-loop - LDAk ,&keep-going JCN - &error - POP2 - JMP2r - - &keep-going - DUP2k ;asma-strlen JSR2 #00 SWP #0001 ADD2 ADD2 - SWP2 ;asma-assemble-token JSR2 asma-IF-ERROR ,&error JCN - ,¯o-loop JMP - - ¬-macro - POP2 - - ;asma-msg-label ;asma/error STA2 - 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 - -( trees ) - -( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- ) -( automatically generated code below ) -( see etc/asma.moon for instructions ) - -( label less greater key binary - than than string data ) - -@asma-first-char-comment - &_entry $2 $2 ') 00 :asma-comment-end - -@asma-first-char-macro - &28 $2 $2 '( 00 :asma-comment-start - &29 :&28 $2 ') 00 :asma-comment-end - &_entry :&29 :&7d '{ 00 :asma-ignore - &7d $2 $2 '} 00 :asma-macro-end - -@asma-first-char-normal - &22 $2 $2 '" 00 :asma-raw-word - &23 :&22 $2 '# 00 :asma-literal-hex - &24 :&23 :&25 '$ 00 :asma-pad-relative - &25 $2 $2 '% 00 :asma-macro-define - &26 :&24 :&29 26 00 ( & ) :asma-sublabel-define - &27 $2 $2 '' 00 :asma-raw-char - &28 :&27 $2 '( 00 :asma-comment-start - &29 :&28 :&2c ') 00 :asma-comment-end - &2c $2 $2 ', 00 :asma-literal-rel-addr - &_entry :&26 :&5d '. 00 :asma-literal-zero-addr - &3a $2 $2 ': 00 :asma-abs-addr - &3b :&3a $2 '; 00 :asma-literal-abs-addr - &40 :&3b :&5b '@ 00 :asma-label-define - &5b $2 $2 '[ 00 :asma-ignore - &5d :&40 :&7c '] 00 :asma-ignore - &7b $2 $2 '{ 00 :asma-ignore - &7c :&7b :&7d '| 00 :asma-pad-absolute - &7d $2 $2 '} 00 :asma-ignore - -@asma-opcodes - &BRK :&AND :&DEI &_disasm "BRK 00 - &_entry :&EQU :&ROT "LIT 00 - &NOP :&MUL :&OVR "NOP 00 - &POP $2 $2 "POP 00 - &DUP :&DIV :&EOR "DUP 00 - &SWP $2 $2 "SWP 00 - &OVR :&ORA :&POP "OVR 00 - &ROT :&NOP :&STR "ROT 00 - &EQU :&DEO :&JSR "EQU 00 - &NEQ $2 $2 "NEQ 00 - >H $2 $2 "GTH 00 - <H $2 $2 "LTH 00 - &JMP $2 $2 "JMP 00 - &JCN :>H :&JMP "JCN 00 - &JSR :&JCN :&LDR "JSR 00 - &STH $2 $2 "STH 00 - &LDZ $2 $2 "LDZ 00 - &STZ $2 $2 "STZ 00 - &LDR :&LDA :&LDZ "LDR 00 - &STR :&STA :&SUB "STR 00 - &LDA $2 $2 "LDA 00 - &STA :&SFT :&STH "STA 00 - &DEI $2 $2 "DEI 00 - &DEO :&BRK :&DUP "DEO 00 - &ADD $2 $2 "ADD 00 - &SUB :&STZ :&SWP "SUB 00 - &MUL :<H :&NEQ "MUL 00 - &DIV $2 $2 "DIV 00 - &AND :&ADD $2 "AND 00 - &ORA $2 $2 "ORA 00 - &EOR $2 $2 "EOR 00 - &SFT $2 $2 "SFT 00 - -( - Heap, a large temporary area for keeping track of labels. More complex - programs need more of this space. If there's insufficient space then the - assembly process will fail, but having extra space above what the most - complex program needs provides no benefit. - - This heap, and the buffers below, are free to be used to hold temporary - data between assembly runs, and do not need to be initialized with any - particular contents to use the assembler. -) - -@asma-heap - -|e000 &end - -( - Buffer for use with loading source code. - The minimum size is the length of the longest token plus one, which is - 0x21 to keep the same capability of the C assembler. - Larger sizes are more efficient, provided there is enough - heap space to keep track of all the labels. -) - -@asma-read-buffer - -|f800 &end - -( - Buffer for use with writing output. - The minimum size is 1, and larger sizes are more efficient. -) - -@asma-write-buffer - -|ffff &end -