Add SIMD instruction variants
All checks were successful
Test / build (push) Successful in 13s

This commit is contained in:
shylie 2025-08-17 11:18:08 -04:00
parent f3773fc82b
commit 80d83f2062
24 changed files with 337 additions and 270 deletions

View File

@ -9,8 +9,8 @@ jobs:
- name: Checkout current - name: Checkout current
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Configure - name: Configure
run: cmake -S emulator -B emulator/build run: cmake -S . -B build
- name: Build - name: Build
run: cmake --build emulator/build run: cmake --build build
- name: Test - name: Test
run: cd emulator/build && ctest --output-on-failure run: cd build && ctest --output-on-failure

4
.gitignore vendored
View File

@ -1,3 +1,3 @@
emulator/.cache/ .cache/
emulator/build/ build/
emulator/customasm/*.bin emulator/customasm/*.bin

12
CMakeLists.txt Normal file
View File

@ -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)

127
DOCS.txt
View File

@ -1,52 +1,52 @@
╔════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ ╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║ Foot ISA ║ ║ Foot ISA ║
╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦════════════════════════════════╣ ╠══════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦════════════════════════════════╣
Instruction Format ║ ║ Addressing Modes ║ Instruction Format ║ ║ Addressing modes
╠══════════╦═══════════════════════════════════════════════╦═══════════════════════════════════════════════════════╣ ╠══════╦═════════════════════════╣ ╠══════════╦══════════════════════╦════════════════╦═══════════════════════════════════════════════════════╣ ╠══════╦═════════════════════════╣
║ ║ ║ Encoding ║ ║ 000 ║ Immediate ║ ║ ║ ║ ║ Encoding ║ ║ 00 ║ Immediate ║
║ Mnemonic ║ Description ║ Semantics ╠═════════════╦═════════════╦═════════════╦═════════════╣ ╠══════╬═════════════════════════╣ ║ Mnemonic ║ Description ║ Semantics ╠═════════════╦═════════════╦═════════════╦═════════════╣ ╠══════╬═════════════════════════╣
║ ║ ║ ║ 24-31 ║ 16-23 ║ 8-15 ║ 0-7 ║ ║ 001 ║ Direct ║ ║ ║ ║ ║ 24-31 ║ 16-23 ║ 8-15 ║ 0-7 ║ ║ 01 ║ Direct ║
╠══════════╬═══════════════════════════════════════════════╬══════╦══════╬══════╦══════╬══════╦══════╬══════╦══════╣ ╠══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╦══════╬══════╦══════╬══════╦══════╬══════╦══════╣ ╠══════╬═════════════════════════╣
CNST ║ Immediate ║ D = I ║ CCCR ║ 0000 ║ DDDd ║ dddd ║ iiii ║ iiii ║ iiii ║ iiii ║ ║ 010 ║ Indirect Auto-increment CNST ║ Load immediate ║ D = I ║ CCCR ║ 0000 ║ 0DDd ║ dddd ║ iiii ║ iiii ║ iiii ║ iiii ║ ║ 10 ║ Indirect
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
CMPR ║ Compare ║ C = A <=> B ║ CCCR ║ 0001 ║ BBBb ║ bbbb ║ 0000 ║ 0000 ║ AAAa ║ aaaa ║ ║ 011 ║ Indirect Auto-decrement ║ CMPR ║ Compare ║ C = A <=> B ║ CCCR ║ 0001 ║ 0BBb ║ bbbb ║ 0000 ║ 0000 ║ 0AAa ║ aaaa ║ ║ 11 ║ Indirect auto-increment ║
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════════════════════════════╣
BWNG ║ Bitwise negate ║ D = ~A ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0001 ║ AAAa ║ aaaa ║ ║ 100 ║ Indirect BWNG ║ Bitwise negate ║ D = ~A ║ CCCR ║ 0001 ║ 0DDd ║ dddd ║ 0000 ║ 0001 ║ 0AAa ║ aaaa ║ ║ Conditional execution flags
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════════════════════════════╣
ARNG ║ Arithmetic negate ║ D = -A ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0010 ║ AAAa ║ aaaa ║ ║ 101 ║ Indirect 1-word offset ARNG ║ Arithmetic negate ║ D = -A ║ CCCR ║ 0001 ║ xDDd ║ dddd ║ 0000 ║ 0010 ║ xAAa ║ aaaa ║ ║ 000 ║ Always
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
LONG ║ Logical negate ║ D = !A ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0011 ║ AAAa ║ aaaa ║ ║ 110 ║ Indirect 2-word offset LONG ║ Logical negate ║ D = !A ║ CCCR ║ 0001 ║ xDDd ║ dddd ║ 0000 ║ 0011 ║ xAAa ║ aaaa ║ ║ 001 ║ A < B
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
CONF ║ Configure processor ║ ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0100 ║ AAAa ║ aaaa ║ ║ 111 ║ Indirect 3-word offset 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 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ Conditional Execution Flags 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 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 000 ║ Always BAND ║ Bitwise and ║ D = A & B ║ CCCR ║ 0011 ║ 0DDd ║ dddd ║ 0BBb ║ bbbb ║ 0AAa ║ aaaa ║ ║ 100 ║ A >= B
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
BXOR ║ Bitwise xor ║ D = A ^ B ║ CCCR ║ 0100 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 001 ║ A < B ║ BXOR ║ Bitwise exclusive or ║ D = A ^ B ║ CCCR ║ 0100 ║ 0DDd ║ dddd ║ 0BBb ║ bbbb ║ 0AAa ║ aaaa ║ ║ 101 ║ A > B ║
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
║ RESERVED ║ ║ ║ CCCR ║ 0101 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 010 ║ A <= B ║ ║ RESERVED ║ ║ ║ ║ 0101 ║ ║ ║ ║ ║ ║ ║ ║ 110 ║ A != B ║
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
SRSH ║ Signed right shift ║ D = A >> B ║ CCCR ║ 0110 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 011 ║ 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 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 100 ║ A >= B 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 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 101 ║ A > B 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 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 110 ║ A != B 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 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 111 ║ Reserved SUBT ║ Subtraction ║ D = A - B ║ CCCR ║ 1010 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 10 ║ 4 8-bit numbers
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╩═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════════════════════════════╣
MULT ║ Multiplication ║ D = A * B >> shift ║ CCCR ║ 1011 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ Processor configuration bits MULT ║ Multiplication ║ D = A * B ║ CCCR ║ 1011 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 11 ║ 8 4-bit numbers
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╦═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════════════════════════════╣
RESERVED ║ ║ ║ CCCR ║ 1100 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 3-0 ║ Multiplication shift DIVI ║ Division ║ D = A / B ║ CCCR ║ 1100 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ Processor configuration bits
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════════════════════════════╣
RESERVED ║ ║ ║ CCCR ║ 1101 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 7-4 ║ Reserved MODU ║ Modulus ║ D = A % B ║ CCCR ║ 1101 ║ xDDd ║ dddd ║ 0BBb ║ bbbb ║ xAAa ║ aaaa ║ ║ 4-0 ║ Multiplication shift
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
DIVI ║ Division ║ D = (A << shift) / B ║ CCCR ║ 1110 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 11-8 ║ Reserved ║ RESERVED ║ ║ ║ ║ 1110 ║ ║ ║ ║ ║ ║ ║ ║ 31-4 ║ Reserved ║
╠══════════╬═══════════════════════════════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣ ╠══════════╬══════════════════════╬════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠══════╬═════════════════════════╣
MODU ║ Modulus ║ D = (A << shift) % B ║ CCCR ║ 1111 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 15-12 ║ Reserved RESERVED ║ ║ ║ ║ 1111 ║ ║ ║ ║ ║ ║ ║ ║ ║
╚══════════╩═══════════════════════════════════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══╩══════╩═════════════════════════╝ ╚══════════╩══════════════════════╩════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══╩══════╩═════════════════════════╝
╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
║ Foot ISA Table Key ║ ║ Foot ISA Table Key ║
@ -60,30 +60,27 @@
║ ║ Store to register ║ ║ ║ indicated A is less than B ║ ║ ║ ║ ║ ║ ║ ║ 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 ║ ║ 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 ║ ║ ║ ║ ║ ║ ║ ║ 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 ║ ║ 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. ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ 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 ║ ║ 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 ║ ║ ║ ║ ║ ║ ║ ║ then use memory contents as operand ║ ║ ║ indicated A is greater than ║ ║ ║ ║ ║ ║
║ ║ or store to memory. ║ ║ ║ or equal to B ║ ║ ║ ║ ║ ║ ║ ║ 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 ║ ║ ║ ║ 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 ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ indicated A is greater than B ║ ║ ║ ║ ║ ║
║ ║ as operand or store to memory. ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ╠════════╬═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣
╠═════════════════╬════════════════════════════════════════════╣ ╠════════╬═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ ║ ║ ║ A != B ║ Run if last CMPR instruction ║ ║ ║ ║ B ║ Operand B Addressing Mode ║
║ Indirect 2-word ║ Use register contents as memory address, ║ ║ A != B ║ Run if last CMPR instruction ║ ║ ║ ║ B ║ Operand B Addressing Mode ║ ║ ║ ║ ║ indicated A is not equal to B ║ ║ ║ ║ ║ ║
║ Offset ║ add 2 to address, then use memory contents ║ ║ ║ indicated A is not equal to B ║ ║ ║ ║ ║ ║ ║ ║ ╠════════╩═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣
║ ║ as operand or store to memory. ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ b ║ Operand B Register Index ║
╠═════════════════╬════════════════════════════════════════════╣ ╠════════╩═══════════════════════════════╣ ║ ║ ╠═══╬═════════════════════════════╣ ║ ║ ║ ║ ║ ║ ║ ║ ║
║ 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. ║ ║ ║ ║ ║ ║ ║ ║
╠═════════════════╩════════════════════════════════════════════╣ ║ ║ ║ ║ ╠═══╬═════════════════════════════╣
║ ║ ║ ║ ║ ║ ║ i ║ Immediate Integer ║ ║ ║ ║ ║ ║ ║ ║ i ║ Immediate Integer ║
╚══════════════════════════════════════════════════════════════╩══╩════════════════════════════════════════╩══╩══════════════════════════════════════════════════╩══╩═══╩═════════════════════════════╝ ╚══════════════════════════════════════════════════════════════╩══╩════════════════════════════════════════╩══╩══════════════════════════════════════════════════╩══╩═══╩═════════════════════════════╝

View File

@ -10,7 +10,6 @@ find_package(SDL3 REQUIRED CONFIG)
add_executable(foot-emulator-cli src/main.cpp) add_executable(foot-emulator-cli src/main.cpp)
target_link_libraries(foot-emulator-cli PUBLIC foot-emulator SDL3::SDL3) target_link_libraries(foot-emulator-cli PUBLIC foot-emulator SDL3::SDL3)
if(PROJECT_IS_TOP_LEVEL) if(FOOT_TESTS)
enable_testing()
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()

View File

@ -18,11 +18,7 @@ struct Operand
Immediate = 0, Immediate = 0,
Direct, Direct,
IndirectAutoIncrement, IndirectAutoIncrement,
IndirectAutoDecrement, Indirect
Indirect,
IndirectOffset1Word,
IndirectOffset2Word,
IndirectOffset3Word
} addressing_mode; } addressing_mode;
uint8_t register_index; uint8_t register_index;
}; };
@ -39,11 +35,11 @@ public:
protected: protected:
Device(uint16_t size); Device(uint16_t size);
uint16_t& memory(uint16_t index); uint32_t& memory(uint16_t index);
private: private:
uint16_t* assigned_memory_base; uint32_t* assigned_memory_base;
uint16_t assigned_memory_size; uint32_t assigned_memory_size;
}; };
class Emulator class Emulator
@ -54,18 +50,18 @@ public:
Emulator(); Emulator();
void run(const std::vector<uint16_t>& program); void run(const std::vector<uint32_t>& program);
void map_device(std::unique_ptr<Device>&& device); void map_device(std::unique_ptr<Device>&& device);
uint16_t& memory_at(uint16_t address); uint32_t& memory_at(uint16_t address);
uint16_t& decode_operand(Operand operand); uint32_t& decode_operand(Operand operand);
uint16_t& register_at(uint8_t index); uint32_t& register_at(uint8_t index);
void run_instruction(); void run_instruction();
private: private:
std::array<uint16_t, 1 << 16> memory; std::array<uint32_t, 1 << 16> memory;
std::array<uint16_t, 1 << 5> registers; std::array<uint32_t, 1 << 5> registers;
enum class Status enum class Status
{ {
Less, Less,
@ -73,8 +69,8 @@ private:
Greater Greater
} status_register; } status_register;
uint32_t instruction; uint32_t instruction;
uint16_t configuration; uint32_t configuration;
uint16_t dummy_value; uint32_t dummy_value;
std::vector<std::unique_ptr<Device>> devices; std::vector<std::unique_ptr<Device>> devices;
uint16_t mapped_base; uint16_t mapped_base;
bool keep_running; bool keep_running;
@ -99,8 +95,23 @@ private:
void DIVI(); void DIVI();
void MODU(); void MODU();
bool repeats(); bool repeats() const;
uint8_t shift(); 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;
}; };
} }

View File

@ -6,7 +6,7 @@ namespace foot
{ {
Operand::Operand(uint8_t bits) : Operand::Operand(uint8_t bits) :
addressing_mode(static_cast<AddressingMode>((bits & 0b11100000) >> 5)), addressing_mode(static_cast<AddressingMode>((bits & 0b01100000) >> 5)),
register_index(bits & 0b00011111) register_index(bits & 0b00011111)
{} {}
@ -15,7 +15,7 @@ Device::Device(uint16_t size) :
assigned_memory_size(size) assigned_memory_size(size)
{} {}
uint16_t& Device::memory(uint16_t index) uint32_t& Device::memory(uint16_t index)
{ {
if (index >= assigned_memory_size) if (index >= assigned_memory_size)
{ {
@ -31,7 +31,7 @@ Emulator::Emulator() :
mapped_base(0) mapped_base(0)
{} {}
void Emulator::run(const std::vector<uint16_t>& program) void Emulator::run(const std::vector<uint32_t>& program)
{ {
std::copy(program.begin(), program.end(), memory.begin()); std::copy(program.begin(), program.end(), memory.begin());
@ -57,12 +57,12 @@ void Emulator::map_device(std::unique_ptr<Device>&& device)
devices.push_back(std::move(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]; return memory[address];
} }
uint16_t& Emulator::decode_operand(Operand operand) uint32_t& Emulator::decode_operand(Operand operand)
{ {
switch (operand.addressing_mode) switch (operand.addressing_mode)
{ {
@ -76,27 +76,15 @@ uint16_t& Emulator::decode_operand(Operand operand)
case Operand::AddressingMode::IndirectAutoIncrement: case Operand::AddressingMode::IndirectAutoIncrement:
return memory[registers[operand.register_index]++]; return memory[registers[operand.register_index]++];
case Operand::AddressingMode::IndirectAutoDecrement:
return memory[registers[operand.register_index]--];
case Operand::AddressingMode::Indirect: case Operand::AddressingMode::Indirect:
return memory[registers[operand.register_index]]; 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: default:
return dummy_value; return dummy_value;
} }
} }
uint16_t& Emulator::register_at(uint8_t index) uint32_t& Emulator::register_at(uint8_t index)
{ {
return registers[index]; return registers[index];
} }
@ -106,7 +94,7 @@ void Emulator::run_instruction()
read_instruction(); read_instruction();
const bool rep = repeats(); 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++) for (int iteration = 0; iteration < loop_count; iteration++)
{ {
@ -155,9 +143,6 @@ void Emulator::run_instruction()
BXOR(); BXOR();
break; break;
case 5:
break;
case 6: case 6:
SRSH(); SRSH();
break; break;
@ -182,11 +167,11 @@ void Emulator::run_instruction()
MULT(); MULT();
break; break;
case 14: case 12:
DIVI(); DIVI();
break; break;
case 15: case 13:
MODU(); MODU();
break; break;
@ -200,10 +185,7 @@ void Emulator::run_instruction()
void Emulator::read_instruction() void Emulator::read_instruction()
{ {
uint16_t low = memory[registers[PC]++]; instruction = memory[registers[PC]++];
uint16_t high = memory[registers[PC]++];
instruction = (uint32_t(high) << 16) | uint32_t(low);
} }
void Emulator::CNST() void Emulator::CNST()
@ -213,8 +195,8 @@ void Emulator::CNST()
void Emulator::CMPR() void Emulator::CMPR()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t b = decode_operand((instruction & 0x00FF0000) >> 16);
if (a < b) if (a < b)
{ {
@ -232,32 +214,32 @@ void Emulator::CMPR()
void Emulator::BWNG() void Emulator::BWNG()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = ~a; d = ~a;
} }
void Emulator::ARNG() void Emulator::ARNG()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = -a; d = apply_many_unary(a, &Emulator::op_arithmetic_negate);
} }
void Emulator::LONG() void Emulator::LONG()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = !a; d = apply_many_unary(a, &Emulator::op_logical_negate);
} }
void Emulator::CONF() void Emulator::CONF()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = configuration; d = configuration;
configuration = a; configuration = a;
@ -265,112 +247,200 @@ void Emulator::CONF()
void Emulator::BWOR() void Emulator::BWOR()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = a | b; d = a | b;
} }
void Emulator::BAND() void Emulator::BAND()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = a & b; d = a & b;
} }
void Emulator::BXOR() void Emulator::BXOR()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = a ^ b; d = a ^ b;
} }
void Emulator::SRSH() void Emulator::SRSH()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); 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() void Emulator::ZLSH()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); 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() void Emulator::CLSH()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); 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() void Emulator::ADDI()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = a + b; d = apply_many_binary(a, b, &Emulator::op_add);
} }
void Emulator::SUBT() void Emulator::SUBT()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = a - b; d = apply_many_binary(a, b, &Emulator::op_sub);
} }
void Emulator::MULT() void Emulator::MULT()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); 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() void Emulator::DIVI()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
// convert from unsigned to signed, then widen d = apply_many_binary(a, b, &Emulator::op_div);
d = uint32_t((int32_t(int16_t(a)) << shift()) / int32_t(int16_t(b)));
} }
void Emulator::MODU() void Emulator::MODU()
{ {
uint16_t a = decode_operand(instruction & 0x000000FF); uint32_t a = decode_operand(instruction & 0x000000FF);
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8); uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16); 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; 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);
} }
} }

View File

@ -8,9 +8,9 @@
namespace namespace
{ {
std::vector<uint16_t> read_file(std::istream& stream) std::vector<uint32_t> read_file(std::istream& stream)
{ {
std::vector<uint16_t> buf; std::vector<uint32_t> buf;
std::streampos pos = stream.tellg(); std::streampos pos = stream.tellg();
stream.seekg(0, std::ios::end); stream.seekg(0, std::ios::end);
@ -20,9 +20,9 @@ std::vector<uint16_t> read_file(std::istream& stream)
for (int i = 0; i < buf.size(); i++) for (int i = 0; i < buf.size(); i++)
{ {
char value[2] = {0, 0}; char value[4] = {};
stream.read(value, 2); stream.read(value, 4);
buf[i] = (uint16_t(value[0]) << 8) | (uint16_t(value[1]) & 0xFF); buf[i] = uint32_t(value[0]) | uint32_t(value[1]) << 8 | uint32_t(value[2]) << 16 | uint32_t(value[3]) << 24;
} }
return buf; return buf;
@ -38,7 +38,7 @@ public:
bool update() override bool update() override
{ {
uint16_t& value = memory(0); uint32_t& value = memory(0);
if (value != 0) if (value != 0)
{ {
std::cout << char(value); std::cout << char(value);
@ -77,6 +77,7 @@ public:
{ {
for (int j = 0; j < height; j++) for (int j = 0; j < height; j++)
{ {
//TODO: fix
const uint16_t mem = memory(i + j * width / 2); const uint16_t mem = memory(i + j * width / 2);
const uint8_t left = mem & 0xFF; const uint8_t left = mem & 0xFF;

View File

@ -12,24 +12,7 @@ int main(int argc, char** argv)
// b - 2, Immediate // b - 2, Immediate
{ {
foot::Emulator emu = run_instructions({ 0x00204567, 0x09200220 }); foot::Emulator emu = run_instructions({ 0x00204567, 0x09200220 });
if (!check(0x4569, emu.register_at(0))) { return 1; } if (!check(0x00004569, 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; }
} }
return 0; return 0;

View File

@ -11,7 +11,7 @@ int main(int argc, char** argv)
// a - 0, Direct // a - 0, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00204567, 0x01200220 }); 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; return 0;

View File

@ -16,7 +16,7 @@ int main(int argc, char** argv)
// b - 1, Direct // b - 1, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00204567, 0x00212345, 0x03202021 }); 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; return 0;

View File

@ -11,7 +11,7 @@ int main(int argc, char** argv)
// a - 0, Direct // a - 0, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00204567, 0x01200120 }); 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; return 0;

View File

@ -16,7 +16,7 @@ int main(int argc, char** argv)
// b - 1, Direct // b - 1, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00204567, 0x00212345, 0x02202021 }); 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; return 0;

View File

@ -16,7 +16,7 @@ int main(int argc, char** argv)
// b - 1, Direct // b - 1, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00204567, 0x00212345, 0x04202021 }); 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; return 0;

View File

@ -11,8 +11,8 @@ int main(int argc, char** argv)
// a - 0, Direct // a - 0, Direct
// b - 2, Immediate // b - 2, Immediate
{ {
foot::Emulator emu = run_instructions({ 0x00204567, 0x08200220 }); foot::Emulator emu = run_instructions({ 0x00204567, 0x08201820 });
if (!check(0x159D, emu.register_at(0))) { return 1; } if (!check(0x67000045, emu.register_at(0))) { return 1; }
} }
return 0; return 0;

View File

@ -18,7 +18,7 @@ int main(int argc, char** argv)
// dst - 0, Indirect // dst - 0, Indirect
// imm = 0x7777 // 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; } if (!check(0x7777, emu.memory_at(0xFFFF))) { return 1; }
} }
@ -31,7 +31,7 @@ int main(int argc, char** argv)
// imm = 0x1234 // imm = 0x1234
{ {
bool failed = false; bool failed = false;
foot::Emulator emu = run_instructions({ 0x003E0010, 0x10401234 }); foot::Emulator emu = run_instructions({ 0x003E0010, 0x10501234 });
for (int i = 0; i < 0x10; i++) for (int i = 0; i < 0x10; i++)
{ {
if (!check(0x1234, emu.memory_at(i))) { failed = true; } if (!check(0x1234, emu.memory_at(i))) { failed = true; }

View File

@ -11,41 +11,41 @@ int main(int argc, char** argv)
// a - 0, Direct // a - 0, Direct
// b - 2, Immediate // b - 2, Immediate
{ {
foot::Emulator emu = run_instructions({ 0x00200005, 0x0E200220 }); foot::Emulator emu = run_instructions({ 0x00200005, 0x0C200220 });
if (!check(0x0002, emu.register_at(0))) { return 1; } if (!check(0x00000002, emu.register_at(0))) { return 1; }
} }
// CNST // CNST
// dst - 0, Direct // dst - 0, Direct
// imm - 0x0007 // imm - 0x0007
// //
// CNST // ARNG
// dst - 1, Direct // dst - 1, Direct
// imm = 0xFFF9 (-7) // a - 7, Immediate
// //
// DIVI // DIVI
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
// b - 1, Direct // b - 1, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00200007, 0x0021FFF9, 0x0E202120 }); foot::Emulator emu = run_instructions({ 0x00200007, 0x01210207, 0x0C202120 });
if (!check(0xFFFF, emu.register_at(0))) { return 1; } if (!check(0xFFFFFFFF, emu.register_at(0))) { return 1; }
} }
// CNST // ARNG
// dst - 0, Direct // dst - 0, Direct
// imm - 0xFFF9 (-7) // a - 7, Immediate
// //
// CNST // ARNG
// dst - 1, Direct // dst - 1, Direct
// imm = 0xFFF9 (-7) // a - 7, Immediate
// //
// DIVI // DIVI
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
// b - 1, 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; } if (!check(0x1, emu.register_at(0))) { return 1; }
} }
@ -55,7 +55,7 @@ int main(int argc, char** argv)
// //
// CNST // CNST
// dst - 1, Direct // dst - 1, Direct
// imm = 0x0001 (0.5) // imm - 0x0001 (0.5)
// //
// CONF // CONF
// dst - X, Immediate // dst - X, Immediate
@ -66,9 +66,9 @@ int main(int argc, char** argv)
// a - 0, Direct // a - 0, Direct
// b - 1, Direct // b - 1, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00200002, 0x00210001, 0x01000401, 0x0E202120 }); foot::Emulator emu = run_instructions({ 0x00200002, 0x00210001, 0x01000401, 0x0C202120 });
// 0x4 (2) // 1 / 0.5 = 2
if (!check(0x4, emu.register_at(0))) { return 1; } if (!check(2 << 1 /* shift 1 for 31.1 fixed-point format */, emu.register_at(0))) { return 1; }
} }
return 0; return 0;

View File

@ -11,19 +11,15 @@ int main(int argc, char** argv)
// a - 0, Direct // a - 0, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00204567, 0x01200320 }); 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 // LONG
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00200000, 0x01200320 }); foot::Emulator emu = run_instruction(0x01200320);
if (!check(0x0001, emu.register_at(0))) { return 1; } if (!check(0x00000001, emu.register_at(0))) { return 1; }
} }
return 0; return 0;

View File

@ -6,12 +6,12 @@ int main(int argc, char** argv)
// dst - 0, Direct // dst - 0, Direct
// imm - 0x0005 // imm - 0x0005
// //
// DIVI // MODU
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
// b - 2, Immediate // 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; } if (!check(0x1, emu.register_at(0))) { return 1; }
} }
@ -19,34 +19,34 @@ int main(int argc, char** argv)
// dst - 0, Direct // dst - 0, Direct
// imm - 0x0005 // imm - 0x0005
// //
// CNST // ARNG
// dst - 1, Direct // dst - 1, Direct
// imm = 0xFFFE (-2) // a = 2, Immediate
// //
// DIVI // MODU
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
// b - 1, 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; } if (!check(0x1, emu.register_at(0))) { return 1; }
} }
// CNST // ARNG
// dst - 0, Direct // dst - 0, Direct
// imm - 0xFFFE (-2) // a = 2, Immediate
// //
// CNST // CNST
// dst - 1, Direct // dst - 1, Direct
// imm = 0x0005 // imm = 0x0005
// //
// DIVI // MODU
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
// b - 1, Direct // b - 1, Direct
{ {
foot::Emulator emu = run_instructions({ 0x0020FFFE, 0x00210005, 0x0F202120 }); foot::Emulator emu = run_instructions({ 0x01200202, 0x00210005, 0x0D202120 });
if (!check(0xFFFE, emu.register_at(0))) { return 1; } if (!check(0xFFFFFFFE, emu.register_at(0))) { return 1; }
} }
// CNST // CNST
@ -55,18 +55,18 @@ int main(int argc, char** argv)
// //
// CNST // CNST
// dst - 1, Direct // dst - 1, Direct
// imm = 0x0003 (1.5) // imm - 0x0003 (1.5)
// //
// CONF // CONF
// dst - X, Immediate // dst - X, Immediate
// a - 1, Immediate // a - 1, Immediate
// //
// MULT // MODU
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
// b - 1, 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; } if (!check(0x2, emu.register_at(0))) { return 1; }
} }

