package vue; // Instruction state and decoder public class Instruction { // Instruction fields public int bits; // Binary encoding public int cond; // Condition for Bcond public int disp; // Displacement for jumps and branches public int format; // Binary format public int id; // Library-specific identifier public int imm; // Immediate operand public int opcode; // Instruction opcode public int reg1; // Source/right register public int reg2; // Destination/left register public int size; // Number of bytes in encoding public int subopcode; // Instruction subopcode /////////////////////////////////////////////////////////////////////////// // Constants // /////////////////////////////////////////////////////////////////////////// // Intermediate instruction IDs private static final int BITSTRING = -2; private static final int FLOATENDO = -3; // Opcode lookup table private static final byte[] LOOKUP_OPCODE = { Vue.MOV_REG, 1, Vue.ADD_REG, 1, Vue.SUB , 1, Vue.CMP_REG, 1, Vue.SHL_REG, 1, Vue.SHR_REG, 1, Vue.JMP , 1, Vue.SAR_REG, 1, Vue.MUL , 1, Vue.DIV , 1, Vue.MULU , 1, Vue.DIVU , 1, Vue.OR , 1, Vue.AND , 1, Vue.XOR , 1, Vue.NOT , 1, Vue.MOV_IMM,-2, Vue.ADD_IMM,-2, Vue.SETF , 2, Vue.CMP_IMM,-2, Vue.SHL_IMM, 2, Vue.SHR_IMM, 2, Vue.CLI , 2, Vue.SAR_IMM, 2, Vue.TRAP , 2, Vue.RETI , 2, Vue.HALT , 2, Vue.ILLEGAL, 0, Vue.LDSR , 2, Vue.STSR , 2, Vue.SEI , 2, BITSTRING , 2, Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3, Vue.BCOND , 3, Vue.MOVEA ,-5, Vue.ADDI ,-5, Vue.JR , 4, Vue.JAL , 4, Vue.ORI , 5, Vue.ANDI , 5, Vue.XORI , 5, Vue.MOVHI , 5, Vue.LD_B , 6, Vue.LD_H , 6, Vue.ILLEGAL, 0, Vue.LD_W , 6, Vue.ST_B , 6, Vue.ST_H , 6, Vue.ILLEGAL, 0, Vue.ST_W , 6, Vue.IN_B , 6, Vue.IN_H , 6, Vue.CAXI , 6, Vue.IN_W , 6, Vue.OUT_B , 6, Vue.OUT_H , 6, FLOATENDO , 7, Vue.OUT_W , 6 }; // Bit string lookup table private static final byte[] LOOKUP_BITSTRING = { Vue.SCH0BSU, Vue.SCH0BSD, Vue.SCH1BSU, Vue.SCH1BSD, Vue.ILLEGAL, Vue.ILLEGAL, Vue.ILLEGAL, Vue.ILLEGAL, Vue.ORBSU , Vue.ANDBSU , Vue.XORBSU , Vue.MOVBSU , Vue.ORNBSU , Vue.ANDNBSU, Vue.XORNBSU, Vue.XORNBSU }; // Floating-point and Nintendo lookup table private static final byte[] LOOKUP_FLOATENDO = { Vue.CMPF_S , Vue.ILLEGAL, Vue.CVT_WS , Vue.CVT_SW , Vue.ADDF_S , Vue.SUBF_S , Vue.MULF_S , Vue.DIVF_S , Vue.XB , Vue.XH , Vue.REV , Vue.TRNC_SW, Vue.MPYHW , Vue.ILLEGAL, Vue.ILLEGAL, Vue.ILLEGAL }; /////////////////////////////////////////////////////////////////////////// // Static Methods // /////////////////////////////////////////////////////////////////////////// // Determine the size of an instruction given its opcode public static int size(int opcode) { return Math.abs(LOOKUP_OPCODE[opcode << 1 | 1]) < 4 ? 2 : 4; } /////////////////////////////////////////////////////////////////////////// // Constructors // /////////////////////////////////////////////////////////////////////////// // Default constructor public Instruction() { } // Decoding constructor public Instruction(int bits) { decode(bits); } // Cloning constructor Instruction(Instruction o) { this(); bits = o.bits; cond = o.cond; disp = o.disp; format = o.format; id = o.id; imm = o.imm; opcode = o.opcode; reg1 = o.reg1; reg2 = o.reg2; size = o.size; subopcode = o.subopcode; } /////////////////////////////////////////////////////////////////////////// // Public Methods // /////////////////////////////////////////////////////////////////////////// // Produce an access descriptor from the current instruction state public Access access(Vue vue) { boolean read = false; var ret = new Access(); ret.address = vue.getRegister(reg1, false) + disp; ret.fetch = vue.getFetch(); ret.type = Vue.S32; // Configure descriptor by ID switch (id) { case Vue.CAXI : read = true; break; case Vue.IN_B : ret.type = Vue.U8 ; read = true; break; case Vue.IN_H : ret.type = Vue.U16; read = true; break; case Vue.IN_W : read = true; break; case Vue.LD_B : ret.type = Vue.S8 ; read = true; break; case Vue.LD_H : ret.type = Vue.S16; read = true; break; case Vue.LD_W : read = true; break; case Vue.OUT_B: ret.type = Vue.U8 ; break; case Vue.OUT_H: ret.type = Vue.U16; break; case Vue.OUT_W: break; case Vue.ST_B : ret.type = Vue.S8 ; break; case Vue.ST_H : ret.type = Vue.S16; break; case Vue.ST_W : break; // TODO: Bit strings default: return null; } // Read the value currently on the bus if (read) ret.value = vue.read(ret.address, ret.type); // Write a register to the bus else if (id != Vue.CAXI) vue.getRegister(reg2, false); // CAXI processing else { int value = vue.read(ret.address, Vue.S32); int compare = vue.getRegister(reg2, false); int exchange = vue.getRegister( 30, false); ret.value = value == compare ? value : exchange; } return ret; } // Decode an instruction from a byte array public Instruction decode(byte[] data, int offset) { return decode( (data[offset + 0] & 0xFF) | (data[offset + 1] & 0xFF) << 8 | (data[offset + 2] & 0xFF) << 16 | (data[offset + 3] & 0xFF) << 24 ); } // Decode an instruction from its binary encoding (swapped halfwords) public Instruction decode(int bits) { byte extend; // Sign-extend the immediate operand int x; // Working variable // Configure instance fields this.bits = bits = bits << 16 | bits >>> 16; opcode = bits >> 26 & 63; x = opcode << 1; id = LOOKUP_OPCODE[x ]; extend = LOOKUP_OPCODE[x + 1]; format = extend < 0 ? -extend : extend; size = format < 4 ? 2 : 4; // Decode by format switch (format) { case 1: reg2 = bits >> 21 & 31; reg1 = bits >> 16 & 31; break; case 2: reg2 = bits >> 21 & 31; imm = extend < 0 ? bits << 11 >> 27 : bits >> 16 & 31; if (id == BITSTRING) { id = imm >= 16 ? Vue.ILLEGAL : LOOKUP_BITSTRING[imm]; subopcode = imm; } if (id == Vue.SETF) cond = imm & 15; break; case 3: opcode = 0x20; cond = bits >> 25 & 15; disp = bits << 7 >> 23; break; case 4: disp = bits << 6 >> 6; break; case 5: reg2 = bits >> 21 & 31; reg1 = bits >> 16 & 31; imm = extend < 0 ? bits << 16 >> 16 : bits & 0xFFFF; break; case 6: reg2 = bits >> 21 & 31; reg1 = bits >> 16 & 31; disp = bits << 16 >> 16; break; case 7: reg2 = bits >> 21 & 31; reg1 = bits >> 16 & 31; subopcode = bits >> 10 & 63; id = subopcode >= 16 ? Vue.ILLEGAL : LOOKUP_FLOATENDO[subopcode]; break; } return this; } }