|
|
|
@ -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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|