View File

@ -19,33 +19,33 @@ int main(int argc, char** argv)
// dst - 0, Direct // dst - 0, Direct
// imm - 0x0007 // imm - 0x0007
// //
// CNST // ARNG
// dst - 1, Direct // dst - 1, Direct
// imm = 0xFFF9 (-7) // a - 7, Immediate
// //
// MULT // MULT
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
// b - 1, Direct // b - 1, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00200007, 0x0021FFF9, 0x0B202120 }); foot::Emulator emu = run_instructions({ 0x00200007, 0x01210207, 0x0B202120 });
if (!check(0xFFCF, emu.register_at(0))) { return 1; } if (!check(0xFFFFFFCF, emu.register_at(0))) { return 1; }
} }
// CNST // ARNG
// dst - 0, Direct // dst - 0, Direct
// imm - 0xFFF9 (-7) // a - 7, Immediate
// //
// CNST // ARNG
// dst - 1, Direct // dst - 1, Direct
// imm = 0xFFF9 (-7) // a - 7, Immediate
// //
// MULT // MULT
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
// b - 1, 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; } if (!check(0x31, emu.register_at(0))) { return 1; }
} }
@ -55,7 +55,7 @@ int main(int argc, char** argv)
// //
// CNST // CNST
// dst - 1, Direct // dst - 1, Direct
// imm = 0x0007 (3.5) // imm - 0x0007 (3.5)
// //
// CONF // CONF
// dst - X, Immediate // dst - X, Immediate
@ -67,8 +67,8 @@ int main(int argc, char** argv)
// b - 1, Direct // b - 1, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00200007, 0x00210007, 0x01000401, 0x0B202120 }); foot::Emulator emu = run_instructions({ 0x00200007, 0x00210007, 0x01000401, 0x0B202120 });
// 0x18 (12) // 3.5 * 3.5 = 12.25 -- truncated to 12 with 31.1 fixed-point format
if (!check(0x18, emu.register_at(0))) { return 1; } if (!check(12 << 1 /* shift 1 for 31.1 fixed-point format */, emu.register_at(0))) { return 1; }
} }
return 0; return 0;

