mirror of
https://github.com/hch12907/orbum.git
synced 2024-06-01 19:08:05 -04:00
VIF: Basic implementation
This commit is contained in:
parent
17bb55c132
commit
afcde2166d
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue