diff --git a/src/execute.c b/src/execute.c index 4e0f608..b5ad72a 100644 --- a/src/execute.c +++ b/src/execute.c @@ -11,6 +11,7 @@ // Prototypes void execute_SDT(Machine *state, a64inst_instruction *inst); +void execute_Branch(Machine *state, a64inst_instruction *inst); // Return maximum of two dwords static dword max(dword a, dword b) { @@ -27,6 +28,28 @@ static dword truncateValue(dword value, a64inst_regType regType) { } } +// Sign extend a given value to a 64-bit signed integer given the number of bits +static int64_t signExtend(dword value, unsigned int n) { + if (n == 0 || n >= 64) { + // If n_bits is 0 or greater than or equal to 64, return the value as is + return (int64_t)value; + } + + uint64_t sign_bit_mask = (uint64_t)1 << (n - 1); + + // Mask to isolate the n-bit value + uint64_t n_bit_mask = (sign_bit_mask << 1) - 1; + + // Check if the sign bit is set + if (value & sign_bit_mask) { + // Sign bit is set, extend the sign + return (int64_t)(value | ~n_bit_mask); + } else { + // Sign bit is not set, return the value as is + return (int64_t)(value & n_bit_mask); + } +} + // Read from processor register, ensuring that a valid register specifier is given // and accounting for the case where the zero register is accessed. Truncate // the 32 most significant bits stored in the R register when reading W register. @@ -131,6 +154,7 @@ void execute(Machine *state, a64inst_instruction *inst) { // Execute a branch instruction case a64inst_BRANCH: + execute_Branch(state, inst); break; // Execute a data processing register instruction @@ -193,4 +217,41 @@ void execute_SDT(Machine *state, a64inst_instruction *inst) { } } -} \ No newline at end of file +} + +static bool isConditionMet(Machine* state, a64inst_ConditionType cond) { + switch(cond) { + case EQ: + return state->conditionCodes.Zero; + case NE: + return !state->conditionCodes.Zero; + case GE: + return state->conditionCodes.Negative == state->conditionCodes.Overflow; + case LT: + return state->conditionCodes.Negative != state->conditionCodes.Overflow; + case GT: + return !state->conditionCodes.Zero && (state->conditionCodes.Negative == state->conditionCodes.Overflow); + case LE: + return state->conditionCodes.Zero || (state->conditionCodes.Negative != state->conditionCodes.Overflow); + case AL: + return true; + } +} + +void execute_Branch(Machine *state, a64inst_instruction *inst) { + switch (inst->data.BranchData.BranchType) { + case a64inst_UNCONDITIONAL: + state->pc += signExtend(inst->data.BranchData.processOpData.unconditionalData.unconditionalOffset * 4, 26); + break; + + case a64inst_REGISTER: + state->pc = state->registers[inst->data.BranchData.processOpData.registerData.src]; + break; + + case a64inst_CONDITIONAL: + if (isConditionMet(state, inst->data.BranchData.processOpData.conditionalData.cond)) { + state->pc += signExtend(inst->data.BranchData.processOpData.conditionalData.offset * 4, 19); + } + break; + } +}