From 9e2604855ea85145ef8d78571726cdfb3ab4546f Mon Sep 17 00:00:00 2001 From: shylie Date: Mon, 7 Jul 2025 09:24:19 -0400 Subject: [PATCH] Add initial working version --- .gitea/workflows/build.yml | 14 ++ .gitignore | 3 + DOCS.txt | 98 ++++----- emulator/CMakeLists.txt | 5 + emulator/customasm/first.asm | 8 + emulator/customasm/foot.asm | 60 ++++++ emulator/foot-emulator.cpp | 375 +++++++++++++++++++++++++++++++++++ emulator/foot-emulator.h | 106 ++++++++++ emulator/main.cpp | 73 +++++++ 9 files changed, 693 insertions(+), 49 deletions(-) create mode 100644 .gitea/workflows/build.yml create mode 100644 .gitignore create mode 100644 emulator/CMakeLists.txt create mode 100644 emulator/customasm/first.asm create mode 100644 emulator/customasm/foot.asm create mode 100644 emulator/foot-emulator.cpp create mode 100644 emulator/foot-emulator.h create mode 100644 emulator/main.cpp diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..cbc8480 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..28f87f7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +emulator/.cache/ +emulator/build/ +emulator/customasm/*.bin diff --git a/DOCS.txt b/DOCS.txt index 434a0bf..ab2ad9d 100644 --- a/DOCS.txt +++ b/DOCS.txt @@ -1,52 +1,52 @@ -╔══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ -║ Foot ISA ║ -╠═════════════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦═════════════════════════════════╣ -║ Instruction Format ║ ║ Addressing Modes ║ -╠══════════╦═════════════════════════╦════════════════════╦═══════════════════════════════════════════════════════╣ ╠═══════╦═════════════════════════╣ -║ ║ ║ ║ Encoding ║ ║ 000 ║ Immediate ║ -║ Mnemonic ║ Description ║ Semantics ╠═════════════╦═════════════╦═════════════╦═════════════╣ ╠═══════╬═════════════════════════╣ -║ ║ ║ ║ 24-31 ║ 16-23 ║ 8-15 ║ 0-7 ║ ║ 001 ║ Direct ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╦══════╬══════╦══════╬══════╦══════╬══════╦══════╣ ╠═══════╬═════════════════════════╣ -║ CNST ║ Immediate ║ D = I ║ CCCR ║ 0000 ║ DDDd ║ dddd ║ iiii ║ iiii ║ iiii ║ iiii ║ ║ 010 ║ Indirect Auto-increment ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ CMPR ║ Compare ║ C = A <=> B ║ CCCR ║ 0001 ║ BBBb ║ bbbb ║ 0000 ║ 0000 ║ AAAa ║ aaaa ║ ║ 011 ║ Indirect Auto-decrement ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ BWNG ║ Bitwise negate ║ D = ~A ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0001 ║ AAAa ║ aaaa ║ ║ 100 ║ Indirect ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ ARNG ║ Arithmetic negate ║ D = -A ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0010 ║ AAAa ║ aaaa ║ ║ 101 ║ Indirect 1-word offset ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ LONG ║ Logical negate ║ D = !A ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0011 ║ AAAa ║ aaaa ║ ║ 110 ║ Indirect 2-word offset ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ CONF ║ Configure processor ║ ║ CCCR ║ 0001 ║ DDDd ║ dddd ║ 0000 ║ 0100 ║ AAAa ║ aaaa ║ ║ 111 ║ Indirect 3-word offset ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╩═════════════════════════╣ -║ BWOR ║ Bitwise or ║ D = A | B ║ CCCR ║ 0010 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ Conditional Execution Flags ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╦═════════════════════════╣ -║ BAND ║ Bitwise and ║ D = A & B ║ CCCR ║ 0011 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 000 ║ Always ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ BXOR ║ Bitwise xor ║ D = A ^ B ║ CCCR ║ 0100 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 001 ║ A < B ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ 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 ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ 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 ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╩═════════════════════════╣ -║ MULS ║ Signed 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 ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ MULR ║ Integer multiplication ║ D = A * B ║ 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 ║ -╠══════════╬═════════════════════════╬════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ -║ MODU ║ Modulus ║ D = A % B ║ CCCR ║ 1111 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 15-12 ║ Reserved ║ -╚══════════╩═════════════════════════╩════════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══╩═══════╩═════════════════════════╝ +╔════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ +║ 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 ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ +║ 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 ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ +║ ZLSH ║ Pad zero left shift ║ D = A << B ║ CCCR ║ 0111 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 100 ║ A >= B ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ +║ CLSH ║ Circular left shift ║ D = A << B ║ CCCR ║ 1000 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 101 ║ A > B ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ +║ ADDI ║ Addition ║ D = A + B ║ CCCR ║ 1001 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 110 ║ A != B ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ +║ SUBT ║ Subtraction ║ D = A - B ║ CCCR ║ 1010 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 111 ║ Reserved ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╩═════════════════════════╣ +║ MULT ║ Multiplication ║ D = A * B >> shift ║ CCCR ║ 1011 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ Processor configuration bits ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╦═════════════════════════╣ +║ RESERVED ║ ║ ║ CCCR ║ 1100 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 3-0 ║ Multiplication shift ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ +║ RESERVED ║ ║ ║ CCCR ║ 1101 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 7-4 ║ Reserved ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ +║ DIVI ║ Division ║ D = (A << shift) / B ║ CCCR ║ 1110 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 11-8 ║ Reserved ║ +╠══════════╬═════════════════════════╬══════════════════════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╬══════╣ ╠═══════╬═════════════════════════╣ +║ MODU ║ Modulus ║ D = (A << shift) % B ║ CCCR ║ 1111 ║ DDDd ║ dddd ║ BBBb ║ bbbb ║ AAAa ║ aaaa ║ ║ 15-12 ║ Reserved ║ +╚══════════╩═════════════════════════╩══════════════════════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══════╩══╩═══════╩═════════════════════════╝ ╔═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗ ║ Foot ISA Table Key ║ diff --git a/emulator/CMakeLists.txt b/emulator/CMakeLists.txt new file mode 100644 index 0000000..abcebcd --- /dev/null +++ b/emulator/CMakeLists.txt @@ -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) diff --git a/emulator/customasm/first.asm b/emulator/customasm/first.asm new file mode 100644 index 0000000..8959677 --- /dev/null +++ b/emulator/customasm/first.asm @@ -0,0 +1,8 @@ +#include "foot.asm" + +CNST. r0, #0xFFFF + +loop: +CNST. [r0], #65 +CNST. [r0], #66 +CNST. r31, #loop diff --git a/emulator/customasm/foot.asm b/emulator/customasm/foot.asm new file mode 100644 index 0000000..049dc5c --- /dev/null +++ b/emulator/customasm/foot.asm @@ -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 diff --git a/emulator/foot-emulator.cpp b/emulator/foot-emulator.cpp new file mode 100644 index 0000000..773307d --- /dev/null +++ b/emulator/foot-emulator.cpp @@ -0,0 +1,375 @@ +#include "foot-emulator.h" + +#include + +namespace foot +{ + +Operand::Operand(uint8_t bits) : + addressing_mode(static_cast((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& 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) +{ + 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; +} + +} diff --git a/emulator/foot-emulator.h b/emulator/foot-emulator.h new file mode 100644 index 0000000..b97a5a3 --- /dev/null +++ b/emulator/foot-emulator.h @@ -0,0 +1,106 @@ +#ifndef FOOT_EMULATOR +#define FOOT_EMULATOR + +#include +#include +#include +#include + +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& program); + void map_device(std::unique_ptr&& device); + + uint16_t& memory_at(uint16_t address); + uint16_t& decode_operand(Operand operand); + +private: + std::array memory; + std::array registers; + enum class Status + { + Less, + Equal, + Greater + } status_register; + uint32_t instruction; + uint16_t configuration; + uint16_t dummy_value; + std::vector> 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 diff --git a/emulator/main.cpp b/emulator/main.cpp new file mode 100644 index 0000000..3f4cf18 --- /dev/null +++ b/emulator/main.cpp @@ -0,0 +1,73 @@ +#include "foot-emulator.h" + +#include +#include + +namespace +{ + +std::vector read_file(std::istream& stream) +{ + std::vector 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()); + + 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] << " " << std::endl; + } + + return 1; +}