/*******************************************************************************
* 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.datatypes;
import openDLX.PipelineConstants;
import openDLX.exception.PipelineDataTypeException;
public class Instruction
{
private uint32 instr;
private uint8 opcode;
private uint8 function;
private uint8 rs;
private uint8 rt;
private uint8 rd;
private uint8 sa;
private uint16 offset;
private uint32 instr_index;
private InstructionType type;
private OpcodeNORMAL op_normal;
private OpcodeSPECIAL op_special;
private OpcodeREGIMM op_regimm;
private MemoryWidth mem_width;
private boolean load;
private boolean store;
private boolean read_rs;
private boolean read_rt;
private boolean read_hi;
private boolean read_lo;
private boolean write_rt;
private boolean write_rd;
private boolean write_hi;
private boolean write_lo;
private boolean use_immediate;
private boolean use_shift_amount;
private boolean use_instr_index;
private boolean branch;
private boolean branch_likely;
private boolean branch_and_link;
private ALUFunction alu_func;
private ALUPort alu_port_a;
private ALUPort alu_port_b;
private BranchCondition branch_cond;
private ImmExtend imm_extend;
private byte read_regs;
private byte write_regs;
private BranchCtrlPort branch_ctrl_port_a;
private BranchCtrlPort branch_ctrl_port_b;
/**
* @param instr
*/
public Instruction(uint32 instr)
{
this.instr = instr;
opcode = new uint8();
function = new uint8();
rs = new uint8();
rt = new uint8();
rd = new uint8();
sa = new uint8();
offset = new uint16();
instr_index = new uint32();
type = InstructionType.UNKNOWN;
op_normal = OpcodeNORMAL.UNKNOWN;
op_special = OpcodeSPECIAL.UNKNOWN;
op_regimm = OpcodeREGIMM.UNKNOWN;
alu_func = ALUFunction.NOP;
alu_port_a = ALUPort.ZERO;
alu_port_b = ALUPort.ZERO;
imm_extend = ImmExtend.UNKNOWN;
branch_cond = BranchCondition.NO_BRANCH;
branch_ctrl_port_a = BranchCtrlPort.ZERO;
branch_ctrl_port_b = BranchCtrlPort.ZERO;
// by default do not load/store
load = false;
store = false;
mem_width = MemoryWidth.WORD;
// by default do not read or write any register
read_rs = false;
read_rt = false;
write_rt = false;
write_rd = false;
// by default do not use immediates or shift amounts
use_immediate = false;
use_shift_amount = false;
use_instr_index = false;
// by default do not branch
branch = false;
branch_likely = false;
branch_and_link = false;
// by default no special register is read nor written
read_lo = false;
read_hi = false;
write_lo = false;
write_hi = false;
read_regs = 0;
write_regs = 0;
chopInstruction();
}
private void chopInstruction()
{
opcode.setValue((byte) ((instr.getValue() >> 26) & 0x3F));
function.setValue((byte) (instr.getValue() & 0x3F));
offset.setValue((short) (instr.getValue() & 0xFFFF));
instr_index.setValue(instr.getValue() & 0x1FFFFFF);
sa.setValue((byte) ((instr.getValue() >> 6) & 0x1F));
rd.setValue((byte) ((instr.getValue() >> 11) & 0x1F));
rt.setValue((byte) ((instr.getValue() >> 16) & 0x1F));
rs.setValue((byte) ((instr.getValue() >> 21) & 0x1F));
//logger.trace("Opcode is: " + opcode.getHex() + " Special: "
// + function.getHex() + " Regimm: " + rt.getHex());
}
/**
* Returns the type of the instruction.
* @see InstructionType
* @return The type of the instruction.
*/
public InstructionType getType()
{
return type;
}
public void setType(InstructionType type)
{
this.type = type;
}
public OpcodeNORMAL getOpNormal()
{
return op_normal;
}
public void setOpNormal(OpcodeNORMAL opNormal)
{
this.op_normal = opNormal;
}
public OpcodeSPECIAL getOpSpecial()
{
return op_special;
}
public void setOpSpecial(OpcodeSPECIAL opSpecial)
{
op_special = opSpecial;
}
public OpcodeREGIMM getOpRegimm()
{
return op_regimm;
}
public void setOpRegimm(OpcodeREGIMM opRegimm)
{
op_regimm = opRegimm;
}
public uint32 getInstr()
{
return instr;
}
public uint8 getOpcode()
{
return opcode;
}
public uint8 getFunction()
{
return function;
}
public uint8 getRegimm()
{
return rt;
}
public uint16 getOffset()
{
return offset;
}
public uint32 getInstrIndex()
{
return instr_index;
}
public void setReadRs(boolean b)
{
if(b && !read_rs)
{
read_regs++;
}
read_rs = b;
}
public boolean getReadRs()
{
return read_rs;
}
public void setReadRt(boolean b)
{
if(b && !read_rt)
{
read_regs++;
}
read_rt = b;
}
public boolean getReadRt()
{
return read_rt;
}
public void setWriteRd(boolean b)
{
if(b && !write_rd)
{
write_regs ++;
}
write_rd = b;
}
public boolean getWriteRd()
{
return write_rd;
}
public void setWriteRt(boolean b)
{
if(b && !write_rt)
{
write_regs ++;
}
write_rt = b;
}
public boolean getWriteRt()
{
return write_rt;
}
public boolean getReadHI()
{
return read_hi;
}
public void setReadHI(boolean b)
{
if(b && !read_hi)
{
read_regs ++;
}
read_hi = b;
}
public boolean getReadLO()
{
return read_lo;
}
public void setReadLO(boolean b)
{
if(b && !read_lo)
{
read_regs ++;
}
read_lo = b;
}
public boolean getWriteHI()
{
return write_hi;
}
public void setWriteHI(boolean b)
{
if(b && !write_hi)
{
write_regs ++;
}
write_hi = b;
}
public boolean getWriteLO()
{
return write_lo;
}
public void setWriteLO(boolean b)
{
if(b && !write_lo)
{
write_regs ++;
}
write_lo = b;
}
public void setUseImmediate(boolean b)
{
use_immediate = b;
}
public boolean getUseImmediate()
{
return use_immediate;
}
public void setUseShiftAmount(boolean b)
{
use_shift_amount = b;
}
public boolean getUseShiftAmount()
{
return use_shift_amount;
}
public void setLoad(boolean b)
{
load = b;
}
public boolean getLoad()
{
return load;
}
public void setStore(boolean b)
{
store = b;
}
public boolean getStore()
{
return store;
}
public void setBranch(boolean b)
{
branch = b;
}
public boolean getBranch()
{
return branch;
}
public void setBranchLikely(boolean b)
{
branch_likely = b;
}
public boolean getBranchLikely()
{
return branch_likely;
}
public void setALUFunction(ALUFunction fnct)
{
alu_func = fnct;
}
public ALUFunction getALUFunction()
{
return alu_func;
}
public uint8 getRs()
{
return rs;
}
public uint8 getRt()
{
return rt;
}
public uint8 getRd()
{
return rd;
}
public uint8 getSa()
{
return sa;
}
public byte getRegReadCount()
{
return read_regs;
}
public byte getRegWriteCount()
{
return write_regs;
}
public void setALUPortA(ALUPort port)
{
alu_port_a = port;
}
public ALUPort getALUPortA()
{
return alu_port_a;
}
public void setALUPortB(ALUPort port)
{
alu_port_b = port;
}
public ALUPort getALUPortB()
{
return alu_port_b;
}
public void setBranchCondition(BranchCondition cond)
{
branch_cond = cond;
}
public BranchCondition getBranchCondition()
{
return branch_cond;
}
public void setBranchPortA(BranchCtrlPort port)
{
branch_ctrl_port_a = port;
}
public BranchCtrlPort getBrachControlPortA()
{
return branch_ctrl_port_a;
}
public void setBranchPortB(BranchCtrlPort port)
{
branch_ctrl_port_b = port;
}
public BranchCtrlPort getBrachControlPortB()
{
return branch_ctrl_port_b;
}
public void setUseInstrIndex(boolean b)
{
use_instr_index = true;
}
public boolean getUseInstrIndex()
{
return use_instr_index;
}
public void setBranchAndLink(boolean b)
{
branch_and_link = b;
}
public boolean getBranchAndLink()
{
return branch_and_link;
}
public void setWriteRA(boolean b) throws PipelineDataTypeException
{
if(write_rd == true)
{
throw new PipelineDataTypeException("Return address already set.");
}
if(b)
{
// if writing the return address set the RD value to the RA register, which is 31
rd.setValue(PipelineConstants.REG_RA);
write_rd = true;
}
else
{
throw new PipelineDataTypeException("Cannot reset return address.");
}
}
public void setReadKernelRegisters(boolean b) throws PipelineDataTypeException
{
if(read_rs == true || read_rt == true)
{
throw new PipelineDataTypeException("MIPS kernel registers already set.");
}
if(b)
{
rs.setValue(PipelineConstants.REG_K0);
read_rs = true;
rt.setValue(PipelineConstants.REG_K1);
read_rt = true;
}
else
{
throw new PipelineDataTypeException("Cannot reset kernel registers.");
}
}
public void setReadDLXTrapParameterRegister(boolean b) throws PipelineDataTypeException
{
if(read_rt == true)
{
throw new PipelineDataTypeException("DLX trap parameters already set.");
}
if(b)
{
rt.setValue(PipelineConstants.REG_R14);
read_rt = true;
}
else
{
throw new PipelineDataTypeException("Cannot reset trap parameters.");
}
}
public void setWriteDLXTrapResultRegister(boolean b) throws PipelineDataTypeException
{
if(write_rd == true)
{
throw new PipelineDataTypeException("DLX trap result register parameter already set.");
}
if(b)
{
rd.setValue(PipelineConstants.REG_R1);
write_rd = true;
}
else
{
throw new PipelineDataTypeException("Cannot reset trap result parameters.");
}
}
public void setMemoryWidth(MemoryWidth mem_width)
{
this.mem_width = mem_width;
}
public MemoryWidth getMemoryWidth()
{
return mem_width;
}
public void setImmExtend(ImmExtend imm_extend)
{
this.imm_extend = imm_extend;
}
public ImmExtend getImmExtend()
{
return imm_extend;
}
public String getString()
{
String s;
s = getOpcodeName()
+ " ALU:" + getALUFunction()
+ " rRs:"
+ getReadRs()
+ ((getReadRs()) ? (" (" + rs.getValue() + "/" + ArchCfg.getRegisterDescription(rs.getValue()) + ")") : (""))
+ " rRt:"
+ getReadRt()
+ ((getReadRt()) ? (" (" + rt.getValue() + "/" + ArchCfg.getRegisterDescription(rt.getValue()) + ")") : (""))
+ " wRt:"
+ getWriteRt()
+ ((getWriteRt()) ? (" (" + rt.getValue() + "/" + ArchCfg.getRegisterDescription(rt.getValue()) + ")") : (""))
+ " wRd:"
+ getWriteRd()
+ ((getWriteRd()) ? (" (" + rd.getValue() + "/" + ArchCfg.getRegisterDescription(rd.getValue()) + ")") : (""))
+ " uIMM:"
+ getUseImmediate()
+ ((getUseImmediate()) ? (" (" + offset.getValue() + ")")
: (""))
+ " uSA:" + getUseShiftAmount() + ((getUseShiftAmount())?(" (" + sa.getValue() + ")"):(""))
+ " uIDX:" + getUseInstrIndex() + ((getUseInstrIndex())?(" (" + instr_index.getValueAsHexString() + ")"):(""))
+ " LD:" + getLoad() + " ST:" + getStore() + " BR:" + getBranch();
return s;
}
private String getOpcodeName()
{
String s;
if(getOpNormal() == OpcodeNORMAL.SPECIAL)
{
s = ""+getOpSpecial();
}
else if(getOpNormal() == OpcodeNORMAL.REGIMM)
{
s = ""+getOpRegimm();
}
else
{
s = ""+getOpNormal();
}
return s;
}
}