View File

@ -15,16 +15,16 @@ int main(int argc, char** argv)
if (!check(0x4567 >> 2, emu.register_at(0))) { return 1; } if (!check(0x4567 >> 2, emu.register_at(0))) { return 1; }
} }
// CNST // ARNG
// dst - 0, Direct // dst - 0, Direct
// imm - 0x8000 // a - 4, Immediate
// //
// SRSH // SRSH
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
{ {
foot::Emulator emu = run_instructions({ 0x00208000, 0x06200220 }); foot::Emulator emu = run_instructions({ 0x01200204, 0x06200220 });
if (!check((-0x8000) >> 2, emu.register_at(0))) { return 1; } if (!check((-2) >> 2, emu.register_at(0))) { return 1; }
} }
return 0; return 0;

View File

@ -19,16 +19,16 @@ int main(int argc, char** argv)
// dst - 0, Direct // dst - 0, Direct
// imm - 0x4567 // imm - 0x4567
// //
// CNST // ARNG
// dst - 1, Direct // dst - 1, Direct
// imm = 0xFFFE (-2) // a - 2, Immediate
// //
// SUBT // SUBT
// dst - 0, Direct // dst - 0, Direct
// a - 0, Direct // a - 0, Direct
// b - 1, 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; } if (!check(0x4569, emu.register_at(0))) { return 1; }
} }

