Browse Source

disassembler first pass

master
Evan Burkey 12 months ago
parent
commit
b5bed801f7
  1. 4
      CMakeLists.txt
  2. 15
      include/synacor.h
  3. 9
      include/vm.h
  4. 2
      src/main.cpp
  5. 211
      src/synacor.cpp
  6. 21
      src/vm.cpp

4
CMakeLists.txt

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.21)
cmake_minimum_required(VERSION 3.12)
project(synacor)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)
find_package(SDL2 REQUIRED)
find_package(OpenGL REQUIRED)

15
include/synacor.h

@ -1,10 +1,15 @@ @@ -1,10 +1,15 @@
#pragma once
#include <string>
#include <utility>
#include <vector>
#include "SDL2/SDL.h"
#include "imgui.h"
#include "vm.h"
struct Simulator {
class Simulator {
public:
Simulator(SDL_Window *, ImGuiIO&);
~Simulator();
@ -12,7 +17,13 @@ struct Simulator { @@ -12,7 +17,13 @@ struct Simulator {
ImGuiIO& io;
Vm *vm;
const ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
std::vector<std::pair<uint16_t, std::string>> disassembly;
bool step_flag;
void load_vm(const char *);
bool gui();
bool tick();
private:
void gen_disassembly();
[[nodiscard]] std::string dval(uint16_t c) const;
};

9
include/vm.h

@ -13,17 +13,17 @@ enum class VmState { @@ -13,17 +13,17 @@ enum class VmState {
HaltError
};
class Vm {
public:
struct Vm {
explicit Vm(const char *path);
~Vm();
void cycle();
VmState state;
std::vector<std::string> output;
uint16_t ic;
private:
uint16_t val(uint16_t);
uint16_t *reg_p(uint16_t);
const uint16_t REG_START = 32768;
const uint16_t REG_END = 32775;
@ -32,6 +32,7 @@ private: @@ -32,6 +32,7 @@ private:
uint16_t *mem;
uint16_t reg[8]{};
std::stack<uint16_t> stack;
uint16_t ic;
std::string line;
uint16_t mem_sz;
bool wmem_flag;
};

2
src/main.cpp

@ -54,7 +54,7 @@ int main() { @@ -54,7 +54,7 @@ int main() {
ImGui_ImplOpenGL3_Init(glsl_version);
Simulator sim(window, io);
while (sim.gui()) {}
while (sim.tick()) {}
cleanup();
return 0;

211
src/synacor.cpp

@ -1,10 +1,14 @@ @@ -1,10 +1,14 @@
#include <algorithm>
#include <iterator>
#include <unistd.h>
#include "synacor.h"
#include "imgui_impl_sdl.h"
#include "imgui_impl_opengl3.h"
#include "imgui_impl_opengl3_loader.h"
Simulator::Simulator(SDL_Window *window, ImGuiIO &io) : window(window), io(io) {
Simulator::Simulator(SDL_Window *window, ImGuiIO &io) : window(window), io(io), step_flag(false) {
vm = nullptr;
load_vm("challenge.bin");
}
@ -16,14 +20,23 @@ Simulator::~Simulator() { @@ -16,14 +20,23 @@ Simulator::~Simulator() {
void Simulator::load_vm(const char *path) {
delete vm;
vm = new Vm(path);
gen_disassembly();
}
bool Simulator::gui() {
bool Simulator::tick() {
bool p_open = true;
if (vm->state == VmState::Running) {
vm->cycle();
if (step_flag) {
vm->state = VmState::Paused;
step_flag = false;
}
} else {
if (vm->wmem_flag) {
gen_disassembly();
vm->wmem_flag = false;
}
SDL_Event event;
while (SDL_PollEvent(&event)) {
ImGui_ImplSDL2_ProcessEvent(&event);
@ -46,32 +59,56 @@ bool Simulator::gui() { @@ -46,32 +59,56 @@ bool Simulator::gui() {
ImGui::SetNextWindowSize(viewport->Size);
if (ImGui::Begin("Synacor Challenge Simulator", &p_open, flags)) {
/* Menu */
if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Load Program")) {
}
ImGui::EndMenu();
}
}
ImGui::EndMainMenuBar();
/* Headers */
ImGui::TextUnformatted("Console");
ImGui::SameLine(viewport->Size.x / 2 + 8);
ImGui::TextUnformatted("Disassembly");
/* Console */
ImGui::TextUnformatted("Console");
ImGui::BeginChild("Console", ImVec2(viewport->Size.x / 2 - 2, viewport->Size.y / 2), true);
ImGui::BeginChild("Console", ImVec2(viewport->Size.x / 2 - 10, viewport->Size.y / 2), true);
for (const auto &line: vm->output) {
ImGui::TextUnformatted(line.c_str());
}
ImGui::EndChild();
if (ImGui::Button("Start VM")) {
/* Disassembler */
ImGui::SameLine();
ImGui::BeginChild("Disassembler", ImVec2(viewport->Size.x / 2 - 10, viewport->Size.y / 2), true);
auto it = std::find_if(disassembly.begin(), disassembly.end(), [&](std::pair<uint16_t, std::string>& p){
return p.first == vm->ic;
});
auto dis = std::distance(disassembly.begin(), it);
if (dis > 5) {
it -= 5;
} else {
it -= dis;
}
for (int j = 0; it != disassembly.end() && j != 30; ++it, ++j) {
char buf[32];
std::sprintf(buf, "%u\t%s", it->first, it->second.c_str());
if (it->first == vm->ic) {
ImGui::TextColored(ImVec4(0, 1.0f, 0, 1.0f), "%s", buf);
} else {
ImGui::TextUnformatted(buf);
}
}
ImGui::EndChild();
/* Console Controls */
if (ImGui::Button("Run")) {
vm->state = VmState::Running;
}
ImGui::SameLine();
if (ImGui::Button("Pause VM")) {
if (ImGui::Button("Pause")) {
vm->state = VmState::Paused;
}
ImGui::SameLine();
if (ImGui::Button("Reset VM")) {
if (ImGui::Button("Step")) {
vm->state = VmState::Running;
step_flag = true;
}
ImGui::SameLine();
if (ImGui::Button("Reset")) {
load_vm("challenge.bin");
}
}
@ -85,6 +122,146 @@ bool Simulator::gui() { @@ -85,6 +122,146 @@ bool Simulator::gui() {
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_GL_SwapWindow(window);
}
return p_open;
}
std::string Simulator::dval(uint16_t c) const {
char buf[32];
if (vm->mem[c] < vm->REG_START) {
std::sprintf(buf, "%u", vm->mem[c]);
} else if (vm->mem[c] <= vm->REG_END) {
std::sprintf(buf, "r[%u]", vm->mem[c] - vm->REG_START);
} else {
std::sprintf(buf, "FAIL");
}
return buf;
}
void Simulator::gen_disassembly() {
if (vm == nullptr) {
disassembly.emplace_back(0, "VM pointer is NULL!");
return;
}
disassembly.clear();
for (uint16_t dc = 0; dc < vm->mem_sz;) {
char buf[32];
uint16_t old_dc = dc;
switch (vm->mem[dc]) {
case 0:
std::sprintf(buf, "halt");
++dc;
break;
case 1:
std::sprintf(buf, "set %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str());
dc += 3;
break;
case 2:
std::sprintf(buf, "push %s", dval(dc + 1).c_str());
dc += 2;
break;
case 3:
std::sprintf(buf, "pop %s", dval(dc + 1).c_str());
dc += 2;
break;
case 4:
std::sprintf(buf, "eq %s %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str(), dval(dc + 3).c_str());
dc += 4;
break;
case 5:
std::sprintf(buf, "gt %s %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str(), dval(dc + 3).c_str());
dc += 4;
break;
case 6:
std::sprintf(buf, "jmp %s", dval(dc + 1).c_str());
dc += 2;
break;
case 7:
std::sprintf(buf, "jt %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str());
dc += 3;
break;
case 8:
std::sprintf(buf, "jf %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str());
dc += 3;
break;
case 9:
std::sprintf(buf, "add %s %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str(), dval(dc + 3).c_str());
dc += 4;
break;
case 10:
std::sprintf(buf, "mult %s %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str(), dval(dc + 3).c_str());
dc += 4;
break;
case 11:
std::sprintf(buf, "mod %s %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str(), dval(dc + 3).c_str());
dc += 4;
break;
case 12:
std::sprintf(buf, "and %s %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str(), dval(dc + 3).c_str());
dc += 4;
break;
case 13:
std::sprintf(buf, "or %s %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str(), dval(dc + 3).c_str());
dc += 4;
break;
case 14:
std::sprintf(buf, "not %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str());
dc += 3;
break;
case 15:
std::sprintf(buf, "rmem %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str());
dc += 3;
break;
case 16:
std::sprintf(buf, "wmem %s %s", dval(dc + 1).c_str(), dval(dc + 2).c_str());
dc += 3;
break;
case 17:
std::sprintf(buf, "call %s", dval(dc + 1).c_str());
dc += 2;
break;
case 18:
std::sprintf(buf, "ret");
dc += 1;
break;
case 19:
std::sprintf(buf, "out %s", dval(dc + 1).c_str());
dc += 2;
break;
case 20:
std::sprintf(buf, "in %s", dval(dc + 1).c_str());
dc += 2;
break;
case 21:
std::sprintf(buf, "noop");
dc += 1;
break;
default:
std::sprintf(buf, "val %s", dval(dc).c_str());
dc += 1;
break;
}
disassembly.emplace_back(old_dc, buf);
}
}

21
src/vm.cpp

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
#include "vm.h"
Vm::Vm(const char *path) : ic(0), state(VmState::Paused) {
Vm::Vm(const char *path) : ic(0), state(VmState::Paused), wmem_flag(false) {
long fsz, i, j;
FILE *fp = fopen(path, "rb");
@ -23,6 +23,7 @@ Vm::Vm(const char *path) : ic(0), state(VmState::Paused) { @@ -23,6 +23,7 @@ Vm::Vm(const char *path) : ic(0), state(VmState::Paused) {
mem = new uint16_t[fsz / 2];
for (i = 0, j = 0; j < fsz; ++i, j += 2) {
mem[i] = raw[j] | raw[j + 1] << 8;
++mem_sz;
}
for (i = 0; i < 8; i++) {
@ -40,12 +41,21 @@ void Vm::cycle() { @@ -40,12 +41,21 @@ void Vm::cycle() {
char c;
char buf[32];
uint16_t *r;
switch (mem[ic]) {
case 0: // halt 0
state = VmState::HaltOp;
break;
case 1: // set 1 a b
r = reg_p(1);
if (r) {
*r = val(2);
ic += 3;
}
break;
case 6: // jmp 6 a
ic = val(1);
break;
@ -98,3 +108,12 @@ uint16_t Vm::val(uint16_t offset) { @@ -98,3 +108,12 @@ uint16_t Vm::val(uint16_t offset) {
state = VmState::HaltError;
return 0;
}
uint16_t* Vm::reg_p(uint16_t offset) {
if (mem[ic + offset] >= REG_START && mem[ic + offset] <= REG_END) {
return &(reg[mem[ic + offset]]);
}
output.emplace_back("\nERROR: reg_p received value outside reg bounds\n");
state = VmState::HaltError;
return nullptr;
}
Loading…
Cancel
Save