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

4
.gitignore vendored
View File

@ -1,3 +1,3 @@
emulator/.cache/
emulator/build/
.cache/
build/
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 ║
╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦════════════════════════════════╣
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
╚══════════╩═══════════════════════════════════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══╩══════╩═════════════════════════╝
╠══════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦════════════════════════════════╣
║ 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 ║
╚══════════════════════════════════════════════════════════════╩══╩════════════════════════════════════════╩══╩══════════════════════════════════════════════════╩══╩═══╩═════════════════════════════╝

View File

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

View File

@ -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<uint16_t>& program);
void run(const std::vector<uint32_t>& program);
void map_device(std::unique_ptr<Device>&& 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<uint16_t, 1 << 16> memory;
std::array<uint16_t, 1 << 5> registers;
std::array<uint32_t, 1 << 16> memory;
std::array<uint32_t, 1 << 5> 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<std::unique_ptr<Device>> 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;
};
}

View File

@ -6,7 +6,7 @@ namespace foot
{
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)
{}
@ -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<uint16_t>& program)
void Emulator::run(const std::vector<uint32_t>& program)
{
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));
}
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);
}
}

View File

@ -8,9 +8,9 @@
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();
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++)
{
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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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; }

View File

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

View File

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

View File

@ -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; }
}

View File

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

View File

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

View File

@ -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; }
}

View File

@ -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<uint32_t>& 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<uint32_t>& instructions
return emu;
}
inline bool check(uint16_t expected, uint16_t actual)
inline bool check(uint32_t expected, uint32_t actual)
{
if (actual != expected)
{

View File

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