Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Core/Core.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,7 @@
<ClCompile Include="Shared\Audio\WaveRecorder.cpp" />
<ClCompile Include="WS\APU\WsApu.cpp" />
<ClCompile Include="WS\Carts\WsCart.cpp" />
<ClCompile Include="WS\Carts\WsKarnak.cpp" />
<ClCompile Include="WS\Debugger\DummyWsCpu.cpp" />
<ClCompile Include="WS\Debugger\WsDebugger.cpp" />
<ClCompile Include="WS\Debugger\WsDisUtils.cpp" />
Expand Down
9 changes: 8 additions & 1 deletion Core/WS/Carts/WsCart.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "WS/Carts/WsKarnak.h"
#include "pch.h"
#include "WS/Carts/WsCart.h"
#include "WS/WsMemoryManager.h"
Expand All @@ -22,10 +23,12 @@ WsCart::WsCart()
_state.SelectedBanks[3] = 0xFF;
}

void WsCart::Init(WsMemoryManager* memoryManager, WsEeprom* cartEeprom)
void WsCart::Init(WsMemoryManager* memoryManager, WsEeprom* cartEeprom, WsKarnak* cartKarnak)
{
_memoryManager = memoryManager;
_cartEeprom = cartEeprom;
_cartKarnak = cartKarnak;
_state.HasKarnak = cartKarnak != nullptr;
}

void WsCart::RefreshMappings()
Expand All @@ -42,6 +45,8 @@ uint8_t WsCart::ReadPort(uint16_t port)
return _state.SelectedBanks[port - 0xC0];
} else if(port < 0xC9 && _cartEeprom) {
return _cartEeprom->ReadPort(port - 0xC4);
} else if(port >= 0xD6 && port < 0xDA && _cartKarnak) {
return _cartKarnak->ReadPort(port);
}

return _memoryManager->GetUnmappedPort();
Expand All @@ -54,6 +59,8 @@ void WsCart::WritePort(uint16_t port, uint8_t value)
_memoryManager->RefreshMappings();
} else if(port < 0xC9 && _cartEeprom) {
_cartEeprom->WritePort(port - 0xC4, value);
} else if(port >= 0xD6 && port < 0xDA && _cartKarnak) {
_cartKarnak->WritePort(port, value);
}
}

Expand Down
3 changes: 2 additions & 1 deletion Core/WS/Carts/WsCart.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class WsCart final : public ISerializable

WsMemoryManager* _memoryManager = nullptr;
WsEeprom* _cartEeprom = nullptr;
WsKarnak* _cartKarnak = nullptr;

void Map(uint32_t start, uint32_t end, MemoryType type, uint32_t offset, bool readonly);
void Unmap(uint32_t start, uint32_t end);
Expand All @@ -25,7 +26,7 @@ class WsCart final : public ISerializable
WsCart();
virtual ~WsCart() {}

void Init(WsMemoryManager* memoryManager, WsEeprom* cartEeprom);
void Init(WsMemoryManager* memoryManager, WsEeprom* cartEeprom, WsKarnak* cartKarnak);
void RefreshMappings();

WsCartState& GetState() { return _state; }
Expand Down
94 changes: 94 additions & 0 deletions Core/WS/Carts/WsKarnak.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include "pch.h"
#include "WS/Carts/WsKarnak.h"
#include "Utilities/Serializer.h"

