all repos — nand2tetris @ c7c3d810220eef180364e7d57c0dfb5a2cd152a9

my nand2tetris progress

Generate static seg. symbol, fix push instruction
x1phosura x1phosura@x1phosura.zone
Sat, 04 Nov 2023 14:35:19 -0700
commit

c7c3d810220eef180364e7d57c0dfb5a2cd152a9

parent

044076b7d21c865c7c6a63e8339be2a6067bd3fe

2 files changed, 103 insertions(+), 74 deletions(-)

jump to
M projects/07/src/codewriter.hprojects/07/src/codewriter.h

@@ -19,7 +19,7 @@ // memory mapping:

// 0-15 virtual registers R0-R15 // 16-255 static variables // 256-2047 stack -#define SP (0) // points to stack +#define SP (0) // points to word ahead of top of stack #define LCL (1) // points to local segment #define ARG (2) // points to argument segment #define POINTER (3)

@@ -29,14 +29,16 @@ #define TEMP (5) //

#define R13 (13) // R13-R15 are scratch space that #define R14 (14) // VM-generated assembly can use #define R15 (15) // for whatever. -#define STATIC (16) // start of static variables segment (240 words long) +#define STATIC (16) // start of static variables segment (240 words, 16-255) -char vm_init[] = "@256\n" // starting address of stack +char vm_init[] = "@256\n" // starting address of stack (nothing pushed yet) "D=A\n" // D = 256 "@SP\n" // A = <constant representing address of SP> "M=D\n" // <memory pointed to by SP> = 256 "\n"; // TODO: add initializers for argument, local, static, constant, this, that + +char *static_sym_name; // static segment index indexes into map, retrieves hack assembly symbol offset #define MAX_STATIC_SYMBOLS (240) // for whatever.

@@ -53,7 +55,9 @@

static bool write_arithmetic(struct vm_instruction_t *vm_instr, FILE *fp) { // TODO: write assembly code for 'add' and 'neg' instructions, turn into - // codegen + // codegen (depend on if unary/binary operation) + // Binary: load RAM[SP], D=M, RAM[SP]--, M=D<op>M (I _think_ this is good) + // Unary: load RAM[SP], M=<op>M (I _think_ this is good) fprintf(fp, "ARITHMETIC INSTRUCTION: "); print_vm_instruction(vm_instr); return true;

@@ -76,11 +80,11 @@ "too many static variables\n", MAX_STATIC_SYMBOLS);

return false; } static_symbol_map[vm_instr->arg2] = g_symbol_offset_bump; - *addr = STATIC + g_symbol_offset_bump; + *addr = g_symbol_offset_bump; ++g_symbol_offset_bump; // bump global symbol offset } else { // offset was found in map, return symbol value/index - *addr = STATIC + symbol_offset; + *addr = symbol_offset; } return true;

@@ -105,59 +109,53 @@ uint16_t addr, arg2 = vm_instr->arg2;

