246 lines
6.5 KiB
C
246 lines
6.5 KiB
C
/*
|
|
* CS 261: Main driver
|
|
*
|
|
* Name: Nicholas Tamassia
|
|
*
|
|
* This code was developed in compliance with the JMU honor code
|
|
*/
|
|
|
|
#include "p1-check.h"
|
|
#include "p2-load.h"
|
|
#include "p3-disas.h"
|
|
#include "p4-interp.h"
|
|
|
|
/*
|
|
* helper function for printing help text
|
|
*/
|
|
void usage(char **argv) {
|
|
printf("Usage: %s <option(s)> mini-elf-file\n", argv[0]);
|
|
printf(" Options are:\n");
|
|
printf(" -h Display usage\n");
|
|
printf(" -H Show the Mini-ELF header\n");
|
|
printf(" -a Show all with brief memory\n");
|
|
printf(" -f Show all with full memory\n");
|
|
printf(" -s Show the program headers\n");
|
|
printf(" -m Show the memory contents (brief)\n");
|
|
printf(" -M Show the memory contents (full)\n");
|
|
printf(" -d Disassemble code contents\n");
|
|
printf(" -D Disassemble data contents\n");
|
|
printf(" -e Execute program\n");
|
|
printf(" -E Execute program (trace mode)\n");
|
|
}
|
|
|
|
void exit_file_error(FILE *file) {
|
|
if (file) {
|
|
fclose(file);
|
|
}
|
|
|
|
printf("Failed to read file\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
void execute_y86(y86_t *cpu, byte_t *memory, bool trace) {
|
|
bool cnd = false;
|
|
y86_reg_t valA = 0;
|
|
y86_reg_t valE = 0;
|
|
|
|
printf("Beginning execution at 0x%04lx\n", cpu->pc);
|
|
|
|
/* Dump initial state of cpu */
|
|
if (trace) {
|
|
dump_cpu_state(cpu);
|
|
}
|
|
|
|
int execution_count = 0;
|
|
|
|
while (cpu->stat == AOK) {
|
|
y86_inst_t inst = fetch(cpu, memory);
|
|
|
|
if (cpu->stat == ADR || cpu->stat == INS) {
|
|
if (trace) {
|
|
printf("\nInvalid instruction at 0x%04lx\n", cpu->pc);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (trace) {
|
|
printf("\nExecuting: ");
|
|
disassemble(&inst);
|
|
printf("\n");
|
|
}
|
|
|
|
valE = decode_execute(cpu, &inst, &cnd, &valA);
|
|
memory_wb_pc(cpu, &inst, memory, cnd, valA, valE);
|
|
|
|
if (inst.icode == IOTRAP && cpu->stat == HLT) {
|
|
printf("I/O Error\n");
|
|
}
|
|
|
|
if (trace && cpu->stat == AOK) {
|
|
dump_cpu_state(cpu);
|
|
}
|
|
|
|
execution_count++;
|
|
}
|
|
|
|
/* Final state of the cpu */
|
|
dump_cpu_state(cpu);
|
|
|
|
printf("Total execution count: %d\n", execution_count);
|
|
|
|
if (trace) {
|
|
printf("\n");
|
|
dump_memory(memory, 0, MEMSIZE);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
int c;
|
|
bool show_elf_header = false;
|
|
bool show_program_header = false;
|
|
bool show_memory_brief = false;
|
|
bool show_memory_full = false;
|
|
bool show_code = false;
|
|
bool show_data = false;
|
|
bool execute_default = false;
|
|
bool execute_trace = false;
|
|
|
|
while ((c = getopt(argc, argv, "hHafsmMdDeE")) != -1) {
|
|
switch (c) {
|
|
case 'h':
|
|
usage(argv);
|
|
return EXIT_SUCCESS;
|
|
case 'H':
|
|
show_elf_header = true;
|
|
break;
|
|
case 'a':
|
|
show_elf_header = true;
|
|
show_program_header = true;
|
|
show_memory_brief = true;
|
|
break;
|
|
case 'f':
|
|
show_elf_header = true;
|
|
show_program_header = true;
|
|
show_memory_full = true;
|
|
break;
|
|
case 's':
|
|
show_program_header = true;
|
|
break;
|
|
case 'm':
|
|
show_memory_brief = true;
|
|
break;
|
|
case 'M':
|
|
show_memory_full = true;
|
|
break;
|
|
case 'd':
|
|
show_code = true;
|
|
break;
|
|
case 'D':
|
|
show_data = true;
|
|
break;
|
|
case 'e':
|
|
execute_default = true;
|
|
break;
|
|
case 'E':
|
|
execute_trace = true;
|
|
break;
|
|
default:
|
|
usage(argv);
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
|
|
/* File path was not the last argument */
|
|
bool invalid_arguments = optind != argc - 1;
|
|
/* Attempted to ask for brief and full memory at same time */
|
|
bool memory_flag_conflict = show_memory_brief && show_memory_full;
|
|
/* Attempted to execute program in both default and trace mode */
|
|
bool execute_flag_conflict = execute_default && execute_trace;
|
|
|
|
if (invalid_arguments || memory_flag_conflict || execute_flag_conflict) {
|
|
usage(argv);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
elf_hdr_t header = {0};
|
|
FILE *header_file = fopen(argv[optind], "r");
|
|
|
|
/* Read contents of header_file into header */
|
|
if (!read_header(header_file, &header)) {
|
|
exit_file_error(header_file);
|
|
}
|
|
|
|
if (show_elf_header) {
|
|
dump_header(&header);
|
|
}
|
|
|
|
elf_phdr_t phdrs[header.e_num_phdr];
|
|
memset(phdrs, 0, sizeof(phdrs));
|
|
|
|
/* Read program headers into phdrs array */
|
|
for (int i = 0; i < header.e_num_phdr; i++) {
|
|
uint16_t offset = header.e_phdr_start + i * sizeof(elf_phdr_t);
|
|
if (!read_phdr(header_file, offset, &phdrs[i])) {
|
|
exit_file_error(header_file);
|
|
}
|
|
}
|
|
|
|
if (show_program_header) {
|
|
dump_phdrs(header.e_num_phdr, phdrs);
|
|
}
|
|
|
|
byte_t memory[MEMSIZE];
|
|
memset(memory, 0, MEMSIZE);
|
|
|
|
/* Read memory segments into memory array */
|
|
for (int i = 0; i < header.e_num_phdr; i++) {
|
|
if (!load_segment(header_file, memory, &phdrs[i])) {
|
|
exit_file_error(header_file);
|
|
}
|
|
}
|
|
|
|
fclose(header_file);
|
|
|
|
if (show_memory_brief) {
|
|
for (int i = 0; i < header.e_num_phdr; i++) {
|
|
uint32_t start = phdrs[i].p_vaddr;
|
|
uint32_t end = start + phdrs[i].p_size;
|
|
|
|
dump_memory(memory, start, end);
|
|
}
|
|
} else if (show_memory_full) {
|
|
dump_memory(memory, 0, MEMSIZE);
|
|
}
|
|
|
|
if (show_code) {
|
|
printf("Disassembly of executable contents:\n");
|
|
|
|
for (int i = 0; i < header.e_num_phdr; i++) {
|
|
if (phdrs[i].p_type == CODE) {
|
|
disassemble_code(memory, &phdrs[i], &header);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (show_data) {
|
|
printf("Disassembly of data contents:\n");
|
|
|
|
for (int i = 0; i < header.e_num_phdr; i++) {
|
|
if (phdrs[i].p_type == DATA && phdrs[i].p_flags == 4) {
|
|
disassemble_rodata(memory, &phdrs[i]);
|
|
} else if (phdrs[i].p_type == DATA) {
|
|
disassemble_data(memory, &phdrs[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (execute_default || execute_trace) {
|
|
y86_t cpu = {0};
|
|
cpu.stat = AOK;
|
|
cpu.pc = header.e_entry;
|
|
|
|
execute_y86(&cpu, memory, execute_trace);
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
} |