Added S-DD1 support

This commit is contained in:
Sour 2019-07-31 23:04:30 -04:00
parent dffce96ed8
commit bbb6be6a9f
13 changed files with 928 additions and 6 deletions

View file

@ -11,6 +11,7 @@
#include "NecDsp.h"
#include "Sa1.h"
#include "Gsu.h"
#include "Sdd1.h"
#include "../Utilities/HexUtilities.h"
#include "../Utilities/VirtualFile.h"
#include "../Utilities/FolderUtilities.h"
@ -187,7 +188,7 @@ CoprocessorType BaseCartridge::GetCoprocessorType()
case 0x01: return CoprocessorType::GSU; break;
case 0x02: return CoprocessorType::OBC1; break;
case 0x03: return CoprocessorType::SA1; break;
case 0x04: return CoprocessorType::DD1; break;
case 0x04: return CoprocessorType::SDD1; break;
case 0x05: return CoprocessorType::RTC; break;
case 0x0E: return CoprocessorType::Satellaview; break;
case 0x0F:
@ -312,7 +313,7 @@ void BaseCartridge::Init(MemoryMappings &mm)
void BaseCartridge::RegisterHandlers(MemoryMappings &mm)
{
if(_coprocessorType == CoprocessorType::GSU || MapSpecificCarts(mm)) {
if(MapSpecificCarts(mm) || _coprocessorType == CoprocessorType::GSU || _coprocessorType == CoprocessorType::SDD1) {
return;
}
@ -366,6 +367,8 @@ void BaseCartridge::InitCoprocessor()
} else if(_coprocessorType == CoprocessorType::GSU) {
_coprocessor.reset(new Gsu(_console, _coprocessorRamSize));
_gsu = dynamic_cast<Gsu*>(_coprocessor.get());
} else if(_coprocessorType == CoprocessorType::SDD1) {
_coprocessor.reset(new Sdd1(_console));
}
}
@ -468,7 +471,7 @@ void BaseCartridge::DisplayCartInfo()
switch(_coprocessorType) {
case CoprocessorType::None: coProcMessage += "<none>"; break;
case CoprocessorType::CX4: coProcMessage += "CX4"; break;
case CoprocessorType::DD1: coProcMessage += "S-DD1"; break;
case CoprocessorType::SDD1: coProcMessage += "S-DD1"; break;
case CoprocessorType::DSP1: coProcMessage += "DSP1"; break;
case CoprocessorType::DSP1B: coProcMessage += "DSP1B"; break;
case CoprocessorType::DSP2: coProcMessage += "DSP2"; break;

View file

@ -36,7 +36,7 @@ enum class CoprocessorType
GSU,
OBC1,
SA1,
DD1,
SDD1,
RTC,
Satellaview,
SPC7110,

View file

@ -142,6 +142,10 @@
<ClInclude Include="ScriptHost.h" />
<ClInclude Include="ScriptingContext.h" />
<ClInclude Include="ScriptManager.h" />
<ClInclude Include="Sdd1.h" />
<ClInclude Include="Sdd1Decomp.h" />
<ClInclude Include="Sdd1Mmc.h" />
<ClInclude Include="Sdd1Types.h" />
<ClInclude Include="SettingTypes.h" />
<ClInclude Include="ShortcutKeyHandler.h" />
<ClInclude Include="SnesController.h" />
@ -221,6 +225,9 @@
<ClCompile Include="ScriptHost.cpp" />
<ClCompile Include="ScriptingContext.cpp" />
<ClCompile Include="ScriptManager.cpp" />
<ClCompile Include="Sdd1.cpp" />
<ClCompile Include="Sdd1Decomp.cpp" />
<ClCompile Include="Sdd1Mmc.cpp" />
<ClCompile Include="ShortcutKeyHandler.cpp" />
<ClCompile Include="SoundMixer.cpp" />
<ClCompile Include="SoundResampler.cpp" />

View file

@ -353,6 +353,18 @@
<ClInclude Include="GsuRamHandler.h">
<Filter>SNES\Coprocessors\GSU</Filter>
</ClInclude>
<ClInclude Include="Sdd1.h">
<Filter>SNES\Coprocessors\SDD1</Filter>
</ClInclude>
<ClInclude Include="Sdd1Mmc.h">
<Filter>SNES\Coprocessors\SDD1</Filter>
</ClInclude>
<ClInclude Include="Sdd1Types.h">
<Filter>SNES\Coprocessors\SDD1</Filter>
</ClInclude>
<ClInclude Include="Sdd1Decomp.h">
<Filter>SNES\Coprocessors\SDD1</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp" />
@ -569,6 +581,15 @@
<ClCompile Include="GsuDisUtils.cpp">
<Filter>Debugger\Disassembler</Filter>
</ClCompile>
<ClCompile Include="Sdd1.cpp">
<Filter>SNES\Coprocessors\SDD1</Filter>
</ClCompile>
<ClCompile Include="Sdd1Mmc.cpp">
<Filter>SNES\Coprocessors\SDD1</Filter>
</ClCompile>
<ClCompile Include="Sdd1Decomp.cpp">
<Filter>SNES\Coprocessors\SDD1</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="SNES">
@ -616,5 +637,8 @@
<Filter Include="SNES\Coprocessors\GSU">
<UniqueIdentifier>{5bda57b5-9204-46f4-85f5-3b550c589a18}</UniqueIdentifier>
</Filter>
<Filter Include="SNES\Coprocessors\SDD1">
<UniqueIdentifier>{991e1865-b4f2-4066-8b10-d7458e636e6e}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>

View file

@ -145,7 +145,7 @@ uint8_t InternalRegisters::Read(uint16_t addr)
default:
LogDebug("[Debug] Unimplemented register read: " + HexUtilities::ToHex(addr));
return 0;
return _memoryManager->GetOpenBus();
}
}

