Files
2025-10-06 00:14:04 -04:00

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;
}