Copied SPC7110 emulation from snes9x_3ds.

This commit is contained in:
João Silva 2017-08-13 06:02:24 +01:00
parent e18e3e55bb
commit fdaf2925f1
13 changed files with 867 additions and 1471 deletions

View File

@ -40,6 +40,7 @@ SOURCES_C := \
$(CORE_DIR)/soundux.c \
$(CORE_DIR)/spc700.c \
$(CORE_DIR)/spc7110.c \
$(CORE_DIR)/spc7110dec.c \
$(CORE_DIR)/srtc.c \
$(CORE_DIR)/tile.c \
$(CORE_DIR)/apu_blargg.c \

View File

@ -340,7 +340,7 @@ void retro_init(void)
void retro_deinit(void)
{
if (Settings.SPC7110)
(*CleanUp7110)();
Del7110Gfx();
S9xDeinitGFX();
S9xDeinitDisplay();
@ -499,50 +499,6 @@ void JustifierButtons(uint32_t* justifiers)
{
}
char* osd_GetPackDir()
{
static char filename[_MAX_PATH];
memset(filename, 0, _MAX_PATH);
char dir [_MAX_DIR + 1];
char drive [_MAX_DRIVE + 1];
char name [_MAX_FNAME + 1];
char ext [_MAX_EXT + 1];
_splitpath(Memory.ROMFilename, drive, dir, name, ext);
_makepath(filename, drive, dir, NULL, NULL);
if (!strncmp((char*)&Memory.ROM [0xffc0], "SUPER POWER LEAG 4 ", 21))
{
if (getenv("SPL4PACK"))
return getenv("SPL4PACK");
else
strcat(filename, "/SPL4-SP7");
}
else if (!strncmp((char*)&Memory.ROM [0xffc0], "MOMOTETSU HAPPY ", 21))
{
if (getenv("MDHPACK"))
return getenv("MDHPACK");
else
strcat(filename, "/SMHT-SP7");
}
else if (!strncmp((char*)&Memory.ROM [0xffc0], "HU TENGAI MAKYO ZERO ", 21))
{
if (getenv("FEOEZPACK"))
return getenv("FEOEZPACK");
else
strcat(filename, "/FEOEZSP7");
}
else if (!strncmp((char*)&Memory.ROM [0xffc0], "JUMP TENGAIMAKYO ZERO", 21))
{
if (getenv("SJNSPACK"))
return getenv("SJNSPACK");
else
strcat(filename, "/SJUMPSP7");
}
else strcat(filename, "/MISC-SP7");
return filename;
}
unsigned retro_get_region()
{
return Settings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
@ -577,11 +533,9 @@ void retro_get_system_av_info(struct retro_system_av_info* info)
info->geometry.aspect_ratio = 4.0 / 3.0;
if (!Settings.PAL)
info->timing.fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE *
SNES_MAX_NTSC_VCOUNTER));
info->timing.fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE * SNES_MAX_NTSC_VCOUNTER));
else
info->timing.fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE *
SNES_MAX_PAL_VCOUNTER));
info->timing.fps = (SNES_CLOCK_SPEED * 6.0 / (SNES_CYCLES_PER_SCANLINE * SNES_MAX_PAL_VCOUNTER));
info->timing.sample_rate = samplerate;
}
@ -597,18 +551,16 @@ size_t retro_serialize_size(void)
return sizeof(CPU) + sizeof(ICPU) + sizeof(PPU) + sizeof(DMA) +
0x10000 + 0x20000 + 0x20000 + 0x8000 +
#ifndef USE_BLARGG_APU
sizeof(APU) + sizeof(IAPU) + 0x10000
sizeof(APU) + sizeof(IAPU) + 0x10000 +
#else
SPC_SAVE_STATE_BLOCK_SIZE
SPC_SAVE_STATE_BLOCK_SIZE +
#endif
+ sizeof(SA1) +
sizeof(s7r) + sizeof(rtc_f9);
sizeof(SA1) + sizeof(s7r) + sizeof(rtc_f9);
}
bool retro_serialize(void* data, size_t size)
{
int32_t i;
S9xUpdateRTC();
S9xSRTCPreSaveState();
uint8_t* buffer = data;
@ -721,7 +673,6 @@ bool retro_unserialize(const void* data, size_t size)
S9xUnpackStatus();
S9xFixCycles();
S9xReschedule();
return true;
}

View File

