* © 2018 Aaron Taylor <ataylor at subgeniuskitty dot com>
* See LICENSE.txt file for copyright and license details.
#include "nedasm_structures.h"
#include "../common/a.out.h"
write_aout_exec_header(FILE * output
, struct exec
* aout_exec
)
uint32_t write_count
= 0;
for (uint32_t i
=0; i
<8; 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;
fprintf(stderr
, "ERROR: Failed to write aout header.\n");
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
);
fprintf(stderr
, "ERROR: Failed to write text segment.\n");
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
++) {
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;
fprintf(stderr
, "ERROR: Failed to write symbol table.\n");
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
);
fprintf(stderr
, "ERROR: Failed to write string table size.\n");
for (uint32_t i
=0; i
< string_table_size
; i
++) {
write_count
= fwrite(&(string_table
[i
]), 1, 1, output
);
fprintf(stderr
, "ERROR: Failed to write string table.\n");
generate_aout(FILE * output
, uint32_t * text_segment
,
struct nlist
* symbol_table
, uint32_t symbol_count
)
N_SETMAGIC(aout_exec
, NED_MAGIC1
, MID_NED
, 0);
aout_exec
.a_text
= (4 * text_segment
[0]); /* 4 bytes per word. */
aout_exec
.a_syms
= (20 * symbol_count
); /* 20 = 5x 32-bit values from nlist struct. */
aout_exec
.a_entry
= MEM_BEGIN
;
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
);
write_word_to_text_segment(uint32_t * word
, uint32_t * text_seg
)
text_seg
[(++text_seg
[0])] = *word
;
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_text_segment(word
, text_seg
);
generate_code_WORD(struct instruction
* instructions
, uint32_t * text_seg
)
/* Set the instruction format to Type A. */
uint32_t temp_word
= 0b10000000000000000000000000000000;
/* Since x in WORD_x will be shifted left by one position, check for validity. */
if (instructions
->data
% 2 != 0) {
fprintf(stderr
, "ERROR: Unable to use odd value with WORD on line %d.\n",
if (instructions
->data
> 0b01111111111111111111111111111111) {
fprintf(stderr
, "ERROR: Value too large for WORD on line %d.\n",
/* Set the data portion of the instruction. */
temp_word
|= instructions
->data
>> 1;
write_word_to_text_segment(&temp_word
, text_seg
);
generate_code_IM(struct instruction
* instructions
,
uint8_t * syllable_count
, uint32_t * temp_word
)
uint8_t temp_syllable
= 0b00100000;
if (instructions
->data
> 0b11111) {
fprintf(stderr
, "ERROR: Value too large for IM on line %d.\n",
temp_syllable
|= instructions
->data
;
*temp_word
|= temp_syllable
<< 6 * (4 - *syllable_count
);
generate_code_LDSP(struct instruction
* instructions
,
uint8_t * syllable_count
, uint32_t * temp_word
)
uint8_t temp_syllable
= 0b00011000;
if (instructions
->data
> 0b111) {
fprintf(stderr
, "ERROR: Value too large for LDSP on line %d.\n",
temp_syllable
|= instructions
->data
;
*temp_word
|= temp_syllable
<< 6 * (4 - *syllable_count
);
generate_code_STSP(struct instruction
* instructions
,
uint8_t * syllable_count
, uint32_t * temp_word
)
uint8_t temp_syllable
= 0b00010000;
if (instructions
->data
> 0b111) {
fprintf(stderr
, "ERROR: Value too large for STSP on line %d.\n",
temp_syllable
|= instructions
->data
;
*temp_word
|= temp_syllable
<< 6 * (4 - *syllable_count
);
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
;
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
);
(temp
->syllable
== LABEL
) ? (label_count
++) : (max_word_count
++);
/* +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;
instructions
= seek_instruction_list_start(instructions
);
while (instructions
!= NULL
) {
/* If starting a new word, zero the word, setting it to Type C by default. */
if (syllable_count
== 0) temp_word
= 0b00000000000000000000000000000000;
switch (instructions
->syllable
) {
/* Must pad partial word w/NOPs & write to disk before starting new WORD. */
pad_word_boundary(&syllable_count
, &temp_word
, text_segment
);
generate_code_WORD(instructions
, text_segment
);
generate_code_IM(instructions
, &syllable_count
, &temp_word
);
generate_code_LDSP(instructions
, &syllable_count
, &temp_word
);
generate_code_STSP(instructions
, &syllable_count
, &temp_word
);
case MVSTCK
: temp_word
|= 0b001111 << 6 * (4 - syllable_count
); break;
case ADD
: temp_word
|= 0b001100 << 6 * (4 - syllable_count
); break;
case XOR
: temp_word
|= 0b001011 << 6 * (4 - syllable_count
); break;
case NOT
: temp_word
|= 0b001010 << 6 * (4 - syllable_count
); break;
case OR
: temp_word
|= 0b001001 << 6 * (4 - syllable_count
); break;
case AND
: temp_word
|= 0b001000 << 6 * (4 - syllable_count
); break;
case BRZ
: temp_word
|= 0b000111 << 6 * (4 - syllable_count
); break;
case TEST
: temp_word
|= 0b000110 << 6 * (4 - syllable_count
); break;
case CMPSWP
: temp_word
|= 0b000101 << 6 * (4 - syllable_count
); break;
case SHIFT
: temp_word
|= 0b000100 << 6 * (4 - syllable_count
); break;
case STORE
: temp_word
|= 0b000011 << 6 * (4 - syllable_count
); break;
case LOAD
: temp_word
|= 0b000010 << 6 * (4 - syllable_count
); break;
case NOP
: temp_word
|= 0b000001 << 6 * (4 - syllable_count
); break;
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;
generate_label(instructions
, symbol_table
, label_count
);
fprintf(stderr
, "ERROR: Unassigned syllable on line %u.\n", instructions
->linenum
);
if (syllable_count
== 4) write_word_to_text_segment(&temp_word
, text_segment
);
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
, text_segment
);
generate_aout(output
, text_segment
, symbol_table
, label_count
);