mirror of https://github.com/stella-emu/stella.git
commit
ee1fdfa565
|
@ -21,6 +21,7 @@
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
#include "Thumbulator.hxx"
|
#include "Thumbulator.hxx"
|
||||||
#include "CartDPCPlus.hxx"
|
#include "CartDPCPlus.hxx"
|
||||||
|
#include "TIA.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
||||||
|
@ -31,6 +32,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
||||||
myParameterPointer(0),
|
myParameterPointer(0),
|
||||||
mySystemCycles(0),
|
mySystemCycles(0),
|
||||||
myFractionalClocks(0.0),
|
myFractionalClocks(0.0),
|
||||||
|
myARMCycles(0),
|
||||||
myCurrentBank(0)
|
myCurrentBank(0)
|
||||||
{
|
{
|
||||||
// Store image, making sure it's at least 29KB
|
// Store image, making sure it's at least 29KB
|
||||||
|
@ -72,6 +74,7 @@ void CartridgeDPCPlus::reset()
|
||||||
{
|
{
|
||||||
// Update cycles to the current system cycles
|
// Update cycles to the current system cycles
|
||||||
mySystemCycles = mySystem->cycles();
|
mySystemCycles = mySystem->cycles();
|
||||||
|
myARMCycles = mySystem->cycles();
|
||||||
myFractionalClocks = 0.0;
|
myFractionalClocks = 0.0;
|
||||||
|
|
||||||
setInitialState();
|
setInitialState();
|
||||||
|
@ -106,6 +109,7 @@ void CartridgeDPCPlus::systemCyclesReset()
|
||||||
{
|
{
|
||||||
// Adjust the cycle counter so that it reflects the new value
|
// Adjust the cycle counter so that it reflects the new value
|
||||||
mySystemCycles -= mySystem->cycles();
|
mySystemCycles -= mySystem->cycles();
|
||||||
|
myARMCycles -= mySystem->cycles();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -188,7 +192,20 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value)
|
||||||
case 255:
|
case 255:
|
||||||
// Call user written ARM code (most likely be C compiled for ARM)
|
// Call user written ARM code (most likely be C compiled for ARM)
|
||||||
try {
|
try {
|
||||||
myThumbEmulator->run();
|
Int32 cycles = mySystem->cycles() - myARMCycles;
|
||||||
|
myARMCycles = mySystem->cycles();
|
||||||
|
|
||||||
|
// setConsoleTiming should go elsewhere for one-time-setup, but doesn't
|
||||||
|
// work in install()
|
||||||
|
//
|
||||||
|
// if put in setInitialState() Stella ends up crashing in System.hxx at
|
||||||
|
// TIA& tia() const { return myTIA; }
|
||||||
|
// with error
|
||||||
|
// "Thread 1: EXC_BAD_ACCESS (code=1, address=0x20)"
|
||||||
|
|
||||||
|
myThumbEmulator->setConsoleTiming(mySystem->tia().consoleTiming());
|
||||||
|
|
||||||
|
myThumbEmulator->run(cycles);
|
||||||
}
|
}
|
||||||
catch(const runtime_error& e) {
|
catch(const runtime_error& e) {
|
||||||
if(!mySystem->autodetectMode())
|
if(!mySystem->autodetectMode())
|
||||||
|
@ -680,8 +697,12 @@ bool CartridgeDPCPlus::save(Serializer& out) const
|
||||||
// The random number generator register
|
// The random number generator register
|
||||||
out.putInt(myRandomNumber);
|
out.putInt(myRandomNumber);
|
||||||
|
|
||||||
|
// Get system cycles and fractional clocks
|
||||||
out.putInt(mySystemCycles);
|
out.putInt(mySystemCycles);
|
||||||
out.putInt(uInt32(myFractionalClocks * 100000000.0));
|
out.putInt(uInt32(myFractionalClocks * 100000000.0));
|
||||||
|
|
||||||
|
// clock info for Thumbulator
|
||||||
|
out.putInt(myARMCycles);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -743,6 +764,9 @@ bool CartridgeDPCPlus::load(Serializer& in)
|
||||||
// Get system cycles and fractional clocks
|
// Get system cycles and fractional clocks
|
||||||
mySystemCycles = in.getInt();
|
mySystemCycles = in.getInt();
|
||||||
myFractionalClocks = double(in.getInt()) / 100000000.0;
|
myFractionalClocks = double(in.getInt()) / 100000000.0;
|
||||||
|
|
||||||
|
// clock info for Thumbulator
|
||||||
|
myARMCycles = (Int32)in.getInt();
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -259,6 +259,9 @@ class CartridgeDPCPlus : public Cartridge
|
||||||
|
|
||||||
// Fractional DPC music OSC clocks unused during the last update
|
// Fractional DPC music OSC clocks unused during the last update
|
||||||
double myFractionalClocks;
|
double myFractionalClocks;
|
||||||
|
|
||||||
|
// System cycle count when the last Thumbulator->Run() occurred
|
||||||
|
Int32 myARMCycles;
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates which bank is currently active
|
||||||
uInt16 myCurrentBank;
|
uInt16 myCurrentBank;
|
||||||
|
|
|
@ -56,8 +56,11 @@ using Common::Base;
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, bool traponfatal)
|
Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, bool traponfatal)
|
||||||
: rom(rom_ptr),
|
: rom(rom_ptr),
|
||||||
ram(ram_ptr)
|
ram(ram_ptr),
|
||||||
|
T1TCR(0),
|
||||||
|
T1TC(0)
|
||||||
{
|
{
|
||||||
|
setConsoleTiming(ConsoleTiming::ntsc);
|
||||||
trapFatalErrors(traponfatal);
|
trapFatalErrors(traponfatal);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
@ -79,6 +82,43 @@ string Thumbulator::run()
|
||||||
return statusMsg.str();
|
return statusMsg.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Thumbulator::setConsoleTiming(ConsoleTiming timing)
|
||||||
|
{
|
||||||
|
// this sets how many ticks of the Harmony/Melody clock
|
||||||
|
// will occur per tick of the 6507 clock
|
||||||
|
constexpr double NTSC = 70.0 / 1.193182; // NTSC 6507 clock rate
|
||||||
|
constexpr double PAL = 70.0 / 1.182298; // PAL 6507 clock rate
|
||||||
|
constexpr double SECAM = 70.0 / 1.187500; // SECAM 6507 clock rate
|
||||||
|
|
||||||
|
switch (timing)
|
||||||
|
{
|
||||||
|
case ConsoleTiming::ntsc: timing_factor = NTSC; break;
|
||||||
|
case ConsoleTiming::secam: timing_factor = SECAM; break;
|
||||||
|
case ConsoleTiming::pal: timing_factor = PAL; break;
|
||||||
|
default: timing_factor = NTSC; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void Thumbulator::updateTimer(uInt32 cycles)
|
||||||
|
{
|
||||||
|
double increment;
|
||||||
|
|
||||||
|
increment = cycles * timing_factor;
|
||||||
|
|
||||||
|
if (T1TCR & 1) // bit 0 controls timer on/off
|
||||||
|
{
|
||||||
|
|
||||||
|
T1TC += uInt32(increment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
string Thumbulator::run(uInt32 cycles)
|
||||||
|
{
|
||||||
|
updateTimer(cycles);
|
||||||
|
return this->run();
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, const char* msg)
|
inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, const char* msg)
|
||||||
{
|
{
|
||||||
|
@ -235,6 +275,14 @@ void Thumbulator::write32(uInt32 addr, uInt32 data)
|
||||||
case 0xE0000000:
|
case 0xE0000000:
|
||||||
DO_DISS(statusMsg << "uart: [" << char(data&0xFF) << "]" << endl);
|
DO_DISS(statusMsg << "uart: [" << char(data&0xFF) << "]" << endl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0xE0008004: // T1TCR - Timer 1 Control Register
|
||||||
|
T1TCR = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xE0008008: // T1TC - Timer 1 Counter
|
||||||
|
T1TC = data;
|
||||||
|
break;
|
||||||
|
|
||||||
case 0xE000E010:
|
case 0xE000E010:
|
||||||
{
|
{
|
||||||
|
@ -348,6 +396,14 @@ uInt32 Thumbulator::read32(uInt32 addr)
|
||||||
{
|
{
|
||||||
switch(addr)
|
switch(addr)
|
||||||
{
|
{
|
||||||
|
case 0xE0008004: // T1TCR - Timer 1 Control Register
|
||||||
|
data = T1TCR;
|
||||||
|
return data;
|
||||||
|
|
||||||
|
case 0xE0008008: // T1TC - Timer 1 Counter
|
||||||
|
data = T1TC;
|
||||||
|
return data;
|
||||||
|
|
||||||
case 0xE000E010:
|
case 0xE000E010:
|
||||||
data = systick_ctrl;
|
data = systick_ctrl;
|
||||||
systick_ctrl &= (~0x00010000);
|
systick_ctrl &= (~0x00010000);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#define THUMBULATOR_HXX
|
#define THUMBULATOR_HXX
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
#include "Console.hxx"
|
||||||
|
|
||||||
#define ROMADDMASK 0x7FFF
|
#define ROMADDMASK 0x7FFF
|
||||||
#define RAMADDMASK 0x1FFF
|
#define RAMADDMASK 0x1FFF
|
||||||
|
@ -54,6 +55,7 @@ class Thumbulator
|
||||||
otherwise an empty string
|
otherwise an empty string
|
||||||
*/
|
*/
|
||||||
string run();
|
string run();
|
||||||
|
string run(uInt32 cycles);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Normally when a fatal error is encountered, the ARM emulation
|
Normally when a fatal error is encountered, the ARM emulation
|
||||||
|
@ -68,6 +70,8 @@ class Thumbulator
|
||||||
@param enable Enable (the default) or disable exceptions on fatal errors
|
@param enable Enable (the default) or disable exceptions on fatal errors
|
||||||
*/
|
*/
|
||||||
static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
||||||
|
|
||||||
|
void setConsoleTiming(ConsoleTiming timing);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uInt32 read_register(uInt32 reg);
|
uInt32 read_register(uInt32 reg);
|
||||||
|
@ -78,6 +82,7 @@ class Thumbulator
|
||||||
uInt32 read32(uInt32 addr);
|
uInt32 read32(uInt32 addr);
|
||||||
void write16(uInt32 addr, uInt32 data);
|
void write16(uInt32 addr, uInt32 data);
|
||||||
void write32(uInt32 addr, uInt32 data);
|
void write32(uInt32 addr, uInt32 data);
|
||||||
|
void updateTimer(uInt32 cycles);
|
||||||
|
|
||||||
void do_zflag(uInt32 x);
|
void do_zflag(uInt32 x);
|
||||||
void do_nflag(uInt32 x);
|
void do_nflag(uInt32 x);
|
||||||
|
@ -106,6 +111,13 @@ class Thumbulator
|
||||||
bool handler_mode;
|
bool handler_mode;
|
||||||
uInt32 systick_ctrl, systick_reload, systick_count, systick_calibrate;
|
uInt32 systick_ctrl, systick_reload, systick_count, systick_calibrate;
|
||||||
uInt64 instructions, fetches, reads, writes, systick_ints;
|
uInt64 instructions, fetches, reads, writes, systick_ints;
|
||||||
|
|
||||||
|
// For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection.
|
||||||
|
// Register names from documentation:
|
||||||
|
// http://www.nxp.com/documents/user_manual/UM10161.pdf
|
||||||
|
uInt32 T1TCR; // Timer 1 Timer Control Register
|
||||||
|
uInt32 T1TC; // Timer 1 Timer Counter
|
||||||
|
double timing_factor;
|
||||||
|
|
||||||
ostringstream statusMsg;
|
ostringstream statusMsg;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue