VPU: Split VPU0/1 into two threads

- VU and VIF are no longer on separate threads
- Instead, they are now on the same "VPU" thread
- VPU is the one which is threaded now - VPU0/1 run on separate threads

This is done to (hopefully!) improve synchronization
This commit is contained in:
hch12907 2019-01-26 00:24:35 +08:00
parent 65b1ae5dd2
commit 3b6cc1f701
13 changed files with 346 additions and 210 deletions

View file

@ -86,6 +86,8 @@ set(COMMON_SRC_FILES
"${CMAKE_SOURCE_DIR}/liborbum/src/Controller/Ee/Vpu/Vif/CVif_SET.cpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Controller/Ee/Vpu/Vif/CVif_TRANSFER.cpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Controller/Ee/Vpu/Vif/CVif_UNPACK.cpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Controller/Ee/Vpu/CVpu.cpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Controller/Ee/Vpu/CVpu.hpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Controller/Ee/Vpu/Vu/CVu.cpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Controller/Ee/Vpu/Vu/CVu.hpp"
"${CMAKE_SOURCE_DIR}/liborbum/src/Controller/Ee/Vpu/Vu/Interpreter/CVuInterpreter.cpp"

View file

@ -8,7 +8,7 @@
CEeCoreInterpreter::CEeCoreInterpreter(Core* core) :
CEeCore(core),
c_vu_interpreter(core)
c_vu_interpreter(core, 0)
{
}

View file

View file

@ -0,0 +1,75 @@
#pragma once
#include "Controller/CController.hpp"
#include "Controller/ControllerEvent.hpp"
#include "Controller/Ee/Vpu/Vif/CVif.hpp"
#include "Controller/Ee/Vpu/Vu/CVu.hpp"
#include "Core.hpp"
class Core;
template<typename VuController>
class CVpu : public CController
{
public:
CVpu(Core* core, int id) :
CController(core),
core_id(id),
vif(CVif(core, id)),
vu(VuController(core, id))
{
}
void handle_event(const ControllerEvent& event)
{
switch (event.type)
{
case ControllerEvent::Type::Time:
{
int ticks_remaining = time_to_ticks(event.data.time_us);
while (ticks_remaining > 0)
ticks_remaining -= time_step(ticks_remaining);
break;
}
default:
{
throw std::runtime_error("CVpu event handler not implemented - please fix!");
}
}
}
/// Runs the VU and VIF.
int time_step(const int ticks_available)
{
// Run VIF and VU for one cycle.
vif.time_step(1);
vu.time_step(1);
return 1;
}
private:
/// Converts a time duration into the number of ticks that would have occurred.
int time_to_ticks(const double time_us)
{
int ticks = static_cast<int>(time_us / 1.0e6 * Constants::EE::VPU::VU::VU_CLK_SPEED * core->get_options().system_bias_vu);
if (ticks < 10)
{
static bool warned = false;
if (!warned)
{
BOOST_LOG(Core::get_logger()) << "VPU ticks too low - increase time delta";
warned = true;
}
}
return ticks;
}
/// The ID of the VPU.
int core_id;
/// VU/VIF executors (can be recompiler or interpreter)
CVif vif;
VuController vu;
};

View file

@ -4,8 +4,9 @@
#include "Core.hpp"
CVif::CVif(Core* core) :
CController(core)
CVif::CVif(Core* core, int id) :
CController(core),
core_id(id)
{
}
@ -48,80 +49,108 @@ int CVif::time_step(const int ticks_available)
{
auto& r = core->get_resources();
for (auto& unit : r.ee.vpu.vif.units)
VifUnit_Base* unit = r.ee.vpu.vif.units[core_id];
// If STC is written, reset the following fields of VIF.STAT:
// VSS, VFS, VIS, INT, ER0, ER1
if (unit->fbrst.extract_field(VifUnitRegister_Fbrst::STC))
{
// If STC is written, reset the following fields of VIF.STAT:
// VSS, VFS, VIS, INT, ER0, ER1
if (unit->fbrst.extract_field(VifUnitRegister_Fbrst::STC))
{
uword stat = unit->stat.read_uword();
stat = VifUnitRegister_Stat::VSS.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::VFS.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::VIS.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::INT.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::ER0.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::ER1.insert_into(stat, 0u);
uword stat = unit->stat.read_uword();
stat = VifUnitRegister_Stat::VSS.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::VFS.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::VIS.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::INT.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::ER0.insert_into(stat, 0u);
stat = VifUnitRegister_Stat::ER1.insert_into(stat, 0u);
unit->stat.write_uword(stat);
unit->stat.write_uword(stat);
}
// Check if VIF is stalled, do not do anything (FBRST.STC needs to be written to before we return).
if (unit->stat.is_stalled())
return 1;
// If the VIF is waiting for the VU, run the current instruction and call it a day
if (unit->stat.extract_field(VifUnitRegister_Stat::VEW))
{
(this->*INSTRUCTION_TABLE[unit->inst->get_info()->impl_index])(unit, *unit->inst);
return 1;
}
// 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))
return 1;
// 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);
// Check for STP
if (!status && unit->fbrst.extract_field(VifUnitRegister_Fbrst::STP))
{
unit->stat.insert_field(VifUnitRegister_Stat::VSS, 1);
unit->fbrst.insert_field(VifUnitRegister_Fbrst::STP, 0);
return 1;
}
// If RST is written, reset the VIF
if (!status && unit->fbrst.extract_field(VifUnitRegister_Fbrst::RST))
{
BOOST_LOG(Core::get_logger()) << "VIF: Resetting VIF" << unit->core_id;
unit->fbrst.insert_field(VifUnitRegister_Fbrst::RST, 0);
// Reinitialize the VIF unit
unit->dma_fifo_queue->initialize();
*unit = VifUnit_Base(unit->core_id, unit->dma_fifo_queue);
return 1;
}
for (int i = unit->packet_progress; i < NUMBER_WORDS_IN_QWORD; i++, unit->packet_progress = i)
{
unit->dma_fifo_queue->read(reinterpret_cast<ubyte*>(&unit->processing_data), NUMBER_BYTES_IN_WORD);
const uword& data = unit->processing_data;
// If the VIF is idling, treat the data as a VIFcode
if (!status)
{
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, *unit->inst);
BOOST_LOG(Core::get_logger()) << "VIF: Fetched instruction " << unit->inst->get_info()->mnemonic;
return 1;
}
// Check if VIF is stalled, do not do anything (FBRST.STC needs to be written to before we continue).
if (unit->stat.is_stalled())
continue;
// If the VIF is waiting for the VU, run the current instruction and call it a day
if (unit->stat.extract_field(VifUnitRegister_Stat::VEW))
else
{
(this->*INSTRUCTION_TABLE[unit->inst->get_info()->impl_index])(unit, *unit->inst);
continue;
}
// 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;
// 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);
// Check for STP
if (!status && unit->fbrst.extract_field(VifUnitRegister_Fbrst::STP))
{
unit->stat.insert_field(VifUnitRegister_Stat::VSS, 1);
unit->fbrst.insert_field(VifUnitRegister_Fbrst::STP, 0);
continue;
}
// If RST is written, reset the VIF
if (!status && unit->fbrst.extract_field(VifUnitRegister_Fbrst::RST))
{
BOOST_LOG(Core::get_logger()) << "VIF: Resetting VIF" << unit->core_id;
unit->fbrst.insert_field(VifUnitRegister_Fbrst::RST, 0);
// Reinitialize the VIF unit
unit->dma_fifo_queue->initialize();
*unit = VifUnit_Base(unit->core_id, unit->dma_fifo_queue);
continue;
}
for (int i = unit->packet_progress; i < NUMBER_WORDS_IN_QWORD; i++, unit->packet_progress = i)
{
unit->dma_fifo_queue->read(reinterpret_cast<ubyte*>(&unit->processing_data), NUMBER_BYTES_IN_WORD);
const uword& data = unit->processing_data;
// If the VIF is idling, treat the data as a VIFcode
if (!status)
// If there are no packets left, set the VIF status to idle
if (!unit->subpackets_left)
{
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, *unit->inst);
BOOST_LOG(Core::get_logger()) << "VIF: Fetched instruction " << unit->inst->get_info()->mnemonic;
continue;
unit->stat.insert_field(VifUnitRegister_Stat::VPS, 0b00);
// If the VIF is idling, treat the data as a VIFcode
if (!status)
{
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, *unit->inst);
// If the VIFcode is valid, set ER1 to 0
if (!unit->inst->get_info()->impl_index)
{
unit->stat.insert_field(VifUnitRegister_Stat::ER1, 0);
}
BOOST_LOG(Core::get_logger()) << "VIF: Fetched instruction " << unit->inst->get_info()->mnemonic;
// TODO: confirm behaviour
// Does it take one whole cycle for the VIF to process a VIFcode?
return 1;
}
}
else
{
unit->subpackets_left--;
// If there are no packets left, set the VIF status to idle
if (!unit->subpackets_left)
{
@ -135,7 +164,7 @@ int CVif::time_step(const int ticks_available)
r.ee.intc.stat.insert_field(EeIntcRegister_Stat::VIF_KEYS[unit->core_id], 1);
}
continue;
return 1;
}
unit->subpackets_left--;
@ -143,11 +172,11 @@ int CVif::time_step(const int ticks_available)
(this->*INSTRUCTION_TABLE[unit->inst->get_info()->impl_index])(unit, *unit->inst);
}
}
}
if (unit->packet_progress >= NUMBER_WORDS_IN_QWORD)
{
unit->packet_progress = 0;
}
if (unit->packet_progress >= NUMBER_WORDS_IN_QWORD)
{
unit->packet_progress = 0;
}
return 1;
@ -209,6 +238,8 @@ void CVif::INSTRUCTION_UNSUPPORTED(VifUnit_Base* unit, const VifcodeInstruction
return NOP(unit, inst);
}
unit->stat.insert_field(VifUnitRegister_Stat::ER1, 1);
throw std::runtime_error("VIFcode CMD field was invalid! Please fix.");
}
@ -218,3 +249,19 @@ void CVif::NOP(VifUnit_Base* unit, const VifcodeInstruction inst)
// nothing to do
return;
}
template <typename T>
void CVif::write_vu_mem(VifUnit_Base* unit, const uword offset, const T data)
{
RResources& r = core->get_resources();
ArrayByteMemory& vu_mem = *r.ee.vpu.vu.units[unit->core_id]->vu_mem;
const uword vu_addr = unit->inst->addr();
}
// Implement write_vu_mem(..) only for selected types
// Note: the requirement for T is 4 bytes long
template void CVif::write_vu_mem<uword>(VifUnit_Base* unit, const uword offset, const uword data);
template void CVif::write_vu_mem<sword>(VifUnit_Base* unit, const uword offset, const sword data);
template void CVif::write_vu_mem< f32 >(VifUnit_Base* unit, const uword offset, const f32 data);

