-improved audio output and small audio emulation fixes and improvements

-added support for one of the multicarts I own because why not
-various small updates regarding the libretro hook, including better handling of rom switching and saving
This commit is contained in:
FIX94 2018-10-31 22:33:10 +01:00
parent 0004be631e
commit 251e12cf98
No known key found for this signature in database
GPG Key ID: CE39016A19D8EADA
8 changed files with 485 additions and 315 deletions

176
apu.c
View File

@ -53,10 +53,10 @@ static uint8_t p1LengthCtr, p2LengthCtr, noiseLengthCtr;
static uint8_t wavLinearCtr;
static uint16_t wavLengthCtr;
static uint8_t wavVolShift;
static uint16_t modeCurCtr = 0;
static uint16_t modeCurCtr;
static uint8_t modePos;
static uint16_t p1freqCtr, p2freqCtr, wavFreqCtr, noiseFreqCtr;
static uint8_t p1Cycle, p2Cycle, wavCycle;
static uint8_t modePos = 0;
static bool p1haltloop, p2haltloop, wavhaltloop, noisehaltloop;
static bool p1dacenable, p2dacenable, wavdacenable, noisedacenable;
static bool p1enable, p2enable, wavenable, noiseenable;
@ -118,16 +118,16 @@ void apuInitBufs()
apuFrequency = 262144;
double dt = 1.0/((double)apuFrequency);
//LP at 22kHz
double rc = 1.0/(M_2_PI * 22000.0);
//LP at 20kHz
double rc = 1.0/(M_2_PI * 20000.0);
#if AUDIO_FLOAT
lpVal = dt / (rc + dt);
#else
//convert to 32bit int for calcs later
lpVal = (int32_t)((dt / (rc + dt))*32768.0);
#endif
//HP at 40Hz
rc = 1.0/(M_2_PI * 40.0);
//HP at 20Hz for GB/GBA (150Hz for GBC)
rc = 1.0/(M_2_PI * 20.0);
#if AUDIO_FLOAT
hpVal = rc / (rc + dt);
#else
@ -154,6 +154,16 @@ void apuDeinitBufs()
apuOutBuf = NULL;
}
#if AUDIO_FLOAT
static float lastHPOutLeft, lastHPOutRight, lastLPOutLeft, lastLPOutRight;
#else
static int32_t lastHPOutLeft, lastHPOutRight, lastLPOutLeft, lastLPOutRight;
#endif
//used externally
uint8_t curP1Out, curP2Out, curWavOut, curNoiseOut;
extern bool emuSkipVsync, emuSkipFrame;
extern bool gbCgbMode;
extern bool gbCgbBootrom;
void apuInit()
@ -166,8 +176,11 @@ void apuInit()
memset(apuOutBuf, 0, apuBufSizeBytes);
curBufPos = 0;
modeCurCtr = 0;
modePos = 0;
freq1 = 0; freq2 = 0; wavFreq = 0; noiseFreq = 0;
noiseShiftReg = 1;
noiseShiftReg = 0;
p1LengthCtr = 0; p2LengthCtr = 0;
noiseLengthCtr = 0; wavLengthCtr = 0;
wavLinearCtr = 0;
@ -197,18 +210,10 @@ void apuInit()
APU_IO_Reg[0x24] = 0x77;
APU_IO_Reg[0x25] = 0xF3;
}
}
#if AUDIO_FLOAT
static float lastHPOutLeft = 0, lastHPOutRight = 0, lastLPOutLeft = 0, lastLPOutRight = 0;
#else
static int32_t lastHPOutLeft = 0, lastHPOutRight = 0, lastLPOutLeft = 0, lastLPOutRight = 0;
#endif
static uint8_t lastP1OutLeft = 0, lastP2OutLeft = 0, lastWavOutLeft = 0, lastNoiseOutLeft = 0;
static uint8_t lastP1OutRight = 0, lastP2OutRight = 0, lastWavOutRight = 0, lastNoiseOutRight = 0;
extern bool emuSkipVsync, emuSkipFrame;
//used externally
uint8_t curP1Out = 0, curP2Out = 0, curWavOut = 0, curNoiseOut = 0;
lastHPOutLeft = 0, lastHPOutRight = 0, lastLPOutLeft = 0, lastLPOutRight = 0;
curP1Out = 0, curP2Out = 0, curWavOut = 0, curNoiseOut = 0;
}
bool apuCycle()
{
@ -238,108 +243,100 @@ bool apuCycle()
#endif
curBufPos = 0;
}
uint8_t p1OutLeft = lastP1OutLeft, p2OutLeft = lastP2OutLeft,
wavOutLeft = lastWavOutLeft, noiseOutLeft = lastNoiseOutLeft;
uint8_t p1OutRight = lastP1OutRight, p2OutRight = lastP2OutRight,
wavOutRight = lastWavOutRight, noiseOutRight = lastNoiseOutRight;
uint8_t apuMasterVolLeft = ((APU_IO_Reg[0x24]>>4)&7), apuMasterVolRight = (APU_IO_Reg[0x24]&7);
int8_t p1Out = 0, p2Out = 0, noiseOut = 0, wavOut = 0;
int8_t p1OutLeft = 0, p2OutLeft = 0,
wavOutLeft = 0, noiseOutLeft = 0;
int8_t p1OutRight = 0, p2OutRight = 0,
wavOutRight = 0, noiseOutRight = 0;
int8_t apuMasterVolLeft = ((APU_IO_Reg[0x24]>>4)&7), apuMasterVolRight = (APU_IO_Reg[0x24]&7);
if(p1enable && p1dacenable)
{
if(p1seq[p1Cycle] && freq1 > 0 && freq1 < 0x7FF)
{
if(p1seq[p1Cycle])
curP1Out = p1Env.curVol;
if(APU_IO_Reg[0x25] & P1_ENABLE_LEFT)
lastP1OutLeft = p1OutLeft = curP1Out;
if(APU_IO_Reg[0x25] & P1_ENABLE_RIGHT)
lastP1OutRight = p1OutRight = curP1Out;
}
else
{
curP1Out = 0;
if(APU_IO_Reg[0x25] & P1_ENABLE_LEFT)
p1OutLeft = 0;
if(APU_IO_Reg[0x25] & P1_ENABLE_RIGHT)
p1OutRight = 0;
//actually audible output
if(freq1 > 0 && freq1 < 0x7FF)
{
//GB/GBC Behavior
//p1Out = (curP1Out<<1)-15;
//GBA Behavior
p1Out = (curP1Out<<1)-p1Env.curVol;
}
}
else
curP1Out = 0;
if(APU_IO_Reg[0x25] & P1_ENABLE_LEFT)
p1OutLeft = p1Out;
if(APU_IO_Reg[0x25] & P1_ENABLE_RIGHT)
p1OutRight = p1Out;
if(p2enable && p2dacenable)
{
if(p2seq[p2Cycle] && freq2 > 0 && freq2 < 0x7FF)
{
if(p2seq[p2Cycle])
curP2Out = p2Env.curVol;
if(APU_IO_Reg[0x25] & P2_ENABLE_LEFT)
lastP2OutLeft = p2OutLeft = curP2Out;
if(APU_IO_Reg[0x25] & P2_ENABLE_RIGHT)
lastP2OutRight = p2OutRight = curP2Out;
}
else
{
curP2Out = 0;
if(APU_IO_Reg[0x25] & P2_ENABLE_LEFT)
p2OutLeft = 0;
if(APU_IO_Reg[0x25] & P2_ENABLE_RIGHT)
p2OutRight = 0;
//actually audible output
if(freq2 > 0 && freq2 < 0x7FF)
{
//GB/GBC Behavior
//p2Out = (curP2Out<<1)-15;
//GBA Behavior
p2Out = (curP2Out<<1)-p2Env.curVol;
}
}
else
curP2Out = 0;
if(APU_IO_Reg[0x25] & P2_ENABLE_LEFT)
p2OutLeft = p2Out;
if(APU_IO_Reg[0x25] & P2_ENABLE_RIGHT)
p2OutRight = p2Out;
if(wavenable && wavdacenable)
{
uint8_t v = APU_IO_Reg[0x30+(wavCycle>>1)];
curWavOut = APU_IO_Reg[0x30+(wavCycle>>1)];
if((wavCycle&1)==0)
v >>= 4;
curWavOut >>= 4;
else
v &= 0xF;
v>>=wavVolShift;
if(v && ((wavFreq > 0 && wavFreq < 0x7FF) || wavEqual))
{
curWavOut = v;
if(APU_IO_Reg[0x25] & WAV_ENABLE_LEFT)
lastWavOutLeft = wavOutLeft = curWavOut;
if(APU_IO_Reg[0x25] & WAV_ENABLE_RIGHT)
lastWavOutRight = wavOutRight = curWavOut;
}
else
{
curWavOut = 0;
if(APU_IO_Reg[0x25] & WAV_ENABLE_LEFT)
wavOutLeft = 0;
if(APU_IO_Reg[0x25] & WAV_ENABLE_RIGHT)
wavOutRight = 0;
}
curWavOut &= 0xF;
curWavOut >>= wavVolShift;
//actually audible output
if((wavFreq > 0 && wavFreq < 0x7FF) || wavEqual)
wavOut = (curWavOut<<1)-15;
}
else
curWavOut = 0;
if(APU_IO_Reg[0x25] & WAV_ENABLE_LEFT)
wavOutLeft = wavOut;
if(APU_IO_Reg[0x25] & WAV_ENABLE_RIGHT)
wavOutRight = wavOut;
if(noiseenable && noisedacenable)
{
if((noiseShiftReg&1) == 0 && noiseFreq > 0)
{
if((noiseShiftReg&1) == 0)
curNoiseOut = noiseEnv.curVol;
if(APU_IO_Reg[0x25] & NOISE_ENABLE_LEFT)
lastNoiseOutLeft = noiseOutLeft = curNoiseOut;
if(APU_IO_Reg[0x25] & NOISE_ENABLE_RIGHT)
lastNoiseOutRight = noiseOutRight = curNoiseOut;
}
else
{
curNoiseOut = 0;
if(APU_IO_Reg[0x25] & NOISE_ENABLE_LEFT)
noiseOutLeft = 0;
if(APU_IO_Reg[0x25] & NOISE_ENABLE_RIGHT)
noiseOutRight = 0;
//actually audible output
if(noiseFreq > 0)
{
//GB/GBC Behavior
//noiseOut = (curNoiseOut<<1)-15;
//GBA Behavior
noiseOut = (curNoiseOut<<1)-noiseEnv.curVol;
}
}
else
curNoiseOut = 0;
if(APU_IO_Reg[0x25] & NOISE_ENABLE_LEFT)
noiseOutLeft = noiseOut;
if(APU_IO_Reg[0x25] & NOISE_ENABLE_RIGHT)
noiseOutRight = noiseOut;
#if AUDIO_FLOAT
//gen output Left
float curInLeft = ((float)(p1OutLeft + p2OutLeft + wavOutLeft + noiseOutLeft))*volLevel[apuMasterVolLeft]/32.f;
float curInLeft = ((float)(p1OutLeft + p2OutLeft + wavOutLeft + noiseOutLeft))*volLevel[apuMasterVolLeft]/85.333333f;
float curLPOutLeft = lastLPOutLeft+(lpVal*(curInLeft-lastLPOutLeft));
float curHPOutLeft = hpVal*(lastHPOutLeft+lastLPOutLeft-curLPOutLeft);
//gen output Right
float curInRight = ((float)(p1OutRight + p2OutRight + wavOutRight + noiseOutRight))*volLevel[apuMasterVolRight]/32.f;
float curInRight = ((float)(p1OutRight + p2OutRight + wavOutRight + noiseOutRight))*volLevel[apuMasterVolRight]/85.333333f;
float curLPOutRight = lastLPOutRight+(lpVal*(curInRight-lastLPOutRight));
float curHPOutRight = hpVal*(lastHPOutRight+lastLPOutRight-curLPOutRight);
//set output Left
@ -355,7 +352,7 @@ bool apuCycle()
#else
int32_t curIn, curOut;
//gen output Left
curIn = ((p1OutLeft + p2OutLeft + wavOutLeft + noiseOutLeft))*(apuMasterVolLeft+1)<<7;
curIn = (p1OutLeft + p2OutLeft + wavOutLeft + noiseOutLeft)*(apuMasterVolLeft+1)*48;
curOut = lastLPOutLeft+((lpVal*(curIn-lastLPOutLeft))>>15); //Set Left Lowpass Output
curIn = (lastHPOutLeft+lastLPOutLeft-curOut); //Set Left Highpass Input
curIn += (curIn>>31)&1; //Add Sign Bit for proper Downshift later
@ -365,7 +362,7 @@ bool apuCycle()
//Save Clipped Left Highpass Output
apuOutBuf[curBufPos++] = ((soundEnabled)?((curOut > 32767)?(32767):((curOut < -32768)?(-32768):curOut)):0);
//gen output Right
curIn = ((p1OutRight + p2OutRight + wavOutRight + noiseOutRight))*(apuMasterVolRight+1)<<7;
curIn = (p1OutRight + p2OutRight + wavOutRight + noiseOutRight)*(apuMasterVolRight+1)*48;
curOut = lastLPOutRight+((lpVal*(curIn-lastLPOutRight))>>15); //Set Right Lowpass Output
curIn = (lastHPOutRight+lastLPOutRight-curOut); //Set Right Highpass Input
curIn += (curIn>>31)&1; //Add Sign Bit for proper Downshift later
@ -567,10 +564,9 @@ void apuClockTimers()
if(noiseFreqCtr == 0)
{
noiseFreqCtr = noiseFreq;
uint8_t cmpBit = noiseMode1 ? (noiseShiftReg>>6)&1 : (noiseShiftReg>>1)&1;
uint8_t cmpRes = (noiseShiftReg&1)^cmpBit;
uint8_t cmpRes = (noiseShiftReg&1)^((noiseShiftReg>>1)&1);
noiseShiftReg >>= 1;
noiseShiftReg |= cmpRes<<14;
noiseShiftReg |= cmpRes << (noiseMode1 ? 6 : 14);
}
if(noiseFreqCtr)
noiseFreqCtr--;
@ -657,8 +653,6 @@ void apuSetReg8(uint16_t addr, uint8_t val)
p1Env.curVol++;
p1Env.curVol &= 0xF;
}
else //Normal behaviour
p1Env.curVol = p1Env.vol;
p1dacenable = (p1Env.modeadd || p1Env.vol);
if(!p1dacenable)
p1enable = false;
@ -731,8 +725,6 @@ void apuSetReg8(uint16_t addr, uint8_t val)
p2Env.curVol++;
p2Env.curVol &= 0xF;
}
else //Normal behaviour
p2Env.curVol = p2Env.vol;
p2dacenable = (p2Env.modeadd || p2Env.vol);
if(!p2dacenable)
p2enable = false;
@ -855,8 +847,6 @@ void apuSetReg8(uint16_t addr, uint8_t val)
noiseEnv.curVol++;
noiseEnv.curVol &= 0xF;
}
else //Normal behaviour
noiseEnv.curVol = noiseEnv.vol;
noisedacenable = (noiseEnv.modeadd || noiseEnv.vol);
if(!noisedacenable)
noiseenable = false;
@ -900,6 +890,8 @@ void apuSetReg8(uint16_t addr, uint8_t val)
noiseEnv.curVol = noiseEnv.vol;
//period 0 is actually period 8!
noiseEnv.divider = (noiseEnv.period-1)&7;
//trigger sets all shift reg bits
noiseShiftReg = 0x7FFF;
}
break;
default:

297
cpu.c
View File

@ -28,15 +28,14 @@ extern uint16_t gbsSP;
extern uint8_t cpuTimer;
extern bool gbCgbMode;
extern bool gbCgbBootrom;
//used externally
bool cpuDoStopSwitch = false;
bool cpuCgbSpeed = false;
//initalized elsewhere
uint8_t cpuAddSpeed = 1;
void cpuSetupActionArr();
bool cpu_oam_dma = false;
bool cpu_oam_dma_running = false;
uint16_t cpu_oam_dma_addr = 0;
bool cpuCgbSpeed = false;
//used externally
bool cpuDoStopSwitch;
bool cpu_oam_dma;
bool cpu_oam_dma_running;
uint16_t cpu_oam_dma_addr;
static uint16_t sp, pc, cpuTmp16;
static uint8_t a,b,c,d,e,f,h,l,cpuTmp;
@ -47,6 +46,18 @@ static bool gbsInitRet, gbsPlayRet;
static uint8_t sub_in_val;
static bool irqEnable;
static bool cpuHaltLoop,cpuStopLoop,cpuHaltBug,cpuPrevInAny;
static uint8_t curInstr;
static bool cpu_oam_dma_started;
static uint8_t cpu_oam_dma_pos;
bool cpuDmaHalt;
static void cpuSetupActionArr();
static const uint8_t *cpu_action_arr;
static uint8_t cpu_arr_pos;
static inline void cpuSetNopArr();
void cpuInit()
{
sub_in_val=0,cpuTmp=0,cpuTmp16=0;
@ -70,8 +81,8 @@ void cpuInit()
cpuHaltLoop = false;
cpuStopLoop = false;
cpuHaltBug = false;
cpuCgbSpeed = false;
cpuPrevInAny = false;
cpuDoStopSwitch = false;
cpu_oam_dma = false;
cpu_oam_dma_running = false;
cpu_oam_dma_addr = 0;
@ -79,15 +90,22 @@ void cpuInit()
//gbs stuff
gbsInitRet = false; //for first init
gbsPlayRet = true; //for first play call
curInstr = 0;
cpu_oam_dma_started = false;
cpu_oam_dma_pos = 0;
cpuDmaHalt = false;
cpuSetNopArr();
}
static void setAImmRegStats()
static inline void setAImmRegStats()
{
f &= ~(P_FLAG_C|P_FLAG_H|P_FLAG_N|P_FLAG_Z);
if(a == 0) f |= P_FLAG_Z;
}
void cpuAdd16(uint16_t x)
static inline void cpuAdd16(uint16_t x)
{
uint32_t r1,r2;
r1=((h<<8)|l)+(x);
@ -103,7 +121,7 @@ void cpuAdd16(uint16_t x)
f = tf;
}
uint16_t cpuAddSp16(uint8_t add)
static inline int16_t cpuAddSp16(uint8_t add)
{
int32_t n = (int8_t)add;
uint32_t r1,r2,r3;
@ -123,7 +141,7 @@ uint16_t cpuAddSp16(uint8_t add)
return (uint16_t)r1;
}
void setAddSubCmpFlags(uint16_t r1, uint16_t r2)
static inline void setAddSubCmpFlags(uint16_t r1, uint16_t r2)
{
if(((uint8_t)r2)==0)
f |= P_FLAG_Z;
@ -141,7 +159,7 @@ void setAddSubCmpFlags(uint16_t r1, uint16_t r2)
f &= ~P_FLAG_H;
}
uint8_t cpuDoAdd8(uint8_t x, uint8_t y)
static inline uint8_t cpuDoAdd8(uint8_t x, uint8_t y)
{
uint16_t r1,r2;
r1=(uint16_t)((x&0xF)+(y&0xF));
@ -154,12 +172,12 @@ uint8_t cpuDoAdd8(uint8_t x, uint8_t y)
return (uint8_t)r2;
}
void cpuAdd8(uint8_t *reg)
static void cpuAdd8(uint8_t *reg)
{
a = cpuDoAdd8(a,*reg);
}
uint8_t cpuDoSub8(uint8_t x, uint8_t y)
static inline uint8_t cpuDoSub8(uint8_t x, uint8_t y)
{
uint16_t r1,r2;
r1=(uint16_t)((x&0xF)-(y&0xF));
@ -172,17 +190,17 @@ uint8_t cpuDoSub8(uint8_t x, uint8_t y)
return (uint8_t)r2;
}
void cpuSub8(uint8_t *reg)
static void cpuSub8(uint8_t *reg)
{
a = cpuDoSub8(a,*reg);
}
void cpuCmp8(uint8_t *reg)
static void cpuCmp8(uint8_t *reg)
{
cpuDoSub8(a,*reg);
}
void cpuSbc8(uint8_t *reg)
static void cpuSbc8(uint8_t *reg)
{
uint16_t r1,r2;
uint8_t x = *reg;
@ -196,7 +214,7 @@ void cpuSbc8(uint8_t *reg)
f |= P_FLAG_N;
}
void cpuAdc8(uint8_t *reg)
static void cpuAdc8(uint8_t *reg)
{
uint16_t r1,r2;
uint8_t x = *reg;
@ -582,7 +600,7 @@ static void cpuDec(uint8_t *reg)
f|=tf;
}
void cpuDAA(uint8_t *reg)
static void cpuDAA(uint8_t *reg)
{
int16_t in = *reg;
@ -744,130 +762,132 @@ enum {
};
/* arrays for multiple similar instructions */
static uint8_t cpu_imm_arr[1] = { CPU_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_a_arr[1] = { CPU_A_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_b_arr[1] = { CPU_B_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_c_arr[1] = { CPU_C_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_d_arr[1] = { CPU_D_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_e_arr[1] = { CPU_E_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_h_arr[1] = { CPU_H_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_l_arr[1] = { CPU_L_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_bc_arr[2] = { CPU_TMP_READ8_BC, CPU_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_de_arr[2] = { CPU_TMP_READ8_DE, CPU_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_hl_arr[2] = { CPU_TMP_READ8_HL, CPU_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_pc_arr[2] = { CPU_TMP_READ8_PC_INC, CPU_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_hl_inc_arr[2] = { CPU_TMP_READ8_HL_INC, CPU_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_hl_dec_arr[2] = { CPU_TMP_READ8_HL_DEC, CPU_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_delay_arr[2] = { CPU_DELAY_CYCLE, CPU_ACTION_GET_INSTRUCTION };
static uint8_t cpu_imm_hl_st_arr[3] = { CPU_TMP_READ8_HL, CPU_ACTION_WRITE8_HL, CPU_GET_INSTRUCTION };
static const uint8_t cpu_imm_arr[1] = { CPU_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_a_arr[1] = { CPU_A_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_b_arr[1] = { CPU_B_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_c_arr[1] = { CPU_C_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_d_arr[1] = { CPU_D_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_e_arr[1] = { CPU_E_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_h_arr[1] = { CPU_H_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_l_arr[1] = { CPU_L_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_bc_arr[2] = { CPU_TMP_READ8_BC, CPU_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_de_arr[2] = { CPU_TMP_READ8_DE, CPU_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_hl_arr[2] = { CPU_TMP_READ8_HL, CPU_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_pc_arr[2] = { CPU_TMP_READ8_PC_INC, CPU_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_hl_inc_arr[2] = { CPU_TMP_READ8_HL_INC, CPU_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_hl_dec_arr[2] = { CPU_TMP_READ8_HL_DEC, CPU_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_delay_arr[2] = { CPU_DELAY_CYCLE, CPU_ACTION_GET_INSTRUCTION };
static const uint8_t cpu_imm_hl_st_arr[3] = { CPU_TMP_READ8_HL, CPU_ACTION_WRITE8_HL, CPU_GET_INSTRUCTION };
/* arrays for single special instructions */
static uint8_t cpu_nop_arr[1] = { CPU_GET_INSTRUCTION };
static uint8_t cpu_sub_arr[1] = { CPU_GET_SUBINSTRUCTION };
static uint8_t cpu_hljmp_arr[1] = { CPU_PC_FROM_HL_GET_INSTRUCTION };
static uint8_t cpu_sp_from_hl_arr[2] = { CPU_SP_FROM_HL, CPU_GET_INSTRUCTION };
static uint8_t cpu_absjmp_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_PCL_FROM_TMP_PCH_READ8_PC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static uint8_t cpu_absjmpnz_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_JPNZ_CHK, CPU_PC_FROM_T16, CPU_GET_INSTRUCTION };
static uint8_t cpu_absjmpnc_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_JPNC_CHK, CPU_PC_FROM_T16, CPU_GET_INSTRUCTION };
static uint8_t cpu_absjmpz_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_JPZ_CHK, CPU_PC_FROM_T16, CPU_GET_INSTRUCTION };
static uint8_t cpu_absjmpc_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_JPC_CHK, CPU_PC_FROM_T16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_nop_arr[1] = { CPU_GET_INSTRUCTION };
static const uint8_t cpu_sub_arr[1] = { CPU_GET_SUBINSTRUCTION };
static const uint8_t cpu_hljmp_arr[1] = { CPU_PC_FROM_HL_GET_INSTRUCTION };
static const uint8_t cpu_sp_from_hl_arr[2] = { CPU_SP_FROM_HL, CPU_GET_INSTRUCTION };
static const uint8_t cpu_absjmp_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_PCL_FROM_TMP_PCH_READ8_PC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_absjmpnz_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_JPNZ_CHK, CPU_PC_FROM_T16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_absjmpnc_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_JPNC_CHK, CPU_PC_FROM_T16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_absjmpz_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_JPZ_CHK, CPU_PC_FROM_T16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_absjmpc_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_JPC_CHK, CPU_PC_FROM_T16, CPU_GET_INSTRUCTION };
static uint8_t cpu_abscall_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static uint8_t cpu_abscallnz_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_CNZ_CHK, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static uint8_t cpu_abscallnc_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_CNC_CHK, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static uint8_t cpu_abscallz_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_CZ_CHK, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static uint8_t cpu_abscallc_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_CC_CHK, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_abscall_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_abscallnz_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_CNZ_CHK, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_abscallnc_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_CNC_CHK, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_abscallz_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_CZ_CHK, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_abscallc_arr[6] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC_CC_CHK, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_GET_INSTRUCTION };
static uint8_t cpu_ret_arr[4] = { CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static uint8_t cpu_reti_arr[4] = { CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_EI_GET_INSTRUCTION };
static uint8_t cpu_retnz_arr[5] = { CPU_RET_NZ_CHK, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static uint8_t cpu_retnc_arr[5] = { CPU_RET_NC_CHK, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static uint8_t cpu_retz_arr[5] = { CPU_RET_Z_CHK, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static uint8_t cpu_retc_arr[5] = { CPU_RET_C_CHK, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ret_arr[4] = { CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_reti_arr[4] = { CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_EI_GET_INSTRUCTION };
static const uint8_t cpu_retnz_arr[5] = { CPU_RET_NZ_CHK, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_retnc_arr[5] = { CPU_RET_NC_CHK, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_retz_arr[5] = { CPU_RET_Z_CHK, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_retc_arr[5] = { CPU_RET_C_CHK, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst00_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_00, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst08_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_08, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst10_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_10, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst18_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_18, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst20_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_20, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst28_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_28, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst30_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_30, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst38_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_38, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst40_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_40, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst48_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_48, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst50_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_50, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst58_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_58, CPU_GET_INSTRUCTION };
static uint8_t cpu_rst60_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_60, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst00_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_00, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst08_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_08, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst10_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_10, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst18_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_18, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst20_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_20, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst28_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_28, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst30_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_30, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst38_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_38, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst40_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_40, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst48_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_48, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst50_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_50, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst58_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_58, CPU_GET_INSTRUCTION };
static const uint8_t cpu_rst60_arr[5] = { CPU_DELAY_CYCLE, CPU_DELAY_CYCLE, CPU_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_60, CPU_GET_INSTRUCTION };
static uint8_t cpu_push_bc_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_B_DEC, CPU_SP_WRITE8_C_DEC, CPU_GET_INSTRUCTION };
static uint8_t cpu_push_de_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_D_DEC, CPU_SP_WRITE8_E_DEC, CPU_GET_INSTRUCTION };
static uint8_t cpu_push_hl_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_H_DEC, CPU_SP_WRITE8_L_DEC, CPU_GET_INSTRUCTION };
static uint8_t cpu_push_af_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_A_DEC, CPU_SP_WRITE8_F_DEC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_push_bc_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_B_DEC, CPU_SP_WRITE8_C_DEC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_push_de_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_D_DEC, CPU_SP_WRITE8_E_DEC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_push_hl_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_H_DEC, CPU_SP_WRITE8_L_DEC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_push_af_arr[4] = { CPU_DELAY_CYCLE, CPU_SP_WRITE8_A_DEC, CPU_SP_WRITE8_F_DEC, CPU_GET_INSTRUCTION };
static uint8_t cpu_pop_bc_arr[3] = { CPU_TMP_READ8_SP_INC, CPU_C_FROM_TMP_B_READ8_SP_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_pop_de_arr[3] = { CPU_TMP_READ8_SP_INC, CPU_E_FROM_TMP_D_READ8_SP_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_pop_hl_arr[3] = { CPU_TMP_READ8_SP_INC, CPU_L_FROM_TMP_H_READ8_SP_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_pop_af_arr[3] = { CPU_TMP_READ8_SP_INC, CPU_F_FROM_TMP_A_READ8_SP_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_pop_bc_arr[3] = { CPU_TMP_READ8_SP_INC, CPU_C_FROM_TMP_B_READ8_SP_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_pop_de_arr[3] = { CPU_TMP_READ8_SP_INC, CPU_E_FROM_TMP_D_READ8_SP_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_pop_hl_arr[3] = { CPU_TMP_READ8_SP_INC, CPU_L_FROM_TMP_H_READ8_SP_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_pop_af_arr[3] = { CPU_TMP_READ8_SP_INC, CPU_F_FROM_TMP_A_READ8_SP_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_a_arr[2] = { CPU_A_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_b_arr[2] = { CPU_B_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_c_arr[2] = { CPU_C_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_d_arr[2] = { CPU_D_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_e_arr[2] = { CPU_E_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_h_arr[2] = { CPU_H_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_l_arr[2] = { CPU_L_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_a_arr[2] = { CPU_A_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_b_arr[2] = { CPU_B_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_c_arr[2] = { CPU_C_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_d_arr[2] = { CPU_D_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_e_arr[2] = { CPU_E_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_h_arr[2] = { CPU_H_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_l_arr[2] = { CPU_L_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ldhc_a_arr[2] = { CPU_C_READHIGH_A, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ldhc_a_arr[2] = { CPU_C_READHIGH_A, CPU_GET_INSTRUCTION };
static uint8_t cpu_ldh_a_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_TMP_READHIGH_A, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ldh_a_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_TMP_READHIGH_A, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_bc_arr[3] = { CPU_C_READ8_PC_INC, CPU_B_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_de_arr[3] = { CPU_E_READ8_PC_INC, CPU_D_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_hl_arr[3] = { CPU_L_READ8_PC_INC, CPU_H_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_sp_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_SPL_FROM_TMP_SPH_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_bc_arr[3] = { CPU_C_READ8_PC_INC, CPU_B_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_de_arr[3] = { CPU_E_READ8_PC_INC, CPU_D_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_hl_arr[3] = { CPU_L_READ8_PC_INC, CPU_H_READ8_PC_INC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_sp_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_SPL_FROM_TMP_SPH_READ8_PC_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld16_a_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC, CPU_A_READ8_TMP16, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld16_a_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC, CPU_A_READ8_TMP16, CPU_GET_INSTRUCTION };
static uint8_t cpu_st_a_arr[2] = { CPU_A_ACTION_WRITE, CPU_GET_INSTRUCTION };
static uint8_t cpu_st_b_arr[2] = { CPU_B_ACTION_WRITE, CPU_GET_INSTRUCTION };
static uint8_t cpu_st_c_arr[2] = { CPU_C_ACTION_WRITE, CPU_GET_INSTRUCTION };
static uint8_t cpu_st_d_arr[2] = { CPU_D_ACTION_WRITE, CPU_GET_INSTRUCTION };
static uint8_t cpu_st_e_arr[2] = { CPU_E_ACTION_WRITE, CPU_GET_INSTRUCTION };
static uint8_t cpu_st_h_arr[2] = { CPU_H_ACTION_WRITE, CPU_GET_INSTRUCTION };
static uint8_t cpu_st_l_arr[2] = { CPU_L_ACTION_WRITE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st_a_arr[2] = { CPU_A_ACTION_WRITE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st_b_arr[2] = { CPU_B_ACTION_WRITE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st_c_arr[2] = { CPU_C_ACTION_WRITE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st_d_arr[2] = { CPU_D_ACTION_WRITE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st_e_arr[2] = { CPU_E_ACTION_WRITE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st_h_arr[2] = { CPU_H_ACTION_WRITE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st_l_arr[2] = { CPU_L_ACTION_WRITE, CPU_GET_INSTRUCTION };
static uint8_t cpu_st_imm_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_ACTION_WRITE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st_imm_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_ACTION_WRITE, CPU_GET_INSTRUCTION };
static uint8_t cpu_sthc_a_arr[2] = { CPU_C_WRITEHIGH_A, CPU_GET_INSTRUCTION };
static uint8_t cpu_sth_a_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_TMP_WRITEHIGH_A, CPU_GET_INSTRUCTION };
static const uint8_t cpu_sthc_a_arr[2] = { CPU_C_WRITEHIGH_A, CPU_GET_INSTRUCTION };
static const uint8_t cpu_sth_a_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_TMP_WRITEHIGH_A, CPU_GET_INSTRUCTION };
static uint8_t cpu_st16_a_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC, CPU_A_ACTION_WRITE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st16_a_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC, CPU_A_ACTION_WRITE, CPU_GET_INSTRUCTION };
static uint8_t cpu_st16_sp_arr[5] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC, CPU_TMP16_WRITE8_SPL_INC, CPU_TMP16_WRITE8_SPH, CPU_GET_INSTRUCTION };
static const uint8_t cpu_st16_sp_arr[5] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T16H_READ8_PC_INC, CPU_TMP16_WRITE8_SPL_INC, CPU_TMP16_WRITE8_SPH, CPU_GET_INSTRUCTION };
static uint8_t cpu_jr_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static uint8_t cpu_jrnz_arr[3] = { CPU_TMP_READ8_PC_INC_JRNZ_CHK, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static uint8_t cpu_jrz_arr[3] = { CPU_TMP_READ8_PC_INC_JRZ_CHK, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static uint8_t cpu_jrnc_arr[3] = { CPU_TMP_READ8_PC_INC_JRNC_CHK, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static uint8_t cpu_jrc_arr[3] = { CPU_TMP_READ8_PC_INC_JRC_CHK, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_jr_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_jrnz_arr[3] = { CPU_TMP_READ8_PC_INC_JRNZ_CHK, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_jrz_arr[3] = { CPU_TMP_READ8_PC_INC_JRZ_CHK, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_jrnc_arr[3] = { CPU_TMP_READ8_PC_INC_JRNC_CHK, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static const uint8_t cpu_jrc_arr[3] = { CPU_TMP_READ8_PC_INC_JRC_CHK, CPU_TMP_ADD_PC, CPU_GET_INSTRUCTION };
static uint8_t cpu_di_arr[1] = { CPU_DI_GET_INSTRUCTION };
static uint8_t cpu_ei_arr[1] = { CPU_GET_INSTRUCTION_EI };
static uint8_t cpu_scf_arr[1] = { CPU_SCF_GET_INSTRUCTION };
static uint8_t cpu_ccf_arr[1] = { CPU_CCF_GET_INSTRUCTION };
static const uint8_t cpu_di_arr[1] = { CPU_DI_GET_INSTRUCTION };
static const uint8_t cpu_ei_arr[1] = { CPU_GET_INSTRUCTION_EI };
static const uint8_t cpu_scf_arr[1] = { CPU_SCF_GET_INSTRUCTION };
static const uint8_t cpu_ccf_arr[1] = { CPU_CCF_GET_INSTRUCTION };
static uint8_t cpu_add_bc_arr[2] = { CPU_BC_ACTION_ADD, CPU_GET_INSTRUCTION };
static uint8_t cpu_add_de_arr[2] = { CPU_DE_ACTION_ADD, CPU_GET_INSTRUCTION };
static uint8_t cpu_add_hl_arr[2] = { CPU_HL_ACTION_ADD, CPU_GET_INSTRUCTION };
static uint8_t cpu_add_sp_arr[2] = { CPU_SP_ACTION_ADD, CPU_GET_INSTRUCTION };
static uint8_t cpu_ld_hl_add_sp_imm_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_HL_ADD_SPECIAL, CPU_GET_INSTRUCTION };
static uint8_t cpu_add_sp_imm_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_SP_ADD_SPECIAL, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static const uint8_t cpu_add_bc_arr[2] = { CPU_BC_ACTION_ADD, CPU_GET_INSTRUCTION };
static const uint8_t cpu_add_de_arr[2] = { CPU_DE_ACTION_ADD, CPU_GET_INSTRUCTION };
static const uint8_t cpu_add_hl_arr[2] = { CPU_HL_ACTION_ADD, CPU_GET_INSTRUCTION };
static const uint8_t cpu_add_sp_arr[2] = { CPU_SP_ACTION_ADD, CPU_GET_INSTRUCTION };
static const uint8_t cpu_ld_hl_add_sp_imm_arr[3] = { CPU_TMP_READ8_PC_INC, CPU_HL_ADD_SPECIAL, CPU_GET_INSTRUCTION };
static const uint8_t cpu_add_sp_imm_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_SP_ADD_SPECIAL, CPU_DELAY_CYCLE, CPU_GET_INSTRUCTION };
static uint8_t cpu_start_arr[1] = { CPU_GET_INSTRUCTION };
static uint8_t *cpu_action_arr = cpu_start_arr;
static uint8_t cpu_arr_pos = 0;
static inline void cpuSetNopArr()
{
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
}
static uint8_t *cpu_instr_arr[256] = {
static const uint8_t *cpu_instr_arr[256] = {
cpu_nop_arr, cpu_ld_bc_arr, cpu_st_a_arr, cpu_imm_delay_arr, //0x00-0x03
cpu_imm_b_arr, cpu_imm_b_arr, cpu_ld_b_arr, cpu_imm_a_arr, //0x04-0x07
cpu_st16_sp_arr, cpu_add_bc_arr, cpu_imm_bc_arr, cpu_imm_delay_arr, //0x08-0x0B
@ -953,7 +973,7 @@ typedef void (*cpu_action_t)(uint8_t*);
static cpu_action_t cpu_actions_arr[256];
static cpu_action_t cpu_action_func;
void cpuSetupActionArr()
static void cpuSetupActionArr()
{
cpu_actions_arr[0x00] = cpuNoAction; cpu_actions_arr[0x01] = cpuNoAction; cpu_actions_arr[0x02] = cpuSTbc; cpu_actions_arr[0x03] = cpuBcInc;
cpu_actions_arr[0x04] = cpuInc; cpu_actions_arr[0x05] = cpuDec; cpu_actions_arr[0x06] = cpuNoAction; cpu_actions_arr[0x07] = cpuRLCA;
@ -1085,7 +1105,7 @@ bool cpuHandleIrqUpdates()
}
return false;
}
static uint8_t curInstr;
void cpuGetInstruction()
{
if(cpuHandleIrqUpdates())
@ -1102,8 +1122,7 @@ void cpuGetInstruction()
//if(!gbsInitRet)
// printf("Init return\n");
gbsInitRet = true; //allow play call
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
cpuSetNopArr();
return;
} //play return
else if(pc == 0x8765)
@ -1111,15 +1130,13 @@ void cpuGetInstruction()
//if(!gbsPlayRet)
// printf("Play return\n");
gbsPlayRet = true; //allow next play call
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
cpuSetNopArr();
return;
}
}
if(cpuHaltLoop)
{
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
cpuSetNopArr();
//happens when IME=0
if(!irqEnable && memGetCurIrqList())
cpuHaltLoop = false;
@ -1132,19 +1149,18 @@ void cpuGetInstruction()
if(cpuInAny && !cpuPrevInAny)
cpuStopLoop = false;
cpuPrevInAny = cpuInAny;
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
cpuSetNopArr();
return;
}
curInstr = memGet8(pc);
cpu_action_arr = cpu_instr_arr[curInstr];
cpu_arr_pos = 0;
if(cpu_action_arr == NULL)
{
printf("CPU Error: Unsupported Instruction at %04x:%02x!\n", pc-1,curInstr);
cpu_action_arr = cpu_nop_arr;
cpuSetNopArr();
cpuSetStopLoop();
}
cpu_arr_pos = 0;
cpu_action_func = cpu_actions_arr[curInstr];
//if(pc==0xABC || pc == 0xAC1 || pc == 0x5E0E || pc == 0x5E0F)
@ -1154,8 +1170,6 @@ void cpuGetInstruction()
cpuHaltBug = false;
}
static bool cpu_oam_dma_started = false;
static uint8_t cpu_oam_dma_pos = 0;
static void cpuHandleOAMDMA()
{
if(cpu_oam_dma)
@ -1184,7 +1198,6 @@ static void cpuHandleOAMDMA()
}
/* Main CPU Interpreter */
bool cpuDmaHalt = false;
void cpuCycle()
{
@ -1233,7 +1246,7 @@ void cpuCycle()
break;
default: //should never happen
printf("CPU Error: Unknown sub %02x\n", sub_instr);
cpu_action_arr = cpu_nop_arr;
cpuSetNopArr();
cpuSetStopLoop();
break;
}
@ -1703,8 +1716,7 @@ void cpuPlayGBS()
a = 0, b = 0, c = 0, d = 0, e = 0;//, h = 0, l = 0;
//jump to play
pc = gbsPlayAddr;
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
cpuSetNopArr();
//printf("Playback Start at %04x\n", pc);
}
extern uint8_t gbsTMA, gbsTAC;
@ -1731,7 +1743,6 @@ void cpuLoadGBS(uint8_t song)
a = song;
pc = gbsInitAddr;
//start getting instructions
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
cpuSetNopArr();
//printf("Init Start at %04x\n", pc);
}

View File

@ -32,10 +32,6 @@ extern uint32_t textureImage[0x5A00];
extern volatile bool emuRenderFrame;
extern const char *VERSION_STRING;
void memLoadSave()
{
}
void memSaveGame()
{
@ -196,12 +192,17 @@ unsigned retro_get_region()
return RETRO_REGION_NTSC;
}
extern bool emuSaveEnabled;
extern char emuSaveName[1024];
extern size_t extTotalSize;
void *retro_get_memory_data(unsigned id)
{
switch(id & RETRO_MEMORY_MASK)
{
case RETRO_MEMORY_SAVE_RAM:
return Ext_Mem;
if(emuSaveName[0] && emuSaveEnabled && extTotalSize)
return Ext_Mem;
break;
}
return NULL;
}
@ -211,7 +212,9 @@ size_t retro_get_memory_size(unsigned id)
switch(id & RETRO_MEMORY_MASK)
{
case RETRO_MEMORY_SAVE_RAM:
return sizeof(Ext_Mem);
if(emuSaveName[0] && emuSaveEnabled && extTotalSize)
return extTotalSize;
break;
}
return 0;
}

151
main.c
View File

@ -32,7 +32,7 @@
#define DEBUG_KEY 0
#define DEBUG_LOAD_INFO 1
const char *VERSION_STRING = "fixGB Alpha v0.8.1";
const char *VERSION_STRING = "fixGB Alpha v0.8.2";
static char window_title[256];
static char window_title_pause[256];
@ -49,7 +49,7 @@ enum {
static void gbEmuFileOpen(const char *name);
static bool gbEmuFileRead();
static void gbEmuFileClose();
static void gbEmuResetRegs();
static void gbEmuDisplayFrame(void);
void gbEmuMainLoop(void);
void gbEmuDeinit(void);
@ -59,30 +59,41 @@ static void gbEmuHandleKeyUp(unsigned char key, int x, int y);
static void gbEmuHandleSpecialDown(int key, int x, int y);
static void gbEmuHandleSpecialUp(int key, int x, int y);
static int emuFileType = FTYPE_UNK;
volatile bool emuRenderFrame;
static int emuFileType;
static char emuFileName[1024];
uint8_t *emuGBROM = NULL;
uint32_t emuGBROMsize = 0;
uint32_t emuGBROMsize;
char emuSaveName[1024];
bool emuSaveEnabled;
//used externally
uint32_t textureImage[0x5A00];
bool gbPause = false;
bool gbEmuGBSPlayback = false;
bool gbsTimerMode = false;
uint16_t gbsLoadAddr = 0;
uint16_t gbsInitAddr = 0;
uint16_t gbsPlayAddr = 0;
uint32_t gbsRomSize = 0;
uint16_t gbsSP = 0;
uint8_t gbsTracksTotal = 0, gbsTMA = 0, gbsTAC = 0;
uint8_t cpuTimer = 3;
bool gbCgbGame = false;
bool gbCgbMode = false;
bool gbCgbBootrom = false;
bool gbAllowInvVRAM = false;
bool gbPause;
bool gbEmuGBSPlayback;
bool gbsTimerMode;
uint16_t gbsLoadAddr;
uint16_t gbsInitAddr;
uint16_t gbsPlayAddr;
uint32_t gbsRomSize;
uint16_t gbsSP;
uint8_t gbsTracksTotal, gbsTMA, gbsTAC;
uint8_t cpuTimer;
bool gbCgbGame;
bool gbCgbMode;
bool gbCgbBootrom;
bool gbAllowInvVRAM;
bool gbIsMulticart;
static bool inPause = false;
static bool inResize = false;
static bool inPause;
static bool inResize;
//used externally
bool emuSkipVsync;
bool emuSkipFrame;
static uint8_t mainClock;
static uint8_t memClock;
#if WINDOWS_BUILD
#include <windows.h>
@ -104,15 +115,28 @@ static DWORD emuMainTotalElapsed = 0;
#define VISIBLE_DOTS 160
#define VISIBLE_LINES 144
static uint32_t linesToDraw = VISIBLE_LINES;
static uint32_t linesToDraw;
static const uint32_t visibleImg = VISIBLE_DOTS*VISIBLE_LINES*4;
static uint8_t scaleFactor = 3;
static uint8_t scaleFactor;
#ifndef __LIBRETRO__
static uint32_t mainLoopRuns;
static uint16_t mainLoopPos;
#endif
static FILE *gbEmuFilePointer = NULL;
#if ZIPSUPPORT
static bool gbEmuFileIsZip;
static uint8_t *gbEmuZipBuf = NULL;
static uint32_t gbEmuZipLen;
static unzFile gbEmuZipObj;
static unz_file_info gbEmuZipObjInfo;
#endif
//from input.c
extern uint8_t inValReads[8];
//from mbc.c
extern bool rtcUsed;
extern size_t extTotalSize;
#ifdef __LIBRETRO__
int gbEmuLoadGame(const char* filename)
@ -124,11 +148,7 @@ int main(int argc, char** argv)
{
#endif
puts(VERSION_STRING);
strcpy(window_title, VERSION_STRING);
memset(textureImage,0,visibleImg);
emuFileType = FTYPE_UNK;
memset(emuFileName,0,1024);
memset(emuSaveName,0,1024);
gbEmuResetRegs();
if(argc >= 2)
gbEmuFileOpen(argv[1]);
if(emuFileType == FTYPE_GB || emuFileType == FTYPE_GBC)
@ -170,6 +190,8 @@ int main(int argc, char** argv)
gbCgbGame = (emuGBROM[0x143] == 0x80 || emuGBROM[0x143] == 0xC0);
gbCgbMode = (gbCgbGame || gbCgbBootrom);
printf("Main: CGB Regs are %sallowed\n", gbCgbMode?"":"dis");
//Quick multicart check
gbIsMulticart = (emuGBROMsize == 0x200000 && strcmp((char*)(emuGBROM+0x134), "QBILLION") == 0);
if(!memInit(true,false))
{
free(emuGBROM);
@ -317,14 +339,59 @@ int main(int argc, char** argv)
return EXIT_SUCCESS;
}
static FILE *gbEmuFilePointer = NULL;
static void gbEmuResetRegs()
{
strcpy(window_title, VERSION_STRING);
emuRenderFrame = false;
linesToDraw = VISIBLE_LINES;
scaleFactor = 3;
memset(textureImage,0,visibleImg);
emuFileType = FTYPE_UNK;
memset(emuFileName,0,1024);
memset(emuSaveName,0,1024);
emuSaveEnabled = false;
if(emuGBROM)
free(emuGBROM);
emuGBROM = NULL;
emuGBROMsize = 0;
gbPause = false;
gbEmuGBSPlayback = false;
gbsTimerMode = false;
gbsLoadAddr = 0, gbsInitAddr = 0;
gbsPlayAddr = 0, gbsRomSize = 0;
gbsSP = 0;
gbsTracksTotal = 0, gbsTMA = 0, gbsTAC = 0;
cpuTimer = 3;
gbCgbGame = false;
gbCgbMode = false;
gbCgbBootrom = false;
gbAllowInvVRAM = false;
gbIsMulticart = false;
inPause = false;
inResize = false;
emuSkipVsync = false;
emuSkipFrame = false;
mainClock = 0;
memClock = 0;
if(gbEmuFilePointer)
fclose(gbEmuFilePointer);
gbEmuFilePointer = NULL;
#if ZIPSUPPORT
static bool gbEmuFileIsZip = false;
static uint8_t *gbEmuZipBuf = NULL;
static uint32_t gbEmuZipLen = 0;
static unzFile gbEmuZipObj;
static unz_file_info gbEmuZipObjInfo;
gbEmuFileIsZip = false;
if(gbEmuZipBuf)
free(gbEmuZipBuf);
gbEmuZipBuf = NULL;
gbEmuZipLen = 0;
#endif
}
static int gbEmuGetFileType(const char *name)
{
int nLen = strlen(name);
@ -487,8 +554,6 @@ static void gbEmuFileClose()
gbEmuFilePointer = NULL;
}
volatile bool emuRenderFrame = false;
void gbEmuDeinit(void)
{
//printf("\n");
@ -498,17 +563,19 @@ void gbEmuDeinit(void)
if(emuGBROM != NULL)
free(emuGBROM);
emuGBROM = NULL;
#ifndef __LIBRETRO__
memSaveGame();
#endif
emuFileType = FTYPE_UNK;
memset(emuFileName,0,1024);
memset(emuSaveName,0,1024);
extTotalSize = 0;
rtcUsed = false;
memDeinit();
gbIsMulticart = false;
//printf("Bye!\n");
}
//used externally
bool emuSkipVsync = false;
bool emuSkipFrame = false;
static uint8_t mainClock = 0;
static uint8_t memClock = 0;
void gbEmuMainLoop(void)
{
//do one scanline loop

98
mbc.c
View File

@ -14,26 +14,37 @@
#include "mbc.h"
uint8_t Ext_Mem[0x20000];
static bool RamIOAllowed = false;
set8FuncT mbcSet8;
set8FuncT mbcSetRAM8;
get8FuncT mbcGetRAM8;
static uint8_t rtcReg = 0;
uint16_t cBank = 1;
uint16_t extBank = 0;
uint16_t bankMask = 0;
uint16_t extMask = 0;
uint16_t extAddrMask = 0;
size_t extTotalSize = 0;
//multicart regs
uint16_t tBank0;
uint16_t tBank1;
uint16_t oBank;
uint16_t iBank;
uint16_t oBankAnd;
uint16_t iBankAnd;
uint8_t mcState;
bool mcLocked;
bool extMemEnabled = false;
bool bankUsed = false;
bool extSelect = false;
bool rtcUsed = false;
bool rtcEnabled = false;
//normal regs
uint8_t rtcReg;
uint16_t cBank;
uint16_t extBank;
uint16_t bankMask;
uint16_t extMask;
uint16_t extAddrMask;
size_t extTotalSize;
static uint8_t lastRTCval = 0;
bool RamIOAllowed;
bool extMemEnabled;
bool bankUsed;
bool extSelect;
bool rtcUsed;
bool rtcEnabled;
uint8_t lastRTCval;
//used in for example VBA
static struct RTCSave_t {
@ -52,6 +63,7 @@ static struct RTCSave_t {
static void noSet8(uint16_t addr, uint8_t val);
static void mbc1Set8(uint16_t addr, uint8_t val);
static void mbc1mcSet8(uint16_t addr, uint8_t val);
static void mbc2Set8(uint16_t addr, uint8_t val);
static void mbc3Set8(uint16_t addr, uint8_t val);
static void mbc5Set8(uint16_t addr, uint8_t val);
@ -69,9 +81,12 @@ static void mbc2SetExtRAM8(uint16_t addr, uint8_t val);
static uint8_t mbcGetNoExtRAM8(uint16_t addr);
static void mbcSetNoExtRAM8(uint16_t addr, uint8_t val);
extern bool gbIsMulticart;
void mbcInit(uint8_t type)
{
if(type == MBC_TYPE_1)
if(gbIsMulticart)
mbcSet8 = mbc1mcSet8;
else if(type == MBC_TYPE_1)
mbcSet8 = mbc1Set8;
else if(type == MBC_TYPE_2)
mbcSet8 = mbc2Set8;
@ -127,6 +142,30 @@ void mbcInit(uint8_t type)
mbcExtRAMInit(type);
}
void mbcResetRegs()
{
//multicart regs
tBank0 = 0, tBank1 = 1;
oBank = 0, iBank = 1;
oBankAnd = 0x20, iBankAnd = 0x3F;
mcState = 0, mcLocked = false;
//normal regs
rtcReg = 0;
cBank = 1;
bankMask = 1;
extBank = 0;
extMask = 0;
extAddrMask = 0;
extTotalSize = 0;
RamIOAllowed = false;
extMemEnabled = false;
bankUsed = false;
extSelect = false;
rtcUsed = false;
rtcEnabled = false;
lastRTCval = 0;
}
static void noSet8(uint16_t addr, uint8_t val)
{
(void)addr;
@ -176,6 +215,35 @@ static void mbc1Set8(uint16_t addr, uint8_t val)
extSelect = !!val;
}
static void mbc1mcSet8(uint16_t addr, uint8_t val)
{
if(addr >= 0x2000 && addr < 0x4000)
{
iBank = val&0x3F;
if(iBank == 0)
iBank |= 1;
tBank1 = ((oBank&oBankAnd)<<1)+(iBank&iBankAnd);
}
else if(addr >= 0x6000 && addr < 0x8000 && !mcLocked)
{
if(mcState == 0)
{
oBank = val&0x3F;
tBank0 = ((oBank&oBankAnd)<<1);
tBank1 = ((oBank&oBankAnd)<<1)+(iBank&iBankAnd);
}
else
{
iBankAnd=(~(val<<1))&0x3F;
oBankAnd=0x20|(val&0x1F);
tBank0 = ((oBank&oBankAnd)<<1);
tBank1 = ((oBank&oBankAnd)<<1)+(iBank&iBankAnd);
mcLocked = !!(val&0x20);
}
mcState^=1;
}
}
static void mbc2Set8(uint16_t addr, uint8_t val)
{
if(addr < 0x2000 && ((addr&0x100) == 0))

1
mbc.h
View File

@ -20,6 +20,7 @@ enum {
};
void mbcInit(uint8_t type);
void mbcResetRegs();
size_t mbcRTCSize();
void mbcRTCInit();
void mbcRTCLoad(FILE *f);

61
mem.c
View File

@ -35,6 +35,7 @@ static uint8_t timerReg;
static uint8_t timerRegVal;
static uint8_t timerResetVal;
static uint16_t timerRegBit;
static bool timerPrevTicked;
static uint8_t sioTimerRegClock;
static uint8_t sioTimerRegTimer;
static uint8_t sioBitsTransfered;
@ -48,15 +49,26 @@ static bool cgbDmaHBlankMode;
static bool cgbBootromEnabled = false;
static bool timerRegEnable = false;
static bool sioTimerRegEnable = false;
static bool emuSaveEnabled = false;
//from main.c
extern bool gbCgbGame;
extern bool gbCgbMode;
extern bool gbCgbBootrom;
extern uint8_t *emuGBROM;
extern bool gbIsMulticart;
//from mbc.c
//multicart regs
extern uint16_t tBank0;
extern uint16_t tBank1;
extern uint16_t oBank;
extern uint16_t iBank;
extern uint16_t oBankAnd;
extern uint16_t iBankAnd;
extern uint8_t mcState;
extern bool mcLocked;
//normal regs
extern uint8_t rtcReg;
extern uint16_t cBank;
extern uint16_t extBank;
extern uint16_t bankMask;
@ -72,16 +84,21 @@ extern bool cpuDoStopSwitch;
extern uint8_t ppuCgbBank;
//from mbc.c
extern bool RamIOAllowed;
extern bool extMemEnabled;
extern bool bankUsed;
extern bool extSelect;
extern bool rtcUsed;
extern bool rtcEnabled;
extern uint8_t lastRTCval;
static get8FuncT memGet8ptr[0x10000];
static set8FuncT memSet8ptr[0x10000];
static uint8_t memCGBBootrom[0x900];
static uint8_t memGetROMBank8(uint16_t addr);
static uint8_t memGetROMNoBank8(uint16_t addr);
static uint8_t memGetROM0Multicart8(uint16_t addr);
static uint8_t memGetROM1Multicart8(uint16_t addr);
static uint8_t memGetBootROMNoBank8(uint16_t addr);
static uint8_t memGetRAMBank8(uint16_t addr);
static uint8_t memGetRAMNoBank8(uint16_t addr);
@ -213,24 +230,17 @@ static void memSetExtVal()
}
}
static uint8_t curGBS = 0;
static uint8_t curGBS;
extern uint8_t gbsTracksTotal;
extern uint32_t gbsRomSize;
bool memInit(bool romcheck, bool gbs)
{
if(romcheck)
{
cBank = 1;
bankMask = 1;
extBank = 0;
extMask = 0;
extAddrMask = 0;
extTotalSize = 0;
bankUsed = false;
extMemEnabled = false;
rtcUsed = false;
mbcResetRegs();
if(gbs)
{
curGBS = 0;
bankUsed = true;
//Get ROM Size multiple
if(gbsRomSize <= 0x8000)
@ -422,6 +432,7 @@ bool memInit(bool romcheck, bool gbs)
timerRegVal = 0;
timerResetVal = 0;
timerRegBit = (1<<9); //Freq 0
timerPrevTicked = false;
sioTimerRegClock = 1;
sioTimerRegTimer = 32;
sioBitsTransfered = 0;
@ -438,6 +449,11 @@ bool memInit(bool romcheck, bool gbs)
return true;
}
void memDeinit()
{
cgbBootromEnabled = false;
}
void memInitGetSetPointers()
{
//init memGet8 and memSet8 arrays
@ -446,12 +462,12 @@ void memInitGetSetPointers()
{
if(addr < 0x4000) //0x0000 - 0x3FFF = Cartridge ROM
{
memGet8ptr[addr] = cgbBootromEnabled?memGetBootROMNoBank8:memGetROMNoBank8;
memGet8ptr[addr] = cgbBootromEnabled?memGetBootROMNoBank8:(gbIsMulticart?memGetROM0Multicart8:memGetROMNoBank8);
memSet8ptr[addr] = mbcSet8;
}
else if(addr < 0x8000) //0x4000 - 0x7FFF = Cartridge ROM (possibly banked)
{
memGet8ptr[addr] = bankUsed?memGetROMBank8:memGetROMNoBank8;
memGet8ptr[addr] = gbIsMulticart?memGetROM1Multicart8:(bankUsed?memGetROMBank8:memGetROMNoBank8);
memSet8ptr[addr] = mbcSet8;
}
else if(addr < 0xA000) //0x8000 - 0x9FFF = PPU VRAM
@ -459,7 +475,7 @@ void memInitGetSetPointers()
memGet8ptr[addr] = gbCgbMode?ppuGetVRAMBank8:ppuGetVRAMNoBank8;
memSet8ptr[addr] = gbCgbMode?ppuSetVRAMBank8:ppuSetVRAMNoBank8;
}
else if(addr < 0xC000) //0xA000 - 0xBFFF = Cardridge RAM
else if(addr < 0xC000) //0xA000 - 0xBFFF = Cartridge RAM
{
memGet8ptr[addr] = mbcGetRAM8;
memSet8ptr[addr] = mbcSetRAM8;
@ -627,6 +643,16 @@ static uint8_t memGetROMNoBank8(uint16_t addr)
return emuGBROM[addr&0x7FFF];
}
static uint8_t memGetROM0Multicart8(uint16_t addr)
{
return emuGBROM[(tBank0<<14)|(addr&0x3FFF)];
}
static uint8_t memGetROM1Multicart8(uint16_t addr)
{
return emuGBROM[(tBank1<<14)|(addr&0x3FFF)];
}
static uint8_t memGetBootROMNoBank8(uint16_t addr)
{
if(addr < 0x100 || (addr >= 0x200 && addr < 0x900))
@ -871,14 +897,14 @@ void memDumpMainMem()
ppuDumpMem();
#endif
}
#ifndef __LIBRETRO__
extern bool emuSaveEnabled;
extern char emuSaveName[1024];
void memLoadSave()
{
if(emuSaveName[0] && (extTotalSize || rtcUsed))
{
emuSaveEnabled = true;
#ifndef __LIBRETRO__
FILE *save = fopen(emuSaveName, "rb");
if(save)
{
@ -895,9 +921,11 @@ void memLoadSave()
printf("Mem: Done reading %s\n", emuSaveName);
fclose(save);
}
#endif
}
}
#ifndef __LIBRETRO__
void memSaveGame()
{
if(emuSaveName[0] && ((emuSaveEnabled && extTotalSize) || rtcUsed))
@ -919,7 +947,6 @@ void memSaveGame()
extern bool gbEmuGBSPlayback;
extern bool gbsTimerMode;
extern uint8_t inValReads[8];
static bool timerPrevTicked = false;
//clocked at 262144 Hz (or 2x that in CGB Mode)
void memClockTimers()
{

1
mem.h
View File

@ -12,6 +12,7 @@ typedef uint8_t (*get8FuncT)(uint16_t);
typedef void (*set8FuncT)(uint16_t, uint8_t val);
bool memInit(bool romcheck, bool gbs);
void memDeinit();
void memInitGetSetPointers();
bool memInitCGBBootrom();
uint8_t memGet8(uint16_t addr);