add a way to test dissassembling of .asm files automatically
This commit is contained in:
parent
32f7f00952
commit
bdaba318eb
@ -6,51 +6,15 @@
|
||||
#define u16 uint16_t
|
||||
#define u8 uint8_t
|
||||
|
||||
struct cpu_state {
|
||||
u16 ax, bx, cx, dx, sp, bp, si, di;
|
||||
};
|
||||
const char *wide_reg_names[8] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" };
|
||||
const char *non_wide_reg_names[8] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" };
|
||||
|
||||
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";
|
||||
}
|
||||
return wide_reg_names[idx];
|
||||
} 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";
|
||||
}
|
||||
return non_wide_reg_names[idx];
|
||||
}
|
||||
|
||||
printf("ERROR: Unknown register %d, wide %d", idx, wide);
|
||||
abort();
|
||||
}
|
||||
|
||||
void dissassemble(FILE *src, FILE *dst) {
|
||||
@ -59,6 +23,7 @@ void dissassemble(FILE *src, FILE *dst) {
|
||||
u8 byte1 = fgetc(src);
|
||||
u8 byte2 = fgetc(src);
|
||||
|
||||
// Register memory to/from register
|
||||
if ((byte1 & 0b11111100) == 0b10001000) {
|
||||
bool wide = byte1 & 0b1;
|
||||
bool direction = (byte1 & 0b10) >> 1;
|
149
src/main.c
149
src/main.c
@ -1,9 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include "os.h"
|
||||
#include "cpu.c"
|
||||
#include <errno.h>
|
||||
#include "asm.c"
|
||||
|
||||
#define strequal(a, b) strcmp(a, b) == 0
|
||||
|
||||
const char *get_tmp_dir() {
|
||||
#ifdef IS_WINDOWS
|
||||
@ -17,6 +20,24 @@ const char *get_tmp_dir() {
|
||||
#endif
|
||||
}
|
||||
|
||||
int strendswith(const char *str, const char *suffix)
|
||||
{
|
||||
if (!str || !suffix)
|
||||
return 0;
|
||||
size_t lenstr = strlen(str);
|
||||
size_t lensuffix = strlen(suffix);
|
||||
if (lensuffix > lenstr)
|
||||
return 0;
|
||||
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
|
||||
}
|
||||
|
||||
char *strdup(const char *src) {
|
||||
char *dst = malloc(strlen (src) + 1);
|
||||
if (dst == NULL) return NULL;
|
||||
strcpy(dst, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void get_tmp_file(char *filename, const char *prefix) {
|
||||
const char *dir = get_tmp_dir();
|
||||
sprintf(filename, "%s\\%sXXXXXX", dir, prefix);
|
||||
@ -24,28 +45,124 @@ void get_tmp_file(char *filename, const char *prefix) {
|
||||
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";
|
||||
void print_usage(const char *program) {
|
||||
fprintf(stderr, "Usage: %s <test|dump> <file>\n", program);
|
||||
}
|
||||
|
||||
int compile_asm(const char *src, const char *dst) {
|
||||
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);
|
||||
snprintf(command, sizeof(command), "nasm \"%s\" -o \"%s\"", src, dst);
|
||||
return system(command);
|
||||
}
|
||||
|
||||
int compare_files(const char *expected, const char *gotten) {
|
||||
int rc = -1;
|
||||
FILE *f1 = fopen(expected, "r");
|
||||
FILE *f2 = fopen(gotten, "r");
|
||||
|
||||
int i = 0;
|
||||
while (!feof(f1) && !feof(f2)) {
|
||||
int byte1 = fgetc(f1);
|
||||
int byte2 = fgetc(f2);
|
||||
if (byte1 != byte2) {
|
||||
printf("Mismatch byte at %d, expected %d got %d\n", i, byte1, byte2);
|
||||
goto err;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!feof(f1) || !feof(f2)) {
|
||||
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
err:
|
||||
fclose(f1);
|
||||
fclose(f2);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
print_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE *assembly = fopen(tmp_filename, "r");
|
||||
if (assembly == NULL) {
|
||||
printf("ERROR: Opening file '%s': %d\n", tmp_filename, errno);
|
||||
if (strequal(argv[1], "test")) {
|
||||
char *asm_file = argv[2];
|
||||
if (!strendswith(asm_file, ".asm")) {
|
||||
printf("ERROR: Expected *.asm file, gotten '%s'", asm_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *bin_filename = "test-input.o";
|
||||
if (compile_asm(asm_file, bin_filename)) {
|
||||
printf("ERROR: Failed to compile '%s'", asm_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE *bin_test = fopen(bin_filename, "rb");
|
||||
if (bin_test == NULL) {
|
||||
printf("ERROR: Opening file '%s': %d\n", bin_filename, errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *dissassembly_filename = "test-dump.asm";
|
||||
FILE *dissassembly = fopen(dissassembly_filename, "wb+");
|
||||
if (dissassembly == NULL) {
|
||||
printf("ERROR: Opening file '%s': %d\n", dissassembly_filename, errno);
|
||||
return -1;
|
||||
}
|
||||
dissassemble(bin_test, dissassembly);
|
||||
fclose(dissassembly);
|
||||
|
||||
char *dissassembly_dump_filename = "test-dump-asm.o";
|
||||
if (compile_asm(dissassembly_filename, dissassembly_dump_filename)) {
|
||||
printf("ERROR: Failed to compile '%s'", dissassembly_filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!compare_files(bin_filename, dissassembly_dump_filename)) {
|
||||
printf("Test success\n");
|
||||
} else {
|
||||
printf("Test failed\n");
|
||||
}
|
||||
|
||||
} else if (strequal(argv[1], "dump")) {
|
||||
char *input_file = argv[2];
|
||||
|
||||
if (strendswith(input_file, ".asm")) {
|
||||
char bin_filename[MAX_PATH_SIZE];
|
||||
get_tmp_file(bin_filename, "nasm_output");
|
||||
|
||||
if (compile_asm(input_file, bin_filename)) {
|
||||
printf("ERROR: Failed to compile '%s'", input_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE *assembly = fopen(bin_filename, "r");
|
||||
if (assembly == NULL) {
|
||||
printf("ERROR: Opening file '%s': %d\n", bin_filename, errno);
|
||||
return -1;
|
||||
}
|
||||
dissassemble(assembly, stdout);
|
||||
|
||||
remove(bin_filename);
|
||||
} else {
|
||||
FILE *assembly = fopen(input_file, "r");
|
||||
if (assembly == NULL) {
|
||||
printf("ERROR: Opening file '%s': %d\n", input_file, errno);
|
||||
return -1;
|
||||
}
|
||||
dissassemble(assembly, stdout);
|
||||
fclose(assembly);
|
||||
}
|
||||
|
||||
} else {
|
||||
print_usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
dissassemble(assembly, stdout);
|
||||
fclose(assembly);
|
||||
|
||||
remove(tmp_filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
1
test-dump-asm.o
Normal file
1
test-dump-asm.o
Normal file
@ -0,0 +1 @@
|
||||
菓
|
3
test-dump.asm
Normal file
3
test-dump.asm
Normal file
@ -0,0 +1,3 @@
|
||||
bits 16
|
||||
|
||||
mov cx, bx
|
1
test-input.o
Normal file
1
test-input.o
Normal file
@ -0,0 +1 @@
|
||||
菓
|
Loading…
Reference in New Issue
Block a user