static const int16_t adpcmAccumulatorStep[16][16] = {
{ 0, 0, 1, 2, 3, 5, 7, 10, 0, 0, -1, -2, -3, -5, -7, -10 },
{ 0, 1, 2, 3, 4, 6, 8, 13, 0, -1, -2, -3, -4, -6, -8, -13 },
{ 0, 1, 2, 4, 5, 7, 10, 15, 0, -1, -2, -4, -5, -7, -10, -15 },
{ 0, 1, 3, 4, 6, 9, 13, 19, 0, -1, -3, -4, -6, -9, -13, -19 },
{ 0, 2, 3, 5, 8, 11, 15, 23, 0, -2, -3, -5, -8, -11, -15, -23 },
{ 0, 2, 4, 7, 10, 14, 19, 29, 0, -2, -4, -7, -10, -14, -19, -29 },
{ 0, 3, 5, 8, 12, 16, 22, 33, 0, -3, -5, -8, -12, -16, -22, -33 },
{ 1, 4, 7, 10, 15, 20, 29, 43, -1, -4, -7, -10, -15, -20, -29, -43 },
{ 1, 4, 8, 13, 18, 25, 35, 53, -1, -4, -8, -13, -18, -25, -35, -53 },
{ 1, 6, 10, 16, 22, 31, 43, 64, -1, -6, -10, -16, -22, -31, -43, -64 },
{ 2, 7, 12, 19, 27, 37, 51, 76, -2, -7, -12, -19, -27, -37, -51, -76 },
{ 2, 9, 16, 24, 34, 46, 64, 96, -2, -9, -16, -24, -34, -46, -64, -96 },
{ 3, 11, 19, 29, 41, 57, 79, 117, -3, -11, -19, -29, -41, -57, -79, -117 },
{ 4, 13, 24, 36, 50, 69, 96, 143, -4, -13, -24, -36, -50, -69, -96, -143 },
{ 4, 16, 29, 44, 62, 85, 118, 175, -4, -16, -29, -44, -62, -85, -118, -175 },
{ 6, 20, 36, 54, 76, 104, 144, 214, -6, -20, -36, -54, -76, -104, -144, -214 }
};
static const int8_t adpcmIndexStep[8] = {
-1,
-1,
0,
0,
1,
2,
2,
3
};

WsKarnak::WsKarnak()
{
Reset();
}

void WsKarnak::Reset()
{
_state.AdpcmAccumulator = 0x100;
_adpcmInputShift = 0;
_adpcmStepIndex = 0;
}

void WsKarnak::ProcessAdpcmInput(uint8_t sample)
{
_state.AdpcmAccumulator += adpcmAccumulatorStep[_adpcmStepIndex][sample & 0xF];
_state.AdpcmAccumulator &= 0x3FF;
_adpcmStepIndex = std::clamp(_adpcmStepIndex + adpcmIndexStep[sample & 0x7], 0, 15);
}

uint8_t WsKarnak::ReadPort(uint16_t port)
{
if(port == 0xD6) {
return (_state.Enable ? 0x80 : 0) | (_state.TimerPeriod & 0x7F);
} else if(port == 0xD9) {
if(_state.AdpcmAccumulator >= 0x300) {
return 0x00;
} else if(_state.AdpcmAccumulator >= 0x200) {
return 0xFF;
} else {
return _state.AdpcmAccumulator >> 1;
}
}

return 0xFF;
}

void WsKarnak::WritePort(uint16_t port, uint8_t value)
{
if(port == 0xD6) {
_state.Enable = (value & 0x80) != 0;
_state.TimerPeriod = value & 0x7F;
if(!_state.Enable) {
Reset();
}
} else if(port == 0xD8) {
if(_state.Enable) {
ProcessAdpcmInput(value >> (_adpcmInputShift ? 0 : 4));
_adpcmInputShift ^= 1;
}
}
}

void WsKarnak::Serialize(Serializer& s)
{
SV(_state.Enable);
SV(_state.TimerPeriod);
SV(_state.AdpcmAccumulator);
SV(_adpcmInputShift);
SV(_adpcmStepIndex);
SV(_timerCounter);
}
28 changes: 28 additions & 0 deletions Core/WS/Carts/WsKarnak.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once
#include "pch.h"
#include "WS/WsTypes.h"
#include "Utilities/ISerializable.h"

class WsKarnak final : public ISerializable
{
protected:
WsKarnakState _state = {};

uint16_t _timerCounter;
int8_t _adpcmStepIndex;
uint8_t _adpcmInputShift;

void Reset();
void ProcessAdpcmInput(uint8_t sample);

public:
WsKarnak();
virtual ~WsKarnak() {}

WsKarnakState& GetState() { return _state; }

virtual uint8_t ReadPort(uint16_t port);
virtual void WritePort(uint16_t port, uint8_t value);

void Serialize(Serializer& s) override;
};
10 changes: 9 additions & 1 deletion Core/WS/WsConsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "WS/WsPpu.h"
#include "WS/WsTimer.h"
#include "WS/Carts/WsCart.h"
#include "WS/Carts/WsKarnak.h"
#include "WS/WsControlManager.h"
#include "WS/WsMemoryManager.h"
#include "WS/WsDmaController.h"
Expand Down Expand Up @@ -128,8 +129,9 @@ LoadRomResult WsConsole::LoadRom(VirtualFile& romFile)
_ppu.reset(new WsPpu(_emu, this, _memoryManager.get(), _timer.get(), _workRam));
_apu.reset(new WsApu(_emu, this, _memoryManager.get(), _dmaController.get()));
_cart.reset(new WsCart());
_cartKarnak.reset(new WsKarnak());

