VIF: Correctly calculate UNPACK subpacket length

This commit is contained in:
hch12907 2018-12-14 18:07:15 +08:00
parent c15fd1fba1
commit 62a7df628f
5 changed files with 58 additions and 26 deletions

View file

@ -80,7 +80,7 @@ int CVif::time_step(const int ticks_available)
unit->code.write_uword(data);
unit->inst = std::make_unique<VifcodeInstruction>(data);
unit->stat.insert_field(VifUnitRegister_Stat::VPS, 0b10);
unit->subpackets_left = obtain_required_words(*unit->inst);
unit->subpackets_left = obtain_required_words(*unit, *unit->inst);
BOOST_LOG(Core::get_logger()) << "VIF: Fetched instruction " << unit->inst->get_info()->mnemonic;
continue;
}
@ -116,18 +116,50 @@ int CVif::time_step(const int ticks_available)
return 1;
}
int CVif::obtain_required_words(const VifcodeInstruction instruction) const
int CVif::obtain_required_words(const VifUnit_Base& unit, const VifcodeInstruction inst) const
{
switch (instruction.get_info()->cpi)
switch (inst.get_info()->cpi)
{
case SpecialVifcodePacketUsage::Num:
return 1 + (instruction.num() ? instruction.num() : 256) * 2;
// branchless version of `1 + inst.num() ? inst.num() : 256` (0 = 2^8)
return 1 + (((inst.num() - 1) & 0xFF) + 1) * 2;
case SpecialVifcodePacketUsage::Immediate:
return 1 + (instruction.imm() ? instruction.imm() : 65536) * 4;
// branchless version of `1 + inst.imm() ? inst.imm() : 65536` (0 = 2^16)
return 1 + (((inst.imm() - 1) & 0xFFFF) + 1) * 4;
case SpecialVifcodePacketUsage::Unpack:
const int cl = unit.cycle.extract_field(VifUnitRegister_Cycle::CL);
const int wl = unit.cycle.extract_field(VifUnitRegister_Cycle::WL);
// The length of each element, in bits
const int element_length = 32 >> inst.vl();
// The number of elements in each data
const int num_of_element = inst.vn() + 1;
if (wl > cl)
{
// The number of data
const int data_num = cl * (inst.num() / wl) + std::min(inst.num() % wl, cl);
// The length of the data in bits
const int data_length = element_length * num_of_element * data_num;
// The length of the data in words (quotient is rounded up if there are remainders, hence the +31)
const int data_words = (data_length + 31) >> 5;
return 1 + data_words;
}
else
{
// The length of the data in bits
const int data_length = element_length * num_of_element * inst.num();
// The length of the data in words (quotient is rounded up if there are remainders, hence the +31)
const int data_words = (data_length + 31) >> 5;
return 1 + data_words;
}
default:
return instruction.get_info()->cpi;
return inst.get_info()->cpi;
}
}

View file

@ -106,5 +106,5 @@ public:
private:
/// Obtains the amount of words (a packet holds 4 subpackets, each subpacket is a
/// word long) required for the instruction.
int obtain_required_words(const VifcodeInstruction inst) const;
int obtain_required_words(const VifUnit_Base& unit, const VifcodeInstruction inst) const;
};

View file

@ -94,7 +94,7 @@ void CVif::STMASK(VifUnit_Base* unit, const VifcodeInstruction inst)
void CVif::STROW(VifUnit_Base* unit, const VifcodeInstruction inst)
{
if (unit->subpackets_left >= obtain_required_words(inst))
if (unit->subpackets_left >= obtain_required_words(*unit, inst))
return;
SizedWordRegister *const row_regs[4] = { &unit->r3, &unit->r2, &unit->r1, &unit->r0 };
@ -104,7 +104,7 @@ void CVif::STROW(VifUnit_Base* unit, const VifcodeInstruction inst)
void CVif::STCOL(VifUnit_Base* unit, const VifcodeInstruction inst)
{
if (unit->subpackets_left >= obtain_required_words(inst))
if (unit->subpackets_left >= obtain_required_words(*unit, inst))
return;
SizedWordRegister *const col_regs[4] = { &unit->c3, &unit->c2, &unit->c1, &unit->c0 };

View file

@ -19,14 +19,14 @@ void CVif::MPG(VifUnit_Base* unit, const VifcodeInstruction inst)
}
// First pass - decoding VIF code & obtaining the num
if (unit->subpackets_left == obtain_required_words(inst))
if (unit->subpackets_left == obtain_required_words(*unit, inst))
{
unit->num.write_uword(inst.num());
unit->stat.insert_field(VifUnitRegister_Stat::VFS, 0b11);
}
// Other passes - transfer data to VU mem
if (unit->subpackets_left < obtain_required_words(inst))
if (unit->subpackets_left < obtain_required_words(*unit, inst))
{
const uword starting_addr = inst.imm() * 8;
const uword offset = (inst.num() - unit->num.read_uword()) * 4 + unit->packet_progress;
@ -47,7 +47,7 @@ void CVif::DIRECT(VifUnit_Base* unit, const VifcodeInstruction inst)
}
// Do nothing in the first pass
if (unit->subpackets_left >= obtain_required_words(inst))
if (unit->subpackets_left >= obtain_required_words(*unit, inst))
{
return;
}
@ -68,7 +68,7 @@ void CVif::DIRECTHL(VifUnit_Base* unit, const VifcodeInstruction inst)
}
// Do nothing in the first pass
if (unit->subpackets_left >= obtain_required_words(inst))
if (unit->subpackets_left >= obtain_required_words(*unit, inst))
{
return;
}

View file

@ -22,19 +22,19 @@ MipsInstructionInfo VIFCODE_INSTRUCTION_TABLE[34] =
{"MPG", 18, SpecialVifcodePacketUsage::Num},
{"DIRECT", 19, SpecialVifcodePacketUsage::Immediate},
{"DIRECTHL", 20, SpecialVifcodePacketUsage::Immediate},
{"UNPACK_S_32", 21, 4},
{"UNPACK_S_16", 22, 3},
{"UNPACK_S_8", 23, 2},
{"UNPACK_V2_32", 24, 7},
{"UNPACK_V2_16", 25, 4},
{"UNPACK_V2_8", 26, 3},
{"UNPACK_V3_32", 27, 10},
{"UNPACK_V3_16", 28, 6},
{"UNPACK_V3_8", 29, 4},
{"UNPACK_V4_32", 30, 13},
{"UNPACK_V4_16", 31, 7},
{"UNPACK_V4_8", 32, 4},
{"UNPACK_V4_5", 33, 3},
{"UNPACK_S_32", 21, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_S_16", 22, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_S_8", 23, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V2_32", 24, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V2_16", 25, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V2_8", 26, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V3_32", 27, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V3_16", 28, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V3_8", 29, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V4_32", 30, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V4_16", 31, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V4_8", 32, SpecialVifcodePacketUsage::Unpack},
{"UNPACK_V4_5", 33, SpecialVifcodePacketUsage::Unpack},
{"UNKNOWN", 0, 1}};
VifcodeInstruction::VifcodeInstruction(const uword value) :