Initial implementation of register machine emulator.
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
Session.vim
|
||||
Emulator
|
||||
build/*
|
||||
.undodir
|
||||
.ccls
|
||||
.tup/*
|
||||
12
Tupfile
Normal file
12
Tupfile
Normal file
@@ -0,0 +1,12 @@
|
||||
CXX = g++
|
||||
CXXFLAGS = -pedantic -std=c++17 -Wall -Wno-unused-parameter -Wno-reorder -Wno-sign-compare -Wno-address -Wno-noexcept-type -Wno-unknown-attributes -Wno-unknown-warning-option
|
||||
CPPFLAGS =
|
||||
LDFLAGS =
|
||||
LIBS = -lgmpxx -lgmp
|
||||
|
||||
SRC_DIR = src
|
||||
BUILD_DIR = build
|
||||
PROG = Emulator
|
||||
|
||||
: foreach $(SRC_DIR)/*.cpp |> $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c %f -o %o |> $(BUILD_DIR)/%B.o
|
||||
: $(BUILD_DIR)/*.o |> $(CXX) %f $(LDFLAGS) $(LIBS) -o %o |> $(PROG)
|
||||
25
src/.clang-format
Normal file
25
src/.clang-format
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
BasedOnStyle: llvm
|
||||
IndentWidth: 4
|
||||
---
|
||||
AccessModifierOffset: -4
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBraces: Attach
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
Cpp11BracedListStyle: false
|
||||
ColumnLimit: 100
|
||||
DerivePointerAlignment: false
|
||||
FixNamespaceComments: true
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: AfterHash
|
||||
Language: Cpp
|
||||
NamespaceIndentation: All
|
||||
PointerAlignment: Left
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: ForIndentation
|
||||
|
||||
...
|
||||
81
src/main.cpp
Normal file
81
src/main.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#include "register.hpp"
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
Register& getOrDefault(std::map<RegIndex, Register>& mapping, const RegIndex& lookup);
|
||||
|
||||
int main() {
|
||||
const constexpr size_t registerIndexPadding = 6;
|
||||
bool executing = true;
|
||||
|
||||
std::cout << "Please enter the program" << std::endl;
|
||||
|
||||
RegIndex pc = 0;
|
||||
Register reg;
|
||||
std::map<RegIndex, Register> registers{};
|
||||
|
||||
std::cin >> reg;
|
||||
auto registerStates = toList(reg);
|
||||
|
||||
std::cout << "\nRegister states at startup:\n";
|
||||
RegIndex i = 0;
|
||||
|
||||
for (; i < registerStates.size(); i++) {
|
||||
const auto registerState = registerStates[i];
|
||||
|
||||
registers.insert(std::make_pair(i, registerState));
|
||||
std::cout << std::setw(registerIndexPadding) << i << ": " << registerState << "\n";
|
||||
}
|
||||
|
||||
std::cout << std::setw(registerIndexPadding) << i << ": 0...\n\n";
|
||||
std::cout << "Beginning Execution..." << std::endl;
|
||||
|
||||
registers.insert(std::make_pair(pc, reg));
|
||||
|
||||
while (executing) {
|
||||
std::cout << "L" << pc << "\t";
|
||||
Register instruction = getOrDefault(registers, pc);
|
||||
|
||||
if (instruction == 0) { /* HALT instruction. */
|
||||
std::cout << "HALT" << std::endl;
|
||||
executing = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto splitInstruction = toPair<false>(instruction);
|
||||
|
||||
if (splitInstruction.first % 2 == 0) { /* R+ instruction */
|
||||
RegIndex sourceRegisterIndex = splitInstruction.first.get_ui();
|
||||
RegIndex destinationLabel = splitInstruction.second.get_ui();
|
||||
|
||||
std::cout << "R" << sourceRegisterIndex << u8"\u207a \u21a3 " << destinationLabel
|
||||
<< "\n";
|
||||
|
||||
getOrDefault(registers, sourceRegisterIndex)++;
|
||||
pc = destinationLabel;
|
||||
} else {
|
||||
RegIndex sourceRegisterIndex = splitInstruction.first.get_ui();
|
||||
|
||||
auto branches = toPair<true>(splitInstruction.second);
|
||||
RegIndex trueLabel = branches.first.get_ui();
|
||||
RegIndex falseLabel = branches.second.get_ui();
|
||||
|
||||
std::cout << "R" << sourceRegisterIndex << "\u207b \u21a3 " << trueLabel << ", "
|
||||
<< falseLabel << "\n";
|
||||
|
||||
auto& sourceRegister = getOrDefault(registers, sourceRegisterIndex);
|
||||
|
||||
if (sourceRegister > 0) {
|
||||
sourceRegister--;
|
||||
pc = trueLabel;
|
||||
} else
|
||||
pc = falseLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Register& getOrDefault(std::map<RegIndex, Register>& mapping, const RegIndex& lookup) {
|
||||
auto valueIter = mapping.try_emplace(lookup, Register{ 0 });
|
||||
return valueIter.first->second;
|
||||
}
|
||||
43
src/register.cpp
Normal file
43
src/register.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "register.hpp"
|
||||
|
||||
template <>
|
||||
std::pair<Register, Register> toPair<false>(Register unsplit) {
|
||||
Register x = 0;
|
||||
|
||||
/* Skip to the first 1 bit in representation */
|
||||
while (unsplit % 2 != 1) {
|
||||
unsplit >>= 1;
|
||||
x++;
|
||||
}
|
||||
|
||||
unsplit >>= 1;
|
||||
|
||||
return std::make_pair(x, unsplit);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::pair<Register, Register> toPair<true>(Register unsplit) {
|
||||
Register x = 0;
|
||||
|
||||
/* Skip past the first 1 bits in representation */
|
||||
while (unsplit % 2 == 1) {
|
||||
unsplit >>= 1;
|
||||
x++;
|
||||
}
|
||||
|
||||
unsplit >>= 1;
|
||||
|
||||
return std::make_pair(x, unsplit);
|
||||
}
|
||||
|
||||
std::vector<Register> toList(Register unsplit) {
|
||||
std::vector<Register> list{};
|
||||
|
||||
while (unsplit != 0) {
|
||||
const auto splitPair = toPair<false>(unsplit);
|
||||
unsplit = splitPair.second;
|
||||
list.push_back(splitPair.first);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
13
src/register.hpp
Normal file
13
src/register.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <gmpxx.h>
|
||||
#include <utility>
|
||||
|
||||
using Register = mpz_class;
|
||||
using RegIndex = uint16_t;
|
||||
|
||||
template <bool mapZero>
|
||||
std::pair<Register, Register> toPair(Register unsplit);
|
||||
|
||||
std::vector<Register> toList(Register unsplit);
|
||||
Reference in New Issue
Block a user