├── Makefile ├── README.md ├── arithmetic.tal ├── jumps.tal ├── literals.tal ├── memory.tal ├── stack.tal ├── testfooter.tal └── testheader.tal /Makefile: -------------------------------------------------------------------------------- 1 | uxnemu = uxncli 2 | uxnasm = uxnasm 3 | 4 | all: literals arithmetic stack jumps memory 5 | 6 | literals: 7 | uxnasm literals.tal literals.rom 8 | 9 | arithmetic: 10 | uxnasm arithmetic.tal arithmetic.rom 11 | 12 | stack: 13 | uxnasm stack.tal stack.rom 14 | 15 | jumps: 16 | uxnasm jumps.tal jumps.rom 17 | 18 | memory: 19 | uxnasm memory.tal memory.rom 20 | 21 | run: all 22 | $(foreach file, $(wildcard ./*.rom), $(uxnemu) $(file) < /dev/null | xxd -p ;) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ! This repo is very out of date and I have not kept it up to date with any changes to the spec since February 2022 ! 2 | I have lost interest in this project and am unlikely to update it any time soon. The instruction set itself has changed and I believe there have been lots of changes to various devices in the interim. Take everything here with a grain of salt. 3 | 4 | # Test suite for the Uxn cpu instruction set 5 | 6 | WIP test programs to help catch implementation errors when porting the Uxn virtual CPU spec. Each program contains the expected program output (as executed on the reference C implementation of Uxn/Varvara) as a hexdump string so it's easily readable in the compiled .rom files as well. 7 | 8 | Some files have ASCII characters as markers embedded in the expected output to help diagnose which instruction has a problem (e.g. arithmetic.tal outputs `+`, `-`, `/`, etc. before each section of tests. 9 | 10 | Edit testheader.tal to change the output method. By default it writes raw result bytes to the console device, but this can be disabled to just leave values on the stack if the implementation doesn't have device output yet. 11 | 12 | ## How to test your own emulator 13 | 14 | ### Emulator with CLI access 15 | 1. Edit the Makefile and change `uxnemu` to point to your emulator 16 | 2. Run `make run` to build the uxn programs, run them, and hexdump the output. Then compare the output to the "expected" string for each rom. 17 | 18 | ### Emulator with its own console device 19 | 1. Load each rom into your emulator 20 | 2. Copy output of console device and compare with the "expected" string for that rom 21 | 22 | ### Emulator without CLI access or console device 23 | 1. Edit testheader.tal to redefine OUT/OUT2/OUTr as null operations 24 | 2. Load each rom into your emulator 25 | 3. Run the rom to completion 26 | 4. Copy the contents of the working stack and compare with the "expected" string for that rom 27 | -------------------------------------------------------------------------------- /arithmetic.tal: -------------------------------------------------------------------------------- 1 | ~testheader.tal 2 | 3 | |0100 4 | ( ADD ) LIT "+ OUT 5 | 6 | ( Adding zero is a no-op ) 7 | #0000 #0000 ADD2 OUT2 8 | 9 | ( Overflows ) 10 | #ffff #0000 ADD2 OUT2 11 | #ffff #0001 ADD2 OUT2 12 | #0001 #ffff ADD2 OUT2 13 | #ffff #ffff ADD2 OUT2 14 | #fffe #ffff ADD2 OUT2 15 | 16 | #ff #00 ADD OUT 17 | #ff #01 ADD OUT 18 | #01 #ff ADD OUT 19 | #ff #ff ADD OUT 20 | #fe #ff ADD OUT 21 | 22 | ( SUB ) LIT "- OUT 23 | 24 | #1337 #ae40 SUB2 OUT2 25 | #ae40 #1337 SUB2 OUT2 26 | 27 | #ffff #0000 SUB2 OUT2 28 | #ffff #0001 SUB2 OUT2 29 | #0001 #ffff SUB2 OUT2 30 | #ffff #ffff SUB2 OUT2 31 | #fffe #ffff SUB2 OUT2 32 | 33 | #ff #00 SUB OUT 34 | #ff #01 SUB OUT 35 | #01 #ff SUB OUT 36 | #ff #ff SUB OUT 37 | #fe #ff SUB OUT 38 | 39 | 40 | ( MUL ) LIT "* OUT 41 | #00 #01 MUL OUT 42 | #3f #e7 MUL OUT 43 | #37 #3f MUL OUT 44 | #10 #02 MUL OUT 45 | #ff #00 MUL OUT 46 | #ff #02 MUL OUT 47 | 48 | ( DIV ) LIT "/ OUT 49 | ( AND ) LIT "& OUT 50 | ( ORA ) LIT "| OUT 51 | ( EOR ) LIT "^ OUT 52 | #00 #00 EOR OUT 53 | #ff #00 EOR OUT 54 | #aa #55 EOR OUT 55 | #ff #ff EOR OUT 56 | 57 | #ffff #ff00 EOR2 OUT2 58 | #aaaa #5555 EOR2 OUT2 59 | 60 | ( SFT ) LIT "> OUT 61 | ( Right ) 62 | #ff #00 SFT OUT 63 | #ff #01 SFT OUT 64 | #ff #07 SFT OUT 65 | #ff #08 SFT OUT 66 | #ff #09 SFT OUT 67 | #ff #0e SFT OUT 68 | #ff #0f SFT OUT 69 | 70 | #ffff #00 SFT2 OUT2 71 | #ffff #01 SFT2 OUT2 72 | #ffff #02 SFT2 OUT2 73 | #ffff #07 SFT2 OUT2 74 | #ffff #08 SFT2 OUT2 75 | #ffff #09 SFT2 OUT2 76 | #ffff #0a SFT2 OUT2 77 | #ffff #0e SFT2 OUT2 78 | #ffff #0f SFT2 OUT2 79 | 80 | ( Left ) 81 | #ff #10 SFT OUT 82 | #ff #70 SFT OUT 83 | #ff #80 SFT OUT 84 | #ff #90 SFT OUT 85 | #ff #e0 SFT OUT 86 | #ff #f0 SFT OUT 87 | 88 | #ffff #10 SFT2 OUT2 89 | #ffff #20 SFT2 OUT2 90 | #ffff #70 SFT2 OUT2 91 | #ffff #80 SFT2 OUT2 92 | #ffff #90 SFT2 OUT2 93 | #ffff #a0 SFT2 OUT2 94 | #ffff #e0 SFT2 OUT2 95 | #ffff #f0 SFT2 OUT2 96 | 97 | ( Both ) 98 | #ff #12 SFT OUT 99 | #ff #77 SFT OUT 100 | #ff #11 SFT OUT 101 | #ff #3f SFT OUT 102 | #ff #ff SFT OUT 103 | 104 | #ffff #11 SFT2 OUT2 105 | #ffff #12 SFT2 OUT2 106 | #ffff #21 SFT2 OUT2 107 | #ffff #7e SFT2 OUT2 108 | #ffff #83 SFT2 OUT2 109 | #ffff #92 SFT2 OUT2 110 | #ffff #2a SFT2 OUT2 111 | #ffff #e3 SFT2 OUT2 112 | 113 | CLOSE 114 | BRK 115 | 116 | @expected "expected 117 | "2b0000ffff00000000fffefffdff0000fefd2d64f79b09fffffffe000200 118 | "00fffffffe0200ff2a00d9892000fe2f267c5e00ffff0000ffffff3eff7f 119 | "0100000000ffff7fff3fff01ff00ff007f003f00030001fe8000000000ff 120 | "fefffcff80ff00fe00fc00c00080007e80fe0000fffe7ffefffc0180ff00 121 | "fe0000fcc000 122 | 123 | ~testfooter.tal 124 | -------------------------------------------------------------------------------- /jumps.tal: -------------------------------------------------------------------------------- 1 | ~testheader.tal 2 | |0100 @Init 3 | ( TODO Backwards relative jumps ) 4 | ( Conditional jumps ) 5 | #01 ,&true JCN 6 | #dd OUT 7 | &true 8 | #01 OUT 9 | 10 | #34 ,&true2 JCN 11 | #ee OUT 12 | &true2 13 | #ab OUT 14 | 15 | #00 ,&false JCN 16 | #cc OUT 17 | &false 18 | #bb OUT 19 | 20 | ( Unconditional jumps ) 21 | #aa OUT 22 | ,&no-ff JMP 23 | #ff OUT 24 | &no-ff 25 | 26 | #13 OUT 27 | ;&no-37 JMP2 28 | #37 OUT 29 | &no-37 30 | 31 | #ab OUT 32 | ;sub-absolute JSR2 33 | #cd OUT 34 | 35 | #01 OUT 36 | ,sub-relative JSR 37 | #23 OUT 38 | 39 | CLOSE 40 | BRK 41 | 42 | @sub-relative 43 | LIT2 "su OUT2 LIT2 "br OUT2 44 | JMP2r 45 | ( Should never reach this point ) 46 | LIT2 "er OUT2 47 | 48 | @sub-absolute 49 | LIT2 "su OUT2 LIT2 "ba OUT2 50 | JMP2r 51 | ( Should never reach this point ) 52 | LIT2 "er OUT2 53 | @expected "expected 54 | "01abccbbaa13ab73756261cd017375627223 55 | ~testfooter.tal 56 | -------------------------------------------------------------------------------- /literals.tal: -------------------------------------------------------------------------------- 1 | ~testheader.tal 2 | 3 | |0100 4 | #00 OUT 5 | #01 OUT 6 | #0101 OUT2 7 | 8 | #1234 OUT2 9 | 10 | #12 #34 OUT2 11 | 12 | #ffff OUT2 13 | 14 | LIT "A OUT 15 | LIT "! OUT 16 | #0d OUT 17 | 18 | CLOSE 19 | BRK 20 | @expected "expected 21 | "0001010112341234ffff41210d 22 | ~testfooter.tal 23 | -------------------------------------------------------------------------------- /memory.tal: -------------------------------------------------------------------------------- 1 | ~testheader.tal 2 | 3 | |0000 4 | @var1 5 | &x $1 &y $2 6 | @var2 7 | &x $1 &y $2 8 | 9 | |0100 10 | #45 .var2/x STZ 11 | #6789 .var2/y STZ2 12 | .var1/x LDZ OUT 13 | .var1/y LDZ2 OUT2 14 | 15 | .var2/x LDZ OUT 16 | .var2/x LDZ2 OUT2 17 | .var2/y LDZ2 OUT2 18 | 19 | ;far LDA OUT 20 | ;far LDA2 OUT2 21 | 22 | #abcd ;far/empty STA2 23 | 24 | ;far/empty LDA OUT 25 | ;far/empty LDA2 OUT2 26 | 27 | ,near LDR OUT 28 | ,near LDR2 OUT2 29 | 30 | #1337 ,near/empty STR2 31 | ,near/empty LDR OUT 32 | ,near/empty LDR2 OUT2 33 | 34 | CLOSE 35 | BRK 36 | @near 3210 &empty $2 37 | 38 | @expected "expected 39 | "0000004545676789767654ababcd323210131337 40 | 41 | ~testfooter.tal 42 | 43 | |fff8 44 | @far 45 | 7654 46 | &empty 47 | $2 48 | -------------------------------------------------------------------------------- /stack.tal: -------------------------------------------------------------------------------- 1 | ~testheader.tal 2 | 3 | |0100 4 | ( Test STH first since we need it to work for the output commands to work properly ) 5 | ( STH ) LIT "H OUT 6 | #ff #01 STH OUT STHr OUT 7 | #ffee #aa55 STH2 OUT2 STHr2 OUT2 8 | 9 | ( OVR ) LIT "V OUT 10 | #03 #04 OVR STH STH OUT STHr OUT STHr OUT 11 | #ffff #aaaa #5555 OVR2 STH2 STH2 OUT2 STH2r OUT2 STH2r OUT2 12 | 13 | ( POP ) LIT "P OUT 14 | POP2 ( Clear #ffff from last section ) 15 | #ff #aa POP OUT 16 | #1337 #aa55 POP2 OUT2 17 | 18 | ( NIP ) LIT "N OUT 19 | #ab #cd NIP OUT 20 | #3456 #789a NIP2 OUT2 21 | 22 | ( ROT ) LIT "R OUT 23 | #12 #34 #56 ROT ROT ROT STH STH OUT STHr OUT STHr OUT 24 | #78 #9a #bc ROT ROT STH STH OUT STHr OUT STHr OUT 25 | #de #f0 #12 ROT STH STH OUT STHr OUT STHr OUT 26 | 27 | 28 | ( SWP ) LIT "S OUT 29 | ( Two swaps does nothing ) 30 | #abcd SWP SWP OUT2 31 | #1337 #4e53 SWP2 SWP2 STH2 OUT2 STH2r OUT2 32 | 33 | #1234 SWP OUT2 34 | #8383 #a55a SWP2 STH2 OUT2 STH2r OUT2 35 | 36 | ( DUP ) LIT "D OUT 37 | 38 | CLOSE 39 | BRK 40 | @expected "expected 41 | "48ff01ffeeaa5556030403aaaa5555aaaa50ff13374ecd789a52123456bc 42 | "789af012de53abcd13374e533412a55a838344 43 | ~testfooter.tal 44 | -------------------------------------------------------------------------------- /testfooter.tal: -------------------------------------------------------------------------------- 1 | ( Stolen from asma ) 2 | @print-byte ( byte -- ) 3 | #20 .Console/write DEO 4 | DUP #04 SFT ,&hex JSR 5 | #0f AND ,&hex JMP 6 | 7 | &hex 8 | #30 ADD DUP #3a LTH ,¬-alpha JCN 9 | #27 ADD 10 | ¬-alpha 11 | .Console/write DEO 12 | JMP2r 13 | 14 | -------------------------------------------------------------------------------- /testheader.tal: -------------------------------------------------------------------------------- 1 | |00 @System &vector $2 &wst $1 &rst $1 &eaddr $2 &ecode $1 &pad $1 &r $2 &g $2 &b $2 &debug $1 &halt $1 2 | |10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ] 3 | 4 | %CLOSE { #01 .System/halt DEO } 5 | 6 | ( Uncomment whichever output style is appropriate for your emulator ) 7 | 8 | ( Do nothing, leave values on the stack. Handy if you don't have DEO implemented yet but can look at the raw stack ) 9 | ( %OUT { } ) 10 | ( %OUTr { } ) 11 | ( %OUT2 { } ) 12 | 13 | ( Raw console bytes out ) 14 | %OUT { .Console/write DEO } 15 | 16 | ( Print to the console as hex chars. ) 17 | ( This may be unreliable if your emulator isn't completed since it relies on stack ops and jumps ) 18 | ( %OUT { ;print-byte JSR2 } ) 19 | 20 | %OUTr { STHr OUT } 21 | %OUT2 { STH OUT STHr OUT } 22 | --------------------------------------------------------------------------------