mirror of https://github.com/stella-emu/stella.git
commit
ee1fdfa565
|
@ -21,6 +21,7 @@
|
|||
#include "System.hxx"
|
||||
#include "Thumbulator.hxx"
|
||||
#include "CartDPCPlus.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
||||
|
@ -31,6 +32,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
|||
myParameterPointer(0),
|
||||
mySystemCycles(0),
|
||||
myFractionalClocks(0.0),
|
||||
myARMCycles(0),
|
||||
myCurrentBank(0)
|
||||
{
|
||||
// Store image, making sure it's at least 29KB
|
||||
|
@ -72,6 +74,7 @@ void CartridgeDPCPlus::reset()
|
|||
{
|
||||
// Update cycles to the current system cycles
|
||||
mySystemCycles = mySystem->cycles();
|
||||
myARMCycles = mySystem->cycles();
|
||||
myFractionalClocks = 0.0;
|
||||
|
||||
setInitialState();
|
||||
|
@ -106,6 +109,7 @@ void CartridgeDPCPlus::systemCyclesReset()
|
|||
{
|
||||
// Adjust the cycle counter so that it reflects the new value
|
||||
mySystemCycles -= mySystem->cycles();
|
||||
myARMCycles -= mySystem->cycles();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -188,7 +192,20 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value)
|
|||
case 255:
|
||||
// Call user written ARM code (most likely be C compiled for ARM)
|
||||
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) {
|
||||
if(!mySystem->autodetectMode())
|
||||
|
@ -680,8 +697,12 @@ bool CartridgeDPCPlus::save(Serializer& out) const
|
|||
// The random number generator register
|
||||
out.putInt(myRandomNumber);
|
||||
|
||||
// Get system cycles and fractional clocks
|
||||
out.putInt(mySystemCycles);
|
||||
out.putInt(uInt32(myFractionalClocks * 100000000.0));
|
||||
|
||||
// clock info for Thumbulator
|
||||
out.putInt(myARMCycles);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
@ -743,6 +764,9 @@ bool CartridgeDPCPlus::load(Serializer& in)
|
|||
// Get system cycles and fractional clocks
|
||||
mySystemCycles = in.getInt();
|
||||
myFractionalClocks = double(in.getInt()) / 100000000.0;
|
||||
|
||||
// clock info for Thumbulator
|
||||
myARMCycles = (Int32)in.getInt();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
|
|
@ -260,6 +260,9 @@ class CartridgeDPCPlus : public Cartridge
|
|||
// Fractional DPC music OSC clocks unused during the last update
|
||||
double myFractionalClocks;
|
||||
|
||||
// System cycle count when the last Thumbulator->Run() occurred
|
||||
Int32 myARMCycles;
|
||||
|
||||
// Indicates which bank is currently active
|
||||
uInt16 myCurrentBank;
|
||||
|
||||
|
|
|
@ -56,8 +56,11 @@ using Common::Base;
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, bool traponfatal)
|
||||
: rom(rom_ptr),
|
||||
ram(ram_ptr)
|
||||
ram(ram_ptr),
|
||||
T1TCR(0),
|
||||
T1TC(0)
|
||||
{
|
||||
setConsoleTiming(ConsoleTiming::ntsc);
|
||||
trapFatalErrors(traponfatal);
|
||||
reset();
|
||||
}
|
||||
|
@ -79,6 +82,43 @@ string Thumbulator::run()
|
|||
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)
|
||||
{
|
||||
|
@ -236,6 +276,14 @@ void Thumbulator::write32(uInt32 addr, uInt32 data)
|
|||
DO_DISS(statusMsg << "uart: [" << char(data&0xFF) << "]" << endl);
|
||||
break;
|
||||
|
||||
case 0xE0008004: // T1TCR - Timer 1 Control Register
|
||||
T1TCR = data;
|
||||
break;
|
||||
|
||||
case 0xE0008008: // T1TC - Timer 1 Counter
|
||||
T1TC = data;
|
||||
break;
|
||||
|
||||
case 0xE000E010:
|
||||
{
|
||||
uInt32 old = systick_ctrl;
|
||||
|
@ -348,6 +396,14 @@ uInt32 Thumbulator::read32(uInt32 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:
|
||||
data = systick_ctrl;
|
||||
systick_ctrl &= (~0x00010000);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define THUMBULATOR_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Console.hxx"
|
||||
|
||||
#define ROMADDMASK 0x7FFF
|
||||
#define RAMADDMASK 0x1FFF
|
||||
|
@ -54,6 +55,7 @@ class Thumbulator
|
|||
otherwise an empty string
|
||||
*/
|
||||
string run();
|
||||
string run(uInt32 cycles);
|
||||
|
||||
/**
|
||||
Normally when a fatal error is encountered, the ARM emulation
|
||||
|
@ -69,6 +71,8 @@ class Thumbulator
|
|||
*/
|
||||
static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
||||
|
||||
void setConsoleTiming(ConsoleTiming timing);
|
||||
|
||||
private:
|
||||
uInt32 read_register(uInt32 reg);
|
||||
void write_register(uInt32 reg, uInt32 data);
|
||||
|
@ -78,6 +82,7 @@ class Thumbulator
|
|||
uInt32 read32(uInt32 addr);
|
||||
void write16(uInt32 addr, uInt32 data);
|
||||
void write32(uInt32 addr, uInt32 data);
|
||||
void updateTimer(uInt32 cycles);
|
||||
|
||||
void do_zflag(uInt32 x);
|
||||
void do_nflag(uInt32 x);
|
||||
|
@ -107,6 +112,13 @@ class Thumbulator
|
|||
uInt32 systick_ctrl, systick_reload, systick_count, systick_calibrate;
|
||||
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;
|
||||
|
||||
static bool trapOnFatal;
|
||||
|
|
Loading…
Reference in New Issue