X-Git-Url: http://git.subgeniuskitty.com/ned1/.git/blobdiff_plain/bc5b63cf94c1f263bbe3757237b242f40711203b..dc87d2445f5e13146058bd672ad8399fad9e73fb:/nedasm/nedasm_codegen.c diff --git a/nedasm/nedasm_codegen.c b/nedasm/nedasm_codegen.c index 9484a1d..ddfd792 100644 --- a/nedasm/nedasm_codegen.c +++ b/nedasm/nedasm_codegen.c @@ -6,30 +6,140 @@ #include #include #include +#include #include "nedasm_structures.h" +#include "nedasm_misc.h" +#include "../common/a.out.h" void -write_word_to_file(uint32_t * word, FILE * file) +write_aout_exec_header(FILE * output, struct exec * aout_exec) { - fwrite(word, 4, 1, file); + uint32_t write_count = 0; + for (uint32_t i=0; i<8; i++) { + switch (i) { + case 0: write_count = fwrite(&(aout_exec->a_midmag), 4, 1, output); break; + case 1: write_count = fwrite(&(aout_exec->a_text), 4, 1, output); break; + case 2: write_count = fwrite(&(aout_exec->a_data), 4, 1, output); break; + case 3: write_count = fwrite(&(aout_exec->a_bss), 4, 1, output); break; + case 4: write_count = fwrite(&(aout_exec->a_syms), 4, 1, output); break; + case 5: write_count = fwrite(&(aout_exec->a_entry), 4, 1, output); break; + case 6: write_count = fwrite(&(aout_exec->a_trsize), 4, 1, output); break; + case 7: write_count = fwrite(&(aout_exec->a_drsize), 4, 1, output); break; + } + if (write_count != 1) { + fprintf(stderr, "ERROR: Failed to write aout header.\n"); + exit(EXIT_FAILURE); + } + } +} + +void +write_aout_text_segment(FILE * output, uint32_t * text_segment) +{ + for (uint32_t i=1; i <= text_segment[0]; i++) { + uint32_t write_count = fwrite(&(text_segment[i]), 4, 1, output); + if (write_count != 1) { + fprintf(stderr, "ERROR: Failed to write text segment.\n"); + exit(EXIT_FAILURE); + } + } +} + +void +write_aout_symbol_table(FILE * output, struct nlist * symbol_table, uint32_t symbol_count) +{ + uint32_t write_count = 0; + for (uint32_t i=0; i < symbol_count; i++) { + for (uint32_t j=0; j<5; j++) { + switch (j) { + case 0: write_count = fwrite(&(symbol_table[i].n_un.n_strx), 4, 1, output); break; + case 1: write_count = fwrite(&(symbol_table[i].n_type), 4, 1, output); break; + case 2: write_count = fwrite(&(symbol_table[i].n_other), 4, 1, output); break; + case 3: write_count = fwrite(&(symbol_table[i].n_desc), 4, 1, output); break; + case 4: write_count = fwrite(&(symbol_table[i].n_value), 4, 1, output); break; + } + if (write_count != 1) { + fprintf(stderr, "ERROR: Failed to write symbol table.\n"); + exit(EXIT_FAILURE); + } + } + } +} + +void +write_aout_string_table(FILE * output, char * string_table, uint32_t string_table_size) +{ + uint32_t write_count = fwrite(&string_table_size, 4, 1, output); + if (write_count != 1) { + fprintf(stderr, "ERROR: Failed to write string table size.\n"); + exit(EXIT_FAILURE); + } + for (uint32_t i=0; i < string_table_size; i++) { + write_count = fwrite(&(string_table[i]), 1, 1, output); + if (write_count != 1) { + fprintf(stderr, "ERROR: Failed to write string table.\n"); + exit(EXIT_FAILURE); + } + } } void -pad_word_boundary(uint8_t * syllable_count, uint32_t * word, FILE * output) +generate_aout(FILE * output, uint32_t * text_segment, + struct nlist * symbol_table, uint32_t symbol_count) +{ + struct exec aout_exec; + N_SETMAGIC(aout_exec, NED_MAGIC1, MID_NED, 0); + aout_exec.a_text = (4 * text_segment[0]); /* 4 bytes per word. */ + aout_exec.a_data = 0; + aout_exec.a_bss = 0; + aout_exec.a_syms = (20 * symbol_count); /* 20 = 5x 32-bit values from nlist struct. */ + aout_exec.a_entry = MEM_BEGIN; + aout_exec.a_trsize = 0; + aout_exec.a_drsize = 0; + write_aout_exec_header(output, &aout_exec); + + write_aout_text_segment(output,text_segment); + + uint32_t string_table_size = 0; + for (uint32_t i = 0; i < symbol_count; i++) { + string_table_size += (strnlen(symbol_table[i].n_un.n_name, MAX_LABEL_LEN) + 1); + } + char * string_table = malloc(string_table_size); + uint32_t string_table_offset = 0; + for (uint32_t i = 0; i < symbol_count; i++) { + uint32_t len = (strnlen(symbol_table[i].n_un.n_name, MAX_LABEL_LEN) + 1); + strncpy(string_table+string_table_offset, symbol_table[i].n_un.n_name, len); + symbol_table[i].n_un.n_strx = string_table_offset; + string_table_offset += len; + } + + write_aout_symbol_table(output, symbol_table, symbol_count); + + write_aout_string_table(output, string_table, string_table_size); +} + +void +write_word_to_text_segment(uint32_t * word, uint32_t * text_seg) +{ + text_seg[(++text_seg[0])] = *word; +} + +void +pad_word_boundary(uint8_t * syllable_count, uint32_t * word, uint32_t * text_seg) { if (*syllable_count > 0) { while (*syllable_count <= 4) { *word |= 0b000001 << 6 * (4 - (*syllable_count)++); } - write_word_to_file(word, output); + write_word_to_text_segment(word, text_seg); *syllable_count = 0; *word = 0; } } void -generate_code_WORD(struct instruction * instructions, FILE * output) +generate_code_WORD(struct instruction * instructions, uint32_t * text_seg) { /* Set the instruction format to Type A. */ uint32_t temp_word = 0b10000000000000000000000000000000; @@ -49,12 +159,11 @@ generate_code_WORD(struct instruction * instructions, FILE * output) /* Set the data portion of the instruction. */ temp_word |= instructions->data >> 1; - /* Write to disk. */ - write_word_to_file(&temp_word, output); + write_word_to_text_segment(&temp_word, text_seg); } void -generate_code_IM(struct instruction * instructions, FILE * output, +generate_code_IM(struct instruction * instructions, uint8_t * syllable_count, uint32_t * temp_word) { uint8_t temp_syllable = 0b00100000; @@ -68,7 +177,7 @@ generate_code_IM(struct instruction * instructions, FILE * output, } void -generate_code_LDSP(struct instruction * instructions, FILE * output, +generate_code_LDSP(struct instruction * instructions, uint8_t * syllable_count, uint32_t * temp_word) { uint8_t temp_syllable = 0b00011000; @@ -82,7 +191,7 @@ generate_code_LDSP(struct instruction * instructions, FILE * output, } void -generate_code_STSP(struct instruction * instructions, FILE * output, +generate_code_STSP(struct instruction * instructions, uint8_t * syllable_count, uint32_t * temp_word) { uint8_t temp_syllable = 0b00010000; @@ -95,12 +204,35 @@ generate_code_STSP(struct instruction * instructions, FILE * output, *temp_word |= temp_syllable << 6 * (4 - *syllable_count); } +void +generate_label(struct instruction * instructions, struct nlist * symbol_table, uint32_t index) +{ + symbol_table[index].n_un.n_name = instructions->label; + symbol_table[index].n_type = N_ABS; + symbol_table[index].n_other = AUX_FUNC; + symbol_table[index].n_desc = 0; + while (instructions->syllable == LABEL) instructions = instructions->next; + symbol_table[index].n_value = instructions->address; +} + void generate_code(struct instruction * instructions, FILE * output) { + uint32_t label_count = 0; + uint32_t max_word_count = 0; + struct instruction * temp = seek_instruction_list_start(instructions); + while (temp != NULL) { + (temp->syllable == LABEL) ? (label_count++) : (max_word_count++); + temp = temp->next; + } + /* +1 to store the number of entries as the first element of the array. */ + uint32_t * text_segment = malloc((max_word_count * sizeof(uint32_t)) + 1); + struct nlist * symbol_table = malloc(label_count * sizeof(struct nlist)); + uint8_t syllable_count = 0; uint32_t temp_word = 0; + label_count = 0; instructions = seek_instruction_list_start(instructions); while (instructions != NULL) { /* If starting a new word, zero the word, setting it to Type C by default. */ @@ -109,17 +241,17 @@ generate_code(struct instruction * instructions, FILE * output) switch (instructions->syllable) { case WORD: /* Must pad partial word w/NOPs & write to disk before starting new WORD. */ - pad_word_boundary(&syllable_count, &temp_word, output); - generate_code_WORD(instructions, output); + pad_word_boundary(&syllable_count, &temp_word, text_segment); + generate_code_WORD(instructions, text_segment); break; case IM: - generate_code_IM(instructions, output, &syllable_count, &temp_word); + generate_code_IM(instructions, &syllable_count, &temp_word); break; case LDSP: - generate_code_LDSP(instructions, output, &syllable_count, &temp_word); + generate_code_LDSP(instructions, &syllable_count, &temp_word); break; case STSP: - generate_code_STSP(instructions, output, &syllable_count, &temp_word); + generate_code_STSP(instructions, &syllable_count, &temp_word); break; case MVSTCK: temp_word |= 0b001111 << 6 * (4 - syllable_count); break; case ADD: temp_word |= 0b001100 << 6 * (4 - syllable_count); break; @@ -137,18 +269,27 @@ generate_code(struct instruction * instructions, FILE * output) case HALT: temp_word |= 0b000000 << 6 * (4 - syllable_count); break; case SWAP: temp_word |= 0b001101 << 6 * (4 - syllable_count); break; case JMP: temp_word |= 0b001110 << 6 * (4 - syllable_count); break; + case LABEL: + generate_label(instructions, symbol_table, label_count); + label_count++; + break; default: fprintf(stderr, "ERROR: Unassigned syllable on line %u.\n", instructions->linenum); break; } - if (syllable_count == 4) write_word_to_file(&temp_word, output); + if (syllable_count == 4) write_word_to_text_segment(&temp_word, text_segment); - if (instructions->syllable != WORD) syllable_count = (syllable_count + 1) % 5; + if (instructions->syllable != WORD && instructions->syllable != LABEL) { + syllable_count = (syllable_count + 1) % 5; + } instructions = instructions->next; } /* If necessary, pad incomplete word with NOPs. */ - pad_word_boundary(&syllable_count, &temp_word, output); + pad_word_boundary(&syllable_count, &temp_word, text_segment); + + /* Write to disk */ + generate_aout(output, text_segment, symbol_table, label_count); }