VU: Instruction decoder rework

This commit is contained in:
hch12907 2018-11-07 10:45:06 +08:00
parent c9713cb365
commit 620110cfa6
4 changed files with 454 additions and 424 deletions

View file

@ -35,17 +35,37 @@ int CVuInterpreter::time_step(const int ticks_available)
const uword upper_raw_inst = (raw_inst >> 32) & 0xFFFFFFFF;
const VuInstruction upper_inst = VuInstruction(upper_raw_inst);
const MipsInstructionInfo upper_info = upper_inst.lower_lookup();
const VuInstructionDecoder upper_decoder = VuInstructionDecoder(upper_inst, upper_info);
const uword lower_raw_inst = raw_inst & 0xFFFFFFFF;
const VuInstruction lower_inst = VuInstruction(lower_raw_inst);
const MipsInstructionInfo lower_info = lower_inst.lower_lookup();
const VuInstructionDecoder lower_decoder = VuInstructionDecoder(lower_inst, lower_info);
const VuInstructionDecoder decoder = VuInstructionDecoder(lower_inst, upper_inst);
// Flush the pipelines
unit->efu.consume_cycle(1);
unit->fdiv.consume_cycle(1);
unit->ialu.consume_cycle(1);
unit->lsu.consume_cycle(1);
for (FmacPipeline& fmac : unit->fmac)
{
fmac.consume_cycle(1);
}
// If the units have finished execution, replace the original regs with new ones
if (!unit->efu.is_running())
unit->p = unit->efu.new_p;
if (!unit->fdiv.is_running())
unit->q = unit->fdiv.new_q;
bool data_hazard_occured = check_data_hazard(unit, upper_decoder, lower_decoder);
// If I (bit 63) is set, execute UpperInst and LOI (using LowerInst as an immediate)
if ((raw_inst >> 63) & 1)
{
execute_upper_instruction(unit, upper_inst, upper_info, decoder);
execute_upper_instruction(unit, upper_decoder, data_hazard_occured);
this->LOI(unit, lower_inst);
// Advance PC and onto the next unit
@ -109,39 +129,39 @@ int CVuInterpreter::time_step(const int ticks_available)
try
{
// Try obtaining the destination (will throw if the instruction writes to non-VF/VI regs)
const uword upper_dest = *decoder.upper_dest();
const uword lower_dest = *decoder.lower_dest();
const uword upper_dest = *upper_decoder.try_get_dest();
const uword lower_dest = *lower_decoder.try_get_dest();
// Check if the lower instruction write to VI or VF
// If it writes to VF, check if it writes to the same reg
if (decoder.decode_lower().field != VuDecodedInst::Int)
if (!lower_decoder.is_integer_instruction())
{
if (upper_dest == lower_dest)
{
SizedQwordRegister original_vf = unit->vf[upper_dest];
execute_lower_instruction(unit, upper_inst, upper_info, decoder);
execute_lower_instruction(unit, lower_decoder, data_hazard_occured);
// The result produced by lower instruction is discarded
unit->vf[upper_dest] = original_vf;
execute_upper_instruction(unit, lower_inst, lower_info, decoder);
execute_upper_instruction(unit, upper_decoder, data_hazard_occured);
}
}
else
{
// Otherwise just run it usually
execute_upper_instruction(unit, upper_inst, upper_info, decoder);
execute_lower_instruction(unit, lower_inst, lower_info, decoder);
// Otherwise just run it as usual
execute_upper_instruction(unit, upper_decoder, data_hazard_occured);
execute_lower_instruction(unit, lower_decoder, data_hazard_occured);
}
}
catch (std::exception)
{
// If one of them write to special regs (P, Q, etc), execute like usual
execute_upper_instruction(unit, upper_inst, upper_info, decoder);
execute_lower_instruction(unit, lower_inst, lower_info, decoder);
execute_upper_instruction(unit, upper_decoder, data_hazard_occured);
execute_lower_instruction(unit, lower_decoder, data_hazard_occured);
}
// Advance the PC
if (!check_data_hazard(unit, decoder))
if (!check_data_hazard(unit, upper_decoder, lower_decoder))
unit->bdelay.advance_pc(unit->pc);
}
@ -149,21 +169,13 @@ int CVuInterpreter::time_step(const int ticks_available)
return 1;
}
int CVuInterpreter::execute_lower_instruction(VuUnit_Base* unit, const VuInstruction inst, MipsInstructionInfo info, const VuInstructionDecoder& decoder)
int CVuInterpreter::execute_lower_instruction(VuUnit_Base* unit, const VuInstructionDecoder& decoder, bool data_hazard)
{
unit->efu.consume_cycle(1);
unit->fdiv.consume_cycle(1);
unit->ialu.consume_cycle(1);
unit->lsu.consume_cycle(1);
// If the units have finished execution, replace the original regs with new ones
if (!unit->efu.is_running())
unit->p = unit->efu.new_p;
if (!unit->fdiv.is_running())
unit->q = unit->fdiv.new_q;
const VuInstruction& inst = decoder.instruction;
const MipsInstructionInfo& info = decoder.instruction_info;
// If there's a data hazard, stall
if (check_data_hazard(unit, decoder))
if (data_hazard)
return 1;
switch (info.pipeline)
@ -208,7 +220,7 @@ int CVuInterpreter::execute_lower_instruction(VuUnit_Base* unit, const VuInstruc
if (!unit->ialu.is_running())
{
// Try to get the destination
int dest = decoder.lower_dest().value_or(0);
int dest = decoder.try_get_dest().value_or(0);
// See FDIV
unit->ialu = IaluPipeline(info.cpi - 2, dest);
@ -225,7 +237,7 @@ int CVuInterpreter::execute_lower_instruction(VuUnit_Base* unit, const VuInstruc
{
if (!unit->lsu.is_running())
{
int dest = decoder.lower_dest().value_or(0);
int dest = decoder.try_get_dest().value_or(0);
unit->lsu = LsuPipeline(info.cpi - 2, dest);
}
@ -242,22 +254,20 @@ int CVuInterpreter::execute_lower_instruction(VuUnit_Base* unit, const VuInstruc
return 1;
}
int CVuInterpreter::execute_upper_instruction(VuUnit_Base* unit, VuInstruction inst, MipsInstructionInfo info, const VuInstructionDecoder& decoder)
int CVuInterpreter::execute_upper_instruction(VuUnit_Base* unit, const VuInstructionDecoder& decoder, bool data_hazard)
{
for (FmacPipeline& fmac : unit->fmac)
{
fmac.consume_cycle(1);
}
const VuInstruction& inst = decoder.instruction;
const MipsInstructionInfo& info = decoder.instruction_info;
// If there's a data hazard, stall
if (check_data_hazard(unit, decoder))
// Stall if there's a data hazard
if (data_hazard)
return 1;
for (FmacPipeline& fmac : unit->fmac)
{
if (!fmac.is_running())
{
fmac = FmacPipeline(info.cpi - 2, decoder.upper_dest().value_or(0), inst.dest());
fmac = FmacPipeline(info.cpi - 2, decoder.try_get_dest().value_or(0), inst.dest());
(this->*VU_INSTRUCTION_TABLE[info.impl_index])(unit, inst);
break;
}
@ -266,122 +276,75 @@ int CVuInterpreter::execute_upper_instruction(VuUnit_Base* unit, VuInstruction i
return 1;
}
bool CVuInterpreter::check_data_hazard(VuUnit_Base* unit, const VuInstructionDecoder& decoder) const
bool CVuInterpreter::check_data_hazard(VuUnit_Base* unit, const VuInstructionDecoder& ud, const VuInstructionDecoder& ld) const
{
// Obtain the registers to be read by the instruction
// If the instruction does not specify the field(s), use 0 as placeholder,
// as VF0/VI0 is hardwired to 0 (and the manual did this too)
const int upper_read[3] = {
decoder.upper_src(0).value_or(0),
decoder.upper_src(1).value_or(0),
decoder.upper_src(2).value_or(-1) // this one's special because only MADD/MSUB uses this
ud.try_get_src(0).value_or(0),
ud.try_get_src(1).value_or(0),
ud.try_get_src(2).value_or(-1) // this one's special because only MADD/MSUB uses this
};
const int lower_read[2] = {
decoder.lower_src(0).value_or(-1),
decoder.lower_src(1).value_or(-1)};
ld.try_get_src(0).value_or(0),
ld.try_get_src(1).value_or(0)
};
// If the instruction is WAITP, return true if EFU is running
if (((decoder.get_lower_inst().value) & 0x7FF) == 0x7BF)
if (((ld.instruction.value) & 0x7FF) == 0x7BF)
{
if (unit->efu.is_running())
return true;
}
// If the instruction is WAITQ, return true if FDIV is running
if (((decoder.get_lower_inst().value) & 0x7FF) == 0x3BF)
if (((ld.instruction.value) & 0x7FF) == 0x3BF)
{
if (unit->fdiv.is_running())
return true;
}
// Upper Instructions data hazard check
// Special case: if the instruction is MADD/MSUB/OPMSUB, then BC relates to 3rd field instead of 2nd
// note: (1 << (3 - inst.bc())) converts BC to DEST
{
VuInstruction inst = decoder.get_upper_inst();
const VuInstruction inst = ud.instruction;
if (upper_read[2] == -1)
{
if (decoder.decode_upper().field == VuDecodedInst::Bc)
for (FmacPipeline& fmac : unit->fmac)
{
for (FmacPipeline& fmac : unit->fmac)
{
if (fmac.is_using_register(upper_read[0], inst.dest()))
return true;
if (fmac.is_using_register(upper_read[1], 1U << (3 - inst.bc())))
return true;
}
}
else if (decoder.decode_upper().field == VuDecodedInst::Dest)
{
for (FmacPipeline& fmac : unit->fmac)
{
if (fmac.is_using_register(upper_read[0], inst.dest()))
return true;
if (fmac.is_using_register(upper_read[1], inst.dest()))
return true;
}
if (fmac.is_using_register(upper_read[0], *ud.try_get_src_field(0)))
return true;
if (fmac.is_using_register(upper_read[1], *ud.try_get_src_field(1)))
return true;
}
}
else
{
if (decoder.decode_upper().field == VuDecodedInst::Bc)
for (FmacPipeline& fmac : unit->fmac)
{
for (FmacPipeline& fmac : unit->fmac)
{
if (fmac.is_using_register(upper_read[0], inst.dest()))
return true;
if (fmac.is_using_register(upper_read[1], inst.dest()))
return true;
if (fmac.is_using_register(upper_read[2], 1U << (3 - inst.bc())))
return true;
}
}
else if (decoder.decode_upper().field == VuDecodedInst::Dest)
{
for (FmacPipeline& fmac : unit->fmac)
{
if (fmac.is_using_register(upper_read[0], inst.dest()))
return true;
if (fmac.is_using_register(upper_read[1], inst.dest()))
return true;
if (fmac.is_using_register(upper_read[2], inst.dest()))
return true;
}
if (fmac.is_using_register(upper_read[0], *ud.try_get_src_field(0)))
return true;
if (fmac.is_using_register(upper_read[1], *ud.try_get_src_field(1)))
return true;
if (fmac.is_using_register(upper_read[2], *ud.try_get_src_field(2)))
return true;
}
}
}
// Lower Instructions data hazard check
{
VuInstruction inst = decoder.get_upper_inst();
const VuInstruction inst = ld.instruction;
if (decoder.decode_lower().field == VuDecodedInst::FsfFtf)
for (FmacPipeline& fmac : unit->fmac)
{
for (FmacPipeline& fmac : unit->fmac)
{
if (fmac.is_using_register(lower_read[0], inst.fsf()))
return true;
if (fmac.is_using_register(lower_read[1], inst.ftf()))
return true;
}
}
else if (decoder.decode_lower().field == VuDecodedInst::Dest)
{
for (FmacPipeline& fmac : unit->fmac)
{
if (fmac.is_using_register(lower_read[0], inst.dest()))
return true;
if (fmac.is_using_register(lower_read[1], inst.dest()))
return true;
}
}
else if (decoder.decode_lower().field == VuDecodedInst::Int)
{
if (unit->lsu.is_using_register(lower_read[0]))
if (fmac.is_using_register(lower_read[0], *ld.try_get_src_field(0)))
return true;
}
if (fmac.is_using_register(lower_read[1], *ld.try_get_src_field(1)))
return true;
}
}
return false;

View file

@ -383,8 +383,8 @@ public:
&CVuInterpreter::XITOP};
private:
bool check_data_hazard(VuUnit_Base* unit, const VuInstructionDecoder& decoder) const;
bool check_data_hazard(VuUnit_Base* unit, const VuInstructionDecoder& upper_decoder, const VuInstructionDecoder& lower_decoder) const;
int execute_upper_instruction(VuUnit_Base* unit, VuInstruction inst, MipsInstructionInfo info, const VuInstructionDecoder& decoder);
int execute_lower_instruction(VuUnit_Base* unit, VuInstruction inst, MipsInstructionInfo info, const VuInstructionDecoder& decoder);
int execute_upper_instruction(VuUnit_Base* unit, const VuInstructionDecoder& decoder, bool handle_data_hazard);
int execute_lower_instruction(VuUnit_Base* unit, const VuInstructionDecoder& decoder, bool handle_data_hazard);
};

View file

@ -1,271 +1,349 @@
#include "Resources/Ee/Vpu/Vu/VuInstructionDecoder.hpp"
/// Each VuInstruction specifies 3 registers (one for the destination reg
/// and others for source) and uses 4 at most (eg MADD/MSUB). In this table index 0
/// stores the destination reg, while index 1, 2 & 3 stores the source reg(s).
/// If the destination bitfield is set to nullopt, then it is assumed that the
/// instruction uses special registers such as P, Q or ACC.
VuDecodedInst VU_DECODE_TABLE[Constants::EE::VPU::VU::NUMBER_VU_INSTRUCTIONS]{
// DESTINATION SOURCE (1) SOURCE (2) SOURCE (3) FIELDS
VuInstructionType VU_INSTRUCTION_DECODE_TABLE[Constants::EE::VPU::VU::NUMBER_VU_INSTRUCTIONS] {
// Upper Instructions
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ABS
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // ADD
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuSpecialRegs::I, std::nullopt, VuDecodedInst::Dest), // ADDi
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuSpecialRegs::Q, std::nullopt, VuDecodedInst::Dest), // ADDq
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // ADDbc_0
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // ADDbc_1
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // ADDbc_2
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // ADDbc_3
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // ADDA
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::I, std::nullopt, VuDecodedInst::Dest), // ADDAi
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::Q, std::nullopt, VuDecodedInst::Dest), // ADDAq
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // ADDAbc_0
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // ADDAbc_1
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // ADDAbc_2
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // ADDAbc_3
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // SUB
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuSpecialRegs::I, std::nullopt, VuDecodedInst::Dest), // SUBi
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuSpecialRegs::Q, std::nullopt, VuDecodedInst::Dest), // SUBq
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // SUBbc_0
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // SUBbc_1
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // SUBbc_2
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // SUBbc_3
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // SUBA
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::I, std::nullopt, VuDecodedInst::Dest), // SUBAi
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::Q, std::nullopt, VuDecodedInst::Dest), // SUBAq
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // SUBAbc_0
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // SUBAbc_1
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // SUBAbc_2
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // SUBAbc_3
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // MUL
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuSpecialRegs::I, std::nullopt, VuDecodedInst::Dest), // MULi
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuSpecialRegs::Q, std::nullopt, VuDecodedInst::Dest), // MULq
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MULbc_0
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MULbc_1
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MULbc_2
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MULbc_3
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // MULA
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::I, std::nullopt, VuDecodedInst::Dest), // MULAi
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::Q, std::nullopt, VuDecodedInst::Dest), // MULAq
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MULAbc_0
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MULAbc_1
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MULAbc_2
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MULAbc_3
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Dest), // MADD
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::I, VuDecodedInst::Dest), // MADDi
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::Q, VuDecodedInst::Dest), // MADDq
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MADDbc_0
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MADDbc_1
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MADDbc_2
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MADDbc_3
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Dest), // MADDA
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::I, VuDecodedInst::Dest), // MADDAi
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::Q, VuDecodedInst::Dest), // MADDAq
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MADDAbc_0
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MADDAbc_1
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MADDAbc_2
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MADDAbc_3
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Dest), // MSUB
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::I, VuDecodedInst::Dest), // MSUBi
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::Q, VuDecodedInst::Dest), // MSUBq
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MSUBbc_0
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MSUBbc_1
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MSUBbc_2
VuDecodedInst(VuInstruction::FD, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MSUBbc_3
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Dest), // MSUBA
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::I, VuDecodedInst::Dest), // MSUBAi
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuSpecialRegs::Q, VuDecodedInst::Dest), // MSUBAq
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MSUBAbc_0
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MSUBAbc_1
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MSUBAbc_2
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Bc), // MSUBAbc_3
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // MAX
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuSpecialRegs::I, std::nullopt, VuDecodedInst::Dest), // MAXi
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MAXbc_0
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MAXbc_1
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MAXbc_2
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MAXbc_3
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // MINI
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuSpecialRegs::I, std::nullopt, VuDecodedInst::Dest), // MINIi
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MINIbc_0
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MINIbc_1
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MINIbc_2
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Bc), // MINIbc_3
VuDecodedInst(VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // OPMULA
VuDecodedInst(VuSpecialRegs::ACC, VuSpecialRegs::ACC, VuInstruction::FS, VuInstruction::FT, VuDecodedInst::Dest), // OPMSUB
VuDecodedInst(std::nullopt, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Dest), // NOP
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // FTOI0
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // FTOI4
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // FTOI12
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // FTOI15
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ITOF0
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ITOF4
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ITOF12
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ITOF15
VuDecodedInst(VuSpecialRegs::CLIP, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Dest), // CLIP
// Lower Instructions
VuDecodedInst(VuSpecialRegs::Q, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::FsfFtf), // DIV
VuDecodedInst(VuSpecialRegs::Q, VuInstruction::FT, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // SQRT
VuDecodedInst(VuSpecialRegs::Q, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::FsfFtf), // RSQRT
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Int), // IADD
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // IADDI
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // IADDIU
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Int), // IAND
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Int), // IOR
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, VuInstruction::FT, std::nullopt, VuDecodedInst::Int), // ISUB
VuDecodedInst(VuInstruction::FD, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // ISUBI
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // MOVE
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // MFIR
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // MTIR
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // MR32
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // LQ
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // LQD
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // LQI
VuDecodedInst(VuInstruction::FS, VuInstruction::FT, std::nullopt, std::nullopt, VuDecodedInst::Dest), // SQ
VuDecodedInst(VuInstruction::FS, VuInstruction::FT, std::nullopt, std::nullopt, VuDecodedInst::Dest), // SQD
VuDecodedInst(VuInstruction::FS, VuInstruction::FT, std::nullopt, std::nullopt, VuDecodedInst::Dest), // SQI
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // ILW
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // ISW
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // ILWR
VuDecodedInst(VuInstruction::FT, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // ISWR
VuDecodedInst(VuSpecialRegs::R, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // RINIT
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::R, std::nullopt, std::nullopt, VuDecodedInst::Dest), // RGET
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::R, std::nullopt, std::nullopt, VuDecodedInst::Dest), // RNEXT
VuDecodedInst(VuSpecialRegs::R, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // RXOR
VuDecodedInst(std::nullopt, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Dest), // WAITQ
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::SF, std::nullopt, std::nullopt, VuDecodedInst::Int), // FSAND
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::SF, std::nullopt, std::nullopt, VuDecodedInst::Int), // FSEQ
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::SF, std::nullopt, std::nullopt, VuDecodedInst::Int), // FSOR
VuDecodedInst(VuSpecialRegs::SF, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Int), // FSSET
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::MAC, VuInstruction::FS, std::nullopt, VuDecodedInst::Int), // FMAND
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::MAC, VuInstruction::FS, std::nullopt, VuDecodedInst::Int), // FMEQ
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::MAC, VuInstruction::FS, std::nullopt, VuDecodedInst::Int), // FMOR
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::CLIP, std::nullopt, std::nullopt, VuDecodedInst::Int), // FCAND
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::CLIP, std::nullopt, std::nullopt, VuDecodedInst::Int), // FCEQ
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::CLIP, std::nullopt, std::nullopt, VuDecodedInst::Int), // FCOR
VuDecodedInst(VuSpecialRegs::CLIP, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Int), // FCSET
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::CLIP, std::nullopt, std::nullopt, VuDecodedInst::Int), // FCGET
VuDecodedInst(VuSpecialRegs::PC, VuInstruction::FT, VuInstruction::FS, std::nullopt, VuDecodedInst::Int), // IBEQ
VuDecodedInst(VuSpecialRegs::PC, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // IBGEZ
VuDecodedInst(VuSpecialRegs::PC, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // IBGTZ
VuDecodedInst(VuSpecialRegs::PC, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // IBLEZ
VuDecodedInst(VuSpecialRegs::PC, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // IBLTZ
VuDecodedInst(VuSpecialRegs::PC, VuInstruction::FT, VuInstruction::FS, std::nullopt, VuDecodedInst::Int), // IBNE
VuDecodedInst(VuSpecialRegs::PC, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Int), // B
VuDecodedInst(VuInstruction::FT, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Int), // BAL
VuDecodedInst(VuSpecialRegs::PC, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Int), // J
VuDecodedInst(VuInstruction::FT, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Int), // JALR
VuDecodedInst(VuInstruction::FT, VuSpecialRegs::P, std::nullopt, std::nullopt, VuDecodedInst::Dest), // MFP
VuDecodedInst(std::nullopt, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Dest), // WAITP
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ESADD
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ERSADD
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ELENG
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ERLENG
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // EATANxy
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // EATANxz
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Dest), // ESUM
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // ERCPR
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // ESQRT
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // ERSQRT
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // ESIN
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // EATAN
VuDecodedInst(VuSpecialRegs::P, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::FsfFtf), // EEXP
VuDecodedInst(std::nullopt, VuInstruction::FS, std::nullopt, std::nullopt, VuDecodedInst::Int), // XGKICK
VuDecodedInst(VuInstruction::FT, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Int), // XTOP
VuDecodedInst(VuInstruction::FT, std::nullopt, std::nullopt, std::nullopt, VuDecodedInst::Int), // XITOP
VuInstructionType::UpperType3, // ABS
VuInstructionType::UpperType1, // ADD
VuInstructionType::UpperType1, // ADDi
VuInstructionType::UpperType1, // ADDq
VuInstructionType::UpperType0, // ADDbc_0
VuInstructionType::UpperType0, // ADDbc_1
VuInstructionType::UpperType0, // ADDbc_2
VuInstructionType::UpperType0, // ADDbc_3
VuInstructionType::UpperType3_ACC, // ADDA
VuInstructionType::UpperType3_ACC, // ADDAi
VuInstructionType::UpperType3_ACC, // ADDAq
VuInstructionType::UpperType2_ACC, // ADDAbc_0
VuInstructionType::UpperType2_ACC, // ADDAbc_1
VuInstructionType::UpperType2_ACC, // ADDAbc_2
VuInstructionType::UpperType2_ACC, // ADDAbc_3
VuInstructionType::UpperType1, // SUB
VuInstructionType::UpperType1, // SUBi
VuInstructionType::UpperType1, // SUBq
VuInstructionType::UpperType0, // SUBbc_0
VuInstructionType::UpperType0, // SUBbc_1
VuInstructionType::UpperType0, // SUBbc_2
VuInstructionType::UpperType0, // SUBbc_3
VuInstructionType::UpperType3_ACC, // SUBA
VuInstructionType::UpperType3_ACC, // SUBAi
VuInstructionType::UpperType3_ACC, // SUBAq
VuInstructionType::UpperType2_ACC, // SUBAbc_0
VuInstructionType::UpperType2_ACC, // SUBAbc_1
VuInstructionType::UpperType2_ACC, // SUBAbc_2
VuInstructionType::UpperType2_ACC, // SUBAbc_3
VuInstructionType::UpperType1, // MUL
VuInstructionType::UpperType1, // MULi
VuInstructionType::UpperType1, // MULq
VuInstructionType::UpperType0, // MULbc_0
VuInstructionType::UpperType0, // MULbc_1
VuInstructionType::UpperType0, // MULbc_2
VuInstructionType::UpperType0, // MULbc_3
VuInstructionType::UpperType3_ACC, // MULA
VuInstructionType::UpperType3_ACC, // MULAi
VuInstructionType::UpperType3_ACC, // MULAq
VuInstructionType::UpperType2_ACC, // MULAbc_0
VuInstructionType::UpperType2_ACC, // MULAbc_1
VuInstructionType::UpperType2_ACC, // MULAbc_2
VuInstructionType::UpperType2_ACC, // MULAbc_3
VuInstructionType::UpperType1, // MADD
VuInstructionType::UpperType1, // MADDi
VuInstructionType::UpperType1, // MADDq
VuInstructionType::UpperType0, // MADDbc_0
VuInstructionType::UpperType0, // MADDbc_1
VuInstructionType::UpperType0, // MADDbc_2
VuInstructionType::UpperType0, // MADDbc_3
VuInstructionType::UpperType3_ACC, // MADDA
VuInstructionType::UpperType3_ACC, // MADDAi
VuInstructionType::UpperType3_ACC, // MADDAq
VuInstructionType::UpperType2_ACC, // MADDAbc_0
VuInstructionType::UpperType2_ACC, // MADDAbc_1
VuInstructionType::UpperType2_ACC, // MADDAbc_2
VuInstructionType::UpperType2_ACC, // MADDAbc_3
VuInstructionType::UpperType1, // MSUB
VuInstructionType::UpperType1, // MSUBi
VuInstructionType::UpperType1, // MSUBq
VuInstructionType::UpperType0, // MSUBbc_0
VuInstructionType::UpperType0, // MSUBbc_1
VuInstructionType::UpperType0, // MSUBbc_2
VuInstructionType::UpperType0, // MSUBbc_3
VuInstructionType::UpperType3_ACC, // MSUBA
VuInstructionType::UpperType3_ACC, // MSUBAi
VuInstructionType::UpperType3_ACC, // MSUBAq
VuInstructionType::UpperType2_ACC, // MSUBAbc_0
VuInstructionType::UpperType2_ACC, // MSUBAbc_1
VuInstructionType::UpperType2_ACC, // MSUBAbc_2
VuInstructionType::UpperType2_ACC, // MSUBAbc_3
VuInstructionType::UpperType1, // MAX
VuInstructionType::UpperType1, // MAXi
VuInstructionType::UpperType0, // MAXbc_0
VuInstructionType::UpperType0, // MAXbc_1
VuInstructionType::UpperType0, // MAXbc_2
VuInstructionType::UpperType0, // MAXbc_3
VuInstructionType::UpperType1, // MINI
VuInstructionType::UpperType1, // MINIi
VuInstructionType::UpperType0, // MINIbc_0
VuInstructionType::UpperType0, // MINIbc_1
VuInstructionType::UpperType0, // MINIbc_2
VuInstructionType::UpperType0, // MINIbc_3
VuInstructionType::UpperType3_ACC, // OPMULA
VuInstructionType::UpperType3_ACC, // OPMSUB
VuInstructionType::UpperType3, // NOP
VuInstructionType::UpperType3, // FTOI0
VuInstructionType::UpperType3, // FTOI4
VuInstructionType::UpperType3, // FTOI12
VuInstructionType::UpperType3, // FTOI15
VuInstructionType::UpperType3, // ITOF0
VuInstructionType::UpperType3, // ITOF4
VuInstructionType::UpperType3, // ITOF12
VuInstructionType::UpperType3, // ITOF15
VuInstructionType::UpperType3, // CLIP
// Lower Instructions
VuInstructionType::LowerType4, // DIV
VuInstructionType::LowerType4, // SQRT
VuInstructionType::LowerType4, // RSQRT
VuInstructionType::LowerType1_I, // IADD
VuInstructionType::LowerType5, // IADDI
VuInstructionType::LowerType8, // IADDIU
VuInstructionType::LowerType1_I, // IAND
VuInstructionType::LowerType1_I, // IOR
VuInstructionType::LowerType1_I, // ISUB
VuInstructionType::LowerType8, // ISUBI
VuInstructionType::LowerType3, // MOVE
VuInstructionType::LowerType3_FT_IS, // MFIR
VuInstructionType::LowerType4_IT_FS, // MTIR
VuInstructionType::LowerType3, // MR32
VuInstructionType::LowerType7_FT_IS, // LQ
VuInstructionType::LowerType3_FT_IS, // LQD
VuInstructionType::LowerType3_FT_IS, // LQI
VuInstructionType::LowerType7, // SQ
VuInstructionType::LowerType3_IT_FS, // SQD
VuInstructionType::LowerType3_IT_FS, // SQI
VuInstructionType::LowerType7_I, // ILW
VuInstructionType::LowerType7_I, // ISW
VuInstructionType::LowerType3_I, // ILWR
VuInstructionType::LowerType3_I, // ISWR
VuInstructionType::LowerType4, // RINIT
VuInstructionType::LowerType3, // RGET
VuInstructionType::LowerType3, // RNEXT
VuInstructionType::LowerType4, // RXOR
VuInstructionType::LowerType3, // WAITQ
VuInstructionType::LowerType8, // FSAND
VuInstructionType::LowerType8, // FSEQ
VuInstructionType::LowerType8, // FSOR
VuInstructionType::LowerType8, // FSSET
VuInstructionType::LowerType8, // FMAND
VuInstructionType::LowerType8, // FMEQ
VuInstructionType::LowerType8, // FMOR
VuInstructionType::LowerType9, // FCAND
VuInstructionType::LowerType9, // FCEQ
VuInstructionType::LowerType9, // FCOR
VuInstructionType::LowerType9, // FCSET
VuInstructionType::LowerType8, // FCGET
VuInstructionType::LowerType7_I, // IBEQ
VuInstructionType::LowerType7_I, // IBGEZ
VuInstructionType::LowerType7_I, // IBGTZ
VuInstructionType::LowerType7_I, // IBLEZ
VuInstructionType::LowerType7_I, // IBLTZ
VuInstructionType::LowerType7_I, // IBNE
VuInstructionType::LowerType7_I, // B
VuInstructionType::LowerType7_I, // BAL
VuInstructionType::LowerType7_I, // JR
VuInstructionType::LowerType7_I, // JALR
VuInstructionType::LowerType3, // MFP
VuInstructionType::LowerType3, // WAITP
VuInstructionType::LowerType3, // ESADD
VuInstructionType::LowerType3, // ERSADD
VuInstructionType::LowerType3, // ELENG
VuInstructionType::LowerType3, // ERLENG
VuInstructionType::LowerType3, // EATANxy
VuInstructionType::LowerType3, // EATANxz
VuInstructionType::LowerType3, // ESUM
VuInstructionType::LowerType4, // ERCPR
VuInstructionType::LowerType4, // ESQRT
VuInstructionType::LowerType4, // ERSQRT
VuInstructionType::LowerType4, // ESIN
VuInstructionType::LowerType4, // EATAN
VuInstructionType::LowerType4, // EEXP
VuInstructionType::LowerType3, // XGKICK
VuInstructionType::LowerType3_I, // XTOP
VuInstructionType::LowerType3_I // XITOP
};
VuInstructionDecoder::VuInstructionDecoder(VuInstruction lower, VuInstruction upper) :
lower_inst(lower),
upper_inst(upper),
decoded_inst_lower(VU_DECODE_TABLE[lower.lower_lookup().impl_index]),
decoded_inst_upper(VU_DECODE_TABLE[lower.upper_lookup().impl_index])
VuInstructionType VuInstructionDecoder::decode_instruction() const
{
return VU_INSTRUCTION_DECODE_TABLE[instruction_info.impl_index];
}
const VuDecodedInst& VuInstructionDecoder::decode_lower() const
std::optional<int> VuInstructionDecoder::try_get_dest() const
{
return decoded_inst_lower;
}
VuInstructionType decoded = decode_instruction();
const VuDecodedInst& VuInstructionDecoder::decode_upper() const
{
return decoded_inst_upper;
}
const VuInstruction& VuInstructionDecoder::get_upper_inst() const
{
return upper_inst;
}
const VuInstruction& VuInstructionDecoder::get_lower_inst() const
{
return lower_inst;
}
std::optional<int> VuInstructionDecoder::upper_dest() const
{
if (decoded_inst_upper.dest_reg.has_value())
switch (decoded)
{
VuDecodeInfo value = decoded_inst_upper.dest_reg.value();
if (Bitfield* ptr = std::get_if<Bitfield>(&value))
{
return ptr->extract_from(upper_inst.value);
}
}
case VuInstructionType::UpperType0:
case VuInstructionType::UpperType1:
case VuInstructionType::LowerType1:
return instruction.fd();
case VuInstructionType::UpperType2:
case VuInstructionType::UpperType3:
case VuInstructionType::LowerType3:
case VuInstructionType::LowerType7_FT_IS:
return instruction.ft();
return std::nullopt;
default:
return std::nullopt;
}
}
std::optional<int> VuInstructionDecoder::upper_src(int index) const
std::optional<int> VuInstructionDecoder::try_get_dest_field() const
{
const std::optional<VuDecodeInfo>* src_regs[3] = {
&decoded_inst_upper.source_reg_1,
&decoded_inst_upper.source_reg_2,
&decoded_inst_upper.source_reg_3};
VuInstructionType decoded = decode_instruction();
if (src_regs[index]->has_value())
switch (decoded)
{
VuDecodeInfo value = src_regs[index]->value();
if (Bitfield* ptr = std::get_if<Bitfield>(&value))
{
return ptr->extract_from(upper_inst.value);
}
}
case VuInstructionType::UpperType0:
case VuInstructionType::UpperType1:
case VuInstructionType::UpperType2:
case VuInstructionType::UpperType3:
case VuInstructionType::LowerType1:
case VuInstructionType::LowerType3:
case VuInstructionType::LowerType7_FT_IS:
return instruction.dest();
return std::nullopt;
case VuInstructionType::LowerType4:
return 1 << (3 - instruction.ftf());
default:
return std::nullopt;
}
}
std::optional<int> VuInstructionDecoder::lower_dest() const
std::optional<int> VuInstructionDecoder::try_get_src(int idx) const
{
if (decoded_inst_lower.dest_reg.has_value())
{
VuDecodeInfo value = decoded_inst_lower.dest_reg.value();
if (Bitfield* ptr = std::get_if<Bitfield>(&value))
{
return ptr->extract_from(lower_inst.value);
}
}
VuInstructionType decoded = decode_instruction();
return std::nullopt;
switch (idx)
{
case 0: switch (decoded)
{
case VuInstructionType::UpperType0:
case VuInstructionType::UpperType1:
case VuInstructionType::UpperType2:
case VuInstructionType::UpperType3:
case VuInstructionType::UpperType1_ACC:
case VuInstructionType::UpperType2_ACC:
case VuInstructionType::UpperType3_ACC:
case VuInstructionType::LowerType1:
case VuInstructionType::LowerType3:
case VuInstructionType::LowerType3_IT_FS:
case VuInstructionType::LowerType4:
case VuInstructionType::LowerType4_IT_FS:
case VuInstructionType::LowerType7:
case VuInstructionType::LowerType8:
return instruction.fs();
default:
return std::nullopt;
}
case 1: switch (decoded)
{
case VuInstructionType::UpperType0:
case VuInstructionType::UpperType1:
case VuInstructionType::UpperType1_ACC:
case VuInstructionType::UpperType2:
case VuInstructionType::UpperType2_ACC:
case VuInstructionType::UpperType3:
case VuInstructionType::UpperType3_ACC:
case VuInstructionType::LowerType1:
case VuInstructionType::LowerType4:
return instruction.ft();
default:
return std::nullopt;
}
default:
return std::nullopt;
}
}
std::optional<int> VuInstructionDecoder::lower_src(int index) const
std::optional<int> VuInstructionDecoder::try_get_src_field(int idx) const
{
const std::optional<VuDecodeInfo>* src_regs[3] = {
&decoded_inst_lower.source_reg_1,
&decoded_inst_lower.source_reg_2,
&decoded_inst_lower.source_reg_3};
VuInstructionType decoded = decode_instruction();
if (src_regs[index]->has_value())
switch (idx)
{
VuDecodeInfo value = src_regs[index]->value();
if (auto ptr = std::get_if<Bitfield>(&value))
case 0: switch (decoded)
{
return ptr->extract_from(lower_inst.value);
}
}
case VuInstructionType::UpperType0:
case VuInstructionType::UpperType1:
case VuInstructionType::UpperType2:
case VuInstructionType::UpperType3:
case VuInstructionType::UpperType1_ACC:
case VuInstructionType::UpperType2_ACC:
case VuInstructionType::UpperType3_ACC:
case VuInstructionType::LowerType1:
case VuInstructionType::LowerType3:
case VuInstructionType::LowerType3_IT_FS:
case VuInstructionType::LowerType7:
case VuInstructionType::LowerType8:
return instruction.dest();
return std::nullopt;
case VuInstructionType::LowerType4:
case VuInstructionType::LowerType4_IT_FS:
return 1 << (3 - instruction.fsf());
default:
return std::nullopt;
}
case 1: switch (decoded)
{
case VuInstructionType::UpperType0:
case VuInstructionType::UpperType2:
case VuInstructionType::UpperType2_ACC:
return 1 << (3 - instruction.bc());
case VuInstructionType::UpperType1:
case VuInstructionType::UpperType1_ACC:
case VuInstructionType::UpperType3:
case VuInstructionType::UpperType3_ACC:
case VuInstructionType::LowerType1:
return instruction.dest();
case VuInstructionType::LowerType4:
return 1 << (3 - instruction.ftf());
default:
return std::nullopt;
}
default:
return std::nullopt;
}
}
bool VuInstructionDecoder::is_integer_instruction() const
{
VuInstructionType decoded = decode_instruction();
switch (decoded)
{
case VuInstructionType::LowerType1:
case VuInstructionType::LowerType3_I:
case VuInstructionType::LowerType3_IT_FS:
case VuInstructionType::LowerType4_IT_FS:
case VuInstructionType::LowerType5:
case VuInstructionType::LowerType7:
case VuInstructionType::LowerType7_I:
case VuInstructionType::LowerType8:
return true;
default:
return false;
}
}

View file

@ -6,86 +6,75 @@
#include "Common/Types/Bitfield.hpp"
#include "Resources/Ee/Vpu/Vu/VuInstruction.hpp"
enum class VuSpecialRegs
/// Used to store the type of the instruction. The type determines the fields in
/// which the instruction is going to have. This is required for VU data hazards
/// checking.
/// Note: Some instructions use the register fields differently, although the
/// formats are considered the same.
/// Note: OPCODE and OPCODE+BC are both 6 bits, OPCODE+0b1111+[*] is 11 bits.
enum class VuInstructionType
{
ACC,
CLIP,
I,
P,
PC, // program counter
Q,
R,
SF, // sticky flag
MAC // mac flag
};
typedef std::variant<Bitfield, VuSpecialRegs> VuDecodeInfo;
struct VuDecodedInst
{
// Used for storing the field specifier (dest, fsf/ftf, bc, etc..)
// Note: Integer GPRs do not have a field.
enum FieldSpecifier
{
FsfFtf = 0,
Dest = 1,
Bc = 2,
Int = 3,
};
// Default constructor
VuDecodedInst() :
dest_reg(std::nullopt),
source_reg_1(std::nullopt),
source_reg_2(std::nullopt),
source_reg_3(std::nullopt),
field(FieldSpecifier::Dest)
{
}
VuDecodedInst(
std::optional<VuDecodeInfo> dest,
std::optional<VuDecodeInfo> src_1,
std::optional<VuDecodeInfo> src_2,
std::optional<VuDecodeInfo> src_3,
int dest_field) :
dest_reg(dest),
source_reg_1(src_1),
source_reg_2(src_2),
source_reg_3(src_3),
field(dest_field)
{
}
std::optional<VuDecodeInfo> dest_reg;
std::optional<VuDecodeInfo> source_reg_1;
std::optional<VuDecodeInfo> source_reg_2;
std::optional<VuDecodeInfo> source_reg_3;
int field;
UpperType0, // DEST, FT, FS, FD, OPCODE+BC
UpperType1, // DEST, FT, FS, FD, OPCODE
UpperType2, // DEST, FT, FS, OPCODE+0b1111+BC
UpperType3, // DEST, FT, FS, OPCODE+0b1111+OPCODE
UpperType1_ACC, // DEST, FT, FS, FD, OPCODE; uses ACC
UpperType2_ACC, // DEST, FT, FS, OPCODE+0b1111+BC; uses ACC
UpperType3_ACC, // DEST, FT, FS, OPCODE+0b1111+OPCODE; uses ACC
LowerType1, // DEST, FT, FS, FD, OPCODE
LowerType1_I, // DEST, IT, IS, ID, OPCODE
LowerType2, // (unspecified)
LowerType3, // DEST, FT, FS, OPCODE+0b1111+OPCODE
LowerType3_I, // DEST, IT, IS, OPCODE+0b1111+OPCODE
LowerType3_IT_FS, // DEST, IT, FS, OPCODE+0b1111+OPCODE
LowerType3_FT_IS, // DEST, FT, IS, OPCODE+0b1111+OPCODE
LowerType4, // FTF+FSF, FT, FS, OPCODE+0b1111+OPCODE
LowerType4_IT_FS, // FTF+FSF, IT, FS, OPCODE+0b1111+OPCODE
LowerType5, // DEST, IT, IS, IMM5, OPCODE
LowerType6, // (unspecified)
LowerType7, // DEST, IT, FS, IMM11
LowerType7_I, // DEST, IT, IS, IMM11
LowerType7_FT_IS, // DEST, FT, IS, IMM11
LowerType8, // LOWER OP, IMM15, IT, IS, IMM15
LowerType9, // LOWER OP, 0b0, IMM24
};
/// The name says all. Contains some helper functions to ease instruction
/// decoding.
class VuInstructionDecoder
{
public:
VuInstructionDecoder(const VuInstruction lower, const VuInstruction upper);
VuInstructionDecoder(const VuInstruction inst, const MipsInstructionInfo info) :
instruction(inst),
instruction_info(info)
{
}
const VuDecodedInst& decode_lower() const;
const VuDecodedInst& decode_upper() const;
/// Decodes the instruction, returning the type of the instruction.
/// See VuInstructionType for more details.
VuInstructionType decode_instruction() const;
const VuInstruction& get_lower_inst() const;
const VuInstruction& get_upper_inst() const;
/// Obtains the location of destination register, if it is specified by
/// the instruction.
/// Note: This function returns nullopt for non-VF/non-VI destinations.
std::optional<int> try_get_dest() const;
std::optional<int> lower_dest() const;
std::optional<int> upper_dest() const;
/// Obtains the field specified by the instruction.
std::optional<int> try_get_dest_field() const;
std::optional<int> lower_src(int index) const;
std::optional<int> upper_src(int index) const;
/// Obtains the location of source register, if specified by the instruction.
/// Some instructions specify 2 or more registers, therefore idx is required
/// to specify which source register to obtain.
/// Note: This function returns nullopt for special sources.
std::optional<int> try_get_src(int idx) const;
private:
VuInstruction lower_inst;
VuInstruction upper_inst;
/// Obtains the field specified by the instruction.
std::optional<int> try_get_src_field(int idx) const;
VuDecodedInst decoded_inst_lower;
VuDecodedInst decoded_inst_upper;
/// Returns true if the instruction uses VI registers as its destination.
bool is_integer_instruction() const;
VuInstruction instruction;
MipsInstructionInfo instruction_info;
};