From 0359d4e0b2235ba8917bbf813af0b15867b840ea Mon Sep 17 00:00:00 2001 From: Sam Stevens Date: Tue, 16 Oct 2018 21:46:37 +0100 Subject: [PATCH] Initial Commit` --- .gitignore | 84 ++++++++++++ .idea/codeStyles/Project.xml | 29 +++++ .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/misc.xml | 7 + .idea/modules.xml | 8 ++ .idea/uVM.iml | 2 + CMakeLists.txt | 6 + main.c | 24 ++++ vm.c | 186 +++++++++++++++++++++++++++ vm.h | 70 ++++++++++ 10 files changed, 421 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/uVM.iml create mode 100644 CMakeLists.txt create mode 100644 main.c create mode 100644 vm.c create mode 100644 vm.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5f3b5a --- /dev/null +++ b/.gitignore @@ -0,0 +1,84 @@ + +# Created by https://www.gitignore.io/api/clion + +### CLion ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### CLion Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/sonarlint + + +# End of https://www.gitignore.io/api/clion diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..30aa626 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..8822db8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..80d14e5 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/uVM.iml b/.idea/uVM.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/uVM.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..485872c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.12) +project(uVM C) + +set(CMAKE_C_STANDARD 11) + +add_executable(uVM main.c vm.c vm.h) \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..8c87dde --- /dev/null +++ b/main.c @@ -0,0 +1,24 @@ +#include + +#include "vm.h" +#include "string.h" + +int main() { + VM* vm = new_vm(); + + uint8_t data[] = { + 0x31, 0x05, + 0x32, 0x02, + 0x73, 0x12 + }; + memcpy(&vm->M, data, 6); + + printf("%i\n", (uint8_t)0x101); + + while(!vm->halted) { + vm_step(vm); + } + + free_vm(vm); + return 0; +} \ No newline at end of file diff --git a/vm.c b/vm.c new file mode 100644 index 0000000..d9d7c99 --- /dev/null +++ b/vm.c @@ -0,0 +1,186 @@ +// +// Created by Sam on 27/08/2018. +// + +#include +#include +#include +#include "vm.h" + +VM *new_vm() { + VM *vm = calloc(1, sizeof(VM)); + return vm; +} + +void free_vm(VM *vm) { + free(vm); +} + +void vm_reset(VM *vm) { + memset(vm->R, 0, sizeof(uint8_t) * VM_REG_SIZE); + vm->PC = 0; + vm->carry = 0; + vm->halted = false; +} + +void vm_clear(VM *vm) { + vm_reset(vm); + memset(&vm->M, 0, VM_MEM_SIZE); +} + +inline uint8_t vm_get_r(VM *vm, uint8_t r) { + if (r == 0) { + return 0; + } + if (r < VM_REG_SIZE) { + return vm->R[r]; + } + return 0; +} + +inline void vm_put_r(VM *vm, uint8_t r, uint8_t v) { + if (r < VM_REG_SIZE) { + vm->R[r] = v; + } +} + +inline void vm_decode_Q(VM_Instruction *inst, uint16_t raw) { + inst->rd = (uint8_t) ((raw & 0x0F00) >> 8); + inst->imm = (uint8_t) (raw & 0x00FF); +} + +inline void vm_decode_S(VM_Instruction *inst, uint16_t raw) { + inst->rd = (uint8_t) ((raw & 0x0F00) >> 8); + inst->rx = (uint8_t) ((raw & 0x00F0) >> 4); + inst->ry = (uint8_t) ((raw & 0x000F) >> 0); +} + +inline void vm_decode_T(VM_Instruction *inst, uint16_t raw) { + inst->rd = (uint8_t) ((raw & 0x0F00) >> 8); + inst->rx = (uint8_t) ((raw & 0x00F0) >> 4); + inst->imm = (uint8_t) ((raw & 0x000F) >> 0); +} + +inline uint8_t vm_subtract(uint8_t x, uint8_t y, uint8_t *ptr_borrow) { + uint8_t borrow = *ptr_borrow, + difference = 0, + xb, yb; + for (uint8_t i = 0; i < 8; i++) { + xb = (uint8_t) ((x >> i) & 1); + yb = (uint8_t) ((y >> i) & 1); + difference |= (uint8_t) (((xb ^ yb) ^ borrow) & 1) << i; + borrow = (uint8_t) (((~xb & yb) | ~(xb ^ yb) * borrow) & 1); + } + + *ptr_borrow = borrow; + return difference; +} + +void vm_step(VM *vm) { + VM_Instruction inst; + memset(&inst, 0, sizeof(VM_Instruction)); + + uint16_t PC = vm->PC; + uint16_t raw = (vm->M[PC] << 8) + vm->M[PC + 1]; + vm->PC += 2; + inst.op = (uint8_t) (raw >> 12); + + if (vm->halted) { + return; + } + + uint8_t temp = 0, x = 0, y = 0; + uint16_t temp16 = 0; + switch (inst.op) { + case OP_LDA: + vm_decode_Q(&inst, raw); + vm_put_r(vm, inst.rd, vm->M[inst.imm]); + break; + case OP_STA: + vm_decode_Q(&inst, raw); + vm->M[inst.imm] = (uint8_t) vm_get_r(vm, inst.rd); + break; + case OP_LDI: + vm_decode_Q(&inst, raw); + vm_put_r(vm, inst.rd, inst.imm); + break; + case OP_ADD: + vm_decode_S(&inst, raw); + vm->carry = 0; + temp = vm_get_r(vm, inst.rx) + vm_get_r(vm, inst.ry); + vm_put_r(vm, inst.rd, temp); + break; + case OP_ADC: + vm_decode_S(&inst, raw); + temp16 = vm_get_r(vm, inst.rx) + vm_get_r(vm, inst.ry) + vm->carry; + vm->carry = (uint8_t) (temp16 >> 8); + vm_put_r(vm, inst.rd, (uint8_t)temp16); + break; + case OP_SUB: + vm_decode_S(&inst, raw); + vm->carry = 0; + temp = vm_get_r(vm, inst.rx) - vm_get_r(vm, inst.ry); + vm_put_r(vm, inst.rd, temp); + break; + case OP_SBC: + vm_decode_S(&inst, raw); + x = vm_get_r(vm, inst.rx); + y = vm_get_r(vm, inst.ry); + temp = vm_subtract(x, y, &vm->carry); + vm_put_r(vm, inst.rd, temp); + break; + case OP_NOT: + vm_decode_T(&inst, raw); + temp = vm_get_r(vm, inst.rx); + vm_put_r(vm, inst.rd, ~temp); + break; + case OP_AND: + vm_decode_S(&inst, raw); + temp = vm_get_r(vm, inst.rx) & vm_get_r(vm, inst.ry); + vm_put_r(vm, inst.rd, temp); + break; + case OP_SHL: + vm_decode_T(&inst, raw); + temp = vm_get_r(vm, inst.rx) << vm_get_r(vm, (uint8_t) inst.imm); + vm_put_r(vm, inst.rd, temp); + break; + case OP_SHR: + vm_decode_T(&inst, raw); + temp = vm_get_r(vm, inst.rx) >> vm_get_r(vm, (uint8_t) inst.imm); + vm_put_r(vm, inst.rd, temp); + break; + case OP_SYS: + vm_decode_Q(&inst, raw); + if (vm->syscall != NULL) { + temp = vm->syscall(vm, inst.imm); + vm_put_r(vm, inst.rd, temp); + } else { + printf("SYSCALL #%d\n", inst.imm); + } + break; + case OP_JMP: + vm_decode_Q(&inst, raw); + vm->PC = vm->M[inst.rd]; + break; + case OP_JEQ: + vm_decode_S(&inst, raw); + if (vm_get_r(vm, inst.rx) == vm_get_r(vm, inst.ry)) { + vm->PC = vm->M[inst.rd]; + } + break; + case OP_JLT: + vm_decode_S(&inst, raw); + if (vm_get_r(vm, inst.rx) < vm_get_r(vm, inst.ry)) { + vm->PC = vm->M[inst.rd]; + } + break; + case OP_HLT: + printf("Halted at 0x%04hX\n", PC); + vm->halted = true; + break; + default: + printf("Unknown Instruction at 0x%04hX: 0x%hhX\n", PC, inst.op); + vm->halted = true; + break; + } +} \ No newline at end of file diff --git a/vm.h b/vm.h new file mode 100644 index 0000000..89141d4 --- /dev/null +++ b/vm.h @@ -0,0 +1,70 @@ +// +// Created by Sam on 27/08/2018. +// + +#ifndef UVM_VM_H +#define UVM_VM_H + +#include +#include + +#define VM_MEM_SIZE (1<<8)-1 +#define VM_REG_SIZE 15 + +#define OP_HLT 0x0 +#define OP_LDA 0x1 +#define OP_STA 0x2 +#define OP_LDI 0x3 +#define OP_ADD 0x4 +#define OP_ADC 0x5 +#define OP_SUB 0x6 +#define OP_SBC 0x7 +#define OP_NOT 0x8 +#define OP_AND 0x9 +#define OP_SHL 0xa +#define OP_SHR 0xb +#define OP_SYS 0xc +#define OP_JMP 0xd +#define OP_JEQ 0xe +#define OP_JLT 0xf + +struct VM_Instruction_t { + uint8_t op; + uint8_t rd; + uint8_t rx; + uint8_t ry; + uint8_t imm; +}; +typedef struct VM_Instruction_t VM_Instruction; + +struct VM_t { + uint8_t R[VM_REG_SIZE]; + uint16_t PC; + uint8_t M[VM_MEM_SIZE]; + uint8_t carry; + bool halted; + uint8_t (*syscall)(struct VM_t* vm, uint8_t callno); +}; +typedef struct VM_t VM; + +VM * new_vm(); + +void free_vm(VM *vm); + +void vm_reset(VM *vm); + +void vm_clear(VM *vm); + +uint8_t vm_get_r(VM *vm, uint8_t r); + +void vm_put_r(VM *vm, uint8_t r, uint8_t v); + +void vm_decode_Q(VM_Instruction *inst, uint16_t raw); +void vm_decode_S(VM_Instruction *inst, uint16_t raw); +void vm_decode_T(VM_Instruction *inst, uint16_t raw); + +uint8_t vm_subtract(uint8_t x, uint8_t y, uint8_t *ptr_borrow); + +void vm_step(VM *vm); + +#endif //UVM_VM_H