mirror of https://github.com/stella-emu/stella.git
More peek/poke refactoring, and improved comments in bankswitching schemes.
This commit is contained in:
parent
68f80f04d9
commit
31907f4be1
|
@ -102,7 +102,7 @@ void CartridgeDFSCWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeDFSCWidget::loadConfig()
|
void CartridgeDFSCWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -131,8 +131,8 @@ string CartridgeDFSCWidget::bankState()
|
||||||
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFE7",
|
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFE7",
|
||||||
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ CartridgeDFWidget::CartridgeDFWidget(
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeDFWidget::loadConfig()
|
void CartridgeDFWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -118,8 +118,8 @@ string CartridgeDFWidget::bankState()
|
||||||
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFD7",
|
"$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFD7",
|
||||||
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
"$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,7 +218,7 @@ void CartridgeDPCPlusWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeDPCPlusWidget::loadConfig()
|
void CartridgeDPCPlusWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
// Get registers, using change tracking
|
// Get registers, using change tracking
|
||||||
IntArray alist;
|
IntArray alist;
|
||||||
|
@ -327,8 +327,8 @@ string CartridgeDPCPlusWidget::bankState()
|
||||||
static const char* const spot[] = {
|
static const char* const spot[] = {
|
||||||
"$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
"$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,7 +156,7 @@ void CartridgeDPCWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeDPCWidget::loadConfig()
|
void CartridgeDPCWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
// Get registers, using change tracking
|
// Get registers, using change tracking
|
||||||
IntArray alist;
|
IntArray alist;
|
||||||
|
@ -228,8 +228,8 @@ string CartridgeDPCWidget::bankState()
|
||||||
ostringstream& buf = buffer();
|
ostringstream& buf = buffer();
|
||||||
|
|
||||||
static const char* const spot[] = { "$FFF8", "$FFF9" };
|
static const char* const spot[] = { "$FFF8", "$FFF9" };
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ void CartridgeEFSCWidget::saveOldState()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeEFSCWidget::loadConfig()
|
void CartridgeEFSCWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -113,8 +113,8 @@ string CartridgeEFSCWidget::bankState()
|
||||||
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
||||||
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ CartridgeEFWidget::CartridgeEFWidget(
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeEFWidget::loadConfig()
|
void CartridgeEFWidget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -100,8 +100,8 @@ string CartridgeEFWidget::bankState()
|
||||||
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
"$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7",
|
||||||
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
"$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF"
|
||||||
};
|
};
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
buf << "Bank = " << std::dec << myCart.getBank()
|
||||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
<< ", hotspot = " << spot[myCart.getBank()];
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ CartridgeF0Widget::CartridgeF0Widget(
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeF0Widget::loadConfig()
|
void CartridgeF0Widget::loadConfig()
|
||||||
{
|
{
|
||||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
myBank->setSelectedIndex(myCart.getBank());
|
||||||
|
|
||||||
CartDebugWidget::loadConfig();
|
CartDebugWidget::loadConfig();
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ string CartridgeF0Widget::bankState()
|
||||||
{
|
{
|
||||||
ostringstream& buf = buffer();
|
ostringstream& buf = buffer();
|
||||||
|
|
||||||
buf << "Bank = " << std::dec << myCart.myCurrentBank << ", hotspot = $FFF0";
|
buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = $FFF0";
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,8 @@ Cartridge2K::Cartridge2K(const BytePtr& image, uInt32 size,
|
||||||
while(mySize < size)
|
while(mySize < size)
|
||||||
mySize <<= 1;
|
mySize <<= 1;
|
||||||
|
|
||||||
// The smallest addressable area by Stella is 64 bytes
|
// We can't use a size smaller than the minimum page size in Stella
|
||||||
// This should really be read from the System, but for now I'm going
|
mySize = std::max(mySize, 1u << System::PAGE_SHIFT);
|
||||||
// to cheat a little and hard-code it to 64 (aka 2^6)
|
|
||||||
if(mySize < 64)
|
|
||||||
mySize = 64;
|
|
||||||
|
|
||||||
// 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
|
||||||
myImage = make_unique<uInt8[]>(mySize);
|
myImage = make_unique<uInt8[]>(mySize);
|
||||||
|
@ -62,6 +59,8 @@ void Cartridge2K::install(System& system)
|
||||||
mySystem = &system;
|
mySystem = &system;
|
||||||
|
|
||||||
// Map ROM image into the system
|
// Map ROM image into the system
|
||||||
|
// Note that we don't need our own peek/poke methods, since the mapping
|
||||||
|
// takes care of the entire address space
|
||||||
System::PageAccess access(this, System::PA_READ);
|
System::PageAccess access(this, System::PA_READ);
|
||||||
for(uInt32 address = 0x1000; address < 0x2000; address += (1 << System::PAGE_SHIFT))
|
for(uInt32 address = 0x1000; address < 0x2000; address += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,11 +27,12 @@ class System;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This is the standard Atari 2K cartridge. These cartridges
|
This is the standard Atari 2K cartridge. These cartridges are not
|
||||||
are not bankswitched, however, the data repeats twice in the
|
bankswitched, however, the data repeats twice in the 2600's 4K cartridge
|
||||||
2600's 4K cartridge addressing space.
|
addressing space. For 'Sub2K' ROMs (ROMs less than 2K in size), the
|
||||||
|
data repeats in intervals based on the size of the ROM.
|
||||||
|
|
||||||
@author Bradford W. Mott
|
@author Stephen Anthony
|
||||||
*/
|
*/
|
||||||
class Cartridge2K : public Cartridge
|
class Cartridge2K : public Cartridge
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,6 +40,8 @@ void Cartridge4K::install(System& system)
|
||||||
mySystem = &system;
|
mySystem = &system;
|
||||||
|
|
||||||
// Map ROM image into the system
|
// Map ROM image into the system
|
||||||
|
// Note that we don't need our own peek/poke methods, since the mapping
|
||||||
|
// takes care of the entire address space
|
||||||
System::PageAccess access(this, System::PA_READ);
|
System::PageAccess access(this, System::PA_READ);
|
||||||
for(uInt32 address = 0x1000; address < 0x2000;
|
for(uInt32 address = 0x1000; address < 0x2000;
|
||||||
address += (1 << System::PAGE_SHIFT))
|
address += (1 << System::PAGE_SHIFT))
|
||||||
|
|
|
@ -28,6 +28,7 @@ class System;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Cartridge class used for 4K games with 128 bytes of RAM.
|
Cartridge class used for 4K games with 128 bytes of RAM.
|
||||||
|
RAM read port is $1080 - $10FF, write port is $1000 - $107F.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Cartridge4KSC : public Cartridge
|
class Cartridge4KSC : public Cartridge
|
||||||
|
|
|
@ -29,6 +29,7 @@ class System;
|
||||||
/**
|
/**
|
||||||
There are 64 4K banks (total of 256K ROM) with 128 bytes of RAM.
|
There are 64 4K banks (total of 256K ROM) with 128 bytes of RAM.
|
||||||
Accessing $1F80 - $1FBF switches to each bank.
|
Accessing $1F80 - $1FBF switches to each bank.
|
||||||
|
RAM read port is $1080 - $10FF, write port is $1000 - $107F.
|
||||||
|
|
||||||
@author Stephen Anthony
|
@author Stephen Anthony
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -29,98 +29,98 @@ class CartridgeDASHWidget;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Cartridge class for new tiling engine "Boulder Dash" format games with RAM.
|
Cartridge class for new tiling engine "Boulder Dash" format games with RAM.
|
||||||
Kind of a combination of 3F and 3E, with better switchability.
|
Kind of a combination of 3F and 3E, with better switchability.
|
||||||
B.Watson's Cart3E was used as a template for building this implementation.
|
B.Watson's Cart3E was used as a template for building this implementation.
|
||||||
|
|
||||||
The destination bank (0-3) is held in the top bits of the value written to
|
The destination bank (0-3) is held in the top bits of the value written to
|
||||||
$3E (for RAM switching) or $3F (for ROM switching). The low 6 bits give
|
$3E (for RAM switching) or $3F (for ROM switching). The low 6 bits give
|
||||||
the actual bank number (0-63) corresponding to 512 byte blocks for RAM and
|
the actual bank number (0-63) corresponding to 512 byte blocks for RAM and
|
||||||
1024 byte blocks for ROM. The maximum size is therefore 32K RAM and 64K ROM.
|
1024 byte blocks for ROM. The maximum size is therefore 32K RAM and 64K ROM.
|
||||||
|
|
||||||
D7D6 indicate the bank number (0-3)
|
D7D6 indicate the bank number (0-3)
|
||||||
D5D4D3D2D1D0 indicate the actual # (0-63) from the image/ram
|
D5D4D3D2D1D0 indicate the actual # (0-63) from the image/ram
|
||||||
|
|
||||||
ROM:
|
ROM:
|
||||||
|
|
||||||
Note: in descriptions $F000 is equivalent to $1000 -- that is, we only deal
|
Note: in descriptions $F000 is equivalent to $1000 -- that is, we only deal
|
||||||
with the low 13 bits of addressing. Stella code uses $1000, I'm used to $F000
|
with the low 13 bits of addressing. Stella code uses $1000, I'm used to $F000
|
||||||
So, mask with top bits clear :) when reading this document.
|
So, mask with top bits clear :) when reading this document.
|
||||||
|
|
||||||
In this scheme, the 4K address space is broken into four 1K ROM segments.
|
In this scheme, the 4K address space is broken into four 1K ROM segments.
|
||||||
living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.),
|
living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.),
|
||||||
and four 512 byte RAM segments, living at 0x1000, 0x1200, 0x1400, 0x1600
|
and four 512 byte RAM segments, living at 0x1000, 0x1200, 0x1400, 0x1600
|
||||||
with write-mirrors +0x800 of these. The last 1K ROM ($FC00-$FFFF) segment
|
with write-mirrors +0x800 of these. The last 1K ROM ($FC00-$FFFF) segment
|
||||||
in the 6502 address space (ie: $1C00-$1FFF) is initialised to point to the
|
in the 6502 address space (ie: $1C00-$1FFF) is initialised to point to the
|
||||||
FIRST 1K of the ROM image, so the reset vectors must be placed at the
|
FIRST 1K of the ROM image, so the reset vectors must be placed at the
|
||||||
end of the first 1K in the ROM image. Note, this is DIFFERENT to 3E which
|
end of the first 1K in the ROM image. Note, this is DIFFERENT to 3E which
|
||||||
switches in the UPPER bank and this bank is fixed. This allows variable sized
|
switches in the UPPER bank and this bank is fixed. This allows variable sized
|
||||||
ROM without having to detect size. First bank (0) in ROM is the default fixed
|
ROM without having to detect size. First bank (0) in ROM is the default fixed
|
||||||
bank mapped to $FC00.
|
bank mapped to $FC00.
|
||||||
|
|
||||||
The system requires the reset vectors to be valid on a reset, so either the
|
The system requires the reset vectors to be valid on a reset, so either the
|
||||||
hardware first switches in the first bank, or the programmer must ensure
|
hardware first switches in the first bank, or the programmer must ensure
|
||||||
that the reset vector is present in ALL ROM banks which might be switched
|
that the reset vector is present in ALL ROM banks which might be switched
|
||||||
into the last bank area. Currently the latter (programmer onus) is required,
|
into the last bank area. Currently the latter (programmer onus) is required,
|
||||||
but it would be nice for the cartridge hardware to auto-switch on reset.
|
but it would be nice for the cartridge hardware to auto-switch on reset.
|
||||||
|
|
||||||
ROM switching (write of block+bank number to $3F) D7D6 upper 2 bits of bank #
|
ROM switching (write of block+bank number to $3F) D7D6 upper 2 bits of bank #
|
||||||
indicates the destination segment (0-3, corresponding to $F000, $F400, $F800,
|
indicates the destination segment (0-3, corresponding to $F000, $F400, $F800,
|
||||||
$FC00), and lower 6 bits indicate the 1K bank to switch in. Can handle 64
|
$FC00), and lower 6 bits indicate the 1K bank to switch in. Can handle 64
|
||||||
x 1K ROM banks (64K total).
|
x 1K ROM banks (64K total).
|
||||||
|
|
||||||
D7 D6 D5D4D3D2D1D0
|
D7 D6 D5D4D3D2D1D0
|
||||||
0 0 x x x x x x switch a 1K ROM bank xxxxx to $F000
|
0 0 x x x x x x switch a 1K ROM bank xxxxx to $F000
|
||||||
0 1 switch a 1K ROM bank xxxxx to $F400
|
0 1 switch a 1K ROM bank xxxxx to $F400
|
||||||
1 0 switch a 1K ROM bank xxxxx to $F800
|
1 0 switch a 1K ROM bank xxxxx to $F800
|
||||||
1 1 switch a 1K ROM bank xxxxx to $FC00
|
1 1 switch a 1K ROM bank xxxxx to $FC00
|
||||||
|
|
||||||
RAM switching (write of segment+bank number to $3E) with D7D6 upper 2 bits of
|
RAM switching (write of segment+bank number to $3E) with D7D6 upper 2 bits of
|
||||||
bank # indicates the destination RAM segment (0-3, corresponding to $F000,
|
bank # indicates the destination RAM segment (0-3, corresponding to $F000,
|
||||||
$F200, $F400, $F600). Note that this allows contiguous 2K of RAM to be
|
$F200, $F400, $F600). Note that this allows contiguous 2K of RAM to be
|
||||||
configured by setting 4 consecutive RAM segments each 512 bytes with
|
configured by setting 4 consecutive RAM segments each 512 bytes with
|
||||||
consecutive addresses. However, as the write address of RAM is +0x800, this
|
consecutive addresses. However, as the write address of RAM is +0x800, this
|
||||||
invalidates ROM access as described below.
|
invalidates ROM access as described below.
|
||||||
|
|
||||||
can handle 64 x 512 byte RAM banks (32K total)
|
can handle 64 x 512 byte RAM banks (32K total)
|
||||||
|
|
||||||
D7 D6 D5D4D3D2D1D0
|
D7 D6 D5D4D3D2D1D0
|
||||||
0 0 x x x x x x switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800
|
0 0 x x x x x x switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800
|
||||||
0 1 switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00
|
0 1 switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00
|
||||||
1 0 switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00
|
1 0 switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00
|
||||||
1 1 switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00
|
1 1 switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00
|
||||||
|
|
||||||
It is possible to switch multiple RAM banks and ROM banks together
|
It is possible to switch multiple RAM banks and ROM banks together
|
||||||
|
|
||||||
For example,
|
For example,
|
||||||
F000-F1FF RAM bank A (512 byte READ)
|
F000-F1FF RAM bank A (512 byte READ)
|
||||||
F200-F3FF high 512 bytes of ROM bank previously loaded at F000
|
F200-F3FF high 512 bytes of ROM bank previously loaded at F000
|
||||||
F400 ROM bank 0 (1K)
|
F400 ROM bank 0 (1K)
|
||||||
F800 RAM bank A (512 byte WRITE)
|
F800 RAM bank A (512 byte WRITE)
|
||||||
FA00-FBFF high 512 bytes of ROM bank previously loaded at F400
|
FA00-FBFF high 512 bytes of ROM bank previously loaded at F400
|
||||||
FC00 ROM bank 1
|
FC00 ROM bank 1
|
||||||
|
|
||||||
This example shows 512 bytes of RAM, and 2 1K ROM banks and two 512 byte ROM
|
This example shows 512 bytes of RAM, and 2 1K ROM banks and two 512 byte ROM
|
||||||
bank halves.
|
bank halves.
|
||||||
|
|
||||||
Switching RAM blocks (D7D6 of $3E) partially invalidates ROM blocks, as below...
|
Switching RAM blocks (D7D6 of $3E) partially invalidates ROM blocks, as below...
|
||||||
|
|
||||||
RAM block Invalidates ROM block
|
RAM block Invalidates ROM block
|
||||||
0 0 (lower half), 2 (lower half)
|
0 0 (lower half), 2 (lower half)
|
||||||
1 0 (upper half), 2 (upper half)
|
1 0 (upper half), 2 (upper half)
|
||||||
2 1 (lower half), 3 (upper half)
|
2 1 (lower half), 3 (upper half)
|
||||||
3 1 (upper half), 3 (lower half)
|
3 1 (upper half), 3 (lower half)
|
||||||
|
|
||||||
For example, RAM block 1 uses address $F200-$F3FF and $FA00-$FBFF
|
For example, RAM block 1 uses address $F200-$F3FF and $FA00-$FBFF
|
||||||
ROM block 0 uses address $F000-$F3FF, and ROM block 2 uses address $F800-$FBFF
|
ROM block 0 uses address $F000-$F3FF, and ROM block 2 uses address $F800-$FBFF
|
||||||
Switching in RAM block 1 makes F200-F3FF ROM inaccessible, however F000-F1FF is
|
Switching in RAM block 1 makes F200-F3FF ROM inaccessible, however F000-F1FF is
|
||||||
still readable. So, care must be paid.
|
still readable. So, care must be paid.
|
||||||
|
|
||||||
This crazy RAM layout is useful as it allows contiguous RAM to be switched in,
|
This crazy RAM layout is useful as it allows contiguous RAM to be switched in,
|
||||||
up to 2K in one sequentially accessible block. This means you CAN have 2K of
|
up to 2K in one sequentially accessible block. This means you CAN have 2K of
|
||||||
consecutive RAM (don't forget to copy your reset vectors!)
|
consecutive RAM (don't forget to copy your reset vectors!)
|
||||||
|
|
||||||
@author Andrew Davie
|
@author Andrew Davie
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class CartridgeDASH: public Cartridge
|
class CartridgeDASH: public Cartridge
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
CartridgeDF::CartridgeDF(const BytePtr& image, uInt32 size,
|
CartridgeDF::CartridgeDF(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings),
|
||||||
myCurrentBank(0)
|
myBankOffset(0)
|
||||||
{
|
{
|
||||||
// Copy the ROM image into my buffer
|
// Copy the ROM image into my buffer
|
||||||
memcpy(myImage, image.get(), std::min(131072u, size));
|
memcpy(myImage, image.get(), std::min(131072u, size));
|
||||||
|
@ -57,7 +57,7 @@ uInt8 CartridgeDF::peek(uInt16 address)
|
||||||
if((address >= 0x0FC0) && (address <= 0x0FDF))
|
if((address >= 0x0FC0) && (address <= 0x0FDF))
|
||||||
bank(address - 0x0FC0);
|
bank(address - 0x0FC0);
|
||||||
|
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[myBankOffset + address];
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -78,8 +78,7 @@ bool CartridgeDF::bank(uInt16 bank)
|
||||||
if(bankLocked()) return false;
|
if(bankLocked()) return false;
|
||||||
|
|
||||||
// Remember what bank we're in
|
// Remember what bank we're in
|
||||||
myCurrentBank = bank;
|
myBankOffset = bank << 12;
|
||||||
uInt32 offset = myCurrentBank << 12;
|
|
||||||
|
|
||||||
System::PageAccess access(this, System::PA_READ);
|
System::PageAccess access(this, System::PA_READ);
|
||||||
|
|
||||||
|
@ -87,7 +86,7 @@ bool CartridgeDF::bank(uInt16 bank)
|
||||||
for(uInt32 i = (0x1FC0 & ~System::PAGE_MASK); i < 0x2000;
|
for(uInt32 i = (0x1FC0 & ~System::PAGE_MASK); i < 0x2000;
|
||||||
i += (1 << System::PAGE_SHIFT))
|
i += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (i & 0x0FFF)];
|
||||||
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +94,8 @@ bool CartridgeDF::bank(uInt16 bank)
|
||||||
for(uInt32 address = 0x1000; address < (0x1FC0U & ~System::PAGE_MASK);
|
for(uInt32 address = 0x1000; address < (0x1FC0U & ~System::PAGE_MASK);
|
||||||
address += (1 << System::PAGE_SHIFT))
|
address += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
|
access.directPeekBase = &myImage[myBankOffset + (address & 0x0FFF)];
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (address & 0x0FFF)];
|
||||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
|
@ -105,7 +104,7 @@ bool CartridgeDF::bank(uInt16 bank)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 CartridgeDF::getBank() const
|
uInt16 CartridgeDF::getBank() const
|
||||||
{
|
{
|
||||||
return myCurrentBank;
|
return myBankOffset >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -117,7 +116,7 @@ uInt16 CartridgeDF::bankCount() const
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool CartridgeDF::patch(uInt16 address, uInt8 value)
|
bool CartridgeDF::patch(uInt16 address, uInt8 value)
|
||||||
{
|
{
|
||||||
myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
|
myImage[myBankOffset + (address & 0x0FFF)] = value;
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +133,7 @@ bool CartridgeDF::save(Serializer& out) const
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
out.putString(name());
|
out.putString(name());
|
||||||
out.putShort(myCurrentBank);
|
out.putInt(myBankOffset);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -153,7 +152,7 @@ bool CartridgeDF::load(Serializer& in)
|
||||||
if(in.getString() != name())
|
if(in.getString() != name())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
myCurrentBank = in.getShort();
|
myBankOffset = in.getInt();
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -162,7 +161,7 @@ bool CartridgeDF::load(Serializer& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember what bank we were in
|
// Remember what bank we were in
|
||||||
bank(myCurrentBank);
|
bank(myBankOffset >> 12);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,8 +152,8 @@ class CartridgeDF : public Cartridge
|
||||||
// The 128K ROM image of the cartridge
|
// The 128K ROM image of the cartridge
|
||||||
uInt8 myImage[32 * 4096];
|
uInt8 myImage[32 * 4096];
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates the offset into the ROM image (aligns to current bank)
|
||||||
uInt16 myCurrentBank;
|
uInt32 myBankOffset;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
CartridgeDFSC::CartridgeDFSC(const BytePtr& image, uInt32 size,
|
CartridgeDFSC::CartridgeDFSC(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings),
|
||||||
myCurrentBank(0)
|
myBankOffset(0)
|
||||||
{
|
{
|
||||||
// Copy the ROM image into my buffer
|
// Copy the ROM image into my buffer
|
||||||
memcpy(myImage, image.get(), std::min(131072u, size));
|
memcpy(myImage, image.get(), std::min(131072u, size));
|
||||||
|
@ -95,7 +95,7 @@ uInt8 CartridgeDFSC::peek(uInt16 address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[myBankOffset + address];
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -107,7 +107,7 @@ bool CartridgeDFSC::poke(uInt16 address, uInt8)
|
||||||
if((address >= 0x0FC0) && (address <= 0x0FDF))
|
if((address >= 0x0FC0) && (address <= 0x0FDF))
|
||||||
bank(address - 0x0FC0);
|
bank(address - 0x0FC0);
|
||||||
|
|
||||||
// NOTE: This does not handle accessing RAM, however, this function
|
// NOTE: This does not handle accessing RAM, however, this method
|
||||||
// should never be called for RAM because of the way page accessing
|
// should never be called for RAM because of the way page accessing
|
||||||
// has been setup
|
// has been setup
|
||||||
return false;
|
return false;
|
||||||
|
@ -119,8 +119,7 @@ bool CartridgeDFSC::bank(uInt16 bank)
|
||||||
if(bankLocked()) return false;
|
if(bankLocked()) return false;
|
||||||
|
|
||||||
// Remember what bank we're in
|
// Remember what bank we're in
|
||||||
myCurrentBank = bank;
|
myBankOffset = bank << 12;
|
||||||
uInt32 offset = myCurrentBank << 12;
|
|
||||||
|
|
||||||
System::PageAccess access(this, System::PA_READ);
|
System::PageAccess access(this, System::PA_READ);
|
||||||
|
|
||||||
|
@ -128,7 +127,7 @@ bool CartridgeDFSC::bank(uInt16 bank)
|
||||||
for(uInt32 i = (0x1FC0 & ~System::PAGE_MASK); i < 0x2000;
|
for(uInt32 i = (0x1FC0 & ~System::PAGE_MASK); i < 0x2000;
|
||||||
i += (1 << System::PAGE_SHIFT))
|
i += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (i & 0x0FFF)];
|
||||||
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,8 +135,8 @@ bool CartridgeDFSC::bank(uInt16 bank)
|
||||||
for(uInt32 address = 0x1100; address < (0x1FC0U & ~System::PAGE_MASK);
|
for(uInt32 address = 0x1100; address < (0x1FC0U & ~System::PAGE_MASK);
|
||||||
address += (1 << System::PAGE_SHIFT))
|
address += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
|
access.directPeekBase = &myImage[myBankOffset + (address & 0x0FFF)];
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (address & 0x0FFF)];
|
||||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
|
@ -146,7 +145,7 @@ bool CartridgeDFSC::bank(uInt16 bank)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 CartridgeDFSC::getBank() const
|
uInt16 CartridgeDFSC::getBank() const
|
||||||
{
|
{
|
||||||
return myCurrentBank;
|
return myBankOffset >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -168,7 +167,7 @@ bool CartridgeDFSC::patch(uInt16 address, uInt8 value)
|
||||||
myRAM[address & 0x007F] = value;
|
myRAM[address & 0x007F] = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
myImage[(myCurrentBank << 12) + address] = value;
|
myImage[myBankOffset + address] = value;
|
||||||
|
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +185,7 @@ bool CartridgeDFSC::save(Serializer& out) const
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
out.putString(name());
|
out.putString(name());
|
||||||
out.putShort(myCurrentBank);
|
out.putInt(myBankOffset);
|
||||||
out.putByteArray(myRAM, 128);
|
out.putByteArray(myRAM, 128);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
|
@ -206,7 +205,7 @@ bool CartridgeDFSC::load(Serializer& in)
|
||||||
if(in.getString() != name())
|
if(in.getString() != name())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
myCurrentBank = in.getShort();
|
myBankOffset = in.getInt();
|
||||||
in.getByteArray(myRAM, 128);
|
in.getByteArray(myRAM, 128);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
|
@ -216,7 +215,7 @@ bool CartridgeDFSC::load(Serializer& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember what bank we were in
|
// Remember what bank we were in
|
||||||
bank(myCurrentBank);
|
bank(myBankOffset >> 12);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ class System;
|
||||||
/**
|
/**
|
||||||
There are 32 4K banks (total of 128K ROM) with 128 bytes of RAM.
|
There are 32 4K banks (total of 128K ROM) with 128 bytes of RAM.
|
||||||
Accessing $1FC0 - $1FDF switches to each bank.
|
Accessing $1FC0 - $1FDF switches to each bank.
|
||||||
|
RAM read port is $1080 - $10FF, write port is $1000 - $107F.
|
||||||
|
|
||||||
@author Stephen Anthony
|
@author Stephen Anthony
|
||||||
*/
|
*/
|
||||||
|
@ -154,8 +155,8 @@ class CartridgeDFSC : public Cartridge
|
||||||
// The 128 bytes of RAM
|
// The 128 bytes of RAM
|
||||||
uInt8 myRAM[128];
|
uInt8 myRAM[128];
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates the offset into the ROM image (aligns to current bank)
|
||||||
uInt16 myCurrentBank;
|
uInt32 myBankOffset;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
|
@ -25,7 +25,7 @@ CartridgeDPC::CartridgeDPC(const BytePtr& image, uInt32 size,
|
||||||
mySize(size),
|
mySize(size),
|
||||||
mySystemCycles(0),
|
mySystemCycles(0),
|
||||||
myFractionalClocks(0.0),
|
myFractionalClocks(0.0),
|
||||||
myCurrentBank(0)
|
myBankOffset(0)
|
||||||
{
|
{
|
||||||
// Make a copy of the entire image
|
// Make a copy of the entire image
|
||||||
memcpy(myImage, image.get(), std::min(size, 8192u + 2048u + 256u));
|
memcpy(myImage, image.get(), std::min(size, 8192u + 2048u + 256u));
|
||||||
|
@ -163,7 +163,7 @@ uInt8 CartridgeDPC::peek(uInt16 address)
|
||||||
// In debugger/bank-locked mode, we ignore all hotspots and in general
|
// In debugger/bank-locked mode, we ignore all hotspots and in general
|
||||||
// anything that can change the internal state of the cart
|
// anything that can change the internal state of the cart
|
||||||
if(bankLocked())
|
if(bankLocked())
|
||||||
return myProgramImage[(myCurrentBank << 12) + address];
|
return myProgramImage[myBankOffset + address];
|
||||||
|
|
||||||
// Clock the random number generator. This should be done for every
|
// Clock the random number generator. This should be done for every
|
||||||
// cartridge access, however, we're only doing it for the DPC and
|
// cartridge access, however, we're only doing it for the DPC and
|
||||||
|
@ -279,7 +279,7 @@ uInt8 CartridgeDPC::peek(uInt16 address)
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return myProgramImage[(myCurrentBank << 12) + address];
|
return myProgramImage[myBankOffset + address];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,8 +395,7 @@ bool CartridgeDPC::bank(uInt16 bank)
|
||||||
if(bankLocked()) return false;
|
if(bankLocked()) return false;
|
||||||
|
|
||||||
// Remember what bank we're in
|
// Remember what bank we're in
|
||||||
myCurrentBank = bank;
|
myBankOffset = bank << 12;
|
||||||
uInt16 offset = myCurrentBank << 12;
|
|
||||||
|
|
||||||
System::PageAccess access(this, System::PA_READ);
|
System::PageAccess access(this, System::PA_READ);
|
||||||
|
|
||||||
|
@ -404,7 +403,7 @@ bool CartridgeDPC::bank(uInt16 bank)
|
||||||
for(uInt32 i = (0x1FF8 & ~System::PAGE_MASK); i < 0x2000;
|
for(uInt32 i = (0x1FF8 & ~System::PAGE_MASK); i < 0x2000;
|
||||||
i += (1 << System::PAGE_SHIFT))
|
i += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (i & 0x0FFF)];
|
||||||
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,8 +411,8 @@ bool CartridgeDPC::bank(uInt16 bank)
|
||||||
for(uInt32 address = 0x1080; address < (0x1FF8U & ~System::PAGE_MASK);
|
for(uInt32 address = 0x1080; address < (0x1FF8U & ~System::PAGE_MASK);
|
||||||
address += (1 << System::PAGE_SHIFT))
|
address += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.directPeekBase = &myProgramImage[offset + (address & 0x0FFF)];
|
access.directPeekBase = &myProgramImage[myBankOffset + (address & 0x0FFF)];
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (address & 0x0FFF)];
|
||||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
|
@ -422,7 +421,7 @@ bool CartridgeDPC::bank(uInt16 bank)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 CartridgeDPC::getBank() const
|
uInt16 CartridgeDPC::getBank() const
|
||||||
{
|
{
|
||||||
return myCurrentBank;
|
return myBankOffset >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -439,7 +438,7 @@ bool CartridgeDPC::patch(uInt16 address, uInt8 value)
|
||||||
// For now, we ignore attempts to patch the DPC address space
|
// For now, we ignore attempts to patch the DPC address space
|
||||||
if(address >= 0x0080)
|
if(address >= 0x0080)
|
||||||
{
|
{
|
||||||
myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
|
myProgramImage[myBankOffset + (address & 0x0FFF)] = value;
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -461,7 +460,7 @@ bool CartridgeDPC::save(Serializer& out) const
|
||||||
out.putString(name());
|
out.putString(name());
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates which bank is currently active
|
||||||
out.putShort(myCurrentBank);
|
out.putShort(myBankOffset);
|
||||||
|
|
||||||
// The top registers for the data fetchers
|
// The top registers for the data fetchers
|
||||||
out.putByteArray(myTops, 8);
|
out.putByteArray(myTops, 8);
|
||||||
|
@ -503,7 +502,7 @@ bool CartridgeDPC::load(Serializer& in)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates which bank is currently active
|
||||||
myCurrentBank = in.getShort();
|
myBankOffset = in.getShort();
|
||||||
|
|
||||||
// The top registers for the data fetchers
|
// The top registers for the data fetchers
|
||||||
in.getByteArray(myTops, 8);
|
in.getByteArray(myTops, 8);
|
||||||
|
@ -535,7 +534,7 @@ bool CartridgeDPC::load(Serializer& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, go to the current bank
|
// Now, go to the current bank
|
||||||
bank(myCurrentBank);
|
bank(myBankOffset >> 12);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,8 +208,8 @@ class CartridgeDPC : 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;
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates the offset into the ROM image (aligns to current bank)
|
||||||
uInt16 myCurrentBank;
|
uInt16 myBankOffset;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
|
@ -33,7 +33,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const BytePtr& image, uInt32 size,
|
||||||
mySystemCycles(0),
|
mySystemCycles(0),
|
||||||
myFractionalClocks(0.0),
|
myFractionalClocks(0.0),
|
||||||
myARMCycles(0),
|
myARMCycles(0),
|
||||||
myCurrentBank(0)
|
myBankOffset(0)
|
||||||
{
|
{
|
||||||
// Image is always 32K, but in the case of ROM > 29K, the image is
|
// Image is always 32K, but in the case of ROM > 29K, the image is
|
||||||
// copied to the end of the buffer
|
// copied to the end of the buffer
|
||||||
|
@ -221,7 +221,7 @@ uInt8 CartridgeDPCPlus::peek(uInt16 address)
|
||||||
{
|
{
|
||||||
address &= 0x0FFF;
|
address &= 0x0FFF;
|
||||||
|
|
||||||
uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address];
|
uInt8 peekvalue = myProgramImage[myBankOffset + address];
|
||||||
uInt8 flag;
|
uInt8 flag;
|
||||||
|
|
||||||
// In debugger/bank-locked mode, we ignore all hotspots and in general
|
// In debugger/bank-locked mode, we ignore all hotspots and in general
|
||||||
|
@ -593,8 +593,7 @@ bool CartridgeDPCPlus::bank(uInt16 bank)
|
||||||
if(bankLocked()) return false;
|
if(bankLocked()) return false;
|
||||||
|
|
||||||
// Remember what bank we're in
|
// Remember what bank we're in
|
||||||
myCurrentBank = bank;
|
myBankOffset = bank << 12;
|
||||||
uInt16 offset = myCurrentBank << 12;
|
|
||||||
|
|
||||||
// Setup the page access methods for the current bank
|
// Setup the page access methods for the current bank
|
||||||
System::PageAccess access(this, System::PA_READ);
|
System::PageAccess access(this, System::PA_READ);
|
||||||
|
@ -603,7 +602,7 @@ bool CartridgeDPCPlus::bank(uInt16 bank)
|
||||||
for(uInt32 address = 0x1080; address < 0x2000;
|
for(uInt32 address = 0x1080; address < 0x2000;
|
||||||
address += (1 << System::PAGE_SHIFT))
|
address += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (address & 0x0FFF)];
|
||||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
|
@ -612,7 +611,7 @@ bool CartridgeDPCPlus::bank(uInt16 bank)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 CartridgeDPCPlus::getBank() const
|
uInt16 CartridgeDPCPlus::getBank() const
|
||||||
{
|
{
|
||||||
return myCurrentBank;
|
return myBankOffset >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -629,7 +628,7 @@ bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value)
|
||||||
// For now, we ignore attempts to patch the DPC address space
|
// For now, we ignore attempts to patch the DPC address space
|
||||||
if(address >= 0x0080)
|
if(address >= 0x0080)
|
||||||
{
|
{
|
||||||
myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
|
myProgramImage[myBankOffset + (address & 0x0FFF)] = value;
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -651,7 +650,7 @@ bool CartridgeDPCPlus::save(Serializer& out) const
|
||||||
out.putString(name());
|
out.putString(name());
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates which bank is currently active
|
||||||
out.putShort(myCurrentBank);
|
out.putShort(myBankOffset);
|
||||||
|
|
||||||
// Harmony RAM
|
// Harmony RAM
|
||||||
out.putByteArray(myDPCRAM, 8192);
|
out.putByteArray(myDPCRAM, 8192);
|
||||||
|
@ -715,7 +714,7 @@ bool CartridgeDPCPlus::load(Serializer& in)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates which bank is currently active
|
||||||
myCurrentBank = in.getShort();
|
myBankOffset = in.getShort();
|
||||||
|
|
||||||
// Harmony RAM
|
// Harmony RAM
|
||||||
in.getByteArray(myDPCRAM, 8192);
|
in.getByteArray(myDPCRAM, 8192);
|
||||||
|
@ -768,7 +767,7 @@ bool CartridgeDPCPlus::load(Serializer& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, go to the current bank
|
// Now, go to the current bank
|
||||||
bank(myCurrentBank);
|
bank(myBankOffset >> 12);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,8 +272,8 @@ class CartridgeDPCPlus : public Cartridge
|
||||||
// System cycle count when the last Thumbulator::run() occurred
|
// System cycle count when the last Thumbulator::run() occurred
|
||||||
Int32 myARMCycles;
|
Int32 myARMCycles;
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates the offset into the ROM image (aligns to current bank)
|
||||||
uInt16 myCurrentBank;
|
uInt16 myBankOffset;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
|
@ -136,7 +136,7 @@ bool CartridgeE7::poke(uInt16 address, uInt8)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This does not handle writing to RAM, however, this
|
// NOTE: This does not handle writing to RAM, however, this
|
||||||
// function should never be called for RAM because of the
|
// method should never be called for RAM because of the
|
||||||
// way page accessing has been setup
|
// way page accessing has been setup
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
CartridgeEF::CartridgeEF(const BytePtr& image, uInt32 size,
|
CartridgeEF::CartridgeEF(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings),
|
||||||
myCurrentBank(0)
|
myBankOffset(0)
|
||||||
{
|
{
|
||||||
// Copy the ROM image into my buffer
|
// Copy the ROM image into my buffer
|
||||||
memcpy(myImage, image.get(), std::min(65536u, size));
|
memcpy(myImage, image.get(), std::min(65536u, size));
|
||||||
|
@ -57,7 +57,7 @@ uInt8 CartridgeEF::peek(uInt16 address)
|
||||||
if((address >= 0x0FE0) && (address <= 0x0FEF))
|
if((address >= 0x0FE0) && (address <= 0x0FEF))
|
||||||
bank(address - 0x0FE0);
|
bank(address - 0x0FE0);
|
||||||
|
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[myBankOffset + address];
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -78,8 +78,7 @@ bool CartridgeEF::bank(uInt16 bank)
|
||||||
if(bankLocked()) return false;
|
if(bankLocked()) return false;
|
||||||
|
|
||||||
// Remember what bank we're in
|
// Remember what bank we're in
|
||||||
myCurrentBank = bank;
|
myBankOffset = bank << 12;
|
||||||
uInt16 offset = myCurrentBank << 12;
|
|
||||||
|
|
||||||
System::PageAccess access(this, System::PA_READ);
|
System::PageAccess access(this, System::PA_READ);
|
||||||
|
|
||||||
|
@ -87,7 +86,7 @@ bool CartridgeEF::bank(uInt16 bank)
|
||||||
for(uInt32 i = (0x1FE0 & ~System::PAGE_MASK); i < 0x2000;
|
for(uInt32 i = (0x1FE0 & ~System::PAGE_MASK); i < 0x2000;
|
||||||
i += (1 << System::PAGE_SHIFT))
|
i += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (i & 0x0FFF)];
|
||||||
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +94,8 @@ bool CartridgeEF::bank(uInt16 bank)
|
||||||
for(uInt32 address = 0x1000; address < (0x1FE0U & ~System::PAGE_MASK);
|
for(uInt32 address = 0x1000; address < (0x1FE0U & ~System::PAGE_MASK);
|
||||||
address += (1 << System::PAGE_SHIFT))
|
address += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
|
access.directPeekBase = &myImage[myBankOffset + (address & 0x0FFF)];
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (address & 0x0FFF)];
|
||||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
|
@ -105,7 +104,7 @@ bool CartridgeEF::bank(uInt16 bank)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 CartridgeEF::getBank() const
|
uInt16 CartridgeEF::getBank() const
|
||||||
{
|
{
|
||||||
return myCurrentBank;
|
return myBankOffset >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -117,7 +116,7 @@ uInt16 CartridgeEF::bankCount() const
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool CartridgeEF::patch(uInt16 address, uInt8 value)
|
bool CartridgeEF::patch(uInt16 address, uInt8 value)
|
||||||
{
|
{
|
||||||
myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
|
myImage[myBankOffset + (address & 0x0FFF)] = value;
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +133,7 @@ bool CartridgeEF::save(Serializer& out) const
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
out.putString(name());
|
out.putString(name());
|
||||||
out.putShort(myCurrentBank);
|
out.putShort(myBankOffset);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -153,7 +152,7 @@ bool CartridgeEF::load(Serializer& in)
|
||||||
if(in.getString() != name())
|
if(in.getString() != name())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
myCurrentBank = in.getShort();
|
myBankOffset = in.getShort();
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -162,7 +161,7 @@ bool CartridgeEF::load(Serializer& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember what bank we were in
|
// Remember what bank we were in
|
||||||
bank(myCurrentBank);
|
bank(myBankOffset >> 12);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,6 @@ class System;
|
||||||
There are 16 4K banks (total of 64K ROM).
|
There are 16 4K banks (total of 64K ROM).
|
||||||
Accessing $1FE0 - $1FEF switches to each bank.
|
Accessing $1FE0 - $1FEF switches to each bank.
|
||||||
|
|
||||||
This interpretation is based on analysis of the z26 assembly code,
|
|
||||||
as this scheme doesn't seem to be documented anywhere.
|
|
||||||
|
|
||||||
@author Stephen Anthony
|
@author Stephen Anthony
|
||||||
*/
|
*/
|
||||||
class CartridgeEF : public Cartridge
|
class CartridgeEF : public Cartridge
|
||||||
|
@ -155,8 +152,8 @@ class CartridgeEF : public Cartridge
|
||||||
// The 64K ROM image of the cartridge
|
// The 64K ROM image of the cartridge
|
||||||
uInt8 myImage[65536];
|
uInt8 myImage[65536];
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates the offset into the ROM image (aligns to current bank)
|
||||||
uInt16 myCurrentBank;
|
uInt16 myBankOffset;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
CartridgeEFSC::CartridgeEFSC(const BytePtr& image, uInt32 size,
|
CartridgeEFSC::CartridgeEFSC(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings),
|
||||||
myCurrentBank(0)
|
myBankOffset(0)
|
||||||
{
|
{
|
||||||
// Copy the ROM image into my buffer
|
// Copy the ROM image into my buffer
|
||||||
memcpy(myImage, image.get(), std::min(65536u, size));
|
memcpy(myImage, image.get(), std::min(65536u, size));
|
||||||
|
@ -95,7 +95,7 @@ uInt8 CartridgeEFSC::peek(uInt16 address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[myBankOffset + address];
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -119,8 +119,7 @@ bool CartridgeEFSC::bank(uInt16 bank)
|
||||||
if(bankLocked()) return false;
|
if(bankLocked()) return false;
|
||||||
|
|
||||||
// Remember what bank we're in
|
// Remember what bank we're in
|
||||||
myCurrentBank = bank;
|
myBankOffset = bank << 12;
|
||||||
uInt16 offset = myCurrentBank << 12;
|
|
||||||
|
|
||||||
System::PageAccess access(this, System::PA_READ);
|
System::PageAccess access(this, System::PA_READ);
|
||||||
|
|
||||||
|
@ -128,7 +127,7 @@ bool CartridgeEFSC::bank(uInt16 bank)
|
||||||
for(uInt32 i = (0x1FE0 & ~System::PAGE_MASK); i < 0x2000;
|
for(uInt32 i = (0x1FE0 & ~System::PAGE_MASK); i < 0x2000;
|
||||||
i += (1 << System::PAGE_SHIFT))
|
i += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (i & 0x0FFF)];
|
||||||
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,8 +135,8 @@ bool CartridgeEFSC::bank(uInt16 bank)
|
||||||
for(uInt32 address = 0x1100; address < (0x1FE0U & ~System::PAGE_MASK);
|
for(uInt32 address = 0x1100; address < (0x1FE0U & ~System::PAGE_MASK);
|
||||||
address += (1 << System::PAGE_SHIFT))
|
address += (1 << System::PAGE_SHIFT))
|
||||||
{
|
{
|
||||||
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
|
access.directPeekBase = &myImage[myBankOffset + (address & 0x0FFF)];
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (address & 0x0FFF)];
|
||||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||||
}
|
}
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
|
@ -146,7 +145,7 @@ bool CartridgeEFSC::bank(uInt16 bank)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 CartridgeEFSC::getBank() const
|
uInt16 CartridgeEFSC::getBank() const
|
||||||
{
|
{
|
||||||
return myCurrentBank;
|
return myBankOffset >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -168,7 +167,7 @@ bool CartridgeEFSC::patch(uInt16 address, uInt8 value)
|
||||||
myRAM[address & 0x007F] = value;
|
myRAM[address & 0x007F] = value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
myImage[(myCurrentBank << 12) + address] = value;
|
myImage[myBankOffset + address] = value;
|
||||||
|
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
}
|
}
|
||||||
|
@ -186,7 +185,7 @@ bool CartridgeEFSC::save(Serializer& out) const
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
out.putString(name());
|
out.putString(name());
|
||||||
out.putShort(myCurrentBank);
|
out.putShort(myBankOffset);
|
||||||
out.putByteArray(myRAM, 128);
|
out.putByteArray(myRAM, 128);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
|
@ -206,7 +205,7 @@ bool CartridgeEFSC::load(Serializer& in)
|
||||||
if(in.getString() != name())
|
if(in.getString() != name())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
myCurrentBank = in.getShort();
|
myBankOffset = in.getShort();
|
||||||
in.getByteArray(myRAM, 128);
|
in.getByteArray(myRAM, 128);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
|
@ -216,7 +215,7 @@ bool CartridgeEFSC::load(Serializer& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember what bank we were in
|
// Remember what bank we were in
|
||||||
bank(myCurrentBank);
|
bank(myBankOffset >> 12);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,7 @@ class System;
|
||||||
Cartridge class used for Homestar Runner by Paul Slocum.
|
Cartridge class used for Homestar Runner by Paul Slocum.
|
||||||
There are 16 4K banks (total of 64K ROM) with 128 bytes of RAM.
|
There are 16 4K banks (total of 64K ROM) with 128 bytes of RAM.
|
||||||
Accessing $1FE0 - $1FEF switches to each bank.
|
Accessing $1FE0 - $1FEF switches to each bank.
|
||||||
|
RAM read port is $1080 - $10FF, write port is $1000 - $107F.
|
||||||
This interpretation is based on analysis of the z26 assembly code,
|
|
||||||
as this scheme doesn't seem to be documented anywhere.
|
|
||||||
|
|
||||||
@author Stephen Anthony
|
@author Stephen Anthony
|
||||||
*/
|
*/
|
||||||
|
@ -158,8 +156,8 @@ class CartridgeEFSC : public Cartridge
|
||||||
// The 128 bytes of RAM
|
// The 128 bytes of RAM
|
||||||
uInt8 myRAM[128];
|
uInt8 myRAM[128];
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates the offset into the ROM image (aligns to current bank)
|
||||||
uInt16 myCurrentBank;
|
uInt16 myBankOffset;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
CartridgeF0::CartridgeF0(const BytePtr& image, uInt32 size,
|
CartridgeF0::CartridgeF0(const BytePtr& image, uInt32 size,
|
||||||
const Settings& settings)
|
const Settings& settings)
|
||||||
: Cartridge(settings),
|
: Cartridge(settings),
|
||||||
myCurrentBank(0)
|
myBankOffset(0)
|
||||||
{
|
{
|
||||||
// Copy the ROM image into my buffer
|
// Copy the ROM image into my buffer
|
||||||
memcpy(myImage, image.get(), std::min(65536u, size));
|
memcpy(myImage, image.get(), std::min(65536u, size));
|
||||||
|
@ -35,9 +35,8 @@ CartridgeF0::CartridgeF0(const BytePtr& image, uInt32 size,
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeF0::reset()
|
void CartridgeF0::reset()
|
||||||
{
|
{
|
||||||
// Upon reset we switch to bank 15
|
// Upon reset we switch to the startup bank
|
||||||
myCurrentBank = 14;
|
bank(myStartBank);
|
||||||
incbank();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -45,9 +44,8 @@ void CartridgeF0::install(System& system)
|
||||||
{
|
{
|
||||||
mySystem = &system;
|
mySystem = &system;
|
||||||
|
|
||||||
// Install pages for bank 1
|
// Install pages for the startup bank
|
||||||
myCurrentBank = 0;
|
bank(myStartBank);
|
||||||
incbank();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -59,7 +57,7 @@ uInt8 CartridgeF0::peek(uInt16 address)
|
||||||
if(address == 0x0FF0)
|
if(address == 0x0FF0)
|
||||||
incbank();
|
incbank();
|
||||||
|
|
||||||
return myImage[(myCurrentBank << 12) + address];
|
return myImage[myBankOffset + address];
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -77,32 +75,9 @@ bool CartridgeF0::poke(uInt16 address, uInt8)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void CartridgeF0::incbank()
|
void CartridgeF0::incbank()
|
||||||
{
|
{
|
||||||
if(bankLocked()) return;
|
// Determine current bank, and increment to the next one
|
||||||
|
uInt8 nextBank = ((myBankOffset >> 12) + 1) & 0x0F;
|
||||||
// Remember what bank we're in
|
bank(nextBank);
|
||||||
myCurrentBank++;
|
|
||||||
myCurrentBank &= 0x0F;
|
|
||||||
uInt16 offset = myCurrentBank << 12;
|
|
||||||
|
|
||||||
System::PageAccess access(this, System::PA_READ);
|
|
||||||
|
|
||||||
// Set the page accessing methods for the hot spots
|
|
||||||
for(uInt32 i = (0x1FF0 & ~System::PAGE_MASK); i < 0x2000;
|
|
||||||
i += (1 << System::PAGE_SHIFT))
|
|
||||||
{
|
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (i & 0x0FFF)];
|
|
||||||
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the page access methods for the current bank
|
|
||||||
for(uInt32 address = 0x1000; address < (0x1FF0U & ~System::PAGE_MASK);
|
|
||||||
address += (1 << System::PAGE_SHIFT))
|
|
||||||
{
|
|
||||||
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
|
|
||||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
|
||||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
|
||||||
}
|
|
||||||
myBankChanged = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -110,8 +85,27 @@ bool CartridgeF0::bank(uInt16 bank)
|
||||||
{
|
{
|
||||||
if(bankLocked()) return false;
|
if(bankLocked()) return false;
|
||||||
|
|
||||||
myCurrentBank = bank - 1;
|
// Remember what bank we're in
|
||||||
incbank();
|
myBankOffset = bank << 12;
|
||||||
|
|
||||||
|
System::PageAccess access(this, System::PA_READ);
|
||||||
|
|
||||||
|
// Set the page accessing methods for the hot spots
|
||||||
|
for(uInt32 i = (0x1FF0 & ~System::PAGE_MASK); i < 0x2000;
|
||||||
|
i += (1 << System::PAGE_SHIFT))
|
||||||
|
{
|
||||||
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (i & 0x0FFF)];
|
||||||
|
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the page access methods for the current bank
|
||||||
|
for(uInt32 address = 0x1000; address < (0x1FF0U & ~System::PAGE_MASK);
|
||||||
|
address += (1 << System::PAGE_SHIFT))
|
||||||
|
{
|
||||||
|
access.directPeekBase = &myImage[myBankOffset + (address & 0x0FFF)];
|
||||||
|
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (address & 0x0FFF)];
|
||||||
|
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||||
|
}
|
||||||
|
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
}
|
}
|
||||||
|
@ -119,7 +113,7 @@ bool CartridgeF0::bank(uInt16 bank)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt16 CartridgeF0::getBank() const
|
uInt16 CartridgeF0::getBank() const
|
||||||
{
|
{
|
||||||
return myCurrentBank;
|
return myBankOffset >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -131,7 +125,7 @@ uInt16 CartridgeF0::bankCount() const
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool CartridgeF0::patch(uInt16 address, uInt8 value)
|
bool CartridgeF0::patch(uInt16 address, uInt8 value)
|
||||||
{
|
{
|
||||||
myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
|
myImage[myBankOffset + (address & 0x0FFF)] = value;
|
||||||
return myBankChanged = true;
|
return myBankChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +142,7 @@ bool CartridgeF0::save(Serializer& out) const
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
out.putString(name());
|
out.putString(name());
|
||||||
out.putShort(myCurrentBank);
|
out.putShort(myBankOffset);
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -167,7 +161,7 @@ bool CartridgeF0::load(Serializer& in)
|
||||||
if(in.getString() != name())
|
if(in.getString() != name())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
myCurrentBank = in.getShort();
|
myBankOffset = in.getShort();
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
@ -176,8 +170,7 @@ bool CartridgeF0::load(Serializer& in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember what bank we were in
|
// Remember what bank we were in
|
||||||
--myCurrentBank;
|
bank(myBankOffset >> 12);
|
||||||
incbank();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,8 +158,8 @@ class CartridgeF0 : public Cartridge
|
||||||
// The 64K ROM image of the cartridge
|
// The 64K ROM image of the cartridge
|
||||||
uInt8 myImage[65536];
|
uInt8 myImage[65536];
|
||||||
|
|
||||||
// Indicates which bank is currently active
|
// Indicates the offset into the ROM image (aligns to current bank)
|
||||||
uInt16 myCurrentBank;
|
uInt16 myBankOffset;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
Loading…
Reference in New Issue