Skip to content

Commit

Permalink
-fixed playback for some gbs music files
Browse files Browse the repository at this point in the history
-implemented APU zombie mode for volume control
-corrected several CPU instruction timing details
-properly implemented OAM DMA with all its timings etc
-corrected some memory bugs and improved timer accuracy
-added basic serial I/O control support as some games rely on its interrupt
-improved PPU accuracy and implemented STAT DMC bug required for some games
  • Loading branch information
FIX94 committed Sep 8, 2017
1 parent fca433f commit 89d2f66
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 105 deletions.
27 changes: 24 additions & 3 deletions apu.c
Original file line number Diff line number Diff line change
Expand Up @@ -638,8 +638,15 @@ void apuSetReg8(uint16_t addr, uint8_t val)
break;
case 0x12:
p1Env.vol = (val>>4)&0xF;
p1Env.curVol = p1Env.vol;
p1Env.modeadd = (val&8)!=0;
if(p1Env.modeadd && p1Env.period == 0 && (val&7) == 0)
{
//"Zombie" Mode
p1Env.curVol++;
p1Env.curVol &= 0xF;
}
else //Normal behaviour
p1Env.curVol = p1Env.vol;
p1dacenable = (p1Env.modeadd || p1Env.vol);
if(!p1dacenable)
p1enable = false;
Expand Down Expand Up @@ -705,8 +712,15 @@ void apuSetReg8(uint16_t addr, uint8_t val)
break;
case 0x17:
p2Env.vol = (val>>4)&0xF;
p2Env.curVol = p2Env.vol;
p2Env.modeadd = (val&8)!=0;
if(p2Env.modeadd && p2Env.period == 0 && (val&7) == 0)
{
//"Zombie" Mode
p2Env.curVol++;
p2Env.curVol &= 0xF;
}
else //Normal behaviour
p2Env.curVol = p2Env.vol;
p2dacenable = (p2Env.modeadd || p2Env.vol);
if(!p2dacenable)
p2enable = false;
Expand Down Expand Up @@ -822,8 +836,15 @@ void apuSetReg8(uint16_t addr, uint8_t val)
break;
case 0x21:
noiseEnv.vol = (val>>4)&0xF;
noiseEnv.curVol = noiseEnv.vol;
noiseEnv.modeadd = (val&8)!=0;
if(noiseEnv.modeadd && noiseEnv.period == 0 && (val&7) == 0)
{
//"Zombie" Mode
noiseEnv.curVol++;
noiseEnv.curVol &= 0xF;
}
else //Normal behaviour
noiseEnv.curVol = noiseEnv.vol;
noisedacenable = (noiseEnv.modeadd || noiseEnv.vol);
if(!noisedacenable)
noiseenable = false;
Expand Down
84 changes: 64 additions & 20 deletions cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ extern bool gbCgbBootrom;
//used externally
bool cpuDoStopSwitch = false;
bool cpuCgbSpeed = false;
uint8_t cpuAddSpeed = 1;
void cpuSetupActionArr();
bool cpu_oam_dma = false;
bool cpu_oam_dma_running = false;
uint16_t cpu_oam_dma_addr = 0;

