( fix16.tal ) ( ) ( use a signed 16-bit short as a fixed point number. ) ( ) ( numbers are interpreted as fractions with an implicit ) ( 256 denominator. the upper byte is signed and ) ( represents the "whole" part of the number, and the ) ( lower byte is unsigned and represents the ) ( "fractional" part of the number. ) ( ) ( 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. ) ( ) ( 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 ) ( ) ( many 8.8 operations are equivalent to unsigned int16: ) ( * addition ) ( * subtraction ) ( or signed int16: ) ( * comparisons/equality ) ( ) ( but due to 16-bit truncation multiplication differs... ) ( ) ( x*y = x0*y0 + x0*y1/256 + x1*y0/256 + x1*y1/65536 ) ( ) ( since we only have 16-bits: ) ( 1. we need to drop the 8 high bits from x0*y0 ) ( 2. we need to drop the 8 low bits from x1*y1 ) ( 3. we need to use all the bits from x0*y1 and x1*y0 ) ( ) ( that said, if either x or y is whole (i.e. ends in 00) ) ( then we can just shift that argument right by 8 and use ) ( MUL2. ) ( ) ( similarly with division we have: ) ( ) ( x divided by #0100 -> x ) ( x divided by #0001 -> x * 256, with likely overfow ) ( #abcd divided by #1000 -> #0abc, rounding with d ) ( x divided by #0200 -> x >> 1 ) ( x divided by #0080 -> x << 1 ) %xyz { ;x16-emit JSR2 #0a #18 DEO } ( useful constants ) ( ) ( to generate your own: ) ( 1. take true value, e.g. 3.14159... ) ( 2. multiply by 256 ) ( 3. round to nearest whole number ) ( 4. emit hex output ) ( ) ( in python: hex(round(x * 256)) ) %x16-zero { #0000 } ( 0.0 ) %x16-one { #0100 } ( 1.0 ) %x16-two { #0200 } ( 2.0 ) %x16-ten { #0a00 } ( 10.0 ) %x16-hundred { #6400 } ( 100.0 ) %x16-minus-one { #7f00 } ( -1.0 ) %x16-minus-two { #7e00 } ( -2.0 ) %x16-pi/2 { #0192 } ( 1.57079... ) %x16-pi { #0324 } ( 3.14159... ) %x16-pi*2 { #0648 } ( 6.28318... ) %x16-e { #02b8 } ( 2.71828... ) %x16-phi { #019e } ( 1.61803... ) %x16-sqrt-2 { #016a } ( 1.41421... ) %x16-sqrt-3 { #01bb } ( 1.73205... ) %x16-epsilon { #0001 } ( 0.00390625 ) %x16-minimum { #8000 } ( -128.0 ) %x16-maximum { #7fff } ( 127.99609375 ) ( useful macros ) %x16-is-non-neg { x16-minimum LTH2 } %x16-is-neg { x16-maximum GTH2 } %x16-emit-dec { #30 ADD #18 DEO } |0100 x16-zero xyz x16-one xyz x16-two xyz x16-ten xyz x16-hundred xyz x16-pi/2 xyz x16-pi xyz x16-pi*2 xyz x16-e xyz x16-phi xyz x16-sqrt-2 xyz x16-sqrt-3 xyz x16-epsilon xyz #1234 xyz #7fff xyz #8000 xyz #8001 xyz #ffff xyz BRK @x16-emit ( x* -> ) DUP2 #8000 EQU2 ,&is-min JCN DUP2 #8000 GTH2 ,&is-neg JCN SWP DUP #64 LTH ,&<100 JCN #64 DIVk DUP x16-emit-dec MUL SUB ,&>=10 JMP &is-min POP2 LIT "- #18 DEO LIT "1 #18 DEO LIT "2 #18 DEO LIT "8 #18 DEO LIT ". #18 DEO LIT "0 #18 DEO LIT "0 #18 DEO LIT "0 #18 DEO JMP2r &is-neg LIT "- #18 DEO #ffff EOR2 INC2 ,x16-emit JMP &<100 DUP #0a LTH ,&<10 JCN &>=10 #0a DIVk DUP x16-emit-dec MUL SUB &<10 x16-emit-dec LIT '. #18 DEO ( emit fractional part ) #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 STH2k MUL2 SUB2 #0080 LTH2 ,&no-round JCN INC2r &no-round STH2r NIP x16-emit-dec JMP2r ( comparison between x and y. ) ( - ff: x < y ) ( - 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 ) ( unsigned comparison between x and y. ) ( - ff: x < y ) ( - 00: x = y ) ( - 01: x > y ) @x16-ucmp ( x* y* -> c^ ) LTH2k ,< JCN GTH2 JMP2r < POP2 POP2 #ff JMP2r @x16-eq ( x* y* -> x=y^ ) EQU2 JMP2r @x16-ne ( x* y* -> x!=0^ ) NEQ2 JMP2r @x16-lt ( x* y* -> x x x x bool^ ) NIP #00 EQU JMP2r @x16-add ( x* y* -> x+y* ) ADD2 JMP2r @x16-sub ( x* y* -> x-y* ) SUB2 JMP2r @x16-negate ( x* -> -x* ) #0000 SWP2 SUB2 JMP2r @x16-mul ( x* y* -> xy* ) DUP #00 EQU ,&rhs-whole JCN SWP2 DUP #00 EQU ,&rhs-whole JCN ,&y3 STR ,&y1 STR ,&x3 STR ,&x1 STR 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 &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 @x16-mod ( x* y* -> x%y* ) ;x16-div JSR2 ;x16-mul JSR2 SUB2 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