View File

@ -5,8 +5,7 @@
inline foot::Emulator run_instruction(uint32_t instruction) inline foot::Emulator run_instruction(uint32_t instruction)
{ {
foot::Emulator emu; foot::Emulator emu;
emu.memory_at(0) = instruction & 0xFFFF; emu.memory_at(0) = instruction;
emu.memory_at(1) = (instruction >> 16) & 0xFFFF;
emu.run_instruction(); emu.run_instruction();
@ -18,8 +17,7 @@ inline foot::Emulator run_instructions(const std::vector<uint32_t>& instructions
foot::Emulator emu; foot::Emulator emu;
for (int i = 0; i < instructions.size(); i++) for (int i = 0; i < instructions.size(); i++)
{ {
emu.memory_at(i * 2) = instructions[i] & 0xFFFF; emu.memory_at(i) = instructions[i];
emu.memory_at(i * 2 + 1) = (instructions[i] >> 16) & 0xFFFF;
} }
for (int i = 0; i < instructions.size(); i++) for (int i = 0; i < instructions.size(); i++)
@ -30,7 +28,7 @@ inline foot::Emulator run_instructions(const std::vector<uint32_t>& instructions
return emu; return emu;
} }
inline bool check(uint16_t expected, uint16_t actual) inline bool check(uint32_t expected, uint32_t actual)
{ {
if (actual != expected) if (actual != expected)
{ {

View File

@ -12,7 +12,7 @@ int main(int argc, char** argv)
// b - 2, Immediate // b - 2, Immediate
{ {
foot::Emulator emu = run_instructions({ 0x00204567, 0x07200220 }); 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; return 0;