119
Core/Sdd1.cpp Normal file
View file

@ -0,0 +1,119 @@
#include "stdafx.h"
#include "Sdd1.h"
#include "Sdd1Mmc.h"
#include "Console.h"
#include "BaseCartridge.h"
#include "MemoryManager.h"
#include "MemoryMappings.h"
Sdd1::Sdd1(Console* console)
{
//This handler is used to dynamically map the ROM based on the banking registers
_sdd1Mmc.reset(new Sdd1Mmc(_state, console->GetCartridge().get()));
MemoryMappings *cpuMappings = console->GetMemoryManager()->GetMemoryMappings();
vector<unique_ptr<IMemoryHandler>> &prgRomHandlers = console->GetCartridge()->GetPrgRomHandlers();
vector<unique_ptr<IMemoryHandler>> &saveRamHandlers = console->GetCartridge()->GetSaveRamHandlers();
//Regular A Bus register handler, keep a reference to it, it'll be overwritten below
_cpuRegisterHandler = cpuMappings->GetHandler(0x4000);
//Based on forum thread info: https://forums.nesdev.com/viewtopic.php?f=12&t=14156
cpuMappings->RegisterHandler(0x00, 0x3F, 0x6000, 0x7FFF, saveRamHandlers);
cpuMappings->RegisterHandler(0x80, 0xBF, 0x6000, 0x7FFF, saveRamHandlers);
cpuMappings->RegisterHandler(0x70, 0x73, 0x0000, 0xFFFF, saveRamHandlers);
//S-DD1 registers (0x4800-0x4807)
cpuMappings->RegisterHandler(0x00, 0x3F, 0x4000, 0x4FFF, this);
cpuMappings->RegisterHandler(0x80, 0xBF, 0x4000, 0x4FFF, this);
cpuMappings->RegisterHandler(0x00, 0x3F, 0x8000, 0xFFFF, prgRomHandlers);
cpuMappings->RegisterHandler(0x80, 0xBF, 0x8000, 0xFFFF, prgRomHandlers);
//Override these segments to implement the miroring that $4805/$4807 cause
cpuMappings->RegisterHandler(0x20, 0x3F, 0x8000, 0xFFFF, _sdd1Mmc.get());
cpuMappings->RegisterHandler(0xA0, 0xBF, 0x8000, 0xFFFF, _sdd1Mmc.get());
//Regular bank switched mappings
cpuMappings->RegisterHandler(0xC0, 0xFF, 0x0000, 0xFFFF, _sdd1Mmc.get());
Reset();
}
void Sdd1::Reset()
{
_state = {};
_state.NeedInit = true;
_state.SelectedBanks[0] = 0;
_state.SelectedBanks[1] = 1;
_state.SelectedBanks[2] = 2;
_state.SelectedBanks[3] = 3;
}
uint8_t Sdd1::Read(uint32_t addr)
{
if((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) {
switch(addr & 0x07) {
case 0: return _state.AllowDmaProcessing;
case 1: return _state.ProcessNextDma;
case 4: case 5: case 6: case 7:
return _state.SelectedBanks[addr & 0x03];
}
}
return _cpuRegisterHandler->Read(addr);
}
void Sdd1::Write(uint32_t addr, uint8_t value)
{
if((uint16_t)addr >= 0x4800 && (uint16_t)addr <= 0x4807) {
//S-DD1 registers
switch(addr & 0x07) {
case 0: _state.AllowDmaProcessing = value; break;
case 1: _state.ProcessNextDma = value; break;
case 4: case 5: case 6: case 7:
_state.SelectedBanks[addr & 0x03] = value;
break;
}
} else {
if((uint16_t)addr >= 0x4300 && (uint16_t)addr <= 0x437A) {
//Keep track of writes to the DMA controller to know which address/length the DMAs will use
uint8_t ch = (addr >> 4) & 0x07;
switch(addr & 0x0F) {
case 0x02: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFFFF00) | value; break;
case 0x03: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0xFF00FF) | (value << 8); break;
case 0x04: _state.DmaAddress[ch] = (_state.DmaAddress[ch] & 0x00FFFF) | (value << 16); break;
case 0x05: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0xFF00) | value; break;
case 0x06: _state.DmaLength[ch] = (_state.DmaLength[ch] & 0x00FF) | (value << 8); break;
}
}
//Forward everything else to the regular handler
_cpuRegisterHandler->Write(addr, value);
}
}
void Sdd1::Serialize(Serializer &s)
{
s.Stream(_state.AllowDmaProcessing, _state.ProcessNextDma, _state.NeedInit);
s.StreamArray(_state.DmaAddress, 8);
s.StreamArray(_state.DmaLength, 8);
s.StreamArray(_state.SelectedBanks, 4);
}
uint8_t Sdd1::Peek(uint32_t addr)
{
return 0;
}
void Sdd1::PeekBlock(uint8_t* output)
{
memset(output, 0, 0x1000);
}
AddressInfo Sdd1::GetAbsoluteAddress(uint32_t address)
{
return { -1, SnesMemoryType::Register };
}

26
Core/Sdd1.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include "stdafx.h"
#include "BaseCoprocessor.h"
#include "Sdd1Types.h"
class Console;
class Sdd1Mmc;
class Sdd1 : public BaseCoprocessor
{
private:
Sdd1State _state;
unique_ptr<Sdd1Mmc> _sdd1Mmc;
IMemoryHandler* _cpuRegisterHandler;
public:
Sdd1(Console *console);
void Serialize(Serializer &s) override;
uint8_t Read(uint32_t addr) override;
uint8_t Peek(uint32_t addr) override;
void PeekBlock(uint8_t* output) override;
void Write(uint32_t addr, uint8_t value) override;
AddressInfo GetAbsoluteAddress(uint32_t address) override;
void Reset() override;
};

446
Core/Sdd1Decomp.cpp Normal file
View file

@ -0,0 +1,446 @@
//Altered to integrate with Mesen-S's code
/************************************************************************
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
#include "stdafx.h"
#include "Sdd1Decomp.h"
#include "Sdd1Mmc.h"
void SDD1_IM::prepareDecomp(Sdd1Mmc *mmc, uint32_t readAddr)
{
_sdd1Mmc = mmc;
_readAddr = readAddr;
bit_count = 4;
}
////////////////////////////////////////////////////
uint8_t SDD1_IM::getCodeword(uint8_t code_len)
{
uint8_t codeword;
codeword = _sdd1Mmc->ReadRom(_readAddr) << bit_count;
++bit_count;
if(codeword & 0x80) {
codeword |= _sdd1Mmc->ReadRom(_readAddr + 1) >> (9 - bit_count);
bit_count += code_len;
}
if(bit_count & 0x08) {
_readAddr++;
bit_count &= 0x07;
}
return codeword;
}
SDD1_GCD::SDD1_GCD(SDD1_IM *associatedIM) :
IM(associatedIM)
{
}
//////////////////////////////////////////////////////
void SDD1_GCD::getRunCount(uint8_t code_num, uint8_t *MPScount, bool *LPSind)
{
const uint8_t run_count[] = {
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
0x0e, 0x06, 0x0a, 0x02, 0x0c, 0x04, 0x08, 0x00,
0x1f, 0x0f, 0x17, 0x07, 0x1b, 0x0b, 0x13, 0x03,
0x1d, 0x0d, 0x15, 0x05, 0x19, 0x09, 0x11, 0x01,
0x1e, 0x0e, 0x16, 0x06, 0x1a, 0x0a, 0x12, 0x02,
0x1c, 0x0c, 0x14, 0x04, 0x18, 0x08, 0x10, 0x00,
0x3f, 0x1f, 0x2f, 0x0f, 0x37, 0x17, 0x27, 0x07,
0x3b, 0x1b, 0x2b, 0x0b, 0x33, 0x13, 0x23, 0x03,
0x3d, 0x1d, 0x2d, 0x0d, 0x35, 0x15, 0x25, 0x05,
0x39, 0x19, 0x29, 0x09, 0x31, 0x11, 0x21, 0x01,
0x3e, 0x1e, 0x2e, 0x0e, 0x36, 0x16, 0x26, 0x06,
0x3a, 0x1a, 0x2a, 0x0a, 0x32, 0x12, 0x22, 0x02,
0x3c, 0x1c, 0x2c, 0x0c, 0x34, 0x14, 0x24, 0x04,
0x38, 0x18, 0x28, 0x08, 0x30, 0x10, 0x20, 0x00,
0x7f, 0x3f, 0x5f, 0x1f, 0x6f, 0x2f, 0x4f, 0x0f,
0x77, 0x37, 0x57, 0x17, 0x67, 0x27, 0x47, 0x07,
0x7b, 0x3b, 0x5b, 0x1b, 0x6b, 0x2b, 0x4b, 0x0b,
0x73, 0x33, 0x53, 0x13, 0x63, 0x23, 0x43, 0x03,
0x7d, 0x3d, 0x5d, 0x1d, 0x6d, 0x2d, 0x4d, 0x0d,
0x75, 0x35, 0x55, 0x15, 0x65, 0x25, 0x45, 0x05,
0x79, 0x39, 0x59, 0x19, 0x69, 0x29, 0x49, 0x09,
0x71, 0x31, 0x51, 0x11, 0x61, 0x21, 0x41, 0x01,
0x7e, 0x3e, 0x5e, 0x1e, 0x6e, 0x2e, 0x4e, 0x0e,
0x76, 0x36, 0x56, 0x16, 0x66, 0x26, 0x46, 0x06,
0x7a, 0x3a, 0x5a, 0x1a, 0x6a, 0x2a, 0x4a, 0x0a,
0x72, 0x32, 0x52, 0x12, 0x62, 0x22, 0x42, 0x02,
0x7c, 0x3c, 0x5c, 0x1c, 0x6c, 0x2c, 0x4c, 0x0c,
0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04,
0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08,
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
};
uint8_t codeword = IM->getCodeword(code_num);
if(codeword & 0x80) {
*LPSind = 1;
*MPScount = run_count[codeword >> (code_num ^ 0x07)];
} else {
*MPScount = (1 << code_num);
}
}
///////////////////////////////////////////////////////
SDD1_BG::SDD1_BG(SDD1_GCD *associatedGCD, uint8_t code) :
GCD(associatedGCD), code_num(code)
{
}
///////////////////////////////////////////////
void SDD1_BG::prepareDecomp(void)
{
MPScount = 0;
LPSind = 0;
}
//////////////////////////////////////////////
uint8_t SDD1_BG::getBit(bool *endOfRun)
{
uint8_t bit;
if(!(MPScount || LPSind)) GCD->getRunCount(code_num, &MPScount, &LPSind);
if(MPScount) {
bit = 0;
MPScount--;
} else {
bit = 1;
LPSind = 0;
}
if(MPScount || LPSind) (*endOfRun) = 0;
else (*endOfRun) = 1;
return bit;
}
/////////////////////////////////////////////////
SDD1_PEM::SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7)
{
BG[0] = associatedBG0;
BG[1] = associatedBG1;
BG[2] = associatedBG2;
BG[3] = associatedBG3;
BG[4] = associatedBG4;
BG[5] = associatedBG5;
BG[6] = associatedBG6;
BG[7] = associatedBG7;
}
/////////////////////////////////////////////////////////
const SDD1_PEM::state SDD1_PEM::evolution_table[] = {
{ 0,25,25},
{ 0, 2, 1},
{ 0, 3, 1},
{ 0, 4, 2},
{ 0, 5, 3},
{ 1, 6, 4},
{ 1, 7, 5},
{ 1, 8, 6},
{ 1, 9, 7},
{ 2,10, 8},
{ 2,11, 9},
{ 2,12,10},
{ 2,13,11},
{ 3,14,12},
{ 3,15,13},
{ 3,16,14},
{ 3,17,15},
{ 4,18,16},
{ 4,19,17},
{ 5,20,18},
{ 5,21,19},
{ 6,22,20},
{ 6,23,21},
{ 7,24,22},
{ 7,24,23},
{ 0,26, 1},
{ 1,27, 2},
{ 2,28, 4},
{ 3,29, 8},
{ 4,30,12},
{ 5,31,16},
{ 6,32,18},
{ 7,24,22}
};
//////////////////////////////////////////////////////
void SDD1_PEM::prepareDecomp(void)
{
for(uint8_t i = 0; i < 32; i++) {
contextInfo[i].status = 0;
contextInfo[i].MPS = 0;
}
}
/////////////////////////////////////////////////////////
uint8_t SDD1_PEM::getBit(uint8_t context)
{
bool endOfRun;
uint8_t bit;
SDD1_ContextInfo *pContInfo = &contextInfo[context];
uint8_t currStatus = pContInfo->status;
const state *pState = &SDD1_PEM::evolution_table[currStatus];
uint8_t currentMPS = pContInfo->MPS;
bit = (BG[pState->code_num])->getBit(&endOfRun);
if(endOfRun)
if(bit) {
if(!(currStatus & 0xfe)) (pContInfo->MPS) ^= 0x01;
(pContInfo->status) = pState->nextIfLPS;
} else
(pContInfo->status) = pState->nextIfMPS;
return bit ^ currentMPS;
}
//////////////////////////////////////////////////////////////
SDD1_CM::SDD1_CM(SDD1_PEM *associatedPEM) :
PEM(associatedPEM)
{
}
//////////////////////////////////////////////////////////////
void SDD1_CM::prepareDecomp(uint8_t firstByte)
{
bitplanesInfo = firstByte & 0xc0;
contextBitsInfo = firstByte & 0x30;
bit_number = 0;
for(int i = 0; i < 8; i++) prevBitplaneBits[i] = 0;
switch(bitplanesInfo) {
case 0x00:
currBitplane = 1;
break;
case 0x40:
currBitplane = 7;
break;
case 0x80:
currBitplane = 3;
}
}
/////////////////////////////////////////////////////////////
uint8_t SDD1_CM::getBit(void)
{
uint8_t currContext;
uint16_t *context_bits;
switch(bitplanesInfo) {
case 0x00:
currBitplane ^= 0x01;
break;
case 0x40:
currBitplane ^= 0x01;
if(!(bit_number & 0x7f)) currBitplane = ((currBitplane + 2) & 0x07);
break;
case 0x80:
currBitplane ^= 0x01;
if(!(bit_number & 0x7f)) currBitplane ^= 0x02;
break;
case 0xc0:
currBitplane = bit_number & 0x07;
}
context_bits = &prevBitplaneBits[currBitplane];
currContext = (currBitplane & 0x01) << 4;
switch(contextBitsInfo) {
case 0x00:
currContext |= ((*context_bits & 0x01c0) >> 5) | (*context_bits & 0x0001);
break;
case 0x10:
currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0001);
break;
case 0x20:
currContext |= ((*context_bits & 0x00c0) >> 5) | (*context_bits & 0x0001);
break;
case 0x30:
currContext |= ((*context_bits & 0x0180) >> 5) | (*context_bits & 0x0003);
}
uint8_t bit = PEM->getBit(currContext);
*context_bits <<= 1;
*context_bits |= bit;
bit_number++;
return bit;
}
//////////////////////////////////////////////////
SDD1_OL::SDD1_OL(SDD1_CM *associatedCM) :
CM(associatedCM)
{
}
///////////////////////////////////////////////////
void SDD1_OL::prepareDecomp(uint8_t firstByte)
{
bitplanesInfo = firstByte & 0xc0;
_regs[0] = 1;
}
///////////////////////////////////////////////////
uint8_t SDD1_OL::decompressByte()
{
switch(bitplanesInfo) {
case 0x00:
case 0x40:
case 0x80:
if(_regs[0] == 0) {
_regs[0] = ~_regs[0];
return _regs[2];
} else {
_regs[1] = 0;
_regs[2] = 0;
_regs[0] = 0x80;
while(_regs[0]) {
if(CM->getBit()) {
_regs[1] |= _regs[0];
}
if(CM->getBit()) {
_regs[2] |= _regs[0];
}
_regs[0] >>= 1;
}
return _regs[1];
}
break;
case 0xC0:
_regs[1] = 0;
_regs[0] = 0x01;
while(_regs[0]) {
if(CM->getBit()) {
_regs[1] |= _regs[0];
}
_regs[0] <<= 1;
}
return _regs[1];
}
throw std::runtime_error("SDD1_OL::decompressByte: Unexpected value");
}
void Sdd1Decomp::Init(Sdd1Mmc *mmc, uint32_t readAddr)
{
uint8_t firstByte = mmc->ReadRom(readAddr);
IM.prepareDecomp(mmc, readAddr);
BG0.prepareDecomp();
BG1.prepareDecomp();
BG2.prepareDecomp();
BG3.prepareDecomp();
BG4.prepareDecomp();
BG5.prepareDecomp();
BG6.prepareDecomp();
BG7.prepareDecomp();
PEM.prepareDecomp();
CM.prepareDecomp(firstByte);
OL.prepareDecomp(firstByte);
}
uint8_t Sdd1Decomp::GetDecompressedByte()
{
return OL.decompressByte();
}
Sdd1Decomp::Sdd1Decomp() :
GCD(&IM),
BG0(&GCD, 0), BG1(&GCD, 1), BG2(&GCD, 2), BG3(&GCD, 3),
BG4(&GCD, 4), BG5(&GCD, 5), BG6(&GCD, 6), BG7(&GCD, 7),
PEM(&BG0, &BG1, &BG2, &BG3, &BG4, &BG5, &BG6, &BG7),
CM(&PEM),
OL(&CM)
{
}

170
Core/Sdd1Decomp.h Normal file
View file

@ -0,0 +1,170 @@
#pragma once
#include "stdafx.h"
/************************************************************************
S-DD1'algorithm emulation code
------------------------------
Author: Andreas Naive
Date: August 2003
Last update: October 2004
This code is Public Domain. There is no copyright holded by the author.
Said this, the author wish to explicitly emphasize his inalienable moral rights
over this piece of intelectual work and the previous research that made it
possible, as recognized by most of the copyright laws around the world.
This code is provided 'as-is', with no warranty, expressed or implied.
No responsability is assumed by the author in connection with it.
The author is greatly indebted with The Dumper, without whose help and
patience providing him with real S-DD1 data the research would have never been
possible. He also wish to note that in the very beggining of his research,
Neviksti had done some steps in the right direction. By last, the author is
indirectly indebted to all the people that worked and contributed in the
S-DD1 issue in the past.
An algorithm's documentation is available as a separate document.
The implementation is obvious when the algorithm is
understood.
************************************************************************/
class Sdd1Mmc;
class SDD1_IM
{ //Input Manager
Sdd1Mmc* _sdd1Mmc;
public:
SDD1_IM(void) {}
void prepareDecomp(Sdd1Mmc *mmc, uint32_t readAddr);
uint8_t getCodeword(const uint8_t code_len);
private:
uint32_t _readAddr;
uint8_t bit_count;
};
////////////////////////////////////////////////////
class SDD1_GCD
{ //Golomb-Code Decoder
public:
SDD1_GCD(SDD1_IM *associatedIM);
void getRunCount(uint8_t code_num, uint8_t *MPScount, bool *LPSind);
private:
SDD1_IM * const IM;
};
//////////////////////////////////////////////////////
class SDD1_BG
{ // Bits Generator
public:
SDD1_BG(SDD1_GCD *associatedGCD, uint8_t code);
void prepareDecomp(void);
uint8_t getBit(bool *endOfRun);
private:
const uint8_t code_num;
uint8_t MPScount;
bool LPSind;
SDD1_GCD *const GCD;
};
////////////////////////////////////////////////
class SDD1_PEM
{ //Probability Estimation Module
public:
SDD1_PEM(SDD1_BG *associatedBG0, SDD1_BG *associatedBG1,
SDD1_BG *associatedBG2, SDD1_BG *associatedBG3,
SDD1_BG *associatedBG4, SDD1_BG *associatedBG5,
SDD1_BG *associatedBG6, SDD1_BG *associatedBG7);
void prepareDecomp(void);
uint8_t getBit(uint8_t context);
private:
struct state
{
uint8_t code_num;
uint8_t nextIfMPS;
uint8_t nextIfLPS;
};
static const state evolution_table[];
struct SDD1_ContextInfo
{
uint8_t status;
uint8_t MPS;
} contextInfo[32];
SDD1_BG * BG[8];
};
///////////////////////////////////////////////////
class SDD1_CM
{ //Context Model
public:
SDD1_CM(SDD1_PEM *associatedPEM);
void prepareDecomp(uint8_t firstByte);
uint8_t getBit(void);
private:
uint8_t bitplanesInfo;
uint8_t contextBitsInfo;
uint8_t bit_number;
uint8_t currBitplane;
uint16_t prevBitplaneBits[8];
SDD1_PEM *const PEM;
};
///////////////////////////////////////////////////
class SDD1_OL
{ //Output Logic
public:
SDD1_OL(SDD1_CM *associatedCM);
void prepareDecomp(uint8_t firstByte);
uint8_t decompressByte();
private:
uint8_t bitplanesInfo;
uint8_t _regs[3];
SDD1_CM *const CM;
};
class Sdd1Decomp
{
public:
Sdd1Decomp();
void Init(Sdd1Mmc *mmc, uint32_t readAddr);
uint8_t GetDecompressedByte();
private:
SDD1_IM IM;
SDD1_GCD GCD;
SDD1_BG BG0; SDD1_BG BG1; SDD1_BG BG2; SDD1_BG BG3;
SDD1_BG BG4; SDD1_BG BG5; SDD1_BG BG6; SDD1_BG BG7;
SDD1_PEM PEM;
SDD1_CM CM;
SDD1_OL OL;
};

84
Core/Sdd1Mmc.cpp Normal file
View file

@ -0,0 +1,84 @@
#include "stdafx.h"
#include "Sdd1Mmc.h"
#include "Sdd1Types.h"
#include "BaseCartridge.h"
Sdd1Mmc::Sdd1Mmc(Sdd1State &state, BaseCartridge *cart)
{
_romHandlers = &cart->GetPrgRomHandlers();
_handlerMask = (uint32_t)((*_romHandlers).size() - 1);
_state = &state;
}
uint8_t Sdd1Mmc::ReadRom(uint32_t addr)
{
return GetHandler(addr)->Read(addr);
}
IMemoryHandler* Sdd1Mmc::GetHandler(uint32_t addr)
{
uint8_t bank = (addr >> 20) - 0x0C;
uint16_t handlerIndex = ((_state->SelectedBanks[bank] & 0x0F) << 8) | ((addr & 0xFF000) >> 12);
return (*_romHandlers)[handlerIndex & _handlerMask].get();
}
uint8_t Sdd1Mmc::Read(uint32_t addr)
{
if(!(addr & 0x400000)) {
uint16_t handlerIndex;
if(((addr & 0x800000) && _state->SelectedBanks[3] & 0x80) || (!(addr & 0x800000) && (_state->SelectedBanks[1] & 0x80))) {
//Force mirroring: $20-$3F mirrors $00-$1F, $A0-$BF mirrors $80-$9F
handlerIndex = (((addr & 0x1F0000) >> 1) | (addr & 0x7000)) >> 12;
} else {
handlerIndex = (((addr & 0x3F0000) >> 1) | (addr & 0x7000)) >> 12;
}
return (*_romHandlers)[handlerIndex & _handlerMask]->Read(addr);
}
//Banks $C0+
uint8_t activeChannels = _state->ProcessNextDma & _state->AllowDmaProcessing;
if(activeChannels) {
//Some DMA channels are being processed, need to check if the address being read matches one of the dma channels
for(int i = 0; i < 8; i++) {
if((activeChannels & (1 << i)) && addr == _state->DmaAddress[i]) {
if(_state->NeedInit) {
_decompressor.Init(this, addr);
_state->NeedInit = false;
}
uint8_t data = _decompressor.GetDecompressedByte();
_state->DmaLength[i]--;
if(_state->DmaLength[i] == 0) {
_state->NeedInit = true;
_state->ProcessNextDma &= ~(1 << i);
}
return data;
}
}
}
return ReadRom(addr);
}
uint8_t Sdd1Mmc::Peek(uint32_t addr)
{
return 0;
}
void Sdd1Mmc::PeekBlock(uint8_t *output)
{
memset(output, 0, 0x1000);
}
void Sdd1Mmc::Write(uint32_t addr, uint8_t value)
{
//ROM, read-only
}
AddressInfo Sdd1Mmc::GetAbsoluteAddress(uint32_t address)
{
return GetHandler(address)->GetAbsoluteAddress(address);
}

30
Core/Sdd1Mmc.h Normal file
View file

@ -0,0 +1,30 @@
#pragma once
#include "stdafx.h"
#include "IMemoryHandler.h"
#include "Sdd1Types.h"
#include "Sdd1Decomp.h"
class BaseCartridge;
class Sdd1Mmc : public IMemoryHandler
{
private:
Sdd1State* _state;
vector<unique_ptr<IMemoryHandler>> *_romHandlers;
uint32_t _handlerMask;
Sdd1Decomp _decompressor;
IMemoryHandler* GetHandler(uint32_t addr);
public:
Sdd1Mmc(Sdd1State &state, BaseCartridge *cart);
uint8_t ReadRom(uint32_t addr);
// Inherited via IMemoryHandler
virtual uint8_t Read(uint32_t addr) override;
virtual uint8_t Peek(uint32_t addr) override;
virtual void PeekBlock(uint8_t * output) override;
virtual void Write(uint32_t addr, uint8_t value) override;
virtual AddressInfo GetAbsoluteAddress(uint32_t address) override;
};

13
Core/Sdd1Types.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include "stdafx.h"
struct Sdd1State
{
uint8_t AllowDmaProcessing;
uint8_t ProcessNextDma;
uint8_t SelectedBanks[4];
uint32_t DmaAddress[8];
uint16_t DmaLength[8];
bool NeedInit;
};

View file

@ -169,7 +169,7 @@ namespace Mesen.GUI
GSU,
OBC1,
SA1,
DD1,
SDD1,
RTC,
Satellaview,
SPC7110,