Fix TWO bad return bugs, make init optional
x1phosura x1phosura@x1phosura.zone
Tue, 12 Dec 2023 21:23:35 -0800
3 files changed,
46 insertions(+),
22 deletions(-)
M
projects/08/src/codewriter.h
→
projects/08/src/codewriter.h
@@ -31,9 +31,11 @@ #define R14 (14) // VM-generated assembly can use
#define R15 (15) // for whatever. #define STATIC (16) // start of static variables segment (240 words, 16-255) +bool g_init = true; + char *static_sym_name; -// retrieve hack assembly RAM offset given static "symbol" number +// retrieve static section offset in RAM given static "symbol" number #define MAX_STATIC_SYMBOLS (240) // for whatever. 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@@ -101,22 +103,34 @@ 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, this, that + +char vm_no_init[] = "@SP\n" + "D=M\n" + "@5\n" + "D=D-A\n" // D = SP - 5 + "@R13\n" + "M=D\n" // R13 = SP - 5 + "@__end\n" + "D=A\n" // D = address of end-of-program + "@R13\n" + "A=M\n" // A = RAM[R13] = SP - 5 + "M=D\n\n"; // set bottom of stack to end-of-program // TODO only output vm_stop when Main.main -char vm_stop[] = "(END)\n" // starting address of stack (nothing pushed yet) - "@END\n" // D = 256 - "0;JMP\n"; // A = <constant representing address of SP> +char vm_stop[] = "(__end)\n" + "@__end\n" // temrinate with infinite loop + "0;JMP\n"; void write_vm_init(FILE *fp) { - fprintf(fp, "%s", vm_init); // can (un)comment to toggle init behavior + if (g_init) + fprintf(fp, "%s", vm_init); // can (un)comment to toggle init behavior + else + fprintf(fp, "%s", vm_no_init); fprintf(fp, "%s\n", comp_vm_funcs); }@@ -419,6 +433,7 @@ static bool write_function(struct vm_instruction_t *vm_instr, FILE *fp)
{ size_t i, num_locals; num_locals = vm_instr->arg2; + // TODO handle 'function func.name 0' as special case char set_local_boilerplate[] = "M=0\n" "A=A+1\n"; char set_sp[] = "D=A\n" // D = number of locals@@ -429,7 +444,8 @@ // (functionName) // injects function entry label into the code
// repeat nVars times: // nVars = number of local variables // push 0 // initializes local variable to 0 fprintf(fp, "(%s)\n", vm_instr->arg1); // write function label - fprintf(fp, "@SP\n"); // get SP + fprintf(fp, "@SP\n" + "A=M\n"); // get SP for (i = 0; i < num_locals; ++i) { fprintf(fp, "%s", set_local_boilerplate); // write 'push 0' }@@ -452,12 +468,24 @@ * LCL = *(frame - 4) // restores LCL for the caller
* goto retAddr // jump to where return address points */ char ret_boilerplate[] = "// *ARG = pop()\n" + "// R13 = retAddr = *(frame - 5)\n" + "@5\n" + "D=A\n" // D = 5 + "@LCL\n" + "A=M-D\n" // A = (LCL - 5) -> return address + "D=M\n" // D = *(LCL - 5) = return address + "@R13\n" + "M=D\n" // R13 = D (retAddr) + // ======== BUG BUG BUG BUG ======== + // THIS WILL OVERWRITE THE SAVED RETURN ADDRESS + "// *ARG = pop()\n" "@SP\n" "AM=M-1\n" // decrement A and SP "D=M\n" // "pop" (read) return value into D "@ARG\n" "A=M\n" // A points to argument segment "M=D\n" // *ARG = D // (D = pop()) + // ======== BUG BUG BUG BUG ======== "// SP = ARG+1\n" "D=A+1\n" // A still contains arg pointer "@SP\n"@@ -481,17 +509,10 @@ "AM=M-1\n" // decrement A and LCL
"D=M\n" // D = *(frame - 3) "@ARG\n" "M=D\n" - "// R13 = retAddr = *(frame - 5)\n" - "@LCL\n" - "AM=M-1\n" // decrement A and LCL - // now LCL = LCL - 4 - "D=M-1\n" // D = *(frame - 4 - 1) - "@R13\n" - "M=D\n" // R13 = D (retAddr) "// LCL = *(frame - 4)\n" "@LCL\n" - "A=M\n" // put pointer in address reg. - "D=M\n" // D = prev. LCL value + "A=M-1\n" // decrement A and LCL + "D=M\n" // D = *(frame - 4) "@LCL\n" "M=D\n" // write prev LCL value to LCL "// goto retAddr\n"
M
projects/08/src/util.h
→
projects/08/src/util.h
@@ -18,9 +18,9 @@ #else
#define DBGLOG(...) #endif +extern bool g_init; // do/don't add initialization bootstrap code 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;
M
projects/08/src/vmtranslator.c
→
projects/08/src/vmtranslator.c
@@ -102,12 +102,10 @@ 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 file_line_no = 0; - //instruction_offset = 0; // TODO: unnecessary? while (fgets(in_line, MAX_LINE_LEN, in_file) != NULL) { // parse loop ++file_line_no; file_line = in_line;@@ -177,10 +175,15 @@ FILE *out_file;
if (argc == 2) { out_file = stdout; - } else if (argc == 3) { + } else if (argc == 3 || argc == 4) { out_file = fopen(argv[2], "wb"); if (out_file == NULL) die("failed to open %s for writing\n", argv[2]); + if (argc == 4) { + if (!strcmp(argv[3], "--no-init")) { + g_init = false; + } + } } else { die("%s", usage_msg); }