Version 4.5b with optimization to squeeze out better performance on the DS-Lite/Phat. Many more of the complex homebrews now run.

This commit is contained in:
Dave Bernazzani 2024-01-14 08:35:07 -05:00
parent 8bcbca5c27
commit 90d3e8ce8d
22 changed files with 211 additions and 122 deletions

View File

@ -14,7 +14,7 @@ include $(DEVKITARM)/ds_rules
export TARGET := NINTV-DS
export TOPDIR := $(CURDIR)
export VERSION := 4.5
export VERSION := 4.5b
ICON := -b $(CURDIR)/logo.bmp "NINTV-DS $(VERSION);wavemotion-dave;https://github.com/wavemotion-dave/NINTV-DS"

Binary file not shown.

View File

@ -26,7 +26,6 @@ GRAPHICS := gfx
#ARCH := -mthumb -mthumb-interwork
ARCH :=
#CFLAGS := -Wno-address-of-packed-member -Wno-multichar -O3 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math $(ARCH)
CFLAGS := -Ofast -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math $(ARCH) -falign-functions=16 -frename-registers
CFLAGS += $(INCLUDE) -DARM9

View File

@ -119,7 +119,8 @@ UINT16 __attribute__ ((aligned (4))) __attribute__((section(".dtcm"))) stretch[
extern UINT8 bCP1610_PIN_IN_BUSRQ;
extern UINT8 bCP1610_PIN_IN_INTRM;
extern UINT8 bCP1610_PIN_OUT_BUSAK;
extern UINT8 bHandleInterrupts;
extern UINT8 I;
AY38900::AY38900(MemoryBus* mb, GROM* go, GRAM* ga)
: Processor("AY-3-8900"),
@ -157,6 +158,8 @@ void AY38900::resetProcessor()
bordersChanged = TRUE;
colorStackChanged = TRUE;
offsetsChanged = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
//local register data
borderColor = 0;
@ -195,7 +198,8 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
bCP1610_PIN_IN_BUSRQ = TRUE;
//kick the irq line
bCP1610_PIN_IN_INTRM = FALSE;
bCP1610_PIN_IN_INTRM = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_VBLANK;
if (totalTicks >= minimum) {
@ -205,6 +209,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_START_ACTIVE_DISPLAY:
bCP1610_PIN_IN_INTRM = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
//if the display is not enabled, skip the rest of the modes
if (!displayEnabled) {
@ -221,6 +226,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
else {
previousDisplayEnabled = TRUE;
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_START_ACTIVE_DISPLAY;
if (totalTicks >= minimum) {
mode = MODE_IDLE_ACTIVE_DISPLAY;
@ -238,6 +244,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
//release SR2
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_IDLE_ACTIVE_DISPLAY +
(2*verticalOffset*TICK_LENGTH_SCANLINE);
@ -248,6 +255,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_0:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(0);
@ -257,6 +265,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_0:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -266,6 +275,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_1:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(1);
@ -275,6 +285,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_1:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -284,6 +295,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_2:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(2);
@ -293,6 +305,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_2:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -302,6 +315,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_3:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(3);
@ -311,6 +325,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_3:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -320,6 +335,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_4:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(4);
@ -329,6 +345,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_4:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -338,6 +355,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_5:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(5);
@ -347,6 +365,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_5:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -356,6 +375,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_6:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(6);
@ -365,6 +385,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_6:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -374,6 +395,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_7:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(7);
@ -383,6 +405,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_7:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -392,6 +415,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_8:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(8);
@ -401,6 +425,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_8:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -410,6 +435,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_9:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(9);
@ -419,6 +445,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_9:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -428,6 +455,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_10:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(10);
@ -437,6 +465,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_10:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
bCP1610_PIN_OUT_BUSAK = TRUE;
totalTicks += TICK_LENGTH_RENDER_ROW;
if (totalTicks >= minimum) {
@ -446,6 +475,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_11:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_FETCH_ROW;
if (totalTicks >= minimum) {
if (myConfig.bLatched) backtab.LatchRow(11);
@ -455,6 +485,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_RENDER_ROW_11:
bCP1610_PIN_IN_BUSRQ = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
//this mode could be cut off in tick length if the vertical
//offset is greater than 1
@ -480,6 +511,7 @@ ITCM_CODE INT32 AY38900::tick(INT32 minimum) {
case MODE_FETCH_ROW_12:
default:
bCP1610_PIN_IN_BUSRQ = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
totalTicks += TICK_LENGTH_SCANLINE;
mode = MODE_VBLANK;
break;

View File

@ -25,6 +25,9 @@ UINT16 amplitudes16Bit[16] __attribute__((section(".dtcm"))) =
INT32 clockDivisor __attribute__((section(".dtcm")));
INT32 clocksPerSample __attribute__((section(".dtcm")));
INT32 cachedTotalOutput __attribute__((section(".dtcm")));
extern UINT8 bUseIVoice;
@ -97,7 +100,7 @@ void AY38914::setClockDivisor(INT32 clockDivisor)
clockDivisor = clockDivisor;
}
ITCM_CODE INT32 AY38914::getClockDivisor() {
INT32 AY38914::getClockDivisor() {
return clockDivisor;
}
@ -185,7 +188,9 @@ ITCM_CODE INT32 AY38914::tick(INT32 minimum)
playSample1(cachedTotalOutput); // This is the ECS PSG on channel 1
}
else
{
playSample0(cachedTotalOutput); // This is the normal Intellivision console PSG
}
totalTicks += clocksPerSample;

View File

@ -77,16 +77,14 @@ class AY38914 : public Processor, public AudioProducer
void setClockDivisor(INT32 clockDivisor);
INT32 getClockDivisor();
//registers
AY38914_Registers registers;
AY38914_Registers registers;
struct Channel_t channel0;
struct Channel_t channel1;
struct Channel_t channel2;
struct Channel_t channel2;
//cached total output sample
UINT8 cachedTotalOutputIsDirty;
INT16 cachedTotalOutput;
//envelope data
UINT8 envelopeIdle;

View File

@ -18,8 +18,8 @@ struct Channel_t
{
INT32 period;
INT32 periodValue;
INT32 volume;
INT32 toneCounter;
UINT8 volume;
UINT8 tone;
UINT8 envelope;
UINT8 toneDisabled;

View File

@ -15,7 +15,7 @@
INT64 sampleBuffer[3] __attribute__((section(".dtcm")));
INT32 commonClockCounter[3] __attribute__((section(".dtcm")));
INT64 commonClocksPerSample[3] __attribute__((section(".dtcm")));
INT32 commonClocksPerSample[3] __attribute__((section(".dtcm")));
INT16 previousSample[3] __attribute__((section(".dtcm")));
INT16 currentSample[3] __attribute__((section(".dtcm")));
@ -37,7 +37,7 @@ void audio_output_line_reset(void)
// --------------------------------------------------------------------------------------
ITCM_CODE void playSample0(INT16 sample) // Normal PSG
{
sampleBuffer[0] += currentSample[0] * commonClocksPerSample[0];
sampleBuffer[0] += currentSample[0] * (INT64)commonClocksPerSample[0];
commonClockCounter[0] += commonClocksPerSample[0];
previousSample[0] = currentSample[0];
currentSample[0] = sample;
@ -45,7 +45,7 @@ ITCM_CODE void playSample0(INT16 sample) // Normal PSG
ITCM_CODE void playSample1(INT16 sample) // ECS PSG or Intellivoice SP0256
{
sampleBuffer[1] += currentSample[1] * commonClocksPerSample[1];
sampleBuffer[1] += currentSample[1] * (INT64)commonClocksPerSample[1];
commonClockCounter[1] += commonClocksPerSample[1];
previousSample[1] = currentSample[1];
currentSample[1] = sample;
@ -54,7 +54,7 @@ ITCM_CODE void playSample1(INT16 sample) // ECS PSG or Intellivoice SP0256
ITCM_CODE void playSample2(INT16 sample) // ECS PSG or Intellivoice SP0256
{
sampleBuffer[2] += currentSample[2] * commonClocksPerSample[2];
sampleBuffer[2] += currentSample[2] * (INT64)commonClocksPerSample[2];
commonClockCounter[2] += commonClocksPerSample[2];
previousSample[2] = currentSample[2];
currentSample[2] = sample;

View File

@ -16,7 +16,7 @@
extern INT64 sampleBuffer[3];
extern INT32 commonClockCounter[3];
extern INT64 commonClocksPerSample[3];
extern INT32 commonClocksPerSample[3];
extern INT16 previousSample[3];
extern INT16 currentSample[3];

View File

@ -19,7 +19,7 @@
// We store the "fast buffer" out in video RAM which is faster than main RAM if
// there is a cache "miss". Experimentally, this buys us about 10% speed up.
// ------------------------------------------------------------------------------
#define PEEK_FAST(x) *((UINT16 *)0x06860000 + (x))
#define PEEK_FAST(x) *((UINT16 *)(0x06860000 | ((x)<<1)))
//the eight registers available in the CP1610
UINT16 r[8] __attribute__((section(".dtcm")));
@ -40,8 +40,8 @@ UINT8 interruptible __attribute__((section(".dtcm")));
UINT8 bCP1610_PIN_IN_BUSRQ __attribute__((section(".dtcm")));
UINT8 bCP1610_PIN_IN_INTRM __attribute__((section(".dtcm")));
UINT8 bCP1610_PIN_OUT_BUSAK __attribute__((section(".dtcm")));
UINT8 bHandleInterrupts __attribute__((section(".dtcm"))) = 0;
//the four external lines
INT8 ext __attribute__((section(".dtcm")));
CP1610::CP1610(MemoryBus* m, UINT16 resetAddress,
@ -69,6 +69,7 @@ void CP1610::resetProcessor()
for (INT32 i = 0; i < 7; i++)
r[i] = 0;
r[7] = resetAddress;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
}
/**
@ -88,28 +89,32 @@ ITCM_CODE INT32 CP1610::tick(INT32 minimum)
do {
// This chunk of code doesn't happen very often (less than 10%) so we use the unlikely() gcc switch to help optmize
if (unlikely(!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM)))
if (unlikely(bHandleInterrupts))
{
if ((!bCP1610_PIN_IN_BUSRQ))
if (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM))
{
if (interruptible)
if ((!bCP1610_PIN_IN_BUSRQ))
{
bCP1610_PIN_OUT_BUSAK = bCP1610_PIN_IN_BUSRQ;
return MAX((usedCycles<<2), minimum);
if (interruptible)
{
bCP1610_PIN_OUT_BUSAK = bCP1610_PIN_IN_BUSRQ;
return MAX((usedCycles<<2), minimum);
}
}
}
else // if ((I && !bCP1610_PIN_IN_INTRM))
{
if (interruptible)
else // if ((I && !bCP1610_PIN_IN_INTRM))
{
bCP1610_PIN_IN_INTRM = TRUE;
interruptible = false;
memoryBus->poke(r[6], r[7]);
r[6]++;
r[7] = interruptAddress;
usedCycles += 7;
if ((usedCycles << 2) >= minimum)
return (usedCycles<<2);
if (interruptible)
{
bCP1610_PIN_IN_INTRM = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
interruptible = false;
memoryBus->poke(r[6], r[7]);
r[6]++;
r[7] = interruptAddress;
usedCycles += 7;
if ((usedCycles << 2) >= minimum)
return (usedCycles<<2);
}
}
}
}
@ -172,6 +177,7 @@ UINT16 CP1610::EIS() {
interruptible = FALSE;
I = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
D = FALSE;
return 4;
@ -182,6 +188,7 @@ UINT16 CP1610::DIS() {
interruptible = FALSE;
I = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
D = FALSE;
return 4;
@ -236,6 +243,7 @@ ITCM_CODE UINT16 CP1610::JSR(UINT16 registerNum, UINT16 target) {
UINT16 CP1610::JE(UINT16 target) {
I = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
r[7] = target;
interruptible = TRUE;
D = FALSE;
@ -244,6 +252,7 @@ UINT16 CP1610::JE(UINT16 target) {
UINT16 CP1610::JSRE(UINT16 registerNum, UINT16 target) {
I = TRUE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
r[registerNum] = r[7]+3;
r[7] = target;
interruptible = TRUE;
@ -254,6 +263,7 @@ UINT16 CP1610::JSRE(UINT16 registerNum, UINT16 target) {
UINT16 CP1610::JD(UINT16 target) {
I = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
r[7] = target;
interruptible = TRUE;
@ -263,6 +273,7 @@ UINT16 CP1610::JD(UINT16 target) {
UINT16 CP1610::JSRD(UINT16 registerNum, UINT16 target) {
I = FALSE;
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
r[registerNum] = r[7]+3;
r[7] = target;
interruptible = TRUE;
@ -275,10 +286,9 @@ ITCM_CODE UINT16 CP1610::INCR(UINT16 registerNum) {
r[7]++;
interruptible = TRUE;
UINT16 newValue = r[registerNum]+1;
S = !!(newValue & 0x8000);
Z = !newValue;
r[registerNum] = newValue;
r[registerNum]++;
S = !!(r[registerNum] & 0x8000);
Z = !r[registerNum];
D = FALSE;
return 6;
@ -288,10 +298,9 @@ ITCM_CODE UINT16 CP1610::DECR(UINT16 registerNum) {
r[7]++;
interruptible = TRUE;
UINT16 newValue = r[registerNum]-1;
S = !!(newValue & 0x8000);
Z = !newValue;
r[registerNum] = newValue;
r[registerNum]--;
S = !!(r[registerNum] & 0x8000);
Z = !r[registerNum];
D = FALSE;
return 6;
@ -944,7 +953,7 @@ UINT16 CP1610::BESC(INT16 displacement) {
return 7;
}
UINT16 CP1610::MVO(UINT16 registerNum, UINT16 address) {
ITCM_CODE UINT16 CP1610::MVO(UINT16 registerNum, UINT16 address) {
r[7] += 2;
interruptible = FALSE;
@ -984,8 +993,9 @@ UINT16 CP1610::MVI_ind(UINT16 registerWithAddress, UINT16 registerToReceive) {
r[registerToReceive] = getIndirect(registerWithAddress);
UINT8 cycles = (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
D = FALSE;
return (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
return cycles;
}
ITCM_CODE UINT16 CP1610::ADD(UINT16 address, UINT16 registerNum) {
@ -1018,8 +1028,9 @@ UINT16 CP1610::ADD_ind(UINT16 registerWithAddress, UINT16 registerToReceive) {
Z = !(newValue & 0xFFFF);
r[registerToReceive] = (UINT16)newValue;
UINT8 cycles = (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
D = FALSE;
return (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
return cycles;
}
ITCM_CODE UINT16 CP1610::SUB(UINT16 address, UINT16 registerNum) {
@ -1052,8 +1063,9 @@ UINT16 CP1610::SUB_ind(UINT16 registerWithAddress, UINT16 registerToReceive) {
Z = !(newValue & 0xFFFF);
r[registerToReceive] = (UINT16)newValue;
UINT8 cycles = (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
D = FALSE;
return (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
return cycles;
}
ITCM_CODE UINT16 CP1610::CMP(UINT16 address, UINT16 registerNum) {
@ -1072,7 +1084,7 @@ ITCM_CODE UINT16 CP1610::CMP(UINT16 address, UINT16 registerNum) {
return 10;
}
UINT16 CP1610::CMP_ind(UINT16 registerWithAddress, UINT16 registerToReceive) {
ITCM_CODE UINT16 CP1610::CMP_ind(UINT16 registerWithAddress, UINT16 registerToReceive) {
r[7]++;
interruptible = TRUE;
@ -1084,8 +1096,9 @@ UINT16 CP1610::CMP_ind(UINT16 registerWithAddress, UINT16 registerToReceive) {
S = !!(newValue & 0x8000);
Z = !(newValue & 0xFFFF);
UINT8 cycles = (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
D = FALSE;
return (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
return cycles;
}
ITCM_CODE UINT16 CP1610::AND(UINT16 address, UINT16 registerNum) {
@ -1110,8 +1123,9 @@ UINT16 CP1610::AND_ind(UINT16 registerWithAddress, UINT16 registerToReceive) {
Z = !value;
r[registerToReceive] = value;
UINT8 cycles = (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
D = FALSE;
return (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
return cycles;
}
UINT16 CP1610::XOR(UINT16 address, UINT16 registerNum) {
@ -1136,8 +1150,9 @@ UINT16 CP1610::XOR_ind(UINT16 registerWithAddress, UINT16 registerToReceive) {
Z = !value;
r[registerToReceive] = value;
UINT8 cycles = (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
D = FALSE;
return (D ? 10 : (registerWithAddress == 6 ? 11 : 8));
return cycles;
}
UINT16 CP1610::decode(void)
@ -4280,4 +4295,6 @@ void CP1610::setState(CP1610State *state)
interruptAddress = state->interruptAddress;
resetAddress = state->resetAddress;
for (int i=0; i<8; i++) r[i] = state->r[i];
bHandleInterrupts = (!bCP1610_PIN_IN_BUSRQ || (I && !bCP1610_PIN_IN_INTRM));
}

View File

@ -36,7 +36,7 @@ ITCM_CODE void GRAM::poke(UINT16 location, UINT16 value)
{
if (!enabled) return;
location &= 0x01FF;
gram_image[location] = (UINT8)value;
dirtyCards[location>>3] = TRUE;
dirtyRAM = TRUE;

View File

@ -125,7 +125,7 @@ void JLP::WriteFlashFile(void)
{
FILE *fp;
dsPrintValue(2,0,0, (char*)"JLP FLASH");
dsPrintValue(hud_x,hud_y,0, (char*)"JLP FLASH");
GetFlashFilename();
fp = fopen(flash_filename, "wb");
if (fp != NULL)
@ -133,7 +133,7 @@ void JLP::WriteFlashFile(void)
fwrite(jlp_flash, 1, JLP_FLASH_SIZE, fp);
fclose(fp);
}
dsPrintValue(2,0,0,(char*)" ");
dsPrintValue(hud_x,hud_y,0,(char*)" ");
}
void JLP::ScheduleWriteFlashFile(void)

View File

@ -1,10 +1,10 @@
// =====================================================================================
// Copyright (c) 2021-2024 Dave Bernazzani (wavemotion-dave)
//
// Copying and distribution of this emulator, its source code and associated
// readme files, with or without modification, are permitted in any medium without
// Copying and distribution of this emulator, its source code and associated
// readme files, with or without modification, are permitted in any medium without
// royalty provided the this copyright notice is used and wavemotion-dave (NINTV-DS)
// and Kyle Davis (BLISS) are thanked profusely.
// and Kyle Davis (BLISS) are thanked profusely.
//
// The NINTV-DS emulator is offered as-is, without any warranty.
// =====================================================================================
@ -18,7 +18,7 @@ UINT16 MAX_READ_OVERLAPPED_MEMORIES = 2;
UINT16 MAX_WRITE_OVERLAPPED_MEMORIES = 3;
// ----------------------------------------------------------------------------------------------
// We use this class and single object to fill all unused memory locations in the memory map.
// We use this class and single object to fill all unused memory locations in the memory map.
// Returns 0xFFFF on all access as a real intellivision would with unused memory regions.
// ----------------------------------------------------------------------------------------------
class UnusedMemory : public Memory
@ -47,9 +47,9 @@ public:
// memories per address location which is sufficient provided we are only
// loading normal ROMs into a stock intellivision with, at most, an intellivoice
// or the JLP cart as the only peripherals... still, this is a strain on the
// older DS-LITE/PHAT. The original BLISS core allowed 16 overlapping memory
// regions (to handle page flipping) which will fit into the DSi but is too
// large for the original DS-LITE/PHAT so for older hardware, we strip down
// older DS-LITE/PHAT. The original BLISS core allowed 16 overlapping memory
// regions (to handle page flipping) which will fit into the DSi but is too
// large for the original DS-LITE/PHAT so for older hardware, we strip down
// to the bare essentials. For the DSi we can allocate more memory and provide
// the full 16 overlapped mapped memories.
// -------------------------------------------------------------------------------
@ -60,50 +60,49 @@ MemoryBus::MemoryBus()
// -------------------------------------------------------------------------------------
// We swap in a larger memory model for the DSi to handle really complex page flipping
// -------------------------------------------------------------------------------------
if (isDSiMode())
if (isDSiMode())
{
MAX_READ_OVERLAPPED_MEMORIES = 16; // Good enough for any page-flipping game. This is massive!
MAX_WRITE_OVERLAPPED_MEMORIES = 17; // Need one extra here to handle the GRAM mirrors up in odd places in ROM
}
else
{
MAX_READ_OVERLAPPED_MEMORIES = 2; // Good enough for almost all games except very large page-flipping games
MAX_WRITE_OVERLAPPED_MEMORIES = 3; // Need one extra here to handle the GRAM mirrors up in odd places in ROM
MAX_READ_OVERLAPPED_MEMORIES = 16; // Good enough for almost all games except very large page-flipping games
MAX_WRITE_OVERLAPPED_MEMORIES = 17; // Need one extra here to handle the GRAM mirrors up in odd places in ROM
}
UINT32 size = 1 << (sizeof(UINT16) << 3);
UINT32 i;
writeableMemoryCounts = new UINT8[size];
memset(writeableMemoryCounts, 0, sizeof(UINT8) * size);
writeableMemorySpace = new Memory**[size];
writeableMemorySpace = new Memory**[size>>4];
// ---------------------------------------------------------------------------------------------------------------------------
// We do this rather than allocate piecemeal so we avoid malloc overhead and extra bytes padded (saves almost 500K on DS)
// On the DS with 3 overlapped memories (enough for most games), this is still 1.5MB of memory (out of the 3.5MB available)
// On the DSi with a full 16 overlapped memories (enough for any game), this is a whopping 8MB (out of the 15.5MB available)
// ---------------------------------------------------------------------------------------------------------------------------
overlappedMemoryPool = new UINT32[size*(MAX_READ_OVERLAPPED_MEMORIES+MAX_WRITE_OVERLAPPED_MEMORIES)];
for (i = 0; i < size; i++)
overlappedMemoryPool = new UINT32[(size*(MAX_READ_OVERLAPPED_MEMORIES+MAX_WRITE_OVERLAPPED_MEMORIES))>>4];
UINT32 *memPoolPtr = (UINT32 *)overlappedMemoryPool;
for (i = 0; i < size>>4; i++)
{
writeableMemorySpace[i] = (Memory **)overlappedMemoryPool;
writeableMemorySpace[i] = (Memory **)memPoolPtr;
for (int j=0; j<MAX_WRITE_OVERLAPPED_MEMORIES; j++)
{
overlappedMemoryPool++;
memPoolPtr++;
writeableMemorySpace[i][j] = &MyUnusedMemory;
}
}
readableMemoryCounts = (UINT16 *) 0x06820000; // Use video memory ... slightly faster and saves main RAM
memset(readableMemoryCounts, 0, sizeof(UINT16) * size);
readableMemorySpace = new Memory**[size];
for (i = 0; i < size; i++)
readableMemorySpace = new Memory**[size>>4];
for (i = 0; i < size>>4; i++)
{
readableMemorySpace[i] = (Memory **)overlappedMemoryPool;
readableMemorySpace[i] = (Memory **)memPoolPtr;
for (int j=0; j<MAX_READ_OVERLAPPED_MEMORIES; j++)
{
overlappedMemoryPool++;
memPoolPtr++;
readableMemorySpace[i][j] = &MyUnusedMemory;
}
}
}
mappedMemoryCount = 0;
}
@ -141,7 +140,7 @@ void MemoryBus::addMemory(Memory* m)
FatalError("GAME TOO COMPLEX - MAX MEMORIES");
return;
}
//add all of the readable locations, if any
if (readAddressMask != 0) {
UINT8 zeroCount = 0;
@ -151,7 +150,7 @@ void MemoryBus::addMemory(Memory* m)
zeroCount++;
}
}
UINT8 combinationCount = (1<<zeroCount);
for (i = 0; i < combinationCount; i++) {
UINT16 orMask = 0;
@ -167,7 +166,7 @@ void MemoryBus::addMemory(Memory* m)
FatalError("ERROR MAX READABLE MEM OVERLAP");
return;
}
readableMemorySpace[k][memCount] = m;
readableMemorySpace[k>>4][memCount] = m;
readableMemoryCounts[k]++;
}
}
@ -182,7 +181,7 @@ void MemoryBus::addMemory(Memory* m)
zeroCount++;
}
}
UINT8 combinationCount = (1<<zeroCount);
for (i = 0; i < combinationCount; i++) {
UINT16 orMask = 0;
@ -197,8 +196,8 @@ void MemoryBus::addMemory(Memory* m)
{
FatalError("ERROR MAX WRITEABLE MEM OVERLAP");
return;
}
writeableMemorySpace[k][memCount] = m;
}
writeableMemorySpace[k>>4][memCount] = m;
writeableMemoryCounts[k]++;
}
}
@ -232,7 +231,7 @@ void MemoryBus::removeMemory(Memory* m)
zeroCount++;
}
}
UINT8 combinationCount = (1<<zeroCount);
for (i = 0; i < combinationCount; i++) {
UINT16 orMask = 0;
@ -241,18 +240,22 @@ void MemoryBus::removeMemory(Memory* m)
UINT16 nextAddress = readAddress | orMask;
UINT16 nextEnd = nextAddress + readSize - 1;
for (UINT32 k = nextAddress; k <= nextEnd; k++) {
for (UINT32 k = nextAddress; k <= nextEnd; k++)
{
UINT16 memCount = readableMemoryCounts[k];
for (UINT16 n = 0; n < memCount; n++) {
if (readableMemorySpace[k][n] == m) {
for (INT32 l = n; l < (memCount-1); l++) {
readableMemorySpace[k][l] = readableMemorySpace[k][l+1];
for (UINT16 n = 0; n < memCount; n++)
{
if (readableMemorySpace[k>>4][n] == m)
{
for (INT32 l = n; l < (memCount-1); l++)
{
readableMemorySpace[k>>4][l] = readableMemorySpace[k>>4][l+1];
}
readableMemorySpace[k][memCount-1] = &MyUnusedMemory;
readableMemoryCounts[k]--;
readableMemorySpace[k>>4][memCount-1] = &MyUnusedMemory;
break;
}
}
readableMemoryCounts[k]--;
}
}
}
@ -266,7 +269,7 @@ void MemoryBus::removeMemory(Memory* m)
zeroCount++;
}
}
UINT8 combinationCount = (1<<zeroCount);
for (i = 0; i < combinationCount; i++) {
UINT16 orMask = 0;
@ -277,17 +280,19 @@ void MemoryBus::removeMemory(Memory* m)
for (UINT32 k = nextAddress; k <= nextEnd; k++) {
UINT16 memCount = writeableMemoryCounts[k];
for (UINT16 n = 0; n < memCount; n++) {
if (writeableMemorySpace[k][n] == m) {
for (INT32 l = n; l < (memCount-1); l++) {
writeableMemorySpace[k][l] =
writeableMemorySpace[k][l+1];
for (UINT16 n = 0; n < memCount; n++)
{
if (writeableMemorySpace[k>>4][n] == m)
{
for (INT32 l = n; l < (memCount-1); l++)
{
writeableMemorySpace[k>>4][l] = writeableMemorySpace[k>>4][l+1];
}
writeableMemorySpace[k][memCount-1] = &MyUnusedMemory;
writeableMemoryCounts[k]--;
writeableMemorySpace[k>>4][memCount-1] = &MyUnusedMemory;
break;
}
}
writeableMemoryCounts[k]--;
}
}
}
@ -310,7 +315,7 @@ void MemoryBus::removeAll()
}
// ------------------------------------------------------------------------------------------------------
// This only needs to be called if we are in a region that might have multiple things mapped to it...
// This only needs to be called if we are in a region that might have multiple things mapped to it...
// Most of the PC ROM access will go through the normal peek() handler which is significantly faster...
// ------------------------------------------------------------------------------------------------------
ITCM_CODE UINT16 MemoryBus::peek_slow(UINT16 location)
@ -320,7 +325,7 @@ ITCM_CODE UINT16 MemoryBus::peek_slow(UINT16 location)
UINT16 value = 0xFFFF;
for (UINT16 i = 0; i < numMemories; i++)
{
value &= readableMemorySpace[location][i]->peek(location);
value &= readableMemorySpace[location>>4][i]->peek(location);
}
return value;
}
@ -334,13 +339,13 @@ ITCM_CODE void MemoryBus::poke(UINT16 location, UINT16 value)
for (UINT16 i = 0; i < numMemories; i++)
{
writeableMemorySpace[location][i]->poke(location, value);
writeableMemorySpace[location>>4][i]->poke(location, value);
}
// For the lower 4K ... keep the "fast memory" updated
if (location < 0x1000)
{
*((UINT16 *)0x06860000 + location) = value;
*((UINT16 *)(0x06860000 | (location<<1))) = value;
}
}
@ -348,7 +353,7 @@ ITCM_CODE void MemoryBus::poke(UINT16 location, UINT16 value)
// ---------------------------------------------------------------------------------------
// Poke Cheat Codes does not need any optimization - only happens once after ROM load.
// We allow poke to both readable and writable memory spaces - most of the time we are
// modifying a ROM location to provide some special cheat effect. We don't need to
// modifying a ROM location to provide some special cheat effect. We don't need to
// update the "fast memory" as the cheats are applied post ROM load but pre "fast buffer".
// ---------------------------------------------------------------------------------------
void MemoryBus::poke_cheat(UINT16 location, UINT16 value)
@ -357,13 +362,13 @@ void MemoryBus::poke_cheat(UINT16 location, UINT16 value)
for (UINT16 i = 0; i < numMemories; i++)
{
readableMemorySpace[location][i]->poke_cheat(location, value);
readableMemorySpace[location>>4][i]->poke_cheat(location, value);
}
numMemories = writeableMemoryCounts[location];
for (UINT16 i = 0; i < numMemories; i++)
{
writeableMemorySpace[location][i]->poke_cheat(location, value);
writeableMemorySpace[location>>4][i]->poke_cheat(location, value);
}
}

View File

@ -33,7 +33,7 @@ class MemoryBus
void reset();
inline UINT16 peek(UINT16 location) {if (((UINT16 *) 0x06820000)[location] == 1) return readableMemorySpace[location][0]->peek(location); else return peek_slow(location);}
inline UINT16 peek(UINT16 location) {if (((UINT16 *) 0x06820000)[location] == 1) return readableMemorySpace[location>>4][0]->peek(location); else return peek_slow(location);}
UINT16 peek_slow(UINT16 location);
// ------------------------------------------------------------------------------------------------
@ -51,9 +51,9 @@ class MemoryBus
// ------------------------------------------------------
UINT16 peek_slow_and_safe(UINT16 location)
{
if (readableMemorySpace[location])
if (readableMemorySpace[location>>4])
{
if (readableMemorySpace[location][0])
if (readableMemorySpace[location>>4][0])
{
return peek_slow(location);
}
@ -72,10 +72,10 @@ class MemoryBus
private:
Memory* mappedMemories[MAX_MAPPED_MEMORIES];
UINT16 mappedMemoryCount;
UINT8* writeableMemoryCounts;
Memory*** writeableMemorySpace;
UINT16* readableMemoryCounts;
Memory*** readableMemorySpace;
UINT16 *readableMemoryCounts;
UINT8 *writeableMemoryCounts;
};
#endif

View File

@ -63,6 +63,12 @@ public:
return ((UINT16*)image)[location];
}
// Useful for when we are copying chunks of memory for bank-switching
inline UINT8 *peek_image_address()
{
return image;
}
UINT16 getWriteSize();
UINT16 getWriteAddress();
UINT16 getWriteAddressMask();

View File

@ -62,9 +62,12 @@ ITCM_CODE void ROMBanker::poke(UINT16 address, UINT16 value)
if (bEnabled) // If we are enabling this bank, we can quickly refresh the fast_memory[]
{
UINT16 *fast_memory = (UINT16 *)0x06860000;
for (int i=(address&0xF000); i<=((address&0xF000)|0xFFF); i++)
UINT32 *ptr = (UINT32 *)rom->peek_image_address();
UINT32 *dest = (UINT32 *) &fast_memory[(address&0xF000)];
for (int i=(address&0xF000); i<=((address&0xF000)|0xFFF); i+=2)
{
fast_memory[i] = rom->peek_fast(i&0xFFF);
*dest++ = *ptr++; // Do this 32-bits at a time for a very slight speed improvement on moving the memory
}
}
else if (gBankerIsMappedHere[address>>12][value&0xF] == 0) // Nothing is here... nothing will be swapped in... We need to check the main memory as there may be an unswapped bank in there...

View File

@ -800,7 +800,7 @@ void SP0256::PAUSE(INT32 immed4) {
periodInterpolation = 0;
}
ITCM_CODE void SP0256::decode() {
void SP0256::decode() {
INT32 immed4 = readBits(4);
INT32 nextInstruction = readBitsReverse(4);
switch (nextInstruction) {
@ -858,7 +858,7 @@ ITCM_CODE void SP0256::decode() {
}
}
ITCM_CODE INT32 SP0256::flipEndian(INT32 value, INT32 bits) {
INT32 SP0256::flipEndian(INT32 value, INT32 bits) {
INT32 output = 0;
INT32 bitMask = 1;
for (INT32 i = 0; i < bits; i++) {

View File

@ -60,7 +60,7 @@ int main(int argc, char **argv)
else
{
mySoundFrequency = 12000; // For the DS-LITE/PHAT we need more speed so we reduce the sound quality a bit...
MAX_ROM_FILE_SIZE = (256 * 1024); // Bit enough for all original 125 commercial games and 98% of homebrews
MAX_ROM_FILE_SIZE = (512 * 1024); // Bit enough for all original 125 commercial games and 98% of homebrews
}
bin_image_buf = new UINT8[MAX_ROM_FILE_SIZE];

View File

@ -54,6 +54,9 @@ UINT8 bUseDiscOverlay __attribute__((section(".dtcm"))) = false;
UINT8 bGameLoaded __attribute__((section(".dtcm"))) = false;
UINT8 bMetaSpeedup __attribute__((section(".dtcm"))) = false;
UINT8 hud_x = 3;
UINT8 hud_y = 0;
// -------------------------------------------------------------
// This one is accessed rather often so we'll put it in .dtcm
// -------------------------------------------------------------
@ -809,10 +812,10 @@ ITCM_CODE void pollInputs(void)
// -------------------------------------------------------------------------------------
if ((keys_pressed & KEY_L) && (keys_pressed & KEY_R))
{
dsPrintValue(3,0,0,(char*)"SNAP");
dsPrintValue(hud_x+2,hud_y,0,(char*)"SNAP");
screenshot();
WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;
dsPrintValue(3,0,0,(char*)" ");
dsPrintValue(hud_x+2,hud_y,0,(char*)" ");
}
else
if ((keys_pressed & KEY_A) && (keys_pressed & KEY_X))
@ -1201,6 +1204,10 @@ void dsShowScreenMain(bool bFull, bool bPlayJingle)
}
}
hud_x = 3;
hud_y = 0;
// Now show the bottom screen - usualy some form of overlay...
#ifdef DEBUG_ENABLE
show_debug_overlay();
@ -1441,7 +1448,7 @@ ITCM_CODE void Run(char *initial_file)
{
sprintf(tmp,"%-6d %-6d %-5d %-5d", debug[0], debug[1], debug[2], debug[3]);
//sprintf(tmp,"%04X %04X %04X %04X %02X %02X", debug[0], debug[1], debug[2], debug[3], debug[4], debug[5]);
dsPrintValue(6,0,0,tmp);
dsPrintValue(5,0,0,tmp);
}
// If we are using the JLP, we call into the 1 second tick function in case there is a dirty flash that needs writing...

View File

@ -27,6 +27,7 @@ typedef enum _RunState
extern UINT16 emu_frames;
extern UINT16 frames_per_sec_calc;
extern UINT8 oneSecTick;
extern UINT8 hud_x, hud_y;
extern UINT8 b_dsi_mode;

View File

@ -232,6 +232,22 @@ void load_custom_overlay(bool bCustomGeneric)
}
}
// Handle HUD_x Line
if (strstr(szName, ".hudx") != NULL)
{
char *ptr = strstr(szName, ".hudx");
ptr += 6;
hud_x = strtoul(ptr, &ptr, 10);
}
// Handle HUD_y Line
if (strstr(szName, ".hudy") != NULL)
{
char *ptr = strstr(szName, ".hudy");
ptr += 6;
hud_y = strtoul(ptr, &ptr, 10);
}
// Handle Tile Line
if (strstr(szName, ".tile") != NULL)
{

View File

@ -25,7 +25,7 @@ extern Emulator *currentEmu;
extern Rip *currentRip;
extern UINT16 global_frames;
#define CURRENT_SAVE_FILE_VER 0x000A
#define CURRENT_SAVE_FILE_VER 0x000B
// ------------------------------------------------------
// We allow up to 3 saves per game. More than enough.