diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index ed6f973..a4bbbb1 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -9,8 +9,8 @@ jobs: - name: Checkout current uses: actions/checkout@v4 - name: Configure - run: cmake -S emulator -B emulator/build + run: cmake -S . -B build - name: Build - run: cmake --build emulator/build + run: cmake --build build - name: Test - run: cd emulator/build && ctest --output-on-failure + run: cd build && ctest --output-on-failure diff --git a/.gitignore b/.gitignore index 28f87f7..fa33649 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -emulator/.cache/ -emulator/build/ +.cache/ +build/ emulator/customasm/*.bin diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6852d9c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.20) + +project(foot) + +if(PROJECT_IS_TOP_LEVEL) + enable_testing() + set(FOOT_TESTS ON) +else() + set(FOOT_TESTS OFF) +endif() + +add_subdirectory(emulator) diff --git a/DOCS.txt b/DOCS.txt index d73baa8..7773b8c 100644 --- a/DOCS.txt +++ b/DOCS.txt @@ -1,52 +1,52 @@ -╔════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ -║ Foot ISA ║ -╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦═════════════════════════════════╣ -║ Instruction Format ║ ║ Addressing Modes ║ -╠══════════╦═════════════════════════╦══════════════════════╦═══════════════════════════════════════════════════════╣ ╠═══════╦═════════════════════════╣ -║ ║ ║ ║ Encoding ║ ║ 000 ║ Immediate ║ -║ Mnemonic ║ Description ║ Semantics ╠═════════════╦═════════════╦═════════════╦═════════════╣ ╠═══════╬═════════════════════════╣ -║ ║ ║ ║ 24-31 ║ 16-23 ║ 8-15 ║ 0-7 ║ ║ 001 ║ Direct ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╦══════╬══════╦══════╬══════╦══════╬══════╦══════╣ ╠═══════╬═════════════════════════╣ -║ CNST ║ Immediate ║ D = I ║ CCCR ║ 0000 ║ DDDd ║ dddd ║ iiii ║ iiii ║ iiii ║ iiii ║ ║ 010 ║ Indirect Auto-increment ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ CMPR ║ Compare ║ C = A <=> B ║ CCCR ║ 0001 ║ BBBb ║ bbbb ║ 0000 ║ 0000 ║ AAAa ║ aaaa ║ ║ 011 ║ Indirect Auto-decrement ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ BWNG ║ Bitwise negate ║ D = ~A ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0001 ║ AAAa ║ aaaa ║ ║ 100 ║ Indirect ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ ARNG ║ Arithmetic negate ║ D = -A ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0010 ║ AAAa ║ aaaa ║ ║ 101 ║ Indirect 1-word offset ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ LONG ║ Logical negate ║ D = !A ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0011 ║ AAAa ║ aaaa ║ ║ 110 ║ Indirect 2-word offset ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ CONF ║ Configure processor ║ ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0100 ║ AAAa ║ aaaa ║ ║ 111 ║ Indirect 3-word offset ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╩═════════════════════════╣ -║ BWOR ║ Bitwise or ║ D = A | B ║ CCCR ║ 0010 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ Conditional Execution Flags ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╦═════════════════════════╣ -║ BAND ║ Bitwise and ║ D = A & B ║ CCCR ║ 0011 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 000 ║ Always ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ BXOR ║ Bitwise xor ║ D = A ^ B ║ CCCR ║ 0100 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 001 ║ A < B ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ RESERVED ║ ║ ║ CCCR ║ 0101 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 010 ║ A <= B ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ SRSH ║ Signed right shift ║ D = A >> B ║ CCCR ║ 0110 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 011 ║ A = B ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ ZLSH ║ Pad zero left shift ║ D = A << B ║ CCCR ║ 0111 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 100 ║ A >= B ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ CLSH ║ Circular left shift ║ D = A << B ║ CCCR ║ 1000 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 101 ║ A > B ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ ADDI ║ Addition ║ D = A + B ║ CCCR ║ 1001 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 110 ║ A != B ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ SUBT ║ Subtraction ║ D = A - B ║ CCCR ║ 1010 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 111 ║ Reserved ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╩═════════════════════════╣ -║ MULT ║ Multiplication ║ D = A * B >> shift ║ CCCR ║ 1011 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ Processor configuration bits ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╦═════════════════════════╣ -║ RESERVED ║ ║ ║ CCCR ║ 1100 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 3-0 ║ Multiplication shift ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ RESERVED ║ ║ ║ CCCR ║ 1101 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 7-4 ║ Reserved ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ DIVI ║ Division ║ D = (A << shift) / B ║ CCCR ║ 1110 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 11-8 ║ Reserved ║ -╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ MODU ║ Modulus ║ D = (A << shift) % B ║ CCCR ║ 1111 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 15-12 ║ Reserved ║ -╚══════════╩═════════════════════════╩══════════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══╩═══════╩═════════════════════════╝ +╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ +║ Foot ISA ║ +╠══════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦════════════════════════════════╣ +║ Instruction Format ║ ║ Addressing modes ║ +╠══════════╦══════════════════════╦════════════════╦═══════════════════════════════════════════════════════╣ ╠══════╦═════════════════════════╣ +║ ║ ║ ║ Encoding ║ ║ 00 ║ Immediate ║ +║ Mnemonic ║ Description ║ Semantics ╠═════════════╦═════════════╦═════════════╦═════════════╣ ╠══════╬═════════════════════════╣ +║ ║ ║ ║ 24-31 ║ 16-23 ║ 8-15 ║ 0-7 ║ ║ 01 ║ Direct ║ +╠══════════╬══════════════════════╬════════════════╬══════╦══════╬══════╦══════╬══════╦══════╬══════╦══════╣ ╠══════╬═════════════════════════╣ +║ CNST ║ Load immediate ║ D = I ║ CCCR ║ 0000 ║ 0DDd ║ dddd ║ iiii ║ iiii ║ iiii ║ iiii ║ ║ 10 ║ Indirect ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ CMPR ║ Compare ║ C = A <=> B ║ CCCR ║ 0001 ║ 0BBb ║ bbbb ║ 0000 ║ 0000 ║ 0AAa ║ aaaa ║ ║ 11 ║ Indirect auto-increment ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╩═════════════════════════╣ +║ BWNG ║ Bitwise negate ║ D = ~A ║ CCCR ║ 0001 ║ 0DDd ║ dddd ║ 0000 ║ 0001 ║ 0AAa ║ aaaa ║ ║ Conditional execution flags ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╦═════════════════════════╣ +║ ARNG ║ Arithmetic negate ║ D = -A ║ CCCR ║ 0001 ║ xDDd ║ dddd ║ 0000 ║ 0010 ║ xAAa ║ aaaa ║ ║ 000 ║ Always ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ LONG ║ Logical negate ║ D = !A ║ CCCR ║ 0001 ║ xDDd ║ dddd ║ 0000 ║ 0011 ║ xAAa ║ aaaa ║ ║ 001 ║ A < B ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ CONF ║ Configure processor ║ D = old config ║ CCCR ║ 0001 ║ 0DDd ║ dddd ║ 0000 ║ 0100 ║ 0AAa ║ aaaa ║ ║ 010 ║ A <= B ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ BWOR ║ Bitwise or ║ D = A | B ║ CCCR ║ 0010 ║ 0DDd ║ dddd ║ 0BBb ║ bbbb ║ 0AAa ║ aaaa ║ ║ 011 ║ A = B ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ BAND ║ Bitwise and ║ D = A & B ║ CCCR ║ 0011 ║ 0DDd ║ dddd ║ 0BBb ║ bbbb ║ 0AAa ║ aaaa ║ ║ 100 ║ A >= B ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ BXOR ║ Bitwise exclusive or ║ D = A ^ B ║ CCCR ║ 0100 ║ 0DDd ║ dddd ║ 0BBb ║ bbbb ║ 0AAa ║ aaaa ║ ║ 101 ║ A > B ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ RESERVED ║ ║ ║ ║ 0101 ║ ║ ║ ║ ║ ║ ║ ║ 110 ║ A != B ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ SRSH ║ Signed right shift ║ D = A >> B ║ CCCR ║ 0110 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 111 ║ Reserved ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╩═════════════════════════╣ +║ ZLSH ║ Pad zero left shift ║ D = A << B ║ CCCR ║ 0111 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ SIMD bits ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╦═════════════════════════╣ +║ CLSH ║ Circular left shift ║ D = A << B ║ CCCR ║ 1000 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 00 ║ 1 32-bit number ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ ADDI ║ Addition ║ D = A + B ║ CCCR ║ 1001 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 01 ║ 2 16-bit numbers ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ SUBT ║ Subtraction ║ D = A - B ║ CCCR ║ 1010 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 10 ║ 4 8-bit numbers ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ MULT ║ Multiplication ║ D = A * B ║ CCCR ║ 1011 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 11 ║ 8 4-bit numbers ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╩═════════════════════════╣ +║ DIVI ║ Division ║ D = A / B ║ CCCR ║ 1100 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ Processor configuration bits ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╦═════════════════════════╣ +║ MODU ║ Modulus ║ D = A % B ║ CCCR ║ 1101 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 4-0 ║ Multiplication shift ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ RESERVED ║ ║ ║ ║ 1110 ║ ║ ║ ║ ║ ║ ║ ║ 31-4 ║ Reserved ║ +╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ +║ RESERVED ║ ║ ║ ║ 1111 ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ +╚══════════╩══════════════════════╩════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══╩══════╩═════════════════════════╝ ╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ Foot ISA Table Key ║ @@ -60,30 +60,27 @@ ║ ║ Store to register ║ ║ ║ indicated A is less than B ║ ║ ║ ║ ║ ║ ╠═════════════════╬════════════════════════════════════════════╣ ╠════════╬═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ ║ Indirect ║ Use register contents as memory address, ║ ║ A <= B ║ Run if last CMPR instruction ║ ║ ║ ║ D ║ Destination Addressing Mode ║ -║ Auto-increment ║ then use memory contents as operand ║ ║ ║ indicated A is less than or ║ ║ ║ ║ ║ ║ +║ ║ then use memory contents as operand ║ ║ ║ indicated A is less than or ║ ║ ║ ║ ║ ║ ║ ║ or store to memory. ║ ║ ║ equal to B ║ ║ ║ ║ ║ ║ -║ ║ Then, increment register contents by 1. ║ ║ ║ ║ ║ ║ ║ ║ ║ ╠═════════════════╬════════════════════════════════════════════╣ ╠════════╬═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ ║ Indirect ║ Use register contents as memory address, ║ ║ A = B ║ Run if last CMPR instruction ║ ║ ║ ║ d ║ Destination Register Index ║ -║ Auto-decrement ║ then use memory contents as operand ║ ║ ║ indicated A equal to B ║ ║ ║ ║ ║ ║ +║ Auto-increment ║ then use memory contents as operand ║ ║ ║ indicated A equal to B ║ ║ ║ ║ ║ ║ ║ ║ or store to memory. ║ ║ ║ ║ ║ ║ ║ ║ ║ -║ ║ Then, decrement register contents by 1. ║ ║ ║ ║ ║ ║ ║ ║ ║ +║ ║ Then, increment register contents by 1. ║ ║ ║ ║ ║ ║ ║ ║ ║ ╠═════════════════╬════════════════════════════════════════════╣ ╠════════╬═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ ║ Indirect ║ Use register contents as memory address, ║ ║ A >= B ║ Run if last CMPR instruction ║ ║ ║ ║ A ║ Operand A Addressing Mode ║ ║ ║ then use memory contents as operand ║ ║ ║ indicated A is greater than ║ ║ ║ ║ ║ ║ ║ ║ or store to memory. ║ ║ ║ or equal to B ║ ║ ║ ║ ║ ║ -╠═════════════════╬════════════════════════════════════════════╣ ╠════════╬═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ -║ Indirect 1-word ║ Use register contents as memory address, ║ ║ A > B ║ Run if last CMPR instruction ║ ║ ║ ║ a ║ Operand A Register Index ║ -║ Offset ║ add 1 to address, then use memory contents ║ ║ ║ indicated A is greater than B ║ ║ ║ ║ ║ ║ -║ ║ as operand or store to memory. ║ ║ ║ ║ ║ ║ ║ ║ ║ -╠═════════════════╬════════════════════════════════════════════╣ ╠════════╬═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ -║ Indirect 2-word ║ Use register contents as memory address, ║ ║ A != B ║ Run if last CMPR instruction ║ ║ ║ ║ B ║ Operand B Addressing Mode ║ -║ Offset ║ add 2 to address, then use memory contents ║ ║ ║ indicated A is not equal to B ║ ║ ║ ║ ║ ║ -║ ║ as operand or store to memory. ║ ║ ║ ║ ║ ║ ║ ║ ║ -╠═════════════════╬════════════════════════════════════════════╣ ╠════════╩═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ -║ Indirect 3-word ║ Use register contents as memory address, ║ ║ ║ ║ ║ ║ b ║ Operand B Register Index ║ -║ Offset ║ add 3 to address, then use memory contents ║ ║ ║ ║ ║ ║ ║ ║ -║ ║ as operand or store to memory. ║ ║ ║ ║ ║ ║ ║ ║ -╠═════════════════╩════════════════════════════════════════════╣ ║ ║ ║ ║ ╠═══╬═════════════════════════════╣ +╠═════════════════╩════════════════════════════════════════════╣ ╠════════╬═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ +║ ║ ║ A > B ║ Run if last CMPR instruction ║ ║ ║ ║ a ║ Operand A Register Index ║ +║ ║ ║ ║ indicated A is greater than B ║ ║ ║ ║ ║ ║ +║ ║ ╠════════╬═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ +║ ║ ║ A != B ║ Run if last CMPR instruction ║ ║ ║ ║ B ║ Operand B Addressing Mode ║ +║ ║ ║ ║ indicated A is not equal to B ║ ║ ║ ║ ║ ║ +║ ║ ╠════════╩═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ +║ ║ ║ ║ ║ ║ ║ b ║ Operand B Register Index ║ +║ ║ ║ ║ ║ ║ ║ ║ ║ +║ ║ ║ ║ ║ ║ ║ ║ ║ +║ ║ ║ ║ ║ ║ ╠═══╬═════════════════════════════╣ ║ ║ ║ ║ ║ ║ ║ i ║ Immediate Integer ║ ╚══════════════════════════════════════════════════════════════╩══╩════════════════════════════════════════╩══╩══════════════════════════════════════════════════╩══╩═══╩═════════════════════════════╝ diff --git a/emulator/CMakeLists.txt b/emulator/CMakeLists.txt index 6170018..ebb9bc0 100644 --- a/emulator/CMakeLists.txt +++ b/emulator/CMakeLists.txt @@ -10,7 +10,6 @@ find_package(SDL3 REQUIRED CONFIG) add_executable(foot-emulator-cli src/main.cpp) target_link_libraries(foot-emulator-cli PUBLIC foot-emulator SDL3::SDL3) -if(PROJECT_IS_TOP_LEVEL) - enable_testing() +if(FOOT_TESTS) add_subdirectory(tests) endif() diff --git a/emulator/include/foot-emulator.h b/emulator/include/foot-emulator.h index c0e8ba6..8683742 100644 --- a/emulator/include/foot-emulator.h +++ b/emulator/include/foot-emulator.h @@ -18,11 +18,7 @@ struct Operand Immediate = 0, Direct, IndirectAutoIncrement, - IndirectAutoDecrement, - Indirect, - IndirectOffset1Word, - IndirectOffset2Word, - IndirectOffset3Word + Indirect } addressing_mode; uint8_t register_index; }; @@ -39,11 +35,11 @@ public: protected: Device(uint16_t size); - uint16_t& memory(uint16_t index); + uint32_t& memory(uint16_t index); private: - uint16_t* assigned_memory_base; - uint16_t assigned_memory_size; + uint32_t* assigned_memory_base; + uint32_t assigned_memory_size; }; class Emulator @@ -54,18 +50,18 @@ public: Emulator(); - void run(const std::vector& program); + void run(const std::vector& program); void map_device(std::unique_ptr&& device); - uint16_t& memory_at(uint16_t address); - uint16_t& decode_operand(Operand operand); - uint16_t& register_at(uint8_t index); + uint32_t& memory_at(uint16_t address); + uint32_t& decode_operand(Operand operand); + uint32_t& register_at(uint8_t index); void run_instruction(); private: - std::array memory; - std::array registers; + std::array memory; + std::array registers; enum class Status { Less, @@ -73,8 +69,8 @@ private: Greater } status_register; uint32_t instruction; - uint16_t configuration; - uint16_t dummy_value; + uint32_t configuration; + uint32_t dummy_value; std::vector> devices; uint16_t mapped_base; bool keep_running; @@ -99,8 +95,23 @@ private: void DIVI(); void MODU(); - bool repeats(); - uint8_t shift(); + bool repeats() const; + uint8_t simd_elements() const; + uint8_t shift() const; + + uint32_t apply_many_unary(uint32_t a, uint32_t (Emulator::*fn)(uint32_t a) const) const; + uint32_t apply_many_binary(uint32_t a, uint32_t b, uint32_t (Emulator::*fn)(uint32_t a, uint32_t b) const) const; + + uint32_t op_arithmetic_negate(uint32_t a) const; + uint32_t op_logical_negate(uint32_t a) const; + uint32_t op_signed_right_shift(uint32_t a, uint32_t b) const; + uint32_t op_pad_zero_left_shift(uint32_t a, uint32_t b) const; + uint32_t op_circular_left_shift(uint32_t a, uint32_t b) const; + uint32_t op_add(uint32_t a, uint32_t b) const; + uint32_t op_sub(uint32_t a, uint32_t b) const; + uint32_t op_mul(uint32_t a, uint32_t b) const; + uint32_t op_div(uint32_t a, uint32_t b) const; + uint32_t op_mod(uint32_t a, uint32_t b) const; }; } diff --git a/emulator/src/foot-emulator.cpp b/emulator/src/foot-emulator.cpp index b525582..2acb44a 100644 --- a/emulator/src/foot-emulator.cpp +++ b/emulator/src/foot-emulator.cpp @@ -6,7 +6,7 @@ namespace foot { Operand::Operand(uint8_t bits) : - addressing_mode(static_cast((bits & 0b11100000) >> 5)), + addressing_mode(static_cast((bits & 0b01100000) >> 5)), register_index(bits & 0b00011111) {} @@ -15,7 +15,7 @@ Device::Device(uint16_t size) : assigned_memory_size(size) {} -uint16_t& Device::memory(uint16_t index) +uint32_t& Device::memory(uint16_t index) { if (index >= assigned_memory_size) { @@ -31,7 +31,7 @@ Emulator::Emulator() : mapped_base(0) {} -void Emulator::run(const std::vector& program) +void Emulator::run(const std::vector& program) { std::copy(program.begin(), program.end(), memory.begin()); @@ -57,12 +57,12 @@ void Emulator::map_device(std::unique_ptr&& device) devices.push_back(std::move(device)); } -uint16_t& Emulator::memory_at(uint16_t address) +uint32_t& Emulator::memory_at(uint16_t address) { return memory[address]; } -uint16_t& Emulator::decode_operand(Operand operand) +uint32_t& Emulator::decode_operand(Operand operand) { switch (operand.addressing_mode) { @@ -76,27 +76,15 @@ uint16_t& Emulator::decode_operand(Operand operand) case Operand::AddressingMode::IndirectAutoIncrement: return memory[registers[operand.register_index]++]; - case Operand::AddressingMode::IndirectAutoDecrement: - return memory[registers[operand.register_index]--]; - case Operand::AddressingMode::Indirect: return memory[registers[operand.register_index]]; - case Operand::AddressingMode::IndirectOffset1Word: - return memory[registers[operand.register_index] + 1]; - - case Operand::AddressingMode::IndirectOffset2Word: - return memory[registers[operand.register_index] + 2]; - - case Operand::AddressingMode::IndirectOffset3Word: - return memory[registers[operand.register_index] + 3]; - default: return dummy_value; } } -uint16_t& Emulator::register_at(uint8_t index) +uint32_t& Emulator::register_at(uint8_t index) { return registers[index]; } @@ -106,7 +94,7 @@ void Emulator::run_instruction() read_instruction(); const bool rep = repeats(); - const uint16_t loop_count = rep ? registers[LC] : 1; + const uint32_t loop_count = rep ? registers[LC] : 1; for (int iteration = 0; iteration < loop_count; iteration++) { @@ -155,9 +143,6 @@ void Emulator::run_instruction() BXOR(); break; - case 5: - break; - case 6: SRSH(); break; @@ -182,11 +167,11 @@ void Emulator::run_instruction() MULT(); break; - case 14: + case 12: DIVI(); break; - case 15: + case 13: MODU(); break; @@ -200,10 +185,7 @@ void Emulator::run_instruction() void Emulator::read_instruction() { - uint16_t low = memory[registers[PC]++]; - uint16_t high = memory[registers[PC]++]; - - instruction = (uint32_t(high) << 16) | uint32_t(low); + instruction = memory[registers[PC]++]; } void Emulator::CNST() @@ -213,8 +195,8 @@ void Emulator::CNST() void Emulator::CMPR() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x00FF0000) >> 16); if (a < b) { @@ -232,32 +214,32 @@ void Emulator::CMPR() void Emulator::BWNG() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); d = ~a; } void Emulator::ARNG() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - d = -a; + d = apply_many_unary(a, &Emulator::op_arithmetic_negate); } void Emulator::LONG() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - d = !a; + d = apply_many_unary(a, &Emulator::op_logical_negate); } void Emulator::CONF() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); d = configuration; configuration = a; @@ -265,112 +247,200 @@ void Emulator::CONF() void Emulator::BWOR() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); d = a | b; } void Emulator::BAND() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); d = a & b; } void Emulator::BXOR() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); d = a ^ b; } void Emulator::SRSH() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - d = int16_t(a) >> int16_t(b); + d = apply_many_binary(a, b, &Emulator::op_signed_right_shift); } void Emulator::ZLSH() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - d = a << b; + d = apply_many_binary(a, b, &Emulator::op_pad_zero_left_shift); } void Emulator::CLSH() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - d = (a << b) | (a >> (16 - b)); + d = apply_many_binary(a, b, &Emulator::op_circular_left_shift); } void Emulator::ADDI() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - d = a + b; + d = apply_many_binary(a, b, &Emulator::op_add); } void Emulator::SUBT() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - d = a - b; + d = apply_many_binary(a, b, &Emulator::op_sub); } void Emulator::MULT() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - d = uint32_t(int32_t(a) * int32_t(b)) >> shift(); + d = apply_many_binary(a, b, &Emulator::op_mul); } void Emulator::DIVI() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - // convert from unsigned to signed, then widen - d = uint32_t((int32_t(int16_t(a)) << shift()) / int32_t(int16_t(b))); + d = apply_many_binary(a, b, &Emulator::op_div); } void Emulator::MODU() { - uint16_t a = decode_operand(instruction & 0x000000FF); - uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); - uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); + uint32_t a = decode_operand(instruction & 0x000000FF); + uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8); + uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16); - d = int16_t(a) % int16_t(b); + d = apply_many_binary(a, b, &Emulator::op_mod); } -bool Emulator::repeats() +bool Emulator::repeats() const { return instruction & 0x10000000; } -uint8_t Emulator::shift() +uint8_t Emulator::simd_elements() const { - return configuration & 0x000F; + uint8_t bits = 0; + if (instruction & (1 << 7)) { bits |= 0b01; } + if (instruction & (1 << 23)) { bits |= 0b10; } + + return 1 << bits; +} + +uint8_t Emulator::shift() const +{ + return configuration & 0x0000001F; +} + +uint32_t Emulator::apply_many_unary(uint32_t a, uint32_t (Emulator::*fn)(uint32_t a) const) const +{ + uint32_t result = 0; + + for (int i = 0; i < simd_elements(); i++) + { + uint32_t simd_element_a = (a >> (i * 32 / simd_elements())) & ((uint64_t(1) << (32 / simd_elements())) - 1); + uint32_t simd_result = (this->*fn)(simd_element_a) << (i * 32 / simd_elements()); + result |= simd_result; + } + + return result; +} + +uint32_t Emulator::apply_many_binary(uint32_t a, uint32_t b, uint32_t (Emulator::*fn)(uint32_t a, uint32_t b) const) const +{ + uint32_t result = 0; + + for (int i = 0; i < simd_elements(); i++) + { + uint32_t simd_element_a = (a >> (i * 32 / simd_elements())) & ((uint64_t(1) << (32 / simd_elements())) - 1); + uint32_t simd_element_b = (b >> (i * 32 / simd_elements())) & ((uint64_t(1) << (32 / simd_elements())) - 1); + uint32_t simd_result = (this->*fn)(simd_element_a, simd_element_b) << (i * 32 / simd_elements()); + result |= simd_result; + } + + return result; +} + +uint32_t Emulator::op_arithmetic_negate(uint32_t a) const +{ + return -a; +} + +uint32_t Emulator::op_logical_negate(uint32_t a) const +{ + return !a; +} + +uint32_t Emulator::op_signed_right_shift(uint32_t a, uint32_t b) const +{ + return int32_t(a) >> b; +} + +uint32_t Emulator::op_pad_zero_left_shift(uint32_t a, uint32_t b) const +{ + return a << b; +} + +uint32_t Emulator::op_circular_left_shift(uint32_t a, uint32_t b) const +{ + return (a << b) | (a >> (32 - b)); +} + +uint32_t Emulator::op_add(uint32_t a, uint32_t b) const +{ + return a + b; +} + +uint32_t Emulator::op_sub(uint32_t a, uint32_t b) const +{ + return a - b; +} + +uint32_t Emulator::op_mul(uint32_t a, uint32_t b) const +{ + return uint64_t(int64_t(a) * int64_t(b)) >> shift(); +} + +uint32_t Emulator::op_div(uint32_t a, uint32_t b) const +{ + // convert from unsigned to signed, then widen + return (int64_t(int32_t(a)) << shift()) / int64_t(int32_t(b)); +} + +uint32_t Emulator::op_mod(uint32_t a, uint32_t b) const +{ + return int32_t(a) % int32_t(b); } } diff --git a/emulator/src/main.cpp b/emulator/src/main.cpp index cba563b..40589fd 100644 --- a/emulator/src/main.cpp +++ b/emulator/src/main.cpp @@ -8,9 +8,9 @@ namespace { -std::vector read_file(std::istream& stream) +std::vector read_file(std::istream& stream) { - std::vector buf; + std::vector buf; std::streampos pos = stream.tellg(); stream.seekg(0, std::ios::end); @@ -20,9 +20,9 @@ std::vector read_file(std::istream& stream) for (int i = 0; i < buf.size(); i++) { - char value[2] = {0, 0}; - stream.read(value, 2); - buf[i] = (uint16_t(value[0]) << 8) | (uint16_t(value[1]) & 0xFF); + char value[4] = {}; + stream.read(value, 4); + buf[i] = uint32_t(value[0]) | uint32_t(value[1]) << 8 | uint32_t(value[2]) << 16 | uint32_t(value[3]) << 24; } return buf; @@ -38,7 +38,7 @@ public: bool update() override { - uint16_t& value = memory(0); + uint32_t& value = memory(0); if (value != 0) { std::cout << char(value); @@ -77,6 +77,7 @@ public: { for (int j = 0; j < height; j++) { + //TODO: fix const uint16_t mem = memory(i + j * width / 2); const uint8_t left = mem & 0xFF; diff --git a/emulator/tests/addi-instruction.cpp b/emulator/tests/addi-instruction.cpp index bff41f1..c682d1b 100644 --- a/emulator/tests/addi-instruction.cpp +++ b/emulator/tests/addi-instruction.cpp @@ -12,24 +12,7 @@ int main(int argc, char** argv) // b - 2, Immediate { foot::Emulator emu = run_instructions({ 0x00204567, 0x09200220 }); - if (!check(0x4569, emu.register_at(0))) { return 1; } - } - - // CNST - // dst - 0, Direct - // imm - 0x4567 - // - // CNST - // dst - 1, Direct - // imm = 0xFFFE (-2) - // - // ADDI - // dst - 0, Direct - // a - 0, Direct - // b - 1, Direct - { - foot::Emulator emu = run_instructions({ 0x00204567, 0x0021FFFE, 0x09202120 }); - if (!check(0x4565, emu.register_at(0))) { return 1; } + if (!check(0x00004569, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/arng-instruction.cpp b/emulator/tests/arng-instruction.cpp index dc16f92..0ced256 100644 --- a/emulator/tests/arng-instruction.cpp +++ b/emulator/tests/arng-instruction.cpp @@ -11,7 +11,7 @@ int main(int argc, char** argv) // a - 0, Direct { foot::Emulator emu = run_instructions({ 0x00204567, 0x01200220 }); - if (!check(0xBA99, emu.register_at(0))) { return 1; } + if (!check(0xFFFFBA99, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/band-instruction.cpp b/emulator/tests/band-instruction.cpp index 586daf0..af3cc79 100644 --- a/emulator/tests/band-instruction.cpp +++ b/emulator/tests/band-instruction.cpp @@ -16,7 +16,7 @@ int main(int argc, char** argv) // b - 1, Direct { foot::Emulator emu = run_instructions({ 0x00204567, 0x00212345, 0x03202021 }); - if (!check(0x4567 & 0x2345, emu.register_at(0))) { return 1; } + if (!check(0x00004567 & 0x00002345, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/bwng-instruction.cpp b/emulator/tests/bwng-instruction.cpp index 4abf780..2bda5cb 100644 --- a/emulator/tests/bwng-instruction.cpp +++ b/emulator/tests/bwng-instruction.cpp @@ -11,7 +11,7 @@ int main(int argc, char** argv) // a - 0, Direct { foot::Emulator emu = run_instructions({ 0x00204567, 0x01200120 }); - if (!check(0xBA98, emu.register_at(0))) { return 1; } + if (!check(0xFFFFBA98, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/bwor-instruction.cpp b/emulator/tests/bwor-instruction.cpp index 9ea7d85..d64725c 100644 --- a/emulator/tests/bwor-instruction.cpp +++ b/emulator/tests/bwor-instruction.cpp @@ -16,7 +16,7 @@ int main(int argc, char** argv) // b - 1, Direct { foot::Emulator emu = run_instructions({ 0x00204567, 0x00212345, 0x02202021 }); - if (!check(0x4567 | 0x2345, emu.register_at(0))) { return 1; } + if (!check(0x00004567 | 0x00002345, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/bxor-instruction.cpp b/emulator/tests/bxor-instruction.cpp index 95b72e2..14ffda5 100644 --- a/emulator/tests/bxor-instruction.cpp +++ b/emulator/tests/bxor-instruction.cpp @@ -16,7 +16,7 @@ int main(int argc, char** argv) // b - 1, Direct { foot::Emulator emu = run_instructions({ 0x00204567, 0x00212345, 0x04202021 }); - if (!check(0x4567 ^ 0x2345, emu.register_at(0))) { return 1; } + if (!check(0x00004567 ^ 0x00002345, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/clsh-instruction.cpp b/emulator/tests/clsh-instruction.cpp index c9c9db5..6b0dfb9 100644 --- a/emulator/tests/clsh-instruction.cpp +++ b/emulator/tests/clsh-instruction.cpp @@ -11,8 +11,8 @@ int main(int argc, char** argv) // a - 0, Direct // b - 2, Immediate { - foot::Emulator emu = run_instructions({ 0x00204567, 0x08200220 }); - if (!check(0x159D, emu.register_at(0))) { return 1; } + foot::Emulator emu = run_instructions({ 0x00204567, 0x08201820 }); + if (!check(0x67000045, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/cnst-instruction.cpp b/emulator/tests/cnst-instruction.cpp index 10351f2..3150fac 100644 --- a/emulator/tests/cnst-instruction.cpp +++ b/emulator/tests/cnst-instruction.cpp @@ -18,7 +18,7 @@ int main(int argc, char** argv) // dst - 0, Indirect // imm = 0x7777 { - foot::Emulator emu = run_instructions({ 0x0020FFFF, 0x00807777 }); + foot::Emulator emu = run_instructions({ 0x0020FFFF, 0x00407777 }); if (!check(0x7777, emu.memory_at(0xFFFF))) { return 1; } } @@ -31,7 +31,7 @@ int main(int argc, char** argv) // imm = 0x1234 { bool failed = false; - foot::Emulator emu = run_instructions({ 0x003E0010, 0x10401234 }); + foot::Emulator emu = run_instructions({ 0x003E0010, 0x10501234 }); for (int i = 0; i < 0x10; i++) { if (!check(0x1234, emu.memory_at(i))) { failed = true; } diff --git a/emulator/tests/divi-instruction.cpp b/emulator/tests/divi-instruction.cpp index 4df438c..23939cf 100644 --- a/emulator/tests/divi-instruction.cpp +++ b/emulator/tests/divi-instruction.cpp @@ -11,41 +11,41 @@ int main(int argc, char** argv) // a - 0, Direct // b - 2, Immediate { - foot::Emulator emu = run_instructions({ 0x00200005, 0x0E200220 }); - if (!check(0x0002, emu.register_at(0))) { return 1; } + foot::Emulator emu = run_instructions({ 0x00200005, 0x0C200220 }); + if (!check(0x00000002, emu.register_at(0))) { return 1; } } // CNST // dst - 0, Direct // imm - 0x0007 // - // CNST + // ARNG // dst - 1, Direct - // imm = 0xFFF9 (-7) + // a - 7, Immediate // // DIVI // dst - 0, Direct // a - 0, Direct // b - 1, Direct { - foot::Emulator emu = run_instructions({ 0x00200007, 0x0021FFF9, 0x0E202120 }); - if (!check(0xFFFF, emu.register_at(0))) { return 1; } + foot::Emulator emu = run_instructions({ 0x00200007, 0x01210207, 0x0C202120 }); + if (!check(0xFFFFFFFF, emu.register_at(0))) { return 1; } } - // CNST + // ARNG // dst - 0, Direct - // imm - 0xFFF9 (-7) + // a - 7, Immediate // - // CNST + // ARNG // dst - 1, Direct - // imm = 0xFFF9 (-7) + // a - 7, Immediate // // DIVI // dst - 0, Direct // a - 0, Direct // b - 1, Direct { - foot::Emulator emu = run_instructions({ 0x0020FFF9, 0x0021FFF9, 0x0E202120 }); + foot::Emulator emu = run_instructions({0x01200207, 0x01210207, 0x0C202120 }); if (!check(0x1, emu.register_at(0))) { return 1; } } @@ -55,7 +55,7 @@ int main(int argc, char** argv) // // CNST // dst - 1, Direct - // imm = 0x0001 (0.5) + // imm - 0x0001 (0.5) // // CONF // dst - X, Immediate @@ -66,9 +66,9 @@ int main(int argc, char** argv) // a - 0, Direct // b - 1, Direct { - foot::Emulator emu = run_instructions({ 0x00200002, 0x00210001, 0x01000401, 0x0E202120 }); - // 0x4 (2) - if (!check(0x4, emu.register_at(0))) { return 1; } + foot::Emulator emu = run_instructions({ 0x00200002, 0x00210001, 0x01000401, 0x0C202120 }); + // 1 / 0.5 = 2 + if (!check(2 << 1 /* shift 1 for 31.1 fixed-point format */, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/long-instruction.cpp b/emulator/tests/long-instruction.cpp index abd1a3d..f6e22b0 100644 --- a/emulator/tests/long-instruction.cpp +++ b/emulator/tests/long-instruction.cpp @@ -11,19 +11,15 @@ int main(int argc, char** argv) // a - 0, Direct { foot::Emulator emu = run_instructions({ 0x00204567, 0x01200320 }); - if (!check(0x0000, emu.register_at(0))) { return 1; } + if (!check(0x00000000, emu.register_at(0))) { return 1; } } - // CNST - // dst - 0, Direct - // imm - 0x0000 - // // LONG // dst - 0, Direct // a - 0, Direct { - foot::Emulator emu = run_instructions({ 0x00200000, 0x01200320 }); - if (!check(0x0001, emu.register_at(0))) { return 1; } + foot::Emulator emu = run_instruction(0x01200320); + if (!check(0x00000001, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/modu-instruction.cpp b/emulator/tests/modu-instruction.cpp index 5a27907..3a2ef51 100644 --- a/emulator/tests/modu-instruction.cpp +++ b/emulator/tests/modu-instruction.cpp @@ -6,12 +6,12 @@ int main(int argc, char** argv) // dst - 0, Direct // imm - 0x0005 // - // DIVI + // MODU // dst - 0, Direct // a - 0, Direct // b - 2, Immediate { - foot::Emulator emu = run_instructions({ 0x00200005, 0x0F200220 }); + foot::Emulator emu = run_instructions({ 0x00200005, 0x0D200220 }); if (!check(0x1, emu.register_at(0))) { return 1; } } @@ -19,34 +19,34 @@ int main(int argc, char** argv) // dst - 0, Direct // imm - 0x0005 // - // CNST + // ARNG // dst - 1, Direct - // imm = 0xFFFE (-2) + // a = 2, Immediate // - // DIVI + // MODU // dst - 0, Direct // a - 0, Direct // b - 1, Direct { - foot::Emulator emu = run_instructions({ 0x00200005, 0x0021FFFE, 0x0F202120 }); + foot::Emulator emu = run_instructions({ 0x00200005, 0x01210202, 0x0D202120 }); if (!check(0x1, emu.register_at(0))) { return 1; } } - // CNST + // ARNG // dst - 0, Direct - // imm - 0xFFFE (-2) + // a = 2, Immediate // // CNST // dst - 1, Direct // imm = 0x0005 // - // DIVI + // MODU // dst - 0, Direct // a - 0, Direct // b - 1, Direct { - foot::Emulator emu = run_instructions({ 0x0020FFFE, 0x00210005, 0x0F202120 }); - if (!check(0xFFFE, emu.register_at(0))) { return 1; } + foot::Emulator emu = run_instructions({ 0x01200202, 0x00210005, 0x0D202120 }); + if (!check(0xFFFFFFFE, emu.register_at(0))) { return 1; } } // CNST @@ -55,18 +55,18 @@ int main(int argc, char** argv) // // CNST // dst - 1, Direct - // imm = 0x0003 (1.5) + // imm - 0x0003 (1.5) // // CONF // dst - X, Immediate // a - 1, Immediate // - // MULT + // MODU // dst - 0, Direct // a - 0, Direct // b - 1, Direct { - foot::Emulator emu = run_instructions({ 0x00200005, 0x00210003, 0x01000401, 0x0F202120 }); + foot::Emulator emu = run_instructions({ 0x00200005, 0x00210003, 0x01000401, 0x0D202120 }); if (!check(0x2, emu.register_at(0))) { return 1; } } diff --git a/emulator/tests/mult-instruction.cpp b/emulator/tests/mult-instruction.cpp index 4692761..ca5e841 100644 --- a/emulator/tests/mult-instruction.cpp +++ b/emulator/tests/mult-instruction.cpp @@ -19,33 +19,33 @@ int main(int argc, char** argv) // dst - 0, Direct // imm - 0x0007 // - // CNST + // ARNG // dst - 1, Direct - // imm = 0xFFF9 (-7) + // a - 7, Immediate // // MULT // dst - 0, Direct // a - 0, Direct // b - 1, Direct { - foot::Emulator emu = run_instructions({ 0x00200007, 0x0021FFF9, 0x0B202120 }); - if (!check(0xFFCF, emu.register_at(0))) { return 1; } + foot::Emulator emu = run_instructions({ 0x00200007, 0x01210207, 0x0B202120 }); + if (!check(0xFFFFFFCF, emu.register_at(0))) { return 1; } } - // CNST + // ARNG // dst - 0, Direct - // imm - 0xFFF9 (-7) + // a - 7, Immediate // - // CNST + // ARNG // dst - 1, Direct - // imm = 0xFFF9 (-7) + // a - 7, Immediate // // MULT // dst - 0, Direct // a - 0, Direct // b - 1, Direct { - foot::Emulator emu = run_instructions({ 0x0020FFF9, 0x0021FFF9, 0x0B202120 }); + foot::Emulator emu = run_instructions({ 0x01200207, 0x01210207, 0x0B202120 }); if (!check(0x31, emu.register_at(0))) { return 1; } } @@ -55,7 +55,7 @@ int main(int argc, char** argv) // // CNST // dst - 1, Direct - // imm = 0x0007 (3.5) + // imm - 0x0007 (3.5) // // CONF // dst - X, Immediate @@ -67,8 +67,8 @@ int main(int argc, char** argv) // b - 1, Direct { foot::Emulator emu = run_instructions({ 0x00200007, 0x00210007, 0x01000401, 0x0B202120 }); - // 0x18 (12) - if (!check(0x18, emu.register_at(0))) { return 1; } + // 3.5 * 3.5 = 12.25 -- truncated to 12 with 31.1 fixed-point format + if (!check(12 << 1 /* shift 1 for 31.1 fixed-point format */, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/srsh-instruction.cpp b/emulator/tests/srsh-instruction.cpp index 3cc74e0..405942a 100644 --- a/emulator/tests/srsh-instruction.cpp +++ b/emulator/tests/srsh-instruction.cpp @@ -15,16 +15,16 @@ int main(int argc, char** argv) if (!check(0x4567 >> 2, emu.register_at(0))) { return 1; } } - // CNST + // ARNG // dst - 0, Direct - // imm - 0x8000 + // a - 4, Immediate // // SRSH // dst - 0, Direct // a - 0, Direct { - foot::Emulator emu = run_instructions({ 0x00208000, 0x06200220 }); - if (!check((-0x8000) >> 2, emu.register_at(0))) { return 1; } + foot::Emulator emu = run_instructions({ 0x01200204, 0x06200220 }); + if (!check((-2) >> 2, emu.register_at(0))) { return 1; } } return 0; diff --git a/emulator/tests/subt-instruction.cpp b/emulator/tests/subt-instruction.cpp index 5d52f45..3e2b126 100644 --- a/emulator/tests/subt-instruction.cpp +++ b/emulator/tests/subt-instruction.cpp @@ -19,16 +19,16 @@ int main(int argc, char** argv) // dst - 0, Direct // imm - 0x4567 // - // CNST + // ARNG // dst - 1, Direct - // imm = 0xFFFE (-2) + // a - 2, Immediate // // SUBT // dst - 0, Direct // a - 0, Direct // b - 1, Direct { - foot::Emulator emu = run_instructions({ 0x00204567, 0x0021FFFE, 0x0A202120 }); + foot::Emulator emu = run_instructions({ 0x00204567, 0x01210202, 0x0A202120 }); if (!check(0x4569, emu.register_at(0))) { return 1; } } diff --git a/emulator/tests/test-common.h b/emulator/tests/test-common.h index b17bbb4..d51598a 100644 --- a/emulator/tests/test-common.h +++ b/emulator/tests/test-common.h @@ -5,8 +5,7 @@ inline foot::Emulator run_instruction(uint32_t instruction) { foot::Emulator emu; - emu.memory_at(0) = instruction & 0xFFFF; - emu.memory_at(1) = (instruction >> 16) & 0xFFFF; + emu.memory_at(0) = instruction; emu.run_instruction(); @@ -18,8 +17,7 @@ inline foot::Emulator run_instructions(const std::vector& instructions foot::Emulator emu; for (int i = 0; i < instructions.size(); i++) { - emu.memory_at(i * 2) = instructions[i] & 0xFFFF; - emu.memory_at(i * 2 + 1) = (instructions[i] >> 16) & 0xFFFF; + emu.memory_at(i) = instructions[i]; } for (int i = 0; i < instructions.size(); i++) @@ -30,7 +28,7 @@ inline foot::Emulator run_instructions(const std::vector& instructions return emu; } -inline bool check(uint16_t expected, uint16_t actual) +inline bool check(uint32_t expected, uint32_t actual) { if (actual != expected) { diff --git a/emulator/tests/zlsh-instruction.cpp b/emulator/tests/zlsh-instruction.cpp index e9218bc..24bd1e5 100644 --- a/emulator/tests/zlsh-instruction.cpp +++ b/emulator/tests/zlsh-instruction.cpp @@ -12,7 +12,7 @@ int main(int argc, char** argv) // b - 2, Immediate { foot::Emulator emu = run_instructions({ 0x00204567, 0x07200220 }); - if (!check(0x159C, emu.register_at(0))) { return 1; } + if (!check(0x0001159C, emu.register_at(0))) { return 1; } } return 0;