This commit is contained in:
parent
464ea876d1
commit
9e2604855e
14
.gitea/workflows/build.yml
Normal file
14
.gitea/workflows/build.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
name: Build
|
||||||
|
|
||||||
|
on: push
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: shy-server
|
||||||
|
steps:
|
||||||
|
- name: Checkout current
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Configure
|
||||||
|
run: cmake -S emulator -B emulator/build
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build emulator/build
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
emulator/.cache/
|
||||||
|
emulator/build/
|
||||||
|
emulator/customasm/*.bin
|
98
DOCS.txt
98
DOCS.txt
@ -1,52 +1,52 @@
|
|||||||
╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
|
╔════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||||
║ Foot ISA ║
|
║ Foot ISA ║
|
||||||
╠═════════════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦═════════════════════════════════╣
|
╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦═════════════════════════════════╣
|
||||||
║ Instruction Format ║ ║ Addressing Modes ║
|
║ Instruction Format ║ ║ Addressing Modes ║
|
||||||
╠══════════╦═════════════════════════╦════════════════════╦═══════════════════════════════════════════════════════╣ ╠═══════╦═════════════════════════╣
|
╠══════════╦═════════════════════════╦══════════════════════╦═══════════════════════════════════════════════════════╣ ╠═══════╦═════════════════════════╣
|
||||||
║ ║ ║ ║ Encoding ║ ║ 000 ║ Immediate ║
|
║ ║ ║ ║ Encoding ║ ║ 000 ║ 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 ║ ║ 001 ║ Direct ║
|
||||||
╠══════════╬═════════════════════════╬════════════════════╬══════╦══════╬══════╦══════╬══════╦══════╬══════╦══════╣ ╠═══════╬═════════════════════════╣
|
╠══════════╬═════════════════════════╬══════════════════════╬══════╦══════╬══════╦══════╬══════╦══════╬══════╦══════╣ ╠═══════╬═════════════════════════╣
|
||||||
║ CNST ║ Immediate ║ D = I ║ CCCR ║ 0000 ║ DDDd ║ dddd ║ iiii ║ iiii ║ iiii ║ iiii ║ ║ 010 ║ Indirect Auto-increment ║
|
║ 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 ║
|
║ 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 ║
|
║ 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 ║
|
║ 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 ║
|
║ 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 ║
|
║ 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 ║
|
║ 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 ║
|
║ 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 ║
|
║ BXOR ║ Bitwise xor ║ D = A ^ B ║ CCCR ║ 0100 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 001 ║ A < B ║
|
||||||
╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣
|
╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣
|
||||||
║ URSH ║ Unsigned right shift ║ D = A >> B ║ CCCR ║ 0101 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 010 ║ A <= B ║
|
║ URSH ║ Unsigned right shift ║ D = A >> B ║ 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 ║
|
║ 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 ║
|
║ 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 ║
|
║ 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 ║
|
║ 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 ║
|
║ SUBT ║ Subtraction ║ D = A - B ║ CCCR ║ 1010 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 111 ║ Reserved ║
|
||||||
╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╩═════════════════════════╣
|
╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╩═════════════════════════╣
|
||||||
║ MULS ║ Signed multiplication ║ D = A * B >> shift ║ CCCR ║ 1011 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ Processor configuration bits ║
|
║ MULT ║ Multiplication ║ D = A * B >> shift ║ CCCR ║ 1011 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ Processor configuration bits ║
|
||||||
╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╦═════════════════════════╣
|
╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╦═════════════════════════╣
|
||||||
║ MULU ║ Unsigned multiplication ║ D = A * B >> shift ║ CCCR ║ 1100 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 3-0 ║ Multiplication shift ║
|
║ RESERVED ║ ║ ║ CCCR ║ 1100 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 3-0 ║ Multiplication shift ║
|
||||||
╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣
|
╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣
|
||||||
║ MULR ║ Integer multiplication ║ D = A * B ║ CCCR ║ 1101 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 7-4 ║ Reserved ║
|
║ RESERVED ║ ║ ║ CCCR ║ 1101 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 7-4 ║ Reserved ║
|
||||||
╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣
|
╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣
|
||||||
║ DIVI ║ Division ║ D = A / B ║ CCCR ║ 1110 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 11-8 ║ Reserved ║
|
║ DIVI ║ Division ║ D = (A << shift) / B ║ CCCR ║ 1110 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 11-8 ║ Reserved ║
|
||||||
╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣
|
╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣
|
||||||
║ MODU ║ Modulus ║ D = A % B ║ CCCR ║ 1111 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 15-12 ║ Reserved ║
|
║ MODU ║ Modulus ║ D = (A << shift) % B ║ CCCR ║ 1111 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 15-12 ║ Reserved ║
|
||||||
╚══════════╩═════════════════════════╩════════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══╩═══════╩═════════════════════════╝
|
╚══════════╩═════════════════════════╩══════════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══╩═══════╩═════════════════════════╝
|
||||||
|
|
||||||
╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
|
╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
|
||||||
║ Foot ISA Table Key ║
|
║ Foot ISA Table Key ║
|
||||||
|
5
emulator/CMakeLists.txt
Normal file
5
emulator/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
project(foot-emu)
|
||||||
|
|
||||||
|
add_executable(foot-emu main.cpp foot-emulator.cpp foot-emulator.h)
|
8
emulator/customasm/first.asm
Normal file
8
emulator/customasm/first.asm
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include "foot.asm"
|
||||||
|
|
||||||
|
CNST. r0, #0xFFFF
|
||||||
|
|
||||||
|
loop:
|
||||||
|
CNST. [r0], #65
|
||||||
|
CNST. [r0], #66
|
||||||
|
CNST. r31, #loop
|
60
emulator/customasm/foot.asm
Normal file
60
emulator/customasm/foot.asm
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#once
|
||||||
|
|
||||||
|
#subruledef operand
|
||||||
|
{
|
||||||
|
#{immediate: i5} => 0b000 @ immediate
|
||||||
|
r{register: u5} => 0b001 @ register
|
||||||
|
[r{register: u5}++] => 0b010 @ register
|
||||||
|
[r{register: u5}--] => 0b011 @ register
|
||||||
|
[r{register: u5}] => 0b100 @ register
|
||||||
|
[r{register: u5} + {offset: u2}] => 0b1 @ offset @ register
|
||||||
|
}
|
||||||
|
|
||||||
|
#subruledef crflags
|
||||||
|
{
|
||||||
|
. => 0b0000
|
||||||
|
.l => 0b0010
|
||||||
|
.le => 0b0100
|
||||||
|
.e => 0b0110
|
||||||
|
.ge => 0b1000
|
||||||
|
.g => 0b1010
|
||||||
|
.ne => 0b1100
|
||||||
|
.r => 0b0001
|
||||||
|
.rl => 0b0011
|
||||||
|
.rle => 0b0101
|
||||||
|
.re => 0b0111
|
||||||
|
.rge => 0b1001
|
||||||
|
.re => 0b1011
|
||||||
|
.rne => 0b1101
|
||||||
|
}
|
||||||
|
|
||||||
|
#ruledef
|
||||||
|
{
|
||||||
|
CNST{flags: crflags} {dst: operand}, #{imm: i16} => imm @ flags @ 0b0000 @ dst
|
||||||
|
CMPR{flags: crflags} {dst: operand}, {a: operand} => 0x00 @ a @ flags @ 0b0001 @ dst
|
||||||
|
BWNG{flags: crflags} {dst: operand}, {a: operand} => 0x01 @ a @ flags @ 0b0001 @ dst
|
||||||
|
ARNG{flags: crflags} {dst: operand}, {a: operand} => 0x02 @ a @ flags @ 0b0001 @ dst
|
||||||
|
LONG{flags: crflags} {dst: operand}, {a: operand} => 0x03 @ a @ flags @ 0b0001 @ dst
|
||||||
|
BWOR{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0010 @ dst
|
||||||
|
BAND{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0011 @ dst
|
||||||
|
BXOR{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0100 @ dst
|
||||||
|
URSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0101 @ dst
|
||||||
|
SRSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0110 @ dst
|
||||||
|
ZLSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0111 @ dst
|
||||||
|
CLSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1000 @ dst
|
||||||
|
ADDI{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1001 @ dst
|
||||||
|
SUBT{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1010 @ dst
|
||||||
|
MULT{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1011 @ dst
|
||||||
|
DIVI{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1110 @ dst
|
||||||
|
MODU{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1111 @ dst
|
||||||
|
}
|
||||||
|
|
||||||
|
#bankdef mem
|
||||||
|
{
|
||||||
|
#bits 16
|
||||||
|
#addr 0
|
||||||
|
#size 0x10000
|
||||||
|
#outp 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#bank mem
|
375
emulator/foot-emulator.cpp
Normal file
375
emulator/foot-emulator.cpp
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
#include "foot-emulator.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace foot
|
||||||
|
{
|
||||||
|
|
||||||
|
Operand::Operand(uint8_t bits) :
|
||||||
|
addressing_mode(static_cast<AddressingMode>((bits & 0b11100000) >> 5)),
|
||||||
|
register_index(bits & 0b00011111)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Device::Device(uint16_t size) :
|
||||||
|
assigned_memory_base(nullptr),
|
||||||
|
assigned_memory_size(size)
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint16_t& Device::memory(uint16_t index)
|
||||||
|
{
|
||||||
|
if (index >= assigned_memory_size)
|
||||||
|
{
|
||||||
|
throw std::range_error("Index out of range");
|
||||||
|
}
|
||||||
|
return assigned_memory_base[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Emulator::Emulator() :
|
||||||
|
memory{},
|
||||||
|
|
||||||
|
mapped_base(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Emulator::run(const std::vector<uint16_t>& program)
|
||||||
|
{
|
||||||
|
std::copy(program.begin(), program.end(), memory.begin());
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
run_instruction();
|
||||||
|
for (auto& device : devices)
|
||||||
|
{
|
||||||
|
device->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::map_device(std::unique_ptr<Device>&& device)
|
||||||
|
{
|
||||||
|
mapped_base -= device->mapped_memory_size();
|
||||||
|
device->assigned_memory_base = &memory[mapped_base];
|
||||||
|
|
||||||
|
devices.push_back(std::move(device));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t& Emulator::memory_at(uint16_t address)
|
||||||
|
{
|
||||||
|
return memory[address];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t& Emulator::decode_operand(Operand operand)
|
||||||
|
{
|
||||||
|
switch (operand.addressing_mode)
|
||||||
|
{
|
||||||
|
case Operand::AddressingMode::Immediate:
|
||||||
|
dummy_value = operand.register_index;
|
||||||
|
return dummy_value;
|
||||||
|
|
||||||
|
case Operand::AddressingMode::Direct:
|
||||||
|
return registers[operand.register_index];
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::read_instruction()
|
||||||
|
{
|
||||||
|
uint16_t low = memory[registers[PC]++];
|
||||||
|
uint16_t high = memory[registers[PC]++];
|
||||||
|
|
||||||
|
instruction = (uint32_t(high) << 16) | uint32_t(low);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::run_instruction()
|
||||||
|
{
|
||||||
|
read_instruction();
|
||||||
|
|
||||||
|
const bool rep = repeats();
|
||||||
|
const uint16_t loop_count = rep ? registers[LC] : 1;
|
||||||
|
|
||||||
|
for (int iteration = 0; iteration < loop_count; iteration++)
|
||||||
|
{
|
||||||
|
if (rep) { registers[LC] = iteration; }
|
||||||
|
|
||||||
|
switch ((instruction & 0x0F000000) >> 24)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
CNST();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
switch ((instruction & 0x0000FF00) >> 8)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
CMPR();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
BWNG();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
ARNG();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
LONG();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
CONF();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
BWOR();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
BAND();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
BXOR();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
URSH();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
SRSH();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
ZLSH();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
CLSH();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9:
|
||||||
|
ADDI();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10:
|
||||||
|
SUBT();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11:
|
||||||
|
MULT();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 14:
|
||||||
|
DIVI();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 15:
|
||||||
|
MODU();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rep) { registers[LC] = loop_count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::CNST()
|
||||||
|
{
|
||||||
|
decode_operand((instruction & 0x00FF0000) >> 16) = instruction & 0x0000FFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::CMPR()
|
||||||
|
{
|
||||||
|
uint16_t a = decode_operand(instruction & 0x000000FF);
|
||||||
|
uint16_t b = decode_operand((instruction & 0x00FF0000) >> 16);
|
||||||
|
|
||||||
|
if (a < b)
|
||||||
|
{
|
||||||
|
status_register = Status::Less;
|
||||||
|
}
|
||||||
|
else if (a > b)
|
||||||
|
{
|
||||||
|
status_register = Status::Greater;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status_register = Status::Equal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::BWNG()
|
||||||
|
{
|
||||||
|
uint16_t a = decode_operand(instruction & 0x000000FF);
|
||||||
|
uint16_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);
|
||||||
|
|
||||||
|
d = -a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::LONG()
|
||||||
|
{
|
||||||
|
uint16_t a = decode_operand(instruction & 0x000000FF);
|
||||||
|
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
|
||||||
|
|
||||||
|
d = !a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::CONF()
|
||||||
|
{
|
||||||
|
uint16_t a = decode_operand(instruction & 0x000000FF);
|
||||||
|
uint16_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
|
||||||
|
|
||||||
|
d = configuration;
|
||||||
|
configuration = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
d = a ^ b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::URSH()
|
||||||
|
{
|
||||||
|
uint16_t a = decode_operand(instruction & 0x000000FF);
|
||||||
|
uint16_t b = decode_operand((instruction & 0x0000FF00) >> 8);
|
||||||
|
uint16_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);
|
||||||
|
|
||||||
|
d = int16_t(a) >> int16_t(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
d = a << b;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
d = (a << b) | (a >> (16 - b));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
d = a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
d = a - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
d = uint32_t(int32_t(a) * int32_t(b)) >> shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
d = uint32_t((int32_t(a) >> shift()) / int32_t(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
d = uint32_t((int32_t(a) >> shift()) / int32_t(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Emulator::repeats()
|
||||||
|
{
|
||||||
|
return instruction & 0x10000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Emulator::shift()
|
||||||
|
{
|
||||||
|
return configuration & 0x000F;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
106
emulator/foot-emulator.h
Normal file
106
emulator/foot-emulator.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#ifndef FOOT_EMULATOR
|
||||||
|
#define FOOT_EMULATOR
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace foot
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Operand
|
||||||
|
{
|
||||||
|
Operand(uint8_t bits);
|
||||||
|
|
||||||
|
enum class AddressingMode
|
||||||
|
{
|
||||||
|
Immediate = 0,
|
||||||
|
Direct,
|
||||||
|
IndirectAutoIncrement,
|
||||||
|
IndirectAutoDecrement,
|
||||||
|
Indirect,
|
||||||
|
IndirectOffset1Word,
|
||||||
|
IndirectOffset2Word,
|
||||||
|
IndirectOffset3Word
|
||||||
|
} addressing_mode;
|
||||||
|
uint8_t register_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Device
|
||||||
|
{
|
||||||
|
friend class Emulator;
|
||||||
|
public:
|
||||||
|
virtual ~Device() = default;
|
||||||
|
|
||||||
|
virtual void update() = 0;
|
||||||
|
virtual uint16_t mapped_memory_size() const { return assigned_memory_size; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Device(uint16_t size);
|
||||||
|
|
||||||
|
uint16_t& memory(uint16_t index);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t* assigned_memory_base;
|
||||||
|
uint16_t assigned_memory_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Emulator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr uint8_t PC = 31;
|
||||||
|
static constexpr uint8_t LC = 30;
|
||||||
|
|
||||||
|
Emulator();
|
||||||
|
|
||||||
|
void run(const std::vector<uint16_t>& program);
|
||||||
|
void map_device(std::unique_ptr<Device>&& device);
|
||||||
|
|
||||||
|
uint16_t& memory_at(uint16_t address);
|
||||||
|
uint16_t& decode_operand(Operand operand);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<uint16_t, 1 << 16> memory;
|
||||||
|
std::array<uint16_t, 1 << 5> registers;
|
||||||
|
enum class Status
|
||||||
|
{
|
||||||
|
Less,
|
||||||
|
Equal,
|
||||||
|
Greater
|
||||||
|
} status_register;
|
||||||
|
uint32_t instruction;
|
||||||
|
uint16_t configuration;
|
||||||
|
uint16_t dummy_value;
|
||||||
|
std::vector<std::unique_ptr<Device>> devices;
|
||||||
|
uint16_t mapped_base;
|
||||||
|
|
||||||
|
void read_instruction();
|
||||||
|
void run_instruction();
|
||||||
|
|
||||||
|
void CNST();
|
||||||
|
void CMPR();
|
||||||
|
void BWNG();
|
||||||
|
void ARNG();
|
||||||
|
void LONG();
|
||||||
|
void CONF();
|
||||||
|
void BWOR();
|
||||||
|
void BAND();
|
||||||
|
void BXOR();
|
||||||
|
void URSH();
|
||||||
|
void SRSH();
|
||||||
|
void ZLSH();
|
||||||
|
void CLSH();
|
||||||
|
void ADDI();
|
||||||
|
void SUBT();
|
||||||
|
void MULT();
|
||||||
|
void DIVI();
|
||||||
|
void MODU();
|
||||||
|
|
||||||
|
bool repeats();
|
||||||
|
uint8_t shift();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif//FOOT_EMULATOR
|
73
emulator/main.cpp
Normal file
73
emulator/main.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "foot-emulator.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
std::vector<uint16_t> read_file(std::istream& stream)
|
||||||
|
{
|
||||||
|
std::vector<uint16_t> buf;
|
||||||
|
|
||||||
|
std::streampos pos = stream.tellg();
|
||||||
|
stream.seekg(0, std::ios::end);
|
||||||
|
pos = stream.tellg() - pos;
|
||||||
|
buf.resize(pos / 2);
|
||||||
|
stream.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrintDevice : public foot::Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PrintDevice() :
|
||||||
|
Device(1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void update() override
|
||||||
|
{
|
||||||
|
uint16_t& value = memory(0);
|
||||||
|
if (value != 0)
|
||||||
|
{
|
||||||
|
std::cout << char(value);
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
foot::Emulator emu;
|
||||||
|
emu.map_device(std::make_unique<PrintDevice>());
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
std::ifstream file(argv[1], std::ios::binary);
|
||||||
|
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to open file: " << argv[1] << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
emu.run(read_file(file));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Usage: " << argv[0] << " <filename>" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user