Now for the main event... the various instruction modes.
Let's start with Add...
Code: Select all
if (instruction == add) {
[divvy up code[codeIndex] into its three seperate bytes]
if (Byte1 == Register3) {
Destination = "r3";
}
if (Byte2 == Register2) {
2ndOperand = "r2";
}
if (Byte3 == Register3) {
3rdOperand ="r3";
}
translation = Destination + "=" + 2ndOperand + "+" + 3rdOperand;
}
That's a waste. Instead, let's divvy it up between the three instruction categories.
Code: Select all
// determine the mode of the processor
modeMask = 2^27 + 2^26 + 2^25 + 2^24;
processorMode = Byte1 && modeMask;
// determine the mode of the instruction
operandTypeMask = 2^24;
instructionMode = processorMode && 2^24;
if (processorMode == registerOperandMode || processorMode == registerImmediateMode) {
// Based on this, we can avoid testing all of the instructions
if (instruction == add || instruction == subtract) {
// I don't think I've got my math off....
op[0] = Byte3 && (2^20 + 2^19 + 2^18 +2^17);
op[1] = Byte2 && (2^16 + 2^15 + 2^14 +2^13);
index = 0;
while (index < 2) {
switch (op[index]) {
case Register0: term[index] = "r0"; break;
case Register1: term[index] = "r1"; break;
case Register2: term[index] = "r2"; break;
case Register3: term[index]= "r3"; break;
case Register4: term[index]= "r4"; break;
case Register5: term[index]= "r5"; break;
case Register6: term[index]= "r6"; break;
case Register7: term[index]= "r7"; break;
case Register8: term[index]= "r8"; break;
case Register9: term[index]= "r9"; break;
case Register10: term[index]= "r10"; break;
case Register11: term[index]= "r11"; break;
case Register12: term[index]= "r12"; break;
case Register13: term[index]= "r13"; break;
case Register14: term[index]= "r14"; break;
// case Register15: term[index] = "r15";
default:
}
index++
}
if (instructionMode == immediate) {
term[3] = byte4;
}
else {
switch (Op1) {
case Register0: term[3] = "r0"; break;
case Register1: term[3] = "r1"; break;
case Register2: term[3] = "r2"; break;
case Register3: term[3] = "r3"; break;
case Register4: term[3] = "r4"; break;
case Register5: term[3] = "r5"; break;
case Register6: term[3] = "r6"; break;
case Register7: term[3] = "r7"; break;
case Register8: term[3] = "r8"; break;
case Register9: term[3] = "r9"; break;
case Register10: term[3] = "r10"; break;
case Register11: term[3] = "r11"; break;
case Register12: term[3] = "r12"; break;
case Register13: term[3] = "r13"; break;
case Register14: term[3] = "r14"; break;
// case Register15: term[3] = "r15";
default:
}
}
if (instruction == add)
translation = term[1] + "=" term[2] + "+" + term[3];
if (instruction == subtract)
translation = term[1] + "=" term[2] + "-" + term[3];
}
if (instruction == multiply || instruction == divide) {
op[0] = Byte3 && (2^20 + 2^19 + 2^18 +2^17);
op[1] = Byte2 && (2^16 + 2^15 + 2^14 +2^13);
op[2] = Byte2 && (2^16 + 2^15 + 2^14 +2^13);
index = 0;
while (index < 3) {
switch (op[index]) {
case Register0: term[index] = "r0"; break;
case Register1: term[index] = "r1"; break;
case Register2: term[index] = "r2"; break;
case Register3: term[index]= "r3"; break;
case Register4: term[index]= "r4"; break;
case Register5: term[index]= "r5"; break;
case Register6: term[index]= "r6"; break;
case Register7: term[index]= "r7"; break;
case Register8: term[index]= "r8"; break;
case Register9: term[index]= "r9"; break;
case Register10: term[index]= "r10"; break;
case Register11: term[index]= "r11"; break;
case Register12: term[index]= "r12"; break;
case Register13: term[index]= "r13"; break;
case Register14: term[index]= "r14"; break;
// case Register15: term[index] = "r15";
default:
}
index++
}
if (instructionMode == immediate) {
term[3] = byte4;
}
else {
switch (Op1) {
case Register0: term[3] = "r0"; break;
case Register1: term[3] = "r1"; break;
case Register2: term[3] = "r2"; break;
case Register3: term[3] = "r3"; break;
case Register4: term[3] = "r4"; break;
case Register5: term[3] = "r5"; break;
case Register6: term[3] = "r6"; break;
case Register7: term[3] = "r7"; break;
case Register8: term[3] = "r8"; break;
case Register9: term[3] = "r9"; break;
case Register10: term[3] = "r10"; break;
case Register11: term[3] = "r11"; break;
case Register12: term[3] = "r12"; break;
case Register13: term[3] = "r13"; break;
case Register14: term[3] = "r14"; break;
// case Register15: term[3] = "r15";
default:
}
}
if (instruction == multiply)
translation = term[1] + "=" term[2] + "*" + term[3];
if (instruction == divide)
translation = term[1] + "=" term[2] + "/" + term[3];
}
}
else
if (processorMode == branch) {
branchAddress = (byte2 * 2^16) + (byte3 * 2^8) + byte4;
for (index = 0; index < subroutineList.length && indexFound == false; index++) {
// has the subroutine already been decoded?
if (subroutineList[index].address == branchAddress) {
// if it has, jump to it
programCounter = branchAddress;
}
// otherwise we've got to decode it
subroutineList[subroutinelist.length].address = branchAddress;
subroutineList[subroutinelist.length].name = "BRANCH_" + branchAddress;
subroutineList[subroutinelist.length].source = subroutineList[subroutinelist.length].name + ":\n";
subroutineList[subroutinelist.length + 1] = new subroutine();
programCounter = branchAddress;
// what next?
}
I'm somewhat confused here. How many different forms of the registers need I account for, do you think?
Edit 3/30/08: added subtraction (not a big change because it behaves just like addition)
Edit 3/27/08: began adding branching.
Edit:
ARM says there are immediate and register forms of the last operand in the instruction. The marker bit is 24. The processor itself has eight modes. I've fitted the ADD instruction appropriately, and all that is left, I suspect, to implement it with reasonable accuracy is the institution of its flag consequences. (which do not even come into account unless the S bit is set).
Because my goal is a speed comparision between automatic translation and interpretation (by means of JS's onTimer function), I see myself as having two remaining tasks ahead:
- implement a branch instruction by which means continuous addition may be employed
- (not sure if the flags are important or not to the test... seems like it's situation dependent).
On the other hand, I've yet to prove that this technique can be used to access memory, either.