-dont close emu when opening with unsupported file or no file at all, display error message instead

-dont close emu on invalid cpu instruction, freeze game instead until a button is pressed
-set window title more proper
-display currently playing .gbs track on screen rather than just on the console via bitmap font
This commit is contained in:
FIX94 2017-06-07 22:25:30 +02:00
parent ea19c06579
commit bffa0e6666
No known key found for this signature in database
GPG Key ID: CE39016A19D8EADA
9 changed files with 276 additions and 132 deletions

4
apu.c
View File

@ -152,11 +152,11 @@ void apuDeinitBufs()
apuOutBuf = NULL;
}
extern bool allowCgbRegs;
extern bool gbCgbMode;
void apuInit()
{
memset(APU_IO_Reg,0,0x50);
if(allowCgbRegs) //essentially 50% duty pulse on CGB
if(gbCgbMode) //essentially 50% duty pulse on CGB
memcpy(APU_IO_Reg+0x30,startWavSetCGB,0x10);
else //relatively random audio pattern on DMG
memcpy(APU_IO_Reg+0x30,startWavSetDMG,0x10);

80
cpu.c
View File

@ -26,7 +26,7 @@ extern uint16_t gbsInitAddr;
extern uint16_t gbsPlayAddr;
extern uint16_t gbsSP;
extern uint8_t cpuTimer;
extern bool allowCgbRegs;
extern bool gbCgbMode;
//used externally
bool cpuDoStopSwitch = false;
@ -41,11 +41,11 @@ static bool gbsInitRet, gbsPlayRet;
static uint8_t sub_in_val;
static bool irqEnable;
static bool cpuHaltLoop,cpuStopLoop,cpuHaltBug;
static bool cpuHaltLoop,cpuStopLoop,cpuHaltBug,cpuPrevInAny;
void cpuInit()
{
sub_in_val=0,cpuTmp=0,cpuTmp16=0;
if(allowCgbRegs) //From GBC Bootrom
if(gbCgbMode) //From GBC Bootrom
a=0x11,b=0,c=0,d=0,e=0x08,f=0x80,h=0,l=0x7C;
else //From GB Bootrom
a=0x01,b=0,c=0x13,d=0,e=0xD8,f=0xB0,h=1,l=0x4D;
@ -56,6 +56,7 @@ void cpuInit()
cpuStopLoop = false;
cpuHaltBug = false;
cpuCgbSpeed = false;
cpuPrevInAny = false;
cpuSetupActionArr();
//gbs stuff
gbsInitRet = false; //for first init
@ -597,6 +598,12 @@ void cpuDAA(uint8_t *reg)
*reg = (uint8_t)in;
}
static void cpuSetStopLoop()
{
printf("CPU: Frozen until Button is pressed\n");
cpuStopLoop = true;
}
static void cpuSTOP(uint8_t *none)
{
(void)none;
@ -607,7 +614,7 @@ static void cpuSTOP(uint8_t *none)
cpuDoStopSwitch = false;
}
else
cpuStopLoop = true;
cpuSetStopLoop();
//takes up 2 instructions?
pc++;
}
@ -1065,13 +1072,13 @@ bool cpuHandleIrqUpdates()
return false;
}
static uint8_t curInstr;
bool cpuGetInstruction()
void cpuGetInstruction()
{
if(cpuHandleIrqUpdates())
{
cpuHaltLoop = false;
cpu_arr_pos = 0;
return true;
return;
}
if(gbEmuGBSPlayback)
{
@ -1083,7 +1090,7 @@ bool cpuGetInstruction()
gbsInitRet = true; //allow play call
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
return true;
return;
} //play return
else if(pc == 0x8765)
{
@ -1092,7 +1099,7 @@ bool cpuGetInstruction()
gbsPlayRet = true; //allow next play call
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
return true;
return;
}
}
if(cpuHaltLoop)
@ -1102,50 +1109,50 @@ bool cpuGetInstruction()
cpuHaltLoop = false;
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
return true;
return;
}
if(cpuStopLoop)
{
if(inputAny())
bool cpuInAny = inputAny();
if(cpuInAny && !cpuPrevInAny)
cpuStopLoop = false;
cpuPrevInAny = cpuInAny;
cpu_action_arr = cpu_nop_arr;
cpu_arr_pos = 0;
return true;
return;
}
curInstr = memGet8(pc);
cpu_action_arr = cpu_instr_arr[curInstr];
if(cpu_action_arr == NULL)
{
printf("Unsupported Instruction at %04x:%02x!\n", pc-1,curInstr);
return false;
printf("CPU Error: Unsupported Instruction at %04x:%02x!\n", pc-1,curInstr);
cpu_action_arr = cpu_nop_arr;
cpuSetStopLoop();
}
cpu_arr_pos = 0;
cpu_action_func = cpu_actions_arr[curInstr];
//if(pc==0xABC || pc == 0xAC1 || pc == 0x5E0E || pc == 0x5E0F)
// printf("%04x %02x a %02x b %02x hl %04x\n", pc, curInstr, a, b, (l|(h<<8)));
//HALT bug: PC doesnt increase after instruction is parsed!
if(!cpuHaltBug) pc++;
cpuHaltBug = false;
return true;
}
/* Main CPU Interpreter */
bool cpuDmaHalt = false;
bool cpuCycle()
void cpuCycle()
{
bool cycleret = true;
if(cpuDmaHalt)
return cycleret;
return;
uint8_t cpu_action, sub_instr;
cpu_action = cpu_action_arr[cpu_arr_pos];
cpu_arr_pos++;
switch(cpu_action)
{
case CPU_GET_INSTRUCTION:
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_GET_SUBINSTRUCTION:
sub_instr = memGet8(pc++);
@ -1180,8 +1187,10 @@ bool cpuCycle()
cpu_action_arr = cpu_imm_a_arr;
break;
default: //should never happen
printf("Unknown sub %02x\n", sub_instr);
return false;
printf("CPU Error: Unknown sub %02x\n", sub_instr);
cpu_action_arr = cpu_nop_arr;
cpuSetStopLoop();
break;
}
//set sub func
switch(sub_instr>>3)
@ -1234,35 +1243,35 @@ bool cpuCycle()
break;
case CPU_ACTION_GET_INSTRUCTION:
cpu_action_func(&cpuTmp);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_A_ACTION_GET_INSTRUCTION:
cpu_action_func(&a);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_B_ACTION_GET_INSTRUCTION:
cpu_action_func(&b);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_C_ACTION_GET_INSTRUCTION:
cpu_action_func(&c);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_D_ACTION_GET_INSTRUCTION:
cpu_action_func(&d);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_E_ACTION_GET_INSTRUCTION:
cpu_action_func(&e);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_H_ACTION_GET_INSTRUCTION:
cpu_action_func(&h);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_L_ACTION_GET_INSTRUCTION:
cpu_action_func(&l);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_ACTION_WRITE:
cpu_action_func(&cpuTmp);
@ -1568,27 +1577,27 @@ bool cpuCycle()
case CPU_DI_GET_INSTRUCTION:
//printf("Disabled IRQs at %04x\n", pc);
irqEnable = false;
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_EI_GET_INSTRUCTION:
//printf("Enabled IRQs and jmp to %04x ",pc);
cycleret = cpuGetInstruction();
cpuGetInstruction();
//printf("%04x\n",pc);
irqEnable = true;
break;
case CPU_SCF_GET_INSTRUCTION:
f |= P_FLAG_C;
f &= ~(P_FLAG_H|P_FLAG_N);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_CCF_GET_INSTRUCTION:
f ^= P_FLAG_C;
f &= ~(P_FLAG_H|P_FLAG_N);
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_PC_FROM_HL_GET_INSTRUCTION:
pc = (l|(h<<8));
cycleret = cpuGetInstruction();
cpuGetInstruction();
break;
case CPU_PC_FROM_T16:
pc = cpuTmp16;
@ -1606,7 +1615,6 @@ bool cpuCycle()
if(!(f & P_FLAG_C)) cpu_arr_pos+=3;
break;
}
return cycleret;
}
uint16_t cpuCurPC()

2
cpu.h
View File

@ -9,7 +9,7 @@
#define _cpu_h_
void cpuInit();
bool cpuCycle();
void cpuCycle();
uint16_t cpuCurPC();
void cpuSetSpeed(bool cgb);
void cpuLoadGBS(uint8_t song);

View File

@ -28,7 +28,7 @@ void inputSet8(uint16_t addr, uint8_t in)
(void)addr;
modeSelect = ((in)>>4)&0x3;
#if DEBUG_INPUT
printf("Set %02x->%02x\n",in,modeSelect);
printf("Input: Set %02x->%02x\n",in,modeSelect);
#endif
}

156
main.c
View File

@ -26,7 +26,10 @@
#define DEBUG_KEY 0
#define DEBUG_LOAD_INFO 1
static const char *VERSION_STRING = "fixGB Alpha v0.5.4";
static const char *VERSION_STRING = "fixGB Alpha v0.5.5";
static char window_title[256];
static char window_title_pause[256];
static int window_handle = -1;
static void gbEmuDisplayFrame(void);
static void gbEmuMainLoop(void);
@ -40,9 +43,8 @@ static void gbEmuHandleSpecialUp(int key, int x, int y);
uint8_t *emuGBROM = NULL;
char *emuSaveName = NULL;
//used externally
uint32_t textureImage[0x9A00];
bool nesPause = false;
bool ppuDebugPauseFrame = false;
uint32_t textureImage[0x5A00];
bool gbPause = false;
bool gbEmuGBSPlayback = false;
bool gbsTimerMode = false;
uint16_t gbsLoadAddr = 0;
@ -52,7 +54,7 @@ uint32_t gbsRomSize = 0;
uint16_t gbsSP = 0;
uint8_t gbsTracksTotal = 0, gbsTMA = 0, gbsTAC = 0;
uint8_t cpuTimer = 3;
bool allowCgbRegs = false;
bool gbCgbMode = false;
static bool inPause = false;
static bool inResize = false;
@ -77,6 +79,7 @@ static DWORD emuMainTotalElapsed = 0;
#define VISIBLE_DOTS 160
#define VISIBLE_LINES 144
static uint32_t linesToDraw = VISIBLE_LINES;
static const uint32_t visibleImg = VISIBLE_DOTS*VISIBLE_LINES*4;
static uint8_t scaleFactor = 3;
static uint32_t mainLoopRuns;
@ -87,10 +90,18 @@ extern uint8_t inValReads[8];
int main(int argc, char** argv)
{
puts(VERSION_STRING);
strcpy(window_title, VERSION_STRING);
memset(textureImage,0,visibleImg);
if(argc >= 2 && (strstr(argv[1],".gbs") != NULL || strstr(argv[1],".GBS") != NULL))
{
FILE *gbF = fopen(argv[1],"rb");
if(!gbF) return EXIT_SUCCESS;
if(!gbF)
{
printf("Main: Could not open %s!\n", argv[1]);
puts("Press enter to exit");
getc(stdin);
return EXIT_SUCCESS;
}
fseek(gbF,0,SEEK_END);
size_t fsize = ftell(gbF);
rewind(gbF);
@ -112,14 +123,14 @@ int main(int argc, char** argv)
if(gbsTAC&0x80)
{
cpuSetSpeed(true);
allowCgbRegs = true;
gbCgbMode = true;
}
else
{
cpuSetSpeed(false);
allowCgbRegs = false;
gbCgbMode = false;
}
printf("Main: CGB Regs are %sallowed\n", allowCgbRegs?"":"dis");
printf("Main: CGB Regs are %sallowed\n", gbCgbMode?"":"dis");
if(gbsTAC&4)
{
printf("Main: GBS Play Timing: Timer\n");
@ -132,19 +143,30 @@ int main(int argc, char** argv)
}
memInit(true,true);
if(tmpROM[0x10] != 0)
{
printf("Game: %.32s\n",(char*)(tmpROM+0x10));
sprintf(window_title, "%.32s (GBS) - %s\n", (char*)(tmpROM+0x10), VERSION_STRING);
}
free(tmpROM);
printf("Read in %s\n", argv[1]);
apuInitBufs();
//does all inits for us
memStartGBS();
gbEmuGBSPlayback = true;
linesToDraw = 20;
scaleFactor = 4;
}
else if(argc >= 2 && (strstr(argv[1],".gbc") != NULL || strstr(argv[1],".GBC") != NULL
|| strstr(argv[1],".gb") != NULL || strstr(argv[1],".GB") != NULL))
{
FILE *gbF = fopen(argv[1],"rb");
if(!gbF) return EXIT_SUCCESS;
if(!gbF)
{
printf("Main: Could not open %s!\n", argv[1]);
puts("Press enter to exit");
getc(stdin);
return EXIT_SUCCESS;
}
fseek(gbF,0,SEEK_END);
size_t fsize = ftell(gbF);
rewind(gbF);
@ -152,7 +174,9 @@ int main(int argc, char** argv)
if(emuGBROM == NULL)
{
printf("Main: Unable to allocate ROM space...\n");
exit(EXIT_SUCCESS);
puts("Press enter to exit");
getc(stdin);
return EXIT_SUCCESS;
}
fread(emuGBROM,1,fsize,gbF);
fclose(gbF);
@ -169,13 +193,14 @@ int main(int argc, char** argv)
memcpy(emuSaveName+strlen(argv[1])-2,"sav",4);
}
//Set CGB Regs allowed
allowCgbRegs = (emuGBROM[0x143] == 0x80 || emuGBROM[0x143] == 0xC0);
printf("Main: CGB Regs are %sallowed\n", allowCgbRegs?"":"dis");
gbCgbMode = (emuGBROM[0x143] == 0x80 || emuGBROM[0x143] == 0xC0);
printf("Main: CGB Regs are %sallowed\n", gbCgbMode?"":"dis");
if(!memInit(true,false))
{
free(emuGBROM);
printf("Exit...\n");
exit(EXIT_SUCCESS);
puts("Press enter to exit");
getc(stdin);
return EXIT_SUCCESS;
}
//CPU DMG Mode
cpuSetSpeed(false);
@ -185,11 +210,28 @@ int main(int argc, char** argv)
apuInit();
inputInit();
if(emuGBROM[0x134] != 0)
printf("Game: %.11s\n", (char*)(emuGBROM+0x134));
{
if(gbCgbMode)
{
printf("Game: %.11s\n", (char*)(emuGBROM+0x134));
sprintf(window_title, "%.11s (CGB) - %s\n", (char*)(emuGBROM+0x134), VERSION_STRING);
}
else
{
printf("Game: %.16s\n", (char*)(emuGBROM+0x134));
sprintf(window_title, "%.16s (DMG) - %s\n", (char*)(emuGBROM+0x134), VERSION_STRING);
}
}
printf("Read in %s\n", argv[1]);
}
if(emuGBROM == NULL)
{
printf("Main: No File to Open! Make sure to call fixGB with a .gb/.gbc/.gbs File as Argument.\n");
puts("Press enter to exit");
getc(stdin);
return EXIT_SUCCESS;
}
sprintf(window_title_pause, "%s (Pause)", window_title);
#if WINDOWS_BUILD
#if DEBUG_HZ
emuFrameStart = GetTickCount();
@ -198,14 +240,13 @@ int main(int argc, char** argv)
emuMainFrameStart = GetTickCount();
#endif
#endif
memset(textureImage,0,visibleImg);
//do one scanline per idle loop
mainLoopRuns = 70224;
mainLoopPos = mainLoopRuns;
glutInit(&argc, argv);
glutInitWindowSize(VISIBLE_DOTS*scaleFactor, VISIBLE_LINES*scaleFactor);
glutInitWindowSize(VISIBLE_DOTS*scaleFactor, linesToDraw*scaleFactor);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutCreateWindow(VERSION_STRING);
window_handle = glutCreateWindow(gbPause ? window_title_pause : window_title);
audioInit();
atexit(&gbEmuDeinit);
glutKeyboardFunc(&gbEmuHandleKeyDown);
@ -220,7 +261,7 @@ int main(int argc, char** argv)
wglSwapIntervalEXT(1);
#endif
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, 4, VISIBLE_DOTS, VISIBLE_LINES, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, textureImage);
glTexImage2D(GL_TEXTURE_2D, 0, 4, VISIBLE_DOTS, linesToDraw, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, textureImage);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -248,6 +289,9 @@ static void gbEmuDeinit(void)
if(emuSaveName != NULL)
free(emuSaveName);
emuSaveName = NULL;
if(window_handle >= 0)
glutDestroyWindow(window_handle);
window_handle = -1;
//printf("Bye!\n");
}
@ -263,7 +307,7 @@ static void gbEmuMainLoop(void)
//do one scanline loop
do
{
if((!emuSkipVsync && emuRenderFrame) || nesPause)
if((!emuSkipVsync && emuRenderFrame) || gbPause)
{
#if (WINDOWS_BUILD && DEBUG_MAIN_CALLS)
emuMainTimesSkipped++;
@ -288,11 +332,7 @@ static void gbEmuMainLoop(void)
if(!(mainClock&cpuTimer))
{
//main CPU clock
if(!cpuCycle())
{
//memDumpMainMem();
exit(EXIT_SUCCESS);
}
cpuCycle();
//mem clock tied to CPU clock, so
//double speed in CGB mode!
if(!(memClock&3))
@ -300,31 +340,26 @@ static void gbEmuMainLoop(void)
memClock++;
}
//run PPU last
if(!ppuCycle())
exit(EXIT_SUCCESS);
ppuCycle();
if(ppuDrawDone())
{
if(!gbEmuGBSPlayback)
emuRenderFrame = true;
//update console stats if requested
#if (WINDOWS_BUILD && DEBUG_HZ)
emuTimesCalled++;
DWORD end = GetTickCount();
emuTotalElapsed += end - emuFrameStart;
if(emuTotalElapsed >= 1000)
{
emuRenderFrame = true;
//update console stats if requested
#if (WINDOWS_BUILD && DEBUG_HZ)
emuTimesCalled++;
DWORD end = GetTickCount();
emuTotalElapsed += end - emuFrameStart;
if(emuTotalElapsed >= 1000)
{
printf("\r%iHz ", emuTimesCalled);
emuTimesCalled = 0;
emuTotalElapsed = 0;
}
emuFrameStart = end;
#endif
glutPostRedisplay();
if(ppuDebugPauseFrame)
nesPause = true;
printf("\r%iHz ", emuTimesCalled);
emuTimesCalled = 0;
emuTotalElapsed = 0;
}
else if(!gbsTimerMode)
emuFrameStart = end;
#endif
glutPostRedisplay();
//send VSync to GBS Player if required
if(gbEmuGBSPlayback && !gbsTimerMode)
cpuPlayGBS();
}
mainClock++;
@ -399,70 +434,71 @@ static void gbEmuHandleKeyDown(unsigned char key, int x, int y)
printf("pause\n");
#endif
inPause = true;
nesPause ^= true;
gbPause ^= true;
glutSetWindowTitle(gbPause ? window_title_pause : window_title);
}
break;
case '1':
if(!inResize)
{
inResize = true;
glutReshapeWindow(VISIBLE_DOTS*1, VISIBLE_LINES*1);
glutReshapeWindow(VISIBLE_DOTS*1, linesToDraw*1);
}
break;
case '2':
if(!inResize)
{
inResize = true;
glutReshapeWindow(VISIBLE_DOTS*2, VISIBLE_LINES*2);
glutReshapeWindow(VISIBLE_DOTS*2, linesToDraw*2);
}
break;
case '3':
if(!inResize)
{
inResize = true;
glutReshapeWindow(VISIBLE_DOTS*3, VISIBLE_LINES*3);
glutReshapeWindow(VISIBLE_DOTS*3, linesToDraw*3);
}
break;
case '4':
if(!inResize)
{
inResize = true;
glutReshapeWindow(VISIBLE_DOTS*4, VISIBLE_LINES*4);
glutReshapeWindow(VISIBLE_DOTS*4, linesToDraw*4);
}
break;
case '5':
if(!inResize)
{
inResize = true;
glutReshapeWindow(VISIBLE_DOTS*5, VISIBLE_LINES*5);
glutReshapeWindow(VISIBLE_DOTS*5, linesToDraw*5);
}
break;
case '6':
if(!inResize)
{
inResize = true;
glutReshapeWindow(VISIBLE_DOTS*6, VISIBLE_LINES*6);
glutReshapeWindow(VISIBLE_DOTS*6, linesToDraw*6);
}
break;
case '7':
if(!inResize)
{
inResize = true;
glutReshapeWindow(VISIBLE_DOTS*7, VISIBLE_LINES*7);
glutReshapeWindow(VISIBLE_DOTS*7, linesToDraw*7);
}
break;
case '8':
if(!inResize)
{
inResize = true;
glutReshapeWindow(VISIBLE_DOTS*8, VISIBLE_LINES*8);
glutReshapeWindow(VISIBLE_DOTS*8, linesToDraw*8);
}
break;
case '9':
if(!inResize)
{
inResize = true;
glutReshapeWindow(VISIBLE_DOTS*9, VISIBLE_LINES*9);
glutReshapeWindow(VISIBLE_DOTS*9, linesToDraw*9);
}
break;
default:
@ -606,7 +642,7 @@ static void gbEmuDisplayFrame()
emuRenderFrame = false;
return;
}
glTexImage2D(GL_TEXTURE_2D, 0, 4, VISIBLE_DOTS, VISIBLE_LINES, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, textureImage);
glTexImage2D(GL_TEXTURE_2D, 0, 4, VISIBLE_DOTS, linesToDraw, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, textureImage);
emuRenderFrame = false;
}
@ -618,10 +654,10 @@ static void gbEmuDisplayFrame()
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
double upscaleVal = round((((double)glutGet(GLUT_WINDOW_HEIGHT))/((double)VISIBLE_LINES))*20.0)/20.0;
double upscaleVal = round((((double)glutGet(GLUT_WINDOW_HEIGHT))/((double)linesToDraw))*20.0)/20.0;
double windowMiddle = ((double)glutGet(GLUT_WINDOW_WIDTH))/2.0;
double drawMiddle = (((double)VISIBLE_DOTS)*upscaleVal)/2.0;
double drawHeight = ((double)VISIBLE_LINES)*upscaleVal;
double drawHeight = ((double)linesToDraw)*upscaleVal;
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex2f(windowMiddle-drawMiddle,drawHeight);

