This commit is contained in:
Thomas Jentzsch 2020-04-16 15:46:59 +02:00
commit c06658a275
148 changed files with 26449 additions and 5118 deletions

2
.gitignore vendored
View File

@ -31,3 +31,5 @@ src/**/*.psess
src/**/*.vspx
src/**/**.pdb
Stella.xcscheme
src/tools/fonts/*

View File

@ -12,7 +12,43 @@
Release History
===========================================================================
6.0.2 to 6.1: (MM dd, 2020)
6.1 to 6.2: (??? ??, 2020)
* Added that paddle centering and sensitivity can be adjusted (TODO: Doc)
* Added that Driving controller sensitivity can be adjusted (TODO: Doc)
* Added high scores: Score addresses, game variation etc. can be defined for
a game. This allows the user to save high scores for these games. For each
game and variation, the top 10 scores can be saved. (TODO: Doc)
* Add option which lets default ROM path follow launcher navigation (TODO: Doc)
* Added displaying last write address in the debugger.
* Added detection of color and audio data in DiStella.
* Restored 'cfg' directory for Distella config files.
-Have fun!
6.1 to 6.1.1: (April 4, 2020)
* Fixed crash in 3E bankswitching scheme when writing to ROM addresses.
* Fix snapshots on Retina HiDPI displays capturing only the top-left
corner.
* Fixed wrong color for BK (background) swatch in the debugger.
* Fixed 'Right Diff' button in Command menu changing left difficulty
instead.
* Fixed compilation of libretro port on Debian Buster.
6.0.2 to 6.1: (March 22, 2020)
* IMPORTANT NOTES:
- Because of major event remapping changes, all remappings will be reset
@ -119,7 +155,9 @@
* Added option to change pitch of Pitfall II music.
* ROM Info Launcher can now display multiple lines per property and
* ROM Info Viewer size is not limited to fixed zoom steps anymore.
* ROM Info Viewer can now display multiple lines per property and the
bank switching type.
* In file listings, you can now select directories by holding 'Shift' on
@ -179,6 +217,10 @@
* Fixed bug in DPC+ scheme; 'fast fetch mode' was enabled at startup,
when it should be disabled by default.
* Some more work on DPC+ playfield 'jitter' effect for certain older DPC+
driver versions; more ROMs are now detected properly. Special thanks
to SpiceWare for his research in this area.
* Added proper Retron77 port.
* Added proper libretro port, and fixed display for OpenGLES renderers.
@ -192,7 +234,8 @@
* Updated included PNG library to latest stable version.
-Have fun!
* Updated UNIX configure script to work with the gcc version 10 and
above.
6.0.1 to 6.0.2: (October 11, 2019)

12
configure vendored
View File

@ -458,11 +458,17 @@ elif test "$have_gcc" = yes; then
fi
case $cxx_version in
4.[7-9]|4.[7-9].[0-9]|4.[7-9].[0-9][-.]*|[5-9]|[5-9].[0-9]|[5-9].[0-9].[0-9]|[5-9].[0-9].[0-9][-.]*)
[1-9]*)
_cxx_major=`echo $cxx_version | cut -d '.' -f 1`
_cxx_minor=`echo $cxx_version | cut -d '.' -f 2`
cxx_version="$cxx_version, ok"
cxx_verc_fail=no
# Need at least version 4.7
if [ $_cxx_major -ge 5 ] || [ $_cxx_major -eq 4 -a $_cxx_minor -ge 7 ]; then
cxx_version="$cxx_version, ok"
cxx_verc_fail=no
else
cxx_version="$cxx_version, bad"
cxx_verc_fail=yes
fi
;;
'not found')
cxx_verc_fail=yes

14
debian/changelog vendored
View File

@ -1,3 +1,17 @@
stella (6.1.1-1) stable; urgency=high
* Version 6.1.1 release
-- Stephen Anthony <sa666666@gmail.com> Sat, 04 Apr 2020 17:09:59 -0230
stella (6.1-1) stable; urgency=high
* Version 6.1 release
-- Stephen Anthony <sa666666@gmail.com> Sun, 22 Mar 2020 17:09:59 -0230
stella (6.0.2-1) stable; urgency=high
* Version 6.0.2 release

View File

@ -121,13 +121,14 @@ feature that no other 2600 debugger has; it's <b>completely</b> cross-platform.<
<li>Supports Distella 'configuration directives', which may be used to
override automatic code/data determination in the disassembly. For now,
the following directives are supported: CODE, GFX, PGFX, DATA, ROW.
These directives can be entered at the debugger prompt, or (automatically)
the following directives are supported: CODE, GFX, PGFX, COL, PCOL, BCOL, AUD, DATA, ROW.
These directives can be entered at the debugger prompt, or be (automatically)
loaded and saved in configuration files.</li>
<li>Extensive disassembly support, both from the emulation core and with help
from Distella. Where possible, the disassembly differentiates between code,
player graphics and playfield graphics (ie, addresses stored in GRPx and PFx)
player and playfield graphics, colors and audio (ie, addresses stored in
GRPx, PFx, COLUxx, AUDxx)
and data (addresses used as an operand of a command). Code sections are also
differentiated between actual code, and 'tentative' code (ie, areas that may
represent code sections, but haven't actually been executed yet). Such
@ -906,7 +907,9 @@ Type "help 'cmd'" to see extended information about the given command.</p>
<pre>
a - Set Accumulator to &lt;value&gt;
aud - Mark 'AUD' range in disassembly
base - Set default number base to &lt;base&gt; (bin, dec, hex)
bcol - Mark 'BCOL' range in disassembly
break - Set/clear breakpoint at &lt;address&gt; and &lt;bank&gt;
breakif - Set/clear breakpoint on &lt;condition&gt;
breaklabel - Set/clear breakpoint on &lt;address&gt; (no mirrors, all banks)
@ -919,6 +922,7 @@ clearsavestateifs - Clear all savestate points
clearwatches - Clear all watches
cls - Clear prompt area of text
code - Mark 'CODE' range in disassembly
col - Mark 'COL' range in disassembly
colortest - Show value xx as TIA color
d - Decimal Mode Flag: set (0 or 1), or toggle (no arg)
data - Mark 'DATA' range in disassembly
@ -959,6 +963,7 @@ clearsavestateifs - Clear all savestate points
n - Negative Flag: set (0 or 1), or toggle (no arg)
palette - Show current TIA palette
pc - Set Program Counter to address xx
pcol - Mark 'PCOL' range in disassembly
pgfx - Mark 'PGFX' range in disassembly
print - Evaluate/print expression xx in hex/dec/binary
ram - Show ZP RAM, or set address xx to yy1 [yy2 ...]
@ -1193,6 +1198,8 @@ the reason will be shown as follows:
<li>"WTrap:" for write traps</li>
<li>"RTrapIf:" for conditional read traps</li>
<li>"WTrapIf:" for conditional write traps</li>
<li>"RWP:" for reads from write ports</li>
<li>"WRP:" for writes to read ports</li>
</ul>
</p>
See the <a href="#BreakpointsEtc"><b>Breakpoints, watches and traps...</b></a>
@ -1215,6 +1222,8 @@ registers. For example, consider the command 'LDA ($80),Y'. The operand of
the command resolves to some address, which isn't always easy to determine at
first glance. The 'Src Addr' area shows the actual resulting operand/address
being used with the given opcode.</p>
<p>The destination address of the last write is shown besides 'Dest'.</p>
<p>There's not much else to say about the CPU Registers widget: if you know 6502
assembly, it's pretty self-explanatory. If you don't, well, you should
learn :)</p>
@ -1369,21 +1378,78 @@ can use. These are known as 'directives', and partly correspond to configuration
options from the standalone Distella program. They are listed in order of
decreasing hierarchy:</p>
<table border="1" cellpadding=4>
<tr><td><b>CODE</b></td><td>Addresses which have appeared in the program counter, or
which tentatively can appear in the program counter. These can be edited in hex.</td></tr>
<tr><td><b>GFX</b></td><td>Addresses which contain data stored in the player graphics registers
(GRP0/GRP1). These addresses are shown with a bitmap of the graphics, which
can be edited in either hex or binary. The bitmap is shown as large blocks.</td></tr>
<tr><td><b>PGFX</b></td><td>Addresses which contain data stored in the playfield graphics registers
(PF0/PF1/PF2). These addresses are shown with a bitmap of the graphics, which
can be edited in either hex or binary. The bitmap is shown as small dashes.</td></tr>
<tr><td><b>DATA</b></td><td>Addresses used as an operand for some opcode. These can be edited
in hex.</td></tr>
<tr><td><b>ROW</b></td><td>Addresses not used as any of the above. These are shown up
to 8 per line, and cannot be edited.</td></tr>
<tr>
<td>
<b>CODE</b>
</td><td>
Addresses which have appeared in the program counter, or
which tentatively can appear in the program counter. These can be edited in hex.
</td>
</tr><tr>
<td>
<b>GFX</b>
</td><td>
Addresses which contain data stored in the player graphics registers
(GRP0/GRP1). These addresses are shown with a bitmap of the graphics, which
can be edited in either hex or binary. The bitmap is shown as large blocks.
</td>
</tr><tr>
<td>
<b>PGFX</b>
</td><td>
Addresses which contain data stored in the playfield graphics registers
(PF0/PF1/PF2). These addresses are shown with a bitmap of the graphics, which
can be edited in either hex or binary. The bitmap is shown as small dashes.
</td>
</tr><tr>
<td>
<b>COL</b>
</td><td>
Addresses which contain data stored in the player color registers
(COLUP0/COLUP1). These addresses are shown as color constants, which
can be edited in hex. The color constant names are depending on the ROM's TV type.
</td>
</tr><tr>
<td>
<b>PCOL</b>
</td><td>
Addresses which contain data stored in the playfield color register
(COLUPF). These addresses are shown as color constants, which
can be edited in hex. The color constant names are depending on the ROM's TV type.
</td>
</tr><tr>
<td>
<b>BCOL</b>
</td><td>
Addresses which contain data stored in the background color register
(COLUBK). These addresses are shown as color constants, which
can be edited in hex. The color constant names are depending on the ROM's TV type.
</td>
</tr><tr>
<td>
<b>AUD</b>
</td><td>
Addresses which contain data stored in the audio registers
(AUDC0/AUDC1/AUDF0/AUDF1/AUDV0/AUDV1). These can be edited
in hex.
</td>
</tr><tr>
<td>
<b>DATA</b>
</td><td>
Addresses used as an operand for some opcode. These can be edited
in hex.
</td>
</tr><tr>
<td>
<b>ROW</b>
</td><td>
Addresses not used as any of the above. These are shown up
to 8 per line and cannot be edited.
</td>
</tr>
</table>
<p>For code sections, the 6502 mnemonic will be UPPERCASE for all standard instructions,
or lowercase for "illegal" 6502 instructions (like "dcp"). If automatic resolving
of code sections has been disabled for any reason, you'll likely see a lot
@ -1445,7 +1511,8 @@ isn't already a defined label).</li>
in either binary or hexidecimal.</li>
<li><b>Use address relocation</b>: Corresponds to the Distella '-r' option
(Relocate calls out of address range).</li>
(Relocate calls out of address range).</br>
Note: The code will continue to run fine, but the ROM image will be altered.</li>
</ul>
@ -1520,12 +1587,12 @@ the RAM in the DPC scheme is not viewable by the 6507, so its addresses start fr
<br>
<h1><a name="DistellaConfiguration">Distella Configuration Files</a></h1>
<p>As mentioned in <a href="#Disassembly"><b>ROM Disassembly</b></a>, Stella supports the following directives:
CODE/GFX/PGFX/DATA/ROW. While the debugger will try to automatically mark address
CODE, GFX, PGFX, COL, PCOL, BCOL, AUD, DATA, ROW. While the debugger will try to automatically mark address
space with the appropriate directive, there are times when it will fail. There are
several options in this case:</p>
<ol>
<li><b>Manually set the directives</b>: Directives can be set in the debugger
prompt with the code/gfx/pgfx/data/row commands. These accept an address range
prompt with the aud/code/col/bcol/gfx/pcol/pgfx/data/row commands. These accept an address range
for the given directive type. Setting a range with the same type a second time
will remove that directive from the range.</li>
<li><b>Use configuration files</b>: Configuration files can be used to automatically

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -70,7 +70,7 @@
<br><br><br>
<center><b>February 1999 - January 2020</b></center>
<center><b>February 1999 - March 2020</b></center>
<center><b>The Stella Team</b></center>
<center><b><a href="https://stella-emu.github.io">Stella Homepage</a></b></center>
@ -2371,7 +2371,7 @@
</tr>
<tr>
<td><pre>-launcherfont &lt;small|medium|large&gt;</pre></td>
<td><pre>-launcherfont &lt;small|low_medium|medium|large|large12|large14|large16&gt;</pre></td>
<td>Set the size of the font in the ROM launcher.</td>
</tr>
@ -2382,9 +2382,10 @@
</tr>
<tr>
<td><pre>-romviewer &lt;0|1|2&gt;</pre></td>
<td>Hide ROM Info Viewer in ROM launcher mode (0), or use the
given zoom level (1 or 2).</td>
<td><pre>-romviewer &lt;float&gt;</pre></td>
<td>Hide ROM Info Viewer in ROM launcher mode (0) or use the
given zoom level.</br>
Note: The zoom level is converted into a percentage in the UI.</td>
</tr>
<tr>
@ -3079,8 +3080,8 @@
launcher and fonts, as well as the 'ROM Info Viewer' can be changed in
<b>UI Settings - Launcher</b> dialog, as shown below:</p>
<img src="graphics/options_ui.png">
<p>Most of the options are self-explanatory, except for the 'ROM Info
viewer', which is described below.</p>
<p>Most of the options are self-explanatory, except for the 'ROM info
width', which is described below.</p>
<h3><b><a name="ROMInfoViewer">ROM Info Viewer</a></b></h3>
@ -3092,27 +3093,21 @@
for each new release of Stella. Note that the snapshots can be any size
generated by Stella; they will be resized accordingly.</p>
<p>Currently, there are several restrictions for this feature:</p>
<ol>
<li>The ROM Info Viewer can be shown in 1x or 2x mode only.</li>
<li>To view snapshots in 1x mode, the ROM launcher window must be sized at
least 640x480. If the launcher isn't large enough, the functionality
will be disabled.</li>
<li>To view snapshots in 2x mode, the ROM launcher window must be sized at
least 1000x720. If the launcher isn't large enough, an attempt will
be made to use 1x mode.</li>
</ol>
The ROM Info Viewer's width can be defined between 0% (off) and 100%. The
value is relative to the launcher width. For too small or too large values,
Stella will automatically correct the width at runtime so that the ROM names
and the current ROM's information always have enough space.
<p>The following snapshots illustrate the various font sizes and rom info
zoom levels:</p>
widths:</p>
<p>ROM Info Viewer in 1x mode, UI sized 800x480, small launcher font:</p>
<p>ROM Info Viewer width at 40%, UI sized 800x480, small launcher font:</p>
<img src="graphics/rominfo_1x_small.png">
<p>ROM Info Viewer in 1x mode, UI sized 1000x720, medium launcher font:</p>
<p>ROM Info Viewer width at 32%, UI sized 1000x720, medium launcher font:</p>
<img src="graphics/rominfo_1x_large.png">
<p>ROM Info Viewer in 2x mode, UI sized 1280x900, large launcher font:</p>
<p>ROM Info Viewer width at 50% , UI sized 1280x900, large launcher font:</p>
<img src="graphics/rominfo_2x_small.png">
<p>The text box in the upper right corner can be used to narrow down the

View File

@ -58,7 +58,7 @@
<center><h1>Stella for RetroN 77</h1></center>
<center><h2>Atari 2600 VCS emulator</h2></center>
<center>Release 6.1 Beta 1</center>
<center>Release 6.1</center>
<center><h2>Quick Navigation Guide</h2></center>
<br/>

View File

@ -137,12 +137,12 @@ class FrameBufferSDL2 : public FrameBuffer
/**
Transform from window to renderer coordinates, x direction
*/
int scaleX(int x) const { return (x * myRenderW) / myWindowW; }
int scaleX(int x) const override { return (x * myRenderW) / myWindowW; }
/**
Transform from window to renderer coordinates, y direction
*/
int scaleY(int y) const { return (y * myRenderH) / myWindowH; }
int scaleY(int y) const override { return (y * myRenderH) / myWindowH; }
protected:
//////////////////////////////////////////////////////////////////////

View File

@ -49,7 +49,7 @@
*/
namespace Common {
template <class T, uInt32 CAPACITY = 100>
template <typename T, uInt32 CAPACITY = 100>
class LinkedObjectPool
{
public:

View File

@ -124,7 +124,7 @@ MouseControl::MouseControl(Console& console, const string& mode)
int m_range = 100;
if(!(m_axis >> m_range))
m_range = 100;
Paddles::setPaddleRange(m_range);
Paddles::setDigitalPaddleRange(m_range);
// If the mouse isn't used at all, we still need one item in the list
if(myModeList.size() == 0)

View File

@ -29,6 +29,7 @@
#include "TIASurface.hxx"
#include "Version.hxx"
#include "PNGLibrary.hxx"
#include "Rect.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PNGLibrary::PNGLibrary(OSystem& osystem)
@ -129,7 +130,13 @@ void PNGLibrary::saveImage(const string& filename, const VariantList& comments)
throw runtime_error("ERROR: Couldn't create snapshot file");
const FrameBuffer& fb = myOSystem.frameBuffer();
const Common::Rect& rect = fb.imageRect();
const Common::Rect& rectUnscaled = fb.imageRect();
const Common::Rect rect(
Common::Point(fb.scaleX(rectUnscaled.x()), fb.scaleY(rectUnscaled.y())),
fb.scaleX(rectUnscaled.w()), fb.scaleY(rectUnscaled.h())
);
png_uint_32 width = rect.w(), height = rect.h();
// Get framebuffer pixel data (we get ABGR format)

View File

@ -27,7 +27,7 @@
*/
namespace Common {
template <class T, uInt32 CAPACITY = 50>
template <typename T, uInt32 CAPACITY = 50>
class FixedStack
{
private:

View File

@ -18,7 +18,7 @@
#ifndef STATE_MANAGER_HXX
#define STATE_MANAGER_HXX
#define STATE_HEADER "06000008state"
#define STATE_HEADER "06010000state"
class OSystem;
class RewindManager;

View File

@ -22,19 +22,19 @@
namespace Vec {
template<class T>
template<typename T>
void append(vector<T>& dst, const vector<T>& src)
{
dst.insert(dst.cend(), src.cbegin(), src.cend());
}
template<class T>
template<typename T>
void insertAt(vector<T>& dst, uInt32 idx, const T& element)
{
dst.insert(dst.cbegin()+idx, element);
}
template<class T>
template<typename T>
void removeAt(vector<T>& dst, uInt32 idx)
{
dst.erase(dst.cbegin()+idx);

View File

@ -18,7 +18,7 @@
#ifndef VERSION_HXX
#define VERSION_HXX
#define STELLA_VERSION "6.1_rc1"
#define STELLA_BUILD "5657"
#define STELLA_VERSION "6.2_pre"
#define STELLA_BUILD "5741"
#endif

View File

@ -119,16 +119,16 @@ namespace BSPF
#endif
// Make 2D-arrays using std::array less verbose
template<class T, size_t ROW, size_t COL>
template<typename T, size_t ROW, size_t COL>
using array2D = std::array<std::array<T, COL>, ROW>;
// Combines 'max' and 'min', and clamps value to the upper/lower value
// if it is outside the specified range
template<class T> inline T clamp(T val, T lower, T upper)
template<typename T> inline T clamp(T val, T lower, T upper)
{
return (val < lower) ? lower : (val > upper) ? upper : val;
}
template<class T> inline void clamp(T& val, T lower, T upper, T setVal)
template<typename T> inline void clamp(T& val, T lower, T upper, T setVal)
{
if(val < lower || val > upper) val = setVal;
}

View File

@ -32,7 +32,10 @@
#include "CartRamWidget.hxx"
#include "RomWidget.hxx"
#include "Base.hxx"
#include "Device.hxx"
#include "exception/EmulationWarning.hxx"
#include "TIA.hxx"
#include "M6532.hxx"
using Common::Base;
using std::hex;
@ -68,16 +71,12 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
}
// Create bank information for each potential bank, and an extra one for ZP RAM
// Banksizes greater than 4096 indicate multi-bank ROMs, but we handle only
// 4K pieces at a time
// Banksizes less than 4K use the actual value
size_t banksize = 0;
myConsole.cartridge().getImage(banksize);
BankInfo info;
info.size = std::min<size_t>(banksize, 4_KB);
for(uInt32 i = 0; i < myConsole.cartridge().bankCount(); ++i)
{
info.size = myConsole.cartridge().bankSize(i);
myBankInfo.push_back(info);
}
info.size = 128; // ZP RAM
myBankInfo.push_back(info);
@ -85,7 +84,7 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
// We know the address for the startup bank right now
myBankInfo[myConsole.cartridge().startBank()].addressList.push_front(
myDebugger.dpeek(0xfffc));
addLabel("Start", myDebugger.dpeek(0xfffc, DATA));
addLabel("Start", myDebugger.dpeek(0xfffc, Device::DATA)); // TOOD: ::CODE???
// Add system equates
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
@ -156,6 +155,18 @@ void CartDebug::saveOldState()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartDebug::lastReadAddress()
{
return mySystem.m6502().lastReadAddress();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartDebug::lastWriteAddress()
{
return mySystem.m6502().lastWriteAddress();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int CartDebug::lastReadBaseAddress()
{
@ -225,11 +236,29 @@ string CartDebug::toString()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDebug::disassemble(bool force)
{
uInt16 PC = myDebugger.cpuDebug().pc();
int bank = (PC & 0x1000) ? getBank(PC) : int(myBankInfo.size()) - 1;
return disassemble(bank, PC, force);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDebug::disassembleBank(int bank)
{
BankInfo& info = myBankInfo[bank];
info.offset = myConsole.cartridge().bankOrigin(bank);
return disassemble(bank, info.offset, true);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDebug::disassemble(int bank, uInt16 PC, bool force)
{
// Test current disassembly; don't re-disassemble if it hasn't changed
// Also check if the current PC is in the current list
bool bankChanged = myConsole.cartridge().bankChanged();
uInt16 PC = myDebugger.cpuDebug().pc();
int pcline = addressToLine(PC);
bool pcfound = (pcline != -1) && (uInt32(pcline) < myDisassembly.list.size()) &&
(myDisassembly.list[pcline].disasm[0] != '.');
@ -241,8 +270,9 @@ bool CartDebug::disassemble(bool force)
if(changed)
{
// Are we disassembling from ROM or ZP RAM?
BankInfo& info = (PC & 0x1000) ? myBankInfo[getBank(PC)] :
myBankInfo[myBankInfo.size()-1];
BankInfo& info = myBankInfo[bank];
//(PC & 0x1000) ? myBankInfo[getBank(PC)] :
//myBankInfo[myBankInfo.size()-1];
// If the offset has changed, all old addresses must be 'converted'
// For example, if the list contains any $fxxx and the address space is now
@ -304,8 +334,8 @@ bool CartDebug::fillDisassemblyList(BankInfo& info, uInt16 search)
const DisassemblyTag& tag = myDisassembly.list[i];
const uInt16 address = tag.address & 0xFFF;
// Exclude 'ROW'; they don't have a valid address
if(tag.type != CartDebug::ROW)
// Exclude 'Device::ROW'; they don't have a valid address
if(tag.type != Device::ROW)
{
// Create a mapping from addresses to line numbers
myAddrToLineList.emplace(address, i);
@ -331,7 +361,7 @@ int CartDebug::addressToLine(uInt16 address) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::disassemble(uInt16 start, uInt16 lines) const
string CartDebug::disassembleLines(uInt16 start, uInt16 lines) const
{
// Fill the string with disassembled data
start &= 0xFFF;
@ -346,7 +376,7 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
if((tag.address & 0xfff) >= start)
{
if(begin == list_size) begin = end;
if(tag.type != CartDebug::ROW)
if(tag.type != Device::ROW)
length = std::max(length, uInt32(tag.disasm.length()));
--lines;
@ -357,7 +387,7 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
for(uInt32 i = begin; i < end; ++i)
{
const CartDebug::DisassemblyTag& tag = myDisassembly.list[i];
if(tag.type == CartDebug::NONE)
if(tag.type == Device::NONE)
continue;
else if(tag.address)
buffer << std::uppercase << std::hex << std::setw(4)
@ -374,7 +404,7 @@ string CartDebug::disassemble(uInt16 start, uInt16 lines) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartDebug::addDirective(CartDebug::DisasmType type,
bool CartDebug::addDirective(Device::AccessType type,
uInt16 start, uInt16 end, int bank)
{
if(end < start || start == 0 || end == 0)
@ -813,12 +843,13 @@ string CartDebug::loadSymbolFile()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::loadConfigFile()
{
// The default naming/location for config files is the ROM dir based on the
// actual ROM filename
// The default naming/location for config files is the CFG dir and based
// on the actual ROM filename
if(myCfgFile == "")
{
FilesystemNode cfg(myOSystem.romFile().getPathWithExt("") + ".cfg");
FilesystemNode romNode(myOSystem.romFile().getPathWithExt("") + ".cfg");
FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName());
if(cfg.isFile() && cfg.isReadable())
myCfgFile = cfg.getPath();
else
@ -876,28 +907,48 @@ string CartDebug::loadConfigFile()
else if(BSPF::startsWithIgnoreCase(directive, "CODE"))
{
buf >> hex >> start >> hex >> end;
addDirective(CartDebug::CODE, start, end, currentbank);
addDirective(Device::CODE, start, end, currentbank);
}
else if(BSPF::startsWithIgnoreCase(directive, "GFX"))
{
buf >> hex >> start >> hex >> end;
addDirective(CartDebug::GFX, start, end, currentbank);
addDirective(Device::GFX, start, end, currentbank);
}
else if(BSPF::startsWithIgnoreCase(directive, "PGFX"))
{
buf >> hex >> start >> hex >> end;
addDirective(CartDebug::PGFX, start, end, currentbank);
addDirective(Device::PGFX, start, end, currentbank);
}
else if(BSPF::startsWithIgnoreCase(directive, "COL"))
{
buf >> hex >> start >> hex >> end;
addDirective(Device::COL, start, end, currentbank);
}
else if(BSPF::startsWithIgnoreCase(directive, "PCOL"))
{
buf >> hex >> start >> hex >> end;
addDirective(Device::PCOL, start, end, currentbank);
}
else if(BSPF::startsWithIgnoreCase(directive, "BCOL"))
{
buf >> hex >> start >> hex >> end;
addDirective(Device::BCOL, start, end, currentbank);
}
else if(BSPF::startsWithIgnoreCase(directive, "AUD"))
{
buf >> hex >> start >> hex >> end;
addDirective(Device::AUD, start, end, currentbank);
}
else if(BSPF::startsWithIgnoreCase(directive, "DATA"))
{
buf >> hex >> start >> hex >> end;
addDirective(CartDebug::DATA, start, end, currentbank);
addDirective(Device::DATA, start, end, currentbank);
}
else if(BSPF::startsWithIgnoreCase(directive, "ROW"))
{
buf >> hex >> start;
buf >> hex >> end;
addDirective(CartDebug::ROW, start, end, currentbank);
addDirective(Device::ROW, start, end, currentbank);
}
}
}
@ -914,14 +965,14 @@ string CartDebug::loadConfigFile()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::saveConfigFile()
{
// The default naming/location for config files is the ROM dir based on the
// actual ROM filename
// The default naming/location for config files is the CFG dir and based
// on the actual ROM filename
FilesystemNode cfg;
if(myCfgFile == "")
{
cfg = FilesystemNode(myOSystem.romFile().getPathWithExt("") + ".cfg");
if(cfg.isFile() && cfg.isWritable())
FilesystemNode romNode(myOSystem.romFile().getPathWithExt("") + ".cfg");
FilesystemNode cfg(myOSystem.cfgDir() + romNode.getName());
if(cfg.getParent().isWritable())
myCfgFile = cfg.getPath();
else
return DebuggerParser::red("config file \'" + cfg.getShortPath() + "\' not writable");
@ -930,13 +981,14 @@ string CartDebug::saveConfigFile()
const string& name = myConsole.properties().get(PropType::Cart_Name);
const string& md5 = myConsole.properties().get(PropType::Cart_MD5);
FilesystemNode cfg(myCfgFile);
ofstream out(cfg.getPath());
if(!out.is_open())
return "Unable to save directives to " + cfg.getShortPath();
// Store all bank information
out << "//Stella.pro: \"" << name << "\"" << endl
<< "//MD5: " << md5 << endl
out << "// Stella.pro: \"" << name << "\"" << endl
<< "// MD5: " << md5 << endl
<< endl;
for(uInt32 b = 0; b < myConsole.cartridge().bankCount(); ++b)
{
@ -954,6 +1006,25 @@ string CartDebug::saveConfigFile()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::saveDisassembly()
{
string NTSC_COLOR[16] = {
"BLACK", "YELLOW", "BROWN", "ORANGE",
"RED", "MAUVE", "VIOLET", "PURPLE",
"BLUE", "BLUE_CYAN", "CYAN", "CYAN_GREEN",
"GREEN", "GREEN_YELLOW", "GREEN_BEIGE", "BEIGE"
};
string PAL_COLOR[16] = {
"BLACK0", "BLACK1", "YELLOW", "GREEN_YELLOW",
"ORANGE", "GREEN", "RED", "CYAN_GREEN",
"MAUVE", "CYAN", "VIOLET", "BLUE_CYAN",
"PURPLE", "BLUE", "BLACKE", "BLACKF"
};
string SECAM_COLOR[8] = {
"BLACK", "BLUE", "RED", "PURPLE",
"GREEN", "CYAN", "YELLOW", "WHITE"
};
bool isNTSC = myConsole.timing() == ConsoleTiming::ntsc;
bool isPAL = myConsole.timing() == ConsoleTiming::pal;
if(myDisasmFile == "")
{
const string& propsname =
@ -972,11 +1043,6 @@ string CartDebug::saveDisassembly()
// We can't print the header to the disassembly until it's actually
// been processed; therefore buffer output to a string first
ostringstream buf;
buf << "\n\n;***********************************************************\n"
<< "; Bank " << myConsole.cartridge().getBank();
if (myConsole.cartridge().bankCount() > 1)
buf << " / 0.." << myConsole.cartridge().bankCount() - 1;
buf << "\n;***********************************************************\n\n";
// Use specific settings for disassembly output
// This will most likely differ from what you see in the debugger
@ -992,13 +1058,35 @@ string CartDebug::saveDisassembly()
Disassembly disasm;
disasm.list.reserve(2048);
for(int bank = 0; bank < myConsole.cartridge().bankCount(); ++bank)
uInt16 bankCount = myConsole.cartridge().bankCount();
uInt16 oldBank = myConsole.cartridge().getBank();
// prepare for switching banks
myConsole.cartridge().unlockBank();
uInt32 origin = 0;
for(int bank = 0; bank < bankCount; ++bank)
{
// TODO: not every CartDebugWidget does it like that, we need a method
myConsole.cartridge().unlockBank();
myConsole.cartridge().bank(bank);
myConsole.cartridge().lockBank();
BankInfo& info = myBankInfo[bank];
disassembleBank(bank);
// An empty address list means that DiStella can't do a disassembly
if(info.addressList.size() == 0)
continue;
buf << "\n\n;***********************************************************\n"
<< "; Bank " << bank;
if (bankCount > 1)
buf << " / 0.." << bankCount - 1;
buf << "\n;***********************************************************\n\n";
// Disassemble bank
disasm.list.clear();
DiStella distella(*this, disasm.list, info, settings,
@ -1007,8 +1095,14 @@ string CartDebug::saveDisassembly()
if (myReserved.breakFound)
addLabel("Break", myDebugger.dpeek(0xfffe));
buf << " SEG CODE\n"
<< " ORG $" << Base::HEX4 << info.offset << "\n\n";
buf << " SEG CODE\n";
if(bankCount == 1)
buf << " ORG $" << Base::HEX4 << info.offset << "\n\n";
else
buf << " ORG $" << Base::HEX4 << origin << "\n"
<< " RORG $" << Base::HEX4 << info.offset << "\n\n";
origin += uInt32(info.size);
// Format in 'distella' style
for(uInt32 i = 0; i < disasm.list.size(); ++i)
@ -1022,50 +1116,62 @@ string CartDebug::saveDisassembly()
switch(tag.type)
{
case CartDebug::CODE:
{
case Device::CODE:
buf << ALIGN(32) << tag.disasm << tag.ccount.substr(0, 5) << tag.ctotal << tag.ccount.substr(5, 2);
if (tag.disasm.find("WSYNC") != std::string::npos)
buf << "\n;---------------------------------------";
break;
}
case CartDebug::ROW:
{
case Device::ROW:
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8*4-1) << "; $" << Base::HEX4 << tag.address << " (*)";
break;
}
case CartDebug::GFX:
{
case Device::GFX:
buf << ".byte " << (settings.gfxFormat == Base::Fmt::_2 ? "%" : "$")
<< tag.bytes << " ; |";
for(int c = 12; c < 20; ++c)
buf << ((tag.disasm[c] == '\x1e') ? "#" : " ");
buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (G)";
break;
}
case CartDebug::PGFX:
{
case Device::PGFX:
buf << ".byte " << (settings.gfxFormat == Base::Fmt::_2 ? "%" : "$")
<< tag.bytes << " ; |";
for(int c = 12; c < 20; ++c)
buf << ((tag.disasm[c] == '\x1f') ? "*" : " ");
buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (P)";
break;
}
case CartDebug::DATA:
{
case Device::COL:
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 15) << "; $" << Base::HEX4 << tag.address << " (C)";
break;
case Device::PCOL:
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 15) << "; $" << Base::HEX4 << tag.address << " (CP)";
break;
case Device::BCOL:
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 15) << "; $" << Base::HEX4 << tag.address << " (CB)";
break;
case Device::AUD:
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (A)";
break;
case Device::DATA:
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)";
break;
}
case CartDebug::NONE:
case Device::NONE:
default:
{
break;
}
} // switch
buf << "\n";
}
}
myConsole.cartridge().unlockBank();
myConsole.cartridge().bank(oldBank);
myConsole.cartridge().lockBank();
// Some boilerplate, similar to what DiStella adds
auto timeinfo = BSPF::localTime();
@ -1075,23 +1181,49 @@ string CartDebug::saveDisassembly()
<< "; ROM properties name : " << myConsole.properties().get(PropType::Cart_Name) << "\n"
<< "; ROM properties MD5 : " << myConsole.properties().get(PropType::Cart_MD5) << "\n"
<< "; Bankswitch type : " << myConsole.cartridge().about() << "\n;\n"
<< "; Legend: * = CODE not yet run (tentative code)\n"
<< "; D = DATA directive (referenced in some way)\n"
<< "; G = GFX directive, shown as '#' (stored in player, missile, ball)\n"
<< "; P = PGFX directive, shown as '*' (stored in playfield)\n"
<< "; i = indexed accessed only\n"
<< "; c = used by code executed in RAM\n"
<< "; s = used by stack\n"
<< "; ! = page crossed, 1 cycle penalty\n"
<< "; Legend: * = CODE not yet run (tentative code)\n"
<< "; D = DATA directive (referenced in some way)\n"
<< "; G = GFX directive, shown as '#' (stored in player, missile, ball)\n"
<< "; P = PGFX directive, shown as '*' (stored in playfield)\n"
<< "; C = COL directive, shown as color constants (stored in player color)\n"
<< "; CP = PCOL directive, shown as color constants (stored in playfield color)\n"
<< "; CB = BCOL directive, shown as color constants (stored in background color)\n"
<< "; A = AUD directive (stored in audio registers)\n"
<< "; i = indexed accessed only\n"
<< "; c = used by code executed in RAM\n"
<< "; s = used by stack\n"
<< "; ! = page crossed, 1 cycle penalty\n"
<< "\n processor 6502\n\n";
out << "\n;-----------------------------------------------------------\n"
<< "; Color constants\n"
<< ";-----------------------------------------------------------\n\n";
if(isNTSC)
{
for(int i = 0; i < 16; ++i)
out << ALIGN(16) << NTSC_COLOR[i] << " = $" << Base::HEX2 << (i << 4) << "\n";
}
else if(isPAL)
{
for(int i = 0; i < 16; ++i)
out << ALIGN(16) << PAL_COLOR[i] << " = $" << Base::HEX2 << (i << 4) << "\n";
}
else
{
for(int i = 0; i < 8; ++i)
out << ALIGN(16) << SECAM_COLOR[i] << " = $" << Base::HEX1 << (i << 1) << "\n";
}
out << "\n";
bool addrUsed = false;
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
addrUsed = addrUsed || myReserved.TIARead[addr] || (mySystem.getAccessFlags(addr) & WRITE);
addrUsed = addrUsed || myReserved.TIARead[addr] || (mySystem.getAccessFlags(addr) & Device::WRITE);
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
addrUsed = addrUsed || myReserved.TIAWrite[addr] || (mySystem.getAccessFlags(addr) & DATA);
addrUsed = addrUsed || myReserved.TIAWrite[addr] || (mySystem.getAccessFlags(addr) & Device::DATA);
for(uInt16 addr = 0x00; addr <= 0x17; ++addr)
addrUsed = addrUsed || myReserved.IOReadWrite[addr];
if(addrUsed)
{
out << "\n;-----------------------------------------------------------\n"
@ -1103,7 +1235,7 @@ string CartDebug::saveDisassembly()
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr])
out << ALIGN(16) << ourTIAMnemonicR[addr] << "= $"
<< Base::HEX2 << right << addr << " ; (R)\n";
else if (mySystem.getAccessFlags(addr) & DATA)
else if (mySystem.getAccessFlags(addr) & Device::DATA)
out << ";" << ALIGN(16-1) << ourTIAMnemonicR[addr] << "= $"
<< Base::HEX2 << right << addr << " ; (Ri)\n";
out << "\n";
@ -1113,7 +1245,7 @@ string CartDebug::saveDisassembly()
if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr])
out << ALIGN(16) << ourTIAMnemonicW[addr] << "= $"
<< Base::HEX2 << right << addr << " ; (W)\n";
else if (mySystem.getAccessFlags(addr) & WRITE)
else if (mySystem.getAccessFlags(addr) & Device::WRITE)
out << ";" << ALIGN(16-1) << ourTIAMnemonicW[addr] << "= $"
<< Base::HEX2 << right << addr << " ; (Wi)\n";
out << "\n";
@ -1128,8 +1260,8 @@ string CartDebug::saveDisassembly()
addrUsed = false;
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80]
|| (mySystem.getAccessFlags(addr) & (DATA | WRITE))
|| (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
|| (mySystem.getAccessFlags(addr) & (Device::DATA | Device::WRITE))
|| (mySystem.getAccessFlags(addr|0x100) & (Device::DATA | Device::WRITE));
if(addrUsed)
{
bool addLine = false;
@ -1138,9 +1270,9 @@ string CartDebug::saveDisassembly()
<< ";-----------------------------------------------------------\n\n";
for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) {
bool ramUsed = (mySystem.getAccessFlags(addr) & (DATA | WRITE));
bool codeUsed = (mySystem.getAccessFlags(addr) & CODE);
bool stackUsed = (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
bool ramUsed = (mySystem.getAccessFlags(addr) & (Device::DATA | Device::WRITE));
bool codeUsed = (mySystem.getAccessFlags(addr) & Device::CODE);
bool stackUsed = (mySystem.getAccessFlags(addr|0x100) & (Device::DATA | Device::WRITE));
if (myReserved.ZPRAM[addr - 0x80] &&
myUserLabels.find(addr) == myUserLabels.end()) {
@ -1196,7 +1328,7 @@ string CartDebug::saveDisassembly()
stringstream retVal;
if(myConsole.cartridge().bankCount() > 1)
retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported, only currently enabled banks disassembled\n");
retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported\n");
retVal << "saved " << node.getShortPath() << " OK";
return retVal.str();
}
@ -1214,12 +1346,27 @@ string CartDebug::saveRom()
return DebuggerParser::red("failed to save ROM");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::saveAccessFile()
{
const string& rom = myConsole.properties().get(PropType::Cart_Name) + ".csv";
FilesystemNode node(myOSystem.defaultSaveDir() + rom);
ofstream out(node.getPath());
if(out)
{
out << myConsole.tia().getAccessCounters();
out << myConsole.riot().getAccessCounters();
out << myConsole.cartridge().getAccessCounters();
return "saved access counters as " + node.getShortPath();
}
else
return DebuggerParser::red("failed to save access counters file");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string CartDebug::listConfig(int bank)
{
if(myConsole.cartridge().bankCount() > 1)
return DebuggerParser::red("config file for multi-bank ROM not yet supported");
uInt32 startbank = 0, endbank = bankCount();
if(bank >= 0 && bank < bankCount())
{
@ -1232,19 +1379,22 @@ string CartDebug::listConfig(int bank)
for(uInt32 b = startbank; b < endbank; ++b)
{
BankInfo& info = myBankInfo[b];
buf << "[" << b << "]" << endl;
buf << "Bank [" << b << "]" << endl;
for(const auto& i: info.directiveList)
{
if(i.type != CartDebug::NONE)
if(i.type != Device::NONE)
{
buf << "(*) ";
disasmTypeAsString(buf, i.type);
AccessTypeAsString(buf, i.type);
buf << " " << Base::HEX4 << i.start << " " << Base::HEX4 << i.end << endl;
}
}
getBankDirectives(buf, info);
}
if(myConsole.cartridge().bankCount() > 1)
buf << DebuggerParser::red("config file for multi-bank ROM not fully supported") << endl;
return buf.str();
}
@ -1334,15 +1484,15 @@ void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const
// Now consider each byte
uInt32 prev = info.offset, addr = prev + 1;
DisasmType prevType = disasmTypeAbsolute(mySystem.getAccessFlags(prev));
Device::AccessType prevType = accessTypeAbsolute(mySystem.getAccessFlags(prev));
for( ; addr < info.offset + info.size; ++addr)
{
DisasmType currType = disasmTypeAbsolute(mySystem.getAccessFlags(addr));
Device::AccessType currType = accessTypeAbsolute(mySystem.getAccessFlags(addr));
// Have we changed to a new type?
if(currType != prevType)
{
disasmTypeAsString(buf, prevType);
AccessTypeAsString(buf, prevType);
buf << " " << Base::HEX4 << prev << " " << Base::HEX4 << (addr-1) << endl;
prev = addr;
@ -1353,13 +1503,13 @@ void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const
// Grab the last directive, making sure it accounts for all remaining space
if(prev != addr)
{
disasmTypeAsString(buf, prevType);
AccessTypeAsString(buf, prevType);
buf << " " << Base::HEX4 << prev << " " << Base::HEX4 << (addr-1) << endl;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartDebug::addressTypeAsString(ostream& buf, uInt16 addr) const
void CartDebug::accessTypeAsString(ostream& buf, uInt16 addr) const
{
if(!(addr & 0x1000))
{
@ -1372,70 +1522,88 @@ void CartDebug::addressTypeAsString(ostream& buf, uInt16 addr) const
label = myDisLabels[addr & 0xFFF];
buf << endl << "directive: " << Base::toString(directive, Base::Fmt::_2_8) << " ";
disasmTypeAsString(buf, directive);
AccessTypeAsString(buf, directive);
buf << endl << "emulation: " << Base::toString(debugger, Base::Fmt::_2_8) << " ";
disasmTypeAsString(buf, debugger);
AccessTypeAsString(buf, debugger);
buf << endl << "tentative: " << Base::toString(label, Base::Fmt::_2_8) << " ";
disasmTypeAsString(buf, label);
AccessTypeAsString(buf, label);
buf << endl;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartDebug::DisasmType CartDebug::disasmTypeAbsolute(uInt8 flags) const
Device::AccessType CartDebug::accessTypeAbsolute(Device::AccessFlags flags) const
{
if(flags & CartDebug::CODE)
return CartDebug::CODE;
else if(flags & CartDebug::TCODE)
return CartDebug::CODE; // TODO - should this be separate??
else if(flags & CartDebug::GFX)
return CartDebug::GFX;
else if(flags & CartDebug::PGFX)
return CartDebug::PGFX;
else if(flags & CartDebug::DATA)
return CartDebug::DATA;
else if(flags & CartDebug::ROW)
return CartDebug::ROW;
if(flags & Device::CODE)
return Device::CODE;
else if(flags & Device::TCODE)
return Device::CODE; // TODO - should this be separate??
else if(flags & Device::GFX)
return Device::GFX;
else if(flags & Device::PGFX)
return Device::PGFX;
else if(flags & Device::COL)
return Device::COL;
else if(flags & Device::PCOL)
return Device::PCOL;
else if(flags & Device::BCOL)
return Device::BCOL;
else if(flags & Device::AUD)
return Device::AUD;
else if(flags & Device::DATA)
return Device::DATA;
else if(flags & Device::ROW)
return Device::ROW;
else
return CartDebug::NONE;
return Device::NONE;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartDebug::disasmTypeAsString(ostream& buf, DisasmType type) const
void CartDebug::AccessTypeAsString(ostream& buf, Device::AccessType type) const
{
switch(type)
{
case CartDebug::CODE: buf << "CODE"; break;
case CartDebug::TCODE: buf << "TCODE"; break;
case CartDebug::GFX: buf << "GFX"; break;
case CartDebug::PGFX: buf << "PGFX"; break;
case CartDebug::DATA: buf << "DATA"; break;
case CartDebug::ROW: buf << "ROW"; break;
case CartDebug::REFERENCED:
case CartDebug::VALID_ENTRY:
case CartDebug::NONE: break;
case Device::CODE: buf << "CODE"; break;
case Device::TCODE: buf << "TCODE"; break;
case Device::GFX: buf << "GFX"; break;
case Device::PGFX: buf << "PGFX"; break;
case Device::COL: buf << "COL"; break;
case Device::PCOL: buf << "PCOL"; break;
case Device::BCOL: buf << "BCOL"; break;
case Device::AUD: buf << "AUD"; break;
case Device::DATA: buf << "DATA"; break;
case Device::ROW: buf << "ROW"; break;
default: break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const
void CartDebug::AccessTypeAsString(ostream& buf, Device::AccessFlags flags) const
{
if(flags)
{
if(flags & CartDebug::CODE)
if(flags & Device::CODE)
buf << "CODE ";
if(flags & CartDebug::TCODE)
if(flags & Device::TCODE)
buf << "TCODE ";
if(flags & CartDebug::GFX)
if(flags & Device::GFX)
buf << "GFX ";
if(flags & CartDebug::PGFX)
if(flags & Device::PGFX)
buf << "PGFX ";
if(flags & CartDebug::DATA)
if(flags & Device::COL)
buf << "COL ";
if(flags & Device::PCOL)
buf << "PCOL ";
if(flags & Device::BCOL)
buf << "BCOL ";
if(flags & Device::AUD)
buf << "AUD ";
if(flags & Device::DATA)
buf << "DATA ";
if(flags & CartDebug::ROW)
if(flags & Device::ROW)
buf << "ROW ";
if(flags & CartDebug::REFERENCED)
if(flags & Device::REFERENCED)
buf << "*REFERENCED ";
if(flags & CartDebug::VALID_ENTRY)
if(flags & Device::VALID_ENTRY)
buf << "*VALID_ENTRY ";
}
else

View File

@ -31,6 +31,7 @@ using CartMethod = int (CartDebug::*)();
#include "bspf.hxx"
#include "DebuggerSystem.hxx"
#include "Device.hxx"
class CartState : public DebuggerState
{
@ -47,30 +48,8 @@ class CartDebug : public DebuggerSystem
friend class DiStella;
public:
enum DisasmType {
NONE = 0,
REFERENCED = 1 << 0, /* 0x01, code somewhere in the program references it,
i.e. LDA $F372 referenced $F372 */
VALID_ENTRY = 1 << 1, /* 0x02, addresses that can have a label placed in front of it.
A good counterexample would be "FF00: LDA $FE00"; $FF01
would be in the middle of a multi-byte instruction, and
therefore cannot be labelled. */
// The following correspond to specific types that can be set within the
// debugger, or specified in a Distella cfg file, and are listed in order
// of decreasing hierarchy
//
CODE = 1 << 7, // 0x80, disassemble-able code segments
TCODE = 1 << 6, // 0x40, (tentative) disassemble-able code segments
GFX = 1 << 5, // 0x20, addresses loaded into GRPx registers
PGFX = 1 << 4, // 0x10, addresses loaded into PFx registers
DATA = 1 << 3, // 0x08, addresses loaded into registers other than GRPx / PFx
ROW = 1 << 2, // 0x04, all other addresses
// special type for poke()
WRITE = TCODE // 0x40, address written to
};
struct DisassemblyTag {
DisasmType type{NONE};
Device::AccessType type{Device::NONE};
uInt16 address{0};
string label;
string disasm;
@ -104,28 +83,27 @@ class CartDebug : public DebuggerSystem
CartDebugWidget* getDebugWidget() const { return myDebugWidget; }
void setDebugWidget(CartDebugWidget* w) { myDebugWidget = w; }
// Return the address of the last CPU read
int lastReadAddress();
// Return the address of the last CPU write
int lastWriteAddress();
// Return the base (= non-mirrored) address of the last CPU read
int lastReadBaseAddress();
// Return the base (= non-mirrored) address of the last CPU write
int lastWriteBaseAddress();
// The following two methods are meant to be used together
// First, a call is made to disassemble(), which updates the disassembly
// list; it will figure out when an actual complete disassembly is
// required, and when the previous results can be used
//
// Later, successive calls to disassemblyList() simply return the
// previous results; no disassembly is done in this case
/**
Disassemble from the given address using the Distella disassembler
Address-to-label mappings (and vice-versa) are also determined here
@param force Force a re-disassembly, even if the state hasn't changed
@return True if disassembly changed from previous call, else false
*/
// TODO
bool disassemble(bool force = false);
bool disassembleBank(int bank);
// First, a call is made to disassemble(), which updates the disassembly
// list, is required; it will figure out when an actual complete
// disassembly is required, and when the previous results can be used
//
// Later, successive calls to disassembly() simply return the
// previous results; no disassembly is done in this case
/**
Get the results from the most recent call to disassemble()
*/
@ -149,7 +127,7 @@ class CartDebug : public DebuggerSystem
@return The disassembly represented as a string
*/
string disassemble(uInt16 start, uInt16 lines) const;
string disassembleLines(uInt16 start, uInt16 lines) const;
/**
Add a directive to the disassembler. Directives are basically overrides
@ -157,14 +135,14 @@ class CartDebug : public DebuggerSystem
things can't be automatically determined. For now, these directives
have exactly the same syntax as in a distella configuration file.
@param type Currently, CODE/DATA/GFX are supported
@param type Currently, CODE/DATA/GFX/PGFX/COL/PCOL/BCOL/AUD/ROW are supported
@param start The start address (inclusive) to mark with the given type
@param end The end address (inclusive) to mark with the given type
@param bank Bank to which these directive apply (0 indicated current bank)
@return True if directive was added, else false if it was removed
*/
bool addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end,
bool addDirective(Device::AccessType type, uInt16 start, uInt16 end,
int bank = -1);
// The following are convenience methods that query the cartridge object
@ -231,6 +209,11 @@ class CartDebug : public DebuggerSystem
string saveDisassembly();
string saveRom();
/**
Save access counters file
*/
string saveAccessFile();
/**
Show Distella directives (both set by the user and determined by Distella)
for the given bank (or all banks, if no bank is specified).
@ -249,18 +232,21 @@ class CartDebug : public DebuggerSystem
*/
void getCompletions(const char* in, StringList& list) const;
// Convert given address to corresponding disassembly type and append to buf
void addressTypeAsString(ostream& buf, uInt16 addr) const;
// Convert given address to corresponding access type and append to buf
void accessTypeAsString(ostream& buf, uInt16 addr) const;
// Convert access enum type to corresponding string and append to buf
void AccessTypeAsString(ostream& buf, Device::AccessType type) const;
private:
using AddrToLabel = std::map<uInt16, string>;
using LabelToAddr = std::map<string, uInt16,
std::function<bool(const string&, const string&)>>;
using AddrTypeArray = std::array<uInt8, 0x1000>;
using AddrTypeArray = std::array<uInt16, 0x1000>;
struct DirectiveTag {
DisasmType type{NONE};
Device::AccessType type{Device::NONE};
uInt16 start{0};
uInt16 end{0};
};
@ -290,6 +276,19 @@ class CartDebug : public DebuggerSystem
};
ReservedEquates myReserved;
/**
Disassemble from the given address using the Distella disassembler
Address-to-label mappings (and vice-versa) are also determined here
@param bank The current bank to disassemble
@param PC A program counter to start with
@param force Force a re-disassembly, even if the state hasn't changed
@return True if disassembly changed from previous call, else false
*/
bool disassemble(int bank, uInt16 PC, bool force = false);
// Actually call DiStella to fill the DisassemblyList structure
// Return whether the search address was actually in the list
bool fillDisassemblyList(BankInfo& bankinfo, uInt16 search);
@ -298,15 +297,12 @@ class CartDebug : public DebuggerSystem
// based on its disassembly
void getBankDirectives(ostream& buf, BankInfo& info) const;
// Get disassembly enum type from 'flags', taking precendence into account
DisasmType disasmTypeAbsolute(uInt8 flags) const;
// Get access enum type from 'flags', taking precendence into account
Device::AccessType accessTypeAbsolute(Device::AccessFlags flags) const;
// Convert disassembly enum type to corresponding string and append to buf
void disasmTypeAsString(ostream& buf, DisasmType type) const;
// Convert all disassembly types in 'flags' to corresponding string and
// Convert all access types in 'flags' to corresponding string and
// append to buf
void disasmTypeAsString(ostream& buf, uInt8 flags) const;
void AccessTypeAsString(ostream& buf, Device::AccessFlags flags) const;
private:
const OSystem& myOSystem;
@ -347,7 +343,7 @@ class CartDebug : public DebuggerSystem
uInt16 myLabelLength{8}; // longest pre-defined label
// Filenames to use for various I/O (currently these are hardcoded)
string myListFile, mySymbolFile, myCfgFile, myDisasmFile, myRomFile;
string myListFile, mySymbolFile, myCfgFile, myDisasmFile;
/// Table of instruction mnemonics
static std::array<const char*, 16> ourTIAMnemonicR; // read mode

View File

@ -20,7 +20,6 @@
#include "M6502.hxx"
#include "System.hxx"
#include "Debugger.hxx"
#include "CartDebug.hxx"
#include "TIADebug.hxx"
#include "CpuDebug.hxx"
@ -46,6 +45,7 @@ const DebuggerState& CpuDebug::getState()
myState.srcA = my6502.lastSrcAddressA();
myState.srcX = my6502.lastSrcAddressX();
myState.srcY = my6502.lastSrcAddressY();
myState.dest = my6502.lastWriteAddress();
Debugger::set_bits(myState.PS, myState.PSbits);
@ -66,6 +66,7 @@ void CpuDebug::saveOldState()
myOldState.srcA = my6502.lastSrcAddressA();
myOldState.srcX = my6502.lastSrcAddressX();
myOldState.srcY = my6502.lastSrcAddressY();
myOldState.dest = my6502.lastWriteAddress();
Debugger::set_bits(myOldState.PS, myOldState.PSbits);
}

View File

@ -31,7 +31,7 @@ class CpuState : public DebuggerState
{
public:
int PC{0}, SP{0}, PS{0}, A{0}, X{0}, Y{0};
int srcS{0}, srcA{0}, srcX{0}, srcY{0};
int srcS{0}, srcA{0}, srcX{0}, srcY{0}, dest{0};
BoolArray PSbits;
};

View File

@ -440,19 +440,19 @@ bool Debugger::writeTrap(uInt16 t)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Debugger::peek(uInt16 addr, uInt8 flags)
uInt8 Debugger::peek(uInt16 addr, Device::AccessFlags flags)
{
return mySystem.peek(addr, flags);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 Debugger::dpeek(uInt16 addr, uInt8 flags)
uInt16 Debugger::dpeek(uInt16 addr, Device::AccessFlags flags)
{
return uInt16(mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::poke(uInt16 addr, uInt8 value, uInt8 flags)
void Debugger::poke(uInt16 addr, uInt8 value, Device::AccessFlags flags)
{
mySystem.poke(addr, value, flags);
}
@ -464,26 +464,26 @@ M6502& Debugger::m6502() const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int Debugger::peekAsInt(int addr, uInt8 flags)
int Debugger::peekAsInt(int addr, Device::AccessFlags flags)
{
return mySystem.peek(uInt16(addr), flags);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int Debugger::dpeekAsInt(int addr, uInt8 flags)
int Debugger::dpeekAsInt(int addr, Device::AccessFlags flags)
{
return mySystem.peek(uInt16(addr), flags) |
(mySystem.peek(uInt16(addr+1), flags) << 8);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int Debugger::getAccessFlags(uInt16 addr) const
Device::AccessFlags Debugger::getAccessFlags(uInt16 addr) const
{
return mySystem.getAccessFlags(addr);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Debugger::setAccessFlags(uInt16 addr, uInt8 flags)
void Debugger::setAccessFlags(uInt16 addr, Device::AccessFlags flags)
{
mySystem.setAccessFlags(addr, flags);
}
@ -887,6 +887,8 @@ std::array<Debugger::PseudoRegister, 11> Debugger::ourPseudoRegisters = { {
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" }
// CPU address access functions:
/*{ "__lastread", "last CPU read address" },
{ "__lastwrite", "last CPU write address" },*/
/*{ "_lastread", "last CPU read address" },
{ "_lastwrite", "last CPU write address" },
{ "__lastbaseread", "last CPU read base address" },
{ "__lastbasewrite", "last CPU write base address" }*/
} };

View File

@ -47,6 +47,7 @@ class RewindManager;
#include "DialogContainer.hxx"
#include "DebuggerDialog.hxx"
#include "FrameBufferConstants.hxx"
#include "Cart.hxx"
#include "bspf.hxx"
/**
@ -243,18 +244,18 @@ class Debugger : public DialogContainer
static Debugger& debugger() { return *myStaticDebugger; }
/** Convenience methods to access peek/poke from System */
uInt8 peek(uInt16 addr, uInt8 flags = 0);
uInt16 dpeek(uInt16 addr, uInt8 flags = 0);
void poke(uInt16 addr, uInt8 value, uInt8 flags = 0);
uInt8 peek(uInt16 addr, Device::AccessFlags flags = Device::NONE);
uInt16 dpeek(uInt16 addr, Device::AccessFlags flags = Device::NONE);
void poke(uInt16 addr, uInt8 value, Device::AccessFlags flags = Device::NONE);
/** Convenience method to access the 6502 from System */
M6502& m6502() const;
/** These are now exposed so Expressions can use them. */
int peekAsInt(int addr, uInt8 flags = 0);
int dpeekAsInt(int addr, uInt8 flags = 0);
int getAccessFlags(uInt16 addr) const;
void setAccessFlags(uInt16 addr, uInt8 flags);
int peekAsInt(int addr, Device::AccessFlags flags = Device::NONE);
int dpeekAsInt(int addr, Device::AccessFlags flags = Device::NONE);
Device::AccessFlags getAccessFlags(uInt16 addr) const;
void setAccessFlags(uInt16 addr, Device::AccessFlags flags);
uInt32 getBaseAddress(uInt32 addr, bool read);

View File

@ -678,6 +678,29 @@ string DebuggerParser::saveScriptFile(string file)
return "saved " + node.getShortPath() + " OK";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerParser::executeDirective(Device::AccessType type)
{
if(argCount != 2)
{
outputCommandError("specify start and end of range only", myCommand);
return;
}
else if(args[1] < args[0])
{
commandResult << red("start address must be <= end address");
return;
}
bool result = debugger.cartDebug().addDirective(type, args[0], args[1]);
commandResult << (result ? "added " : "removed ");
debugger.cartDebug().AccessTypeAsString(commandResult, type);
commandResult << " directive on range $"
<< hex << args[0] << " $" << hex << args[1];
debugger.rom().invalidate();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// executor methods for commands[] array. All are void, no args.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -689,6 +712,13 @@ void DebuggerParser::executeA()
debugger.cpuDebug().setA(uInt8(args[0]));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "aud"
void DebuggerParser::executeAud()
{
executeDirective(Device::AUD);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "base"
void DebuggerParser::executeBase()
@ -720,6 +750,13 @@ void DebuggerParser::executeBase()
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "bcol"
void DebuggerParser::executeBCol()
{
executeDirective(Device::BCOL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "break"
void DebuggerParser::executeBreak()
@ -912,22 +949,14 @@ void DebuggerParser::executeCls()
// "code"
void DebuggerParser::executeCode()
{
if(argCount != 2)
{
outputCommandError("specify start and end of range only", myCommand);
return;
}
else if(args[1] < args[0])
{
commandResult << red("start address must be <= end address");
return;
}
executeDirective(Device::CODE);
}
bool result = debugger.cartDebug().addDirective(
CartDebug::CODE, args[0], args[1]);
commandResult << (result ? "added" : "removed") << " CODE directive on range $"
<< hex << args[0] << " $" << hex << args[1];
debugger.rom().invalidate();
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "col"
void DebuggerParser::executeCol()
{
executeDirective(Device::COL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -953,22 +982,7 @@ void DebuggerParser::executeD()
// "data"
void DebuggerParser::executeData()
{
if(argCount != 2)
{
outputCommandError("specify start and end of range only", myCommand);
return;
}
else if(args[1] < args[0])
{
commandResult << red("start address must be <= end address");
return;
}
bool result = debugger.cartDebug().addDirective(
CartDebug::DATA, args[0], args[1]);
commandResult << (result ? "added" : "removed") << " DATA directive on range $"
<< hex << args[0] << " $" << hex << args[1];
debugger.rom().invalidate();
executeDirective(Device::DATA);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1067,7 +1081,7 @@ void DebuggerParser::executeDisasm()
return;
}
commandResult << debugger.cartDebug().disassemble(start, lines);
commandResult << debugger.cartDebug().disassembleLines(start, lines);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1270,22 +1284,7 @@ void DebuggerParser::executeFunction()
// "gfx"
void DebuggerParser::executeGfx()
{
if(argCount != 2)
{
outputCommandError("specify start and end of range only", myCommand);
return;
}
else if(args[1] < args[0])
{
commandResult << red("start address must be <= end address");
return;
}
bool result = debugger.cartDebug().addDirective(
CartDebug::GFX, args[0], args[1]);
commandResult << (result ? "added" : "removed") << " GFX directive on range $"
<< hex << args[0] << " $" << hex << args[1];
debugger.rom().invalidate();
executeDirective(Device::GFX);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1626,26 +1625,18 @@ void DebuggerParser::executePc()
debugger.cpuDebug().setPC(args[0]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "pcol"
void DebuggerParser::executePCol()
{
executeDirective(Device::PCOL);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "pgfx"
void DebuggerParser::executePGfx()
{
if(argCount != 2)
{
outputCommandError("specify start and end of range only", myCommand);
return;
}
else if(args[1] < args[0])
{
commandResult << red("start address must be <= end address");
return;
}
bool result = debugger.cartDebug().addDirective(
CartDebug::PGFX, args[0], args[1]);
commandResult << (result ? "added" : "removed") << " PGFX directive on range $"
<< hex << args[0] << " $" << hex << args[1];
debugger.rom().invalidate();
executeDirective(Device::PGFX);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1722,22 +1713,7 @@ void DebuggerParser::executeRom()
// "row"
void DebuggerParser::executeRow()
{
if(argCount != 2)
{
outputCommandError("specify start and end of range only", myCommand);
return;
}
else if(args[1] < args[0])
{
commandResult << red("start address must be <= end address");
return;
}
bool result = debugger.cartDebug().addDirective(
CartDebug::ROW, args[0], args[1]);
commandResult << (result ? "added" : "removed") << " ROW directive on range $"
<< hex << args[0] << " $" << hex << args[1];
debugger.rom().invalidate();
executeDirective(Device::ROW);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -1833,6 +1809,13 @@ void DebuggerParser::executeSave()
commandResult << saveScriptFile(argStrings[0]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "saveaccess"
void DebuggerParser::executeSaveAccess()
{
commandResult << debugger.cartDebug().saveAccessFile();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// "saveconfig"
void DebuggerParser::executeSaveconfig()
@ -2054,18 +2037,18 @@ void DebuggerParser::executeTraps(bool read, bool write, const string& command,
if(read)
{
if(beginRead != endRead)
conditionBuf << "__lastread>=" << Base::toString(beginRead) << "&&__lastread<=" << Base::toString(endRead);
conditionBuf << "__lastbaseread>=" << Base::toString(beginRead) << "&&__lastbaseread<=" << Base::toString(endRead);
else
conditionBuf << "__lastread==" << Base::toString(beginRead);
conditionBuf << "__lastbaseread==" << Base::toString(beginRead);
}
if(read && write)
conditionBuf << "||";
if(write)
{
if(beginWrite != endWrite)
conditionBuf << "__lastwrite>=" << Base::toString(beginWrite) << "&&__lastwrite<=" << Base::toString(endWrite);
conditionBuf << "__lastbasewrite>=" << Base::toString(beginWrite) << "&&__lastbasewrite<=" << Base::toString(endWrite);
else
conditionBuf << "__lastwrite==" << Base::toString(beginWrite);
conditionBuf << "__lastbasewrite==" << Base::toString(beginWrite);
}
// parenthesize provided condition (end)
if(hasCond)
@ -2194,7 +2177,7 @@ void DebuggerParser::executeType()
for(uInt32 i = beg; i <= end; ++i)
{
commandResult << Base::HEX4 << i << ": ";
debugger.cartDebug().addressTypeAsString(commandResult, i);
debugger.cartDebug().accessTypeAsString(commandResult, i);
commandResult << endl;
}
}
@ -2300,7 +2283,7 @@ void DebuggerParser::executeZ()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// List of all commands available to the parser
std::array<DebuggerParser::Command, 95> DebuggerParser::commands = { {
std::array<DebuggerParser::Command, 100> DebuggerParser::commands = { {
{
"a",
"Set Accumulator to <value>",
@ -2311,6 +2294,16 @@ std::array<DebuggerParser::Command, 95> DebuggerParser::commands = { {
std::mem_fn(&DebuggerParser::executeA)
},
{
"aud",
"Mark 'AUD' range in disassembly",
"Start and end of range required\nExample: aud f000 f010",
true,
false,
{ Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE },
std::mem_fn(&DebuggerParser::executeAud)
},
{
"base",
"Set default number base to <base>",
@ -2321,6 +2314,17 @@ std::array<DebuggerParser::Command, 95> DebuggerParser::commands = { {
std::mem_fn(&DebuggerParser::executeBase)
},
{
"bcol",
"Mark 'BCOL' range in disassembly",
"Start and end of range required\nExample: bcol f000 f010",
true,
false,
{ Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE },
std::mem_fn(&DebuggerParser::executeBCol)
},
{
"break",
"Break at <address> and <bank>",
@ -2442,6 +2446,16 @@ std::array<DebuggerParser::Command, 95> DebuggerParser::commands = { {
std::mem_fn(&DebuggerParser::executeCode)
},
{
"col",
"Mark 'COL' range in disassembly",
"Start and end of range required\nExample: col f000 f010",
true,
false,
{ Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE },
std::mem_fn(&DebuggerParser::executeCol)
},
{
"colortest",
"Show value xx as TIA color",
@ -2847,6 +2861,16 @@ std::array<DebuggerParser::Command, 95> DebuggerParser::commands = { {
std::mem_fn(&DebuggerParser::executePc)
},
{
"pcol",
"Mark 'PCOL' range in disassembly",
"Start and end of range required\nExample: col f000 f010",
true,
false,
{ Parameters::ARG_WORD, Parameters::ARG_MULTI_BYTE },
std::mem_fn(&DebuggerParser::executePCol)
},
{
"pgfx",
"Mark 'PGFX' range in disassembly",
@ -2980,6 +3004,16 @@ std::array<DebuggerParser::Command, 95> DebuggerParser::commands = { {
std::mem_fn(&DebuggerParser::executeSave)
},
{
"saveaccess",
"Save the access counters to CSV file",
"Example: saveaccess (no parameters)",
false,
false,
{ Parameters::ARG_END_ARGS },
std::mem_fn(&DebuggerParser::executeSaveAccess)
},
{
"saveconfig",
"Save Distella config file (with default name)",
@ -3182,7 +3216,7 @@ std::array<DebuggerParser::Command, 95> DebuggerParser::commands = { {
{
"type",
"Show disassembly type for address xx [yy]",
"Show access type for address xx [yy]",
"Example: type f000, type f000 f010",
true,
false,

View File

@ -27,6 +27,7 @@ class FilesystemNode;
struct Command;
#include "bspf.hxx"
#include "Device.hxx"
class DebuggerParser
{
@ -97,7 +98,7 @@ class DebuggerParser
std::array<Parameters, 10> parms;
std::function<void (DebuggerParser*)> executor;
};
static std::array<Command, 95> commands;
static std::array<Command, 100> commands;
struct Trap
{
@ -140,9 +141,13 @@ class DebuggerParser
// output the error with the example provided for the command
void outputCommandError(const string& errorMsg, int command);
void executeDirective(Device::AccessType type);
// List of available command methods
void executeA();
void executeAud();
void executeBase();
void executeBCol();
void executeBreak();
void executeBreakif();
void executeBreaklabel();
@ -155,6 +160,7 @@ class DebuggerParser
void executeClearwatches();
void executeCls();
void executeCode();
void executeCol();
void executeColortest();
void executeD();
void executeData();
@ -195,6 +201,7 @@ class DebuggerParser
void executeN();
void executePalette();
void executePc();
void executePCol();
void executePGfx();
void executePrint();
void executeRam();
@ -208,6 +215,7 @@ class DebuggerParser
void executeRunToPc();
void executeS();
void executeSave();
void executeSaveAccess();
void executeSaveallstates();
void executeSaveconfig();
void executeSavedisassembly();

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@
#include "Base.hxx"
#include "CartDebug.hxx"
#include "Device.hxx"
#include "bspf.hxx"
/**
@ -71,11 +72,26 @@ class DiStella
CartDebug::AddrTypeArray& directives,
CartDebug::ReservedEquates& reserved);
private:
/**
Enumeration of the addressing type (RAM, ROM, RIOT, TIA...)
*/
enum class AddressType : int
{
INVALID,
ROM,
TIA,
RIOT,
ROM_MIRROR,
ZP_RAM
};
private:
// Indicate that a new line of disassembly has been completed
// In the original Distella code, this indicated a new line to be printed
// Here, we add a new entry to the DisassemblyList
void addEntry(CartDebug::DisasmType type);
void addEntry(Device::AccessType type);
// Process directives given in the list
// Directives are basically the contents of a distella configuration file
@ -87,32 +103,32 @@ class DiStella
void disasmFromAddress(uInt32 distart);
bool check_range(uInt16 start, uInt16 end) const;
int mark(uInt32 address, uInt8 mask, bool directive = false);
bool checkBit(uInt16 address, uInt8 mask, bool useDebugger = true) const;
bool checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger = true) const;
AddressType mark(uInt32 address, uInt16 mask, bool directive = false);
bool checkBit(uInt16 address, uInt16 mask, bool useDebugger = true) const;
bool checkBits(uInt16 address, uInt16 mask, uInt16 notMask, bool useDebugger = true) const;
void outputGraphics();
void outputBytes(CartDebug::DisasmType type);
void outputColors();
void outputBytes(Device::AccessType type);
// Convenience methods to generate appropriate labels
inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, int labfound)
inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, AddressType labfound)
{
if(!myDbg.getLabel(buf, addr, true))
buf << "L" << Common::Base::HEX4 << addr;
}
inline void labelA12Low(stringstream& buf, uInt8 op, uInt16 addr, int labfound)
inline void labelA12Low(stringstream& buf, uInt8 op, uInt16 addr, AddressType labfound)
{
myDbg.getLabel(buf, addr, ourLookup[op].rw_mode == RWMode::READ, 2);
if (labfound == 2)
if (labfound == AddressType::TIA)
{
if(ourLookup[op].rw_mode == RWMode::READ)
myReserved.TIARead[addr & 0x0F] = true;
else
myReserved.TIAWrite[addr & 0x3F] = true;
}
else if (labfound == 3)
else if (labfound == AddressType::RIOT)
myReserved.IOReadWrite[(addr & 0xFF) - 0x80] = true;
else if (labfound == 5)
else if (labfound == AddressType::ZP_RAM)
myReserved.ZPRAM[(addr & 0xFF) - 0x80] = true;
}

View File

@ -35,7 +35,8 @@ CartridgeDPCPlusWidget::CartridgeDPCPlusWidget(
<< "DPC registers accessible @ $F000 - $F07F\n"
<< " $F000 - $F03F (R), $F040 - $F07F (W)\n"
<< "Banks accessible at hotspots $FFF6 to $FFFB\n"
<< "Startup bank = " << cart.startBank() << "\n";
<< "Startup bank = " << cart.startBank() << "\n"
<< "Ver = " << cart.myDriverMD5;
#if 0
// Eventually, we should query this from the debugger/disassembler

View File

@ -93,10 +93,11 @@ CpuWidget::CpuWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& n
myCpuDataSrc[i]->setEditable(false, true);
src_y += fontHeight+2;
}
int swidth = lfont.getStringWidth("Source Address");
new StaticTextWidget(boss, lfont, xpos, src_y + 4, src_w,
fontHeight, swidth <= src_w ? "Source Address" : "Source Addr",
TextAlign::Center);
// Last write destination address
new StaticTextWidget(boss, lfont, xpos - fontWidth * 4.5, src_y + 4, "Dest");
myCpuDataDest = new EditTextWidget(boss, nfont, xpos, src_y + 2, src_w, fontHeight+1);
myCpuDataDest->setEditable(false, true);
// Add labels for other CPU registers
xpos = x;
@ -325,6 +326,10 @@ void CpuWidget::loadConfig()
myCpuDataSrc[3]->setText((srcY != EmptyString ? srcY : Common::Base::toString(state.srcY)),
state.srcY != oldstate.srcY);
const string& dest = state.dest < 0 ? "" : cart.getLabel(state.dest, false);
myCpuDataDest->setText((dest != EmptyString ? dest : Common::Base::toString(state.dest)),
state.dest != oldstate.dest);
// Update the PS register booleans
changed.clear();
for(uInt32 i = 0; i < state.PSbits.size(); ++i)

View File

@ -76,6 +76,7 @@ class CpuWidget : public Widget, public CommandSender
ToggleBitWidget* myPSRegister{nullptr};
EditTextWidget* myPCLabel{nullptr};
std::array<EditTextWidget*, 4> myCpuDataSrc{nullptr};
EditTextWidget* myCpuDataDest{nullptr};
private:
// Following constructors and assignment operators not supported

View File

@ -511,9 +511,10 @@ void RomListWidget::drawWidget(bool hilite)
// Bytes are only editable if they represent code, graphics, or accessible data
// Otherwise, the disassembly should get all remaining space
if(dlist[pos].type & (CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX|CartDebug::DATA))
if(dlist[pos].type & (Device::CODE|Device::GFX|Device::PGFX|
Device::COL|Device::PCOL|Device::BCOL|Device::DATA))
{
if(dlist[pos].type == CartDebug::CODE)
if(dlist[pos].type == Device::CODE)
{
// Draw mnemonic
s.drawString(_font, dlist[pos].disasm.substr(0, 7), xpos + _labelWidth, ypos,
@ -592,8 +593,8 @@ void RomListWidget::startEditMode()
_editMode = true;
switch(myDisasm->list[_selectedItem].type)
{
case CartDebug::GFX:
case CartDebug::PGFX:
case Device::GFX:
case Device::PGFX:
_base = DiStella::settings.gfxFormat;
break;
default:

View File

@ -143,10 +143,10 @@ void TiaInfoWidget::loadConfig()
uInt64 total = tia.cyclesLo() + (uInt64(tia.cyclesHi()) << 32);
uInt64 totalOld = oldTia.info[2] + (uInt64(oldTia.info[3]) << 32);
myTotalCycles->setText(Common::Base::toString(total / 1000000, Common::Base::Fmt::_10_6) + "e6",
myTotalCycles->setText(Common::Base::toString(uInt32(total) / 1000000, Common::Base::Fmt::_10_6) + "e6",
total != totalOld);
uInt32 delta = total - totalOld;
myDeltaCycles->setText(Common::Base::toString(delta, Common::Base::Fmt::_10_8)); // no coloring
uInt64 delta = total - totalOld;
myDeltaCycles->setText(Common::Base::toString(uInt32(delta), Common::Base::Fmt::_10_8)); // no coloring
int clk = tia.clocksThisLine();
myScanlineCount->setText(Common::Base::toString(tia.scanlines(), Common::Base::Fmt::_10_3),

View File

@ -20,7 +20,7 @@
#include "MD5.hxx"
#ifdef DEBUGGER_SUPPORT
#include "Debugger.hxx"
#include "CartDebug.hxx"
#include "Base.hxx"
#endif
#include "Cart.hxx"
@ -39,7 +39,7 @@ Cartridge::Cartridge(const Settings& settings, const string& md5)
for(uInt32 i = 0; i < 256; ++i)
myRWPRandomValues[i] = rand.next();
myRAMAccesses.reserve(5);
myRamReadAccesses.reserve(5);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -76,6 +76,16 @@ bool Cartridge::bankChanged()
return changed;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 Cartridge::bankSize(uInt16 bank) const
{
size_t size;
getImage(size);
return std::min(uInt32(size) / bankCount(), 4_KB); // assuming that each bank has the same size
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Cartridge::peekRAM(uInt8& dest, uInt16 address)
{
@ -87,7 +97,7 @@ uInt8 Cartridge::peekRAM(uInt8& dest, uInt16 address)
if(!bankLocked() && !mySystem->autodetectMode())
{
// Record access here; final determination will happen in ::pokeRAM()
myRAMAccesses.push_back(address);
myRamReadAccesses.push_back(address);
dest = value;
}
#else
@ -101,11 +111,11 @@ uInt8 Cartridge::peekRAM(uInt8& dest, uInt16 address)
void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value)
{
#ifdef DEBUGGER_SUPPORT
for(auto i = myRAMAccesses.begin(); i != myRAMAccesses.end(); ++i)
for(auto i = myRamReadAccesses.begin(); i != myRamReadAccesses.end(); ++i)
{
if(*i == address)
{
myRAMAccesses.erase(i);
myRamReadAccesses.erase(i);
break;
}
}
@ -114,16 +124,96 @@ void Cartridge::pokeRAM(uInt8& dest, uInt16 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge::createCodeAccessBase(size_t size)
void Cartridge::createRomAccessArrays(size_t size)
{
myAccessSize = uInt32(size);
#ifdef DEBUGGER_SUPPORT
myCodeAccessBase = make_unique<uInt8[]>(size);
std::fill_n(myCodeAccessBase.get(), size, CartDebug::ROW);
myRomAccessBase = make_unique<Device::AccessFlags[]>(size);
std::fill_n(myRomAccessBase.get(), size, Device::ROW);
myRomAccessCounter = make_unique<Device::AccessCounter[]>(size * 2);
std::fill_n(myRomAccessCounter.get(), size * 2, 0);
#else
myCodeAccessBase = nullptr;
myRomAccessBase = nullptr;
myRomAccessCounter = nullptr;
#endif
}
#ifdef DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Cartridge::getAccessCounters() const
{
ostringstream out;
uInt32 offset = 0;
for(uInt16 bank = 0; bank < bankCount(); ++bank)
{
uInt16 origin = bankOrigin(bank);
uInt16 bankSize = this->bankSize(bank);
out << "Bank " << Common::Base::toString(bank, Common::Base::Fmt::_10_8) << " / 0.."
<< Common::Base::toString(bankCount() - 1, Common::Base::Fmt::_10_8) << " reads:\n";
for(uInt16 addr = 0; addr < bankSize; ++addr)
{
out << Common::Base::HEX4 << (addr | origin) << ","
<< Common::Base::toString(myRomAccessCounter[offset + addr], Common::Base::Fmt::_10_8) << ", ";
}
out << "\n";
out << "Bank " << Common::Base::toString(bank, Common::Base::Fmt::_10_8) << " / 0.."
<< Common::Base::toString(bankCount() - 1, Common::Base::Fmt::_10_8) << " writes:\n";
for(uInt16 addr = 0; addr < bankSize; ++addr)
{
out << Common::Base::HEX4 << (addr | origin) << ","
<< Common::Base::toString(myRomAccessCounter[offset + addr + myAccessSize], Common::Base::Fmt::_10_8) << ", ";
}
out << "\n";
offset += bankSize;
}
return out.str();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 Cartridge::bankOrigin(uInt16 bank) const
{
// isolate the high 3 address bits, count them and
// select the most frequent to define the bank origin
// TODO: origin for banks smaller than 4K
const int intervals = 0x8000 / 0x100;
uInt32 offset = bank * bankSize();
//uInt16 addrMask = (4_KB - 1) & ~(bankSize(bank) - 1);
//int addrShift = 0;
std::array<uInt16, intervals> count; // up to 128 256 byte interval origins
//if(addrMask)
// addrShift = log(addrMask) / log(2);
//addrMask;
count.fill(0);
for(uInt16 addr = 0x0000; addr < bankSize(bank); ++addr)
{
Device::AccessFlags flags = myRomAccessBase[offset + addr];
// only count really accessed addresses
if(flags & ~Device::ROW)
{
//uInt16 addrBit = addr >> addrShift;
count[(flags & Device::HADDR) >> 13]++;
}
}
uInt16 max = 0, maxIdx = 0;
for(int idx = 0; idx < intervals; ++idx)
{
if(count[idx] > max)
{
max = count[idx];
maxIdx = idx;
}
}
return maxIdx << 13 | 0x1000; //| (offset & 0xfff);
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge::initializeRAM(uInt8* arr, size_t size, uInt8 val) const
{

View File

@ -31,6 +31,7 @@ class GuiObject;
#include "Font.hxx"
#endif
/**
A cartridge is a device which contains the machine code for a
game and handles any bankswitching performed by the cartridge.
@ -112,7 +113,7 @@ class Cartridge : public Device
Clears information about all accesses to cart RAM.
*/
void clearAllRAMAccesses() {
myRAMAccesses.clear();
myRamReadAccesses.clear();
myRamWriteAccess = 0;
}
@ -124,7 +125,7 @@ class Cartridge : public Device
@return Address of illegal access if one occurred, else 0
*/
uInt16 getIllegalRAMReadAccess() const {
return myRAMAccesses.size() > 0 ? myRAMAccesses[0] : 0;
return myRamReadAccesses.size() > 0 ? myRamReadAccesses[0] : 0;
}
/**
@ -135,6 +136,22 @@ class Cartridge : public Device
@return Address of illegal access if one occurred, else 0
*/
uInt16 getIllegalRAMWriteAccess() const { return myRamWriteAccess; }
/**
Query the access counters
@return The access counters as comma separated string
*/
string getAccessCounters() const override;
/**
Determine the bank's origin
@param bank The bank to query
@return The origin of the bank
*/
uInt16 bankOrigin(uInt16 bank) const;
#endif
public:
@ -177,6 +194,14 @@ class Cartridge : public Device
*/
virtual uInt16 bankCount() const { return 1; }
/**
Get the size of a bank.
@param bank The bank to get the size for
@return The bank's size
*/
virtual uInt16 bankSize(uInt16 bank = 0) const;
/**
Patch the cartridge ROM.
@ -273,7 +298,7 @@ class Cartridge : public Device
@param size The size of the code-access array to create
*/
void createCodeAccessBase(size_t size);
void createRomAccessArrays(size_t size);
/**
Fill the given RAM array with (possibly random) data.
@ -321,12 +346,20 @@ class Cartridge : public Device
bool myBankChanged{true};
// The array containing information about every byte of ROM indicating
// whether it is used as code.
ByteBuffer myCodeAccessBase;
// whether it is used as code, data, graphics etc.
std::unique_ptr<Device::AccessFlags[]> myRomAccessBase;
// The array containing information about every byte of ROM indicating
// how often it is accessed.
std::unique_ptr<Device::AccessCounter[]> myRomAccessCounter;
// Contains address of illegal RAM write access or 0
uInt16 myRamWriteAccess{0};
// Total size of ROM access area (might include RAM too)
uInt32 myAccessSize;
private:
// The startup bank to use (where to look for the reset vector address)
uInt16 myStartBank{0};
@ -347,8 +380,10 @@ class Cartridge : public Device
// Used when we want the 'Cartridge.StartBank' ROM property
StartBankFromPropsFunc myStartBankFromPropsFunc;
// Contains
ShortArray myRAMAccesses;
// Used to answer whether an access in the last instruction cycle
// generated an illegal read RAM access. Contains address of illegal
// access.
ShortArray myRamReadAccesses;
// Following constructors and assignment operators not supported
Cartridge() = delete;

View File

@ -25,7 +25,7 @@ Cartridge0840::Cartridge0840(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -137,7 +137,7 @@ bool Cartridge0840::bank(uInt16 bank)
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -51,7 +51,7 @@ Cartridge2K::Cartridge2K(const ByteBuffer& image, size_t size,
mySize = System::PAGE_SIZE;
}
createCodeAccessBase(mySize);
createRomAccessArrays(mySize);
// Set mask for accessing the image buffer
// This is guaranteed to work, as mySize is a power of two
@ -76,7 +76,9 @@ void Cartridge2K::install(System& system)
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[addr & myMask];
access.codeAccessBase = &myCodeAccessBase[addr & myMask];
access.romAccessBase = &myRomAccessBase[addr & myMask];
access.romPeekCounter = &myRomAccessCounter[addr & myMask];
access.romPokeCounter = &myRomAccessCounter[(addr & myMask) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}

View File

@ -30,7 +30,7 @@ Cartridge3E::Cartridge3E(const ByteBuffer& image, size_t size,
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
createCodeAccessBase(mySize + myRAM.size());
createRomAccessArrays(mySize + myRAM.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -59,7 +59,9 @@ void Cartridge3E::install(System& system)
for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)];
access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (addr & 0x07FF)];
access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)];
access.romPeekCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF)];
access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -73,25 +75,19 @@ uInt8 Cartridge3E::peek(uInt16 address)
uInt16 peekAddress = address;
address &= 0x0FFF;
if(address < 0x0800)
// Due to the way paging is set up, the only way to get here is a TIA read or
// attempting to read from the RAM write port
if(address < 0x0040) // TIA access
return mySystem->tia().peek(address);
else if(myCurrentBank >= 256)
{
if(myCurrentBank < 256)
return myImage[(address & 0x07FF) + (myCurrentBank << 11)];
else
{
if(address < 0x0400)
return myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)];
else
{
// Reading from the write port triggers an unwanted write
return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], peekAddress);
}
}
}
else
{
return myImage[(address & 0x07FF) + mySize - 2048];
// Reading from the write port triggers an unwanted write
return peekRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], peekAddress);
}
// Make compiler happy; should never get here
return myImage[(address & 0x07FF) + mySize - 2048];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -111,11 +107,12 @@ bool Cartridge3E::poke(uInt16 address, uInt8 value)
return mySystem->tia().poke(address, value);
}
else
else if(myCurrentBank >= 256)
{
if(address & 0x0400)
{
pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)], pokeAddress, value);
pokeRAM(myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)],
pokeAddress, value);
return true;
}
else
@ -128,6 +125,7 @@ bool Cartridge3E::poke(uInt16 address, uInt8 value)
return false;
}
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -158,7 +156,9 @@ bool Cartridge3E::bank(uInt16 bank)
for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[offset + (addr & 0x07FF)];
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x07FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}
@ -174,10 +174,13 @@ bool Cartridge3E::bank(uInt16 bank)
System::PageAccess access(this, System::PageAccessType::READ);
// Map read-port RAM image into the system
// Writes are mapped to poke(), to check for write to the read port
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[offset + (addr & 0x03FF)];
access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -185,11 +188,12 @@ bool Cartridge3E::bank(uInt16 bank)
access.type = System::PageAccessType::WRITE;
// Map write-port RAM image into the system
// Map access to this class, since we need to inspect all accesses to
// check if RWP happens
// Reads are mapped to peek(), to check for read from write port
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[mySize + offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[mySize + offset + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}
@ -216,6 +220,12 @@ uInt16 Cartridge3E::bankCount() const
return 256 + 32;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 Cartridge3E::bankSize(uInt16 bank) const
{
return 2_KB; // we cannot use bankCount() here, because it delivers wrong numbers
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Cartridge3E::patch(uInt16 address, uInt8 value)
{

View File

@ -111,6 +111,14 @@ class Cartridge3E : public Cartridge
*/
uInt16 bankCount() const override;
/**
Get the size of a bank.
@param bank The bank to get the size for
@return The bank's size
*/
virtual uInt16 bankSize(uInt16 bank = 0) const override;
/**
Patch the cartridge ROM.

View File

@ -30,7 +30,7 @@ Cartridge3EPlus::Cartridge3EPlus(const ByteBuffer& image, size_t size,
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
createCodeAccessBase(mySize + myRAM.size());
createRomAccessArrays(mySize + myRAM.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -143,10 +143,22 @@ bool Cartridge3EPlus::poke(uInt16 address, uInt8 value)
if(whichBankIsThere & BITMASK_ROMRAM)
{
uInt32 byteOffset = address & BITMASK_RAM_BANK;
uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset;
pokeRAM(myRAM[baseAddress], address, value);
changed = true;
if(address & RAM_BANK_SIZE)
{
uInt32 byteOffset = address & BITMASK_RAM_BANK;
uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset;
pokeRAM(myRAM[baseAddress], address, value);
changed = true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
pokeRAM(dummy, address, value);
myRamWriteAccess = address;
changed = false;
}
}
}
@ -202,7 +214,7 @@ void Cartridge3EPlus::bankRAMSlot(uInt16 bank)
if(!upper)
access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
access.romAccessBase = &myRomAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
mySystem->setPageAccess(addr, access);
}
}
@ -242,7 +254,7 @@ void Cartridge3EPlus::bankROMSlot(uInt16 bank)
for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
access.romAccessBase = &myRomAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
mySystem->setPageAccess(addr, access);
}
}

View File

@ -30,7 +30,7 @@ Cartridge3F::Cartridge3F(const ByteBuffer& image, size_t size,
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
createCodeAccessBase(mySize);
createRomAccessArrays(mySize);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -57,7 +57,9 @@ void Cartridge3F::install(System& system)
for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)];
access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (addr & 0x07FF)];
access.romAccessBase = &myRomAccessBase[(mySize - 2048) + (addr & 0x07FF)];
access.romPeekCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF)];
access.romPokeCounter = &myRomAccessCounter[(mySize - 2048) + (addr & 0x07FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -117,7 +119,9 @@ bool Cartridge3F::bank(uInt16 bank)
for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[offset + (addr & 0x07FF)];
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x07FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x07FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -34,14 +34,14 @@ Cartridge4A50::Cartridge4A50(const ByteBuffer& image, size_t size,
for(uInt32 slice = 0; slice < 128_KB / size; ++slice)
std::copy_n(image.get(), size, myImage.begin() + (slice*size));
// We use System::PageAccess.codeAccessBase, but don't allow its use
// We use System::PageAccess.romAccessBase, but don't allow its use
// through a pointer, since the address space of 4A50 carts can change
// at the instruction level, and PageAccess is normally defined at an
// interval of 64 bytes
//
// Instead, access will be through the getAccessFlags and setAccessFlags
// methods below
createCodeAccessBase(myImage.size() + myRAM.size());
createRomAccessArrays(myImage.size() + myRAM.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -181,68 +181,70 @@ bool Cartridge4A50::poke(uInt16 address, uInt8 value)
return myBankChanged;
}
#ifdef DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Cartridge4A50::getAccessFlags(uInt16 address) const
Device::AccessFlags Cartridge4A50::getAccessFlags(uInt16 address) const
{
if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff
{
if(myIsRomLow)
return myCodeAccessBase[(address & 0x7ff) + mySliceLow];
return myRomAccessBase[(address & 0x7ff) + mySliceLow];
else
return myCodeAccessBase[131072 + (address & 0x7ff) + mySliceLow];
return myRomAccessBase[131072 + (address & 0x7ff) + mySliceLow];
}
else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff
((address & 0x1fff) <= 0x1dff))
{
if(myIsRomMiddle)
return myCodeAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000];
return myRomAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000];
else
return myCodeAccessBase[131072 + (address & 0x7ff) + mySliceMiddle];
return myRomAccessBase[131072 + (address & 0x7ff) + mySliceMiddle];
}
else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff
{
if(myIsRomHigh)
return myCodeAccessBase[(address & 0xff) + mySliceHigh + 0x10000];
return myRomAccessBase[(address & 0xff) + mySliceHigh + 0x10000];
else
return myCodeAccessBase[131072 + (address & 0xff) + mySliceHigh];
return myRomAccessBase[131072 + (address & 0xff) + mySliceHigh];
}
else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff
{
return myCodeAccessBase[(address & 0xff) + 0x1ff00];
return myRomAccessBase[(address & 0xff) + 0x1ff00];
}
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge4A50::setAccessFlags(uInt16 address, uInt8 flags)
void Cartridge4A50::setAccessFlags(uInt16 address, Device::AccessFlags flags)
{
if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff
{
if(myIsRomLow)
myCodeAccessBase[(address & 0x7ff) + mySliceLow] |= flags;
myRomAccessBase[(address & 0x7ff) + mySliceLow] |= flags;
else
myCodeAccessBase[131072 + (address & 0x7ff) + mySliceLow] |= flags;
myRomAccessBase[131072 + (address & 0x7ff) + mySliceLow] |= flags;
}
else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff
((address & 0x1fff) <= 0x1dff))
{
if(myIsRomMiddle)
myCodeAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000] |= flags;
myRomAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000] |= flags;
else
myCodeAccessBase[131072 + (address & 0x7ff) + mySliceMiddle] |= flags;
myRomAccessBase[131072 + (address & 0x7ff) + mySliceMiddle] |= flags;
}
else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff
{
if(myIsRomHigh)
myCodeAccessBase[(address & 0xff) + mySliceHigh + 0x10000] |= flags;
myRomAccessBase[(address & 0xff) + mySliceHigh + 0x10000] |= flags;
else
myCodeAccessBase[131072 + (address & 0xff) + mySliceHigh] |= flags;
myRomAccessBase[131072 + (address & 0xff) + mySliceHigh] |= flags;
}
else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff
{
myCodeAccessBase[(address & 0xff) + 0x1ff00] |= flags;
myRomAccessBase[(address & 0xff) + 0x1ff00] |= flags;
}
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge4A50::checkBankSwitch(uInt16 address, uInt8 value)

View File

@ -153,20 +153,21 @@ class Cartridge4A50 : public Cartridge
bool poke(uInt16 address, uInt8 value) override;
private:
#ifdef DEBUGGER_SUPPORT
/**
Query the given address type for the associated disassembly flags.
Query the given address type for the associated access flags.
@param address The address to query
*/
uInt8 getAccessFlags(uInt16 address) const override;
Device::AccessFlags getAccessFlags(uInt16 address) const override;
/**
Change the given address to use the given disassembly flags.
Change the given address to use the given access flags.
@param address The address to modify
@param flags A bitfield of DisasmType directives for the given address
@param flags A bitfield of AccessType directives for the given address
*/
void setAccessFlags(uInt16 address, uInt8 flags) override;
void setAccessFlags(uInt16 address, Device::AccessFlags flags) override;
#endif
/**
Check all possible hotspots
*/

View File

@ -25,7 +25,7 @@ Cartridge4K::Cartridge4K(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -46,7 +46,9 @@ void Cartridge4K::install(System& system)
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[addr & 0x0FFF];
access.codeAccessBase = &myCodeAccessBase[addr & 0x0FFF];
access.romAccessBase = &myRomAccessBase[addr & 0x0FFF];
access.romPeekCounter = &myRomAccessCounter[addr & 0x0FFF];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}

View File

@ -25,7 +25,7 @@ Cartridge4KSC::Cartridge4KSC(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -49,7 +49,7 @@ void Cartridge4KSC::install(System& system)
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
mySystem->setPageAccess(addr, access);
}
@ -58,7 +58,7 @@ void Cartridge4KSC::install(System& system)
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
mySystem->setPageAccess(addr, access);
}
@ -66,7 +66,7 @@ void Cartridge4KSC::install(System& system)
for(uInt16 addr = 0x1100; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[addr & 0x0FFF];
access.codeAccessBase = &myCodeAccessBase[addr & 0x0FFF];
access.romAccessBase = &myRomAccessBase[addr & 0x0FFF];
mySystem->setPageAccess(addr, access);
}
}

View File

@ -35,13 +35,13 @@ CartridgeAR::CartridgeAR(const ByteBuffer& image, size_t size,
std::copy_n(ourDefaultHeader.data(), ourDefaultHeader.size(),
myLoadImages.get()+myImage.size());
// We use System::PageAccess.codeAccessBase, but don't allow its use
// We use System::PageAccess.romAccessBase, but don't allow its use
// through a pointer, since the AR scheme doesn't support bankswitching
// in the normal sense
//
// Instead, access will be through the getAccessFlags and setAccessFlags
// methods below
createCodeAccessBase(mySize);
createRomAccessArrays(mySize);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -190,19 +190,21 @@ bool CartridgeAR::poke(uInt16 addr, uInt8)
return modified;
}
#ifdef DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeAR::getAccessFlags(uInt16 address) const
Device::AccessFlags CartridgeAR::getAccessFlags(uInt16 address) const
{
return myCodeAccessBase[(address & 0x07FF) +
return myRomAccessBase[(address & 0x07FF) +
myImageOffset[(address & 0x0800) ? 1 : 0]];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::setAccessFlags(uInt16 address, uInt8 flags)
void CartridgeAR::setAccessFlags(uInt16 address, Device::AccessFlags flags)
{
myCodeAccessBase[(address & 0x07FF) +
myRomAccessBase[(address & 0x07FF) +
myImageOffset[(address & 0x0800) ? 1 : 0]] |= flags;
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeAR::bankConfiguration(uInt8 configuration)

View File

@ -159,19 +159,21 @@ class CartridgeAR : public Cartridge
bool poke(uInt16 address, uInt8 value) override;
private:
#ifdef DEBUGGER_SUPPORT
/**
Query the given address type for the associated disassembly flags.
Query the given address type for the associated access flags.
@param address The address to query
*/
uInt8 getAccessFlags(uInt16 address) const override;
Device::AccessFlags getAccessFlags(uInt16 address) const override;
/**
Change the given address to use the given disassembly flags.
Change the given address to use the given access flags.
@param address The address to modify
@param flags A bitfield of DisasmType directives for the given address
@param flags A bitfield of AccessType directives for the given address
*/
void setAccessFlags(uInt16 address, uInt8 flags) override;
void setAccessFlags(uInt16 address, Device::AccessFlags flags) override;
#endif
// Handle a change to the bank configuration
bool bankConfiguration(uInt8 configuration);

View File

@ -25,7 +25,7 @@ CartridgeBF::CartridgeBF(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -88,7 +88,7 @@ bool CartridgeBF::bank(uInt16 bank)
for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
mySystem->setPageAccess(addr, access);
}
@ -97,7 +97,7 @@ bool CartridgeBF::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeBFSC::CartridgeBFSC(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -51,7 +51,7 @@ void CartridgeBFSC::install(System& system)
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
mySystem->setPageAccess(addr, access);
}
@ -60,7 +60,7 @@ void CartridgeBFSC::install(System& system)
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
mySystem->setPageAccess(addr, access);
}
@ -127,7 +127,7 @@ bool CartridgeBFSC::bank(uInt16 bank)
for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
mySystem->setPageAccess(addr, access);
}
@ -136,7 +136,7 @@ bool CartridgeBFSC::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -49,7 +49,7 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size,
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
// Even though the ROM is 32K, only 28K is accessible to the 6507
createCodeAccessBase(28_KB);
createRomAccessArrays(28_KB);
// Pointer to the program ROM (28K @ 0 byte offset)
// which starts after the 2K BUS Driver and 2K C Code
@ -442,7 +442,9 @@ bool CartridgeBUS::bank(uInt16 bank)
// Map Program ROM image into the system
for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + 28_KB];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -65,7 +65,7 @@ CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size,
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
// even though the ROM is 32K, only 28K is accessible to the 6507
createCodeAccessBase(28_KB);
createRomAccessArrays(28_KB);
// Pointer to the program ROM (28K @ 0 byte offset)
// which starts after the 2K CDF Driver and 2K C Code
@ -415,7 +415,9 @@ bool CartridgeCDF::bank(uInt16 bank)
// Map Program ROM image into the system
for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + 28_KB];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -27,7 +27,7 @@ CartridgeCM::CartridgeCM(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -119,7 +119,9 @@ bool CartridgeCM::bank(uInt16 bank)
for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -131,12 +133,16 @@ bool CartridgeCM::bank(uInt16 bank)
if(mySWCHA & 0x10)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
}
else
{
access.directPeekBase = &myRAM[addr & 0x7FF];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x07FF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x07FF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x07FF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x07FF) + myAccessSize];
}
if((mySWCHA & 0x30) == 0x20)

View File

@ -28,7 +28,7 @@ CartridgeCTY::CartridgeCTY(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
// Default to no tune data in case user is utilizing an old ROM
myTuneData.fill(0);
@ -240,7 +240,9 @@ bool CartridgeCTY::bank(uInt16 bank)
System::PageAccess access(this, System::PageAccessType::READ);
for(uInt16 addr = 0x1080; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -40,7 +40,7 @@ CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size,
// Copy the RAM image into a buffer for use in reset()
std::copy_n(image.get(), myInitialRAM.size(), myInitialRAM.begin());
}
createCodeAccessBase(myImage.size() + myRAM.size());
createRomAccessArrays(myImage.size() + myRAM.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -68,7 +68,9 @@ void CartridgeCV::install(System& system)
for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[addr & 0x07FF];
access.codeAccessBase = &myCodeAccessBase[addr & 0x07FF];
access.romAccessBase = &myRomAccessBase[addr & 0x07FF];
access.romPeekCounter = &myRomAccessCounter[addr & 0x07FF];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x07FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -76,7 +78,7 @@ void CartridgeCV::install(System& system)
// Map access to this class, since we need to inspect all accesses to
// check if RWP happens
access.directPeekBase = nullptr;
access.codeAccessBase = nullptr;
access.romAccessBase = nullptr;
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
mySystem->setPageAccess(addr, access);
@ -87,7 +89,9 @@ void CartridgeCV::install(System& system)
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x03FF];
access.codeAccessBase = &myCodeAccessBase[2048 + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[2048 + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[2048 + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[2048 + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}
@ -104,8 +108,21 @@ uInt8 CartridgeCV::peek(uInt16 address)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeCV::poke(uInt16 address, uInt8 value)
{
pokeRAM(myRAM[address & 0x03FF], address, value);
return true;
if(address & 0x0400)
{
pokeRAM(myRAM[address & 0x03FF], address, value);
return true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
pokeRAM(dummy, address, value);
myRamWriteAccess = address;
return false;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -30,7 +30,7 @@ CartridgeCVPlus::CartridgeCVPlus(const ByteBuffer& image, size_t size,
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
createCodeAccessBase(mySize + myRAM.size());
createRomAccessArrays(mySize + myRAM.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -58,11 +58,13 @@ void CartridgeCVPlus::install(System& system)
// Map access to this class, since we need to inspect all accesses to
// check if RWP happens
access.directPeekBase = access.directPokeBase = nullptr;
access.codeAccessBase = nullptr;
access.romAccessBase = nullptr;
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[mySize + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[mySize + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[mySize + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[mySize + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -71,7 +73,9 @@ void CartridgeCVPlus::install(System& system)
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x03FF];
access.codeAccessBase = &myCodeAccessBase[mySize + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[mySize + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[mySize + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[mySize + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -104,9 +108,22 @@ bool CartridgeCVPlus::poke(uInt16 address, uInt8 value)
return mySystem->tia().poke(address, value);
}
else
pokeRAM(myRAM[address & 0x03FF], pokeAddress, value);
{
if(address & 0x0400)
{
pokeRAM(myRAM[address & 0x03FF], pokeAddress, value);
return true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
return true;
pokeRAM(dummy, pokeAddress, value);
myRamWriteAccess = pokeAddress;
return false;
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -135,7 +152,7 @@ bool CartridgeCVPlus::bank(uInt16 bank)
for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[offset + (addr & 0x07FF)];
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x07FF)];
mySystem->setPageAccess(addr, access);
}

View File

@ -30,7 +30,7 @@ CartridgeDASH::CartridgeDASH(const ByteBuffer& image, size_t size,
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
createCodeAccessBase(mySize + myRAM.size());
createRomAccessArrays(mySize + myRAM.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -135,10 +135,22 @@ bool CartridgeDASH::poke(uInt16 address, uInt8 value)
if(whichBankIsThere & BITMASK_ROMRAM)
{
uInt32 byteOffset = address & BITMASK_RAM_BANK;
uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset;
pokeRAM(myRAM[baseAddress], address, value);
changed = true;
if(address & RAM_BANK_SIZE)
{
uInt32 byteOffset = address & BITMASK_RAM_BANK;
uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset;
pokeRAM(myRAM[baseAddress], address, value);
changed = true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
pokeRAM(dummy, address, value);
myRamWriteAccess = address;
changed = false;
}
}
}
@ -192,7 +204,7 @@ void CartridgeDASH::bankRAMSlot(uInt16 bank)
if(!upper)
access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
access.romAccessBase = &myRomAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))];
mySystem->setPageAccess(addr, access);
}
}
@ -235,7 +247,7 @@ void CartridgeDASH::bankROMSlot(uInt16 bank)
for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
access.romAccessBase = &myRomAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))];
mySystem->setPageAccess(addr, access);
}
}

View File

@ -25,7 +25,7 @@ CartridgeDF::CartridgeDF(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -84,7 +84,9 @@ bool CartridgeDF::bank(uInt16 bank)
for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -93,7 +95,9 @@ bool CartridgeDF::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeDFSC::CartridgeDFSC(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -51,7 +51,9 @@ void CartridgeDFSC::install(System& system)
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
access.romPeekCounter = &myRomAccessCounter[addr & 0x007F];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -60,7 +62,9 @@ void CartridgeDFSC::install(System& system)
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)];
access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -127,7 +131,9 @@ bool CartridgeDFSC::bank(uInt16 bank)
for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -136,7 +142,9 @@ bool CartridgeDFSC::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -27,7 +27,7 @@ CartridgeDPC::CartridgeDPC(const ByteBuffer& image, size_t size,
{
// Make a copy of the entire image
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(8_KB);
createRomAccessArrays(8_KB);
// Pointer to the program ROM (8K @ 0 byte offset)
myProgramImage = myImage.data();
@ -373,7 +373,9 @@ bool CartridgeDPC::bank(uInt16 bank)
for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -382,7 +384,9 @@ bool CartridgeDPC::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myProgramImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -36,7 +36,7 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size,
if(mySize < myImage.size())
myImage.fill(0);
std::copy_n(image.get(), size, myImage.begin() + (myImage.size() - mySize));
createCodeAccessBase(24_KB);
createRomAccessArrays(24_KB);
// Pointer to the program ROM (24K @ 3K offset; ignore first 3K)
myProgramImage = myImage.data() + 3_KB;
@ -57,9 +57,20 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size,
Thumbulator::ConfigureFor::DPCplus,
this);
// Currently only one known DPC+ ARM driver exhibits a problem
// with the default mask to use for DFxFRACLOW
if(MD5::hash(image, 3_KB) == "8dd73b44fd11c488326ce507cbeb19d1")
// Currently 4 DPC+ driver versions have been identified:
// 17884ec14f9b1d06fe8d617a1fbdcf47 Jitter Encore Compatible
// 5f80b5a5adbe483addc3f6e6f1b472f8 Stable Encore Compatible
// 8dd73b44fd11c488326ce507cbeb19d1 Stable NOT Encore Compatible
// b328dbdf787400c0f0e2b88b425872a5 Jitter Encore Compatible
//
// Jitter/Stable refers to the appearance of the playfield in bB games if
// the DFxFRACINC registers are not updated before every drawscreen.
//
// The default mask for DFxFRACLOW implements the Jitter behavior. This
// changes the mask to implement the Stable behavior.
myDriverMD5 = MD5::hash(image, 3_KB);
if(myDriverMD5 == "5f80b5a5adbe483addc3f6e6f1b472f8" ||
myDriverMD5 == "8dd73b44fd11c488326ce507cbeb19d1" )
myFractionalLowMask = 0x0F0000;
setInitialState();
@ -593,7 +604,9 @@ bool CartridgeDPCPlus::bank(uInt16 bank)
// Map Program ROM image into the system
for(uInt16 addr = 0x1080; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + 24_KB];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -272,6 +272,10 @@ class CartridgeDPCPlus : public Cartridge
// Indicates the offset into the ROM image (aligns to current bank)
uInt16 myBankOffset{0};
// MD5 value of the 3K DPC+ driver. Used to determine which mask to use,
// and shown in the Cartridge tab of the debugger
string myDriverMD5;
// Older DPC+ driver code had different behaviour wrt the mask used
// to retrieve 'DFxFRACLOW' (fractional data pointer low byte)
// ROMs built with an old DPC+ driver and using the newer mask can

View File

@ -25,7 +25,7 @@ CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -61,13 +61,17 @@ void CartridgeE0::install(System& system)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[0x1C00 + (addr & 0x03FF)];
access.codeAccessBase = &myCodeAccessBase[0x1C00 + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[0x1C00 + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[0x1C00 + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[0x1C00 + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
// Set the page accessing methods for the hot spots in the last segment
access.directPeekBase = nullptr;
access.codeAccessBase = &myCodeAccessBase[0x1FC0]; // TJ: is this the correct address (or 0x1FE0)?
access.romAccessBase = &myRomAccessBase[0x1FC0]; // TJ: is this the correct address (or 0x1FE0)?
access.romPeekCounter = &myRomAccessCounter[0x1FC0];
access.romPokeCounter = &myRomAccessCounter[0x1FC0 + myAccessSize];
access.type = System::PageAccessType::READ;
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
@ -144,7 +148,9 @@ void CartridgeE0::segmentZero(uInt16 slice)
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[offset + (addr & 0x03FF)];
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
myBankChanged = true;
@ -165,7 +171,9 @@ void CartridgeE0::segmentOne(uInt16 slice)
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[offset + (addr & 0x03FF)];
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
myBankChanged = true;
@ -186,7 +194,9 @@ void CartridgeE0::segmentTwo(uInt16 slice)
for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[offset + (addr & 0x03FF)];
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeEF::CartridgeEF(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -84,7 +84,9 @@ bool CartridgeEF::bank(uInt16 bank)
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -93,7 +95,9 @@ bool CartridgeEF::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeEFSC::CartridgeEFSC(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -51,7 +51,9 @@ void CartridgeEFSC::install(System& system)
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
access.romPeekCounter = &myRomAccessCounter[addr & 0x007F];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -60,7 +62,9 @@ void CartridgeEFSC::install(System& system)
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)];
access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -127,7 +131,9 @@ bool CartridgeEFSC::bank(uInt16 bank)
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -136,7 +142,9 @@ bool CartridgeEFSC::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeF0::CartridgeF0(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -91,7 +91,9 @@ bool CartridgeF0::bank(uInt16 bank)
for(uInt16 addr = (0x1FF0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -100,7 +102,9 @@ bool CartridgeF0::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}

View File

@ -26,7 +26,7 @@ CartridgeF4::CartridgeF4(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -88,7 +88,9 @@ bool CartridgeF4::bank(uInt16 bank)
for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -97,7 +99,9 @@ bool CartridgeF4::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeF4SC::CartridgeF4SC(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -51,7 +51,9 @@ void CartridgeF4SC::install(System& system)
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
access.romPeekCounter = &myRomAccessCounter[addr & 0x007F];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -60,7 +62,9 @@ void CartridgeF4SC::install(System& system)
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)];
access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -127,7 +131,9 @@ bool CartridgeF4SC::bank(uInt16 bank)
for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -136,7 +142,9 @@ bool CartridgeF4SC::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeF6::CartridgeF6(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -128,7 +128,9 @@ bool CartridgeF6::bank(uInt16 bank)
for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -137,7 +139,9 @@ bool CartridgeF6::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeF6SC::CartridgeF6SC(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -51,7 +51,9 @@ void CartridgeF6SC::install(System& system)
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
access.romPeekCounter = &myRomAccessCounter[addr & 0x007F];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -60,7 +62,9 @@ void CartridgeF6SC::install(System& system)
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)];
access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -167,7 +171,9 @@ bool CartridgeF6SC::bank(uInt16 bank)
for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -176,7 +182,9 @@ bool CartridgeF6SC::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeF8::CartridgeF8(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -109,7 +109,9 @@ bool CartridgeF8::bank(uInt16 bank)
for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -118,7 +120,9 @@ bool CartridgeF8::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeF8SC::CartridgeF8SC(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -51,7 +51,9 @@ void CartridgeF8SC::install(System& system)
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
access.romAccessBase = &myRomAccessBase[addr & 0x007F];
access.romPeekCounter = &myRomAccessCounter[addr & 0x007F];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x07F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -60,7 +62,9 @@ void CartridgeF8SC::install(System& system)
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x007F];
access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
access.romAccessBase = &myRomAccessBase[0x80 + (addr & 0x007F)];
access.romPeekCounter = &myRomAccessCounter[0x80 + (addr & 0x007F)];
access.romPokeCounter = &myRomAccessCounter[0x80 + (addr & 0x007F) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -147,7 +151,9 @@ bool CartridgeF8SC::bank(uInt16 bank)
for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -156,7 +162,9 @@ bool CartridgeF8SC::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -25,7 +25,7 @@ CartridgeFA::CartridgeFA(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -51,7 +51,9 @@ void CartridgeFA::install(System& system)
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[addr & 0x00FF];
access.romAccessBase = &myRomAccessBase[addr & 0x00FF];
access.romPeekCounter = &myRomAccessCounter[addr & 0x00FF];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -60,7 +62,9 @@ void CartridgeFA::install(System& system)
for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x00FF];
access.codeAccessBase = &myCodeAccessBase[0x100 + (addr & 0x00FF)];
access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)];
access.romPeekCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF)];
access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -157,7 +161,9 @@ bool CartridgeFA::bank(uInt16 bank)
for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -166,7 +172,9 @@ bool CartridgeFA::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -35,7 +35,7 @@ CartridgeFA2::CartridgeFA2(const ByteBuffer& image, size_t size,
// Copy the ROM image into my buffer
std::copy_n(img_ptr, mySize, myImage.begin());
createCodeAccessBase(mySize);
createRomAccessArrays(mySize);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -61,7 +61,9 @@ void CartridgeFA2::install(System& system)
access.type = System::PageAccessType::WRITE;
for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[addr & 0x00FF];
access.romAccessBase = &myRomAccessBase[addr & 0x00FF];
access.romPeekCounter = &myRomAccessCounter[addr & 0x00FF];
access.romPokeCounter = &myRomAccessCounter[(addr & 0x00FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -71,7 +73,9 @@ void CartridgeFA2::install(System& system)
for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myRAM[addr & 0x00FF];
access.codeAccessBase = &myCodeAccessBase[0x100 + (addr & 0x00FF)];
access.romAccessBase = &myRomAccessBase[0x100 + (addr & 0x00FF)];
access.romPeekCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF)];
access.romPokeCounter = &myRomAccessCounter[0x100 + (addr & 0x00FF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -222,7 +226,9 @@ bool CartridgeFA2::bank(uInt16 bank)
for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -231,7 +237,9 @@ bool CartridgeFA2::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -26,7 +26,7 @@ CartridgeFC::CartridgeFC(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -113,7 +113,9 @@ bool CartridgeFC::bank(uInt16 bank)
for (uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
@ -122,7 +124,9 @@ bool CartridgeFC::bank(uInt16 bank)
addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
myCurrentBank = myTargetBank;

View File

@ -26,7 +26,7 @@ CartridgeFE::CartridgeFE(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -49,11 +49,6 @@ void CartridgeFE::install(System& system)
System::PageAccess access(this, System::PageAccessType::READWRITE);
for(uInt16 addr = 0x180; addr < 0x200; addr += System::PAGE_SIZE)
mySystem->setPageAccess(addr, access);
// Map all of the cart accesses to call peek and poke
access.type = System::PageAccessType::READ;
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
mySystem->setPageAccess(addr, access);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -104,6 +99,19 @@ bool CartridgeFE::bank(uInt16 bank)
return false;
myBankOffset = bank << 12;
System::PageAccess access(this, System::PageAccessType::READ);
// Setup the page access methods for the current bank
// Map all of the cart accesses to call peek and poke
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;
}
@ -160,7 +168,7 @@ bool CartridgeFE::load(Serializer& in)
}
catch(...)
{
cerr << "ERROR: CartridgeF8SC::load" << endl;
cerr << "ERROR: CartridgeFE::load" << endl;
return false;
}

View File

@ -29,7 +29,7 @@ CartridgeMDM::CartridgeMDM(const ByteBuffer& image, size_t size,
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
createCodeAccessBase(mySize);
createRomAccessArrays(mySize);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -111,7 +111,9 @@ bool CartridgeMDM::bank(uInt16 bank)
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}

View File

@ -34,7 +34,7 @@ void CartridgeMNetwork::initialize(const ByteBuffer& image, size_t size)
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min<size_t>(romSize(), size), myImage.get());
createCodeAccessBase(romSize() + myRAM.size());
createRomAccessArrays(romSize() + myRAM.size());
myRAMSlice = bankCount() - 1;
}
@ -70,7 +70,9 @@ void CartridgeMNetwork::setAccess(uInt16 addrFrom, uInt16 size,
access.directPeekBase = &directData[directOffset + (addr & addrMask)];
else if(type == System::PageAccessType::WRITE) // all RAM writes mapped to ::poke()
access.directPokeBase = nullptr;
access.codeAccessBase = &myCodeAccessBase[codeOffset + (addr & addrMask)];
access.romAccessBase = &myRomAccessBase[codeOffset + (addr & addrMask)];
access.romPeekCounter = &myRomAccessCounter[codeOffset + (addr & addrMask)];
access.romPokeCounter = &myRomAccessCounter[codeOffset + (addr & addrMask) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
}
@ -86,7 +88,9 @@ void CartridgeMNetwork::install(System& system)
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[0x1fc0];
access.romAccessBase = &myRomAccessBase[0x1fc0];
access.romPeekCounter = &myRomAccessCounter[0x1fc0];
access.romPokeCounter = &myRomAccessCounter[0x1fc0 + myAccessSize];
mySystem->setPageAccess(addr, access);
}
/*setAccess(0x1FE0 & ~System::PAGE_MASK, System::PAGE_SIZE,
@ -137,13 +141,42 @@ bool CartridgeMNetwork::poke(uInt16 address, uInt8 value)
// All RAM writes are mapped here
if((myCurrentSlice[0] == myRAMSlice) && (address < BANK_SIZE / 2))
{
pokeRAM(myRAM[address & (BANK_SIZE / 2 - 1)], pokeAddress, value);
return true;
// RAM slices
if(!(address & 0x0400))
{
pokeRAM(myRAM[address & (BANK_SIZE / 2 - 1)], pokeAddress, value);
return true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
pokeRAM(dummy, pokeAddress, value);
myRamWriteAccess = pokeAddress;
return false;
}
}
else if((address >= 0x0800) && (address <= 0x08FF))
else
{
pokeRAM(myRAM[0x0400 + (myCurrentRAM << 8) + (address & 0x00FF)], pokeAddress, value);
return true;
// fixed 256 bytes of RAM
if((address >= 0x0800) && (address <= 0x09FF))
{
if(!(address & 0x100))
{
pokeRAM(myRAM[0x0400 + (myCurrentRAM << 8) + (address & 0x00FF)], pokeAddress, value);
return true;
}
else
{
// Writing to the read port should be ignored, but trigger a break if option enabled
uInt8 dummy;
pokeRAM(dummy, pokeAddress, value);
myRamWriteAccess = pokeAddress;
return false;
}
}
}
return false;

View File

@ -29,7 +29,7 @@ CartridgeSB::CartridgeSB(const ByteBuffer& image, size_t size,
// Copy the ROM image into my buffer
std::copy_n(image.get(), mySize, myImage.get());
createCodeAccessBase(mySize);
createRomAccessArrays(mySize);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -121,7 +121,9 @@ bool CartridgeSB::bank(uInt16 bank)
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -27,7 +27,7 @@ CartridgeUA::CartridgeUA(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -135,7 +135,9 @@ bool CartridgeUA::bank(uInt16 bank)
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -37,7 +37,7 @@ CartridgeWD::CartridgeWD(const ByteBuffer& image, size_t size,
}
else
std::copy_n(image.get(), mySize, myImage.begin());
createCodeAccessBase(8_KB);
createRomAccessArrays(8_KB);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -63,7 +63,9 @@ void CartridgeWD::install(System& system)
for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE)
{
read.directPeekBase = &myRAM[addr & 0x003F];
read.codeAccessBase = &myCodeAccessBase[addr & 0x003F];
read.romAccessBase = &myRomAccessBase[addr & 0x003F];
read.romPeekCounter = &myRomAccessCounter[addr & 0x003F];
read.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + 8_KB];
mySystem->setPageAccess(addr, read);
}
@ -73,7 +75,9 @@ void CartridgeWD::install(System& system)
System::PageAccess write(this, System::PageAccessType::WRITE);
for(uInt16 addr = 0x1040; addr < 0x1080; addr += System::PAGE_SIZE)
{
write.codeAccessBase = &myCodeAccessBase[addr & 0x003F];
write.romAccessBase = &myRomAccessBase[addr & 0x003F];
write.romPeekCounter = &myRomAccessCounter[addr & 0x003F];
write.romPokeCounter = &myRomAccessCounter[(addr & 0x003F) + 8_KB];
mySystem->setPageAccess(addr, write);
}
@ -177,7 +181,9 @@ void CartridgeWD::segmentZero(uInt8 slice)
// Skip first 128 bytes; it is always RAM
for(uInt16 addr = 0x1080; addr < 0x1400; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB];
mySystem->setPageAccess(addr, access);
}
myOffset[0] = offset;
@ -191,7 +197,9 @@ void CartridgeWD::segmentOne(uInt8 slice)
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB];
mySystem->setPageAccess(addr, access);
}
myOffset[1] = offset;
@ -205,7 +213,9 @@ void CartridgeWD::segmentTwo(uInt8 slice)
for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB];
mySystem->setPageAccess(addr, access);
}
myOffset[2] = offset;
@ -225,7 +235,9 @@ void CartridgeWD::segmentThree(uInt8 slice)
for(uInt16 addr = 0x1C00; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x03FF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x03FF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x03FF) + 8_KB];
mySystem->setPageAccess(addr, access);
}
myOffset[3] = offset;

View File

@ -27,7 +27,7 @@ CartridgeX07::CartridgeX07(const ByteBuffer& image, size_t size,
{
// Copy the ROM image into my buffer
std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
createCodeAccessBase(myImage.size());
createRomAccessArrays(myImage.size());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -115,7 +115,9 @@ bool CartridgeX07::bank(uInt16 bank)
for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
{
access.directPeekBase = &myImage[offset + (addr & 0x0FFF)];
access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x0FFF)];
access.romAccessBase = &myRomAccessBase[offset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[offset + (addr & 0x0FFF)];
access.romPokeCounter = &myRomAccessCounter[offset + (addr & 0x0FFF) + myAccessSize];
mySystem->setPageAccess(addr, access);
}
return myBankChanged = true;

View File

@ -745,7 +745,7 @@ void Console::updateVcenter(Int32 vcenter)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Console::changeScanlineAdjust(int direction)
{
Int32 newAdjustVSize = myTIA->adjustVSize();;
Int32 newAdjustVSize = myTIA->adjustVSize();
if (direction != -1 && direction != +1) return;
@ -923,6 +923,11 @@ unique_ptr<Controller> Console::getControllerPort(const Controller::Type type,
swapAxis = true;
else if(type == Controller::Type::PaddlesIAxDr)
swapAxis = swapDir = true;
Paddles::setAnalogXCenter(BSPF::stringToInt(myProperties.get(PropType::Controller_PaddlesXCenter)));
Paddles::setAnalogYCenter(BSPF::stringToInt(myProperties.get(PropType::Controller_PaddlesYCenter)));
Paddles::setAnalogSensitivity(myOSystem.settings().getInt("psense"));
controller = make_unique<Paddles>(port, myEvent, *mySystem,
swapPaddles, swapAxis, swapDir);
break;

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,39 @@ class System;
*/
class Device : public Serializable
{
public:
enum AccessType {
NONE = 0,
REFERENCED = 1 << 0, /* 0x01, code somewhere in the program references it,
i.e. LDA $F372 referenced $F372 */
VALID_ENTRY = 1 << 1, /* 0x02, addresses that can have a label placed in front of it.
A good counterexample would be "FF00: LDA $FE00"; $FF01
would be in the middle of a multi-byte instruction, and
therefore cannot be labelled. */
// The following correspond to specific types that can be set within the
// debugger, or specified in a Distella cfg file, and are listed in order
// of increasing hierarchy
//
ROW = 1 << 2, // 0x004, all other addresses
DATA = 1 << 3, // 0x008, addresses loaded into registers other than GRPx / PFx / COLUxx, AUDxx
AUD = 1 << 4, // 0x010, addresses loaded into audio registers
BCOL = 1 << 5, // 0x020, addresses loaded into COLUBK register
PCOL = 1 << 6, // 0x040, addresses loaded into COLUPF register
COL = 1 << 7, // 0x080, addresses loaded into COLUPx registers
PGFX = 1 << 8, // 0x100, addresses loaded into PFx registers
GFX = 1 << 9, // 0x200, addresses loaded into GRPx registers
TCODE = 1 << 10, // 0x400, (tentative) disassemble-able code segments
CODE = 1 << 11, // 0x800, disassemble-able code segments
// special bits for address
HADDR = 1 << 13 | 1 << 14 | 1 << 15, // 0xe000, // highest 3 address bits
// special type for poke()
WRITE = TCODE // 0x200, address written to
};
using AccessFlags = uInt16;
using AccessCounter = uInt32;
public:
Device() = default;
virtual ~Device() = default;
@ -97,20 +130,36 @@ class Device : public Serializable
*/
virtual bool poke(uInt16 address, uInt8 value) { return false; }
#ifdef DEBUGGER_SUPPORT
/**
Query the given address for its disassembly flags
Query the given address for its access flags
@param address The address to modify
*/
virtual uInt8 getAccessFlags(uInt16 address) const { return 0; }
virtual AccessFlags getAccessFlags(uInt16 address) const { return AccessType::NONE; }
/**
Change the given address type to use the given disassembly flags
Change the given address type to use the given access flags
@param address The address to modify
@param flags A bitfield of DisasmType directives for the given address
@param flags A bitfield of AccessType directives for the given address
*/
virtual void setAccessFlags(uInt16 address, uInt8 flags) { }
virtual void setAccessFlags(uInt16 address, AccessFlags flags) { }
/**
Increase the given address's access counter
@param address The address to modify
*/
virtual void increaseAccessCounter(uInt16 address, bool isWrite = false) { }
/**
Query the access counters
@return The access counters as comma separated string
*/
virtual string getAccessCounters() const { return ""; }
#endif
protected:
/// Pointer to the system the device is installed in or the null pointer

View File

@ -55,7 +55,7 @@ class DispatchResult
if (myStatus != status) throw runtime_error("invalid status for operation");
}
template<class ...Ts> void assertStatus(Status status, Ts... more) const
template<typename ...Ts> void assertStatus(Status status, Ts... more) const
{
if (myStatus == status) return;

View File

@ -49,10 +49,6 @@ Driving::Driving(Jack jack, const Event& event, const System& system)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Driving::update()
{
// Make sure direct gray codes from Stelladaptor stay in sync with
// simulated gray codes generated by PC keyboard or PC joystick
myCounter = (myGrayIndex << 2) | (myCounter & 3);
// Digital events (from keyboard or joystick hats & buttons)
setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0);
int d_axis = myEvent.get(myXAxisValue);
@ -92,8 +88,7 @@ void Driving::update()
}
// Only consider the lower-most bits (corresponding to pins 1 & 2)
myCounter &= 0x0f;
myGrayIndex = myCounter >> 2;
myGrayIndex = Int32(myCounter * SENSITIVITY / 4.0F) & 0b11;
// Stelladaptor is the only controller that should set this
int yaxis = myEvent.get(myYAxisValue);
@ -111,6 +106,10 @@ void Driving::update()
myGrayIndex = 2; // up + down
else /* if(yaxis < 16384-4096) */
myGrayIndex = 0; // no movement
// Make sure direct gray codes from Stelladaptor stay in sync with
// simulated gray codes generated by PC keyboard or PC joystick
myCounter = myGrayIndex / SENSITIVITY * 4.0F;
}
// Gray codes for rotation
@ -154,3 +153,13 @@ bool Driving::setMouseControl(
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Driving::setSensitivity(int sensitivity)
{
BSPF::clamp(sensitivity, 1, 20, 10);
SENSITIVITY = sensitivity / 10.0F;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
float Driving::SENSITIVITY = 1.0;

View File

@ -76,9 +76,18 @@ class Driving : public Controller
bool setMouseControl(
Controller::Type xtype, int xid, Controller::Type ytype, int yid) override;
/**
Sets the sensitivity for digital emulation of driving controlle movement
using a keyboard.
@param sensitivity Value from 1 to 20, with larger values causing
more movement (10 represents the baseline)
*/
static void setSensitivity(int sensitivity);
private:
// Counter to iterate through the gray codes
uInt32 myCounter{0};
Int32 myCounter{0};
// Index into the gray code table
uInt32 myGrayIndex{0};
@ -98,6 +107,10 @@ class Driving : public Controller
// Controllers to emulate in 'specific' mouse axis mode
int myControlIDX{-1}, myControlIDY{-1};
// User-defined sensitivity; adjustable since end-users may prefer different
// speeds
static float SENSITIVITY;
private:
// Following constructors and assignment operators not supported
Driving() = delete;

View File

@ -29,6 +29,7 @@
#include "Paddles.hxx"
#include "Lightgun.hxx"
#include "PointingDevice.hxx"
#include "Driving.hxx"
#include "PropsSet.hxx"
#include "Settings.hxx"
#include "Sound.hxx"
@ -97,6 +98,7 @@ void EventHandler::initialize()
Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense"));
Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense"));
PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense"));
Driving::setSensitivity(myOSystem.settings().getInt("dcsense"));
#ifdef GUI_SUPPORT
// Set quick select delay when typing characters in listwidgets

View File

@ -36,9 +36,14 @@
#ifdef GUI_SUPPORT
#include "Font.hxx"
#include "StellaFont.hxx"
#include "ConsoleMediumBFont.hxx"
#include "StellaMediumFont.hxx"
#include "StellaLargeFont.hxx"
#include "Stella12x24tFont.hxx"
#include "Stella14x28tFont.hxx"
#include "Stella16x32tFont.hxx"
#include "ConsoleFont.hxx"
#include "ConsoleBFont.hxx"
#include "Launcher.hxx"
#include "Menu.hxx"
#include "CommandMenu.hxx"
@ -106,27 +111,42 @@ bool FrameBuffer::initialize()
// This font is used in a variety of situations when a really small
// font is needed; we let the specific widget/dialog decide when to
// use it
mySmallFont = make_unique<GUI::Font>(GUI::stellaDesc);
mySmallFont = make_unique<GUI::Font>(GUI::stellaDesc); // 6x10
// The general font used in all UI elements
// This is determined by the size of the framebuffer
if(myOSystem.settings().getBool("minimal_ui"))
myFont = make_unique<GUI::Font>(GUI::stellaLargeDesc);
{
myFont = make_unique<GUI::Font>(GUI::stella12x24tDesc); // 12x24
// The info font used in all UI elements
// This is determined by the size of the framebuffer
myInfoFont = make_unique<GUI::Font>(GUI::stellaLargeDesc); // 10x20
}
else
myFont = make_unique<GUI::Font>(GUI::stellaMediumDesc);
{
myFont = make_unique<GUI::Font>(GUI::stellaMediumDesc); // 9x18
// The info font used in all UI elements
// This is determined by the size of the framebuffer
myInfoFont = make_unique<GUI::Font>(GUI::consoleDesc); // 8x13
}
// The info font used in all UI elements
// This is determined by the size of the framebuffer
myInfoFont = make_unique<GUI::Font>(GUI::consoleDesc);
// The font used by the ROM launcher
const string& lf = myOSystem.settings().getString("launcherfont");
if(lf == "small")
myLauncherFont = make_unique<GUI::Font>(GUI::consoleDesc);
myLauncherFont = make_unique<GUI::Font>(GUI::consoleBDesc); // 8x13
else if(lf == "low_medium")
myLauncherFont = make_unique<GUI::Font>(GUI::consoleMediumBDesc); // 9x15
else if(lf == "medium")
myLauncherFont = make_unique<GUI::Font>(GUI::stellaMediumDesc);
else
myLauncherFont = make_unique<GUI::Font>(GUI::stellaLargeDesc);
myLauncherFont = make_unique<GUI::Font>(GUI::stellaMediumDesc); // 9x18
else if(lf == "large" || lf == "large10")
myLauncherFont = make_unique<GUI::Font>(GUI::stellaLargeDesc); // 10x20
else if(lf == "large12")
myLauncherFont = make_unique<GUI::Font>(GUI::stella12x24tDesc); // 12x24
else if(lf == "large14")
myLauncherFont = make_unique<GUI::Font>(GUI::stella14x28tDesc); // 14x28
else // "large16"
myLauncherFont = make_unique<GUI::Font>(GUI::stella16x32tDesc); // 16x32
#endif
// Determine possible TIA windowed zoom levels

View File

@ -381,6 +381,16 @@ class FrameBuffer
*/
virtual void clear() = 0;
/**
Transform from window to renderer coordinates, x direction
*/
virtual int scaleX(int x) const { return x; }
/**
Transform from window to renderer coordinates, y direction
*/
virtual int scaleY(int y) const { return y; }
protected:
/**
This method is called to query and initialize the video hardware

View File

@ -18,26 +18,20 @@
#ifdef DEBUGGER_SUPPORT
#include "Debugger.hxx"
#include "Expression.hxx"
#include "CartDebug.hxx"
#include "Device.hxx"
#include "Base.hxx"
// Flags for disassembly types
#define DISASM_CODE CartDebug::CODE
// #define DISASM_GFX CartDebug::GFX
// #define DISASM_PGFX CartDebug::PGFX
#define DISASM_DATA CartDebug::DATA
// #define DISASM_ROW CartDebug::ROW
#define DISASM_WRITE CartDebug::WRITE
#define DISASM_NONE 0
// Flags for access types
#define DISASM_CODE Device::CODE
#define DISASM_DATA Device::DATA
#define DISASM_WRITE Device::WRITE
#define DISASM_NONE Device::NONE
#else
// Flags for disassembly types
// Flags for access types
#define DISASM_CODE 0
// #define DISASM_GFX 0
// #define DISASM_PGFX 0
#define DISASM_DATA 0
// #define DISASM_ROW 0
#define DISASM_NONE 0
#define DISASM_WRITE 0
#define DISASM_NONE 0
#endif
#include "Settings.hxx"
#include "Vec.hxx"
@ -104,7 +98,7 @@ void M6502::reset()
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline uInt8 M6502::peek(uInt16 address, uInt8 flags)
inline uInt8 M6502::peek(uInt16 address, Device::AccessFlags flags)
{
handleHalt();
@ -144,7 +138,7 @@ inline uInt8 M6502::peek(uInt16 address, uInt8 flags)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags)
inline void M6502::poke(uInt16 address, uInt8 value, Device::AccessFlags flags)
{
////////////////////////////////////////////////
// TODO - move this logic directly into CartAR
@ -300,8 +294,8 @@ inline void M6502::_execute(uInt64 cycles, DispatchResult& result)
mySystem->cart().clearAllRAMAccesses();
#endif // DEBUGGER_SUPPORT
// Reset the peek/poke address pointers
myLastPeekAddress = myLastPokeAddress = myDataAddressForPoke = 0;
// Reset the data poke address pointer
myDataAddressForPoke = 0;
try {
uInt16 operandAddress = 0, intermediateAddress = 0;

View File

@ -34,6 +34,7 @@ class DispatchResult;
#endif
#include "bspf.hxx"
#include "Device.hxx"
#include "Serializable.hxx"
/**
@ -156,13 +157,27 @@ class M6502 : public Serializable
@return The address of the last read
*/
uInt16 lastReadBaseAddress() const { return myLastPeekBaseAddress; }
uInt16 lastReadAddress() const { return myLastPeekAddress; }
/**
Return the last address that was part of a write/poke.
@return The address of the last write
*/
uInt16 lastWriteAddress() const { return myLastPokeAddress; }
/**
Return the last (non-mirrored) address that was part of a read/peek.
@return The address of the last read
*/
uInt16 lastReadBaseAddress() const { return myLastPeekBaseAddress; }
/**
Return the last (non-mirrored) address that was part of a write/poke.
@return The address of the last write
*/
uInt16 lastWriteBaseAddress() const { return myLastPokeBaseAddress; }
/**
@ -255,7 +270,7 @@ class M6502 : public Serializable
@return The byte at the specified address
*/
uInt8 peek(uInt16 address, uInt8 flags);
uInt8 peek(uInt16 address, Device::AccessFlags flags);
/**
Change the byte at the specified address to the given value and
@ -264,7 +279,7 @@ class M6502 : public Serializable
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
void poke(uInt16 address, uInt8 value, uInt8 flags = 0);
void poke(uInt16 address, uInt8 value, Device::AccessFlags flags = Device::NONE);
/**
Get the 8-bit value of the Processor Status register.
@ -377,7 +392,7 @@ class M6502 : public Serializable
/// accessed specifically by a peek or poke command
uInt16 myLastPeekBaseAddress{0}, myLastPokeBaseAddress{0};
// Indicates the type of the last access
uInt8 myFlags{0};
uInt16 myFlags{0};
/// Indicates the last address used to access data by a peek command
/// for the CPU registers (S/A/X/Y)

View File

@ -3770,9 +3770,9 @@ case 0x40:
}
{
peek(0x0100 + SP++, DISASM_NONE);
PS(peek(0x0100 + SP++, DISASM_NONE));
PC = peek(0x0100 + SP++, DISASM_NONE);
PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8);
PS(peek(0x0100 + SP++, DISASM_DATA));
PC = peek(0x0100 + SP++, DISASM_DATA);
PC |= (uInt16(peek(0x0100 + SP, DISASM_DATA)) << 8);
}
break;
@ -3784,8 +3784,8 @@ case 0x60:
}
{
peek(0x0100 + SP++, DISASM_NONE);
PC = peek(0x0100 + SP++, DISASM_NONE);
PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8);
PC = peek(0x0100 + SP++, DISASM_DATA);
PC |= (uInt16(peek(0x0100 + SP, DISASM_DATA)) << 8);
peek(PC++, DISASM_NONE);
}
break;

View File

@ -885,15 +885,15 @@ define(M6502_RRA, `{
define(M6502_RTI, `{
peek(0x0100 + SP++, DISASM_NONE);
PS(peek(0x0100 + SP++, DISASM_NONE));
PC = peek(0x0100 + SP++, DISASM_NONE);
PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8);
PS(peek(0x0100 + SP++, DISASM_DATA));
PC = peek(0x0100 + SP++, DISASM_DATA);
PC |= (uInt16(peek(0x0100 + SP, DISASM_DATA)) << 8);
}')
define(M6502_RTS, `{
peek(0x0100 + SP++, DISASM_NONE);
PC = peek(0x0100 + SP++, DISASM_NONE);
PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8);
PC = peek(0x0100 + SP++, DISASM_DATA);
PC |= (uInt16(peek(0x0100 + SP, DISASM_DATA)) << 8);
peek(PC++, DISASM_NONE);
}')

View File

@ -21,9 +21,7 @@
#include "Settings.hxx"
#include "Switches.hxx"
#include "System.hxx"
#ifdef DEBUGGER_SUPPORT
#include "CartDebug.hxx"
#endif
#include "Base.hxx"
#include "M6532.hxx"
@ -460,14 +458,17 @@ uInt32 M6532::timerClocks() const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::createAccessBases()
{
myRAMAccessBase.fill(CartDebug::NONE);
myStackAccessBase.fill(CartDebug::NONE);
myIOAccessBase.fill(CartDebug::NONE);
myRAMAccessBase.fill(Device::NONE);
myStackAccessBase.fill(Device::NONE);
myIOAccessBase.fill(Device::NONE);
myRAMAccessCounter.fill(0);
myStackAccessCounter.fill(0);
myIOAccessCounter.fill(0);
myZPAccessDelay.fill(ZP_DELAY);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 M6532::getAccessFlags(uInt16 address) const
Device::AccessFlags M6532::getAccessFlags(uInt16 address) const
{
if (address & IO_BIT)
return myIOAccessBase[address & IO_MASK];
@ -478,10 +479,10 @@ uInt8 M6532::getAccessFlags(uInt16 address) const
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::setAccessFlags(uInt16 address, uInt8 flags)
void M6532::setAccessFlags(uInt16 address, Device::AccessFlags flags)
{
// ignore none flag
if (flags != CartDebug::NONE) {
if (flags != Device::NONE) {
if (address & IO_BIT)
myIOAccessBase[address & IO_MASK] |= flags;
else {
@ -495,4 +496,63 @@ void M6532::setAccessFlags(uInt16 address, uInt8 flags)
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::increaseAccessCounter(uInt16 address, bool isWrite)
{
if (address & IO_BIT)
myIOAccessCounter[(isWrite ? IO_SIZE : 0) + (address & IO_MASK)]++;
else {
// the first access, either by direct RAM or stack access is assumed as initialization
if (myZPAccessDelay[address & RAM_MASK])
myZPAccessDelay[address & RAM_MASK]--;
else if (address & STACK_BIT)
myStackAccessCounter[(isWrite ? STACK_SIZE : 0) + (address & STACK_MASK)]++;
else
myRAMAccessCounter[(isWrite ? RAM_SIZE : 0) + (address & RAM_MASK)]++;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string M6532::getAccessCounters() const
{
ostringstream out;
out << "RAM reads:\n";
for(uInt16 addr = 0x00; addr < RAM_SIZE; ++addr)
out << Common::Base::HEX4 << (addr | 0x80) << ","
<< Common::Base::toString(myRAMAccessCounter[addr], Common::Base::Fmt::_10_8) << ", ";
out << "\n";
out << "RAM writes:\n";
for(uInt16 addr = 0x00; addr < RAM_SIZE; ++addr)
out << Common::Base::HEX4 << (addr | 0x80) << ","
<< Common::Base::toString(myRAMAccessCounter[RAM_SIZE + addr], Common::Base::Fmt::_10_8) << ", ";
out << "\n";
out << "Stack reads:\n";
for(uInt16 addr = 0x00; addr < STACK_SIZE; ++addr)
out << Common::Base::HEX4 << (addr | 0x180) << ","
<< Common::Base::toString(myStackAccessCounter[addr], Common::Base::Fmt::_10_8) << ", ";
out << "\n";
out << "Stack writes:\n";
for(uInt16 addr = 0x00; addr < STACK_SIZE; ++addr)
out << Common::Base::HEX4 << (addr | 0x180) << ","
<< Common::Base::toString(myStackAccessCounter[STACK_SIZE + addr], Common::Base::Fmt::_10_8) << ", ";
out << "\n";
out << "IO reads:\n";
for(uInt16 addr = 0x00; addr < IO_SIZE; ++addr)
out << Common::Base::HEX4 << (addr | 0x280) << ","
<< Common::Base::toString(myIOAccessCounter[addr], Common::Base::Fmt::_10_8) << ", ";
out << "\n";
out << "IO writes:\n";
for(uInt16 addr = 0x00; addr < IO_SIZE; ++addr)
out << Common::Base::HEX4 << (addr | 0x280) << ","
<< Common::Base::toString(myIOAccessCounter[IO_SIZE + addr], Common::Base::Fmt::_10_8) << ", ";
out << "\n";
return out.str();
}
#endif // DEBUGGER_SUPPORT

View File

@ -130,12 +130,21 @@ class M6532 : public Device
*/
const uInt8* getRAM() const { return myRAM.data(); }
#ifdef DEBUGGER_SUPPORT
/**
Query the access counters
@return The access counters as comma separated string
*/
string getAccessCounters() const override;
#endif
private:
void setTimerRegister(uInt8 data, uInt8 interval);
void setPinState(bool shcha);
#ifdef DEBUGGER_SUPPORT
#ifdef DEBUGGER_SUPPORT
// The following are used by the debugger to read INTIM/TIMINT
// We need separate methods to do this, so the state of the system
// isn't changed
@ -147,19 +156,26 @@ class M6532 : public Device
void createAccessBases();
/**
Query the given address type for the associated disassembly flags.
Query the given address type for the associated access flags.
@param address The address to query
*/
uInt8 getAccessFlags(uInt16 address) const override;
Device::AccessFlags getAccessFlags(uInt16 address) const override;
/**
Change the given address to use the given disassembly flags.
Change the given address to use the given access flags.
@param address The address to modify
@param flags A bitfield of DisasmType directives for the given address
@param flags A bitfield of AccessType directives for the given address
*/
void setAccessFlags(uInt16 address, uInt8 flags) override;
#endif // DEBUGGER_SUPPORT
void setAccessFlags(uInt16 address, Device::AccessFlags flags) override;
/**
Increase the given address's access counter
@param address The address to modify
*/
void increaseAccessCounter(uInt16 address, bool isWrite) override;
#endif // DEBUGGER_SUPPORT
private:
// Reference to the console
@ -221,13 +237,18 @@ class M6532 : public Device
RAM_SIZE = 0x80, RAM_MASK = RAM_SIZE - 1,
STACK_SIZE = RAM_SIZE, STACK_MASK = RAM_MASK, STACK_BIT = 0x100,
IO_SIZE = 0x20, IO_MASK = IO_SIZE - 1, IO_BIT = 0x200,
ZP_DELAY = 1;
ZP_DELAY = 1 * 2;
// The arrays containing information about every byte of RIOT
// indicating whether and how (RW) it is used.
std::array<uInt8, RAM_SIZE> myRAMAccessBase;
std::array<uInt8, STACK_SIZE> myStackAccessBase;
std::array<uInt8, IO_SIZE> myIOAccessBase;
std::array<Device::AccessFlags, RAM_SIZE> myRAMAccessBase;
std::array<Device::AccessFlags, STACK_SIZE> myStackAccessBase;
std::array<Device::AccessFlags, IO_SIZE> myIOAccessBase;
// The arrays containing information about every byte of RIOT
// indicating how often it is accessed.
std::array<Device::AccessCounter, RAM_SIZE * 2> myRAMAccessCounter;
std::array<Device::AccessCounter, STACK_SIZE * 2> myStackAccessCounter;
std::array<Device::AccessCounter, IO_SIZE * 2> myIOAccessCounter;
// The array used to skip the first ZP access tracking
std::array<uInt8, RAM_SIZE> myZPAccessDelay;
#endif // DEBUGGER_SUPPORT

View File

@ -268,6 +268,9 @@ void OSystem::setConfigPaths()
buildDirIfRequired(myStateDir, myBaseDir + "state");
buildDirIfRequired(myNVRamDir, myBaseDir + "nvram");
#ifdef DEBUGGER_SUPPORT
buildDirIfRequired(myCfgDir, myBaseDir + "cfg");
#endif
#ifdef PNG_SUPPORT
mySnapshotSaveDir = mySettings->getString("snapsavedir");
@ -292,6 +295,7 @@ void OSystem::setConfigPaths()
dbgPath("base dir ", myBaseDir);
dbgPath("state dir ", myStateDir);
dbgPath("nvram dir ", myNVRamDir);
dbgPath("cfg dir ", myCfgDir);
dbgPath("ssave dir ", mySnapshotSaveDir);
dbgPath("sload dir ", mySnapshotLoadDir);
dbgPath("cheat file", myCheatFile);
@ -600,6 +604,8 @@ unique_ptr<Console> OSystem::openConsole(const FilesystemNode& romfile, string&
CMDLINE_PROPS_UPDATE("vcenter", PropType::Display_VCenter);
CMDLINE_PROPS_UPDATE("pp", PropType::Display_Phosphor);
CMDLINE_PROPS_UPDATE("ppblend", PropType::Display_PPBlend);
CMDLINE_PROPS_UPDATE("pxcenter", PropType::Controller_PaddlesXCenter);
CMDLINE_PROPS_UPDATE("pycenter", PropType::Controller_PaddlesYCenter);
// Finally, create the cart with the correct properties
if(cart)

View File

@ -270,6 +270,13 @@ class OSystem
const string& cheatFile() const { return myCheatFile; }
#endif
#ifdef DEBUGGER_SUPPORT
/**
Return the full/complete directory name for storing Distella cfg files.
*/
const string& cfgDir() const { return myCfgDir; }
#endif
#ifdef PNG_SUPPORT
/**
Return the full/complete directory name for saving and loading
@ -529,6 +536,7 @@ class OSystem
string mySnapshotSaveDir;
string mySnapshotLoadDir;
string myNVRamDir;
string myCfgDir;
string myDefaultSaveDir;
string myDefaultLoadDir;

Some files were not shown because too many files have changed in this diff Show More