From: David Griffith Date: Fri, 12 Jul 2019 20:55:33 +0000 (-0700) Subject: Adding the Praxix tests to test suite. X-Git-Url: https://scope-eye.net/git/?a=commitdiff_plain;h=e51dcacda4c2d3832c7d8962e4b1e0db6d3c2452;p=liskon_frotz.git Adding the Praxix tests to test suite. --- diff --git a/src/test/praxix.inf b/src/test/praxix.inf new file mode 100644 index 0000000..c3e3afa --- /dev/null +++ b/src/test/praxix.inf @@ -0,0 +1,2687 @@ +! Praxix - a Z-Machine unit test +! by Zarf and Dannii +! Public domain, but please share your changes so we can improve the tests + +! The indirect test is Copyright (C) 2003, Amir Karger + +! TODO: +! @encode_text +! @erase_line +! @get_cursor +! @set_font +! @call 0 +! @random - check it's a good distribution +! @print_table - check line breaks are only printed between lines +! Consider making this test suite non-interactive, and have another test suite for interactive tests +! Move too any tests which are manually confirmed by eye, so that all of Praxix can be summed up by "All tests passed" +! Maybe add tests for @loadw/@storew etc to check they are casting array+word correctly +! 1.1 spec unicode texts + +Constant Story "Praxix"; +Constant Headline "A Z-code interpreter unit test^"; +Release 1; + +! To compile this canonically, do "inform praxix.inf". No other +! options. + +Constant HDR_GAMERELEASE $02; ! word +Constant HDR_GAMEFLAGS $10; ! word +Constant HDR_GAMESERIAL $12; ! six ASCII characters +Constant HDR_SPECREVISION $32; ! word + +Array buffer -> 123; ! Buffer for parsing main line of input +Array parse buffer 63; ! Parse table mirroring it + +Global failures = 0; +Global total_failures = 0; + +[ Main ix; + ! deal with some compiler warnings + ix = PrintShortName; + + new_line; + Banner(); + new_line; + + LookSub(); + TestLoop(); + + print "^Goodbye.^"; +]; + +[ Keyboard; + while (true) { + print ">"; + buffer->0 = 120; + parse->0 = 15; + read buffer parse; + if (parse->1) + break; + } +]; + +[ Banner i; + if (Story ~= 0) { + #IfV5; style bold; #Endif; + print (string) Story; + #IfV5; style roman; #Endif; + } + if (Headline ~= 0) print ": ", (string) Headline; + print "Release ", (HDR_GAMERELEASE-->0) & $03ff, " / Serial number "; + for (i=0 : i<6 : i++) print (char) HDR_GAMESERIAL->i; + print " / Inform v"; inversion; + print ", compiler options "; + #Ifdef STRICT_MODE; + print "S"; + #Endif; ! STRICT_MODE + #Ifdef INFIX; + print "X"; + #Ifnot; + #Ifdef DEBUG; + print "D"; + #Endif; ! DEBUG + #Endif; ! INFIX + new_line; +]; + +[ Version; + ! Print the version number + print HDR_SPECREVISION->0, ".", HDR_SPECREVISION->1; +]; + +[ TestLoop wd paddr plen ix obj found; + while (true) { + new_line; + if (failures) { + print failures, " uncounted test failures!^^"; + failures = 0; + } + + Keyboard(); + wd = parse-->1; + + if (wd == 'quit' or 'q//') + return; + + found = nothing; + + objectloop (obj ofclass TestClass) { + paddr = obj.&name; + plen = obj.#name / WORDSIZE; + for (ix=0 : ixix == wd) { + found = obj; + break; + } + } + if (found) + break; + } + + if (~~found) { + print "I don't understand that command.^"; + continue; + } + + found.testfunc(); + } +]; + +Attribute meta; + +Class TestClass + with + short_name 0, + testfunc TestNothing, + fail_count; + +[ PrintShortName obj addr; + if (obj provides short_name && obj.short_name) { + print (string) obj.short_name; + rtrue; + } + if (obj ofclass TestClass) { + addr = obj.&name; + print (address) (addr-->0); + rtrue; + } + print (object) obj; +]; + +! Print out in base 16 a byte or word +[ Hex val byte nibble i; + print "$"; + for (i=0 : i<2 : i++) + { + @log_shift val (-8) -> byte; + @log_shift val (8) -> val; + if (byte == 0 && i == 0) + continue; + nibble = byte & $0F; + @log_shift byte (-4) -> byte; + if (byte <= 9) + print (char) (byte+'0'); + else + print (char) (byte-10+'A'); + if (nibble <= 9) + print (char) (nibble+'0'); + else + print (char) (nibble-10+'A'); + } +]; + +[ check val wanted; + if (val == wanted) { + print val; + rtrue; + } + failures++; + print val, " (should be ", wanted, " FAIL)"; + rfalse; +]; + +[ check_unspecified val wanted; + if (val == wanted) { + print val, " (Unspecified)"; + rtrue; + } + print val, " (Unspecified but ", wanted, " is suggested)"; + rfalse; +]; + +[ check_arr_3 arr v0 v1 v2; + if (arr->0 == v0 && arr->1 == v1 && arr->2 == v2) { + print v0, " ", v1, " ", v2; + rtrue; + } + failures++; + print arr->0, " ", arr->1, " ", arr->2; + print " (should be ", v0, " ", v1, " ", v2, " FAIL)"; + rfalse; +]; + +[ check_hex val wanted; + if (val == wanted) { + print (Hex) val; + rtrue; + } + failures++; + print (Hex) val, " (should be ", (Hex) wanted, " FAIL)"; + rfalse; +]; + +[ check_hex_unspecified val wanted; + if (val == wanted) { + print (Hex) val, " (Unspecified)"; + rtrue; + } + print (Hex) val, " (Unspecified but ", wanted, " is suggested)"; + rfalse; +]; + +[ check_hex_min val min; + if (val >= min) { + print (Hex) val; + rtrue; + } + failures++; + print (Hex) val, " (should be >= ", (Hex) min, " FAIL)"; + rfalse; +]; + +[ check_array test gold len func + ix testch goldch; + for (ix=0 : ixix; + testch = test->ix; + if (testch ~= goldch) { + func(goldch, ix); + check(testch, goldch); + new_line; + } + } +]; + +[ count_failures val; + print "^"; + if (failures) { + val = failures; + total_failures = total_failures + failures; + failures = 0; + print_ret val, " tests failed."; + } + else { + "Passed."; + } +]; + +TestClass LookAction + with name 'look' 'l//' 'help' '?//', + testfunc LookSub, + has meta; + +TestClass AllAction + with name 'all', + testfunc [ obj startfail res ix; + print "All tests:^"; + startfail = total_failures; + objectloop (obj ofclass TestClass) { + if (obj has meta) + continue; + + res = total_failures; + print "^"; + obj.testfunc(); + obj.fail_count = total_failures - res; + } + res = total_failures - startfail; + if (res == 0) { + "^All tests passed."; + } + else { + print "^", res, " tests failed overall: "; + ix = 0; + objectloop (obj ofclass TestClass) { + if (obj.fail_count) { + if (ix) + print ", "; + print (name) obj, " (", obj.fail_count, ")"; + ix++; + } + } + "."; + } + ], + has meta; + +[ TestNothing; + "Nothing happens."; +]; + +[ LookSub obj ix; + print "A voice booooms out: Welcome to the test chamber.^^"; + print "Type ~help~ to repeat this message, ~quit~ to exit, + ~all~ to run all tests, or one of the following test options: "; + + ix = 0; + objectloop (obj ofclass TestClass) { + if (obj has meta) + continue; + if (ix) print ", "; + print "~", (name) obj, "~"; + ix++; + } + print "."; + + print "^(Some tests check unspecified behaviour, and their results will be marked by (Unspecified).)^"; + + new_line; + if (total_failures) { + print "^", total_failures, " tests have failed so far in this run.^"; + } +]; + +Global testglobal; +Global testglobal2; + +TestClass OperandTest + with name 'operand', + testfunc [ ix val; + print "Basic operand values:^^"; + + testglobal = 1; + ix = 1; + val = (ix == testglobal); + print "(1==1)="; check(val, 1); print ", "; + val = (1 == testglobal); + print "(1==1)="; check(val, 1); print ", "; + val = (1 == ix); + print "(1==1)="; check(val, 1); print ", "; + @push 1; + val = 1; + @je 1 sp ?jump1; + val = 0; + .jump1; + print "(1==1)="; check(val, 1); print "^"; + + testglobal = -2; + ix = -2; + val = (ix == testglobal); + print "(-2==-2)="; check(val, 1); print ", "; + val = (-2 == testglobal); + print "(-2==-2)="; check(val, 1); print ", "; + val = (-2 == ix); + print "(-2==-2)="; check(val, 1); print ", "; + @push (-2); + val = 1; + @je (-2) sp ?jump2; + val = 0; + .jump2; + print "(-2==-2)="; check(val, 1); print "^"; + + count_failures(); + ]; + + +TestClass ArithTest + with name 'arith', + testfunc [ val; + print "Integer arithmetic:^^"; + + @add 2 2 val; + print "2+2="; check(val, 4); print ", "; + @add (-2) (-3) val; + print "-2+-3="; check(val, -5); print ", "; + @add 3 (-4) val; + print "3+-4="; check(val, -1); print ", "; + @add (-4) 5 val; + print "-4+5="; check(val, 1); print ", "; + @add $7FFF $7FFE val; + print "$7FFF+$7FFE="; check(val, -3); print ", "; + @add $8000 $8000 val; + print "$8000+$8000="; check(val, 0); print "^"; + testglobal = 6; testglobal2 = 8; + @add testglobal testglobal2 val; + print "Globals 6+8="; check(val, 14); print ", "; + testglobal = $7FFE; testglobal2 = $7FFD; + @add testglobal testglobal2 val; + print "$7FFE+$7FFD="; check(val, -5); print "^"; + + @sub 2 2 val; + print "2-2="; check(val, 0); print ", "; + @sub (-2) 3 val; + print "-2-3="; check(val, -5); print ", "; + @sub 3 4 val; + print "3-4="; check(val, -1); print ", "; + @sub (-4) (-5) val; + print "-4-(-5)="; check(val, 1); print ", "; + @sub $7FFF $7FFE val; + print "$7FFF-$7FFE="; check(val, 1); print ", "; + @sub $8000 $8001 val; + print "$8000-$8001="; check(val, -1); print ", "; + @sub $7FFF $8001 val; + print "$7FFF-$8001="; check(val, -2); print "^"; + testglobal = 6; testglobal2 = 8; + @sub testglobal testglobal2 val; + print "Globals 6-8="; check(val, -2); print ", "; + testglobal = $7FFD; testglobal2 = $7FFE; + @sub testglobal testglobal2 val; + print "$7FFD-$7FFE="; check(val, -1); print "^"; + + @mul 2 2 val; + print "2*2="; check(val, 4); print ", "; + @mul (-2) (-3) val; + print "-2*-3="; check(val, 6); print ", "; + @mul 3 (-4) val; + print "3*-4="; check(val, -12); print ", "; + @mul (-4) 5 val; + print "-4*5="; check(val, -20); print ", "; + @mul $100 $100 val; + print "$100*$100 (trunc)="; check(val, 0); print ", "; + @mul 311 373 val; + print "311*373 (trunc)="; check_hex(val, -15069); print "^"; + testglobal = -6; testglobal2 = -8; + @mul testglobal testglobal2 val; + print "Globals -6*-8="; check(val, 48); print ", "; + testglobal = -311; testglobal2 = 373; + @mul testglobal testglobal2 val; + print "Globals -311*373="; check(val, 15069); print "^"; + + @div 12 3 val; + print "12/3="; check(val, 4); print ", "; + @div 11 2 val; + print "11/2="; check(val, 5); print ", "; + @div (-11) 2 val; + print "-11/2="; check(val, -5); print ", "; + @div 11 (-2) val; + print "11/-2="; check(val, -5); print ", "; + @div (-11) (-2) val; + print "-11/-2="; check(val, 5); print ", "; + @div $7fff 2 val; + print "$7fff/2="; check_hex(val, $3fff); print ", "; + @div $7fff (-2) val; + print "$7fff/-2="; check_hex(val, -$3fff); print ", "; + @div (-$7fff) 2 val; + print "-$7fff/2="; check_hex(val, -$3fff); print ", "; + @div (-$7fff) (-2) val; + print "-$7fff/-2="; check_hex(val, $3fff); print ", "; + @div $8000 2 val; + print "$8000/2="; check_hex(val, $C000); print ", "; + @div $8000 (-2) val; + print "$8000/(-2)="; check_hex(val, $4000); print ", "; + @div $8000 1 val; + print "$8000/1="; check_hex(val, $8000); print "^"; + + testglobal = -48; testglobal2 = -8; + @div testglobal testglobal2 val; + print "Globals -48/-8="; check(val, 6); print ", "; + testglobal = 48; testglobal2 = 7; + @div testglobal testglobal2 val; + print "48/7="; check(val, 6); print ", "; + testglobal = 48; testglobal2 = -7; + @div testglobal testglobal2 val; + print "48/-7="; check(val, -6); print ", "; + testglobal = -48; testglobal2 = 7; + @div testglobal testglobal2 val; + print "-48/7="; check(val, -6); print ", "; + testglobal = -48; testglobal2 = -7; + @div testglobal testglobal2 val; + print "-48/-7="; check(val, 6); print "^"; + + @mod 12 3 val; + print "12%3="; check(val, 0); print ", "; + @mod 13 5 val; + print "13%5="; check(val, 3); print ", "; + @mod (-13) 5 val; + print "-13%5="; check(val, -3); print ", "; + @mod 13 (-5) val; + print "13%-5="; check(val, 3); print ", "; + @mod (-13) (-5) val; + print "-13%-5="; check(val, -3); print ", "; + @mod $7fff 11 val; + print "$7fff%11="; check(val, 9); print ", "; + @mod (-$7fff) 11 val; + print "-$7fff%11="; check(val, -9); print ", "; + @mod $7fff (-11) val; + print "$7fff%-11="; check(val, 9); print ", "; + @mod (-$7fff) (-11) val; + print "-$7fff%-11="; check(val, -9); print ", "; + @mod $8000 7 val; + print "$8000%7="; check(val, -1); print ", "; + @mod $8000 (-7) val; + print "$8000%-7="; check(val, -1); print ", "; + @mod $8000 2 val; + print "$8000%2="; check(val, 0); print ", "; + @mod $8000 (-2) val; + print "$8000%-2="; check(val, 0); print ", "; + @mod $8000 1 val; + print "$8000%1="; check(val, 0); print "^"; + + testglobal = 49; testglobal2 = 8; + @mod testglobal testglobal2 val; + print "Globals 49%8="; check(val, 1); print ", "; + testglobal = 49; testglobal2 = -8; + @mod testglobal testglobal2 val; + print "49%-8="; check(val, 1); print ", "; + testglobal = -49; testglobal2 = 8; + @mod testglobal testglobal2 val; + print "-49%8="; check(val, -1); print ", "; + testglobal = -49; testglobal2 = -8; + @mod testglobal testglobal2 val; + print "-49%-8="; check(val, -1); print "^"; + + count_failures(); + ]; + +TestClass CompoundArithTest + with name 'comarith' 'comparith', + testfunc [ val xloc yloc zloc; + print "Compound arithmetic expressions:^^"; + + testglobal = 7; + yloc = 2; + zloc = -4; + val = (testglobal + yloc) * zloc; + print "(7+2)*-4="; check(val, -36); print "^"; + + xloc = $7FFF; + yloc = 2; + zloc = 16; + val = (xloc + yloc) / zloc; + print "($7FFF+2)/16="; check(val, -$7FF); print "^"; + + xloc = -$7FFF; + yloc = -2; + zloc = 16; + val = (xloc + yloc) / zloc; + print "(-$7FFF+-2)/16="; check(val, $7FF); print "^"; + + xloc = -26103; + yloc = -32647; + val = (xloc + yloc) / 9; + print "(-26103+-32647)/9="; check(val, 754); print "^"; + + xloc = -$7FFF; + yloc = 2; + zloc = 16; + val = (xloc - yloc) / zloc; + print "(-$7FFF-2)/16="; check(val, $7FF); print "^"; + + xloc = $7FFF; + yloc = -2; + zloc = 16; + val = (xloc - yloc) / zloc; + print "($7FFF--2)/16="; check(val, -$7FF); print "^"; + + xloc = -26103; + yloc = 32647; + val = (xloc - yloc) / 9; + print "(-26103-32647)/9="; check(val, 754); print "^"; + + xloc = $100; + yloc = $100; + zloc = 16; + val = (xloc * yloc) / zloc + 1; + print "($100*$100)/16+1="; check(val, 1); print "^"; + + xloc = 311; + yloc = 373; + zloc = 16; + val = (xloc * yloc) / zloc; + print "(311*373)/16="; check(val, -941); print "^"; + + xloc = 311; + zloc = 16; + val = (xloc * -373) / zloc; + print "(311*-373)/16="; check(val, 941); print "^"; + + yloc = 373; + val = (111 * yloc) / 16; + print "(111*373)/16="; check(val, -1508); print "^"; + + yloc = -373; + val = (111 * yloc) / 16; + print "(111*-373)/16="; check(val, 1508); print "^"; + + count_failures(); + ]; + +TestClass BitwiseTest + with name 'bitwise' 'bits' 'bit', + testfunc [ val; + print "Bitwise arithmetic:^^"; + + @and 0 0 val; + print "0&0="; check_hex(val, 0); print ", "; + @and $FFFF 0 val; + print "$FFFF&0="; check_hex(val, 0); print ", "; + @and $FFFF $FFFF val; + print "$FFFF&$FFFF="; check_hex(val, $FFFF); print ", "; + @and $013F $F310 val; + print "$013F&$F310="; check_hex(val, $0110); print ", "; + @and $F731 $137F val; + print "$F731&$137F="; check_hex(val, $1331); print ", "; + @and $35 $56 val; + print "$35&56="; check_hex(val, $14); print "^"; + + @or 0 0 val; + print "0|0="; check_hex(val, 0); print ", "; + @or $FFFF 0 val; + print "$FFFF|0="; check_hex(val, $FFFF); print ", "; + @or $FFFF $FFFF val; + print "$FFFF|$FFFF="; check_hex(val, $FFFF); print ", "; + @or $3700 $0012 val; + print "$3700|$0012="; check_hex(val, $3712); print ", "; + @or $35 $56 val; + print "$35|56="; check_hex(val, $77); print "^"; + + @not 0 val; + print "!0="; check_hex(val, $FFFF); print ", "; + @not 1 val; + print "!1="; check_hex(val, $FFFE); print ", "; + @not $F val; + print "!$F="; check_hex(val, $FFF0); print ", "; + @not $7FFF val; + print "!$7FFF="; check_hex(val, $8000); print ", "; + @not $8000 val; + print "!$8000="; check_hex(val, $7FFF); print ", "; + @not $FFFD val; + print "!$FFFD="; check_hex(val, $2); print "^"; + + count_failures(); + ]; + +TestClass ShiftTest + with name 'shift', + testfunc [ val res ix; + print "Bit shifts:^^"; + + @log_shift $11 0 val; + print "$11u<<0="; check_hex(val, $11); print ", "; + @log_shift $11 1 val; + print "$11u<<1="; check_hex(val, $22); print ", "; + @log_shift $11 4 val; + print "$11u<<4="; check_hex(val, $110); print ", "; + @log_shift $11 10 val; + print "$11u<<10="; check_hex(val, $4400); print ", "; + @log_shift $11 15 val; + print "$11u<<15="; check_hex(val, $8000); print ", "; + @log_shift $11 16 val; + print "$11u<<16="; check_hex_unspecified(val, 0); print ", "; + @log_shift (-2) 0 val; + print "-2u<<0="; check(val, -2); print ", "; + @log_shift (-2) 1 val; + print "-2u<<1="; check(val, -4); print ", "; + @log_shift (-2) 7 val; + print "-2u<<7="; check(val, -256); print ", "; + @log_shift (-2) 15 val; + print "-2u<<15="; check(val, 0); print "^"; + + testglobal = 1; + res = 1; + for (ix=0 : ix<16 : ix++) { + @log_shift testglobal ix val; + print "1u<<", ix, "="; check_hex(val, res); print ", "; + res = res+res; + } + @log_shift testglobal ix val; + print "1u<<", ix, "="; check_hex_unspecified(val, 0); print "^"; + + @log_shift $4001 (0) val; + print "$4001u>>-0="; check_hex(val, $4001); print ", "; + @log_shift $4001 (-1) val; + print "$4001u>>-1="; check_hex(val, $2000); print ", "; + @log_shift $4001 (-6) val; + print "$4001u>>-6="; check_hex(val, $100); print ", "; + @log_shift $4001 (-11) val; + print "$4001u>>-11="; check_hex(val, $8); print ", "; + @log_shift $4001 (-15) val; + print "$4001u>>-15="; check_hex(val, $0); print ", "; + @log_shift $4001 (-16) val; + print "$4001u>>-16="; check_hex_unspecified(val, $0); print "^"; + + @log_shift $7FFF (0) val; + print "$7FFFu>>-0="; check_hex(val, $7FFF); print ", "; + @log_shift $7FFF (-1) val; + print "$7FFFu>>-1="; check_hex(val, $3FFF); print ", "; + @log_shift $7FFF (-2) val; + print "$7FFFu>>-2="; check_hex(val, $1FFF); print ", "; + @log_shift $7FFF (-6) val; + print "$7FFFu>>-6="; check_hex(val, $1FF); print ", "; + @log_shift $7FFF (-12) val; + print "$7FFFu>>-12="; check_hex(val, $7); print ", "; + @log_shift $7FFF (-15) val; + print "$7FFFu>>-15="; check_hex(val, $0); print ", "; + @log_shift $7FFF (-16) val; + print "$7FFFu>>-16="; check_hex_unspecified(val, $0); print "^"; + + @log_shift (-1) (0) val; + print "-1u>>-0="; check_hex(val, -1); print ", "; + @log_shift (-1) (-1) val; + print "-1u>>-1="; check_hex(val, $7FFF); print ", "; + @log_shift (-1) (-2) val; + print "-1u>>-2="; check_hex(val, $3FFF); print ", "; + @log_shift (-1) (-6) val; + print "-1u>>-6="; check_hex(val, $3FF); print ", "; + @log_shift (-1) (-12) val; + print "-1u>>-12="; check_hex(val, $F); print ", "; + @log_shift (-1) (-13) val; + print "-1u>>-13="; check_hex(val, $7); print ", "; + @log_shift (-1) (-15) val; + print "-1u>>-15="; check_hex(val, $1); print ", "; + @log_shift (-1) (-16) val; + print "-1u>>-16="; check_hex_unspecified(val, $0); print ", "; + @log_shift (-1) (-17) val; + print "-1u>>-17="; check_hex_unspecified(val, $0); print "^"; + + testglobal = -1; + res = $7fff; + for (ix=-1 : ix>-16 : ix--) { + @log_shift testglobal ix val; + print "-1u>>", ix, "="; check_hex(val, res); print ", "; + res = res / 2; + } + @log_shift testglobal ix val; + print "-1u>>", ix, "="; check_hex_unspecified(val, 0); print "^"; + + @art_shift $11 0 val; + print "$11s<<0="; check_hex(val, $11); print ", "; + @art_shift $11 1 val; + print "$11s<<1="; check_hex(val, $22); print ", "; + @art_shift $11 4 val; + print "$11s<<4="; check_hex(val, $110); print ", "; + @art_shift $11 10 val; + print "$11s<<10="; check_hex(val, $4400); print ", "; + @art_shift $11 15 val; + print "$11s<<15="; check_hex(val, $8000); print ", "; + @art_shift $11 16 val; + print "$11s<<16="; check_hex_unspecified(val, 0); print ", "; + @art_shift (-2) 0 val; + print "-2s<<0="; check(val, -2); print ", "; + @art_shift (-2) 1 val; + print "-2s<<1="; check(val, -4); print ", "; + @art_shift (-2) 7 val; + print "-2s<<7="; check(val, -256); print ", "; + @art_shift (-2) 15 val; + print "-2s<<15="; check(val, 0); print "^"; + + testglobal = 1; + res = 1; + for (ix=0 : ix<16 : ix++) { + @art_shift testglobal ix val; + print "1s<<", ix, "="; check_hex(val, res); print ", "; + res = res+res; + } + @art_shift testglobal ix val; + print "1s<<", ix, "="; check_hex_unspecified(val, 0); print "^"; + + @art_shift $4001 (0) val; + print "$4001s>>-0="; check_hex(val, $4001); print ", "; + @art_shift $4001 (-1) val; + print "$4001s>>-1="; check_hex(val, $2000); print ", "; + @art_shift $4001 (-6) val; + print "$4001s>>-6="; check_hex(val, $100); print ", "; + @art_shift $4001 (-11) val; + print "$4001s>>-11="; check_hex(val, $8); print ", "; + @art_shift $4001 (-15) val; + print "$4001s>>-15="; check_hex(val, $0); print ", "; + @art_shift $4001 (-16) val; + print "$4001s>>-16="; check_hex_unspecified(val, $0); print "^"; + + @art_shift $7FFF (0) val; + print "$7FFFs>>-0="; check_hex(val, $7FFF); print ", "; + @art_shift $7FFF (-1) val; + print "$7FFFs>>-1="; check_hex(val, $3FFF); print ", "; + @art_shift $7FFF (-2) val; + print "$7FFFs>>-2="; check_hex(val, $1FFF); print ", "; + @art_shift $7FFF (-6) val; + print "$7FFFs>>-6="; check_hex(val, $1FF); print ", "; + @art_shift $7FFF (-12) val; + print "$7FFFs>>-12="; check_hex(val, $7); print ", "; + @art_shift $7FFF (-13) val; + print "$7FFFs>>-13="; check_hex(val, $3); print ", "; + @art_shift $7FFF (-14) val; + print "$7FFFs>>-14="; check_hex(val, $1); print ", "; + @art_shift $7FFF (-15) val; + print "$7FFFs>>-15="; check_hex(val, $0); print ", "; + @art_shift $7FFF (-16) val; + print "$7FFFs>>-16="; check_hex_unspecified(val, $0); print "^"; + + @art_shift (-1) (0) val; + print "-1s>>-0="; check(val, -1); print ", "; + @art_shift (-1) (-1) val; + print "-1s>>-1="; check(val, -1); print ", "; + @art_shift (-1) (-15) val; + print "-1s>>-15="; check(val, -1); print ", "; + @art_shift (-1) (-16) val; + print "-1s>>-16="; check_hex_unspecified(val, -1); print ", "; + @art_shift (-1) (-17) val; + print "-1s>>-17="; check_hex_unspecified(val, -1); print "^"; + + @art_shift (-1000) (0) val; + print "-1000s>>-0="; check(val, -1000); print ", "; + @art_shift (-1000) (-1) val; + print "-1000s>>-1="; check(val, -500); print ", "; + @art_shift (-1000) (-2) val; + print "-1000s>>-2="; check(val, -250); print ", "; + @art_shift (-1000) (-4) val; + print "-1000s>>-4="; check(val, -63); print ", "; + @art_shift (-1000) (-6) val; + print "-1000s>>-6="; check(val, -16); print ", "; + @art_shift (-1000) (-9) val; + print "-1000s>>-9="; check(val, -2); print ", "; + @art_shift (-1000) (-15) val; + print "-1000s>>-15="; check(val, -1); print ", "; + @art_shift (-1000) (-16) val; + print "-1000s>>-16="; check_hex_unspecified(val, -1); print ", "; + @art_shift (-1000) (-17) val; + print "-1000s>>-17="; check_hex_unspecified(val, -1); print "^"; + + testglobal = -1; + for (ix=0 : ix>-16 : ix--) { + @art_shift testglobal ix val; + print "-1s>>", ix, "="; check(val, -1); print ", "; + } + @art_shift testglobal ix val; + print "-1s>>", ix, "="; check_hex_unspecified(val, -1); print "^"; + + count_failures(); + ]; + +TestClass IncrementTest + with name 'inc' 'dec' 'increment' 'decrement', + testfunc [ val; + print "Increment/decrement:^^"; + + val = 0; + @inc val; + print "0++="; check(val, 1); print ", "; + val = 1; + @inc val; + print "1++="; check(val, 2); print ", "; + val = -1; + @inc val; + print "-1++="; check(val, 0); print ", "; + val = -10; + @inc val; + print "-10++="; check(val, -9); print ", "; + val = $7FFF; + @inc val; + print "$7FFF++="; check_hex(val, $8000); print ", "; + val = $C000; + @inc val; + print "$C000++="; check_hex(val, $C001); print "^"; + + testglobal = 0; + @inc testglobal; + print "0++="; check(testglobal, 1); print ", "; + testglobal = 1; + @inc testglobal; + print "1++="; check(testglobal, 2); print ", "; + testglobal = -1; + @inc testglobal; + print "-1++="; check(testglobal, 0); print ", "; + testglobal = -10; + @inc testglobal; + print "-10++="; check(testglobal, -9); print ", "; + testglobal = $7FFF; + @inc testglobal; + print "$7FFF++="; check_hex(testglobal, $8000); print ", "; + testglobal = $C000; + @inc testglobal; + print "$C000++="; check_hex(testglobal, $C001); print "^"; + + @push 0; + @inc sp; + @pull val; + print "0++="; check(val, 1); print ", "; + @push 1; + @inc sp; + @pull val; + print "1++="; check(val, 2); print ", "; + @push -1; + @inc sp; + @pull val; + print "-1++="; check(val, 0); print ", "; + @push -10; + @inc sp; + @pull val; + print "-10++="; check(val, -9); print ", "; + @push $7FFF; + @inc sp; + @pull val; + print "$7FFF++="; check_hex(val, $8000); print ", "; + @push $C000; + @inc sp; + @pull val; + print "$C000++="; check_hex(val, $C001); print "^"; + + val = 0; + @dec val; + print "0--="; check(val, -1); print ", "; + val = 1; + @dec val; + print "1--="; check(val, 0); print ", "; + val = -1; + @dec val; + print "-1--="; check(val, -2); print ", "; + val = 10; + @dec val; + print "10--="; check(val, 9); print ", "; + val = $8000; + @dec val; + print "$8000--="; check_hex(val, $7FFF); print ", "; + val = $C000; + @dec val; + print "$C000--="; check_hex(val, $BFFF); print "^"; + + testglobal = 0; + @dec testglobal; + print "0--="; check(testglobal, -1); print ", "; + testglobal = 1; + @dec testglobal; + print "1--="; check(testglobal, 0); print ", "; + testglobal = -1; + @dec testglobal; + print "-1--="; check(testglobal, -2); print ", "; + testglobal = 10; + @dec testglobal; + print "10--="; check(testglobal, 9); print ", "; + testglobal = $8000; + @dec testglobal; + print "$8000--="; check_hex(testglobal, $7FFF); print ", "; + testglobal = $C000; + @dec testglobal; + print "$C000--="; check_hex(testglobal, $BFFF); print "^"; + + @push 0; + @dec sp; + @pull val; + print "0--="; check(val, -1); print ", "; + @push 1; + @dec sp; + @pull val; + print "1--="; check(val, 0); print ", "; + @push -1; + @dec sp; + @pull val; + print "-1--="; check(val, -2); print ", "; + @push 10; + @dec sp; + @pull val; + print "10--="; check(val, 9); print ", "; + @push $8000; + @dec sp; + @pull val; + print "$8000--="; check_hex(val, $7FFF); print ", "; + @push $C000; + @dec sp; + @pull val; + print "$C000--="; check_hex(val, $BFFF); print "^"; + + count_failures(); + ]; + +TestClass IncrementBranchTest + with name 'incchk' 'decchk' 'inccheck' 'deccheck', + testfunc [ val res; + print "Increment/decrement and branch:^^"; + + res = 0; + val = 1; + @inc_chk res 0 ?jump1a; + val = 0; + .jump1a; + print "++0="; check(res, 1); print ","; check(val, 1); print ", "; + + res = 1; + val = 1; + @inc_chk res 0 ?jump1b; + val = 0; + .jump1b; + print "++1="; check(res, 2); print ","; check(val, 1); print ", "; + + res = -1; + val = 1; + @inc_chk res 0 ?jump1c; + val = 0; + .jump1c; + print "++-1="; check(res, 0); print ","; check(val, 0); print ", "; + + res = 100; + val = 1; + @inc_chk res 0 ?jump1d; + val = 0; + .jump1d; + print "++100="; check(res, 101); print ","; check(val, 1); print ", "; + + res = -10; + val = 1; + @inc_chk res 0 ?jump1e; + val = 0; + .jump1e; + print "++-10="; check(res, -9); print ","; check(val, 0); print ", "; + + res = $7FFF; + val = 1; + @inc_chk res 0 ?jump1f; + val = 0; + .jump1f; + print "++$7FFF="; check_hex(res, $8000); print ","; check(val, 0); print ", "; + + res = $C000; + val = 1; + @inc_chk res 0 ?jump1g; + val = 0; + .jump1g; + print "++$C000="; check_hex(res, $C001); print ","; check(val, 0); print "^"; + + + testglobal2 = 0; + testglobal = 1; + @inc_chk testglobal2 0 ?jump2a; + testglobal = 0; + .jump2a; + print "++0="; check(testglobal2, 1); print ","; check(testglobal, 1); print ", "; + + testglobal2 = 1; + testglobal = 1; + @inc_chk testglobal2 0 ?jump2b; + testglobal = 0; + .jump2b; + print "++1="; check(testglobal2, 2); print ","; check(testglobal, 1); print ", "; + + testglobal2 = -1; + testglobal = 1; + @inc_chk testglobal2 0 ?jump2c; + testglobal = 0; + .jump2c; + print "++-1="; check(testglobal2, 0); print ","; check(testglobal, 0); print ", "; + + testglobal2 = 100; + testglobal = 1; + @inc_chk testglobal2 0 ?jump2d; + testglobal = 0; + .jump2d; + print "++100="; check(testglobal2, 101); print ","; check(testglobal, 1); print ", "; + + testglobal2 = -10; + testglobal = 1; + @inc_chk testglobal2 0 ?jump2e; + testglobal = 0; + .jump2e; + print "++-10="; check(testglobal2, -9); print ","; check(testglobal, 0); print ", "; + + testglobal2 = $7FFF; + testglobal = 1; + @inc_chk testglobal2 0 ?jump2f; + testglobal = 0; + .jump2f; + print "++$7FFF="; check_hex(testglobal2, $8000); print ","; check(testglobal, 0); print ", "; + + testglobal2 = $C000; + testglobal = 1; + @inc_chk testglobal2 0 ?jump2g; + testglobal = 0; + .jump2g; + print "++$C000="; check_hex(testglobal2, $C001); print ","; check(testglobal, 0); print "^"; + + + @push 0; + val = 1; + @inc_chk sp 0 ?jump3a; + val = 0; + .jump3a; + @pull res; + print "++0="; check(res, 1); print ","; check(val, 1); print ", "; + + @push 1; + val = 1; + @inc_chk sp 0 ?jump3b; + val = 0; + .jump3b; + @pull res; + print "++1="; check(res, 2); print ","; check(val, 1); print ", "; + + @push -1; + val = 1; + @inc_chk sp 0 ?jump3c; + val = 0; + .jump3c; + @pull res; + print "++-1="; check(res, 0); print ","; check(val, 0); print ", "; + + @push 100; + val = 1; + @inc_chk sp 0 ?jump3d; + val = 0; + .jump3d; + @pull res; + print "++100="; check(res, 101); print ","; check(val, 1); print ", "; + + @push -10; + val = 1; + @inc_chk sp 0 ?jump3e; + val = 0; + .jump3e; + @pull res; + print "++-10="; check(res, -9); print ","; check(val, 0); print ", "; + + @push $7FFF; + val = 1; + @inc_chk sp 0 ?jump3f; + val = 0; + .jump3f; + @pull res; + print "++$7FFF="; check_hex(res, $8000); print ","; check(val, 0); print ", "; + + @push $C000; + val = 1; + @inc_chk sp 0 ?jump3g; + val = 0; + .jump3g; + @pull res; + print "++$C000="; check_hex(res, $C001); print ","; check(val, 0); print "^"; + + + res = 0; + val = 1; + @dec_chk res 0 ?jump4a; + val = 0; + .jump4a; + print "--0="; check(res, -1); print ","; check(val, 1); print ", "; + + res = 1; + val = 1; + @dec_chk res 0 ?jump4b; + val = 0; + .jump4b; + print "--1="; check(res, 0); print ","; check(val, 0); print ", "; + + res = -1; + val = 1; + @dec_chk res 0 ?jump4c; + val = 0; + .jump4c; + print "---1="; check(res, -2); print ","; check(val, 1); print ", "; + + res = 100; + val = 1; + @dec_chk res 0 ?jump4d; + val = 0; + .jump4d; + print "--100="; check(res, 99); print ","; check(val, 0); print ", "; + + res = -10; + val = 1; + @dec_chk res 0 ?jump4e; + val = 0; + .jump4e; + print "---10="; check(res, -11); print ","; check(val, 1); print ", "; + + res = $8000; + val = 1; + @dec_chk res 0 ?jump4f; + val = 0; + .jump4f; + print "--$8000="; check_hex(res, $7FFF); print ","; check(val, 0); print ", "; + + res = $C000; + val = 1; + @dec_chk res 0 ?jump4g; + val = 0; + .jump4g; + print "--$C000="; check_hex(res, $BFFF); print ","; check(val, 1); print "^"; + + + testglobal2 = 0; + testglobal = 1; + @dec_chk testglobal2 0 ?jump5a; + testglobal = 0; + .jump5a; + print "--0="; check(testglobal2, -1); print ","; check(testglobal, 1); print ", "; + + testglobal2 = 1; + testglobal = 1; + @dec_chk testglobal2 0 ?jump5b; + testglobal = 0; + .jump5b; + print "--1="; check(testglobal2, 0); print ","; check(testglobal, 0); print ", "; + + testglobal2 = -1; + testglobal = 1; + @dec_chk testglobal2 0 ?jump5c; + testglobal = 0; + .jump5c; + print "---1="; check(testglobal2, -2); print ","; check(testglobal, 1); print ", "; + + testglobal2 = 100; + testglobal = 1; + @dec_chk testglobal2 0 ?jump5d; + testglobal = 0; + .jump5d; + print "--100="; check(testglobal2, 99); print ","; check(testglobal, 0); print ", "; + + testglobal2 = -10; + testglobal = 1; + @dec_chk testglobal2 0 ?jump5e; + testglobal = 0; + .jump5e; + print "---10="; check(testglobal2, -11); print ","; check(testglobal, 1); print ", "; + + testglobal2 = $8000; + testglobal = 1; + @dec_chk testglobal2 0 ?jump5f; + testglobal = 0; + .jump5f; + print "--$8000="; check_hex(testglobal2, $7FFF); print ","; check(testglobal, 0); print ", "; + + testglobal2 = $C000; + testglobal = 1; + @dec_chk testglobal2 0 ?jump5g; + testglobal = 0; + .jump5g; + print "--$C000="; check_hex(testglobal2, $BFFF); print ","; check(testglobal, 1); print "^"; + + + @push 0; + val = 1; + @dec_chk sp 0 ?jump6a; + val = 0; + .jump6a; + @pull res; + print "--0="; check(res, -1); print ","; check(val, 1); print ", "; + + @push 1; + val = 1; + @dec_chk sp 0 ?jump6b; + val = 0; + .jump6b; + @pull res; + print "--1="; check(res, 0); print ","; check(val, 0); print ", "; + + @push -1; + val = 1; + @dec_chk sp 0 ?jump6c; + val = 0; + .jump6c; + @pull res; + print "---1="; check(res, -2); print ","; check(val, 1); print ", "; + + @push 100; + val = 1; + @dec_chk sp 0 ?jump6d; + val = 0; + .jump6d; + @pull res; + print "--100="; check(res, 99); print ","; check(val, 0); print ", "; + + @push -10; + val = 1; + @dec_chk sp 0 ?jump6e; + val = 0; + .jump6e; + @pull res; + print "---10="; check(res, -11); print ","; check(val, 1); print ", "; + + @push $8000; + val = 1; + @dec_chk sp 0 ?jump6f; + val = 0; + .jump6f; + @pull res; + print "--$8000="; check_hex(res, $7FFF); print ","; check(val, 0); print ", "; + + @push $C000; + val = 1; + @dec_chk sp 0 ?jump6g; + val = 0; + .jump6g; + @pull res; + print "--$C000="; check_hex(res, $BFFF); print ","; check(val, 1); print "^"; + + + res = 50; + val = 1; + @inc_chk res 60 ?jumpxa; + val = 0; + .jumpxa; + print "++50="; check(res, 51); print ","; check(val, 0); print ", "; + + res = 70; + val = 1; + @inc_chk res 60 ?jumpxb; + val = 0; + .jumpxb; + print "++70="; check(res, 71); print ","; check(val, 1); print ", "; + + res = -50; + val = 1; + @inc_chk res (-60) ?jumpxc; + val = 0; + .jumpxc; + print "++-50="; check(res, -49); print ","; check(val, 1); print ", "; + + res = -70; + val = 1; + @inc_chk res (-60) ?jumpxd; + val = 0; + .jumpxd; + print "++-70="; check(res, -69); print ","; check(val, 0); print ", "; + + res = -50; + val = 1; + @inc_chk res 60 ?jumpxe; + val = 0; + .jumpxe; + print "++-50="; check(res, -49); print ","; check(val, 0); print ", "; + + res = 50; + val = 1; + @inc_chk res (-60) ?jumpxf; + val = 0; + .jumpxf; + print "++50="; check(res, 51); print ","; check(val, 1); print "^"; + + + res = 50; + val = 1; + @dec_chk res 60 ?jumpya; + val = 0; + .jumpya; + print "--50="; check(res, 49); print ","; check(val, 1); print ", "; + + res = 70; + val = 1; + @dec_chk res 60 ?jumpyb; + val = 0; + .jumpyb; + print "--70="; check(res, 69); print ","; check(val, 0); print ", "; + + res = -50; + val = 1; + @dec_chk res (-60) ?jumpyc; + val = 0; + .jumpyc; + print "---50="; check(res, -51); print ","; check(val, 0); print ", "; + + res = -70; + val = 1; + @dec_chk res (-60) ?jumpyd; + val = 0; + .jumpyd; + print "---70="; check(res, -71); print ","; check(val, 1); print ", "; + + res = -50; + val = 1; + @dec_chk res 60 ?jumpye; + val = 0; + .jumpye; + print "---50="; check(res, -51); print ","; check(val, 1); print ", "; + + res = 50; + val = 1; + @dec_chk res (-60) ?jumpyf; + val = 0; + .jumpyf; + print "--50="; check(res, 49); print ","; check(val, 0); print "^"; + + + count_failures(); + ]; + +Array array1 --> $1357 $FDB9 $0011 $FFEE; +Array array2 --> 4; + +TestClass ArrayTest + with name 'array' 'loadw' 'loadb' 'storew' 'storeb', + testfunc [ val ix addr; + print "Array loads and stores:^^"; + + addr = array1; + @loadw array1 0 -> val; + print "a-->0="; check_hex(val, $1357); print ", "; + @loadw addr 0 -> val; + print "a-->0="; check_hex(val, $1357); print ", "; + + ix = 1; + @loadw array1 ix -> val; + print "a-->1="; check_hex(val, $FDB9); print ", "; + @loadw addr ix -> val; + print "a-->1="; check_hex(val, $FDB9); print ", "; + + testglobal = 2; + @loadw array1 testglobal -> val; + print "a-->2="; check_hex(val, $0011); print ", "; + @loadw addr testglobal -> val; + print "a-->2="; check_hex(val, $0011); print ", "; + + @push 3; + @loadw array1 sp -> val; + print "a-->3="; check_hex(val, $FFEE); print ", "; + @push 3; + @loadw addr sp -> val; + print "a-->3="; check_hex(val, $FFEE); print "^"; + + addr = array1+3; + @loadw addr (-1) -> val; + print "a+3-->-1="; check_hex(val, $57FD); print ", "; + @loadw addr 0 -> val; + print "a+3-->0="; check_hex(val, $B900); print ", "; + @loadw addr 1 -> val; + print "a+3-->1="; check_hex(val, $11FF); print ", "; + testglobal = array1+3; + @loadw testglobal (-1) -> val; + print "a+3-->-1="; check_hex(val, $57FD); print ", "; + @loadw testglobal 0 -> val; + print "a+3-->0="; check_hex(val, $B900); print ", "; + @loadw testglobal 1 -> val; + print "a+3-->1="; check_hex(val, $11FF); print "^"; + + + addr = array1; + @loadb array1 0 -> val; + print "a->0="; check_hex(val, $13); print ", "; + @loadb addr 0 -> val; + print "a->0="; check_hex(val, $13); print ", "; + + ix = 1; + @loadb array1 ix -> val; + print "a->1="; check_hex(val, $57); print ", "; + @loadb addr ix -> val; + print "a->1="; check_hex(val, $57); print ", "; + + testglobal = 2; + @loadb array1 testglobal -> val; + print "a->2="; check_hex(val, $FD); print ", "; + @loadb addr testglobal -> val; + print "a->2="; check_hex(val, $FD); print ", "; + + @push 3; + @loadb array1 sp -> val; + print "a->3="; check_hex(val, $B9); print ", "; + @push 3; + @loadb addr sp -> val; + print "a->3="; check_hex(val, $B9); print "^"; + + addr = array1+3; + @loadb addr (-1) -> val; + print "a+3->-1="; check_hex(val, $FD); print ", "; + @loadb addr 0 -> val; + print "a+3->0="; check_hex(val, $B9); print ", "; + @loadb addr 1 -> val; + print "a+3->1="; check_hex(val, $00); print ", "; + testglobal = array1+3; + @loadb testglobal (-1) -> val; + print "a+3->-1="; check_hex(val, $FD); print ", "; + @loadb testglobal 0 -> val; + print "a+3->0="; check_hex(val, $B9); print ", "; + @loadb testglobal 1 -> val; + print "a+3->1="; check_hex(val, $00); print "^"; + + + addr = array2; + @storew array2 0 $1201; + @loadw array2 0 -> val; + print "a-->0="; check_hex(val, $1201); print ", "; + @storew addr 0 $2302; + @loadw array2 0 -> val; + print "a-->0="; check_hex(val, $2302); print ", "; + + ix = 1; + @storew array2 ix $3403; + @loadw array2 1 -> val; + print "a-->1="; check_hex(val, $3403); print ", "; + @storew addr ix $4504; + @loadw array2 1 -> val; + print "a-->1="; check_hex(val, $4504); print ", "; + + testglobal = 2; + @storew array2 testglobal $5605; + @loadw array2 2 -> val; + print "a-->2="; check_hex(val, $5605); print ", "; + @storew addr testglobal $6706; + @loadw array2 2 -> val; + print "a-->2="; check_hex(val, $6706); print ", "; + + @push 3; + @storew array2 sp $7807; + @loadw array2 3 -> val; + print "a-->3="; check_hex(val, $7807); print ", "; + @push 3; + @storew addr sp $8908; + @loadw array2 3 -> val; + print "a-->3="; check_hex(val, $8908); print "^"; + + addr = array2+4; + @storew addr (-1) $AB0A; + @loadw array2 1 -> val; + print "a-->-1="; check_hex(val, $AB0A); print ", "; + @storew addr 0 $BC0B; + @loadw array2 2 -> val; + print "a-->0="; check_hex(val, $BC0B); print ", "; + @storew addr 1 $CD0C; + @loadw array2 3 -> val; + print "a-->1="; check_hex(val, $CD0C); print ", "; + + testglobal = array2+4; + @storew testglobal (-1) $BA1B; + @loadw array2 1 -> val; + print "a-->-1="; check_hex(val, $BA1B); print ", "; + @storew testglobal 0 $CB1C; + @loadw array2 2 -> val; + print "a-->0="; check_hex(val, $CB1C); print ", "; + @storew testglobal 1 $DC1D; + @loadw array2 3 -> val; + print "a-->1="; check_hex(val, $DC1D); print "^"; + + + addr = array2; + @storeb array2 0 $12; + @loadb array2 0 -> val; + print "a->0="; check_hex(val, $12); print ", "; + @storeb addr 0 $23; + @loadb array2 0 -> val; + print "a->0="; check_hex(val, $23); print ", "; + + ix = 1; + @storeb array2 ix $34; + @loadb array2 1 -> val; + print "a->1="; check_hex(val, $34); print ", "; + @storeb addr ix $45; + @loadb array2 1 -> val; + print "a->1="; check_hex(val, $45); print ", "; + + testglobal = 2; + @storeb array2 testglobal $56; + @loadb array2 2 -> val; + print "a->2="; check_hex(val, $56); print ", "; + @storeb addr testglobal $67; + @loadb array2 2 -> val; + print "a->2="; check_hex(val, $67); print ", "; + + @push 3; + @storeb array2 sp $78; + @loadb array2 3 -> val; + print "a->3="; check_hex(val, $78); print ", "; + @push 3; + @storeb addr sp $89; + @loadb array2 3 -> val; + print "a->3="; check_hex(val, $89); print "^"; + + addr = array2+4; + @storeb addr (-1) $AB; + @loadb array2 3 -> val; + print "a->-1="; check_hex(val, $AB); print ", "; + @storeb addr 0 $BC; + @loadb array2 4 -> val; + print "a->0="; check_hex(val, $BC); print ", "; + @storeb addr 1 $CD; + @loadb array2 5 -> val; + print "a->1="; check_hex(val, $CD); print ", "; + + testglobal = array2+4; + @storeb testglobal (-1) $BA; + @loadb array2 3 -> val; + print "a->-1="; check_hex(val, $BA); print ", "; + @storeb testglobal 0 $CB; + @loadb array2 4 -> val; + print "a->0="; check_hex(val, $CB); print ", "; + @storeb testglobal 1 $DC; + @loadb array2 5 -> val; + print "a->1="; check_hex(val, $DC); print "^"; + + ix = $F1; + @storeb array2 0 ix; + ix = $E2; + @storeb array2 1 ix; + @loadw array2 0 -> val; + print "$F1 concat $E2 = "; check_hex(val, $F1E2); print "^"; + + ix = $9876; + @storew array2 1 ix; + @loadb array2 2 -> val; + print "$9876 = "; check_hex(val, $98); print " "; + @loadb array2 3 -> val; + print "concat "; check_hex(val, $76); print "^"; + + count_failures(); + ]; + +TestClass UndoTest + with name 'undo', + testfunc [ val loc; + print "Undo:^^"; + + val = HDR_GAMEFLAGS-->0; ! "Flags 2" byte + if (val & 16) + print "Interpreter claims to support undo.^^"; + else + print "Interpreter claims to not support undo. (Continuing test anyway...)^^"; + + print "Using a local variable for @@64save_undo result:^"; + loc = 99; + testglobal = 999; + @save_undo val; + if (val == -1) { + print "Undo is not available on this interpreter.^"; + count_failures(); + return; + } + if (val == 0) { + print "@@64save_undo failed!^"; + failures++; + count_failures(); + return; + } + if (val == 1) { + print "Undo saved...^"; + ! The following changes will be undone. + loc = 77; + testglobal = 777; + failures++; + print "Restoring undo...^"; + @restore_undo val; + if (val == 0) { + print "@@64restore_undo failed (value 0)!^"; + } + else { + print "@@64restore_undo failed with unknown return value: ", val, "^"; + } + failures++; + count_failures(); + return; + } + else if (val ~= 2) { + print "Unknown @@64save_undo return value: ", val, "^"; + failures++; + count_failures(); + return; + } + print "Undo succeeded, return value "; check(val, 2); print ".^"; + print "loc="; check(loc, 99); print " glob="; check(testglobal, 999); print "^"; + + print "Using a global variable for @@64save_undo result:^"; + loc = 98; + testglobal = 998; + @save_undo testglobal2; + if (testglobal2 == -1) { + print "Undo is not available on this interpreter.^"; + count_failures(); + return; + } + if (testglobal2 == 0) { + print "@@64save_undo failed!^"; + failures++; + count_failures(); + return; + } + if (testglobal2 == 1) { + print "Undo saved...^"; + ! The following changes will be undone. + loc = 77; + testglobal = 777; + failures++; + print "Restoring undo...^"; + @restore_undo testglobal2; + if (testglobal2 == 0) { + print "@@64restore_undo failed (value 0)!^"; + } + else { + print "@@64restore_undo failed with unknown return value: ", testglobal2, "^"; + } + failures++; + count_failures(); + return; + } + else if (testglobal2 ~= 2) { + print "Unknown @@64save_undo return value: ", testglobal2, "^"; + failures++; + count_failures(); + return; + } + print "Undo succeeded, return value "; check(testglobal2, 2); print ".^"; + print "loc="; check(loc, 98); print " glob="; check(testglobal, 998); print "^"; + + print "Calling @@64save_undo within a function or two:^"; + loc = 97; + testglobal = 997; + val = undo_depth_check(); + if (val == -1) { + print "Undo is not available on this interpreter.^"; + count_failures(); + return; + } + if (val == 0) { + print "@@64save_undo failed!^"; + failures++; + count_failures(); + return; + } + if (val == 1) { + print "Undo saved...^"; + ! The following changes will be undone. + loc = 77; + testglobal = 777; + failures++; + print "Restoring undo...^"; + @restore_undo val; + if (val == 0) { + print "@@64restore_undo failed (value 0)!^"; + } + else { + print "@@64restore_undo failed with unknown return value: ", val, "^"; + } + failures++; + count_failures(); + return; + } + else if (val ~= 2) { + print "Unknown @@64save_undo return value: ", val, "^"; + failures++; + count_failures(); + return; + } + print "Undo succeeded, return value "; check(val, 2); print ".^"; + print "loc="; check(loc, 97); print " glob="; check(testglobal, 997); print "^"; + @check_arg_count 3 ?~ok; + print "Error: test method wrongly got argument 3!^"; + failures++; + .ok; + + print "Using the stack for @@64save_undo result:^"; + loc = 98; + testglobal = 998; + testglobal2 = -99; + @save_undo sp; + @pull testglobal2; + if (testglobal2 == -1) { + print "Undo is not available on this interpreter.^"; + count_failures(); + return; + } + if (testglobal2 == 0) { + print "@@64save_undo failed!^"; + failures++; + count_failures(); + return; + } + if (testglobal2 == 1) { + print "Undo saved...^"; + ! The following changes will be undone. + loc = 77; + testglobal = 777; + testglobal2 = -99; + failures++; + print "Restoring undo...^"; + @restore_undo sp; + @pull testglobal2; + if (testglobal2 == 0) { + print "@@64restore_undo failed (value 0)!^"; + } + else { + print "@@64restore_undo failed with unknown return value: ", testglobal2, "^"; + } + failures++; + count_failures(); + return; + } + else if (testglobal2 ~= 2) { + print "Unknown @@64save_undo return value: ", testglobal2, "^"; + failures++; + count_failures(); + return; + } + print "Undo succeeded, return value "; check(testglobal2, 2); print ".^"; + print "loc="; check(loc, 98); print " glob="; check(testglobal, 998); print "^"; + + print "Checking @@64save_undo saves the stack correctly:^"; + @push 9; + loc = 99; + testglobal = 999; + testglobal2 = -999; + @save_undo val; + if (val == -1) { + print "Undo is not available on this interpreter.^"; + count_failures(); + return; + } + if (val == 0) { + print "@@64save_undo failed!^"; + failures++; + count_failures(); + return; + } + if (val == 1) { + print "Undo saved...^"; + ! The following changes will be undone. + loc = 77; + testglobal = 777; + testglobal2 = -777; + @pull val; + print "guard="; check(val, 9); print "^"; + val = 7; + failures++; + print "Restoring undo...^"; + @restore_undo testglobal2; + if (testglobal2 == 0) { + print "@@64restore_undo failed (value 0)!^"; + } + else { + print "@@64restore_undo failed with unknown return value: ", testglobal2, "^"; + } + failures++; + count_failures(); + return; + } + else if (val ~= 2) { + print "Unknown @@64save_undo return value: ", val, "^"; + failures++; + count_failures(); + return; + } + print "Undo succeeded, return value "; check(val, 2); print ".^"; + print "loc="; check(loc, 99); print " glob="; check(testglobal, 999); print " glob2="; check(testglobal2, -999); print "^"; + + @pull val; + print "guard="; check(val, 9); print "^"; + + count_failures(); + ]; + +[ undo_depth_check; + return undo_depth_check2(11, 22, 33); +]; + +[ undo_depth_check2 foo bar baz val; + bar = 1; + foo = bar; + baz = foo; + @save_undo val; + @check_arg_count 3 ?ok; + print "Error: undo_depth_check2 did not get argument 3!^"; + failures++; + .ok; + return val; +]; + +TestClass MultiUndoTest + with name 'multiundo', + testfunc [ val loc; + print "Multi-level undo:^(Note: this capability is not required by the spec.)^^"; + + val = HDR_GAMEFLAGS-->0; ! "Flags 2" byte + if (val & 16) + print "Interpreter claims to support undo.^^"; + else + print "Interpreter claims to not support undo. (Continuing test anyway...)^^"; + + loc = 99; + testglobal = 999; + @save_undo val; + if (val == -1) { + print "Undo is not available on this interpreter.^"; + count_failures(); + return; + } + if (val == 0) { + print "First @@64save_undo failed!^"; + failures++; + count_failures(); + return; + } + if (val == 1) { + print "Undo 1 saved...^"; + ! The following changes will be undone. + loc = 77; + testglobal = 777; + failures++; + + @save_undo val; + if (val == -1) { + print "Undo returned ~unavailable~, even though it was available the first time.^"; + count_failures(); + return; + } + if (val == 0) { + print "Second @@64save_undo failed! This interpreter apparently doesn't support multi-level undo. This should not be considered a bug.^"; + failures--; ! cancel the previous failure + count_failures(); + return; + } + if (val == 1) { + print "Undo 2 saved...^"; + ! The following changes will be undone. + loc = 55; + testglobal = 555; + failures++; + + print "Restoring undo 2...^"; + @restore_undo val; + if (val == 0) { + print "Second @@64restore_undo failed (value 0)!^"; + } + else { + print "Second @@64restore_undo failed with unknown return value: ", val, "^"; + } + failures++; + count_failures(); + return; + } + else if (val ~= 2) { + print "Unknown @@64save_undo return value: ", val, "^"; + failures++; + count_failures(); + return; + } + + print "Undo 2 succeeded, return value "; check(val, 2); print ".^"; + print "loc="; check(loc, 77); print " glob="; check(testglobal, 777); print "^"; + + print "Restoring undo 1...^"; + @restore_undo val; + if (val == 0) { + print "First @@64restore_undo failed (value 0)!^"; + } + else { + print "First @@64restore_undo failed with unknown return value: ", val, "^"; + } + failures++; + count_failures(); + return; + } + else if (val ~= 2) { + print "Unknown @@64save_undo return value: ", val, "^"; + failures++; + count_failures(); + return; + } + print "Undo 1 succeeded, return value "; check(val, 2); print ".^"; + print "loc="; check(loc, 99); print " glob="; check(testglobal, 999); print "^"; + + count_failures(); + ]; + +! The Indirect test is copied more-or-less whole from czech.inf +! (as of Oct 1 2010). Comments copied also: +! +! Indirect-able opcodes: inc, dec, inc_chk, dec_chk, store, pull, load +! Spec Version 1.1 (draft7): "an indirect reference to the stack +! pointer does not push or pull the top item of the stack - it is read +! or written in place." +! Based on my tests (see rec.arts.int-fiction 20031028), this seems to mean +! that, e.g., for load, you NEVER pop the stack, for all cases +! (a) load sp; (b) load [sp]; (c) i=0; load [i]; (d) sp=0; load [sp]; +! +! Overall rules: +! - Do NOT push/pop for "foo sp": write in place +! - DO pop for "foo [sp]". However, if top of stack is 0, only pop ONCE. +! - "bar = 0; foo [bar]" yields EXACTLY the same results as "foo sp" +! ("push 0; foo [sp] is also identical to "foo sp".) +! +TestClass IndirectTest + with name 'indirect', + testfunc [ ix; + print "Indirect opcodes:^^"; + + for (ix = 0: ix < 100: ix++) { + do_indirect_test(ix); + } + + count_failures(); + ]; + +[ do_indirect_test which + result local2 spointer lpointer rpointer + top_of_stack which_str expectr expect1 expect2; + + ! First, set up everything we're going to need. + + local2 = 51; + ! Gtemp = 61; + result = 71; + spointer = 0; ! stack + rpointer = 2; ! points to 'result' + lpointer = 3; ! local2 + ! gpointer = 21; ! '21' means 6th global, which is (hopefully!) Gtemp + expectr = 999; ! don't test 'result' unless we change this value + + @push 41; @push 42; @push 43; @push 44; @push 45; + switch (which) { + + ! load -> result + 0: + @load sp -> result; ! compiles as 'load 0 -> result' + expectr = 45; expect1 = 45; expect2 = 44; + which_str = "load sp -> result"; + 1: + @load [spointer] -> result; + expectr = 45; expect1 = 45; expect2 = 44; + which_str = "load [spointer] -> result"; + 2: + @push lpointer; @load [sp] -> result; + expectr = 51; expect1 = 45; expect2 = 44; + which_str = "load [sp=lpointer] -> result"; + 3: + @push spointer; @load [sp] -> result; + expectr = 45; expect1 = 45; expect2 = 44; + which_str = "load [sp=spointer] -> result"; + + ! load -> sp + 4: + @load sp -> sp; + expect1 = 45; expect2 = 45; + which_str = "load sp -> sp"; + 5: + @push lpointer; @load [sp] -> sp; + expect1 = 51; expect2 = 45; + which_str = "load [sp=lpointer] -> sp"; + 6: + @push spointer; @load [sp] -> sp; + expect1 = 45; expect2 = 45; + which_str = "load [sp=spointer] -> sp"; + + ! store + 10: + @store sp 83; + expect1 = 83; expect2 = 44; + which_str = "store sp 83"; + 11: + @store [spointer] 83; + expect1 = 83; expect2 = 44; + which_str = "store [spointer] 83"; + 12: + @push spointer; @store [sp] 83; + expect1 = 83; expect2 = 44; + which_str = "store [sp=spointer] 83"; + + 13: + @store [rpointer] 83; + expectr = 83; expect1 = 45; expect2 = 44; + which_str = "store [rpointer] 83"; + 14: + @push rpointer; @store [sp] 83; + expectr = 83; expect1 = 45; expect2 = 44; + which_str = "store [sp=rpointer] 83"; + + 15: + @store result sp; + expectr = 45; expect1 = 44; expect2 = 43; + which_str = "store result sp"; + 16: + @store sp sp; + expect1 = 45; expect2 = 43; + which_str = "store sp sp"; + 17: + @push spointer; @store [sp] sp; + expect1 = 45; expect2 = 43; + which_str = "store [sp=spointer] sp"; + + 18: + @store [rpointer] sp; + expectr = 45; expect1 = 44; expect2 = 43; + which_str = "store [rpointer] sp"; + 19: + @push rpointer; @store [sp] sp; + expectr = 45; expect1 = 44; expect2 = 43; + which_str = "store [sp=rpointer] sp"; + + ! pull + 20: + @pull result; + expectr = 45; expect1 = 44; expect2 = 43; + which_str = "pull result"; + 21: + @pull [rpointer]; + expectr = 45; expect1 = 44; expect2 = 43; + which_str = "pull [rpointer]"; + 22: + @push rpointer; @pull [sp]; + expectr = 45; expect1 = 44; expect2 = 43; + which_str = "pull [sp=rpointer]"; + + 23: + @pull sp; + expect1 = 45; expect2 = 43; + which_str = "pull sp"; + 24: + @push spointer; @pull [sp]; + expect1 = 45; expect2 = 43; + which_str = "pull [sp=spointer]"; + 25: + @pull [spointer]; + expect1 = 45; expect2 = 43; + which_str = "pull [spointer]"; + + ! inc + 30: + @inc result; + expectr = 72; expect1 = 45; expect2 = 44; + which_str = "inc result"; + 31: + @inc [rpointer]; + expectr = 72; expect1 = 45; expect2 = 44; + which_str = "inc [rpointer]"; + 32: + @push rpointer; @inc [sp]; + expectr = 72; expect1 = 45; expect2 = 44; + which_str = "inc [sp=rpointer]"; + + 33: + @inc sp; + expect1 = 46; expect2 = 44; + which_str = "inc sp"; + 34: + @inc [spointer]; + expect1 = 46; expect2 = 44; + which_str = "inc [spointer]"; + 35: + @push spointer; @inc [sp]; + expect1 = 46; expect2 = 44; + which_str = "inc [sp=spointer]"; + + ! dec + 40: + @dec result; + expectr = 70; expect1 = 45; expect2 = 44; + which_str = "dec result"; + 41: + @dec [rpointer]; + expectr = 70; expect1 = 45; expect2 = 44; + which_str = "dec [rpointer]"; + 42: + @push rpointer; @dec [sp]; + expectr = 70; expect1 = 45; expect2 = 44; + which_str = "dec [sp=rpointer]"; + + 43: + @dec sp; + expect1 = 44; expect2 = 44; + which_str = "dec sp"; + 44: + @dec [spointer]; + expect1 = 44; expect2 = 44; + which_str = "dec [spointer]"; + 45: + @push spointer; @dec [sp]; + expect1 = 44; expect2 = 44; + which_str = "dec [sp=spointer]"; + + ! inc_chk + 50: + which_str = "inc_chk result"; + @inc_chk result 72 ?bad_indirect_inc; + expectr = 72; expect1 = 45; expect2 = 44; + 51: + which_str = "inc_chk [rpointer]"; + @inc_chk [rpointer] 72 ?bad_indirect_inc; + expectr = 72; expect1 = 45; expect2 = 44; + 52: + which_str = "inc_chk [sp=rpointer]"; + @push rpointer; @inc_chk [sp] 72 ?bad_indirect_inc; + expectr = 72; expect1 = 45; expect2 = 44; + + 53: + which_str = "inc_chk sp"; + @inc_chk sp 46 ?bad_indirect_inc; + expect1 = 46; expect2 = 44; + 54: + which_str = "inc_chk [spointer]"; + @inc_chk [spointer] 46 ?bad_indirect_inc; + expect1 = 46; expect2 = 44; + 55: + which_str = "inc_chk [sp=spointer]"; + @push spointer; @inc_chk [sp] 46 ?bad_indirect_inc; + expect1 = 46; expect2 = 44; + + ! dec_chk + 60: + which_str = "dec_chk result"; + @dec_chk result 70 ?bad_indirect_inc; + expectr = 70; expect1 = 45; expect2 = 44; + 61: + which_str = "dec_chk [rpointer]"; + @dec_chk [rpointer] 70 ?bad_indirect_inc; + expectr = 70; expect1 = 45; expect2 = 44; + 62: + which_str = "dec_chk [sp=rpointer]"; + @push rpointer; @dec_chk [sp] 70 ?bad_indirect_inc; + expectr = 70; expect1 = 45; expect2 = 44; + + 63: + which_str = "dec_chk sp"; + @dec_chk sp 44 ?bad_indirect_inc; + expect1 = 44; expect2 = 44; + 64: + which_str = "dec_chk [spointer]"; + @dec_chk [spointer] 44 ?bad_indirect_inc; + expect1 = 44; expect2 = 44; + 65: + which_str = "dec_chk [sp=spointer]"; + @push spointer; @dec_chk [sp] 44 ?bad_indirect_inc; + expect1 = 44; expect2 = 44; + + default: + rfalse; ! no test here; do nothing. + } + + ! Test results + print (string) which_str, ": "; + @je expectr 999 ?skip_expectr; + check(result, expectr); print ", "; + .skip_expectr; + @pull top_of_stack; + check(top_of_stack, expect1); print ", "; + @pull top_of_stack; + check(top_of_stack, expect2); + + new_line; + rtrue; + + ! If you got here, inc_chk/dec_chk broke + .bad_indirect_inc; + print (string) which_str, ": "; + check(result, 123); + new_line; + rfalse; +]; + +! The lengths here must exceed the number of characters printed (below) +! by at least 3. +Array streambuf -> 170; +Array streambufcmp -> 170; + +! The StreamTrip test sends every legal, printable ZSCII character to +! a memory stream, and then reads them back. They should all survive +! the journey unscathed. +! +! Note that character 9 (tab) and 10 (unix newline) are not legal for +! output. (Despite the fact that Zork 1 uses tabs for indenting +! the temple book's text.) (Tab is legal in V6, but this test is for +! v5/8.) +! +! Printing character 0 is legal, but doesn't generate output. It should +! not count towards the stream count either. (See 3.8.2.1.) +! +TestClass StreamTripTest + with name 'streamtrip', + short_name "streamtrip", + testfunc [ ix len pos; + print "Memory stream round-trip:^^"; + + @output_stream 3 streambuf; + pos = 0; + @print_char 13; ! newline + streambufcmp->pos = 13; pos++; + for (ix=32 : ix <= 126 : ix++) { + streambufcmp->pos = ix; pos++; + @print_char ix; + } + for (ix=155 : ix <= 223 : ix++) { + streambufcmp->pos = ix; pos++; + @print_char ix; + } + ! no streambufcmp output for the no-op + @print_char 0; ! no-op + @print_char 64; ! @-sign + streambufcmp->pos = 64; pos++; + @output_stream -3; + + ix = streambuf; + len = ix-->0; + print "Number of characters written: "; check(pos, 166); new_line; + print "Number of characters read: "; check(len, 166); new_line; + + check_array( streambuf+2, streambufcmp, len, Streamtripprint ); + + count_failures(); + ]; + +[ Streamtripprint ch; + print "Mismatch for ", ch, " '"; + @print_char ch; + print "': "; +]; + +TestClass StreamOpTest + with name 'streamop', + short_name "streamop", + testfunc [ len; + print "Memory stream opcodes:^^"; + + @output_stream 3 streambuf; + @print_paddr "abc"; + @output_stream -3; + + len = (streambuf+0)-->0; + print "@@64print_paddr: "; + check(len, 3); print " characters written: "; + check_arr_3(streambuf+2, 'a', 'b', 'c'); new_line; + + @output_stream 3 streambuf; + @print_num 789; + @output_stream -3; + + len = (streambuf+0)-->0; + print "@@64print_num: "; + check(len, 3); print " characters written: "; + check_arr_3(streambuf+2, '7', '8', '9'); new_line; + + @output_stream 3 streambuf; + @print_char 'x'; + @output_stream -3; + + len = (streambuf+0)-->0; + print "@@64print_char: "; + check(len, 1); print " characters written: "; + check_arr_3(streambuf+2, 'x', '8', '9'); new_line; + + count_failures(); + ]; + +TestClass Throwcatch + with name 'throwcatch' 'throw' 'catch', + short_name "throwcatch", + testfunc [ val; + print "@@64throw/@@64catch:^^"; + + testglobal = 0; + testglobal2 = 0; + + val = Throwfunc1(); + + print "The function with @@64catch will be returned with the value of @@64throw: "; check(val, 1); print "^"; + print "Intermediate functions should not set their storers.^testglobal="; check(testglobal, 0); print "^"; + print "testglobal2="; check(testglobal2, 0); print "^"; + + count_failures(); + ]; + +[ Throwfunc1 val; + print "Throwfunc1^"; + val = Throwfunc2(); + print "Returning from Throwfunc1^^"; + return val; +]; + +[ Throwfunc2 val; + print "Throwfunc2^"; + @catch -> val; + val = Throwfunc3(val); + print "Returning from Throwfunc2^"; + return 2; +]; + +[ Throwfunc3 val; + print "Throwfunc3^"; + testglobal = Throwfunc4(val); + print "Returning from Throwfunc3^"; + return 3; +]; + +[ Throwfunc4 val; + print "Throwfunc4^"; + testglobal2 = Throwfunc5(val); + print "Returning from Throwfunc4^"; + return 4; +]; + +[ Throwfunc5 val; + print "Throwfunc5^About to @@64throw - should then return from Throwfunc1^"; + @throw 1 val; + print "Returning from Throwfunc5^"; + return 5; +]; + +Array tables_data -> 256; +Array copy_table_reference -> +$00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0a $0b $0c $0d $0e $0f +$00 $01 $02 $03 $04 $05 $06 $07 $18 $19 $1a $1b $1c $1d $1e $1f +$30 $31 $32 $33 $34 $35 $36 $37 $28 $29 $2a $2b $2c $2d $2e $2f +$30 $31 $32 $33 $34 $35 $36 $37 $38 $39 $3a $3b $3c $3d $3e $3f +$40 $41 $42 $43 $40 $41 $42 $43 $44 $45 $46 $47 $4c $4d $4e $4f +$54 $55 $56 $57 $58 $59 $5a $5b $58 $59 $5a $5b $5c $5d $5e $5f +$60 $61 $62 $63 $60 $61 $62 $63 $60 $61 $62 $63 $6c $6d $6e $6f +$00 $00 $00 $00 $00 $00 $00 $00 $78 $79 $7a $7b $7c $7d $7e $7f; + +TestClass Tables + with name 'tables' 'table', + testfunc [ val val2 ix; + print "*_table tests:^^"; + + for (ix=0 : ix<256 : ix++) { + tables_data->ix = ix; + } + + print "@@64print_table - should print the alphabet in upper then lower case:^"; + val = tables_data + $41; + @print_table val 26 2 6; + + print "^^@@64scan_table:"; + print "^Default form, first word: "; + @scan_table $0001 tables_data 128 -> val ?~bad_scan_table; + check(val, tables_data); + print "^Default form, another word: "; + @scan_table $8081 tables_data 128 -> val ?~bad_scan_table; + check(val, tables_data + $80); + print "^Manually specified default form: "; + @scan_table $8081 tables_data 128 $82 -> val ?~bad_scan_table; + check(val, tables_data + $80); + print "^Default form, nonexistent word: "; + @scan_table $0102 tables_data 128 -> val ?bad_scan_table; + check(val, 0); + + print "^Byte form, first byte: "; + @scan_table $00 tables_data 256 $01 -> val ?~bad_scan_table; + check(val, tables_data); + print "^Byte form, another byte: "; + @scan_table $80 tables_data 256 $01 -> val ?~bad_scan_table; + check(val, tables_data + $80); + print "^Byte form, nonexistent byte: "; + @scan_table $100 tables_data 256 $01 -> val ?bad_scan_table; + check(val, 0); + + print "^Longer form, first word: "; + @scan_table $0001 tables_data 64 $84 -> val ?~bad_scan_table; + check(val, tables_data); + print "^Longer form, another word: "; + @scan_table $8081 tables_data 64 $84 -> val ?~bad_scan_table; + check(val, tables_data + $80); + print "^Longer form, a word which will be skipped: "; + @scan_table $0203 tables_data 64 $84 -> val ?bad_scan_table; + check(val, 0); + + print "^Longer byte form, first byte: "; + @scan_table $00 tables_data 64 $04 -> val ?~bad_scan_table; + check(val, tables_data); + print "^Longer byte form, another byte: "; + @scan_table $80 tables_data 64 $04 -> val ?~bad_scan_table; + check(val, tables_data + $80); + print "^Longer byte form, a byte which will be skipped: "; + @scan_table $02 tables_data 64 $04 -> val ?bad_scan_table; + check(val, 0); + + print "^Default form, word after length of table: "; + @scan_table $8081 tables_data 63 -> val ?bad_scan_table; + check(val, 0); + print "^Longer form, word after length of table: "; + @scan_table $8081 tables_data 31 $84 -> val ?bad_scan_table; + check(val, 0); + + .copy_table; + print "^^@@64copy_table:^"; + print "Copying forward, non-overlapping.^"; + val = tables_data + $10; + @copy_table tables_data val 8; + val2 = copy_table_reference + $10; + check_array( val, val2, 16, Copytableprint ); + + print "Copying backwards, non-overlapping.^"; + val = tables_data + $20; + val2 = tables_data + $30; + @copy_table val2 val 8; + val2 = copy_table_reference + $20; + check_array( val, val2, 16, Copytableprint ); + + print "Copying forward, overlapping, non-corrupting.^"; + val = tables_data + $40; + val2 = tables_data + $44; + @copy_table val val2 8; + val2 = copy_table_reference + $40; + check_array( val, val2, 16, Copytableprint ); + + print "Copying backward, overlapping, non-corrupting.^"; + val = tables_data + $50; + val2 = tables_data + $54; + @copy_table val2 val 8; + val2 = copy_table_reference + $50; + check_array( val, val2, 16, Copytableprint ); + + print "Copying forward, overlapping, corrupting.^"; + val = tables_data + $60; + val2 = tables_data + $64; + @copy_table val val2 (-8); + val2 = copy_table_reference + $60; + check_array( val, val2, 16, Copytableprint ); + + print "Using @@64copy_table to zero out an array.^"; + val = tables_data + $70; + @copy_table val 0 8; + val2 = copy_table_reference + $70; + check_array( val, val2, 16, Copytableprint ); + + val = failures; + + print "Checking final table (failures are not counted twice).^"; + check_array( tables_data, copy_table_reference, 128, Copytableprint ); + + failures = val; + count_failures(); + return; + + .bad_scan_table; + print "^Bad @@64scan_table branch."; + failures++; + jump copy_table; + ]; + +[ Copytableprint ch ix; + print "Mismatch for index ", ix, ": "; +]; + +TestClass specfixes + with name 'specfixes' 'fixes', + testfunc [ val ; + print "Z-Machine 1.1 Updates/Clarifications:^^"; + + ! Operand evalution + ! Opcode operands are always evaluated from first to last + print "Operand evalution: "; + @push 2; + @push 4; + @sub sp sp -> val; + print "4-2="; check(val, 2); print "^"; + + ! Indirect variable references + ! An indirect reference to the stack pointer does not push or pull the top item of the stack - it is read or written in place. + print "Indirect variable references:^"; + @push 9; + @push 5; + @dec sp; + @pull val; + @pull val; + print "@@64dec: guard="; check(val, 9); print "^"; + @push 9; + @push 7; + @dec_chk sp 2 ?jumpfail; + @pull val; + @pull val; + print "@@64dec_chk: guard="; check(val, 9); print "^"; + @push 9; + @push 5; + @inc sp; + @pull val; + @pull val; + print "@@64inc: guard="; check(val, 9); print "^"; + @push 9; + @push 2; + @inc_chk sp 7 ?jumpfail; + @pull val; + @pull val; + print "@@64inc_chk: guard="; check(val, 9); print "^"; + ! Push an extra value in case @load fails - we don't want a stack underflow + @push 1; + @push 9; + @load sp -> val; + @pull val; + print "@@64load: guard="; check(val, 9); print "^"; + @push 9; + @pull sp; + @pull val; + print "@@64pull: guard="; check(val, 9); print "^"; + @push 9; + @push 1; + @store sp 2; + @pull val; + @pull val; + print "@@64store: guard="; check(val, 9); print "^"; + + ! @je + ! @je can take between 2 and 4 operands. + print "@@64je operands: "; + val = 1; + @je 1 0 1 ?je1; + val = 0; + .je1; + print "3: "; check(val, 1); + val = 1; + @je 1 0 0 1 ?je2; + val = 0; + .je2; + print ", 4: "; check(val, 1); print "^"; + + ! @get_prop_len + ! @get_prop_len 0 must return 0. + val = 1; + print "@@64get_prop_len 0: "; + @get_prop_len 0 -> val; + check(val, 0); print "^"; + + !### @set_cursor + !### @output_stream + !### Mouse + !### Sound + + count_failures(); + return; + + .jumpfail; + failures++; + count_failures(); + ]; + +Array basic_color_set --> $0000 $001D $0340 $03BD $59A0 $7C1F $77A0 $7FFF $5AD6 $4631 $2D6B; + +Array rainbow_set --> $001f $007f $00bf $00ff $013f $019f $01df $023f $027f $02bf $02ff $035f $039f $03df $03fd $03fb $03f9 $03f6 $03f4 $03f2 $03ef $03ed $03eb $03e8 $03e6 $03e4 $03e1 $07e0 $0fe0 $1be0 $23e0 $2be0 $33e0 $3fe0 $47e0 $53e0 $5be0 $63e0 $6be0 $77e0 $7fe0 $7f80 $7f40 $7f00 $7ec0 $7e60 $7e20 $7dc0 $7d80 $7d40 $7d00 $7ca0 $7c60 $7c00 $7c01 $7c04 $7c06 $7c09 $7c0b $7c0d $7c0f $7c12 $7c14 $7c17 $7c19 $7c1b $7c1d $781f $701f $641f $5c1f $541f $4c1f $401f $381f $2c1f $241f $1c1f $141f $081f; + +TestClass spec11 + with name 'spec11', + testfunc [ i val; + print "Z-Machine 1.1 tests:^^"; + + ! Check we're in a 1.1 version interpreter + val = HDR_SPECREVISION-->0; + if (val < $0101) + { + print "Stopping, interpreter is only version "; Version(); print ".^"; + return; + } + + print "Ok, interpreter is version "; Version(); print ".^^"; + + ! Test @set_true_colour by printing a rainbow + print "Checking @@64set_true_colour by printing a pretty rainbow (ultimate prettiness of rainbow depends on the observer's tastes):^^"; + + @set_text_style 8; + for (i=0 : i<80 : i++) + { + val = rainbow_set-->i; + @"EXT:13" -1 val; + print " "; + } + @set_colour 1 1; + @set_text_style 0; + print "^^"; + + ! Check the recommended colour set + print "Checking if the basic colour set uses the recommended true colours:^^"; + + @set_text_style 8; + print "Recommended: "; + for (i=0 : i<11 : i++) + { + val = basic_color_set-->i; + @"EXT:13" -1 val; + print " "; + } + @set_colour 1 1; + print "^Interpreter: "; + for (i=2 : i<13 : i++) + { + @set_colour 1 i; + print " "; + } + @set_colour 1 1; + @set_text_style 0; + print "^"; + + !count_failures(); + return; + ]; + +TestClass gestalt + with name 'spec12' 'gestalt', + testfunc [ val ; + print "Z-Machine 1.2 (@@64gestalt):^^"; + + ! Check we're in a 1.2 version interpreter + val = HDR_SPECREVISION-->0; + if (val < $0102) + { + print "Stopping, interpreter is only version "; Version(); print ".^"; + return; + } + + print "Ok, interpreter is version "; Version(); print ".^^"; + + ! Checking non-existant selector + @"EXT:30S" 0 0 -> val; + print "Selector 0 (non-existant): 0="; check(val, 0); print "^"; + + ! Checking Standard Revision selector + @"EXT:30S" 1 0 -> val; + print "Selector 1 (Standard Revision): $0102<= "; check_hex_min(val, $0102); print "^"; + + count_failures(); + return; + ]; diff --git a/src/test/praxix.z5 b/src/test/praxix.z5 new file mode 100644 index 0000000..87f83a7 Binary files /dev/null and b/src/test/praxix.z5 differ