Add decode and execute structure for DPI instructions w/ S

This commit is contained in:
Themis Demetriades 2024-06-05 20:11:56 +01:00
parent 8b0bb1888b
commit 024044afc7
2 changed files with 153 additions and 19 deletions

View File

@ -113,6 +113,9 @@ a64inst_instruction *decode(word wrd) {
switch(inst->data.DPRegisterData.DPROpType) {
case a64inst_DPR_ARITHMLOGIC:
if (arithmLogicData.type == a64inst_DPR_ARITHM && (arithmLogicData.negShiftedSrc2 || arithmLogicData.shiftType == a64inst_ROR)) {
fprintf(stderr, "Attempting to decode arithmetic DPR instruction with invalid format!\n");
}
arithmLogicData.shiftAmount = getBits(wrd, DP_REG_ARITHMLOGIC_SHIFTAMOUNT_LSB, DP_REG_ARITHMLOGIC_SHIFTAMOUNT_MSB);
break;
@ -121,7 +124,7 @@ a64inst_instruction *decode(word wrd) {
arithmLogicData.type == DP_REG_MULTIPLY_ARITHMFLAG &&
arithmLogicData.shiftType == DP_REG_MULTIPLY_SHIFTTYPE &&
arithmLogicData.negShiftedSrc2 == DP_REG_MULTIPLY_NEGSRC2FLAG)) {
fprintf(stderr, "Attempting to decode multiply instruction with invalid format!\n");
fprintf(stderr, "Attempting to decode multiply DPR instruction with invalid format!\n");
}
inst->data.DPRegisterData.processOpData.multiplydata.summand = getBits(wrd, DP_REG_MULTIPLY_SUMMAND_LSB, DP_REG_MULTIPLY_SUMMAND_MSB);
inst->data.DPRegisterData.processOpData.multiplydata.negProd = getBits(wrd, DP_REG_MULTIPLY_NEGPROD_LSB, DP_REG_MULTIPLY_NEGPROD_MSB);

View File

@ -25,11 +25,11 @@ static dword max(dword a, dword b) {
// Truncate a given value to the size of a word or dword depending on the register type
static dword truncateValue(dword value, a64inst_regType regType) {
if (regType == a64inst_R) {
if (regType == a64inst_X) {
return value;
} else {
//return value & ~(dword)((1 << WORD_BITS) - 1)
return value & (dword)(((dword)1 << WORD_BITS) - 1);
return (word)value;
//return value & (dword)(((dword)1 << WORD_BITS) - 1);
}
}
@ -67,35 +67,40 @@ static dword readRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regT
}
}
// TODO:
// Write to a processor register, ensuring that a valid register specifier is given
// and truncating the value being written when it can't fit in the specified register.
// and truncating the value being written when it can't fit in the specified register
static void writeRegister(Machine *state, a64inst_regSpecifier reg, a64inst_regType regType, dword value) {
assert(reg <= REGISTER_COUNT);
if (regType == a64inst_R) {
state->registers[reg] = truncateValue(value, regType);
} else {
*(word*)(state->registers + reg) = (word)truncateValue(value, regType);
}
state->registers[reg] = truncateValue(value, regType);
}
// Returns the position of the MSB of the given register type
inline static dword getMSBPos(a64inst_regType regType) {
return (regType ? DWORD_BITS : WORD_BITS) - 1;
}
// Returns the MSB of the given value assuming it's of the size stored in the given register type
inline static uint8_t getMSB(dword value, a64inst_regType regType) {
return value >> getMSBPos(regType);
}
// Updates N and Z condition codes given the machine and a result value
static void updateCondNZ(Machine *state, dword result, a64inst_regType regType) {
size_t msb = (regType ? DWORD_BITS : WORD_BITS) - 1;
state->conditionCodes.Negative = result >> msb;
state->conditionCodes.Negative = getMSB(result, regType);
state->conditionCodes.Zero = result == 0;
}
// Execute a data processing immediate instruction
static void executeDPImmediate(Machine *state, a64inst_instruction *inst) {
assert(inst->type == a64inst_DPIMMEDIATE);
a64inst_regType regType = inst->data.DPImmediateData.regType;
a64inst_regSpecifier dest = inst->data.DPImmediateData.dest;
switch(inst->data.DPImmediateData.DPIOpType) {
// Execute an arithmetic data processing instruction
// Execute an arithmetic immediate data processing instruction
case a64inst_DPI_ARITHM:;
// If shift flag is enabled, logical left shift by the number of bits specified by the architecture
@ -106,8 +111,8 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) {
}
switch(inst->data.DPImmediateData.processOp) {
dword result;
case(a64inst_ADDS):
result = srcVal + arithmImm;
writeRegister(state, dest, regType, result);
@ -131,6 +136,7 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) {
break;
case(a64inst_SUB):
printf("wag1\n");
writeRegister(state, dest, regType, srcVal - arithmImm);
break;
@ -141,7 +147,7 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) {
}
break;
// Execute a wide move data processing instruction
// Execute a wide move immediate data processing instruction
case a64inst_DPI_WIDEMOV:;
uint8_t shiftScalar = inst->data.DPImmediateData.processOpData.wideMovData.shiftScalar;
dword wideMovImm = inst->data.DPImmediateData.processOpData.wideMovData.immediate;
@ -173,6 +179,131 @@ static void executeDPImmediate(Machine *state, a64inst_instruction *inst) {
// Unknown instruction detected!
default:
fprintf(stderr, "Attempting to execute instruction with unknown DPI operand type!\n");
break;
}
}
// Execute a data processing register instruction
static void executeDPRegister(Machine *state, a64inst_instruction *inst) {
assert(inst->type == a64inst_DPREGISTER);
a64inst_regType regType = inst->data.DPRegisterData.regType;
a64inst_regSpecifier dest = inst->data.DPRegisterData.dest;
dword src1Val = readRegister(state, inst->data.DPRegisterData.src1, regType);
dword src2Val = readRegister(state, inst->data.DPRegisterData.src2, regType);
switch(inst->data.DPRegisterData.DPROpType) {
// Execute an arithmetic or logic register data processing instruction
case a64inst_DPR_ARITHMLOGIC:;
// Apply shift to value held in second register
a64inst_DPRegister_ArithmLogicData arithmLogicData = inst->data.DPRegisterData.processOpData.arithmLogicData;
uint8_t shiftAmount = arithmLogicData.shiftAmount;
switch(arithmLogicData.shiftType) {
case a64inst_LSL:
src2Val = truncateValue(src2Val << shiftAmount, regType);
break;
case a64inst_LSR:
src2Val = truncateValue(src2Val >> shiftAmount, regType);
break;
case a64inst_ASR:
src2Val = truncateValue((int64_t)src2Val >> shiftAmount, regType);
break;
case a64inst_ROR:
if (arithmLogicData.type != a64inst_DPR_LOGIC) {
fprintf(stderr, "Attempting to perform ROR shift on non-logic register data processing instruction!\n");
}
src2Val = truncateValue(src2Val >> shiftAmount | src2Val << (getMSBPos(regType) - shiftAmount), regType);
break;
default:
fprintf(stderr, "Attempting to execute arithmetic/logic register data processing instruction with invalid shift type!\n");
break;
}
dword result;
switch(arithmLogicData.type) {
case a64inst_DPR_ARITHM:
switch(inst->data.DPRegisterData.processOp) {
case(a64inst_ADDS):
result = src1Val + src2Val;
writeRegister(state, dest, regType, result);
updateCondNZ(state, result, regType);
state->conditionCodes.Overflow = max(src1Val, src2Val) > result;
state->conditionCodes.Carry = state->conditionCodes.Overflow;
break;
case(a64inst_ADD):
writeRegister(state, dest, regType, src1Val + src2Val);
break;
case(a64inst_SUBS):
result = src1Val - src2Val;
writeRegister(state, dest, regType, result);
updateCondNZ(state, result, regType);
state->conditionCodes.Overflow = src1Val < result;
state->conditionCodes.Carry = state->conditionCodes.Overflow;
break;
case(a64inst_SUB):
writeRegister(state, dest, regType, src1Val - src2Val);
break;
// Unknown opcode detected!
default:
fprintf(stderr, "Unknown opcode detected in a DPI arithmetic instruction!\n");
break;
}
break;
case a64inst_DPR_LOGIC:
switch(inst->data.DPRegisterData.processOp) {
case a64inst_AND:
writeRegister(state, dest, regType, src1Val & src2Val);
break;
case a64inst_OR:
writeRegister(state, dest, regType, src1Val | src2Val);
break;
case a64inst_XOR:
writeRegister(state, dest, regType, src1Val ^ src2Val);
break;
case a64inst_AND_FLAGGED:;
result = src1Val & src2Val;
writeRegister(state, dest, regType, result);
state->conditionCodes.Overflow = 0;
state->conditionCodes.Carry = 0;
updateCondNZ(state, result, regType);
break;
}
break;
default:
fprintf(stderr, "Attempting to execute an instruction with an unknown DPR arithmetic or logic subtype!\n");
break;
}
break;
// Execute a multiply register data processing instruction
case a64inst_DPR_MULTIPLY:
break;
// Unknown instruction detected!
default:
fprintf(stderr, "Attempting to execute instruction with unknown DPR operand type!\n");
break;
}
}
@ -197,7 +328,7 @@ void execute(Machine *state, a64inst_instruction *inst) {
// Execute a data processing register instruction
case a64inst_DPREGISTER:
readRegister(state, 0, 0); //FOR COMPILATION PURPOSES
executeDPRegister(state, inst);
break;
case a64inst_SINGLETRANSFER: