Mesen-SX/Core/AluMulDiv.cpp

136 lines
2.5 KiB
C++
Raw Normal View History

#include "stdafx.h"
#include "AluMulDiv.h"
#include "Cpu.h"
2019-10-10 23:54:38 -04:00
#include "InternalRegisterTypes.h"
#include "../Utilities/Serializer.h"
2019-08-09 11:45:20 -04:00
void AluMulDiv::Initialize(Cpu* cpu)
{
_cpu = cpu;
2019-10-10 23:54:38 -04:00
_state = {};
_state.MultOperand1 = 0xFF;
_state.Dividend = 0xFFFF;
}
void AluMulDiv::Run(bool isRead)
{
uint64_t cpuCycle = _cpu->GetCycleCount();
2020-12-19 23:30:09 +03:00
if (isRead)
{
//Run 1 cycle less for read operations, since they occur earlier within the CPU cycle, compared to a write
cpuCycle--;
}
2020-12-19 23:30:09 +03:00
if (_multCounter != 0 || _divCounter != 0)
{
uint64_t cyclesToRun = cpuCycle - _prevCpuCycle;
2020-12-19 23:30:09 +03:00
while (cyclesToRun--)
{
if (!_multCounter && !_divCounter)
{
break;
}
2020-12-19 23:30:09 +03:00
if (_multCounter > 0)
{
_multCounter--;
2020-12-19 23:30:09 +03:00
if (_state.DivResult & 0x01)
{
2019-10-10 23:54:38 -04:00
_state.MultOrRemainderResult += _shift;
}
_shift <<= 1;
2019-10-10 23:54:38 -04:00
_state.DivResult >>= 1;
}
2020-12-19 23:30:09 +03:00
if (_divCounter > 0)
{
_divCounter--;
_shift >>= 1;
2019-10-10 23:54:38 -04:00
_state.DivResult <<= 1;
2020-12-19 23:30:09 +03:00
if (_state.MultOrRemainderResult >= _shift)
{
2019-10-10 23:54:38 -04:00
_state.MultOrRemainderResult -= _shift;
_state.DivResult |= 1;
}
}
}
}
2020-12-19 23:30:09 +03:00
_prevCpuCycle = cpuCycle;
}
uint8_t AluMulDiv::Read(uint16_t addr)
{
Run(true);
2020-12-19 23:30:09 +03:00
switch (addr)
{
case 0x4214: return (uint8_t)_state.DivResult;
case 0x4215: return (uint8_t)(_state.DivResult >> 8);
2020-12-19 23:30:09 +03:00
case 0x4216: return (uint8_t)_state.MultOrRemainderResult;
case 0x4217: return (uint8_t)(_state.MultOrRemainderResult >> 8);
}
throw std::runtime_error("ALU: invalid address");
}
void AluMulDiv::Write(uint16_t addr, uint8_t value)
{
Run(false);
2020-12-19 23:30:09 +03:00
switch (addr)
{
case 0x4202: _state.MultOperand1 = value;
break;
case 0x4203:
_state.MultOrRemainderResult = 0;
if (!_divCounter && !_multCounter)
{
_multCounter = 8;
_state.MultOperand2 = value;
_state.DivResult = (value << 8) | _state.MultOperand1;
_shift = value;
}
break;
2020-12-19 23:30:09 +03:00
case 0x4204: _state.Dividend = (_state.Dividend & 0xFF00) | value;
break;
case 0x4205: _state.Dividend = (_state.Dividend & 0xFF) | (value << 8);
break;
case 0x4206:
_state.MultOrRemainderResult = _state.Dividend;
if (!_divCounter && !_multCounter)
{
_divCounter = 16;
_state.Divisor = value;
_shift = (value << 16);
}
break;
2020-12-19 23:30:09 +03:00
default: throw std::runtime_error("ALU: invalid address");
}
}
2019-10-10 23:54:38 -04:00
AluState AluMulDiv::GetState()
{
return _state;
}
2020-12-19 23:30:09 +03:00
void AluMulDiv::Serialize(Serializer& s)
{
s.Stream(
2020-12-19 23:30:09 +03:00
_state.MultOperand1, _state.MultOperand2, _state.MultOrRemainderResult, _state.Dividend, _state.Divisor,
_state.DivResult,
_divCounter, _multCounter, _shift, _prevCpuCycle
);
}