Fix broken static push/pop implementation
x1phosura x1phosura@x1phosura.zone
Thu, 07 Dec 2023 22:16:42 -0800
3 files changed,
38 insertions(+),
22 deletions(-)
M
projects/08/src/codewriter.h
→
projects/08/src/codewriter.h
@@ -33,11 +33,11 @@ #define STATIC (16) // start of static variables segment (240 words, 16-255)
char *static_sym_name; -// static segment index indexes into map, retrieves hack assembly symbol offset +// retrieve hack assembly RAM offset given static "symbol" number #define MAX_STATIC_SYMBOLS (240) // for whatever. -uint16_t static_symbol_map[MAX_STATIC_SYMBOLS]; -uint8_t g_symbol_offset_bump = 0; // holds current largest symbol offset, bumps - +uint16_t static_symbol_map[MAX_STATIC_SYMBOLS]; // 0..239 maps to 16..255 +uint8_t g_symbol_offset_start = 0; // set to g_symbol_offset_stop on new file +uint8_t g_symbol_offset_stop = 0; // bump when new static number (sym) found char comp_vm_funcs[] = "@__comp_funcs_end\n" "0;JMP\n"@@ -97,13 +97,17 @@ "0;JMP\n" // return
"\n" "(__comp_funcs_end)\n"; -char vm_init[] = "@256\n" // start address of stack (nothing pushed yet) - "D=A\n" // D = 256 +char vm_init[] = "@261\n" // start address of stack (nothing pushed yet) + "D=A\n" // D = 261 (why? because we are simulating a + // "call", and a call would add 5 to SP, which + // is expected to be initialized to 256. + // TODO: verify if I also need to init LCL, ARG + // THIS/THAT etc... (I probably don't) "@SP\n" // A = <constant representing address of SP> "M=D\n" // <memory pointed to by SP> = 256 "@Sys.init\n" // jump to Sys.init function (not call since "0;JMP\n\n"; // we don't need to set up the stack) -// TODO: add initializers for argument, local, static, constant, this, that +// TODO: add initializers for argument, local, static, this, that // TODO only output vm_stop when Main.main char vm_stop[] = "(END)\n" // starting address of stack (nothing pushed yet)@@ -197,30 +201,35 @@
return true; } +// attempt to either 1) resolve an existing static variable, or 2) associate +// the static variable with a new slot in the static section (which can later +// be resolved) static bool resolve_static_address(struct vm_instruction_t *vm_instr, uint16_t *addr) { - uint16_t symbol_offset; - if (vm_instr->arg2 >= MAX_STATIC_SYMBOLS) { - err("error: arg2 too large, >= %u\n", MAX_STATIC_SYMBOLS); + uint16_t sym_offset; + // Basically, g_symbol_offset_start "indexes" into the VM files', and + // g_symbol_offset_stop indexes the last added static var per file. + // These variables serve as a window into static_symbol_map + if (g_symbol_offset_stop >= MAX_STATIC_SYMBOLS) { + err("error: symbol offset grew too large (>= %u), too many " + "static variables\n", MAX_STATIC_SYMBOLS); return false; } - symbol_offset = static_symbol_map[vm_instr->arg2]; - if (symbol_offset == 0xffff) { // new offset not in map (-1 special) - if (g_symbol_offset_bump >= MAX_STATIC_SYMBOLS) { - err("error: symbol offset grew too large (>= %u), " - "too many static variables\n", MAX_STATIC_SYMBOLS); - return false; + for (sym_offset = g_symbol_offset_start; + sym_offset <= g_symbol_offset_stop; ++sym_offset) { + // found static "symbol" (number after push/pop static ...) + if (static_symbol_map[sym_offset] == vm_instr->arg2) { + *addr = sym_offset + 16; + return true; } - static_symbol_map[vm_instr->arg2] = g_symbol_offset_bump; - *addr = g_symbol_offset_bump; - ++g_symbol_offset_bump; // bump global symbol offset - } else { - // offset found in map, return symbol value/index - *addr = symbol_offset; } + // insert vm_instr->arg2 into next static_symbol_map slot + static_symbol_map[g_symbol_offset_stop] = vm_instr->arg2; + ++g_symbol_offset_stop; // bump stop offset + *addr = (g_symbol_offset_stop - 1) + 16; // add 16 to map to RAM return true; }@@ -491,6 +500,8 @@ "A=M\n" // A = retAddr
"0;JMP\n" // return "\n"; + // idea: make global function, "call" this function when doing 'return' + // similar to conditional branch (TODO) fprintf(fp, "%s", ret_boilerplate); return true; }
M
projects/08/src/util.h
→
projects/08/src/util.h
@@ -21,6 +21,9 @@
extern char *file_line; // reference to currently-read line (for convenience) extern size_t file_line_no; // line number, regardless of line content +extern uint8_t g_symbol_offset_start; +extern uint8_t g_symbol_offset_stop; + #define err(...) (fprintf(stdout, __VA_ARGS__), \ fprintf(stdout, "%lu | %s\n", file_line_no, file_line)) #define die(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0)
M
projects/08/src/vmtranslator.c
→
projects/08/src/vmtranslator.c
@@ -102,6 +102,7 @@ size_t i, line_len;
if (add_init) write_vm_init(out_file); + //g_symbol_offset_bump = 0; // reset symbol map pointer (might be bug/unnecessary) for (i = 0; i < MAX_STATIC_SYMBOLS; ++i) static_symbol_map[i] = -1; // initialize symbol map table@@ -148,6 +149,7 @@ FILE *in_file = fopen(vm_file_path, "r"); // read input file
if (in_file == NULL) die("failed to open %s for reading\n", vm_file_path); + g_symbol_offset_start = g_symbol_offset_stop; // bump on new file if (!set_static_symbol_name(vm_file_path)) die("error reading file name %s\n", vm_file_path); fprintf(out_file, "// path: %s\n", vm_file_path); // for debugging