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 ║
|
||||
╠═════════════════════════════════════════════════════════════════════════════════════════════════════════════════╦══╦═════════════════════════════════╣
|
||||
║ 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 ║
|
||||
|
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