/* register.c */ #include "project.h" #include #include /* List of all registers */ static reg_t regs[] = { /* Normal register set */ {"zero", 0x0, R_NORMAL, 0}, { "xw", 0x1, R_NORMAL, 0}, { "yw", 0x2, R_NORMAL, 0}, { "zw", 0x3, R_NORMAL, 0}, { "r0", 0x4, R_NORMAL, 0}, { "r1", 0x5, R_NORMAL, 0}, { "r2", 0x6, R_NORMAL, 0}, { "r3", 0x7, R_NORMAL, 0}, { "r4", 0x8, R_NORMAL, 0}, { "r5", 0x9, R_NORMAL, 0}, { "r6", 0xa, R_NORMAL, 0}, { "r7", 0xb, R_NORMAL, 0}, { "c0", 0xc, R_NORMAL, 0}, { "c1", 0xd, R_NORMAL, 0}, { "cf", 0xe, R_NORMAL, 0}, { "pc", 0xf, R_NORMAL, 0}, /* BCD register set */ { "u0", 0x0, R_BCD, 0}, { "u1", 0x1, R_BCD, 0}, { "u2", 0x2, R_BCD, 0}, { "u3", 0x3, R_BCD, 0}, { "u4", 0x4, R_BCD, 0}, { "u5", 0x5, R_BCD, 0}, { "u6", 0x6, R_BCD, 0}, { "u7", 0x7, R_BCD, 0}, { "v0", 0x8, R_BCD, 0}, { "v1", 0x9, R_BCD, 0}, { "v2", 0xa, R_BCD, 0}, { "v3", 0xb, R_BCD, 0}, { "v4", 0xc, R_BCD, 0}, { "v5", 0xd, R_BCD, 0}, { "v6", 0xe, R_BCD, 0}, { "v7", 0xf, R_BCD, 0}, /* Pseudoregister set */ { "u", 0x0, R_PSEUDO, 0}, { "uh", 0x1, R_PSEUDO, 0}, { "ul", 0x2, R_PSEUDO, 0}, { "v", 0x3, R_PSEUDO, 0}, { "vh", 0x4, R_PSEUDO, 0}, { "vl", 0x5, R_PSEUDO, 0}, /* End of list */ { NULL } }; /* Given the name of a register, returns its reg_t*. */ reg_t* reg_by_name(char* name) { reg_t* p = regs; while (p->name != NULL && strcmp(p->name, name) != 0) p++; if (p->name == NULL) return NULL; return p; } /* Given the code and type of a register, returns its reg_t*. */ reg_t* reg_by_code(unsigned code, reg_type_t type) { reg_t* p = regs; while (p->name != NULL && (p->code != code || p->type != type)) p++; if (p->name == NULL) return NULL; return p; } /* Returns the value of a register. */ unsigned reg_read(reg_t* reg) { switch (reg->type) { case R_NORMAL: case R_BCD: return reg->val; case R_PSEUDO: die("Cannot directly read pseudoregisters\n"); } } /* Sets the value of a register. */ void reg_write(reg_t* reg, unsigned val) { switch (reg->type) { case R_NORMAL: reg->val = val & 0xffffffff; break; case R_BCD: reg->val = val & 0x0000000f; break; case R_PSEUDO: die("Cannot directly modify pseudoregisters\n"); } } /* Initializes all registers from values embedded in the memory image. */ void reg_initialize(void) { int i, j; reg_type_t type; reg_t* reg; label_t* label; char* buf = NULL; int buf_len = 0; unsigned val; /* Perform this step for both the normal and BCD register sets */ for (j = 0; j < 2; j++) { /* Determine what register set to work with */ switch (j) { case 0: label = label_by_name(".nreg"); type = R_NORMAL; break; case 1: label = label_by_name(".breg"); type = R_BCD; } /* Set initial value for entire register set */ val = label != NULL ? mem_read(label->addr) : 0xdeadbeef; for (i = 0; i < 16; i++) { reg = reg_by_code(i, type); if (reg == NULL) continue; reg_write(reg, val); } /* Set initial value for individual registers */ for (i = 0; i < 16; i++) { int reg_name_len; /* Get register */ reg = reg_by_code(i, type); if (reg == NULL) continue; /* Get label name */ reg_name_len = strlen(reg->name); if (reg_name_len + 2 > buf_len) { buf_len = reg_name_len + 2; buf = realloc(buf, buf_len); if (buf == NULL) die("Out of memory\n"); } buf[0] = '.'; memcpy(buf + 1, reg->name, reg_name_len + 1); /* Get label */ label = label_by_name(buf); if (label == NULL) continue; /* Set register value */ reg_write(reg, mem_read(label->addr)); } } /* No memory leaks, please */ free(buf); } /* EOF */