// TODO: maybe add SP counter/check to catch overflows // TODO: if vm_instr->arg1 == "constant", push_constant, else push_segment - char push_const_boilerplate[] = "@%hu\n" // A = constant - "D=A\n" // D = constant - "@SP\n" - "M=M+1\n" // RAM[SP]++ // inc SP - "A=M\n" // A = RAM[SP] - "M=D\n"; // RAM[SP] = constant - char push_addr_boilerplate[] = "@%hu\n" // A = segment + index - "D=M\n" // D = RAM[segment + index] - "@SP\n" - "M=M+1\n" // RAM[SP]++ // inc SP - "A=M\n" // A = RAM[SP] - "M=D\n"; // RAM[SP] = constant - char push_indirect_boilerplate[] = "@%hu\n" // A = segment - "D=A\n" // D = segment - "@%hu\n" // A = index - "A=A+D\n" // A = segment + index - "D=M\n" // D = RAM[segment + index] - "@SP\n" - "M=M+1\n" // RAM[SP]++ - "A=M\n" // A = RAM[SP] - "M=D\n"; + char const_template[] = "@%hu\n" // A = constant + "D=A\n%s"; // D = constant + char addr_template[] = "@%hu\n" // A = segment + index + "D=M\n%s"; // D = RAM[segment + index] + char static_template[] = "@%s.%hu\n" // A = segment + index + "D=M\n%s"; // D = RAM[segment + index] + char indirect_template[] = "@%hu\n" // A = segment + "D=A\n" // D = segment + "@%hu\n" // A = index + "A=A+D\n" // A = segment + index + "D=M\n%s"; // D = RAM[segment + index] + char push_boilerplate[] = "@SP\n" + "M=M+1\n" // RAM[SP]++ // inc SP + "A=M-1\n" // A = RAM[SP] - 1 // prev top + "M=D\n"; // RAM[SP] = constant + // TODO: move segment resolution to separate function if (!strcmp(vm_instr->arg1, "constant")) { // TODO: check size of constant (allowed to be > 32,767?) // TODO: look up in nand2tetris forums in case issue already noted - fprintf(fp, push_const_boilerplate, arg2); - } else { - // TODO: move segment resolution to separate function - if (!strcmp(vm_instr->arg1, "argument")) { - fprintf(fp, push_indirect_boilerplate, ARG, arg2); - } else if (!strcmp(vm_instr->arg1, "local")) { - fprintf(fp, push_indirect_boilerplate, LCL, arg2); - } else if (!strcmp(vm_instr->arg1, "static")) { - if (!resolve_static_address(vm_instr, &addr)) { - return false; - } - fprintf(fp, push_addr_boilerplate, addr); - } else if (!strcmp(vm_instr->arg1, "this")) { - fprintf(fp, push_indirect_boilerplate, THIS, arg2); - } else if (!strcmp(vm_instr->arg1, "that")) { - fprintf(fp, push_indirect_boilerplate, THAT, arg2); - } else if (!strcmp(vm_instr->arg1, "pointer")) { - addr = POINTER + vm_instr->arg2; - fprintf(fp, push_addr_boilerplate, addr); - } else if (!strcmp(vm_instr->arg1, "temp")) { - addr = TEMP + vm_instr->arg2; - fprintf(fp, push_addr_boilerplate, addr); - } else { - err("error: invalid segment name \"%s\"\n", - vm_instr->arg1); + fprintf(fp, const_template, arg2, push_boilerplate); + } else if (!strcmp(vm_instr->arg1, "argument")) { + fprintf(fp, indirect_template, ARG, arg2, push_boilerplate); + } else if (!strcmp(vm_instr->arg1, "local")) { + fprintf(fp, indirect_template, LCL, arg2, push_boilerplate); + } else if (!strcmp(vm_instr->arg1, "static")) { + if (!resolve_static_address(vm_instr, &addr)) { return false; } + fprintf(fp, static_template, static_sym_name, addr, + push_boilerplate); + } else if (!strcmp(vm_instr->arg1, "this")) { + fprintf(fp, indirect_template, THIS, arg2, push_boilerplate); + } else if (!strcmp(vm_instr->arg1, "that")) { + fprintf(fp, indirect_template, THAT, arg2, push_boilerplate); + } else if (!strcmp(vm_instr->arg1, "pointer")) { + addr = POINTER + vm_instr->arg2; + fprintf(fp, addr_template, addr, push_boilerplate); + } else if (!strcmp(vm_instr->arg1, "temp")) { + addr = TEMP + vm_instr->arg2; + fprintf(fp, addr_template, addr, push_boilerplate); + } else { + err("error: invalid segment name \"%s\"\n", + vm_instr->arg1); + return false; } + return true; }

@@ -167,40 +165,40 @@ {

// TODO: maybe add SP counter/check to catch overflows // can use R13-R15 for scratch space uint16_t addr, arg2 = vm_instr->arg2; - char pop_addr_boilerplate[] = "@%hu\n" // A = segment + index - "D=M\n" // D = RAM[segment + index] - "@SP\n" - "AM=M-1\n" // RAM[SP]--, A = RAM[SP] - "M=D\n"; // D = RAM[SP] - char pop_indirect_boilerplate[] = "@%hu\n" // @segment - "D=A\n" // D = segment - "@%hu\n" // @index - "A=A+D\n" // A = segment + index - "D=M\n" // D = RAM[segment + index] - "@SP\n" - "AM=M-1\n" // RAM[SP]--; A = RAM[SP] - "M=D\n"; + char addr_template[] = "@%hu\n" // A = segment + index + "D=M\n%s"; // D = RAM[segment + index] + char static_template[] = "@%s.%hu\n" // A = segment + index + "D=M\n%s"; // D = RAM[segment + index] + char indirect_template[] = "@%hu\n" // @segment + "D=A\n" // D = segment + "@%hu\n" // @index + "A=A+D\n" // A = segment + index + "D=M\n%s"; // D = RAM[segment + index] + char pop_boilerplate[] = "@SP\n" + "AM=M-1\n" // RAM[SP]--, A = RAM[SP] + "M=D\n"; // RAM[SP] = D // TODO: move segment resolution to separate function if (!strcmp(vm_instr->arg1, "argument")) { - fprintf(fp, pop_indirect_boilerplate, ARG, arg2); + fprintf(fp, indirect_template, ARG, arg2, pop_boilerplate); } else if (!strcmp(vm_instr->arg1, "local")) { - fprintf(fp, pop_indirect_boilerplate, LCL, arg2); + fprintf(fp, indirect_template, LCL, arg2, pop_boilerplate); } else if (!strcmp(vm_instr->arg1, "static")) { if (!resolve_static_address(vm_instr, &addr)) { return false; } - fprintf(fp, pop_addr_boilerplate, addr); + fprintf(fp, static_template, static_sym_name, addr, + pop_boilerplate); } else if (!strcmp(vm_instr->arg1, "this")) { - fprintf(fp, pop_indirect_boilerplate, THIS, arg2); + fprintf(fp, indirect_template, THIS, arg2, pop_boilerplate); } else if (!strcmp(vm_instr->arg1, "that")) { - fprintf(fp, pop_indirect_boilerplate, THAT, arg2); + fprintf(fp, indirect_template, THAT, arg2, pop_boilerplate); } else if (!strcmp(vm_instr->arg1, "pointer")) { addr = POINTER + vm_instr->arg2; - fprintf(fp, pop_addr_boilerplate, addr); + fprintf(fp, addr_template, addr, pop_boilerplate); } else if (!strcmp(vm_instr->arg1, "temp")) { addr = TEMP + vm_instr->arg2; - fprintf(fp, pop_addr_boilerplate, addr); + fprintf(fp, addr_template, addr, pop_boilerplate); } else { err("error: invalid segment name \"%s\"\n", vm_instr->arg1);
M projects/07/src/vmtranslator.cprojects/07/src/vmtranslator.c

@@ -1,3 +1,4 @@

+#include <libgen.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h>

@@ -13,6 +14,33 @@

char *file_line; size_t file_line_no; + +bool set_static_symbol_name(char *filename) { + size_t i, filename_len, base_name_len; + char *tmp, *base_name; + + filename_len = strlen(filename); + tmp = malloc(filename_len + 1); + for (i = 0; i < filename_len; ++i) + tmp[i] = filename[i]; // copy filename (basename may modify arg) + + base_name = basename(tmp); + base_name_len = strlen(base_name); + static_sym_name = malloc(base_name_len + 1); + + for (i = 0; i < base_name_len && base_name[i] != '.'; ++i) { + if (!is_symbol_char(base_name[i])) { + err("found bad character '0x%hhx' in filename \"%s\"\n", + base_name[i], filename); + return false; + } + static_sym_name[i] = base_name[i]; + } + static_sym_name[i] = '\0'; + free(tmp); + return true; +} + // translate: iterate over lines in in_file, translate VM instructions to // assembly, write to out_file bool translate(FILE *in_file, FILE *out_file)

@@ -23,7 +51,7 @@ size_t i, line_len;

write_vm_init(out_file); for (i = 0; i < MAX_STATIC_SYMBOLS; ++i) - static_symbol_map[i] = -1; + static_symbol_map[i] = -1; // initialize symbol map table file_line_no = 0; //instruction_offset = 0; // TODO: unnecessary?

@@ -82,13 +110,16 @@ in_file = fopen(argv[1], "r"); // read input file

if (in_file == NULL) die("failed to open %s for reading\n", argv[1]); - if(!translate(in_file, out_file)) // first pass + if (!set_static_symbol_name(argv[1])) + die("error reading file name %s\n", argv[1]); + if (!translate(in_file, out_file)) // first pass die("failed to translate VM code in file\n"); if (fclose(in_file)) die("failed to close VM file\n"); if (fclose(out_file)) // TODO check if stdout die("failed to close assembly output file\n"); + free(static_sym_name); return 0; }