mirror of
https://github.com/hch12907/orbum.git
synced 2024-06-02 19:38:16 -04:00
171 lines
4.5 KiB
C++
171 lines
4.5 KiB
C++
#include <stdexcept>
|
|
|
|
#include "Resources/Iop/Timers/IopTimersUnitRegisters.hpp"
|
|
|
|
#include "Core.hpp"
|
|
|
|
IopTimersUnitRegister_Count::IopTimersUnitRegister_Count(const bool b32_mode) :
|
|
is_using_32b_mode(b32_mode),
|
|
is_overflowed(false),
|
|
prescale_target(1),
|
|
prescale_count(0)
|
|
{
|
|
}
|
|
|
|
void IopTimersUnitRegister_Count::increment(const uword value)
|
|
{
|
|
if (!is_using_32b_mode)
|
|
increment_16(value);
|
|
else
|
|
increment_32(value);
|
|
}
|
|
|
|
bool IopTimersUnitRegister_Count::is_overflowed_and_reset()
|
|
{
|
|
bool temp = is_overflowed;
|
|
is_overflowed = false;
|
|
return temp;
|
|
}
|
|
|
|
void IopTimersUnitRegister_Count::reset_prescale(const int prescale_target)
|
|
{
|
|
write_uword(0);
|
|
|
|
this->prescale_target = prescale_target;
|
|
prescale_count = 0;
|
|
}
|
|
|
|
void IopTimersUnitRegister_Count::increment_16(const uhword value)
|
|
{
|
|
// Update only if the prescale threshold has been reached.
|
|
prescale_count += static_cast<int>(value);
|
|
if (prescale_count >= prescale_target)
|
|
{
|
|
uword count = read_uword();
|
|
|
|
while (prescale_count >= prescale_target)
|
|
{
|
|
count += 1;
|
|
prescale_count -= prescale_target;
|
|
}
|
|
|
|
if (count > VALUE_UHWORD_MAX)
|
|
{
|
|
count %= VALUE_UHWORD_MAX;
|
|
is_overflowed = true;
|
|
}
|
|
|
|
write_uword(count);
|
|
}
|
|
}
|
|
|
|
void IopTimersUnitRegister_Count::increment_32(const uword value)
|
|
{
|
|
// Update only if the prescale threshold has been reached.
|
|
prescale_count += static_cast<int>(value);
|
|
if (prescale_count >= prescale_target)
|
|
{
|
|
udword count = static_cast<udword>(read_uword());
|
|
|
|
while (prescale_count >= prescale_target)
|
|
{
|
|
count += 1;
|
|
prescale_count -= prescale_target;
|
|
}
|
|
|
|
if (count > VALUE_UWORD_MAX)
|
|
{
|
|
count %= VALUE_UWORD_MAX;
|
|
is_overflowed = true;
|
|
}
|
|
|
|
write_uword(static_cast<uword>(count));
|
|
}
|
|
}
|
|
|
|
IopTimersUnitRegister_Mode::IopTimersUnitRegister_Mode() :
|
|
write_latch(false)
|
|
{
|
|
}
|
|
|
|
void IopTimersUnitRegister_Mode::byte_bus_write_uhword(const BusContext context, const usize offset, const uhword value)
|
|
{
|
|
if (offset != 0)
|
|
throw std::runtime_error("Iop timers write hword offset not 0.");
|
|
|
|
auto _lock = scope_lock();
|
|
|
|
if (write_latch)
|
|
BOOST_LOG(Core::get_logger()) << "IOP Timer unit write latch was already set - please check (might be ok)!";
|
|
|
|
write_uhword(offset, value);
|
|
|
|
// Signal a timer unit reset is required.
|
|
write_latch = true;
|
|
}
|
|
|
|
void IopTimersUnitRegister_Mode::byte_bus_write_uword(const BusContext context, const usize offset, const uword value)
|
|
{
|
|
auto _lock = scope_lock();
|
|
|
|
// Signal a timer unit reset is required.
|
|
if (write_latch)
|
|
BOOST_LOG(Core::get_logger()) << "IOP Timer unit write latch was already set - please check (might be ok)!";
|
|
|
|
write_uword(value);
|
|
|
|
write_latch = true;
|
|
}
|
|
|
|
bool IopTimersUnitRegister_Mode::is_enabled()
|
|
{
|
|
bool irq_on_of = extract_field(IopTimersUnitRegister_Mode::IRQ_ON_OF) > 0;
|
|
bool irq_on_target = extract_field(IopTimersUnitRegister_Mode::IRQ_ON_TARGET) > 0;
|
|
return irq_on_of || irq_on_target;
|
|
}
|
|
|
|
std::pair<uword, ControllerEventType> IopTimersUnitRegister_Mode::get_properties(const int unit_id)
|
|
{
|
|
if (unit_id < 0 || unit_id > 5)
|
|
throw std::runtime_error("Invalid IOP timer index to determine clock source!");
|
|
|
|
// Sources are majorly different for each type of timer... no easy way of doing this... :( .
|
|
if (unit_id < 3)
|
|
{
|
|
// Check for Prescale8 (bit 9).
|
|
if (extract_field(PRESCALE0) > 0)
|
|
{
|
|
throw std::runtime_error("IOP Timers calculate_prescale_and_set_event() not fully implemented [0].");
|
|
}
|
|
else
|
|
{
|
|
if (extract_field(EVENT_SRC) == 0)
|
|
{
|
|
return std::make_pair(1, ControllerEventType::Time);
|
|
}
|
|
else
|
|
{
|
|
return std::make_pair(1, ControllerEventType::HBlank);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check for Prescale8/16/256 (bits 13 and 14).
|
|
if (extract_field(PRESCALE1) > 0)
|
|
{
|
|
throw std::runtime_error("IOP Timers calculate_prescale_and_set_event() not fully implemented [1].");
|
|
}
|
|
else
|
|
{
|
|
if (extract_field(EVENT_SRC) == 0)
|
|
{
|
|
return std::make_pair(1, ControllerEventType::Time);
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("IOP Timers calculate_prescale_and_set_event() not fully implemented [2].");
|
|
}
|
|
}
|
|
}
|
|
} |