private int nextInst()
{
//bit of background stuff
//r0 is always locked to 0
register[0] = 0;
//time the instruction took to complete
int executionTime = 0;
//divides the instruction in usable parts
UInt32 instruction = memory.instructionLoad(pc, out executionTime);
long inst = (instruction & 0xfc000000) >> 26;//why do I have to declare this long?!?
//get immediate bit
long immed = inst >> 3;
immed = immed & 1;
//get instruction type bits
long type = inst >> 4;
inst = inst & 7;
long regA = (instruction & 0x03e00000) >> 21;
long regB = (instruction & 0x001f0000) >> 16;
UInt16 address = (UInt16)(instruction & 0x0000ffff);
long regC = (address & 0x001f);
Int32 valA = register[regA];
Int32 valB = register[regB];
Int32 valC = register[regC];
if (immed != 0) {
valC = address;
}
++pc;
UInt64 exTmp;
Int32 exTimeTMP;
int tmp = 0;
if (type == 0) { //arithmetic
switch (inst) {
case 0://Add
exTmp = ((UInt64)valB & 0xffffffff) + ((UInt64)valC & 0xffffffff);//apparently, C# does the sign-extendy thing even when casting to ulong
register[exreg] = (Int32)(exTmp >> 32);
register[regA] = (Int32)exTmp;
break;
case 1://Sub
exTmp = ((UInt64)valB & 0xffffffff) + ((UInt64)(-valC) & 0xffffffff);
register[exreg] = (Int32)(exTmp >> 32);
register[regA] = (Int32)exTmp;
break;
case 2://Mul
exTmp = ((UInt64)valB & 0xffffffff) * ((UInt64)valC & 0xffffffff);
register[exreg] = (Int32)(exTmp >> 32);
register[regA] = (Int32)exTmp;
executionTime += 9;
break;
case 3://Div
if (valC == 0) {
//illegalInstructionInterrupt
interruptsPending.Enqueue(258);//change to dividebyzerointerrupt when available
register[regA] = -1;
register[exreg] = -1;
break;
}
register[exreg] = valB - (valB / valC) * valC;//this is equal to valB % valC on most systems.
register[regA] = valB / valC;
executionTime += 39;
break;
case 4://And
register[regA] = valB & valC;
break;
case 5://Or
register[regA] = valB | valC;
break;
case 6://Xor
register[regA] = valB ^ valC;
break;
case 7://Not
register[regC] = valC ^ -1;
break;
}
} else if (type == 1) { //extended arithmetic
switch (inst) {
case 0://Flcmp
float f1 = Util.itof(valB);
float f2 = Util.itof(valC);
if (f1 < f2) {
register[regA] = -1;
} else if (f1 > f2) {
register[regA] = 1;
} else {
register[regA] = 0;
}
break;
case 1://Sr
if (valC != 0) {
register[exreg] = valB << 32 - (valC & 0x1f);
} else {
register[exreg] = 0;
}
register[regA] = (Int32)((UInt32)valB >> (valC & 0x1f));//logical right shift
break;
case 2://Sl
if (valC != 0) {
register[exreg] = (Int32)((UInt32)valB >> (32 - valC & 0x3f));
} else {
register[exreg] = 0;
}
register[regA] = valB << (valC & 0x3f);
break;
case 3://Sra
if (valC != 0) {
register[exreg] = valB << 32 - (valC & 0x1f);
} else {
register[exreg] = 0;
}
register[regA] = valB >> (valC & 0x1f);//arithmetic right shift
break;
case 4://Sx
spawnException(258);
break;
case 5://Float
tmp = floatInst(address, regA);
if (tmp == -1) {
return tmp;
} else {
executionTime += tmp;
}
break;
case 6://Extnd
tmp = extndInst(address, (Int32)regA, (Int32)regB, (Int32)regC, valA, valB, valC, immed != 0);
if (tmp == -1) {
return tmp;
} else {
executionTime += tmp;
}
break;
case 7://Cmp
if (valB < valC) {
register[regA] = -1;
} else if (valB == valC) {
register[regA] = 0;
} else {
register[regA] = 1;
}
break;
}
} else if (type == 2) { //branching
switch (inst) {
case 0://Beq/Br
if (valA == valB) {
pc += (UInt16)valC;
executionTime += 1;
}
break;
case 1://Bne
if (valA != valB) {
pc += (UInt16)valC;
executionTime += 1;
}
break;
case 2://Jmpeq/Jmp
if (valA == valB) {
pc = (UInt16)valC;
executionTime += 1;
valA = 4711;//this made the jmp instruction start working for some goddamned reason. It just goes to show, when in doubt: 4711
}
break;
case 3://Bl
if (valA < valB) {
pc += (UInt16)valC;
executionTime += 1;
}
break;
case 4://Ble
if (valA <= valB) {
pc += (UInt16)valC;
executionTime += 1;
}
break;
case 5://Bx
//TODO: DO something with this instruction
spawnException(258);
break;
case 6://Call
register[15] = pc;
if (immed != 0) {
pc += (UInt16)valC;
} else {
pc = (UInt16)valC;
}
executionTime += 1;
break;
case 7://eret
pc = (UInt16)register[31];
interruptStatus.setStatus(IntStatus.IQUEUEHANDLE, true);
executionTime += 1;
break;
}
} else if (type == 3) { //data move
switch (inst) {
case 0://Mov
if (immed != 0) {
valC += (Int32)regB << 16;
}
register[regA] = valC;
break;
case 1://Movhi
register[regA] = valC << 16;
break;
case 2://Rd
register[regA] = memory.readMem((UInt16)((valB + valC) & 0x0000ffff), out exTimeTMP);
executionTime += exTimeTMP - 1 + memReadDelaySlots((int)regA);
break;
case 3://Wr
tmp = (UInt16)((valB + valC) & 0x0000ffff);
executionTime += memory.writeMem(valA, (UInt16)tmp) - 1;
break;
case 4://Push
executionTime += memory.writeMem(valC, (UInt16)(register[14] & 0x0000ffff)) - 1;
register[14] = register[14] + 1;
break;
case 5://Pop
register[regA] = memory.readMem((UInt16)((register[14] - 1) & 0x0000ffff), out exTimeTMP);
register[14] = register[14] - 1;
executionTime += exTimeTMP - 1 + memReadDelaySlots((int)regA);
break;
case 6://Rdx
spawnException(258);
//EX = memory.readMem((UInt16)((valB + valC) & 0x0000ffff), out exTimeTMP);
//executionTime += exTimeTMP - 1;
break;
case 7://Int
spawnException(valC);
executionTime += 1;
break;
}
}
return executionTime;
}