📄 nestreme.cpp
字号:
DWORD dwEndTime = 0; // The ending time of our frame.
DWORD dwTotalTime = 0; // The total time of our frame.
DWORD dwFrames = 0; // The number of frames drawn in a second.
MSG msg; // Message structure.
DWORD dwSoundFrameSkip = OPTIONS_NUM_AUDIOFRAMESKIP;
DWORD dwGfxFrameSkip = OPTIONS_NUM_GFXFRAMESKIP;
char strFrameCount[128] = {0};
// Create the child window for running the program.
hwndRunWnd = CreateWindowEx(WS_EX_MDICHILD,
strRunClassName,
strRunTitleName,
WS_CHILD,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
hwndMDIClient,
NULL,
g_hInstance,
NULL);
if (hwndRunWnd == NULL)
FATAL(hwndMDIClient, "Couldn't Create the run window");
// Create DirectDraw for the window.
CreateDirectDraw(hwndRunWnd);
// Create and initialize DirectSound.
CreateSound(hwndRunWnd);
// Keep running the program until the user has chosen to stop.
while (bRunning == TRUE)
{
// If there is a message for this window, then we need
// to process it. Otherwise, we are free to run then
// NES ROM until the user has chosen to stop. (bRunning == FALSE)
if (PeekMessage(&msg, hwndRunWnd, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
TranslateMessage(&msg);
}
else
{
// If we are back at the beginning of the screen
// then clear the screen to the background color.
if (wScanline == 0)
{
// Start our FPS counter.
dwBeginTime = GetTickCount();
// Initialize the surface to do our drawing.
if (!dwGfxFrameSkip)
{
BeginDrawing();
}
// Draw all the sprites behind the background.
if (!dwGfxFrameSkip)
{
if (Options_bSpritesEnabled)
DrawSprites(SPRITE_BEHIND);
}
}
// Single step the cpu.
RunCPU(RUNCPU_RUN);
// Do all the cyclic tasks.
CPU_DoCyclicTasks();
// Draw the scanline if its one of the scanlines on the screen.
// i.e Don't draw the scanlines in VBlank.
if (!dwGfxFrameSkip)
{
if ((wScanline < 240) && (CPU.Memory[0x2001] & 0x08) && Options_bBackgroundEnabled)
DrawScanline();
}
// Flip the surfaces if we are done drawing the frame.
if (wScanline == NUM_SCANLINES_SCREEN)
{
// Draw all the sprites in front of the background.
if (!dwGfxFrameSkip)
{
if (Options_bSpritesEnabled)
DrawSprites(SPRITE_INFRONT);
}
// Output the number of frames per second.
OutputText(strFrameCount, 0, 0, RGB(255, 255, 255), 0);
// Now that everything has been drawn.
if (!dwGfxFrameSkip)
{
EndDrawing();
}
// Update our sound for the frame.
if (!dwSoundFrameSkip)
APU_DoFrame();
if ((dwSoundFrameSkip--) == 0)
dwSoundFrameSkip = OPTIONS_NUM_AUDIOFRAMESKIP;
if ((dwGfxFrameSkip--) == 0)
dwGfxFrameSkip = OPTIONS_NUM_GFXFRAMESKIP;
}
else if (wScanline == (NUM_SCANLINES_VBLANK+NUM_SCANLINES_SCREEN-1))
{
// Wait so we only go 60 FPS.
//DWORD dwTemp = GetTickCount();
//if ((dwTemp - dwBeginTime) < 16)
// Wait(16 - (dwTemp - dwBeginTime));
// Calculate the FPS.
dwFrames++;
dwEndTime = GetTickCount();
dwTotalTime += dwEndTime - dwBeginTime;
// Display the FPS every 1 second.
if (dwTotalTime >= 1000)
{
sprintf(strFrameCount, "Fps = %d", dwFrames);
dwFrames = 0;
dwTotalTime = 0;
}
}
}
}
// Clean up DirectDraw, DirectSound and destroy the window.
DestroyDirectDraw();
DestroySound();
DestroyWindow(hwndRunWnd);
return 0;
} // end CPU_Run()
//------------------------------------------------------------------------------
// Name: CPU_RunUntilBreak()
// Desc: Runs the NES in debug mode until a breakpoint is encountered or
// the user selects the break command.
//------------------------------------------------------------------------------
DWORD WINAPI CPU_RunUntilBreak(LPVOID lpParam)
{
// As long as the user hasn't pressed break or we havn't
// encountered a breakpoint, keep executing.
while (bBreak == FALSE)
{
// Single step the cpu.
RunCPU(RUNCPU_STEP);
// Do all the cyclic tasks.
CPU_DoCyclicTasks();
// Check for breakpoints and tell the loop to break
// if the PC is at a breakpoint.
for (int i = 0; i < OPTIONS_NUM_BREAKPOINTS; i++)
{
if (CPU.P == awBreakpoints[i])
{
bBreak = TRUE;
break;
}
}
}
// Update all the debugging information and reset the break command.
UpdateDebugInfo();
bBreak = FALSE;
return 0;
} // end CPU_RunUntilBreak()
//------------------------------------------------------------------------------
// Name: CPU_Step()
// Desc: Single steps through instructions in debug mode.
//------------------------------------------------------------------------------
HRESULT CPU_Step()
{
// Single step the cpu.
RunCPU(RUNCPU_STEP);
// Do all the cyclic tasks.
CPU_DoCyclicTasks();
// Update all the debugging information.
UpdateDebugInfo();
return S_OK;
} // end CPU_Step()
//------------------------------------------------------------------------------
// Name: SetListViewText()
// Desc: Sets the text of an item in a list view control.
//------------------------------------------------------------------------------
HRESULT SetListViewText(HWND hwndLV, UINT uRow, UINT uCol, LPSTR strText)
{
LV_ITEM lvI; // List view item structure.
// Fill out the item structure.
lvI.mask = LVIF_TEXT;
lvI.iItem = uRow;
lvI.iSubItem = uCol;
lvI.pszText = strText;
lvI.state = 0;
lvI.stateMask = 0;
// Set the text of the item
if (ListView_SetItem(hwndLV, &lvI) == FALSE)
return ERROR;
return S_OK;
} // end SetListViewText()
//------------------------------------------------------------------------------
// Name: ToggleBreakpoint()
// Desc: Turns a breakpoint on or off.
//------------------------------------------------------------------------------
HRESULT ToggleBreakpoint(UINT uItem)
{
char strPC[5]; // Text to hold the PC address of the item.
char strAddress[5]; // Text to hold the address of the breakpoint.
// Get the address that the user has selected to add a breakpoint.
ListView_GetItemText(hwndCodeLV, uItem, 0, strPC, 5);
// Loop through and see if a breakpoint is already added on this line.
for (int i = 0; i < OPTIONS_NUM_BREAKPOINTS; i++)
{
// Convert the breakpoint address to a string.
sprintf(strAddress, "%04X", awBreakpoints[i]);
// If the breakpoint is already on this line, then we
// need to disable it.
if (strcmp(strAddress, strPC) == 0)
return DisableBreakpoint(i, uItem);
}
// If the breakpoint does not exist on this line,
// then we must add a breakpoint.
return AddBreakpoint((WORD)strtoul(strPC, NULL, 16), uItem);
} // end ToggleBreakpoint()
//------------------------------------------------------------------------------
// Name: UpdateInstrCursorPos()
// Desc: Places the selection marker of the code list view on the
// current instruction.
//------------------------------------------------------------------------------
HRESULT UpdateInstrCursorPos()
{
LVFINDINFO lvfi; // List view find item info.
DWORD dwItem; // Current item to be selected.
char strPC[10]; // String of the PC's value.
// Convert the PC's value to a hexadecimal string
sprintf(strPC, "%04X:", CPU.P);
// Initialize the structure to find our PC string.
lvfi.flags = LVFI_STRING;
lvfi.psz = strPC;
// Find the item in the list view.
dwItem = ListView_FindItem(hwndCodeLV, -1, &lvfi);
// If the item is not found then we need to dissassemble the rom
// again because the program counter is out of range, then select
// the first instruction.
if (dwItem == -1)
{
DissassembleROM();
dwItem = 0;
}
// Select the item.
SetFocus(hwndCodeLV);
ListView_SetItemState(hwndCodeLV, dwItem, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
return S_OK;
} // end UpdateInstrCursorPos()
//------------------------------------------------------------------------------
// Name: UpdateDebugInfo()
// Desc: Updates all the debugging information in the Registers List View.
//------------------------------------------------------------------------------
HRESULT UpdateDebugInfo()
{
// Update all the registers.
UpdateRegisters();
// Select the current instruction line.
UpdateInstrCursorPos();
return S_OK;
} // end UpdateDebugInfo()
//------------------------------------------------------------------------------
// Name: UpdateRegisters()
// Desc: Updates all the register values in the register list view.
//------------------------------------------------------------------------------
HRESULT UpdateRegisters()
{
char strText[128]; // Text to hold the info to be added.
// Update the A register.
UPDATE_VAR_IN_REG_LISTVIEW(0, "A", CPU.A);
// Update the X register.
UPDATE_VAR_IN_REG_LISTVIEW(1, "X", CPU.X);
// Update the Y register.
UPDATE_VAR_IN_REG_LISTVIEW(2, "Y", CPU.Y);
// Update the SP register.
UPDATE_VAR_IN_REG_LISTVIEW(3, "SP", CPU.S);
// Update the PC register.
UPDATE_VAR_IN_REG_LISTVIEW(4, "PC", CPU.P);
// Update the flags register.
sprintf(strText, "Flags");
SetListViewText(hwndRegsLV, 5, 0, strText);
sprintf(&strText[0], "%c", (CPU.F & 0x80) ? 'S' : 's');
sprintf(&strText[1], "%c", (CPU.F & 0x40) ? 'V' : 'v');
sprintf(&strText[2], "%c", ' ');
sprintf(&strText[3], "%c", (CPU.F & 0x10) ? 'B' : 'b');
sprintf(&strText[4], "%c", (CPU.F & 0x08) ? 'D' : 'd');
sprintf(&strText[5], "%c", (CPU.F & 0x04) ? 'I' : 'i');
sprintf(&strText[6], "%c", (CPU.F & 0x02) ? 'Z' : 'z');
sprintf(&strText[7], "%c", (CPU.F & 0x01) ? 'C' : 'c');
SetListViewText(hwndRegsLV, 5, 1, strText);
// Update the Nintendo registers.
UPDATE_VAR_IN_REG_LISTVIEW(7, "$2000", CPU.Memory[0x2000]);
UPDATE_VAR_IN_REG_LISTVIEW(8, "$2001", CPU.Memory[0x2001]);
UPDATE_VAR_IN_REG_LISTVIEW(9, "$2002", CPU.Memory[0x2002]);
UPDATE_VAR_IN_REG_LISTVIEW(10, "$2003", CPU.Memory[0x2003]);
UPDATE_VAR_IN_REG_LISTVIEW(11, "$2004", CPU.Memory[0x2004]);
UPDATE_VAR_IN_REG_LISTVIEW(12, "$2005", CPU.Memory[0x2005]);
UPDATE_VAR_IN_REG_LISTVIEW(13, "$2006", CPU.Memory[0x2006]);
UPDATE_VAR_IN_REG_LISTVIEW(14, "$2007", CPU.Memory[0x2007]);
UPDATE_VAR_IN_REG_LISTVIEW(15, "$4000", CPU.Memory[0x4000]);
UPDATE_VAR_IN_REG_LISTVIEW(16, "$4001", CPU.Memory[0x4001]);
UPDATE_VAR_IN_REG_LISTVIEW(17, "$4002", CPU.Memory[0x4002]);
UPDATE_VAR_IN_REG_LISTVIEW(18, "$4003", CPU.Memory[0x4003]);
UPDATE_VAR_IN_REG_LISTVIEW(19, "$4004", CPU.Memory[0x4004]);
UPDATE_VAR_IN_REG_LISTVIEW(20, "$4005", CPU.Memory[0x4005]);
UPDATE_VAR_IN_REG_LISTVIEW(21, "$4006", CPU.Memory[0x4006]);
UPDATE_VAR_IN_REG_LISTVIEW(22, "$4007", CPU.Memory[0x4007]);
UPDATE_VAR_IN_REG_LISTVIEW(23, "$4008", CPU.Memory[0x4008]);
UPDATE_VAR_IN_REG_LISTVIEW(24, "$4009", CPU.Memory[0x4009]);
UPDATE_VAR_IN_REG_LISTVIEW(25, "$4010", CPU.Memory[0x4010]);
UPDATE_VAR_IN_REG_LISTVIEW(26, "$4011", CPU.Memory[0x4011]);
UPDATE_VAR_IN_REG_LISTVIEW(27, "$4012", CPU.Memory[0x4012]);
UPDATE_VAR_IN_REG_LISTVIEW(28, "$4013", CPU.Memory[0x4013]);
UPDATE_VAR_IN_REG_LISTVIEW(29, "$4014", CPU.Memory[0x4014]);
UPDATE_VAR_IN_REG_LISTVIEW(30, "$4015", CPU.Memory[0x4015]);
UPDATE_VAR_IN_REG_LISTVIEW(31, "$4016", CPU.Memory[0x4016]);
UPDATE_VAR_IN_REG_LISTVIEW(32, "$4017", CPU.Memory[0x4017]);
// Update the number of cpu cycles.
sprintf(strText, "Cycles");
SetListViewText(hwndRegsLV, 34, 0, strText);
sprintf(strText, "%d", CPU.byCycles);
SetListViewText(hwndRegsLV, 34, 1, strText);
// Update the scanline number.
sprintf(strText, "Scanline");
SetListViewText(hwndRegsLV, 35, 0, strText);
sprintf(strText, "%d", wScanline);
SetListViewText(hwndRegsLV, 35, 1, strText);
// Update the VRAM Address.
UPDATE_VAR_IN_REG_LISTVIEW(36, "VRAM Address", wVRAMAddress);
return S_OK;
} // end UpdateRegisters()
//------------------------------------------------------------------------------
// Name: Wait()
// Desc: Waits the number of milliseconds passed into the function.
//------------------------------------------------------------------------------
__inline VOID Wait(DWORD dwTime)
{
DWORD dwBegin = GetTickCount();
while ((GetTickCount() - dwBegin) <= dwTime);
} // end Wait()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -