VIF: Basic implementation

This commit is contained in:
hch12907 2018-11-19 22:09:49 +08:00
parent 17bb55c132
commit afcde2166d
5 changed files with 102 additions and 27 deletions

View file

@ -3,7 +3,6 @@
#include "Controller/Ee/Vpu/Vif/CVif.hpp"
#include "Core.hpp"
#include "Resources/RResources.hpp"
CVif::CVif(Core* core) :
CController(core)
@ -58,40 +57,72 @@ int CVif::time_step(const int ticks_available)
// Check the FIFO queue for incoming DMA packet. Exit early if there is nothing to process.
if (!unit->dma_fifo_queue->has_read_available(NUMBER_BYTES_IN_QWORD))
continue;
uqword packet;
unit->dma_fifo_queue->read(reinterpret_cast<ubyte*>(&packet), NUMBER_BYTES_IN_QWORD);
// We have an incoming DMA unit of data, now we must split it into 4 x 32-bit and process each one. // TODO: check wih pcsx2's code.
for (auto& data : packet.uw)
uqword raw_data;
unit->dma_fifo_queue->read(reinterpret_cast<ubyte*>(&raw_data), NUMBER_BYTES_IN_QWORD);
for (uword data : raw_data.uw)
{
// Check the NUM register, to determine if we are continuing a VIFcode instruction instead of reading a VIFcode.
if (unit->num.extract_field(VifUnitRegister_Num::NUM))
// Four VIF statuses: 0b00 Idle, 01 Waiting for data, 10 Decoding VIFcode, 11 Decompressing data
const ubyte status = unit->stat.extract_field(VifUnitRegister_Stat::VPS);
unit->processing_data = data;
// If the VIF is idling, treat the data as a VIFcode
if (!status)
{
unit->code.write_uword(data);
unit->inst = VifcodeInstruction(data);
unit->stat.insert_field(VifUnitRegister_Stat::VPS, 0b10);
unit->packets_left = obtain_required_words(unit->inst);
continue;
}
else
{
// Set the current data as the VIFcode.
VifcodeInstruction inst = VifcodeInstruction(data);
unit->packets_left--;
// Process the VIFcode by calling the instruction handler.
(this->*INSTRUCTION_TABLE[inst.get_info()->impl_index])(unit, inst);
(this->*INSTRUCTION_TABLE[unit->inst.get_info().impl_index])(unit, unit->inst);
// If the I bit is set, we need to raise an interrupt after the whole VIF packet has been processed - set a context variable.
/*
if (instruction.i())
// If there are no packets left, set the VIF status to idle
if (!unit->packets_left)
{
auto _lock = r.ee.intc.stat.scope_lock();
r.ee.intc.stat.insert_field(EeIntcRegister_Stat::VIF, 1);
unit->stat.insert_field(VifUnitRegister_Stat::VPS, 0b00);
// If the I bit is set, raise an interrupt
if (unit->inst.i())
{
auto _lock = r.ee.intc.stat.scope_lock();
r.ee.intc.stat.insert_field(EeIntcRegister_Stat::VIF_KEYS[unit->core_id], 1);
}
continue;
}
*/
}
}
}
// TODO: different for each unit...
return 1;
}
int CVif::obtain_required_words(const VifcodeInstruction instruction) const
{
switch (instruction.get_info()->cpi)
{
case SpecialVifcodePacketUsage::Num:
return 1 + instruction.num() * 2;
case SpecialVifcodePacketUsage::Immediate:
return 1 + instruction.imm() * 4;
case SpecialVifcodePacketUsage::Unpack:
return 10; // Fixme: This is COMPLETELY wrong
default:
return instruction.get_info()->cpi;
}
}
void CVif::INSTRUCTION_UNSUPPORTED(VifUnit_Base* unit, const VifcodeInstruction inst)
{
throw std::runtime_error("VIFcode CMD field was invalid! Please fix.");
@ -102,4 +133,4 @@ void CVif::NOP(VifUnit_Base* unit, const VifcodeInstruction inst)
{
// nothing to do
return;
}
}

View file