static uint16_t sp, pc, cpuTmp16;
static uint8_t a,b,c,d,e,f,h,l,cpuTmp;
Expand Down Expand Up @@ -68,6 +72,9 @@ void cpuInit()
cpuHaltBug = false;
cpuCgbSpeed = false;
cpuPrevInAny = false;
cpu_oam_dma = false;
cpu_oam_dma_running = false;
cpu_oam_dma_addr = 0;
cpuSetupActionArr();
//gbs stuff
gbsInitRet = false; //for first init
Expand Down Expand Up @@ -634,7 +641,6 @@ enum {
CPU_GET_INSTRUCTION = 0,
CPU_GET_SUBINSTRUCTION,
CPU_DELAY_CYCLE,
CPU_DELAY_RETI_CYCLE,
CPU_ACTION_GET_INSTRUCTION,
CPU_A_ACTION_GET_INSTRUCTION,
CPU_B_ACTION_GET_INSTRUCTION,
Expand Down Expand Up @@ -726,6 +732,7 @@ enum {
CPU_TMP16_WRITE8_SPH,
CPU_DI_GET_INSTRUCTION,
CPU_EI_GET_INSTRUCTION,
CPU_GET_INSTRUCTION_EI,
CPU_SCF_GET_INSTRUCTION,
CPU_CCF_GET_INSTRUCTION,
CPU_PC_FROM_HL_GET_INSTRUCTION,
Expand Down Expand Up @@ -766,17 +773,17 @@ static uint8_t cpu_absjmpz_arr[4] = { CPU_TMP_READ8_PC_INC, CPU_T16L_FROM_TMP_T1
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 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_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_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_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_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_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_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_SP_WRITE8_PCH_DEC, CPU_SP_WRITE8_PCL_DEC_PC_FROM_T16, CPU_PC_FROM_T16, CPU_GET_INSTRUCTION };

static uint8_t cpu_ret_arr[4] = { CPU_DELAY_CYCLE, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_reti_arr[4] = { CPU_DELAY_RETI_CYCLE, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_EI_GET_INSTRUCTION };
static uint8_t cpu_retnz_arr[5] = { CPU_RET_NZ_CHK, CPU_DELAY_CYCLE, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_retnc_arr[5] = { CPU_RET_NC_CHK, CPU_DELAY_CYCLE, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_retz_arr[5] = { CPU_RET_Z_CHK, CPU_DELAY_CYCLE, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, CPU_GET_INSTRUCTION };
static uint8_t cpu_retc_arr[5] = { CPU_RET_C_CHK, CPU_DELAY_CYCLE, CPU_TMP_READ8_SP_INC, CPU_PCL_FROM_TMP_PCH_READ8_SP_INC, 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 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 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 };
Expand Down Expand Up @@ -845,7 +852,7 @@ static uint8_t cpu_jrnc_arr[3] = { CPU_TMP_READ8_PC_INC_JRNC_CHK, CPU_TMP_ADD_PC
static 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_EI_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 };

Expand Down Expand Up @@ -1111,12 +1118,13 @@ void cpuGetInstruction()
}
if(cpuHaltLoop)
{
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
//happens when IME=0
if(!irqEnable && memGetCurIrqList())
cpuHaltLoop = false;
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
return;
else //keep waiting
return;
}
if(cpuStopLoop)
{
Expand Down Expand Up @@ -1146,13 +1154,43 @@ 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)
{
if(!cpu_oam_dma_started)
cpu_oam_dma_started = true;
else
{
cpu_oam_dma = false;
cpu_oam_dma_started = false;
cpu_oam_dma_running = true;
cpu_oam_dma_pos = 0;
}
}
if(cpu_oam_dma_running)
{
if(cpu_oam_dma_pos == 0xA0)
cpu_oam_dma_running = false;
else
{
//printf("OAM Copying %02x\n", cpu_oam_dma_pos);
ppuSetOAMDMAVal(cpu_oam_dma_pos,memGet8(cpu_oam_dma_addr+cpu_oam_dma_pos));
cpu_oam_dma_pos++;
}
}
}

/* Main CPU Interpreter */
bool cpuDmaHalt = false;

void cpuCycle()
{
if(cpuDmaHalt)
return;
cpuHandleOAMDMA();
uint8_t cpu_action, sub_instr;
cpu_action = cpu_action_arr[cpu_arr_pos];
cpu_arr_pos++;
Expand Down Expand Up @@ -1245,9 +1283,6 @@ void cpuCycle()
break;
case CPU_DELAY_CYCLE:
break;
case CPU_DELAY_RETI_CYCLE:
//printf("RETI from %04x\n", pc);
break;
case CPU_ACTION_GET_INSTRUCTION:
cpu_action_func(&cpuTmp);
cpuGetInstruction();
Expand Down Expand Up @@ -1587,6 +1622,12 @@ void cpuCycle()
cpuGetInstruction();
break;
case CPU_EI_GET_INSTRUCTION:
irqEnable = true;
//printf("Enabled IRQs and jmp to %04x ",pc);
cpuGetInstruction();
//printf("%04x\n",pc);
break;
case CPU_GET_INSTRUCTION_EI:
//printf("Enabled IRQs and jmp to %04x ",pc);
cpuGetInstruction();
//printf("%04x\n",pc);
Expand Down Expand Up @@ -1635,12 +1676,14 @@ void cpuSetSpeed(bool cgb)
{
//printf("CPU: CGB Speed\n");
cpuCgbSpeed = true;
cpuAddSpeed = 2;
cpuTimer = 1;
}
else
{
//printf("CPU: DMG Speed\n");
cpuCgbSpeed = false;
cpuAddSpeed = 1;
cpuTimer = 3;
}
}
Expand All @@ -1656,7 +1699,8 @@ void cpuPlayGBS()
sp--;
memSet8(sp, 0x65);
//IMPORTANT: some GBS files dont work without this
a = 0, b = 0, c = 0, d = 0, e = 0, h = 0, l = 0;
//Keep HL though, some GBS files use them as global address
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;
Expand Down
2 changes: 1 addition & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#define DEBUG_KEY 0
#define DEBUG_LOAD_INFO 1

static const char *VERSION_STRING = "fixGB Alpha v0.7.2";
static const char *VERSION_STRING = "fixGB Alpha v0.8";
static char window_title[256];
static char window_title_pause[256];

Expand Down
Loading

0 comments on commit 89d2f66

Please sign in to comment.