2
mbc.c
View File

@ -96,7 +96,7 @@ void mbcInit(uint8_t type)
{
mbcGetRAM8 = mbc2GetExtRAM8;
mbcSetRAM8 = mbc2SetExtRAM8;
printf("MBC Set Special MBC2 RAM Functions\n");
printf("MBC: Set Special MBC2 RAM Functions\n");
}
else if(extTotalSize < 0x2000)
{

47
mem.c
View File

@ -48,7 +48,7 @@ static bool timerRegEnable = false;
static bool emuSaveEnabled = false;
//from main.c
extern bool allowCgbRegs;
extern bool gbCgbMode;
extern uint8_t *emuGBROM;
//from mbc.c
@ -390,7 +390,7 @@ bool memInit(bool romcheck, bool gbs)
memLoadSave();
break;
default:
printf("Mem: Unsupported Type %02x!\n", emuGBROM[0x147]);
printf("Mem Error: Unsupported MBC Type %02x!\n", emuGBROM[0x147]);
return false;
}
}
@ -444,8 +444,8 @@ bool memInit(bool romcheck, bool gbs)
}
else if(addr < 0xA000) //PPU VRAM
{
memGet8ptr[addr] = allowCgbRegs?ppuGetVRAMBank8:ppuGetVRAMNoBank8;
memSet8ptr[addr] = allowCgbRegs?ppuSetVRAMBank8:ppuSetVRAMNoBank8;
memGet8ptr[addr] = gbCgbMode?ppuGetVRAMBank8:ppuGetVRAMNoBank8;
memSet8ptr[addr] = gbCgbMode?ppuSetVRAMBank8:ppuSetVRAMNoBank8;
}
else if(addr < 0xC000) //Cardridge RAM
{
@ -459,8 +459,8 @@ bool memInit(bool romcheck, bool gbs)
}
else if(addr < 0xE000) //Main RAM (possibly banked)
{
memGet8ptr[addr] = allowCgbRegs?memGetRAMBank8:memGetRAMNoBank8;
memSet8ptr[addr] = allowCgbRegs?memSetRAMBank8:memSetRAMNoBank8;
memGet8ptr[addr] = gbCgbMode?memGetRAMBank8:memGetRAMNoBank8;
memSet8ptr[addr] = gbCgbMode?memSetRAMBank8:memSetRAMNoBank8;
}
else if(addr < 0xF000) //Echo Main RAM
{
@ -469,8 +469,8 @@ bool memInit(bool romcheck, bool gbs)
}
else if(addr < 0xFE00) //Echo Main RAM (possibly banked)
{
memGet8ptr[addr] = allowCgbRegs?memGetRAMBank8:memGetRAMNoBank8;
memSet8ptr[addr] = allowCgbRegs?memSetRAMBank8:memSetRAMNoBank8;
memGet8ptr[addr] = gbCgbMode?memGetRAMBank8:memGetRAMNoBank8;
memSet8ptr[addr] = gbCgbMode?memSetRAMBank8:memSetRAMNoBank8;
}
else if(addr < 0xFEA0) //PPU OAM
{
@ -504,13 +504,13 @@ bool memInit(bool romcheck, bool gbs)
}
else if(addr < 0xFF68) //General CGB Features
{
memGet8ptr[addr] = allowCgbRegs?memGetGeneralReg8:memGetInvalid8;
memSet8ptr[addr] = allowCgbRegs?memSetGeneralReg8:memSetInvalid8;
memGet8ptr[addr] = gbCgbMode?memGetGeneralReg8:memGetInvalid8;
memSet8ptr[addr] = gbCgbMode?memSetGeneralReg8:memSetInvalid8;
}
else if(addr < 0xFF6C) //PPU CGB Regs
{
memGet8ptr[addr] = allowCgbRegs?ppuGetReg8:memGetInvalid8;
memSet8ptr[addr] = allowCgbRegs?ppuSetReg8:memSetInvalid8;
memGet8ptr[addr] = gbCgbMode?ppuGetReg8:memGetInvalid8;
memSet8ptr[addr] = gbCgbMode?ppuSetReg8:memSetInvalid8;
}
else if(addr < 0xFF80) //General CGB Features
{
@ -528,7 +528,7 @@ bool memInit(bool romcheck, bool gbs)
memSet8ptr[addr] = memSetGeneralReg8;
}
else //Should never happen
printf("MEM WARNING: Address %04x uninitialized!\n", addr);
printf("Mem Warning: Address %04x uninitialized!\n", addr);
}
return true;
}
@ -536,7 +536,8 @@ bool memInit(bool romcheck, bool gbs)
void memStartGBS()
{
curGBS = 1;
printf("Track %i/%i ", curGBS, gbsTracksTotal);
//printf("Track %i/%i ", curGBS, gbsTracksTotal);
ppuDrawGBSTrackNum(curGBS, gbsTracksTotal);
cpuLoadGBS(curGBS-1);
}
@ -630,15 +631,15 @@ static uint8_t memGetGeneralReg8(uint16_t addr)
case 0x56:
return irReq|0x3C;
case 0x6C:
return (!(allowCgbRegs))|0xFE;
return (!(gbCgbMode))|0xFE;
case 0x70:
return (allowCgbRegs)?(cgbMainBank|0xF8):0xFF;
return (gbCgbMode)?(cgbMainBank|0xF8):0xFF;
case 0x72:
return genericReg[0];
case 0x73:
return genericReg[1];
case 0x74:
return (allowCgbRegs)?genericReg[2]:0xFF;
return (gbCgbMode)?genericReg[2]:0xFF;
case 0x75:
return genericReg[3]|0x8F;
case 0x76:
@ -748,7 +749,7 @@ static void memSetGeneralReg8(uint16_t addr, uint8_t val)
case 0x56:
irReq = val;
case 0x70:
if(allowCgbRegs)
if(gbCgbMode)
{
cgbMainBank = (val&7);
if(cgbMainBank == 0)
@ -762,7 +763,7 @@ static void memSetGeneralReg8(uint16_t addr, uint8_t val)
genericReg[1] = val;
break;
case 0x74:
if(allowCgbRegs)
if(gbCgbMode)
genericReg[2] = val;
break;
case 0x75:
@ -790,7 +791,7 @@ void memDumpMainMem()
FILE *f = fopen("MainMem.bin","wb");
if(f)
{
fwrite(Main_Mem,1,allowCgbRegs?0x8000:0x2000,f);
fwrite(Main_Mem,1,gbCgbMode?0x8000:0x2000,f);
fclose(f);
}
f = fopen("HighMem.bin","wb");
@ -860,7 +861,8 @@ void memClockTimers()
curGBS++;
if(curGBS > gbsTracksTotal)
curGBS = 1;
printf("\rTrack %i/%i ", curGBS, gbsTracksTotal);
//printf("\rTrack %i/%i ", curGBS, gbsTracksTotal);
ppuDrawGBSTrackNum(curGBS, gbsTracksTotal);
cpuLoadGBS(curGBS-1);
}
else if(!inValReads[BUTTON_RIGHT])
@ -872,7 +874,8 @@ void memClockTimers()
curGBS--;
if(curGBS < 1)
curGBS = gbsTracksTotal;
printf("\rTrack %i/%i ", curGBS, gbsTracksTotal);
//printf("\rTrack %i/%i ", curGBS, gbsTracksTotal);
ppuDrawGBSTrackNum(curGBS, gbsTracksTotal);
cpuLoadGBS(curGBS-1);
}
else if(!inValReads[BUTTON_LEFT])

