/*******************************************************************************
* openDLX - A DLX/MIPS processor simulator.
* Copyright (C) 2013 The openDLX project, University of Augsburg, Germany
* Project URL: <https://sourceforge.net/projects/opendlx>
* Development branch: <https://github.com/smetzlaff/openDLX>
*
*
* This program 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
* any later version.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program, see <LICENSE>. If not, see
* <http://www.gnu.org/licenses/>.
******************************************************************************/
package openDLX.asm.instruction;
/**
* <p>
* This class is a wrapper around an instruction word Its operations access the
* bit fields of such an instruction word.
* </p>
*/
public class Instruction {
private int instrWord_;
/*
* ============================* Constructors *============================
*/
public static Instruction fromMnemonic(String mnemonic) {
Instruction i = Instructions.instance().getInstruction(mnemonic);
if (i != null)
return i.clone();
else
return null;
}
/**
* Standard constructor
*/
public Instruction() {
setInstrWord(0);
}
/**
* Constructor for instruction word
*
* @param instrWord
*/
public Instruction(int instrWord) {
setInstrWord(instrWord);
}
/**
* Constructor for IType
*
* @param opcode
* @param rs
* source register
* @param rt
* destination register
* @param offset
* immediate value
* @throws InstructionException
*/
public Instruction(int opcode, int rs, int rt, int offset) throws InstructionException {
setOpcode(opcode);
setRs(rs);
setRt(rt);
setOffset(offset);
}
/**
* Constructor for JType
*
* @param opcode
* @param index
* jump destination
* @throws InstructionException
*/
public Instruction(int opcode, int index) throws InstructionException {
setOpcode(opcode);
setInstrIndex(index);
}
/**
* Constructor for RType
*
* @param opcode
* @param rs
* source register
* @param rt
* target register or regimm opcode specifier
* @param rd
* destination register
* @param sa
* shift amount
* @param function
* additional opcode value for special opcode
* @throws InstructionException
*/
public Instruction(int opcode, int rs, int rt, int rd, int sa, int function)
throws InstructionException {
setOpcode(opcode);
setRs(rs);
setRt(rt);
setRd(rd);
setSa(sa);
setFunction(function);
}
/*
* ============================* Getter/Setter *============================
*/
// ================* instrType *================
public InstructionType calcInstType() {
return Instructions.instance().getType(this);
}
// ================* opcodeType *================
public OpcodeType opcodeType() {
int opcode = opcode();
if (opcode == 0) {
return OpcodeType.Special;
} else if (opcode == 1) {
return OpcodeType.Regimm;
} else {
return OpcodeType.Normal;
}
}
// ================* skeleton *================
public int skeleton() {
OpcodeType type = opcodeType();
if (type == OpcodeType.Special)
return instrWord() & 0xFC00003F;
else if (type == OpcodeType.Regimm)
return instrWord() & 0xFC1F0000;
else
return instrWord() & 0xFC000000;
}
// ================* instrWord *================
public int instrWord() {
return instrWord_;
}
public void setInstrWord(int instrWord) {
this.instrWord_ = instrWord;
}
// ================* opcode *================
public int opcode() {
return (instrWord_ >> 26) & 0x3F;
}
public void setOpcode(int opcode) throws InstructionException {
if (opcode > 0x3F || opcode < 0x0)
throw new InstructionException("opcode too long");
instrWord_ = (instrWord_ & 0x03FFFFFF) | (opcode << 26);
}
// ================* rs *================
public int rs() {
return (instrWord_ >> 21) & 0x1F;
}
public void setRs(int rs) throws InstructionException {
if (rs > 0x1F || rs < 0)
throw new InstructionException("register too long");
instrWord_ = (instrWord_ & 0xFC1FFFFF) | (rs << 21);
}
// ================* base *================
public int base() {
return (instrWord_ >> 21) & 0x1F;
}
public void setBase(int base) throws InstructionException {
if (base > 0x1F || base < 0)
throw new InstructionException("register too long");
instrWord_ = (instrWord_ & 0xFC1FFFFF) | (base << 21);
}
// ================* rt *================
public int rt() {
return (instrWord_ >> 16) & 0x1F;
}
public void setRt(int rt) throws InstructionException {
if (rt > 0x1F || rt < 0)
throw new InstructionException("register too long");
instrWord_ = (instrWord_ & 0xFFE0FFFF) | (rt << 16);
}
// ================* rd *================
public int rd() {
return (instrWord_ >> 11) & 0x1F;
}
public void setRd(int rd) throws InstructionException {
if (rd > 0x1F || rd < 0)
throw new InstructionException("register too long");
instrWord_ = (instrWord_ & 0xFFFF07FF) | (rd << 11);
}
// ================* sa *================
public int sa() {
return (instrWord_ >> 6) & 0x1F;
}
public void setSa(int sa) throws InstructionException {
if (sa > 0x1F || sa < 0)
throw new InstructionException("shift amount too long");
instrWord_ = (instrWord_ & 0xFFFFFF3F) | (sa << 6);
}
// ================* function *================
public int function() {
return instrWord_ & 0x3F;
}
public void setFunction(int function) throws InstructionException {
if (function > 0x3F || function < 0)
throw new InstructionException("function too long");
instrWord_ = (instrWord_ & 0xFFFFFFC0) | function;
}
// ================* offset *================
public int offset() {
return instrWord_ & 0xFFFF;
}
public int offset2k() {
int offset = instrWord_ & 0x7FFF;
if ((instrWord_ & 0x8000) != 0) {
//TODO???
offset = offset | 0xFFFF8000;
}
return offset;
}
public void setOffset(int offset) throws InstructionException {
if (offset > 0xFFFF || offset < -0xFFFF)
throw new InstructionException("offset too big");
instrWord_ = (instrWord_ & 0xFFFF0000) | (offset & 0xFFFF);
}
// ================* instrIndex *================
public int instrIndex() {
return instrWord_ & 0x03FFFFFF;
}
public int instrIndex2k() {
int index = instrWord_ & 0x01FFFFFF;
if ((instrWord_ & 0x02000000) != 0) {
index = index | 0xfe000000;
}
return index;
}
public void setInstrIndex(int index) throws InstructionException {
if (index > 0x3FFFFFF || index < 0)
throw new InstructionException("index too big");
instrWord_ = (instrWord_ & 0xFC000000) | (index & 0x3FFFFFF);
}
/*
* ===============================* String *===============================
*/
public String toString() {
StringBuffer strBuf = new StringBuffer();
String mnemonic = toMnemonic();
if (mnemonic != null) {
strBuf.append(mnemonic);
} else {
strBuf.append("unknown");
}
InstructionType type = calcInstType();
if (type != null)
switch (type) {
case LOAD:
strBuf.append(' ');
strBuf.append('r');
strBuf.append(rt());
strBuf.append(',');
strBuf.append(offset2k());
strBuf.append('(');
strBuf.append('r');
strBuf.append(base());
strBuf.append(')');
break;
case SAVE:
strBuf.append(' ');
strBuf.append(offset2k());
strBuf.append('(');
strBuf.append('r');
strBuf.append(base());
strBuf.append(')');
strBuf.append(',');
strBuf.append('r');
strBuf.append(rt());
break;
case ALU_REGISTER:
strBuf.append(' ');
strBuf.append('r');
strBuf.append(rd());
strBuf.append(',');
strBuf.append('r');
strBuf.append(rs());
strBuf.append(',');
strBuf.append('r');
strBuf.append(rt());
break;
case ALU_IMMEDIATE:
strBuf.append(' ');
strBuf.append('r');
strBuf.append(rt());
strBuf.append(',');
strBuf.append('r');
strBuf.append(rs());
strBuf.append(',');
strBuf.append(offset2k());
break;
case BRANCH:
strBuf.append(' ');
strBuf.append('r');
strBuf.append(rs());
strBuf.append(',');
strBuf.append("0x");
strBuf.append(Integer.toHexString(offset2k() << 2));
break;
case LOAD_IMMEDIATE:
strBuf.append(' ');
strBuf.append(rt());
strBuf.append(',');
strBuf.append(offset2k());
break;
case JUMP:
strBuf.append(' ');
strBuf.append("0x");
strBuf.append(Integer.toHexString(instrIndex() << 2));
break;
case JUMP_REGISTER:
strBuf.append(' ');
strBuf.append('r');
strBuf.append(rs());
break;
case SHIFT_IMMEDIATE:
strBuf.append(' ');
strBuf.append('r');
strBuf.append(rd());
strBuf.append(',');
strBuf.append('r');
strBuf.append(rt());
strBuf.append(',');
strBuf.append(sa());
break;
case TRAP:
strBuf.append(' ');
strBuf.append(rs());
break;
case NOP:
//"nop" already in strBuf
default:
}
return strBuf.toString();
}
public String toMnemonic() {
return Instructions.instance().getMnemonic(this);
}
public String toHexString() {
String hex = Integer.toHexString(instrWord());
//leading zeros
for (int diff = 8 - hex.length(); diff > 0; diff--) {
hex = '0' + hex;
}
hex = "0x" + hex;
return hex;
}
/*public String toFormatedBinString(InstructionType type) {
// String printStr = toString() + "\n";
String printStr = new String();
int mask = 1;
switch (type) {
case IType:
for (int i = 32; i > 0; i--) {
if (i == 6 || i == 11 || i == 16)
printStr = ' ' + printStr;
if ((instrWord_ & mask) == 0)
printStr = '0' + printStr;
else
printStr = '1' + printStr;
mask = mask << 1;
}
printStr = "\n+-----------------------------------+\n"
+ "|opcode rs rt offset |\n|" + printStr
+ "|\n+-----------------------------------+\n";
break;
case JType:
for (int i = 0; i < 32; i++) {
if (i == 26)
printStr = ' ' + printStr;
if ((instrWord_ & mask) == 0)
printStr = '0' + printStr;
else
printStr = '1' + printStr;
mask = mask << 1;
}
printStr = "\n+---------------------------------+\n"
+ "|opcode instr_index |\n|" + printStr
+ "|\n+---------------------------------+\n";
break;
case RType:
for (int i = 0; i < 32; i++) {
if (i == 6 || i == 11 || i == 16 || i == 21 || i == 26)
printStr = ' ' + printStr;
if ((instrWord_ & mask) == 0)
printStr = '0' + printStr;
else
printStr = '1' + printStr;
mask = mask << 1;
}
printStr = "\n+-------------------------------------+\n"
+ "|opcode rs rt rd sa func |\n|" + printStr
+ "|\n+-------------------------------------+\n";
break;
case Unknown:
for (int i = 0; i < 32; i++) {
if (i % 4 == 0 && i != 0)
printStr = ' ' + printStr;
if ((instrWord_ & mask) == 0)
printStr = '0' + printStr;
else
printStr = '1' + printStr;
mask = mask << 1;
}
printStr = "\n+---------------------------------------+\n|" + printStr
+ "|\n+---------------------------------------+\n";
}
return printStr;
}*/
/*
* ==============================* Equality *==============================
*/
public boolean equals(Object o) {
if (o instanceof Instruction) {
Instruction i = (Instruction) o;
if (i.instrWord() == instrWord())
return true;
}
return false;
}
/**
* true if i is the same mnemonic e.g. "<b>add r1,r0,r0</b>" and
* "<b>add r9,r8,r7</b>"
*
* @param i
* @return
*/
public boolean equalsFamily(Instruction i) {
if (i.skeleton() == skeleton())
return true;
return false;
}
public Instruction clone() {
return new Instruction(instrWord());
}
}