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

356 lines
9.4 KiB
C

/*
* CS 261 PA4: Mini-ELF interpreter
*
* Name: Nicholas Tamassia
*
* This code was developed in compliance with the JMU honor code
*/
#include "p4-interp.h"
/**********************************************************************
* REQUIRED FUNCTIONS
*********************************************************************/
bool cmov_cond(y86_t *cpu, y86_cmov_t ifun);
bool cmov_cond(y86_t *cpu, y86_cmov_t ifun) {
bool equals = cpu->zf;
bool less_than = cpu->sf != cpu->of;
switch (ifun) {
case RRMOVQ:
return true;
case CMOVLE:
return less_than || equals;
case CMOVL:
return less_than && !equals;
case CMOVE:
return equals;
case CMOVNE:
return !equals;
case CMOVGE:
return !less_than || equals;
case CMOVG:
return !less_than && !equals;
case BADCMOV:
default:
cpu->stat = INS;
return false;
}
}
int64_t OP(y86_t *cpu, y86_op_t ifun, int64_t valA, int64_t valB);
int64_t OP(y86_t *cpu, y86_op_t ifun, int64_t valA, int64_t valB) {
int64_t result = 0;
switch (ifun) {
case ADD:
result = valA + valB;
cpu->of = ((valA > 0 && valB > 0 && result < 0) ||
(valA < 0 && valB < 0 && result > 0));
break;
case SUB:
result = valB - valA;
cpu->of = ((valA < 0 && valB > 0 && result < 0) ||
(valA > 0 && valB < 0 && result > 0));
break;
case AND:
result = valA & valB;
cpu->of = false;
break;
case XOR:
result = valA ^ valB;
cpu->of = false;
break;
case BADOP:
default:
cpu->stat = INS;
return 0;
}
cpu->sf = result < 0;
cpu->zf = result == 0;
return result;
}
bool jmp_cond(y86_t *cpu, y86_jump_t ifun);
bool jmp_cond(y86_t *cpu, y86_jump_t ifun) {
bool equals = cpu->zf;
bool less_than = cpu->sf != cpu->of;
switch (ifun) {
case JMP:
return true;
case JLE:
return less_than || equals;
case JL:
return less_than && !equals;
case JE:
return equals;
case JNE:
return !equals;
case JGE:
return !less_than || equals;
case JG:
return !less_than && !equals;
case BADJUMP:
default:
cpu->stat = INS;
return false;
}
}
y86_reg_t decode_execute(y86_t *cpu, y86_inst_t *inst, bool *cnd,
y86_reg_t *valA) {
y86_reg_t valE = 0;
if (cpu == NULL) {
return valE;
}
if (inst == NULL || cnd == NULL || valA == NULL) {
cpu->stat = INS;
return valE;
}
switch (inst->icode) {
case HALT:
cpu->stat = HLT;
break;
case NOP:
break;
case CMOV:
*valA = cpu->reg[inst->ra];
valE = *valA;
*cnd = cmov_cond(cpu, inst->ifun.cmov);
break;
case IRMOVQ:
valE = inst->valC.v;
break;
case RMMOVQ:
*valA = cpu->reg[inst->ra];
valE = cpu->reg[inst->rb] + inst->valC.d;
break;
case MRMOVQ:
valE = cpu->reg[inst->rb] + inst->valC.d;
break;
case OPQ:
*valA = cpu->reg[inst->ra];
valE = OP(cpu, inst->ifun.op, *valA, cpu->reg[inst->rb]);
break;
case JUMP:
*cnd = jmp_cond(cpu, inst->ifun.jump);
break;
case CALL:
valE = cpu->reg[RSP] - 8;
break;
case PUSHQ:
*valA = cpu->reg[inst->ra];
valE = cpu->reg[RSP] - 8;
break;
case POPQ:
case RET:
*valA = cpu->reg[RSP];
valE = cpu->reg[RSP] + 8;
break;
case IOTRAP:
break;
case INVALID:
default:
cpu->stat = INS;
break;
}
return valE;
}
bool validate_address(y86_reg_t dest_address, size_t size, y86_t *cpu);
bool validate_address(y86_reg_t dest_address, size_t size, y86_t *cpu) {
bool valid = dest_address <= MEMSIZE - size;
if (!valid) {
cpu->stat = ADR;
}
return valid;
}
char buffer[100];
int buffer_offset = 0;
void iotrap(y86_t *cpu, y86_iotrap_t ifun, byte_t *memory);
void iotrap(y86_t *cpu, y86_iotrap_t ifun, byte_t *memory) {
int64_t dec = 0;
y86_reg_t rdi = cpu->reg[RDI];
y86_reg_t rsi = cpu->reg[RSI];
char *start = buffer + buffer_offset;
size_t space = sizeof(buffer) - buffer_offset;
switch (ifun) {
case CHAROUT:
if (validate_address(rsi, 1, cpu)) {
buffer[buffer_offset++] = memory[rsi];
}
break;
case CHARIN:
if (validate_address(rdi, 1, cpu) &&
scanf("%c", memory + rdi) <= 0) {
cpu->stat = HLT;
}
break;
case DECOUT:
if (validate_address(rsi, sizeof(dec), cpu)) {
memcpy(&dec, memory + rsi, sizeof(dec));
buffer_offset += snprintf(start, space, "%ld", dec);
}
break;
case DECIN:
if (!validate_address(rdi, sizeof(dec), cpu)) {
break;
}
if (scanf("%ld", &dec) <= 0) {
cpu->stat = HLT;
} else {
memcpy(memory + rdi, &dec, sizeof(dec));
}
break;
case STROUT:
if (validate_address(rsi, 1, cpu)) {
buffer_offset += snprintf(start, space, "%s", memory + rsi);
}
break;
case FLUSH:
printf("%s", buffer);
memset(buffer, 0, sizeof(buffer));
buffer_offset = 0;
break;
case BADTRAP:
default:
cpu->stat = INS;
break;
}
}
void memory_wb_pc(y86_t *cpu, y86_inst_t *inst, byte_t *memory, bool cnd,
y86_reg_t valA, y86_reg_t valE) {
if (cpu == NULL) {
return;
}
if (inst == NULL || memory == NULL) {
cpu->stat = INS;
return;
}
y86_reg_t *RA = &cpu->reg[inst->ra];
y86_reg_t *RB = &cpu->reg[inst->rb];
switch (inst->icode) {
case HALT:
case NOP:
cpu->pc = inst->valP;
break;
case CMOV:
if (cnd) {
*RB = valE;
}
cpu->pc = inst->valP;
break;
case IRMOVQ:
case OPQ:
*RB = valE;
cpu->pc = inst->valP;
break;
case RMMOVQ:
if (validate_address(valE, sizeof(valA), cpu)) {
memcpy(memory + valE, &valA, sizeof(valA));
}
cpu->pc = inst->valP;
break;
case MRMOVQ:
if (validate_address(valE, sizeof(*RA), cpu)) {
memcpy(RA, memory + valE, sizeof(*RA));
}
cpu->pc = inst->valP;
break;
case JUMP:
cpu->pc = cnd ? inst->valC.dest : inst->valP;
break;
case CALL:
if (validate_address(valE, sizeof(inst->valP), cpu)) {
memcpy(memory + valE, &inst->valP, sizeof(inst->valP));
cpu->reg[RSP] = valE;
}
cpu->pc = inst->valC.dest;
break;
case RET:
if (validate_address(valA, sizeof(cpu->pc), cpu)) {
memcpy(&cpu->pc, memory + valA, sizeof(cpu->pc));
cpu->reg[RSP] = valE;
}
break;
case PUSHQ:
if (validate_address(valE, sizeof(valA), cpu)) {
memcpy(memory + valE, &valA, sizeof(valA));
cpu->reg[RSP] = valE;
}
cpu->pc = inst->valP;
break;
case POPQ:
if (validate_address(valA, sizeof(*RA), cpu)) {
memcpy(RA, memory + valA, sizeof(*RA));
cpu->reg[RSP] = valE;
}
cpu->pc = inst->valP;
break;
case IOTRAP:
iotrap(cpu, inst->ifun.trap, memory);
cpu->pc = inst->valP;
break;
case INVALID:
default:
break;
}
}
/**********************************************************************
* OPTIONAL FUNCTIONS
*********************************************************************/
const char *registers[] = {"rax", "rcx", "rdx", "rbx", "rsp",
"rbp", "rsi", "rdi", "r8", "r9",
"r10", "r11", "r12", "r13", "r14"};
const char *status_codes[] = {"INVALID", "AOK", "HLT", "ADR", "INS"};
void dump_cpu_state(y86_t *cpu) {
printf("Y86 CPU state:\n");
char buffer[50];
snprintf(buffer, sizeof(buffer), "PC: %016lx", cpu->pc);
printf("%24s", buffer);
snprintf(buffer, sizeof(buffer), "flags: Z%d S%d O%d %3s", cpu->zf,
cpu->sf, cpu->of, status_codes[cpu->stat]);
printf(" %24s\n", buffer);
for (int i = 0; i < NUMREGS; i++) {
snprintf(buffer, sizeof(buffer), "%%%s: %016lx", registers[i],
cpu->reg[i]);
printf("%24s", buffer);
printf((i % 2 == 0 && i < NUMREGS - 1) ? " " : "\n");
}
}