@ -7,8 +7,9 @@
#include "dma.h"
#include "apu.h"
#include "sa1.h"
#include "spc7110.h"
#include "sdd1emu.h"
#include "spc7110.h"
#include "spc7110dec.h"
static uint8_t sdd1_decode_buffer[0x10000];
@ -17,7 +18,7 @@ extern uint8_t* HDMAMemPointers [8];
extern uint8_t* HDMABasePointers [8];
/**********************************************************************************************/
/* S9xDoDMA() */
/* S9xDoDMA() */
/* This function preforms the general dma transfer */
/**********************************************************************************************/
void S9xDoDMA(uint8_t Channel)
@ -36,7 +37,6 @@ void S9xDoDMA(uint8_t Channel)
CPU.InDMA = true;
d = &DMA[Channel];
count = d->TransferBytes;
// Prepare for custom chip DMA
@ -66,7 +66,7 @@ void S9xDoDMA(uint8_t Channel)
{
if (d->AAddressFixed && Memory.FillRAM [0x4801] > 0)
{
uint8_t *in_ptr;
uint8_t* in_ptr;
// XXX: Should probably verify that we're DMAing from ROM?
// And somewhere we should make sure we're not running across a mapping boundary too.
@ -85,43 +85,23 @@ void S9xDoDMA(uint8_t Channel)
}
if (Settings.SPC7110 && (d->AAddress == 0x4800 || d->ABank == 0x50))
{
uint32_t i;
int32_t icount;
i = (s7r.reg4805 | (s7r.reg4806 << 8));
i *= s7r.AlignBy;
i += s7r.bank50Internal;
i %= DECOMP_BUFFER_SIZE;
if ((i + d->TransferBytes) < DECOMP_BUFFER_SIZE)
spc7110_dma = &s7r.bank50[i];
else
{
uint32_t j;
spc7110_dma = (uint8_t*)malloc(d->TransferBytes);
j = DECOMP_BUFFER_SIZE - i;
memcpy(spc7110_dma, &s7r.bank50[i], j);
memcpy(&spc7110_dma[j], s7r.bank50, d->TransferBytes - j);
s7_wrap = true;
}
icount = s7r.reg4809 | (s7r.reg480A << 8);
icount -= d->TransferBytes;
int32_t c;
spc7110_dma = &s7r.bank50[0];
for(c = 0; c < count; c++)
s7r.bank50[c] = spc7110dec_read();
int32_t icount = (s7r.reg4809 | (s7r.reg480A << 8)) - count;
s7r.reg4809 = 0x00ff & icount;
s7r.reg480A = (0xff00 & icount) >> 8;
s7r.bank50Internal += d->TransferBytes;
s7r.bank50Internal %= DECOMP_BUFFER_SIZE;
inc = 1;
d->AAddress -= count;
}
if (d->BAddress == 0x18 && SA1.in_char_dma && (d->ABank & 0xf0) == 0x40)
{
int32_t i;
// Perform packed bitmap to PPU character format conversion on the
// data before transmitting it to V-RAM via-DMA.
int32_t i;
int32_t num_chars = 1 << ((Memory.FillRAM [0x2231] >> 2) & 7);
int32_t depth = (Memory.FillRAM [0x2231] & 3) == 0 ? 8 :
(Memory.FillRAM [0x2231] & 3) == 1 ? 4 : 2;
int32_t depth = (Memory.FillRAM [0x2231] & 3) == 0 ? 8 : (Memory.FillRAM [0x2231] & 3) == 1 ? 4 : 2;
int32_t bytes_per_char = 8 * depth;
int32_t bytes_per_line = depth * num_chars;
@ -138,13 +118,11 @@ void S9xDoDMA(uint8_t Channel)
switch (depth)
{
case 2:
for (i = 0; i < count; i += inc, base += char_line_bytes,
inc = char_line_bytes, char_count = num_chars)
for (i = 0 ; i < count ; i += inc, base += char_line_bytes, inc = char_line_bytes, char_count = num_chars)
{
uint32_t j;
uint8_t* line = base + (num_chars - char_count) * 2;
for (j = 0; j < char_count && p - buffer < count;
j++, line += 2)
for (j = 0 ; j < char_count && p - buffer < count ; j++, line += 2)
{
int32_t b, l;
uint8_t* q = line;
@ -168,13 +146,11 @@ void S9xDoDMA(uint8_t Channel)
}
break;
case 4:
for (i = 0; i < count; i += inc, base += char_line_bytes,
inc = char_line_bytes, char_count = num_chars)
for (i = 0 ; i < count ; i += inc, base += char_line_bytes, inc = char_line_bytes, char_count = num_chars)
{
uint32_t j;
uint8_t* line = base + (num_chars - char_count) * 4;
for (j = 0; j < char_count && p - buffer < count;
j++, line += 4)
for (j = 0 ; j < char_count && p - buffer < count ; j++, line += 4)
{
uint8_t* q = line;
int32_t b, l;
@ -199,13 +175,11 @@ void S9xDoDMA(uint8_t Channel)
}
break;
case 8:
for (i = 0; i < count; i += inc, base += char_line_bytes,
inc = char_line_bytes, char_count = num_chars)
for(i = 0 ; i < count ; i += inc, base += char_line_bytes, inc = char_line_bytes, char_count = num_chars)
{
uint8_t* line = base + (num_chars - char_count) * 8;
uint32_t j;
for (j = 0; j < char_count && p - buffer < count;
j++, line += 8)
for(j = 0 ; j < char_count && p - buffer < count ; j++, line += 8)
{
uint8_t* q = line;
int32_t b, l;
@ -242,7 +216,7 @@ void S9xDoDMA(uint8_t Channel)
* XXX: GetBasePointer whenever we cross a boundry, and when
* XXX: GetBasePointer returns (0) to take the 'slow path' and use
* XXX: S9xGetByte instead of *base. GetBasePointer() would want to
* XXX: return (0) for MAP_PPU and whatever else is a register range
* XXX: return 0 for MAP_PPU and whatever else is a register range
* XXX: rather than a RAM/ROM block, and we'd want to detect MAP_PPU
* XXX: (or specifically, Address Bus B addresses $2100-$21FF in
* XXX: banks $00-$3F) specially and treat it as MAP_NONE (since
@ -289,8 +263,7 @@ void S9xDoDMA(uint8_t Channel)
Work = *(base + p);
REGISTER_2104(Work);
p += inc;
}
while (--count > 0);
} while (--count > 0);
break;
case 0x18:
IPPU.FirstVRAMRead = true;
@ -301,8 +274,7 @@ void S9xDoDMA(uint8_t Channel)
Work = *(base + p);
REGISTER_2118_linear(Work);
p += inc;
}
while (--count > 0);
} while (--count > 0);
}
else
{
@ -311,8 +283,7 @@ void S9xDoDMA(uint8_t Channel)
Work = *(base + p);
REGISTER_2118_tile(Work);
p += inc;
}
while (--count > 0);
} while (--count > 0);
}
break;
case 0x19:
@ -324,8 +295,7 @@ void S9xDoDMA(uint8_t Channel)
Work = *(base + p);
REGISTER_2119_linear(Work);
p += inc;
}
while (--count > 0);
} while (--count > 0);
}
else
{
@ -334,8 +304,7 @@ void S9xDoDMA(uint8_t Channel)
Work = *(base + p);
REGISTER_2119_tile(Work);
p += inc;
}
while (--count > 0);
} while (--count > 0);
}
break;
case 0x22:
@ -344,8 +313,7 @@ void S9xDoDMA(uint8_t Channel)
Work = *(base + p);
REGISTER_2122(Work);
p += inc;
}
while (--count > 0);
} while (--count > 0);
break;
case 0x80:
do
@ -353,8 +321,7 @@ void S9xDoDMA(uint8_t Channel)
Work = *(base + p);
REGISTER_2180(Work);
p += inc;
}
while (--count > 0);
} while (--count > 0);
break;
default:
do
@ -362,8 +329,7 @@ void S9xDoDMA(uint8_t Channel)
Work = *(base + p);
S9xSetPPU(Work, 0x2100 + d->BAddress);
p += inc;
}
while (--count > 0);
} while (--count > 0);
break;
}
}
@ -459,8 +425,7 @@ void S9xDoDMA(uint8_t Channel)
S9xSetPPU(Work, 0x2101 + d->BAddress);
p += inc;
count -= 4;
}
while (count > 0);
} while (count > 0);
}
else if (d->TransferMode == 4)
{
@ -488,8 +453,7 @@ void S9xDoDMA(uint8_t Channel)
S9xSetPPU(Work, 0x2103 + d->BAddress);
p += inc;
count -= 4;
}
while (count > 0);
} while (count > 0);
}
}
else
@ -549,7 +513,6 @@ void S9xDoDMA(uint8_t Channel)
d->AAddress += inc;
count--;
break;
case 4:
Work = S9xGetPPU(0x2100 + d->BAddress);
S9xSetByte(Work, (d->ABank << 16) + d->AAddress);
@ -574,13 +537,11 @@ void S9xDoDMA(uint8_t Channel)
d->AAddress += inc;
count--;
break;
default:
count = 0;
break;
}
}
while (count);
} while (count);
}
#ifndef USE_BLARGG_APU
IAPU.APUExecuting = Settings.APUEnabled;
@ -593,20 +554,15 @@ void S9xDoDMA(uint8_t Channel)
while (CPU.Cycles > CPU.NextEvent)
S9xDoHBlankProcessing_NoSFX();
if (Settings.SPC7110 && spc7110_dma)
{
if (spc7110_dma && s7_wrap)
free(spc7110_dma);
}
if (Settings.SPC7110 && spc7110_dma && s7_wrap)
free(spc7110_dma);
update_address:
// Super Punch-Out requires that the A-BUS address be updated after the
// DMA transfer.
// Super Punch-Out requires that the A-BUS address be updated after the DMA transfer.
Memory.FillRAM[0x4302 + (Channel << 4)] = (uint8_t) d->AAddress;
Memory.FillRAM[0x4303 + (Channel << 4)] = d->AAddress >> 8;
// Secret of the Mana requires that the DMA bytes transfer count be set to
// zero when DMA has completed.
// Secret of the Mana requires that the DMA bytes transfer count be set to zero when DMA has completed.
Memory.FillRAM [0x4305 + (Channel << 4)] = 0;
Memory.FillRAM [0x4306 + (Channel << 4)] = 0;
@ -619,13 +575,8 @@ update_address:
void S9xStartHDMA()
{
uint8_t i;
IPPU.HDMA = Memory.FillRAM [0x420c];
if (Settings.DisableHDMA)
IPPU.HDMA = 0;
else
IPPU.HDMA = Memory.FillRAM [0x420c];
//per anomie timing post
if (IPPU.HDMA != 0)
CPU.Cycles += ONE_CYCLE * 3;
@ -718,8 +669,7 @@ uint8_t S9xDoHDMA(uint8_t byte)
p->IndirectAddress = p->Address;
}
if (!(HDMABasePointers [d] = HDMAMemPointers [d] =
S9xGetMemPointer((p->IndirectBank << 16) + p->IndirectAddress)))
if (!(HDMABasePointers [d] = HDMAMemPointers [d] = S9xGetMemPointer((p->IndirectBank << 16) + p->IndirectAddress)))
{
/* XXX: Instead of this, goto a slow path that first
* XXX: verifies src!=Address Bus B, then uses

View File

@ -7,5 +7,4 @@ void S9xResetDMA(void);
uint8_t S9xDoHDMA(uint8_t);
void S9xStartHDMA(void);
void S9xDoDMA(uint8_t);
#endif

View File

@ -21,10 +21,7 @@ void S9xResetDSP1()
uint8_t S9xGetDSP(uint16_t address)
{
uint8_t t;
t = (*GetDSP)(address);
return (t);
return (*GetDSP)(address);
}
void S9xSetDSP(uint8_t byte, uint16_t address)
@ -48,8 +45,7 @@ void DSP1SetByte(uint8_t byte, uint16_t address)
DSP1.in_index = 0;
DSP1.waiting4command = false;
DSP1.first_parameter = true;
// Mario Kart uses 0x00, 0x02, 0x06, 0x0c, 0x28, 0x0a
switch (byte)
switch (byte) // Mario Kart uses 0x00, 0x02, 0x06, 0x0c, 0x28, 0x0a
{
case 0x07:
case 0x0a:
@ -628,8 +624,7 @@ void DSP2SetByte(uint8_t byte, uint16_t address)
uint32_t temp;
#endif
if ((address & 0xf000) == 0x6000 ||
(address >= 0x8000 && address < 0xc000))
if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000))
{
if (DSP1.waiting4command)
{

View File

@ -199,9 +199,6 @@ inline void S9xSetByte(uint8_t Byte, uint32_t Address)
case MAP_C4:
S9xSetC4(Byte, Address & 0xffff);
return;
case MAP_SPC7110_DRAM:
s7r.bank50[(Address & 0xffff)] = (uint8_t) Byte;
break;
case MAP_OBC_RAM:
SetOBC1(Byte, Address & 0xFFFF);
return;
@ -297,10 +294,6 @@ inline void S9xSetWord(uint16_t Word, uint32_t Address)
#endif
CPU.SRAMModified = true;
return;
case MAP_SPC7110_DRAM:
s7r.bank50[(Address & 0xffff)] = (uint8_t) Word;
s7r.bank50[((Address + 1) & 0xffff)] = (uint8_t) Word;
break;
case MAP_SA1RAM:
*(Memory.SRAM + (Address & 0xffff)) = (uint8_t) Word;
*(Memory.SRAM + ((Address + 1) & 0xffff)) = (uint8_t)(Word >> 8);

View File

@ -578,8 +578,7 @@ bool LoadROM(
uint8_t* RomHeader = Memory.ROM;
Memory.ExtendedFormat = NOPE;
if (CleanUp7110 != NULL)
(*CleanUp7110)();
Del7110Gfx();
memset(&SNESGameFixes, 0, sizeof(SNESGameFixes));
SNESGameFixes.SRAMInitialValue = 0x60;

File diff suppressed because it is too large Load Diff

View File

@ -6,15 +6,7 @@
#define DECOMP_BUFFER_SIZE 0x10000
extern void (*LoadUp7110)(char*);
extern void (*CleanUp7110)(void);
extern void (*Copy7110)(void);
extern uint16_t cacheMegs;
void Del7110Gfx(void);
void Close7110Gfx(void);
void Drop7110Gfx(void);
uint8_t S9xGetSPC7110(uint16_t Address);
uint8_t S9xGetSPC7110Byte(uint32_t Address);
uint8_t* Get7110BasePtr(uint32_t);
@ -26,12 +18,6 @@ void S9xUpdateRTC(void);
void Do7110Logging(void);
int32_t S9xRTCDaysInMonth(int32_t month, int32_t year);
//These are platform-dependant functions, but should work on
//most systems that use GNU compilers, and on Win32.
void SPC7110Load(char*);
void SPC7110Open(char*);
void SPC7110Grab(char*);
typedef struct
{
uint8_t reg[16];
@ -99,9 +85,4 @@ typedef struct
extern SPC7110Regs s7r;
extern S7RTC rtc_f9;
// These are defined in spc7110.cpp
bool S9xSaveSPC7110RTC(S7RTC* rtc_f9);
bool S9xLoadSPC7110RTC(S7RTC* rtc_f9);
#endif

619
source/spc7110dec.c Normal file
View File

@ -0,0 +1,619 @@
#include "../copyright"
#include "memmap.h"
#include "spc7110dec.h"
#define SPC7110_DECOMP_BUFFER_SIZE 64 /* must be >= 64, and must be a power of two */
static const uint8_t evolution_table[53][4] = /* { prob, nextlps, nextmps, toggle invert } */
{
{0x5a, 1, 1, 1}, {0x25, 6, 2, 0}, {0x11, 8, 3, 0},
{0x08, 10, 4, 0}, {0x03, 12, 5, 0}, {0x01, 15, 5, 0},
{0x5a, 7, 7, 1}, {0x3f, 19, 8, 0}, {0x2c, 21, 9, 0},
{0x20, 22, 10, 0}, {0x17, 23, 11, 0}, {0x11, 25, 12, 0},
{0x0c, 26, 13, 0}, {0x09, 28, 14, 0}, {0x07, 29, 15, 0},
{0x05, 31, 16, 0}, {0x04, 32, 17, 0}, {0x03, 34, 18, 0},
{0x02, 35, 5, 0}, {0x5a, 20, 20, 1}, {0x48, 39, 21, 0},
{0x3a, 40, 22, 0}, {0x2e, 42, 23, 0}, {0x26, 44, 24, 0},
{0x1f, 45, 25, 0}, {0x19, 46, 26, 0}, {0x15, 25, 27, 0},
{0x11, 26, 28, 0}, {0x0e, 26, 29, 0}, {0x0b, 27, 30, 0},
{0x09, 28, 31, 0}, {0x08, 29, 32, 0}, {0x07, 30, 33, 0},
{0x05, 31, 34, 0}, {0x04, 33, 35, 0}, {0x04, 33, 36, 0},
{0x03, 34, 37, 0}, {0x02, 35, 38, 0}, {0x02, 36, 5, 0},
{0x58, 39, 40, 1}, {0x4d, 47, 41, 0}, {0x43, 48, 42, 0},
{0x3b, 49, 43, 0}, {0x34, 50, 44, 0}, {0x2e, 51, 45, 0},
{0x29, 44, 46, 0}, {0x25, 45, 24, 0}, {0x56, 47, 48, 1},
{0x4f, 47, 49, 0}, {0x47, 48, 50, 0}, {0x41, 49, 51, 0},
{0x3c, 50, 52, 0}, {0x37, 51, 43, 0},
};
static const uint8_t mode2_context_table[32][2] = /* { next 0, next 1 } */
{
{1, 2}, {3, 8}, {13, 14}, {15, 16},
{17, 18}, {19, 20}, {21, 22}, {23, 24},
{25, 26}, {25, 26}, {25, 26}, {25, 26},
{25, 26}, {27, 28}, {29, 30}, {31, 31},
{31, 31}, {31, 31}, {31, 31}, {31, 31},
{31, 31}, {31, 31}, {31, 31}, {31, 31},
{31, 31}, {31, 31}, {31, 31}, {31, 31},
{31, 31}, {31, 31}, {31, 31}, {31, 31},
};
typedef struct
{
uint32_t mode;
uint32_t offset;
uint32_t original_mode;
uint32_t original_offset;
uint32_t original_index;
uint32_t read_counter;
uint8_t *buffer;
uint32_t buffer_rdoffset;
uint32_t buffer_wroffset;
uint32_t buffer_length;
struct ContextState
{
uint8_t index;
uint8_t invert;
} context[32];
uint32_t morton16[2][256];
uint32_t morton32[4][256];
} SPC7110Decomp;
SPC7110Decomp decomp;
uint8_t spc7110dec_read()
{
decomp.read_counter++;
if(decomp.buffer_length == 0)
{
switch(decomp.mode)
{
case 0:
spc7110dec_mode0(false);
break;
case 1:
spc7110dec_mode1(false);
break;
case 2:
spc7110dec_mode2(false);
break;
default:
return 0x00;
}
}
uint8_t data = decomp.buffer[decomp.buffer_rdoffset++];
decomp.buffer_rdoffset &= SPC7110_DECOMP_BUFFER_SIZE - 1;
decomp.buffer_length--;
return data;
}
void spc7110dec_write(uint8_t data)
{
decomp.buffer[decomp.buffer_wroffset++] = data;
decomp.buffer_wroffset &= SPC7110_DECOMP_BUFFER_SIZE - 1;
decomp.buffer_length++;
}
uint8_t spc7110dec_dataread()
{
uint32_t size = Memory.CalculatedSize - 0x100000;
while(decomp.offset >= size)
decomp.offset -= size;
return Memory.ROM[0x100000 + decomp.offset++];
}
void spc7110dec_clear(uint32_t mode, uint32_t offset, uint32_t index)
{
decomp.original_mode = mode;
decomp.original_offset = offset;
decomp.original_index = index;
decomp.mode = mode;
decomp.offset = offset;
decomp.buffer_rdoffset = 0;
decomp.buffer_wroffset = 0;
decomp.buffer_length = 0;
uint32_t i;
for(i = 0; i < 32; i++) // reset decomp.context states
{
decomp.context[i].index = 0;
decomp.context[i].invert = 0;
}
switch(decomp.mode)
{
case 0:
spc7110dec_mode0(true);
break;
case 1:
spc7110dec_mode1(true);
break;
case 2:
spc7110dec_mode2(true);
break;
}
while(index--) // decompress up to requested output data index
spc7110dec_read();
decomp.read_counter = 0;
}
void spc7110dec_mode0(bool init)
{
static uint8_t val, in, span;
static int32_t out, inverts, lps, in_count;
if(init)
{
out = inverts = lps = 0;
span = 0xff;
val = spc7110dec_dataread();
in = spc7110dec_dataread();
in_count = 8;
return;
}
while(decomp.buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
{
uint32_t bit;
for(bit = 0; bit < 8; bit++)
{
/* Get decomp.context */
uint8_t mask = (1 << (bit & 3)) - 1;
uint8_t con = mask + ((inverts & mask) ^ (lps & mask));
if(bit > 3)
con += 15;
/* Get prob and mps */
uint32_t prob = spc7110dec_probability(con);
uint32_t mps = (((out >> 15) & 1) ^ decomp.context[con].invert);
/* Get bit */
uint32_t flag_lps;
if(val <= span - prob) // mps
{
span = span - prob;
out = (out << 1) + mps;
flag_lps = 0;
}
else // lps
{
val = val - (span - (prob - 1));
span = prob - 1;
out = (out << 1) + 1 - mps;
flag_lps = 1;
}
/* Renormalize */
uint32_t shift = 0;
while(span < 0x7f)
{
shift++;
span = (span << 1) + 1;
val = (val << 1) + (in >> 7);
in <<= 1;
if(--in_count == 0)
{
in = spc7110dec_dataread();
in_count = 8;
}
}
/* Update processing info */
lps = (lps << 1) + flag_lps;
inverts = (inverts << 1) + decomp.context[con].invert;
/* Update context state */
if(flag_lps & spc7110dec_toggle_invert(con))
decomp.context[con].invert ^= 1;
if(flag_lps)
decomp.context[con].index = spc7110dec_next_lps(con);
else if(shift)
decomp.context[con].index = spc7110dec_next_mps(con);
}
/* Save byte */
spc7110dec_write(out);
}
}
void spc7110dec_mode1(bool init)
{
static uint32_t pixelorder[4], realorder[4];
static uint8_t in, val, span;
static int32_t out, inverts, lps, in_count;
if(init)
{
uint32_t i;
for(i = 0; i < 4; i++)
pixelorder[i] = i;
out = inverts = lps = 0;
span = 0xff;
val = spc7110dec_dataread();
in = spc7110dec_dataread();
in_count = 8;
return;
}
while(decomp.buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
{
uint32_t pixel;
for(pixel = 0; pixel < 8; pixel++)
{
/* Get first symbol decomp.context */
uint32_t a = ((out >> (1 * 2)) & 3);
uint32_t b = ((out >> (7 * 2)) & 3);
uint32_t c = ((out >> (8 * 2)) & 3);
uint32_t con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
/* Update pixel order */
uint32_t m, n;
for(m = 0; m < 4; m++)
if(pixelorder[m] == a)
break;
for(n = m; n > 0; n--)
pixelorder[n] = pixelorder[n - 1];
pixelorder[0] = a;
/* Calculate the real pixel order */
for(m = 0; m < 4; m++)
realorder[m] = pixelorder[m];
/* Rotate reference pixel c value to top */
for(m = 0; m < 4; m++)
if(realorder[m] == c)
break;
for(n = m; n > 0; n--)
realorder[n] = realorder[n - 1];
realorder[0] = c;
/* Rotate reference pixel b value to top */
for(m = 0; m < 4; m++)
if(realorder[m] == b)
break;
for(n = m; n > 0; n--)
realorder[n] = realorder[n - 1];
realorder[0] = b;
/* Rotate reference pixel a value to top */
for(m = 0; m < 4; m++)
if(realorder[m] == a)
break;
for(n = m; n > 0; n--)
realorder[n] = realorder[n - 1];
realorder[0] = a;
/* Get 2 symbols */
uint32_t bit;
for(bit = 0; bit < 2; bit++)
{
/* Get prob */
uint32_t prob = spc7110dec_probability(con);
/* Get symbol */
uint32_t flag_lps;
if(val <= span - prob) // mps
{
span = span - prob;
flag_lps = 0;
}
else // lps
{
val = val - (span - (prob - 1));
span = prob - 1;
flag_lps = 1;
}
/* Renormalize */
uint32_t shift = 0;
while(span < 0x7f)
{
shift++;
span = (span << 1) + 1;
val = (val << 1) + (in >> 7);
in <<= 1;
if(--in_count == 0)
{
in = spc7110dec_dataread();
in_count = 8;
}
}
/* Update processing info */
lps = (lps << 1) + flag_lps;
inverts = (inverts << 1) + decomp.context[con].invert;
/* Update context state */
if(flag_lps & spc7110dec_toggle_invert(con))
decomp.context[con].invert ^= 1;
if(flag_lps)
decomp.context[con].index = spc7110dec_next_lps(con);
else if(shift)
decomp.context[con].index = spc7110dec_next_mps(con);
/* Get next decomp.context */
con = 5 + (con << 1) + ((lps ^ inverts) & 1);
}
/* Get pixel */
b = realorder[(lps ^ inverts) & 3];
out = (out << 2) + b;
}
/* Turn pixel data into bitplanes */
uint32_t data = spc7110dec_morton_2x8(out);
spc7110dec_write(data >> 8);
spc7110dec_write(data >> 0);
}
}
void spc7110dec_mode2(bool init)
{
static uint32_t pixelorder[16], realorder[16];
static uint8_t bitplanebuffer[16], buffer_index;
static uint8_t in, val, span;
static int32_t out0, out1, inverts, lps, in_count;
if(init)
{
uint32_t i;
for(i = 0; i < 16; i++)
pixelorder[i] = i;
buffer_index = 0;
out0 = out1 = inverts = lps = 0;
span = 0xff;
val = spc7110dec_dataread();
in = spc7110dec_dataread();
in_count = 8;
return;
}
while(decomp.buffer_length < (SPC7110_DECOMP_BUFFER_SIZE >> 1))
{
uint32_t pixel;
for(pixel = 0; pixel < 8; pixel++)
{
/* Get first symbol context */
uint32_t a = ((out0 >> (0 * 4)) & 15);
uint32_t b = ((out0 >> (7 * 4)) & 15);
uint32_t c = ((out1 >> (0 * 4)) & 15);
uint32_t con = 0;
uint32_t refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
/* Update pixel order */
uint32_t m, n;
for(m = 0; m < 16; m++)
if(pixelorder[m] == a)
break;
for(n = m; n > 0; n--)
pixelorder[n] = pixelorder[n - 1];
pixelorder[0] = a;
/* Calculate the real pixel order */
for(m = 0; m < 16; m++)
realorder[m] = pixelorder[m];
/* Rotate reference pixel c value to top */
for(m = 0; m < 16; m++)
if(realorder[m] == c)
break;
for(n = m; n > 0; n--)
realorder[n] = realorder[n - 1];
realorder[0] = c;
/* Rotate reference pixel b value to top */
for(m = 0; m < 16; m++)
if(realorder[m] == b)
break;
for(n = m; n > 0; n--)
realorder[n] = realorder[n - 1];
realorder[0] = b;
/* Rotate reference pixel a value to top */
for(m = 0; m < 16; m++)
if(realorder[m] == a)
break;
for(n = m; n > 0; n--)
realorder[n] = realorder[n - 1];
realorder[0] = a;
/* Get 4 symbols */
uint32_t bit;
for(bit = 0; bit < 4; bit++)
{
/* Get prob */
uint32_t prob = spc7110dec_probability(con);
/* Get symbol */
uint32_t flag_lps;
if(val <= span - prob) // mps
{
span = span - prob;
flag_lps = 0;
}
else // lps
{
val = val - (span - (prob - 1));
span = prob - 1;
flag_lps = 1;
}
/* Renormalize */
uint32_t shift = 0;
while(span < 0x7f)
{
shift++;
span = (span << 1) + 1;
val = (val << 1) + (in >> 7);
in <<= 1;
if(--in_count == 0)
{
in = spc7110dec_dataread();
in_count = 8;
}
}
/* Update processing info */
lps = (lps << 1) + flag_lps;
uint32_t invertbit = decomp.context[con].invert;
inverts = (inverts << 1) + invertbit;
/* Update decomp.context state */
if(flag_lps & spc7110dec_toggle_invert(con))
decomp.context[con].invert ^= 1;
if(flag_lps)
decomp.context[con].index = spc7110dec_next_lps(con);
else if(shift)
decomp.context[con].index = spc7110dec_next_mps(con);
/* Get next decomp.context */
con = mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0);
}
/* Get pixel */
b = realorder[(lps ^ inverts) & 0x0f];
out1 = (out1 << 4) + ((out0 >> 28) & 0x0f);
out0 = (out0 << 4) + b;
}
/* Convert pixel data into bitplanes */
uint32_t data = spc7110dec_morton_4x8(out0);
spc7110dec_write(data >> 24);
spc7110dec_write(data >> 16);
bitplanebuffer[buffer_index++] = data >> 8;
bitplanebuffer[buffer_index++] = data >> 0;
if(buffer_index == 16)
{
uint32_t i;
for(i = 0; i < 16; i++)
spc7110dec_write(bitplanebuffer[i]);
buffer_index = 0;
}
}
}
uint8_t spc7110dec_probability(uint32_t n)
{
return evolution_table[decomp.context[n].index][0];
}
uint8_t spc7110dec_next_lps(uint32_t n)
{
return evolution_table[decomp.context[n].index][1];
}
uint8_t spc7110dec_next_mps(uint32_t n)
{
return evolution_table[decomp.context[n].index][2];
}
bool spc7110dec_toggle_invert(uint32_t n)
{
return evolution_table[decomp.context[n].index][3];
}
uint32_t spc7110dec_morton_2x8(uint32_t data)
{
/* Reverse morton lookup: de-interleave two 8-bit values
* 15, 13, 11, 9, 7, 5, 3, 1 -> 15-8
* 14, 12, 10, 8, 6, 4, 2, 0 -> 7 -0 */
return decomp.morton16[0][(data >> 0) & 255] + decomp.morton16[1][(data >> 8) & 255];
}
uint32_t spc7110dec_morton_4x8(uint32_t data)
{
/* Reverse morton lookup: de-interleave four 8-bit values
* 31, 27, 23, 19, 15, 11, 7, 3 -> 31-24
* 30, 26, 22, 18, 14, 10, 6, 2 -> 23-16
* 29, 25, 21, 17, 13, 9, 5, 1 -> 15-8
* 28, 24, 20, 16, 12, 8, 4, 0 -> 7 -0 */
return decomp.morton32[0][(data >> 0) & 255] + decomp.morton32[1][(data >> 8) & 255] + decomp.morton32[2][(data >> 16) & 255] + decomp.morton32[3][(data >> 24) & 255];
}
void spc7110dec_reset()
{
/* Mode 3 is invalid; this is treated as a special case to always return 0x00
* set to mode 3 so that reading decomp port before starting first decomp will return 0x00 */
decomp.mode = 3;
decomp.buffer_rdoffset = 0;
decomp.buffer_wroffset = 0;
decomp.buffer_length = 0;
}
void spc7110dec_init()
{
decomp.buffer = malloc(SPC7110_DECOMP_BUFFER_SIZE);
spc7110dec_reset();
/* Initialize reverse morton lookup tables */
uint32_t i;
for(i = 0; i < 256; i++)
{
#define map(x, y) (((i >> x) & 1) << y)
/* 2x8-bit */
decomp.morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6) + map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4);
decomp.morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2) + map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0);
/* 4x8-bit */
decomp.morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7) + map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6);
decomp.morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5) + map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4);
decomp.morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3) + map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2);
decomp.morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1) + map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0);
#undef map
}
}
void spc7110dec_deinit()
{
free(decomp.buffer);
}

28
source/spc7110dec.h Normal file
View File

@ -0,0 +1,28 @@
#include "../copyright"
#ifndef _SPC7110DEC_H_
#define _SPC7110DEC_H_
#include "port.h"
uint8_t spc7110dec_read(void);
void spc7110dec_clear(uint32_t mode, uint32_t offset, uint32_t index);
void spc7110dec_reset(void);
void spc7110dec_init(void);
void spc7110dec_deinit(void);
void spc7110dec_write(uint8_t data);
uint8_t spc7110dec_dataread(void);
void spc7110dec_mode0(bool init);
void spc7110dec_mode1(bool init);
void spc7110dec_mode2(bool init);
uint8_t spc7110dec_probability(uint32_t n);
uint8_t spc7110dec_next_lps(uint32_t n);
uint8_t spc7110dec_next_mps(uint32_t n);
bool spc7110dec_toggle_invert(uint32_t n);
uint32_t spc7110dec_morton_2x8(uint32_t data);
uint32_t spc7110dec_morton_4x8(uint32_t data);
#endif

View File

@ -34,12 +34,10 @@ Index Description Range (nibble)
SRTC_DATA rtc;
static int32_t month_keys[12] = { 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6 };
/*********************************************************************************************
*
* Note, if you are doing a save state for this game:
*
* On save:
@ -50,8 +48,6 @@ static int32_t month_keys[12] = { 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6 };
*
* restore the rtc data structure
* rtc.system_timestamp = time (NULL);
*
*
*********************************************************************************************/
@ -68,9 +64,7 @@ void S9xHardResetSRTC(void)
rtc.mode = MODE_READ;
rtc.count_enable = false;
rtc.needs_init = true;
// Get system timestamp
rtc.system_timestamp = time(NULL);
rtc.system_timestamp = time(NULL); // Get system timestamp
}
/**********************************************************************************************/
@ -83,10 +77,9 @@ uint32_t S9xSRTCComputeDayOfWeek(void)
uint32_t month = rtc.data[8];
uint32_t day = rtc.data[7] * 10 + rtc.data[6];
uint32_t day_of_week;
year += (rtc.data[11] - 9) * 100;
// Range check the month for valid array indicies
// Range check the month for valid array indices
if (month > 12)
month = 1;
@ -102,48 +95,37 @@ uint32_t S9xSRTCComputeDayOfWeek(void)
/**********************************************************************************************/
/* S9xSRTCDaysInMonth(void) */
/* S9xSRTCDaysInMonth() */
/* Return the number of days in a specific month for a certain year */
/**********************************************************************************************/
int32_t S9xSRTCDaysInMmonth(int32_t month, int32_t year)
{
int32_t mdays;
switch (month)
switch(month)
{
case 2:
if ((year % 4 == 0)) // DKJM2 only uses 199x - 22xx
mdays = 29;
else
mdays = 28;
break;
case 4:
case 6:
case 9:
case 11:
mdays = 30;
break;
default: // months 1,3,5,7,8,10,12
mdays = 31;
break;
case 2:
if((year % 4 == 0)) /* DKJM2 only uses 199x - 22xx */
return 29;
return 28;
case 4:
case 6:
case 9:
case 11:
return 30;
default:
return 31;
}
return mdays;
}
#define DAYTICKS (60*60*24)
#define HOURTICKS (60*60)
#define MINUTETICKS 60
#define MINUTETICKS 60
#define HOURTICKS (60 * MINUTETICKS)
#define DAYTICKS (24 * HOURTICKS)
/**********************************************************************************************/
/* S9xUpdateSrtcTime(void) */
/* S9xUpdateSrtcTime() */
/* Advance the S-RTC time if counting is enabled */
/**********************************************************************************************/
void S9xUpdateSrtcTime(void)
void S9xUpdateSrtcTime(void)
{
time_t cur_systime;
int32_t time_diff;
@ -160,12 +142,6 @@ void S9xUpdateSrtcTime(void)
if (rtc.count_enable && !rtc.needs_init)
{
cur_systime = time(NULL);
// This method assumes one time_t clock tick is one second
// which should work on PCs and GNU systems.
// If your tick interval is different adjust the
// DAYTICK, HOURTICK, and MINUTETICK defines
time_diff = (int32_t)(cur_systime - rtc.system_timestamp);
rtc.system_timestamp = cur_systime;
@ -178,7 +154,6 @@ void S9xUpdateSrtcTime(void)
int32_t month;
int32_t year;
int32_t temp_days;
int32_t year_hundreds;
int32_t year_tens;
int32_t year_ones;
@ -238,7 +213,6 @@ void S9xUpdateSrtcTime(void)
{
year = rtc.data[10] * 10 + rtc.data[9];
year += (1000 + rtc.data[11] * 100);
month = rtc.data[8];
days += (rtc.data[7] * 10 + rtc.data[6]);
while (days > (temp_days = S9xSRTCDaysInMmonth(month, year)))
@ -256,7 +230,6 @@ void S9xUpdateSrtcTime(void)
year_ones = year_tens % 10;
year_tens /= 10;
year_hundreds = (year - 1000) / 100;
rtc.data[6] = days % 10;
rtc.data[7] = days / 10;
rtc.data[8] = month;
@ -272,7 +245,6 @@ void S9xUpdateSrtcTime(void)
rtc.data[3] = minutes / 10;
rtc.data[4] = hours % 10;
rtc.data[5] = hours / 10;
return;
}
}
@ -287,25 +259,18 @@ void S9xSetSRTC(uint8_t data, uint16_t Address)
{
data &= 0x0F; // Data is only 4-bits, mask out unused bits.
if (data >= 0xD)
if (data >= 0xD) // It's an RTC command
{
// It's an RTC command
switch (data)
{
case 0xD:
rtc.mode = MODE_READ;
rtc.index = -1;
break;
case 0xE:
rtc.mode = MODE_COMMAND;
break;
default:
// Ignore the write if it's an 0xF ???
// Probably should switch back to read mode -- but this
// sequence never occurs in DKJM2
break;
}
@ -318,14 +283,10 @@ void S9xSetSRTC(uint8_t data, uint16_t Address)
{
rtc.data[rtc.index++] = data;
if (rtc.index == MAX_RTC_INDEX)
if (rtc.index == MAX_RTC_INDEX) // We have all the data for the RTC load
{
// We have all the data for the RTC load
rtc.system_timestamp = time(NULL); // Get local system time
// Get the day of the week
rtc.data[rtc.index++] = S9xSRTCComputeDayOfWeek();
rtc.system_timestamp = time(NULL); // Get local system time
rtc.data[rtc.index++] = S9xSRTCComputeDayOfWeek(); // Get the day of the week
// Start RTC counting again
rtc.count_enable = true;
@ -334,55 +295,32 @@ void S9xSetSRTC(uint8_t data, uint16_t Address)
return;
}
else
{
// Attempting to write too much data
// error(); // ignore??
}
}
else if (rtc.mode == MODE_COMMAND)
{
switch (data)
{
case COMMAND_CLEAR_RTC:
// Disable RTC counter
rtc.count_enable = false;
rtc.count_enable = false; // Disable RTC counter
memset(rtc.data, 0, MAX_RTC_INDEX + 1);
rtc.index = -1;
rtc.mode = MODE_COMMAND_DONE;
break;
case COMMAND_LOAD_RTC:
// Disable RTC counter
rtc.count_enable = false;
rtc.count_enable = false; // Disable RTC counter
rtc.index = 0; // Setup for writing
rtc.mode = MODE_LOAD_RTC;
break;
default:
rtc.mode = MODE_COMMAND_DONE;
// unrecognized command - need to implement.
rtc.mode = MODE_COMMAND_DONE; // unrecognized command - need to implement.
}
return;
}
else
{
if (rtc.mode == MODE_READ)
{
// Attempting to write while in read mode. Ignore.
}
if (rtc.mode == MODE_COMMAND_DONE)
{
// Maybe this isn't an error. Maybe we should kick off
// a new E command. But is this valid?
}
}
}
/**********************************************************************************************/
/* S9xGetSRTC(void) */
/* S9xGetSRTC() */
/* This function retrieves data from the S-RTC */
/**********************************************************************************************/
uint8_t S9xGetSRTC(uint16_t Address)
@ -391,20 +329,17 @@ uint8_t S9xGetSRTC(uint16_t Address)
{
if (rtc.index < 0)
{
S9xUpdateSrtcTime(); // Only update it if the game reads it
S9xUpdateSrtcTime(); // Only update it if the game reads it
rtc.index++;
return (0x0f); // Send start marker.
return 0x0f; // Send start marker.
}
else if (rtc.index > MAX_RTC_INDEX)
{
rtc.index = -1; // Setup for next set of reads
return (0x0f); // Data done marker.
rtc.index = -1; // Setup for next set of reads
return 0x0f; // Data done marker.
}
else
{
// Feed out the data
return rtc.data[rtc.index++];
}
return rtc.data[rtc.index++]; // Feed out the data
}
else
return 0x0;
@ -415,8 +350,8 @@ void S9xSRTCPreSaveState()
if (Settings.SRTC)
{
S9xUpdateSrtcTime();
int32_t s = Memory.SRAMSize ? (1 << (Memory.SRAMSize + 3)) * 128 : 0;
if (s > 0x20000)
s = 0x20000;

View File

@ -36,11 +36,11 @@ Index Description Range (nibble)
typedef struct
{
bool needs_init;
bool count_enable; // Does RTC mark time or is it frozen
bool count_enable; // Does RTC mark time or is it frozen
uint8_t data [MAX_RTC_INDEX + 1];
int8_t index;
uint8_t mode;
time_t system_timestamp; // Of latest RTC load time
time_t system_timestamp; // Of latest RTC load time
} SRTC_DATA;
extern SRTC_DATA rtc;
@ -52,7 +52,4 @@ void S9xSRTCPreSaveState(void);
void S9xSRTCPostLoadState(void);
void S9xResetSRTC(void);
void S9xHardResetSRTC(void);
#define SRTC_SRAM_PAD (4 + 8 + 1 + MAX_RTC_INDEX)
#endif // _srtc_h