View file

@ -15,7 +15,7 @@ class Core;
class CVif : public CController
{
public:
CVif(Core* core);
CVif(Core* core, int id);
void handle_event(const ControllerEvent& event) override;
@ -107,4 +107,11 @@ 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 VifUnit_Base& unit, const VifcodeInstruction inst) const;
/// Stores the ID of the VIF.
int core_id;
/// A helper function for writing data to the VU mem.
template<typename T>
void write_vu_mem(VifUnit_Base* unit, const uword offset, const T data);
};

View file

@ -5,6 +5,7 @@
void CVif::UNPACK_S_32(VifUnit_Base* unit, const VifcodeInstruction inst)
{
}
void CVif::UNPACK_S_16(VifUnit_Base* unit, const VifcodeInstruction inst)

View file

@ -4,8 +4,9 @@
#include "Resources/RResources.hpp"
CVu::CVu(Core* core) :
CController(core)
CVu::CVu(Core* core, int id) :
CController(core),
core_id(id)
{
}

View file

@ -9,14 +9,18 @@ class Core;
class CVu : public CController
{
public:
CVu(Core* core);
CVu(Core* core, int id);
void handle_event(const ControllerEvent& event) override;
/// Steps through the VU core state, executing one macro and one micro instruction.
virtual int time_step(const int ticks_available) = 0;
protected:
/// Stores the ID of the VU
int core_id;
private:
/// Converts a time duration into the number of ticks that would have occurred.
int time_to_ticks(const double time_us);
};
};

View file

@ -7,8 +7,8 @@
#include "Core.hpp"
#include "Resources/RResources.hpp"
CVuInterpreter::CVuInterpreter(Core* core) :
CVu(core)
CVuInterpreter::CVuInterpreter(Core* core, int id) :
CVu(core, id)
{
}
@ -20,149 +20,148 @@ int CVuInterpreter::time_step(const int ticks_available)
RResources& r = core->get_resources();
for (auto* unit : r.ee.vpu.vu.units)
VuUnit_Base* const unit = r.ee.vpu.vu.units[core_id];
// Move on if the unit is not running and the delay slot is empty
if (unit->operation_state != VuOperationState::Run && !unit->bdelay.is_branch_pending())
{
// Move on if the unit is not running and the delay slot is empty
if (unit->operation_state != VuOperationState::Run && !unit->bdelay.is_branch_pending())
return 1;
}
// PC & Instructions stuff...
const uword pc = unit->pc.read_uword() & 0x0FFF;
const udword raw_inst = unit->micro_mem->read_uword(pc);
const uword upper_raw_inst = (raw_inst >> 32) & 0xFFFFFFFF;
const VuInstruction upper_inst = VuInstruction(upper_raw_inst);
const MipsInstructionInfo upper_info = upper_inst.get_upper_info();
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.get_lower_info();
const VuInstructionDecoder lower_decoder = VuInstructionDecoder(lower_inst, lower_info);
// 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_decoder, data_hazard_occured);
this->LOI(unit, lower_inst);
// Advance PC and onto the next cycle
unit->bdelay.advance_pc(unit->pc);
return 1;
}
// If E (bit 62) is set, execute current and next instruction, and
// terminate the current micro subroutine
// Here we setup a delay slot for the next instruction
if ((raw_inst >> 62) & 1)
{
if (unit->bdelay.is_branch_pending())
{
continue;
BOOST_LOG(Core::get_logger()) << "Found E-bit in branch delay slot";
}
// PC & Instructions stuff...
const uword pc = unit->pc.read_uword() & 0x0FFF;
const udword raw_inst = unit->micro_mem->read_uword(pc);
// Don't actually branch
unit->bdelay.set_branch_itype(unit->pc, 0);
const uword upper_raw_inst = (raw_inst >> 32) & 0xFFFFFFFF;
const VuInstruction upper_inst = VuInstruction(upper_raw_inst);
const MipsInstructionInfo upper_info = upper_inst.get_upper_info();
const VuInstructionDecoder upper_decoder = VuInstructionDecoder(upper_inst, upper_info);
// Change the state of the VU
unit->operation_state = VuOperationState::Ready;
}
const uword lower_raw_inst = raw_inst & 0xFFFFFFFF;
const VuInstruction lower_inst = VuInstruction(lower_raw_inst);
const MipsInstructionInfo lower_info = lower_inst.get_lower_info();
const VuInstructionDecoder lower_decoder = VuInstructionDecoder(lower_inst, lower_info);
// 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)
// If M (bit 61) is set, then execute QMTC2 or CTC2 without interlocking
// (VU0 only)
if (((raw_inst >> 61) & 1) && unit->core_id == 0)
{
VuUnit_Vu0& vu = r.ee.vpu.vu.unit_0;
if (vu.transferred_reg.has_value())
{
fmac.consume_cycle(1);
*vu.ccr[vu.transferred_reg_location] = vu.transferred_reg.value();
vu.transferred_reg = std::nullopt;
}
}
// 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)
// If D (bit 60) and DE (in FBRST) is set, terminate the micro subroutine and interrupt
if ((raw_inst >> 60) & 1)
{
if (r.ee.vpu.vu.fbrst.de(unit->core_id))
{
execute_upper_instruction(unit, upper_decoder, data_hazard_occured);
this->LOI(unit, lower_inst);
// Advance PC and onto the next unit
unit->bdelay.advance_pc(unit->pc);
continue;
auto _lock = r.ee.intc.stat.scope_lock();
r.ee.intc.stat.insert_field(EeIntcRegister_Stat::VU_KEYS[unit->core_id], 1);
unit->operation_state = VuOperationState::Stop;
}
}
// If E (bit 62) is set, execute current and next instruction, and
// terminate the current micro subroutine
// Here we setup a delay slot for the next instruction
if ((raw_inst >> 62) & 1)
// If T (bit 59) and TE (in FBRST) is set, terminate the micro subroutine and interrupt
if ((raw_inst >> 59) & 1)
{
if (r.ee.vpu.vu.fbrst.te(unit->core_id))
{
if (unit->bdelay.is_branch_pending())
auto _lock = r.ee.intc.stat.scope_lock();
r.ee.intc.stat.insert_field(EeIntcRegister_Stat::VU_KEYS[unit->core_id], 1);
unit->operation_state = VuOperationState::Stop;
}
}
// Register writing priority, if both upper and lower inst write to the same
// register, the priority is: COP2 Transfer > Upper Inst > Lower Inst
try
{
// Try obtaining the destination (will throw if the instruction writes to non-VF/VI regs)
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 (!lower_decoder.is_integer_instruction())
{
if (upper_dest == lower_dest)
{
BOOST_LOG(Core::get_logger()) << "Found E-bit in branch delay slot";
}
// Don't actually branch
unit->bdelay.set_branch_itype(unit->pc, 0);
// Change the state of the VU
unit->operation_state = VuOperationState::Ready;
}
// If M (bit 61) is set, then execute QMTC2 or CTC2 without interlocking
// (VU0 only)
if (((raw_inst >> 61) & 1) && unit->core_id == 0)
{
VuUnit_Vu0& vu = r.ee.vpu.vu.unit_0;
if (vu.transferred_reg.has_value())
{
*vu.ccr[vu.transferred_reg_location] = vu.transferred_reg.value();
vu.transferred_reg = std::nullopt;
}
}
// If D (bit 60) and DE (in FBRST) is set, terminate the micro subroutine and interrupt
if ((raw_inst >> 60) & 1)
{
if (r.ee.vpu.vu.fbrst.de(unit->core_id))
{
auto _lock = r.ee.intc.stat.scope_lock();
r.ee.intc.stat.insert_field(EeIntcRegister_Stat::VU_KEYS[unit->core_id], 1);
unit->operation_state = VuOperationState::Stop;
}
}
// If T (bit 59) and TE (in FBRST) is set, terminate the micro subroutine and interrupt
if ((raw_inst >> 59) & 1)
{
if (r.ee.vpu.vu.fbrst.te(unit->core_id))
{
auto _lock = r.ee.intc.stat.scope_lock();
r.ee.intc.stat.insert_field(EeIntcRegister_Stat::VU_KEYS[unit->core_id], 1);
unit->operation_state = VuOperationState::Stop;
}
}
// Register writing priority, if both upper and lower inst write to the same
// register, the priority is: COP2 Transfer > Upper Inst > Lower Inst
try
{
// Try obtaining the destination (will throw if the instruction writes to non-VF/VI regs)
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 (!lower_decoder.is_integer_instruction())
{
if (upper_dest == lower_dest)
{
SizedQwordRegister original_vf = unit->vf[upper_dest];
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, upper_decoder, data_hazard_occured);
}
}
else
{
// Otherwise just run it as usual
execute_upper_instruction(unit, upper_decoder, data_hazard_occured);
SizedQwordRegister original_vf = unit->vf[upper_dest];
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, upper_decoder, data_hazard_occured);
}
}
catch (std::exception)
else
{
// If one of them write to special regs (P, Q, etc), execute like usual
// Otherwise just run it as usual
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, upper_decoder, lower_decoder))
unit->bdelay.advance_pc(unit->pc);
}
catch (std::exception)
{
// If one of them write to special regs (P, Q, etc), execute like usual
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, upper_decoder, lower_decoder))
unit->bdelay.advance_pc(unit->pc);
// TODO: Correct CPI
return 1;