112
ppu.c
View File

@ -46,8 +46,8 @@ typedef void (*drawFunc)(size_t);
static drawFunc ppuDrawDot = NULL;
//from main.c
extern uint32_t textureImage[0x9A00];
extern bool allowCgbRegs;
extern uint32_t textureImage[0x5A00];
extern bool gbCgbMode;
//used externally
uint8_t ppuCgbBank = 0;
@ -92,7 +92,7 @@ static const uint8_t defaultCGBObjPal[0x40] = {
void ppuInit()
{
//Set start line
if(allowCgbRegs)
if(gbCgbMode)
{
ppuClock = 170;
ppuMode = 1;
@ -117,7 +117,7 @@ void ppuInit()
ppuHBlank = false;
ppuHBlankTriggered = false;
//set draw method depending on DMG or CGB Mode
ppuDrawDot = allowCgbRegs?ppuDrawDotCGB:ppuDrawDotDMG;
ppuDrawDot = gbCgbMode?ppuDrawDotCGB:ppuDrawDotDMG;
//init buffers
memset(PPU_Reg,0,12);
memset(PPU_OAM,0,0xA0);
@ -159,12 +159,12 @@ void ppuInit()
}
extern bool gbEmuGBSPlayback;
bool ppuCycle()
void ppuCycle()
{
if(gbEmuGBSPlayback)
goto ppuIncreasePos;
if(!(PPU_Reg[0] & PPU_ENABLE))
return true;
return;
//Update line match stat
ppuLineMatch = ((PPU_Reg[4] == PPU_Reg[5]) ? PPU_LINEMATCH : 0);
//check for line IRQ on first clock
@ -223,6 +223,7 @@ bool ppuCycle()
{
//makes it possible to draw 160x144 in here :)
size_t drawPos = (ppuDots)+(ppuLines*160);
//heavy cpu load from this
ppuDrawDot(drawPos);
ppuDots++;
}
@ -286,7 +287,7 @@ ppuIncreasePos:
//copy our line val into public reg
PPU_Reg[4] = ppuLines;
}
return true;
return;
}
bool ppuDrawDone()
@ -439,7 +440,7 @@ void ppuDumpMem()
FILE *f = fopen("PPU_VRAM.bin","wb");
if(f)
{
fwrite(PPU_VRAM,1,allowCgbRegs?0x4000:0x2000,f);
fwrite(PPU_VRAM,1,gbCgbMode?0x4000:0x2000,f);
fclose(f);
}
f = fopen("PPU_OAM.bin","wb");
@ -791,3 +792,98 @@ static void ppuDrawDotCGB(size_t drawPos)
//copy color value from BGR32 LUT
textureImage[drawPos] = PPU_CGB_BGRLUT[cgbRGB&0x7FFF];
}
//64x12 1BPP "Track"
static const uint8_t ppuGBSTextTrack[96] =
{
0x0C, 0x1C, 0x03, 0xD8, 0x7C, 0x71, 0xC0, 0x00, 0x0C, 0x1C, 0x07, 0xF8, 0xFE, 0x73, 0x80, 0x00,
0x0C, 0x1C, 0x06, 0x39, 0xE2, 0x77, 0x00, 0x00, 0x0C, 0x1C, 0x07, 0x39, 0xC0, 0x7E, 0x00, 0x00,
0x0C, 0x1C, 0x07, 0xF9, 0xC0, 0x7C, 0x00, 0x00, 0x0C, 0x1C, 0x01, 0xF9, 0xC0, 0x7C, 0x00, 0x00,
0x0C, 0x1E, 0x60, 0x38, 0xE2, 0x7E, 0x00, 0x00, 0x0C, 0x1F, 0xE3, 0xF8, 0xFE, 0x77, 0x00, 0x00,
0x0C, 0x1D, 0xC3, 0xF0, 0x3C, 0x73, 0xC0, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
0xFF, 0xC0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
};
//128x12 1BPP "0123456789/"
static const uint8_t ppuGbsTextRest[192] =
{
0x0E, 0x1F, 0xF7, 0xF8, 0xF8, 0x03, 0x9F, 0x01, 0xF0, 0x60, 0x1F, 0x0F, 0x83, 0x00, 0x00, 0x00,
0x3F, 0x9F, 0xF7, 0xF9, 0xFC, 0x03, 0x9F, 0xC3, 0xF8, 0x70, 0x3F, 0x8F, 0xC3, 0x00, 0x00, 0x00,
0x3B, 0x83, 0x83, 0x80, 0x0E, 0x7F, 0xC1, 0xE7, 0x1C, 0x70, 0x71, 0xC0, 0xE1, 0x80, 0x00, 0x00,
0x71, 0xC3, 0x81, 0xC0, 0x0E, 0x7F, 0xC0, 0xE7, 0x1C, 0x30, 0x71, 0xC0, 0x71, 0x80, 0x00, 0x00,
0x79, 0xC3, 0x80, 0xE0, 0x0E, 0x63, 0x80, 0xE7, 0x1C, 0x38, 0x71, 0xC7, 0x70, 0xC0, 0x00, 0x00,
0x7D, 0xC3, 0x80, 0x70, 0x7E, 0x33, 0x81, 0xE7, 0x1C, 0x18, 0x3F, 0x8F, 0xF0, 0xC0, 0x00, 0x00,
0x77, 0xC3, 0x80, 0x70, 0x7C, 0x13, 0x9F, 0xC7, 0xF8, 0x1C, 0x1F, 0x1C, 0x70, 0x60, 0x00, 0x00,
0x73, 0xC3, 0x80, 0x38, 0x0E, 0x1B, 0x9F, 0x87, 0x70, 0x1C, 0x31, 0x9C, 0x70, 0x60, 0x00, 0x00,
0x71, 0xC3, 0x80, 0x38, 0x0E, 0x0B, 0x9C, 0x07, 0x00, 0x0C, 0x71, 0xDC, 0x70, 0x30, 0x00, 0x00,
0x3B, 0x9F, 0x80, 0x38, 0x0E, 0x0F, 0x9C, 0x03, 0x80, 0x0E, 0x71, 0xDC, 0x70, 0x30, 0x00, 0x00,
0x3F, 0x8F, 0x83, 0xF1, 0xFC, 0x07, 0x9F, 0xC1, 0xF9, 0xFE, 0x3F, 0x8F, 0xE0, 0x18, 0x00, 0x00,
0x0E, 0x03, 0x81, 0xE0, 0xF8, 0x03, 0x9F, 0xC0, 0xF9, 0xFE, 0x1F, 0x07, 0xC0, 0x18, 0x00, 0x00,
};
static void ppuDrawRest(uint8_t curX, uint8_t sym)
{
uint8_t i, j;
for(i = 0; i < 12; i++)
{
for(j = 0; j < 10; j++)
{
size_t drawPos = (j+curX)+((i+4)*160);
uint8_t xSel = (j+(sym*10));
if(ppuGbsTextRest[((11-i)<<4)+(xSel>>3)]&(0x80>>(xSel&7)))
textureImage[drawPos] = 0xFFFFFFFF; //White
else
textureImage[drawPos] = 0xFF000000; //Black
}
}
}
void ppuDrawGBSTrackNum(uint8_t cTrack, uint8_t trackTotal)
{
memset(textureImage,0,0x16800);
uint8_t curX = 4;
//draw "Track"
uint8_t i, j;
for(i = 0; i < 12; i++)
{
for(j = 0; j < 50; j++)
{
size_t drawPos = (j+curX)+((i+4)*160);
if(ppuGBSTextTrack[((11-i)<<3)+(j>>3)]&(0x80>>(j&7)))
textureImage[drawPos] = 0xFFFFFFFF; //White
else
textureImage[drawPos] = 0xFF000000; //Black
}
}
//"Track" len+space
curX+=60;
//draw current num
if(cTrack > 99)
{
ppuDrawRest(curX, (cTrack/100)%10);
curX+=10;
}
if(cTrack > 9)
{
ppuDrawRest(curX, (cTrack/10)%10);
curX+=10;
}
ppuDrawRest(curX, cTrack%10);
curX+=10;
//draw the "/"
ppuDrawRest(curX, 10);
curX+=10;
//draw total num
if(trackTotal > 99)
{
ppuDrawRest(curX, (trackTotal/100)%10);
curX+=10;
}
if(trackTotal > 9)
{
ppuDrawRest(curX, (trackTotal/10)%10);
curX+=10;
}
ppuDrawRest(curX, trackTotal%10);
curX+=10;
}

3
ppu.h
View File

@ -9,7 +9,7 @@
#define _ppu_h_
void ppuInit();
bool ppuCycle();
void ppuCycle();
bool ppuDrawDone();
uint8_t ppuGetVRAMBank8(uint16_t addr);
uint8_t ppuGetVRAMNoBank8(uint16_t addr);
@ -22,5 +22,6 @@ void ppuSetReg8(uint16_t addr, uint8_t val);
bool ppuInVBlank();
bool ppuInHBlank();
void ppuDumpMem();
void ppuDrawGBSTrackNum(uint8_t cTrack, uint8_t trackTotal);
#endif