/**
* ****************************************************************************
* Copyright (c) 2010-2016 by Min Cai (min.cai.china@gmail.com).
* <p>
* This file is part of the Archimulator multicore architectural simulator.
* <p>
* Archimulator is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* <p>
* Archimulator is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License
* along with Archimulator. If not, see <http://www.gnu.org/licenses/>.
* ****************************************************************************
*/
package archimulator.isa.dissembler;
import archimulator.isa.ArchitecturalRegisterFile;
import archimulator.isa.BitField;
import archimulator.isa.StaticInstruction;
import archimulator.util.math.MathHelper;
/**
* MIPS disassembler.
*
* @author Min Cai
*/
public class MipsDisassembler {
/**
* Get the type of the specified machine instruction.
*
* @param machineInstruction the machine instruction
* @return the type of the specified machine instruction
*/
public static MachineInstructionType getMachineInstructionType(int machineInstruction) {
int opcode = BitField.OPCODE.valueOf(machineInstruction);
switch (opcode) {
case 0:
return MachineInstructionType.R;
case 0x02:
case 0x03:
return MachineInstructionType.J;
case 0x11:
return MachineInstructionType.F;
default:
return MachineInstructionType.I;
}
}
/**
* Get a value indicating whether the specified machine instruction is RMT or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is RMT or not
*/
public static boolean isRMt(int machineInstruction) {
int func = BitField.FUNC.valueOf(machineInstruction);
return func == 0x10 || func == 0x11;
}
/**
* Get a value indicating whether the specified machine instruction is RMF or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is RMF or not
*/
public static boolean isRMf(int machineInstruction) {
int func = BitField.FUNC.valueOf(machineInstruction);
return func == 0x12 || func == 0x13;
}
/**
* Get a value indicating whether the specified machine instruction is ROneOp or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is ROneOp or not
*/
public static boolean isROneOp(int machineInstruction) {
int func = BitField.FUNC.valueOf(machineInstruction);
return func == 0x08 || func == 0x09;
}
/**
* Get a value indicating whether the specified machine instruction is RTwoOp or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is RTwoOp or not
*/
public static boolean isRTwoOp(int machineInstruction) {
int func = BitField.FUNC.valueOf(machineInstruction);
return func >= 0x18 && func <= 0x1b;
}
/**
* Get a value indicating whether the specified machine instruction is a load/store or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a load/store or not
*/
public static boolean isLoadStore(int machineInstruction) {
int opcode = BitField.OPCODE.valueOf(machineInstruction);
return opcode >= 0x20 && opcode <= 0x2e || opcode == 0x30 || opcode == 0x38;
}
/**
* Get a value indicating whether the specified machine instruction is a floating point load/store or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a floating point load/store or not
*/
public static boolean isFPLoadStore(int machineInstruction) {
int opcode = BitField.OPCODE.valueOf(machineInstruction);
return opcode == 0x31 || opcode == 0x39;
}
/**
* Get a value indicating whether the specified machine instruction is a one operand branch or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a one operand branch or not
*/
public static boolean isOneOpBranch(int machineInstruction) {
int opcode = BitField.OPCODE.valueOf(machineInstruction);
return opcode == 0x00 || opcode == 0x01 || opcode == 0x06 || opcode == 0x07;
}
/**
* Get a value indicating whether the specified machine instruction is a shift operation or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a shift operation or not
*/
public static boolean isShift(int machineInstruction) {
int func = BitField.FUNC.valueOf(machineInstruction);
return func == 0x00 || func == 0x01 || func == 0x03;
}
/**
* Get a value indicating whether the specified machine instruction is a convert operation or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a convert operation or not
*/
public static boolean isCVT(int machineInstruction) {
int func = BitField.FUNC.valueOf(machineInstruction);
return func == 32 || func == 33 || func == 36;
}
/**
* Get a value indicating whether the specified machine instruction is a compare operation or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a compare operation or not
*/
public static boolean isCompare(int machineInstruction) {
int func = BitField.FUNC.valueOf(machineInstruction);
return func >= 48;
}
/**
* Get a value indicating whether the specified machine instruction is a move operation from a GPR to a floating point register or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a move operation from a GPR to a floating point register or not
*/
public static boolean isGprFpMove(int machineInstruction) {
int rs = BitField.RS.valueOf(machineInstruction);
return rs == 0 || rs == 4;
}
/**
* Get a value indicating whether the specified machine instruction is a move operation from a GPR to a floating point register or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a move operation from a GPR to the FCR or not
*/
public static boolean isGprFcrMove(int machineInstruction) {
int rs = BitField.RS.valueOf(machineInstruction);
return rs == 2 || rs == 6;
}
/**
* Get a value indicating whether the specified machine instruction is a floating point branch operation or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a floating point branch operation or not
*/
public static boolean isFpBranch(int machineInstruction) {
int rs = BitField.RS.valueOf(machineInstruction);
return rs == 8;
}
/**
* Get a value indicating whether the specified machine instruction is a system call or not.
*
* @param machineInstruction the machine instruction
* @return a value indicating whether the specified machine instruction is a system call or not
*/
public static boolean isSystemCall(int machineInstruction) {
int opcodeLo = BitField.OPCODE_LO.valueOf(machineInstruction);
int funcHi = BitField.FUNC_HI.valueOf(machineInstruction);
int funcLo = BitField.FUNC_LO.valueOf(machineInstruction);
return opcodeLo == 0x0 && funcHi == 0x1 && funcLo == 0x4;
}
/**
* Disassemble the specified static instruction at the specified program counter (PC).
*
* @param pc the program counter (PC) value
* @param staticInstruction the static instruction
* @return the text representation of the disassembled instruction
*/
public static String disassemble(int pc, StaticInstruction staticInstruction) {
StringBuilder sb = new StringBuilder();
int machineInstruction = staticInstruction.getMachineInstruction();
sb.append(String.format("0x%08x: 0x%08x %s ", pc, machineInstruction, staticInstruction.getMnemonic().toString().toLowerCase()));
if (machineInstruction == 0x00000000) {
return sb.toString().trim();
}
MachineInstructionType machineInstructionType = getMachineInstructionType(machineInstruction);
int imm = MathHelper.signExtend(BitField.INTIMM.valueOf(machineInstruction));
int rs = BitField.RS.valueOf(machineInstruction);
int rt = BitField.RT.valueOf(machineInstruction);
int rd = BitField.RD.valueOf(machineInstruction);
int fs = BitField.FS.valueOf(machineInstruction);
int ft = BitField.FT.valueOf(machineInstruction);
int fd = BitField.FD.valueOf(machineInstruction);
int shift = BitField.SHIFT.valueOf(machineInstruction);
int target = BitField.TARGET.valueOf(machineInstruction);
switch (machineInstructionType) {
case J:
sb.append(String.format("%x", target));
break;
case I:
if (isOneOpBranch(machineInstruction)) {
sb.append(String.format("$%s, %d", ArchitecturalRegisterFile.GPR_NAMES[rs], imm));
} else if (isLoadStore(machineInstruction)) {
sb.append(String.format("$%s, %d($%s)", ArchitecturalRegisterFile.GPR_NAMES[rt], imm, ArchitecturalRegisterFile.GPR_NAMES[rs]));
} else if (isFPLoadStore(machineInstruction)) {
sb.append(String.format("$f%d, %d($%s)", ft, imm, ArchitecturalRegisterFile.GPR_NAMES[rs]));
} else {
sb.append(String.format("$%s, $%s, %d", ArchitecturalRegisterFile.GPR_NAMES[rt], ArchitecturalRegisterFile.GPR_NAMES[rs], imm));
}
break;
case F:
if (isCVT(machineInstruction)) {
sb.append(String.format("$f%d, $f%d", fd, fs));
} else if (isCompare(machineInstruction)) {
sb.append(String.format("%d, $f%d, $f%d", fd >> 2, fs, ft));
} else if (isFpBranch(machineInstruction)) {
sb.append(String.format("%d, %d", fd >> 2, imm));
} else if (isGprFpMove(machineInstruction)) {
sb.append(String.format("$%s, $f%d", ArchitecturalRegisterFile.GPR_NAMES[rt], fs));
} else if (isGprFcrMove(machineInstruction)) {
sb.append(String.format("$%s, $%d", ArchitecturalRegisterFile.GPR_NAMES[rt], fs));
} else {
sb.append(String.format("$f%d, $f%d, $f%d", fd, fs, ft));
}
break;
case R:
if (!isSystemCall(machineInstruction)) {
if (isShift(machineInstruction)) {
sb.append(String.format("$%s, $%s, %d", ArchitecturalRegisterFile.GPR_NAMES[rd], ArchitecturalRegisterFile.GPR_NAMES[rt], shift));
} else if (isROneOp(machineInstruction)) {
sb.append(String.format("$%s", ArchitecturalRegisterFile.GPR_NAMES[rs]));
} else if (isRTwoOp(machineInstruction)) {
sb.append(String.format("$%s, $%s", ArchitecturalRegisterFile.GPR_NAMES[rs], ArchitecturalRegisterFile.GPR_NAMES[rt]));
} else if (isRMt(machineInstruction)) {
sb.append(String.format("$%s", ArchitecturalRegisterFile.GPR_NAMES[rs]));
} else if (isRMf(machineInstruction)) {
sb.append(String.format("$%s", ArchitecturalRegisterFile.GPR_NAMES[rd]));
} else {
sb.append(String.format("$%s, $%s, $%s", ArchitecturalRegisterFile.GPR_NAMES[rd], ArchitecturalRegisterFile.GPR_NAMES[rs], ArchitecturalRegisterFile.GPR_NAMES[rt]));
}
}
break;
default:
throw new IllegalArgumentException();
}
return sb.toString().trim();
}
}