View file

@ -11,7 +11,7 @@ class Core;
class CVuInterpreter : public CVu
{
public:
CVuInterpreter(Core* core);
CVuInterpreter(Core* core, int id);
/// Steps through the VU core state, executing one macro and one micro instruction.
int time_step(const int ticks_available) override;

View file

@ -24,7 +24,7 @@
#include "Controller/Ee/Intc/CEeIntc.hpp"
#include "Controller/Ee/Ipu/CIpu.hpp"
#include "Controller/Ee/Timers/CEeTimers.hpp"
#include "Controller/Ee/Vpu/Vif/CVif.hpp"
#include "Controller/Ee/Vpu/CVpu.hpp"
#include "Controller/Ee/Vpu/Vu/Interpreter/CVuInterpreter.hpp"
#include "Controller/Gs/Core/CGsCore.hpp"
#include "Controller/Gs/Crtc/CCrtc.hpp"
@ -50,8 +50,8 @@ CoreOptions CoreOptions::make_default()
"",
"",
"",
10,
4, //std::thread::hardware_concurrency() - 1,
1,
8, //std::thread::hardware_concurrency() - 1,
1.0,
1.0,
@ -132,8 +132,8 @@ Core::Core(const CoreOptions& options) :
controllers[ControllerType::Type::EeIntc] = std::make_unique<CEeIntc>(this);
controllers[ControllerType::Type::Gif] = std::make_unique<CGif>(this);
controllers[ControllerType::Type::Ipu] = std::make_unique<CIpu>(this);
controllers[ControllerType::Type::Vif] = std::make_unique<CVif>(this);
controllers[ControllerType::Type::Vu] = std::make_unique<CVuInterpreter>(this);
controllers[ControllerType::Type::Vif] = std::make_unique<CVpu<CVuInterpreter>>(this, 0);
controllers[ControllerType::Type::Vu] = std::make_unique<CVpu<CVuInterpreter>>(this, 1);
controllers[ControllerType::Type::IopCore] = std::make_unique<CIopCoreInterpreter>(this);
controllers[ControllerType::Type::IopDmac] = std::make_unique<CIopDmac>(this);
controllers[ControllerType::Type::IopTimers] = std::make_unique<CIopTimers>(this);

View file

@ -23,10 +23,10 @@ public:
/// The data being processed by the VIF.
uword processing_data;
/// A packet has 4 subpackets. Which one are we processing now?
/// A packet has 4 subpackets (words) - this is nth subpacket we are processing
uword packet_progress;
/// The amount of packets that are needed for processing.
/// The amount of packets left for processing.
uword subpackets_left;
/// DMA FIFO queue.