diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5f4ebb8 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +main.exe diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..aa80fea --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,23 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**", + "C:/MinGW/include/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.22000.0", + "compilerPath": "C:/MinGW/bin/gcc.exe", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "windows-gcc-x86", + "configurationProvider": "ms-vscode.makefile-tools" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..baee89d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "files.associations": { + "stdlib.h": "c", + "stdio.h": "c", + "os.h": "c", + "fcntl.h": "c", + "io.h": "c", + "errno.h": "c", + "stdbool.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..066b128 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +CC=gcc +CFLAGS=-g -Wall +INCLUDES=./include + +.DEFAULT_GOAL := main + +%: src/%.c + $(CC) -o $@ $< $(CFLAGS) -I$(INCLUDES) + +clean: + rm main.exe \ No newline at end of file diff --git a/examples/many_register_mov.asm b/examples/many_register_mov.asm new file mode 100644 index 0000000..8ae1fe1 --- /dev/null +++ b/examples/many_register_mov.asm @@ -0,0 +1,29 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 38 +; ======================================================================== + +bits 16 + +mov cx, bx +mov ch, ah +mov dx, bx +mov si, bx +mov bx, di +mov al, cl +mov ch, ch +mov bx, ax +mov bx, si +mov sp, di +mov bp, ax \ No newline at end of file diff --git a/examples/single_register_mov.asm b/examples/single_register_mov.asm new file mode 100644 index 0000000..5f91c9c --- /dev/null +++ b/examples/single_register_mov.asm @@ -0,0 +1,19 @@ +; ======================================================================== +; +; (C) Copyright 2023 by Molly Rocket, Inc., All Rights Reserved. +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Please see https://computerenhance.com for further information +; +; ======================================================================== + +; ======================================================================== +; LISTING 37 +; ======================================================================== + +bits 16 + +mov cx, bx \ No newline at end of file diff --git a/include/os.h b/include/os.h new file mode 100644 index 0000000..addd605 --- /dev/null +++ b/include/os.h @@ -0,0 +1,15 @@ + +#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + #define IS_WINDOWS +#elif defined(__linux__) + #define IS_LINUX +#else + #error Unable to determine platform +#endif + +#if defined(IS_LINUX) + #include + #define MAX_PATH_SIZE PATH_MAX +#elif defined(IS_WINDOWS) + #define MAX_PATH_SIZE 260 +#endif \ No newline at end of file diff --git a/src/cpu.c b/src/cpu.c new file mode 100644 index 0000000..adba19e --- /dev/null +++ b/src/cpu.c @@ -0,0 +1,83 @@ +#include +#include +#include + +#define u32 uint32_t +#define u16 uint16_t +#define u8 uint8_t + +struct cpu_state { + u16 ax, bx, cx, dx, sp, bp, si, di; +}; + +const char *lookup_reg_name(u8 idx, bool wide) { + if (wide) { + if (idx == 0b000) { + return "ax"; + } else if (idx == 0b001) { + return "cx"; + } else if (idx == 0b010) { + return "dx"; + } else if (idx == 0b011) { + return "bx"; + } else if (idx == 0b100) { + return "sp"; + } else if (idx == 0b101) { + return "bp"; + } else if (idx == 0b110) { + return "si"; + } else if (idx == 0b111) { + return "di"; + } + } else { + if (idx == 0b000) { + return "al"; + } else if (idx == 0b001) { + return "cl"; + } else if (idx == 0b010) { + return "dl"; + } else if (idx == 0b011) { + return "bl"; + } else if (idx == 0b100) { + return "ah"; + } else if (idx == 0b101) { + return "ch"; + } else if (idx == 0b110) { + return "dh"; + } else if (idx == 0b111) { + return "bh"; + } + } + + printf("ERROR: Unknown register %d, wide %d", idx, wide); + abort(); +} + +void dissassemble(FILE *src, FILE *dst) { + fprintf(dst, "bits 16\n\n"); + while (!feof(src)) { + u8 byte1 = fgetc(src); + u8 byte2 = fgetc(src); + + if ((byte1 & 0b11111100) == 0b10001000) { + bool wide = byte1 & 0b1; + bool direction = (byte1 & 0b10) >> 1; + + u8 mod = byte2 & 0b11000000; + u8 reg = (byte2 & 0b00111000) >> 3; + u8 rm = byte2 & 0b00000111; + if (mod == 0b11000000) { + const char *reg_name = lookup_reg_name(reg, wide); + const char *rm_name = lookup_reg_name(rm, wide); + if (direction) { + fprintf(dst, "mov %s, %s\n", reg_name, rm_name); + } else { + fprintf(dst, "mov %s, %s\n", rm_name, reg_name); + } + } else { + printf("ERROR: Unsupported mod '%d'", mod); + abort(); + } + } + } +} \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..0560385 --- /dev/null +++ b/src/main.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include "os.h" +#include "cpu.c" +#include + +const char *get_tmp_dir() { +#ifdef IS_WINDOWS + char *dir; + if ((dir = getenv("TMPDIR")) != NULL) return dir; + if ((dir = getenv("TEMP")) != NULL) return dir; + if ((dir = getenv("TMP")) != NULL) return dir; + return NULL; +#elif IS_LINUX + return "/tmp"; +#endif +} + +void get_tmp_file(char *filename, const char *prefix) { + const char *dir = get_tmp_dir(); + sprintf(filename, "%s\\%sXXXXXX", dir, prefix); + int fd = mkstemp(filename); + close(fd); +} + +int main() { + char tmp_filename[MAX_PATH_SIZE]; + get_tmp_file(tmp_filename, "nasm_output"); + + char *example_filename = "examples/many_register_mov.asm"; + + char command[512] = { 0 }; + snprintf(command, sizeof(command), "nasm \"%s\" -o \"%s\"", example_filename, tmp_filename); + if (system(command)) { + printf("ERROR: Failed to compile '%s'", example_filename); + return -1; + } + + FILE *assembly = fopen(tmp_filename, "r"); + if (assembly == NULL) { + printf("ERROR: Opening file '%s': %d\n", tmp_filename, errno); + return -1; + } + dissassemble(assembly, stdout); + fclose(assembly); + + remove(tmp_filename); + + return 0; +}