diff --git a/chr/ascii.chr b/chr/ascii.chr new file mode 100644 index 0000000..a85f905 Binary files /dev/null and b/chr/ascii.chr differ diff --git a/chr/ascii.tal b/chr/ascii.tal new file mode 100644 index 0000000..e21181e --- /dev/null +++ b/chr/ascii.tal @@ -0,0 +1,64 @@ + 7f 71 75 75 75 71 7f 00 7f 7d 7d 7d 7d 7d 7f 00 + 7f 71 7d 71 77 71 7f 00 7f 71 7d 71 7d 71 7f 00 + 7f 75 75 71 7d 7d 7f 00 7f 71 77 71 7d 71 7f 00 + 7f 71 77 71 75 71 7f 00 7f 71 7d 7d 7d 7d 7f 00 + 7f 71 75 71 75 71 7f 00 7f 71 75 71 7d 7d 7f 00 + 7f 7b 75 71 75 75 7f 00 7f 73 75 73 75 73 7f 00 + 7f 79 77 77 77 79 7f 00 7f 73 75 75 75 73 7f 00 + 7f 71 77 73 77 71 7f 00 7f 71 77 73 77 77 7f 00 + 7f 51 55 55 55 51 7f 00 7f 5d 5d 5d 5d 5d 7f 00 + 7f 51 5d 51 57 51 7f 00 7f 51 5d 51 5d 51 7f 00 + 7f 55 55 51 5d 5d 7f 00 7f 51 57 51 5d 51 7f 00 + 7f 51 57 51 55 51 7f 00 7f 51 5d 5d 5d 5d 7f 00 + 7f 51 55 51 55 51 7f 00 7f 51 55 51 5d 5d 7f 00 + 7f 5b 55 51 55 55 7f 00 7f 53 55 53 55 53 7f 00 + 7f 59 57 57 57 59 7f 00 7f 53 55 55 55 53 7f 00 + 7f 51 57 53 57 51 7f 00 7f 51 57 53 57 57 7f 00 + 00 00 00 00 00 00 00 00 18 18 18 18 18 00 18 00 + 66 66 66 00 00 00 00 00 66 66 ff 66 ff 66 66 00 + 18 3e 40 3c 02 7c 18 00 62 66 0c 18 30 66 46 00 + 3c 66 3c 38 67 66 3f 00 0c 18 30 00 00 00 00 00 + 0c 18 30 30 30 18 0c 00 30 18 0c 0c 0c 18 30 00 + 00 66 3c ff 3c 66 00 00 00 18 18 7e 18 18 00 00 + 00 00 00 00 18 18 30 00 00 00 00 7e 00 00 00 00 + 00 00 00 00 00 18 18 00 03 06 0c 18 30 60 c0 00 + 3c 66 6e 76 66 66 3c 00 18 18 38 18 18 18 7e 00 + 3c 66 06 0c 30 60 7e 00 3c 66 06 1c 06 66 3c 00 + 0c 1c 3c cc fe 0c 0c 00 7e 60 7c 06 06 66 3c 00 + 3c 66 60 7c 66 66 3c 00 7e 66 0c 18 18 18 18 00 + 3c 66 66 3c 66 66 3c 00 3c 66 66 3e 06 66 3c 00 + 00 00 18 00 18 00 00 00 00 00 18 00 18 18 30 00 + 0c 18 30 60 30 18 0c 00 00 00 7e 00 7e 00 00 00 + 30 18 0c 06 0c 18 30 00 3c 66 06 0c 18 00 18 00 + 3c 66 6e 6e 60 62 3c 00 18 3c 66 7e 66 66 66 00 + 7c 66 66 7c 66 66 7c 00 3c 66 60 60 60 66 3c 00 + 78 6c 66 66 66 6c 78 00 7e 60 60 78 60 60 7e 00 + 7e 60 60 78 60 60 60 00 3c 66 60 6e 66 66 3c 00 + 66 66 66 7e 66 66 66 00 3c 18 18 18 18 18 3c 00 + 1e 0c 0c 0c 0c 6c 38 00 66 6c 78 70 78 6c 66 00 + 60 60 60 60 60 60 7e 00 63 77 7f 6b 63 63 63 00 + 66 76 7e 7e 6e 66 66 00 3c 66 66 66 66 66 3c 00 + 7c 66 66 7c 60 60 60 00 3c 66 66 66 66 3c 0e 00 + 7c 66 66 7c 78 6c 66 00 3c 66 60 3c 06 66 3c 00 + 7e 18 18 18 18 18 18 00 66 66 66 66 66 66 3c 00 + 66 66 66 66 66 3c 18 00 63 63 63 6b 7f 77 63 00 + 66 66 3c 18 3c 66 66 00 66 66 66 3c 18 18 18 00 + 7e 06 0c 18 30 60 7e 00 3c 30 30 30 30 30 3c 00 + c0 60 30 18 0c 06 03 00 3c 0c 0c 0c 0c 0c 3c 00 + 00 18 3c 66 00 00 00 00 00 00 00 00 00 00 ff ff + 30 18 0c 00 00 00 00 00 00 00 3c 06 3e 46 3e 00 + 00 60 60 7c 66 66 7c 00 00 00 3c 60 60 60 3c 00 + 00 06 06 3e 66 66 3e 00 00 00 3c 66 7e 60 3c 00 + 00 0e 18 3e 18 18 18 00 00 00 3e 66 66 3e 06 7c + 00 60 60 7c 66 66 66 00 00 18 00 38 18 18 3c 00 + 00 06 00 06 06 06 06 3c 00 60 60 6c 78 6c 66 00 + 00 38 18 18 18 18 3c 00 00 00 66 7f 7f 6b 63 00 + 00 00 7c 66 66 66 66 00 00 00 3c 66 66 66 3c 00 + 00 00 7c 66 66 7c 60 60 00 00 3e 66 66 3e 06 06 + 00 00 7c 66 60 60 60 00 00 00 3e 60 3c 06 7c 00 + 00 18 7e 18 18 18 0e 00 00 00 66 66 66 66 3e 00 + 00 00 66 66 66 3c 18 00 00 00 63 6b 7f 3e 36 00 + 00 00 66 3c 18 3c 66 00 00 00 66 66 66 3e 0c 78 + 00 00 7e 0c 18 30 7e 00 1c 30 30 60 30 30 1c 00 + 18 18 18 18 18 18 18 18 38 0c 0c 06 0c 0c 38 00 + 3b 6e 00 00 00 00 00 00 7f 77 67 41 67 77 7f 00 diff --git a/chr/cyber.chr b/chr/cyber.chr new file mode 100644 index 0000000..8a16c7a Binary files /dev/null and b/chr/cyber.chr differ diff --git a/chr/cyber.tal b/chr/cyber.tal new file mode 100644 index 0000000..c62479e --- /dev/null +++ b/chr/cyber.tal @@ -0,0 +1,61 @@ + 80 40 20 10 08 04 02 01 80 40 20 10 08 04 02 01 + 80 40 20 10 08 04 02 01 01 02 04 08 10 20 40 80 + 01 02 04 08 10 20 40 80 01 02 04 08 10 20 40 80 + 80 80 80 80 80 80 80 80 01 01 01 01 01 01 01 01 + ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 80 40 20 10 08 04 02 01 c0 c0 20 10 08 04 02 01 + 80 40 20 10 08 04 03 03 01 02 04 08 10 20 40 80 + 03 03 04 08 10 20 40 80 01 02 04 08 10 20 c0 c0 + 40 40 40 40 40 40 40 40 02 02 02 02 02 02 02 02 + 00 ff 00 00 00 00 00 00 00 00 00 00 00 00 ff 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 80 40 20 10 08 04 02 01 a0 60 e0 10 08 04 02 01 + 80 40 20 10 08 07 06 05 01 02 04 08 10 20 40 80 + 05 06 07 08 10 20 40 80 01 02 04 08 10 e0 60 a0 + 20 20 20 20 20 20 20 20 04 04 04 04 04 04 04 04 + 00 00 ff 00 00 00 00 00 00 00 00 00 00 ff 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 80 40 20 10 08 04 02 01 90 50 30 f0 08 04 02 01 + 80 40 20 10 0f 0c 0a 09 01 02 04 08 10 20 40 80 + 09 0a 0c 0f 10 20 40 80 01 02 04 08 f0 30 50 90 + 10 10 10 10 10 10 10 10 08 08 08 08 08 08 08 08 + 00 00 00 ff 00 00 00 00 00 00 00 00 ff 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 80 40 20 10 08 04 02 01 88 48 28 18 f8 04 02 01 + 80 40 20 1f 18 14 12 11 01 02 04 08 10 20 40 80 + 11 12 14 18 1f 20 40 80 01 02 04 f8 18 28 48 88 + 08 08 08 08 08 08 08 08 10 10 10 10 10 10 10 10 + 00 00 00 00 ff 00 00 00 00 00 00 ff 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 80 40 20 10 08 04 02 01 84 44 24 14 0c fc 02 01 + 80 40 3f 30 28 24 22 21 01 02 04 08 10 20 40 80 + 21 22 24 28 30 3f 40 80 01 02 fc 0c 14 24 44 84 + 04 04 04 04 04 04 04 04 20 20 20 20 20 20 20 20 + 00 00 00 00 00 ff 00 00 00 00 ff 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 80 40 20 10 08 04 02 01 82 42 22 12 0a 06 fe 01 + 80 7f 60 50 48 44 42 41 01 02 04 08 10 20 40 80 + 41 42 44 48 50 60 7f 80 01 fe 06 0a 12 22 42 82 + 02 02 02 02 02 02 02 02 40 40 40 40 40 40 40 40 + 00 00 00 00 00 00 ff 00 00 ff 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 80 40 20 10 08 04 02 01 81 41 21 11 09 05 03 ff + ff c0 a0 90 88 84 82 81 01 02 04 08 10 20 40 80 + 81 82 84 88 90 a0 c0 ff ff 03 05 09 11 21 41 81 + 01 01 01 01 01 01 01 01 80 80 80 80 80 80 80 80 + 00 00 00 00 00 00 00 ff ff 00 00 00 00 00 00 00 diff --git a/ff.tal b/ff.tal index de6e166..0867030 100644 --- a/ff.tal +++ b/ff.tal @@ -36,7 +36,6 @@ #0cd5 .System/g DEO2 #0b66 .System/b DEO2 - ;draw-scene JSR2 ;draw-party-info JSR2 ;draw-menu JSR2 diff --git a/fix16.tal b/fix16.tal index aea9b64..700d143 100644 --- a/fix16.tal +++ b/fix16.tal @@ -10,23 +10,23 @@ ( ) ( 16-bit fixed point can represent fractional values ) ( in the range -128 <= x < 128. the smallest fraction it ) -( can represent is 1/256, which is about 0.004. ) +( can represent is 1/256, which is about 0.0039. ) ( ) ( SHORT FRACTION DECIMAL ) -( #0000 0/256 0.000 ) -( #0001 1/256 0.004 ) -( #0002 2/256 0.008 ) -( #0040 64/256 0.250 ) -( #0080 128/256 0.500 ) -( #0100 256/256 1.000 ) -( #0700 1792/256 7.000 ) -( #7f00 32512/256 127.000 ) -( #7fff 32767/256 127.996 ) -( #8000 -32768/256 -128.000 ) -( #8001 -32767/256 -127.996 ) -( #8100 -32767/256 -127.000 ) -( #ff00 -256/256 -1.000 ) -( #ffff -1/256 -0.004 ) +( #0000 0/256 0.0000 ) +( #0001 1/256 0.0039 ) +( #0002 2/256 0.0078 ) +( #0040 64/256 0.2500 ) +( #0080 128/256 0.5000 ) +( #0100 256/256 1.0000 ) +( #0700 1792/256 7.0000 ) +( #7f00 32512/256 127.0000 ) +( #7fff 32767/256 127.9961 ) +( #8000 -32768/256 -128.0000 ) +( #8001 -32767/256 -127.9961 ) +( #8100 -32767/256 -127.0000 ) +( #ff00 -256/256 -1.0000 ) +( #ffff -1/256 -0.0039 ) ( ) ( many 8.8 operations are equivalent to unsigned int16: ) ( * addition ) @@ -60,6 +60,7 @@ ( useful constants ) ( ) ( to generate your own: ) +( ) ( 1. take true value, e.g. 3.14159... ) ( 2. multiply by 256 ) ( 3. round to nearest whole number ) @@ -80,9 +81,10 @@ %x16-phi { #019e } ( 1.61803... ) %x16-sqrt-2 { #016a } ( 1.41421... ) %x16-sqrt-3 { #01bb } ( 1.73205... ) -%x16-epsilon { #0001 } ( 0.00390625 ) +%x16-epsilon { #0001 } ( 0.00390... ) %x16-minimum { #8000 } ( -128.0 ) -%x16-maximum { #7fff } ( 127.99609375 ) +%x16-maximum { #7fff } ( 127.99609... ) +%x16-max-whole { #7f00 } ( 127.0 ) ( useful macros ) %x16-is-non-neg { x16-minimum LTH2 } @@ -90,7 +92,7 @@ %x16-emit-dec { #30 ADD #18 DEO } -|0100 +( |0100 x16-zero xyz x16-one xyz x16-two xyz @@ -104,12 +106,27 @@ x16-sqrt-2 xyz x16-sqrt-3 xyz x16-epsilon xyz + #0002 xyz #1234 xyz #7fff xyz #8000 xyz #8001 xyz #ffff xyz - BRK + #0200 xyz + #0834 #0000 ;x16-add JSR2 xyz + #0834 #0834 ;x16-add JSR2 xyz + #0834 #0834 ;x16-mul JSR2 xyz + #0834 #0200 ;x16-div JSR2 xyz + #0100 xyz + #0003 xyz + #0100 #0003 ;x16-div JSR2 xyz + #0834 xyz + #0080 xyz + #0834 #0080 ;x16-div JSR2 xyz + #0834 xyz + #0300 xyz + #0834 #0300 ;x16-div JSR2 xyz + BRK ) @x16-emit ( x* -> ) DUP2 #8000 EQU2 ,&is-min JCN @@ -130,6 +147,7 @@ #00 SWP ( lo* ) #000a MUL2 #0100 DIV2k DUP2 NIP x16-emit-dec MUL2 SUB2 #000a MUL2 #0100 DIV2k DUP2 NIP x16-emit-dec MUL2 SUB2 + #000a MUL2 #0100 DIV2k DUP2 NIP x16-emit-dec MUL2 SUB2 #000a MUL2 #0100 DIV2k STH2k MUL2 SUB2 #0080 LTH2 ,&no-round JCN INC2r &no-round STH2r NIP x16-emit-dec JMP2r @@ -138,13 +156,12 @@ ( - 00: x = y ) ( - 01: x > y ) @x16-cmp ( x* y* -> c^ ) - STH2k x16-is-neg ,&yn JMP - x16-is-non-neg ,&ypxp ( y>=0 ) - POP2 POP2r #ff JMP2r ( x<0 y>=0 ) - &ypxp ;x16-ucmp JMP2 ( x>=0 y>=0 ) - &yn x16-is-neg ,&ynxn ( y<0 ) - POP2 POP2r #01 JMP2r ( x>=0 y<0 ) - &ynxn SWP2 ;x16-ucmp JMP2 ( x<0 y<0 ) + STH2k x16-is-neg ,&yn JCN ( x* [y*] ; ? ) + DUP2 x16-is-non-neg ,&same JCN ( x* [y*] ; y>=0 ) + POP2 POP2r #ff JMP2r ( -1 ; x<0 y>=0 ) + &yn DUP2 x16-is-neg ,&same JCN ( x* [y*] ; y<0 ) + POP2 POP2r #01 JMP2r ( 1 ; x>=0 y<0 ) + &same STH2r ;x16-ucmp JMP2 ( res ; x<0 y<0 b ) ( unsigned comparison between x and y. ) ( - ff: x < y ) @@ -180,79 +197,32 @@ LIT2 &x2 00 &x3 00 LIT2 &y2 00 &y3 00 MUL2 #08 SFT2 LIT2 &x0 00 &x1 00 ,&y2 LDR2 MUL2 ADD2 ,&x2 LDR2 LIT2 &y0 00 &y1 00 MUL2 ADD2 - ,&x0 LDR2 ,&x0 LDR2 MUL2 #80 SFT2 ADD2 JMP2r + ,&x0 LDR2 ,&y0 LDR2 MUL2 #80 SFT2 ADD2 JMP2r &rhs-whole #08 SFT2 MUL2 JMP2r @x16-div ( x* y* -> x/y* ) - SWP2 DUP2 x16-is-non-neg ,&non-negative ( y x ) - ;x16-negate JSR2 SWP2 DIV2 ;x16-negate JMP2 - &non-negative - SWP2 DIV2 JMP2r +( DUP ,¬-whole JCN + #08 SFT2 DIV2 JMP2r ( since y is whole, x/(y>>8) is correct ) + ¬-whole ) + DIV2k STH2k ( x y x/y {x/y} ) + LITr 80 SFT2r ( x y x/y {div=(x/y)<<8 ) + OVR2 STH2 ( x y x/y {y div} ) + MUL2 SUB2 ( x%y {y div} ) + STH2r LIT2r 0100 ( x%y y {0100 div} ) + ( we know x%y < y, so start right-shifting y ) + &loop + DUP2 #0000 EQU2 ,&done JCN + #01 SFT2 LITr 01 SFT2r ( rem yi {shifti div} ) + LTH2k ,&loop JCN ( rem yi {shifti div} ) + SWP2 OVR2 SUB2 SWP2 ( rem-yi yi {shifti div} ) + DUP2r ROT2r ADD2r SWP2r ( rem-yi yi {shifti div+shifti} ) + ,&loop JMP ( rem-yi yi {shifti div+shifti} ) + &done + POP2 POP2 ( {shiftk div} ) + POP2r STH2r JMP2r ( div ) -@x16-mod ( x* y* -> x%y* ) - ;x16-div JSR2 ;x16-mul JSR2 SUB2 JMP2r +@x16-quotient ( x* y* -> x//y* ) + DIV2 #80 SFT2 JMP2r -@x16-mod-div ( x* y* -> x%y* x/y* ) - ;x16-div JSR2 STH2k ;x16-mul JSR2 SUB2 STH2r JMP2r - -@x16-div-mod ( x* y* -> x/y* x%y* ) - ;x16-mod-div JSR2 SWP2 JMP2r - -( trigonometry ) -( ) -( this uses there different angle representations: ) -( ) -( 1. angle representation (#0080 = pi, #0100 = 2pi) ) -( 2. fix16 representation (#0324 = pi, #0648 = 2pi) ) -( 3. degrees (#00b4 = pi, #0168 = 2pi) ) -( ) -( angles are the most precise, but may require some ) -( conversion. ) - -( calculate the sin of the given angle. ) -( ) -( the input should be an angle and the ) -( result will be 16-bit fixed point. ) -( ) -( cos(x) = sin(x + pi/2) ) -@cos-angle ( x* -> cos(x)* ) - #0080 ADD2 ;sin-angle JMP2 - -( calculate the sin of the given angle. ) -( ) -( the input should be an angle and the ) -( result will be 16-bit fixed point. ) -( ) -( sin table offset math: ) -( 0 <= x < 64 -> table[x] ) -( 64 <= x < 128 -> table[127 - x] ) -( 128 <= x < 192 -> -table[x - 128] ) -( 192 <= x < 256 -> -table[255 - x] ) -@sin-angle ( x* -> sin(x)* ) - NIP DUP #7f GTH ,&d180+ JCN - #0001 STH2 - DUP #3f GTH ,&d90 ,&load JMP - &d90 #7f SWP SUB ,&load JMP - &d180+ - #ffff STH2 - DUP #bf GTH ,&d270 #80 SUB ,&load JMP - &d270 #ff SWP SUB ,&load JMP - &load ,sin-table ADD LDR2 STH2r MUL2 JMP2r - -( sin table with 64 entries for 1/4 of a unit circle. ) -( ) -( there is no need for interpolation when using ) -( angle values, since 256 distinct values can be ) -( produced using reflection. ) -( ) -( these table values go from 0 until pi/2 (i.e. from ) -( angles #00 until #80). ) -@sin-table ( 0 - pi/2: 64 steps ) - 0000 0006 000d 0013 0019 001f 0026 002c - 0032 0038 003e 0044 004a 0050 0056 005c - 0062 0068 006d 0073 0079 007e 0084 0089 - 008e 0093 0098 009d 00a2 00a7 00ac 00b1 - 00b5 00b9 00be 00c2 00c6 00ca 00ce 00d1 - 00d5 00d8 00dc 00df 00e2 00e5 00e7 00ea - 00ed 00ef 00f1 00f3 00f5 00f7 00f8 00fa - 00fb 00fc 00fd 00fe 00ff 00ff 0100 0100 +@x16-remainder ( x* y* -> x%y* ) + DIV2k MUL2 SUB2 JMP2r diff --git a/term.tal b/term.tal new file mode 100644 index 0000000..d4d15fb --- /dev/null +++ b/term.tal @@ -0,0 +1,254 @@ +|00 @System [ &vect $2 &pad $6 &r $2 &g $2 &b $2 ] +|10 @Console [ &vect $2 &r $1 &pad $5 &w $1 ] +|20 @Screen [ &vect $2 &w $2 &h $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ] +|80 @Controller [ &vect $2 &button $1 &key $1 ] + +|0000 + @dirty $1 ( screen needs redraw? ) + @tint $1 ( draw mode. 01=regular, 04=inverted ) + + @rows $2 ( height in characters ) + @cols $2 ( width in characters ) + + @cur-x $2 ( cursor x: 0 <= cur-x < cols ) + @cur-y $2 ( cursor y: 0 <= cur-y < rows ) + + @bg-frame $2 + @bg-counter $1 + +|0100 + ( 32 characters = 256 pixels ) + #0020 .rows STZ2 + #0040 .cols STZ2 + + ( set screen height/width based on rows/cols ) + .rows LDZ2 #30 SFT2 .Screen/h DEO2 + .cols LDZ2 #30 SFT2 .Screen/w DEO2 + + ( set colors ) + #0ff3 .System/r DEO2 + #0fd5 .System/g DEO2 + #2f66 .System/b DEO2 +( #08f3 .System/r DEO2 + #0cd5 .System/g DEO2 + #0b66 .System/b DEO2 ) + + ( clear screen for initial draw ) + ;clear-screen JSR2 + + ( draw background ) + #0000 .bg-frame STZ2 + #00 .bg-counter STZ +( #0000 ;draw-background JSR2 ) + + ( set up interrupts ) + ;redraw .Screen/vect DEO2 ( set up screen ) + ;on-key .Controller/vect DEO2 ( set up keyboard ) + + ( return ) + BRK + +@draw-background ( frame* -> ) + STH2 + + STH2kr #70 SFT2 ;cyber ADD2 #0048 ADD2 .Screen/addr DEO2 + LIT2r 000f LIT2 0000 + &loop1 + DUP2 #30 SFT2 .Screen/y DEO2 + DUP2 .cols LDZ2 OVR2 SUB2 ,hline JSR + INC2 DUP2 STH2kr LTH2 ,&loop1 JCN + POP2 POP2r + + STH2kr #70 SFT2 ;cyber ADD2 #0040 ADD2 .Screen/addr DEO2 + LIT2r 0020 LIT2 0011 + &loop2 + DUP2 #30 SFT2 .Screen/y DEO2 + .rows LDZ2 OVR2 INC2 SUB2 .cols LDZ2 OVR2 SUB2 ,hline JSR + INC2 DUP2 STH2kr LTH2 ,&loop2 JCN + POP2 POP2r + + POP2r JMP2r + +@dline ( n -> ) + #0000 SWP2 SUB2 STH2 + &loop + .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2 + .Screen/y DEI2 #0008 ADD2 .Screen/y DEO2 + #02 .Screen/sprite DEO + INC2r STH2kr ORA ,&loop JCN + POP2r JMP2r + +@hline ( x1 x2 -> ) + STH2 &loop + DUP2 #30 SFT2 .Screen/x DEO2 + #02 .Screen/sprite DEO + INC2 DUP2 STH2kr LTH2 ,&loop JCN + POP2 POP2r JMP2r + +@vline ( y1 y2 -> ) + STH2 &loop + DUP2 #30 SFT2 .Screen/y DEO2 + #02 .Screen/sprite DEO + INC2 DUP2 STH2kr LTH2 ,&loop JCN + POP2 POP2r JMP2r + +@clear-screen + #01 .dirty STZ + ;screen STH2 + #0000 &yloop + #0000 &xloop + #20 STH2kr STA INC2r + INC2 DUP2 .cols LDZ2 LTH2 ,&xloop JCN + POP2 + INC2 DUP2 .rows LDZ2 LTH2 ,&yloop JCN + POP2 POP2r + JMP2r + +@redraw + .bg-counter LDZ DUP ,&done-bg JCN + .bg-frame LDZ2 + ( DUP2 NIP LIT "a ADD #18 DEO #0a #18 DEO ) + DUP2 ;draw-background JSR2 + INC2 #0007 AND2 .bg-frame STZ2 + &done-bg + INC #03 AND .bg-counter STZ + + #41 .tint STZ + .dirty LDZ #00 EQU ,&done JCN + ;screen STH2 + #0000 DUP2 .Screen/y DEO2 + &yloop + #0000 DUP2 .Screen/x DEO2 + &xloop + STH2kr LDA ;draw-tile JSR2 + .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2 + INC2 INC2r + DUP2 .cols LDZ2 LTH2 ,&xloop JCN + POP2 + .Screen/y DEI2 #0008 ADD2 .Screen/y DEO2 + INC2 + DUP2 .rows LDZ2 LTH2 ,&yloop JCN + POP2 POP2r + + ;show-cursor JSR2 + #00 .dirty STZ + &done BRK + +@hide-cursor + #41 .tint STZ + ;draw-cursor JMP2 + +@show-cursor + #44 .tint STZ + ;draw-cursor JMP2 + +@draw-cursor + .cur-x LDZ2 #30 SFT2 .Screen/x DEO2 + .cur-y LDZ2 #30 SFT2 .Screen/y DEO2 + .cur-y LDZ2 .cols LDZ2 MUL2 .cur-x LDZ2 ADD2 ;screen ADD2 LDA + ;draw-tile JMP2 + +@on-key + .Controller/key DEI #00 EQU ,&skip JCN + .Controller/key DEI ;read JSR2 + &skip BRK + +@read ( byte^ -> ) + DUP #07 EQU ;read-bel JCN2 + DUP #08 EQU ;read-bs JCN2 + DUP #09 EQU ;read-tab JCN2 + DUP #0a EQU ;read-nl JCN2 + DUP #0d EQU ;read-cr JCN2 + DUP #1b EQU ;read-esc JCN2 + DUP #7f EQU ;read-del JCN2 + ;read-normal JMP2 + +@read-bel JMP2r +@read-bs POP ;scroll JMP2 +@read-tab POP POP2r #0000 DIV +@read-esc JMP2r +@read-del JMP2r + +@read-cr ( 0d -> ) + POP + ;hide-cursor JSR2 + #0000 .cur-x STZ2 + ;down JMP2 + +@read-nl ( 0a -> ) + ,read-cr JMP + +@forward ( -> ) + .cur-x LDZ2 INC2 DUP2 .cols LDZ2 LTH2 ,&ok JCN + POP2 #0000 .cur-x STZ2 ;down JMP2 + &ok .cur-x STZ2 + ;show-cursor JMP2 + +@down ( -> ) + .cur-y LDZ2 INC2 DUP2 .rows LDZ2 LTH2 ,&ok JCN + POP2 ;scroll JMP2 + &ok .cur-y STZ2 + ;show-cursor JMP2 + +@scroll + ;end-screen STH2 + ;screen .cols LDZ2 ADD2 STH2 + &loop + STH2kr LDA #20 STH2kr STA + STH2kr .cols LDZ2 SUB2 STA + INC2r GTH2kr STHr ,&loop JCN + POP2r POP2r + #01 .dirty STZ + ;show-cursor JMP2 + +@cursor-addr ( -> addr* ) + .cur-y LDZ2 .cols LDZ2 MUL2 + .cur-x LDZ2 ADD2 ;screen ADD2 + JMP2r + +@read-normal ( c -> ) + ;hide-cursor JSR2 + DUP ;cursor-addr JSR2 STA + ;draw-tile JSR2 + ;forward JMP2 + +( 0 <= c < 256 ) +@draw-tile ( c^ -> ) + DUP #80 LTH + ,draw-7bit JCN + ,draw-8bit JMP + +( 0 <= index < 128 ) +@load-tile ( index^ -> ) + #00 SWP #30 SFT2 + ;ascii ADD2 .Screen/addr DEO2 + JMP2r + +( 0 <= c < 128 ) +@draw-7bit ( c^ -> ) + ;load-tile JSR2 + .tint LDZ .Screen/sprite DEO + JMP2r + +( 128 <= c < 256 ) +@draw-8bit ( 8bit^ -> ) + #80 SUB ;load-tile JSR2 + .tint LDZ #05 EOR .Screen/sprite DEO + JMP2r + +( 128 1-bit 8x8 tiles for ASCII 7-bit characters ) +@ascii + ~chr/ascii.tal + +( cyber background ) +@cyber + ~chr/cyber.tal + +( screen to store characters for redraw, etc. ) +@screen $0800 ( 64 x 32 ) +@end-screen + +( northwest=10 north=40 northeast=28 ) +( west=30 center=56 east=38 ) +( southwest=20 south=48 southeast=08 ) +@bg-layout $0800 diff --git a/test-fix16.py b/test-fix16.py new file mode 100644 index 0000000..814aeb2 --- /dev/null +++ b/test-fix16.py @@ -0,0 +1,124 @@ +#!/usr/bin/python + +from math import floor, log +from os import environ +from random import randint +from subprocess import Popen, PIPE, run + +u8 = {'sz': 1 << 8, 'fmt': b'%02x'} +u16 = {'sz': 1 << 16, 'fmt': b'%04x'} +z16 = {'sz': 1 << 16, 'fmt': b'%04x'} + +def eq(got, expected): + return got == expected +def booleq(got, expected): + return bool(got) == bool(expected) +def releq(got, expected): + if (expected - 1) <= got and got <= (expected + 1): + return True + else: + error = abs(got - expected) / (abs(expected) + 0.001) + return error < 0.01 + +def testcase(p, sym, args, out, f, eq): + vals = [] + for name, g in args: + val = randint(0, g['sz'] - 1) + while val == 0 and g is z16: + val = randint(0, g['sz'] - 1) + vals.append((name, g, val)) + #vals = [(name, g, randint(0, g['sz'] - 1)) for (name, g) in args] + p.stdin.write(sym) + for _, g, x in vals: + p.stdin.write(g['fmt'] % x) + p.stdin.write(b'\n') + p.stdin.flush() + got = int(p.stdout.readline().strip().decode('utf-8'), 16) + xs = [x for _, _, x in vals] + z = f(*xs) + expected = z + if eq(got, expected): + return None + else: + res = {'got': got, 'expected': expected} + for name, _, x in vals: + res[name] = x + return res + +def test(p, trials, sym, args, out, f, eq=eq): + fails = 0 + cases = [] + for i in range(0, trials): + case1 = testcase(p, sym, args, out, f, eq) + if case1 is not None: + fails += 1 + cases.append(case1) + name = sym.decode('utf-8') + if fails == 0: + print('%s passed %d trials' % (name, trials)) + else: + print('%s failed %d/%d trials (%r)' % (name, fails, trials, cases)) + +def pipe(): + return Popen(['uxncli', 'run.rom'], stdin=PIPE, stdout=PIPE) + +def x16_add(x, y): + return (x + y) % 65536 +def x16_sub(x, y): + return (x - y) % 65536 +def x16_mul(x, y): + return ((x * y) // 256) % 65536 +def x16_div(x, y): + return ((x * 256) // y) % 65536 +def x16_quot(x, y): + return x16_div(x, y) & 0xff00 +def x16_rem(x, y): + return x % y +def x16_is_whole(x): + return int((x & 0xff) == 0) +def x16_negate(x): + if x == 32768 or x == 0: + return x + else: + return 65536 - x +def x16_eq(x, y): + return x == y +def x16_ne(x, y): + return x != y +def tosigned(x): + return x if x < 32768 else x - 65536 +def x16_lt(x, y): + return int(tosigned(x) < tosigned(y)) +def x16_gt(x, y): + return int(tosigned(x) > tosigned(y)) +def x16_lteq(x, y): + return int(tosigned(x) <= tosigned(y)) +def x16_gteq(x, y): + return int(tosigned(x) >= tosigned(y)) + +def main(): + trials = 100000 + run(['uxnasm', 'test-fix16.tal', 'run.rom']) + p = pipe() + test(p, trials, b'+', [('x', u16), ('y', u16)], u16, x16_add) + test(p, trials, b'-', [('x', u16), ('y', u16)], u16, x16_sub) + test(p, trials, b'*', [('x', u16), ('y', u16)], u16, x16_mul) + test(p, trials, b'/', [('x', u16), ('y', z16)], u16, x16_div, eq=releq) + test(p, trials, b'\\', [('x', u16), ('y', z16)], u16, x16_quot) + test(p, trials, b'%', [('x', u16), ('y', z16)], u16, x16_rem) + test(p, trials, b'w', [('x', u16)], u8, x16_is_whole, eq=booleq) + test(p, trials, b'N', [('x', u16)], u16, x16_negate) + test(p, trials, b'=', [('x', u16), ('y', u16)], u8, x16_eq) + test(p, trials, b'!', [('x', u16), ('y', u16)], u8, x16_ne) + test(p, trials, b'<', [('x', u16), ('y', u16)], u8, x16_lt) + test(p, trials, b'>', [('x', u16), ('y', u16)], u8, x16_gt) + test(p, trials, b'{', [('x', u16), ('y', u16)], u8, x16_lteq) + test(p, trials, b'}', [('x', u16), ('y', u16)], u8, x16_gteq) + p.stdin.write(b'\n\n') + p.stdin.flush() + p.stdin.close() + p.stdout.close() + p.kill() + +if __name__ == "__main__": + main() diff --git a/test-fix16.tal b/test-fix16.tal new file mode 100644 index 0000000..199897d --- /dev/null +++ b/test-fix16.tal @@ -0,0 +1,156 @@ +( test-fix16.tal ) +( ) +( testing uxntal words based on input/output bytes. ) +( ) +( this harness works best testing words that are "pure" ) +( in the sense that they read from the data stack and ) +( write results back onto the data stack. words which ) +( manipulate the return stack or read/write from devices ) +( may require something else. ) +( ) +( the model is as follows: ) +( ) +( - each test case is a line of text ending in a newline ) +( - lines starts with a character that selects a test ) +( - after that, 0 or more hexadecimal bytes are provided ) +( - the test runs ) +( - result is 0 or more hexadecimal bytes (or an error) ) +( - an empty line ends the test ) +( ) +( for example, the input "+12345678\n" would run a test ) +( selected by "+" with 4 input bytes on the stack: ) +( ) +( wst: 12 34 56 78 ) +( ) +( each case should be added to @interact, along with the ) +( number of bytes it expects to read and write. ) + +( program ) +|0100 ;interact #10 DEO2 BRK + +( include the code being tested ) +~fix16.tal + +( testing ) +@buf $33 ( line buffer, not including trailing newline ) +@pos $2 ( next position in buffer to write to ) + +( save character input and execute tests ) +( ) +( tests always start with a single character then ) +( additional arguments are passed as bytes before ) +( a terminating newline. ) +( ) +( the last byte read will be on the top of the stack ) +( and the earliest on the bottom. ) +@interact + #12 DEI ( read c ) + DUP #0a EQU ,&exec JCN ( exec if c is a newline ) + ;pos LDA2 ;buf ADD2 STA ( else write c to buf+pos ) + ;pos LDA2k INC2 SWP2 STA2 BRK ( increment pos ) + &exec POP ( ) + ;pos LDA2 #0000 EQU2 ;exit JCN2 ( exit on an empty line ) + ;buf LDA LIT "+ EQU ;test-x16-add JCN2 + ;buf LDA LIT "* EQU ;test-x16-mul JCN2 + ;buf LDA LIT "- EQU ;test-x16-sub JCN2 + ;buf LDA LIT "/ EQU ;test-x16-div JCN2 + ;buf LDA LIT "\ EQU ;test-x16-quotient JCN2 + ;buf LDA LIT "% EQU ;test-x16-remainder JCN2 + ;buf LDA LIT "w EQU ;test-x16-is-whole JCN2 + ;buf LDA LIT "N EQU ;test-x16-negate JCN2 + ;buf LDA LIT "= EQU ;test-x16-eq JCN2 + ;buf LDA LIT "! EQU ;test-x16-ne JCN2 + ;buf LDA LIT "< EQU ;test-x16-lt JCN2 + ;buf LDA LIT "> EQU ;test-x16-gt JCN2 + ;buf LDA LIT "{ EQU ;test-x16-lteq JCN2 + ;buf LDA LIT "} EQU ;test-x16-gteq JCN2 + LIT "? #18 DEO #0a #18 DEO ;reset JSR2 BRK + +( set the interpreter to exit now ) +@exit + #01 #0f DEO BRK + +( reads j bytes, emits k bytes ) +@test ( j^ k^ word* -> ) + STH2 STH STH ( {j k word} ) + ;buf INC2 STHr ( buf+1 j {k word} ) + ;read-bytes JSR2 ( {k word} ) + ROTr ROTr STH2r ( word {k} ) + JSR2 STHr ( k ) + ;emit-bytes JSR2 ( ) + #0a #18 DEO ( ) + ;reset JSR2 BRK ( ) + +( reset the interpreter to read another line ) +@reset ( -> ) + #0000 ;pos STA2 + #00 ;buf STA + JMP2r + +( different test executors ) +( ) +( TEST-NAME #IN #OUT WORD-TO-TEST HARNESS ) +@test-x16-add #04 #02 ;x16-add ;test JMP2 +@test-x16-mul #04 #02 ;x16-mul ;test JMP2 +@test-x16-sub #04 #02 ;x16-sub ;test JMP2 +@test-x16-div #04 #02 ;x16-div ;test JMP2 +@test-x16-quotient #04 #02 ;x16-quotient ;test JMP2 +@test-x16-remainder #04 #02 ;x16-remainder ;test JMP2 +@test-x16-is-whole #02 #01 ;x16-is-whole ;test JMP2 +@test-x16-negate #02 #02 ;x16-negate ;test JMP2 +@test-x16-eq #04 #01 ;x16-eq ;test JMP2 +@test-x16-ne #04 #01 ;x16-ne ;test JMP2 +@test-x16-lt #04 #01 ;x16-lt ;test JMP2 +@test-x16-lteq #04 #01 ;x16-lteq ;test JMP2 +@test-x16-gt #04 #01 ;x16-gt ;test JMP2 +@test-x16-gteq #04 #01 ;x16-gteq ;test JMP2 + +( reads one byte from ASCII: "13" -> 0x13 ) +@read-byte ( c0^ c1^ -> n^ ) + ( lower char ) + DUP #3a LTH ,&lo-digit JCN + #57 ,&lo JMP &lo-digit #30 + &lo SUB SWP + ( higher char ) + DUP #3a LTH ,&hi-digit JCN + #57 ,&hi JMP &hi-digit #30 + &hi SUB #40 SFT ORA + JMP2r + +( read k bytes from the buffer ) +@read-bytes ( addr* k^ -> ) + DUP ,&non-zero JCN ( addr k ) + POP POP2 JMP2r ( ) + &non-zero + STH STH2k ( addr {addr k} ) + LDA2 ;read-byte JSR2 ( byte {addr k} ) + STH2r #0002 ADD2 ( byte addr+2 {k} ) + STHr #01 SUB ( byte addr+2 k-1 ) + ,read-bytes JMP ( byte addr+2 k-1 ) + +( emit n bytes from the stack, earliest first ) +( ) +( examples: ) +( - #aa #bb #cc #03 will emit "aabbcc" ) +( - #aa #bb #01 will emit "bb" leaving aa on wst ) +( - #00 will emit nothing ) +@emit-bytes ( n -> ) + DUP + &loop ( n k {} ) + DUP #00 EQU ,&next JCN + ROT STH #01 SUB ( n k-1 ) + ,&loop JMP + &next ( n 0 {} ) + POP + &while ( n-i {} ) + DUP #00 EQU ,&done JCN + STHr ;emit JSR2 #01 SUB + ,&while JMP + &done + POP JMP2r + +( emit a single byte in hexadecimal notation ) +@emit + DUP #04 SFT ,&char JSR + &char #0f AND DUP #09 GTH #27 MUL ADD #30 ADD #18 DEO + JMP2r diff --git a/test-math32.py b/test-math32.py index 160bd68..8915697 100644 --- a/test-math32.py +++ b/test-math32.py @@ -60,7 +60,7 @@ def bitcount(x): def gcd(a, b): return a if b == 0 else gcd(b, a % b) - + def main(): trials = 100 run(['uxnasm', 'test-math32.tal', 'run.rom'])