@ -2,6 +2,8 @@
#include "Common/Constants.hpp"
#include "Controller/CController.hpp"
#include "Resources/RResources.hpp"
#include "Resources/Ee/Gif/GifRegisters.hpp"
#include "Resources/Ee/Vpu/Vif/VifUnits.hpp"
#include "Resources/Ee/Vpu/Vif/VifcodeInstruction.hpp"
@ -89,4 +91,9 @@ public:
&CVif::DIRECTHL,
&CVif::UNPACK,
};
};
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;
};

View file

@ -14,6 +14,15 @@ public:
/// ID of the VIF unit.
int core_id;
/// The instruction the VIF is currently processing.
VifcodeInstruction inst;
/// The data being processed by the VIF.
uword processing_data;
/// The amount of packets that are needed for processing.
uword packets_left;
/// DMA FIFO queue.
DmaFifoQueue<>* dma_fifo_queue;

View file

@ -19,10 +19,10 @@ MipsInstructionInfo VIFCODE_INSTRUCTION_TABLE[21] =
{"STMASK", 15, 2},
{"STROW", 16, 5},
{"STCOL", 17, 5},
{"MPG", 18, 10},
{"DIRECT", 19, 10},
{"DIRECTHL", 20, 10},
{"UNPACK", 21, 100}};
{"MPG", 18, SpecialVifcodePacketUsage::Num},
{"DIRECT", 19, SpecialVifcodePacketUsage::Immediate},
{"DIRECTHL", 20, SpecialVifcodePacketUsage::Immediate},
{"UNPACK", 21, SpecialVifcodePacketUsage::Unpack}};
VifcodeInstruction::VifcodeInstruction(const uword value) :
MipsInstruction(value),

View file

@ -4,6 +4,18 @@
#include "Common/Types/Mips/MipsInstructionInfo.hpp"
#include "Common/Types/Primitive.hpp"
/// Some VIFcode use an arbitrary amount of packets (such as MPG) while others
/// use a fixed amount of packets. Thus, for those special VIFcodes we use magic
/// numbers to store their packet length. (100 and above ought to be enough... right?)
struct SpecialVifcodePacketUsage
{
enum {
Num = 100,
Immediate = 200,
Unpack = 300,
};
};
/// A VIFcode type, as explained on page 87 of the EE Users Manual.
/// Although a VIF transfer packet is 128-bit long, the VIFcode part is 32-bit.
struct VifcodeInstruction : public MipsInstruction
@ -11,8 +23,14 @@ struct VifcodeInstruction : public MipsInstruction
static constexpr Bitfield IMM = Bitfield(0, 16);
static constexpr Bitfield NUM = Bitfield(16, 8);
static constexpr Bitfield CMD = Bitfield(24, 8);
static constexpr Bitfield CMDHI = Bitfield(29, 2);
static constexpr Bitfield CMDLO = Bitfield(24, 5);
static constexpr Bitfield CMDHI = Bitfield(29, 2);
static constexpr Bitfield I = Bitfield(31, 1);
// Used by UNPACK
static constexpr Bitfield VL = Bitfield(24, 2);
static constexpr Bitfield VN = Bitfield(26, 2);
static constexpr Bitfield M = Bitfield(28, 1);
VifcodeInstruction(const uword value);
@ -43,8 +61,18 @@ struct VifcodeInstruction : public MipsInstruction
return static_cast<ubyte>(CMDHI.extract_from(value));
}
ubyte i() const
{
return static_cast<ubyte>(I.extract_from(value));
}
ubyte m() const
{
return static_cast<ubyte>(M.extract_from(value));
}
/// Performs a lookup if required and returns the instruction details.
const MipsInstructionInfo* get_info()
const MipsInstructionInfo* get_info() const
{
if (!info)
info = lookup();
@ -53,7 +81,7 @@ struct VifcodeInstruction : public MipsInstruction
private:
/// Instruction information (from performing lookup).
MipsInstructionInfo* info;
mutable MipsInstructionInfo* info;
/// Determines what instruction this is by performing a lookup.
MipsInstructionInfo* lookup() const;