356 lines
9.4 KiB
C
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");
|
|
}
|
|
}
|