_cart->Init(_memoryManager.get(), _cartEeprom.get());
_cart->Init(_memoryManager.get(), _cartEeprom.get(), _cartKarnak.get());
_memoryManager->Init(_emu, this, _cpu.get(), _ppu.get(), _controlManager.get(), _cart.get(), _timer.get(), _dmaController.get(), _internalEeprom.get(), _apu.get(), _serial.get());
_timer->Init(_memoryManager.get());
_dmaController->Init(_memoryManager.get(), _apu.get());
Expand Down Expand Up @@ -447,6 +449,9 @@ WsState WsConsole::GetState()
if(_cartEeprom) {
state.CartEeprom = _cartEeprom->GetState();
}
if(_cartKarnak) {
state.CartKarnak = _cartKarnak->GetState();
}
return state;
}

Expand Down Expand Up @@ -496,4 +501,7 @@ void WsConsole::Serialize(Serializer& s)
if(_cartEeprom) {
SV(_cartEeprom);
}
if(_cartKarnak) {
SV(_cartKarnak);
}
}
2 changes: 2 additions & 0 deletions Core/WS/WsConsole.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class WsMemoryManager;
class WsControlManager;
class WsDmaController;
class WsEeprom;
class WsKarnak;
enum class WsModel : uint8_t;

class WsConsole final : public IConsole
Expand All @@ -31,6 +32,7 @@ class WsConsole final : public IConsole
unique_ptr<WsDmaController> _dmaController;
unique_ptr<WsEeprom> _internalEeprom;
unique_ptr<WsEeprom> _cartEeprom;
unique_ptr<WsKarnak> _cartKarnak;

uint8_t* _workRam = nullptr;
uint32_t _workRamSize = 0;
Expand Down
9 changes: 9 additions & 0 deletions Core/WS/WsTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -445,9 +445,17 @@ struct WsEepromState

struct WsCartState
{
bool HasKarnak;
uint8_t SelectedBanks[4];
};

struct WsKarnakState
{
bool Enable;
uint8_t TimerPeriod;
uint16_t AdpcmAccumulator;
};

struct WsState
{
WsCpuState Cpu;
Expand All @@ -461,6 +469,7 @@ struct WsState
WsEepromState InternalEeprom;
WsCartState Cart;
WsEepromState CartEeprom;
WsKarnakState CartKarnak;
WsModel Model;
};

Expand Down
9 changes: 9 additions & 0 deletions UI/Debugger/RegisterViewer/WsRegisterViewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,15 @@ private static RegisterViewerTab GetCartTab(ref WsState ws)
});
}

if(ws.Cart.HasKarnak) {
entries.AddRange(new List<RegEntry>() {
new RegEntry("", "Cart Karnak"),
new RegEntry("$D6.7", "Enabled", ws.CartKarnak.Enable),
new RegEntry("$D6.0-6", "Timer Period", ws.CartKarnak.TimerPeriod, Format.X8),
new RegEntry("$D9", "ADPCM Output", ws.CartKarnak.AdpcmAccumulator >= 0x300 ? 0x00 : (ws.CartKarnak.AdpcmAccumulator >= 0x200 ? 0xFF : (ws.CartKarnak.AdpcmAccumulator >> 1)), Format.X8)
});
}

return new RegisterViewerTab("Cart", entries, CpuType.Ws, MemoryType.WsPort);
}

Expand Down
9 changes: 9 additions & 0 deletions UI/Interop/ConsoleState/WsState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -442,10 +442,18 @@ public struct WsEepromState

public struct WsCartState
{
[MarshalAs(UnmanagedType.I1)] public bool HasKarnak;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] SelectedBanks;
}

public struct WsKarnakState
{
[MarshalAs(UnmanagedType.I1)] public bool Enable;
public byte TimerPeriod;
public UInt16 AdpcmAccumulator;
}

public struct WsState : BaseState
{
public WsCpuState Cpu;
Expand All @@ -459,5 +467,6 @@ public struct WsState : BaseState
public WsEepromState InternalEeprom;
public WsCartState Cart;
public WsEepromState CartEeprom;
public WsKarnakState CartKarnak;
public WsModel Model;
}
Loading