A7800DS/arm9/source/emu/ProSystem.c
2025-02-26 10:56:25 -05:00

191 lines
7.4 KiB
C

// ----------------------------------------------------------------------------
// ___ ___ ___ ___ ___ ____ ___ _ _
// /__/ /__/ / / /__ /__/ /__ / /_ / |/ /
// / / \ /__/ ___/ ___/ ___/ / /__ / / emulator
//
// ----------------------------------------------------------------------------
// Copyright 2003, 2004 Greg Stanton
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------------
// ProSystem.cpp
// ----------------------------------------------------------------------------
#include "ProSystem.h"
#include "Database.h"
extern u8 isDS_LITE;
extern u8 frameSkipMask;
uint prosystem_cycles __attribute__((section(".dtcm"))) = 0;
uint32 bg32 __attribute__((section(".dtcm"))) = 0;
uint bRenderFrame __attribute__((section(".dtcm"))) = 0;
#define CYCLES_BEFORE_DMA 28 // Number of cycles before DMA kicks in (really 7 CPU cycles)
#define CYCLES_PER_SCANLINE 454 // 454 Cycles per Scanline in an NTSC system (really 113.5 CPU cycles)
// ----------------------------------------------------------------------------
// Reset
// ----------------------------------------------------------------------------
void prosystem_Reset()
{
if(cartridge_IsLoaded())
{
sally_Reset();
region_Reset();
tia_Clear();
tia_Reset();
pokey_Clear();
pokey_Reset();
memory_Reset();
maria_Clear();
maria_Reset();
riot_Reset();
cartridge_LoadHighScoreCart();
cartridge_Store(); // Always call this - it may setup some RAM or other stuff below the BIOS region...
// Load 7800 BIOS if available... otherwise direct load the CART
if(bios_available && !bSkipBIOS)
{
bios_Store();
bios_show_counter = myCartInfo.biosTimeout;
}
prosystem_cycles = sally_ExecuteRES();
}
}
// ----------------------------------------------------------------------------
// ExecuteFrame - this is hand-tuned for NTSC output with hard-coded
// NTSC frame values ... this will not work properly if a PAL ROM is used.
// ----------------------------------------------------------------------------
ITCM_CODE void prosystem_ExecuteFrame(const byte * input)
{
extern u16 gTotalAtariFrames;
extern word * framePtr;
extern uint maria_cycles;
gTotalAtariFrames++;
bRenderFrame = 0;
riot_SetInput(input);
// ---------------------------------------------------------------------
// Handle the VERTICAL BLANK area first... speeds up processing below...
// ---------------------------------------------------------------------
memory_ram[MSTAT] = 128; // Into the Vertical Blank...
// -------------------------------------------------------------------------------------------
// Note: this is not accurate. It should be 263 scanlines total but it doesn't work for all
// games at 263 so we've gone with 262 for maximum compatibility. This is likely due to some
// emulation cycle counting inaccuracies. At 263, some games run too fast (Asteroids, Deluxe)
// and some crash (Robotron) and some issues with Pole Position II and the joystick selection
// of a course to play. I've also seen graphical glitches in Crossbow when loaded via the
// BIOS and all kinds of graphical oddities in Xenophobe. Be very careful if you change this...
// be sure you understand the consequences (and this developer doesn't... so be warned!).
// -------------------------------------------------------------------------------------------
for(maria_scanline = 1; maria_scanline <= 21; maria_scanline++)
{
prosystem_cycles = 0;
if(maria_scanline == 21) // Maria can start to do her thing... We've had 20 VBLANK scanlines
{
memory_ram[MSTAT] = 0; // Out of the vertical blank
framePtr = (word * )(maria_surface);
sally_Execute(CYCLES_BEFORE_DMA);
maria_RenderScanlineTOP();
// Cycle Stealing happens here...
prosystem_cycles += ((maria_cycles + 3) >> 2) << 2; // Always a multiple of 4
if(riot_and_wsync & 2) riot_UpdateTimer(maria_cycles >> 2);
}
else
{
sally_Execute(CYCLES_BEFORE_DMA);
}
sally_Execute(CYCLES_PER_SCANLINE);
if(myCartInfo.pokeyType) // If pokey enabled, we process 1 pokey sample and 1 TIA sample. Good enough.
{
pokey_Process();
pokey_Scanline();
}
else tia_Process(); // If all we have to deal with is the TIA, we can do so at 31KHz
}
// ------------------------------------------------------------
// Now handle the Main display area...
// ------------------------------------------------------------
for(; maria_scanline < 263; maria_scanline++)
{
prosystem_cycles = 0;
if(maria_scanline >= 30)
{
// --------------------------------------------------------------------------
// We can start to render the scanlines if we are not skipping this frame.
// The DS/DSi only has 192 vertical pixels and we can perform some hardware
// scaling but there is a point at which we really can't show any more lines.
// To that end, we'll render ~223 lines which is good enough for most games.
// If a game uses more overscan area - those scanlines won't show on screen.
// ---------------------------------------------------------------------------
if(maria_scanline >= 253)
{
bRenderFrame = 0; // We can stop rendering frames... DS can't show it anyway with limited vertical resolution.
}
else
{
bRenderFrame = gTotalAtariFrames & frameSkipMask;
}
}
sally_Execute(CYCLES_BEFORE_DMA);
maria_RenderScanline();
// Cycle Stealing happens here...
prosystem_cycles += ((maria_cycles + 3) >> 2) << 2; // Always a multiple of 4
if(riot_and_wsync & 2) riot_UpdateTimer(maria_cycles >> 2);
sally_Execute(CYCLES_PER_SCANLINE);
if(myCartInfo.pokeyType) // If pokey enabled, we process 1 pokey sample and 1 TIA sample. Good enough.
{
pokey_Process();
pokey_Scanline();
}
else tia_Process(); // If all we have to deal with is the TIA, we can do so at 31KHz
}
}
// ----------------------------------------------------------------------------
// Close
// ----------------------------------------------------------------------------
void prosystem_Close()
{
cartridge_Release();
maria_Reset();
maria_Clear();
memory_Reset();
tia_Reset();
tia_Clear();
}