mirror of https://github.com/stella-emu/stella.git
Reworked 'read from write port' emulation for carts with extended RAM.
The values written and returned in such a case are now more accurate, and are a combination of the previous databus value and randomization (the latter emulating the randomness of Z-state bits). This provides more accurate emulation than before, where zeros were used instead. In particular, types 3E and E7 are now working correctly for the first time. Thanks to Batari for suggestions in this area. Moved random number generation from Cartridge to System class. The Subversion build number is now shown in the AboutDialog box. Still TODO is add architecture information (i386, x86_64, etc). git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1895 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
25f483dc27
commit
3df721e0be
|
@ -50,7 +50,7 @@ void Cartridge3E::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 32768; ++i)
|
for(uInt32 i = 0; i < 32768; ++i)
|
||||||
myRam[i] = myRandGenerator.next();
|
myRam[i] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// We'll map bank 0 into the first segment upon reset
|
// We'll map bank 0 into the first segment upon reset
|
||||||
bank(0);
|
bank(0);
|
||||||
|
@ -101,10 +101,19 @@ uInt8 Cartridge3E::peek(uInt16 address)
|
||||||
{
|
{
|
||||||
if(myCurrentBank < 256)
|
if(myCurrentBank < 256)
|
||||||
return myImage[(address & 0x07FF) + (myCurrentBank << 11)];
|
return myImage[(address & 0x07FF) + (myCurrentBank << 11)];
|
||||||
else if(address < 0x400) // Read from write port gives undefined values
|
|
||||||
return myRandGenerator.next();
|
|
||||||
else
|
else
|
||||||
return myRam[(address & 0x03FF) + ((myCurrentBank - 256) << 10)];
|
{
|
||||||
|
if(address < 0x0400)
|
||||||
|
return myRam[(address & 0x03FF) + ((myCurrentBank - 256) << 10)];
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Reading from the write port triggers an unwanted write
|
||||||
|
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||||
|
|
||||||
|
if(myBankLocked) return value;
|
||||||
|
else return myRam[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,7 +46,7 @@ void Cartridge4A50::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 32768; ++i)
|
for(uInt32 i = 0; i < 32768; ++i)
|
||||||
myRAM[i] = myRandGenerator.next();
|
myRAM[i] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
mySliceLow = mySliceMiddle = mySliceHigh = 0;
|
mySliceLow = mySliceMiddle = mySliceHigh = 0;
|
||||||
myIsRomLow = myIsRomMiddle = myIsRomHigh = true;
|
myIsRomLow = myIsRomMiddle = myIsRomHigh = true;
|
||||||
|
|
|
@ -53,7 +53,7 @@ void CartridgeAR::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 6 * 1024; ++i)
|
for(uInt32 i = 0; i < 6 * 1024; ++i)
|
||||||
myImage[i] = myRandGenerator.next();
|
myImage[i] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// Initialize SC BIOS ROM
|
// Initialize SC BIOS ROM
|
||||||
initializeROM();
|
initializeROM();
|
||||||
|
@ -300,7 +300,7 @@ void CartridgeAR::initializeROM()
|
||||||
|
|
||||||
// The accumulator should contain a random value after exiting the
|
// The accumulator should contain a random value after exiting the
|
||||||
// SC BIOS code - a value placed in offset 281 will be stored in A
|
// SC BIOS code - a value placed in offset 281 will be stored in A
|
||||||
ourDummyROMCode[281] = myRandGenerator.next();
|
ourDummyROMCode[281] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam
|
// Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam
|
||||||
for(uInt32 i = 0; i < 2048; ++i)
|
for(uInt32 i = 0; i < 2048; ++i)
|
||||||
|
|
|
@ -30,8 +30,6 @@ CartridgeCV::CartridgeCV(const uInt8* image, uInt32 size)
|
||||||
myROM = new uInt8[mySize];
|
myROM = new uInt8[mySize];
|
||||||
memcpy(myROM, image, mySize);
|
memcpy(myROM, image, mySize);
|
||||||
|
|
||||||
reset();
|
|
||||||
|
|
||||||
// This cart contains 1024 bytes extended RAM @ 0x1000
|
// This cart contains 1024 bytes extended RAM @ 0x1000
|
||||||
registerRamArea(0x1000, 1024, 0x00, 0x400);
|
registerRamArea(0x1000, 1024, 0x00, 0x400);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +50,7 @@ void CartridgeCV::reset()
|
||||||
|
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 1024; ++i)
|
for(uInt32 i = 0; i < 1024; ++i)
|
||||||
myRAM[i] = myRandGenerator.next();
|
myRAM[i] = mySystem->randGenerator().next();
|
||||||
}
|
}
|
||||||
else if(mySize == 4096)
|
else if(mySize == 4096)
|
||||||
{
|
{
|
||||||
|
@ -110,13 +108,13 @@ void CartridgeCV::install(System& system)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt8 CartridgeCV::peek(uInt16 address)
|
uInt8 CartridgeCV::peek(uInt16 address)
|
||||||
{
|
{
|
||||||
// Reading from the write port triggers an unwanted write
|
|
||||||
// The value written to RAM is somewhat undefined, so we use 0
|
|
||||||
// Thanks to Kroko of AtariAge for this advice and code idea
|
|
||||||
if((address & 0x0FFF) < 0x0800) // Write port is at 0xF400 - 0xF800 (1024 bytes)
|
if((address & 0x0FFF) < 0x0800) // Write port is at 0xF400 - 0xF800 (1024 bytes)
|
||||||
{ // Read port is handled in ::install()
|
{ // Read port is handled in ::install()
|
||||||
if(myBankLocked) return 0;
|
// Reading from the write port triggers an unwanted write
|
||||||
else return myRAM[address & 0x03FF] = 0;
|
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||||
|
|
||||||
|
if(myBankLocked) return value;
|
||||||
|
else return myRAM[address & 0x03FF] = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,7 +46,7 @@ void CartridgeE7::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 2048; ++i)
|
for(uInt32 i = 0; i < 2048; ++i)
|
||||||
myRAM[i] = myRandGenerator.next();
|
myRAM[i] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// Install some default banks for the RAM and first segment
|
// Install some default banks for the RAM and first segment
|
||||||
bankRAM(0);
|
bankRAM(0);
|
||||||
|
@ -104,11 +104,14 @@ uInt8 CartridgeE7::peek(uInt16 address)
|
||||||
bankRAM(address & 0x0003);
|
bankRAM(address & 0x0003);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: The following does not handle reading from RAM, however,
|
if((address < 0x0400) && (bank() == 7))
|
||||||
// this function should never be called for RAM because of the
|
{
|
||||||
// way page accessing has been setup
|
// Reading from the write port triggers an unwanted write
|
||||||
if((bank() == 7) && (address < 0x400))
|
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||||
return myRandGenerator.next(); // Read from write port gives undefined values
|
|
||||||
|
if(myBankLocked) return value;
|
||||||
|
else return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)] = value;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)];
|
return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)];
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ void CartridgeEFSC::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 128; ++i)
|
for(uInt32 i = 0; i < 128; ++i)
|
||||||
myRAM[i] = myRandGenerator.next();
|
myRAM[i] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// Upon reset we switch to bank 1
|
// Upon reset we switch to bank 1
|
||||||
bank(1);
|
bank(1);
|
||||||
|
@ -99,13 +99,13 @@ uInt8 CartridgeEFSC::peek(uInt16 address)
|
||||||
if((address >= 0x0FE0) && (address <= 0x0FEF))
|
if((address >= 0x0FE0) && (address <= 0x0FEF))
|
||||||
bank(address - 0x0FE0);
|
bank(address - 0x0FE0);
|
||||||
|
|
||||||
// Reading from the write port triggers an unwanted write
|
|
||||||
// The value written to RAM is somewhat undefined, so we use 0
|
|
||||||
// Thanks to Kroko of AtariAge for this advice and code idea
|
|
||||||
if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes)
|
if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes)
|
||||||
{
|
{
|
||||||
if(myBankLocked) return 0;
|
// Reading from the write port triggers an unwanted write
|
||||||
else return myRAM[address] = 0;
|
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||||
|
|
||||||
|
if(myBankLocked) return value;
|
||||||
|
else return myRAM[address] = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[(myCurrentBank << 12) + address];
|
||||||
|
|
|
@ -42,7 +42,7 @@ void CartridgeF4SC::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 128; ++i)
|
for(uInt32 i = 0; i < 128; ++i)
|
||||||
myRAM[i] = myRandGenerator.next();
|
myRAM[i] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// Upon reset we switch to bank 0
|
// Upon reset we switch to bank 0
|
||||||
bank(0);
|
bank(0);
|
||||||
|
@ -99,13 +99,13 @@ uInt8 CartridgeF4SC::peek(uInt16 address)
|
||||||
if((address >= 0x0FF4) && (address <= 0x0FFB))
|
if((address >= 0x0FF4) && (address <= 0x0FFB))
|
||||||
bank(address - 0x0FF4);
|
bank(address - 0x0FF4);
|
||||||
|
|
||||||
// Reading from the write port triggers an unwanted write
|
|
||||||
// The value written to RAM is somewhat undefined, so we use 0
|
|
||||||
// Thanks to Kroko of AtariAge for this advice and code idea
|
|
||||||
if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes)
|
if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes)
|
||||||
{
|
{
|
||||||
if(myBankLocked) return 0;
|
// Reading from the write port triggers an unwanted write
|
||||||
else return myRAM[address] = 0;
|
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||||
|
|
||||||
|
if(myBankLocked) return value;
|
||||||
|
else return myRAM[address] = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[(myCurrentBank << 12) + address];
|
||||||
|
|
|
@ -42,7 +42,7 @@ void CartridgeF6SC::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 128; ++i)
|
for(uInt32 i = 0; i < 128; ++i)
|
||||||
myRAM[i] = myRandGenerator.next();
|
myRAM[i] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// Upon reset we switch to bank 0
|
// Upon reset we switch to bank 0
|
||||||
bank(0);
|
bank(0);
|
||||||
|
@ -122,13 +122,13 @@ uInt8 CartridgeF6SC::peek(uInt16 address)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reading from the write port triggers an unwanted write
|
|
||||||
// The value written to RAM is somewhat undefined, so we use 0
|
|
||||||
// Thanks to Kroko of AtariAge for this advice and code idea
|
|
||||||
if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes)
|
if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes)
|
||||||
{
|
{
|
||||||
if(myBankLocked) return 0;
|
// Reading from the write port triggers an unwanted write
|
||||||
else return myRAM[address] = 0;
|
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||||
|
|
||||||
|
if(myBankLocked) return value;
|
||||||
|
else return myRAM[address] = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[(myCurrentBank << 12) + address];
|
||||||
|
|
|
@ -42,7 +42,7 @@ void CartridgeF8SC::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 128; ++i)
|
for(uInt32 i = 0; i < 128; ++i)
|
||||||
myRAM[i] = myRandGenerator.next();
|
myRAM[i] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// Upon reset we switch to bank 1
|
// Upon reset we switch to bank 1
|
||||||
bank(1);
|
bank(1);
|
||||||
|
@ -112,13 +112,13 @@ uInt8 CartridgeF8SC::peek(uInt16 address)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reading from the write port triggers an unwanted write
|
|
||||||
// The value written to RAM is somewhat undefined, so we use 0
|
|
||||||
// Thanks to Kroko of AtariAge for this advice and code idea
|
|
||||||
if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes)
|
if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes)
|
||||||
{
|
{
|
||||||
if(myBankLocked) return 0;
|
// Reading from the write port triggers an unwanted write
|
||||||
else return myRAM[address] = 0;
|
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||||
|
|
||||||
|
if(myBankLocked) return value;
|
||||||
|
else return myRAM[address] = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[(myCurrentBank << 12) + address];
|
||||||
|
|
|
@ -42,7 +42,7 @@ void CartridgeFASC::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 256; ++i)
|
for(uInt32 i = 0; i < 256; ++i)
|
||||||
myRAM[i] = myRandGenerator.next();
|
myRAM[i] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// Upon reset we switch to bank 2
|
// Upon reset we switch to bank 2
|
||||||
bank(2);
|
bank(2);
|
||||||
|
@ -117,22 +117,16 @@ uInt8 CartridgeFASC::peek(uInt16 address)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reading from the write port triggers an unwanted write
|
|
||||||
// The value written to RAM is somewhat undefined, so we use 0
|
|
||||||
// Thanks to Kroko of AtariAge for this advice and code idea
|
|
||||||
if(address < 0x0100) // Write port is at 0xF000 - 0xF100 (256 bytes)
|
if(address < 0x0100) // Write port is at 0xF000 - 0xF100 (256 bytes)
|
||||||
{
|
{
|
||||||
if(!myBankLocked)
|
// Reading from the write port triggers an unwanted write
|
||||||
{
|
uInt8 value = mySystem->getDataBusState(0xFF);
|
||||||
return myRAM[address] = 0;
|
|
||||||
}
|
if(myBankLocked) return value;
|
||||||
else
|
else return myRAM[address] = value;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[(myCurrentBank << 12) + address];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
#include "CartMC.hxx"
|
#include "CartMC.hxx"
|
||||||
|
|
||||||
|
// TODO - properly handle read from write port functionality
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
CartridgeMC::CartridgeMC(const uInt8* image, uInt32 size)
|
CartridgeMC::CartridgeMC(const uInt8* image, uInt32 size)
|
||||||
: mySlot3Locked(false)
|
: mySlot3Locked(false)
|
||||||
|
@ -46,7 +48,7 @@ void CartridgeMC::reset()
|
||||||
{
|
{
|
||||||
// Initialize RAM with random values
|
// Initialize RAM with random values
|
||||||
for(uInt32 i = 0; i < 32768; ++i)
|
for(uInt32 i = 0; i < 32768; ++i)
|
||||||
myRAM[i] = myRandGenerator.next();
|
myRAM[i] = mySystem->randGenerator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
M6532::M6532(const Console& console)
|
M6532::M6532(const Console& console)
|
||||||
: myConsole(console)
|
: myConsole(console)
|
||||||
{
|
{
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -42,11 +41,11 @@ void M6532::reset()
|
||||||
{
|
{
|
||||||
// Randomize the 128 bytes of memory
|
// Randomize the 128 bytes of memory
|
||||||
for(uInt32 t = 0; t < 128; ++t)
|
for(uInt32 t = 0; t < 128; ++t)
|
||||||
myRAM[t] = myRandGenerator.next();
|
myRAM[t] = mySystem->randGenerator().next();
|
||||||
|
|
||||||
// The timer absolutely cannot be initialized to zero; some games will
|
// The timer absolutely cannot be initialized to zero; some games will
|
||||||
// loop or hang (notably Solaris and H.E.R.O.)
|
// loop or hang (notably Solaris and H.E.R.O.)
|
||||||
myTimer = (0xff - (myRandGenerator.next() % 0xfe)) << 10;
|
myTimer = (0xff - (mySystem->randGenerator().next() % 0xfe)) << 10;
|
||||||
myIntervalShift = 10;
|
myIntervalShift = 10;
|
||||||
myCyclesWhenTimerSet = 0;
|
myCyclesWhenTimerSet = 0;
|
||||||
myInterruptEnabled = false;
|
myInterruptEnabled = false;
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include "Console.hxx"
|
#include "Console.hxx"
|
||||||
#include "Random.hxx"
|
#include "Random.hxx"
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
|
#include "Version.hxx"
|
||||||
|
|
||||||
#include "OSystem.hxx"
|
#include "OSystem.hxx"
|
||||||
|
|
||||||
|
@ -114,7 +115,7 @@ OSystem::OSystem()
|
||||||
ostringstream info;
|
ostringstream info;
|
||||||
const SDL_version* ver = SDL_Linked_Version();
|
const SDL_version* ver = SDL_Linked_Version();
|
||||||
|
|
||||||
info << "Build " << "TODO" << ", using ";
|
info << "Build " << STELLA_BUILD << ", using ";
|
||||||
info << "SDL " << (int)ver->major << "." << (int)ver->minor << "." << (int)ver->patch << " ";
|
info << "SDL " << (int)ver->major << "." << (int)ver->minor << "." << (int)ver->patch << " ";
|
||||||
info << "[" << " " << "]";
|
info << "[" << " " << "]";
|
||||||
myBuildInfo = info.str();
|
myBuildInfo = info.str();
|
||||||
|
|
|
@ -66,7 +66,6 @@ class Random
|
||||||
// Indicates the next random number
|
// Indicates the next random number
|
||||||
uInt32 myValue;
|
uInt32 myValue;
|
||||||
|
|
||||||
private:
|
|
||||||
// Set the OSystem we're using
|
// Set the OSystem we're using
|
||||||
static const OSystem* ourSystem;
|
static const OSystem* ourSystem;
|
||||||
};
|
};
|
||||||
|
|
|
@ -169,7 +169,9 @@ void TIA::reset()
|
||||||
myDumpEnabled = false;
|
myDumpEnabled = false;
|
||||||
myDumpDisabledCycle = 0;
|
myDumpDisabledCycle = 0;
|
||||||
|
|
||||||
myFloatTIAOutputPins = mySettings.getBool("tiafloat");
|
// The mask indicates which pins should be driven high
|
||||||
|
// If a pin is floating (the default), then its mask value is 0
|
||||||
|
myOutputPinsMask = mySettings.getBool("tiafloat") ? 0x00 : 0x3F;
|
||||||
|
|
||||||
myFrameCounter = 0;
|
myFrameCounter = 0;
|
||||||
myScanlineCountForLastFrame = 0;
|
myScanlineCountForLastFrame = 0;
|
||||||
|
@ -1233,9 +1235,9 @@ uInt8 TIA::peek(uInt16 addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// On certain CMOS EPROM chips the unused TIA pins on a read are not
|
// On certain CMOS EPROM chips the unused TIA pins on a read are not
|
||||||
// floating but pulled high. Programmers might want to check their
|
// floating but pulled high. Programmers might want to check their
|
||||||
// games for compatibility, so we make this optional.
|
// games for compatibility, so we make this optional.
|
||||||
value |= myFloatTIAOutputPins ? (mySystem->getDataBusState() & 0x3F) : 0x3F;
|
value |= ((mySystem->getDataBusState() | myOutputPinsMask) & 0x3F);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,7 +563,8 @@ class TIA : public Device
|
||||||
bool myAllowHMOVEBlanks;
|
bool myAllowHMOVEBlanks;
|
||||||
|
|
||||||
// Indicates if unused TIA pins are floating on a peek
|
// Indicates if unused TIA pins are floating on a peek
|
||||||
bool myFloatTIAOutputPins;
|
// Otherwise, they're forced high
|
||||||
|
uInt8 myOutputPinsMask;
|
||||||
|
|
||||||
// Bitmap of the objects that should be considered while drawing
|
// Bitmap of the objects that should be considered while drawing
|
||||||
uInt8 myEnabledObjects;
|
uInt8 myEnabledObjects;
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
Device::Device()
|
Device::Device()
|
||||||
: mySystem(0)
|
: mySystem(0)
|
||||||
{
|
{
|
||||||
myRandGenerator.initSeed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -35,6 +34,3 @@ void Device::systemCyclesReset()
|
||||||
{
|
{
|
||||||
// By default I do nothing when my system resets its cycle counter
|
// By default I do nothing when my system resets its cycle counter
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
Random Device::myRandGenerator;
|
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
class System;
|
class System;
|
||||||
|
|
||||||
#include "Random.hxx"
|
|
||||||
#include "Serializable.hxx"
|
#include "Serializable.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
@ -47,7 +46,11 @@ class Device : public Serializable
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
Reset device to its power-on state
|
Reset device to its power-on state.
|
||||||
|
|
||||||
|
*DO NOT* call this method until the device has been attached to
|
||||||
|
the System. In fact, it should never be necessary to call this
|
||||||
|
method directly at all.
|
||||||
*/
|
*/
|
||||||
virtual void reset() = 0;
|
virtual void reset() = 0;
|
||||||
|
|
||||||
|
@ -108,10 +111,6 @@ class Device : public Serializable
|
||||||
protected:
|
protected:
|
||||||
/// Pointer to the system the device is installed in or the null pointer
|
/// Pointer to the system the device is installed in or the null pointer
|
||||||
System* mySystem;
|
System* mySystem;
|
||||||
|
|
||||||
/// Many devices need a source of random numbers, usually for emulating
|
|
||||||
/// unknown/undefined behaviour
|
|
||||||
static class Random myRandGenerator;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -41,6 +41,9 @@ System::System(uInt16 n, uInt16 m)
|
||||||
// Make sure the arguments are reasonable
|
// Make sure the arguments are reasonable
|
||||||
assert((1 <= m) && (m <= n) && (n <= 16));
|
assert((1 <= m) && (m <= n) && (n <= 16));
|
||||||
|
|
||||||
|
// Create a new random number generator
|
||||||
|
myRandom = new Random();
|
||||||
|
|
||||||
// Allocate page table
|
// Allocate page table
|
||||||
myPageAccessTable = new PageAccess[myNumberOfPages];
|
myPageAccessTable = new PageAccess[myNumberOfPages];
|
||||||
|
|
||||||
|
@ -72,6 +75,9 @@ System::~System()
|
||||||
|
|
||||||
// Free my page access table
|
// Free my page access table
|
||||||
delete[] myPageAccessTable;
|
delete[] myPageAccessTable;
|
||||||
|
|
||||||
|
// Free the random number generator
|
||||||
|
delete myRandom;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -28,6 +28,7 @@ class NullDevice;
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
#include "Device.hxx"
|
#include "Device.hxx"
|
||||||
#include "NullDev.hxx"
|
#include "NullDev.hxx"
|
||||||
|
#include "Random.hxx"
|
||||||
#include "Serializable.hxx"
|
#include "Serializable.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,6 +139,16 @@ class System : public Serializable
|
||||||
return *myTIA;
|
return *myTIA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Answer the random generator attached to the system.
|
||||||
|
|
||||||
|
@return The random generator
|
||||||
|
*/
|
||||||
|
Random& randGenerator()
|
||||||
|
{
|
||||||
|
return *myRandom;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the null device associated with the system. Every system
|
Get the null device associated with the system. Every system
|
||||||
has a null device associated with it that's used by pages which
|
has a null device associated with it that's used by pages which
|
||||||
|
@ -215,13 +226,35 @@ class System : public Serializable
|
||||||
Get the current state of the data bus in the system. The current
|
Get the current state of the data bus in the system. The current
|
||||||
state is the last data that was accessed by the system.
|
state is the last data that was accessed by the system.
|
||||||
|
|
||||||
@return the data bus state
|
@return The data bus state
|
||||||
*/
|
*/
|
||||||
inline uInt8 getDataBusState() const
|
inline uInt8 getDataBusState() const
|
||||||
{
|
{
|
||||||
return myDataBusState;
|
return myDataBusState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the current state of the data bus in the system, taking into
|
||||||
|
account that certain bits are in Z-state (undriven). In those
|
||||||
|
cases, the bits are floating, but will usually be the same as the
|
||||||
|
last data bus value (the 'usually' is emulated by randomly driving
|
||||||
|
certain bits high).
|
||||||
|
|
||||||
|
However, some CMOS EPROM chips always drive Z-state bits high.
|
||||||
|
This is emulated by hmask, which specifies to push a specific
|
||||||
|
Z-state bit high.
|
||||||
|
|
||||||
|
@param zmask The bits which are in Z-state
|
||||||
|
@param hmask The bits which should always be driven high
|
||||||
|
@return The data bus state
|
||||||
|
*/
|
||||||
|
inline uInt8 getDataBusState(uInt8 zmask, uInt8 hmask = 0x00)
|
||||||
|
{
|
||||||
|
// For the pins that are floating, randomly decide which are high or low
|
||||||
|
// Otherwise, they're specifically driven high
|
||||||
|
return (myDataBusState | (myRandom->next() | hmask)) & zmask;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the byte at the specified address. No masking of the
|
Get the byte at the specified address. No masking of the
|
||||||
address occurs before it's sent to the device mapped at
|
address occurs before it's sent to the device mapped at
|
||||||
|
@ -352,6 +385,10 @@ class System : public Serializable
|
||||||
// TIA device attached to the system or the null pointer
|
// TIA device attached to the system or the null pointer
|
||||||
TIA* myTIA;
|
TIA* myTIA;
|
||||||
|
|
||||||
|
// Many devices need a source of random numbers, usually for emulating
|
||||||
|
// unknown/undefined behaviour
|
||||||
|
Random* myRandom;
|
||||||
|
|
||||||
// Number of system cycles executed since the last reset
|
// Number of system cycles executed since the last reset
|
||||||
uInt32 myCycles;
|
uInt32 myCycles;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue