mirror of
https://github.com/libretro/stella2023.git
synced 2024-11-27 02:40:37 +00:00
Merge branch 'master' into refactoring/frame_manager
This commit is contained in:
commit
be877f8503
@ -46,6 +46,10 @@
|
||||
sometimes the image was 'double-blended', resulting in a snapshot that
|
||||
was too dark.
|
||||
|
||||
* Fixed crash when selecting 'CompuMate' as a controller type for a non-
|
||||
CompuMate ROM; this controller type can no longer be manually
|
||||
selected, and will be used automatically used for CompuMate ROMs.
|
||||
|
||||
* Added debugger pseudo-register '_fcycles', which gives the number of
|
||||
CPU cycles that have occurred since the frame started.
|
||||
|
||||
@ -2676,7 +2680,7 @@
|
||||
|
||||
* Fixed crash when adding one-shot cheats.
|
||||
|
||||
* Fixed bug in RAM comparitive searches in the debugger.
|
||||
* Fixed bug in RAM comparative searches in the debugger.
|
||||
|
||||
* Fixed bug with setting snapshot naming type from the GUI (it was
|
||||
always being set to 'romname').
|
||||
|
11
Makefile
11
Makefile
@ -53,6 +53,13 @@ CXXFLAGS+= -Wall -Wextra -Wno-unused-parameter -Wno-ignored-qualifiers
|
||||
ifdef HAVE_GCC
|
||||
CXXFLAGS+= -Wno-multichar -Wunused -fno-rtti -Woverloaded-virtual -Wnon-virtual-dtor -std=c++14
|
||||
endif
|
||||
ifdef HAVE_CLANG
|
||||
CXXFLAGS+= -Weverything -Wno-c++17-extensions -Wno-c++98-compat -Wno-c++98-compat-pedantic \
|
||||
-Wno-double-promotion -Wno-switch-enum -Wno-conversion \
|
||||
-Wno-inconsistent-missing-destructor-override \
|
||||
-Wno-exit-time-destructors -Wno-global-constructors -Wno-weak-vtables \
|
||||
-Wno-four-char-constants -Wno-padded
|
||||
endif
|
||||
|
||||
ifdef PROFILE
|
||||
PROF:= -g -pg -fprofile-arcs -ftest-coverage
|
||||
@ -63,10 +70,6 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
# Even more warnings...
|
||||
#CXXFLAGS+= -pedantic -Wpointer-arith -Wcast-qual -Wconversion
|
||||
#CXXFLAGS+= -Wshadow -Wimplicit -Wundef -Wnon-virtual-dtor
|
||||
#CXXFLAGS+= -Wno-reorder -Wwrite-strings -fcheck-new -Wctor-dtor-privacy
|
||||
|
||||
#######################################################################
|
||||
# Misc stuff - you should never have to edit this #
|
||||
|
45
configure
vendored
45
configure
vendored
@ -386,14 +386,16 @@ cc_check_define __GNUC__ && have_gcc=yes
|
||||
|
||||
if test "$have_clang" = yes; then
|
||||
|
||||
clang_minor=$( $CXX -dM -E -x c /dev/null | grep __clang_minor__ | sed 's/.*\([0-9][0-9]*\).*/\1/' )
|
||||
clang_patch=$( $CXX -dM -E -x c /dev/null | grep __clang_patchlevel__ | sed 's/.*\([0-9][0-9]*\).*/\1/' )
|
||||
clang_major=$( $CXX -dM -E -x c /dev/null | grep __clang_major__ | sed 's/.*\([0-9][0-9]*\).*/\1/' )
|
||||
|
||||
cxx_version="$clang_major.$clang_minor.$clang_patch"
|
||||
|
||||
is_xcode=$( $CXX -dM -E -x c /dev/null | grep __apple_build_version__ )
|
||||
|
||||
# Need at least version 8
|
||||
if test -n "$is_xcode"; then
|
||||
clang_minor=$( $CXX -dM -E -x c /dev/null | grep __clang_minor__ | sed 's/.*\([0-9][0-9]*\).*/\1/' )
|
||||
clang_patch=$( $CXX -dM -E -x c /dev/null | grep __clang_patchlevel__ | sed 's/.*\([0-9][0-9]*\).*/\1/' )
|
||||
clang_major=$( $CXX -dM -E -x c /dev/null | grep __clang_major__ | sed 's/.*\([0-9][0-9]*\).*/\1/' )
|
||||
|
||||
cxx_version="$clang_major.$clang_minor.$clang_patch"
|
||||
cxx_name="XCode $cxx_version"
|
||||
|
||||
if test $clang_major -ge 8; then
|
||||
@ -401,35 +403,23 @@ if test "$have_clang" = yes; then
|
||||
cxx_verc_fail=no
|
||||
else
|
||||
cxx_version="$cxx_version, bad"
|
||||
cxx_verc_fail=bad
|
||||
cxx_verc_fail=yes
|
||||
fi
|
||||
else
|
||||
cxx_name=`( $cc -v ) 2>&1 | tail -n 1 | cut -d ' ' -f 1`
|
||||
cxx_version=$( $CXX -dM -E -x c /dev/null | grep __clang_version__ | sed 's/^.*[^0-9]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$/\1/g' 2>&1)
|
||||
if test "$?" -gt 0; then
|
||||
cxx_version="not found"
|
||||
# Need at least version 3.5
|
||||
if [ $clang_major -ge 4 ] || [ $clang_major -eq 3 -a $clang_minor -ge 5 ]; then
|
||||
cxx_version="$cxx_version, ok"
|
||||
cxx_verc_fail=no
|
||||
else
|
||||
cxx_version="$cxx_version, bad"
|
||||
cxx_verc_fail=yes
|
||||
fi
|
||||
|
||||
case $cxx_version in
|
||||
[3].[4-9]|[3].[4-9].[0-9]|[3].[4-9].[0-9][-.]*|[4-9].[0-9].[0-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
|
||||
;;
|
||||
'not found')
|
||||
cxx_verc_fail=yes
|
||||
;;
|
||||
*)
|
||||
cxx_version="$cxx_version, bad"
|
||||
cxx_verc_fail=yes
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
CXXFLAGS="$CXXFLAGS"
|
||||
_make_def_HAVE_GCC3='HAVE_GCC3 = 1'
|
||||
add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP'
|
||||
_make_def_HAVE_GCC='HAVE_GCC = 1'
|
||||
_make_def_HAVE_CLANG='HAVE_CLANG = 1'
|
||||
echo "$cxx_version"
|
||||
|
||||
elif test "$have_gcc" = yes; then
|
||||
@ -505,7 +495,7 @@ fi
|
||||
if test "$cxx_verc_fail" = yes ; then
|
||||
echo
|
||||
echo "The version of your compiler is not supported at this time"
|
||||
echo "Please ensure you are using GCC 4.7 / Clang 3.4 or above"
|
||||
echo "Please ensure you are using GCC 5.0 / Clang 3.8 or above"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@ -827,6 +817,7 @@ PROFILE := $_build_profile
|
||||
|
||||
$_make_def_HAVE_GCC
|
||||
$_make_def_HAVE_GCC3
|
||||
$_make_def_HAVE_CLANG
|
||||
|
||||
INCLUDES += $INCLUDES
|
||||
OBJS += $OBJS
|
||||
|
@ -957,7 +957,7 @@ and the input is empty, all RAM locations are highlighted.</p>
|
||||
|
||||
<p>The 'Compare' button is used to compare the given value using all
|
||||
addresses currently highlighted. This may be an absolute number (such as 2),
|
||||
or a comparitive number (such as -1). Using a '+' or '-' operator
|
||||
or a comparative number (such as -1). Using a '+' or '-' operator
|
||||
means 'search addresses for values that have changed by that amount'.</p>
|
||||
<p>The 'Reset' button resets the entire operation; it clears the highlighted
|
||||
addresses and allows another search.</p>
|
||||
|
@ -57,13 +57,13 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
|
||||
xpos += myCheatList->getWidth() + 5; ypos = 15;
|
||||
|
||||
b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
||||
"Add", kAddCheatCmd);
|
||||
"Add" + ELLIPSIS, kAddCheatCmd);
|
||||
wid.push_back(b);
|
||||
ypos += lineHeight + 10;
|
||||
|
||||
myEditButton =
|
||||
new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
||||
"Edit", kEditCheatCmd);
|
||||
"Edit" + ELLIPSIS, kEditCheatCmd);
|
||||
wid.push_back(myEditButton);
|
||||
ypos += lineHeight + 10;
|
||||
|
||||
@ -74,7 +74,7 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
|
||||
ypos += lineHeight + 10;
|
||||
|
||||
b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
||||
"One shot", kAddOneShotCmd);
|
||||
"One shot" + ELLIPSIS, kAddOneShotCmd);
|
||||
wid.push_back(b);
|
||||
|
||||
// Inputbox which will pop up when adding/editing a cheat
|
||||
@ -196,12 +196,12 @@ void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case kOKCmd:
|
||||
case GuiObject::kOKCmd:
|
||||
saveConfig();
|
||||
close();
|
||||
break;
|
||||
|
||||
case kCloseCmd:
|
||||
case GuiObject::kCloseCmd:
|
||||
close();
|
||||
break;
|
||||
|
||||
|
@ -71,6 +71,11 @@ class Base
|
||||
os.flags(myHexflags);
|
||||
return os << std::setw(2) << std::setfill('0');
|
||||
}
|
||||
static inline std::ostream& HEX3(std::ostream& os)
|
||||
{
|
||||
os.flags(myHexflags);
|
||||
return os << std::setw(3) << std::setfill('0');
|
||||
}
|
||||
static inline std::ostream& HEX4(std::ostream& os) {
|
||||
os.flags(myHexflags);
|
||||
return os << std::setw(4) << std::setfill('0');
|
||||
@ -93,6 +98,7 @@ class Base
|
||||
|
||||
// Format specifiers to use for sprintf (eventually we may convert
|
||||
// to C++ streams
|
||||
static ostringstream buf;
|
||||
static const char* const myLowerFmt[4];
|
||||
static const char* const myUpperFmt[4];
|
||||
static const char* const* myFmt;
|
||||
|
@ -55,7 +55,7 @@ class FilesystemNodeFactory
|
||||
return new FilesystemNodeZIP(path);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -42,7 +42,6 @@ class FilesystemNodeZIP : public AbstractFSNode
|
||||
* Creates a FilesystemNodeZIP for a given path.
|
||||
*
|
||||
* @param path String with the path the new node should point to.
|
||||
* @param node Raw pointer to use for the internal FSNode
|
||||
*/
|
||||
FilesystemNodeZIP(const string& path);
|
||||
|
||||
|
163
src/common/LinkedObjectPool.hxx
Normal file
163
src/common/LinkedObjectPool.hxx
Normal file
@ -0,0 +1,163 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef LINKED_OBJECT_POOL_HXX
|
||||
#define LINKED_OBJECT_POOL_HXX
|
||||
|
||||
#include <list>
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
* A fixed-size object-pool based doubly-linked list that makes use of
|
||||
* multiple STL lists, to reduce frequent (de)allocations.
|
||||
*
|
||||
* This structure can be used as either a stack or queue, but also allows
|
||||
* for removal at any location in the list.
|
||||
*
|
||||
* There are two internal lists; one stores active nodes, and the other
|
||||
* stores pool nodes that have been 'deleted' from the active list (note
|
||||
* that no actual deletion takes place; nodes are simply moved from one list
|
||||
* to another). Similarly, when a new node is added to the active list, it
|
||||
* is simply moved from the pool list to the active list.
|
||||
*
|
||||
* NOTE: For efficiency reasons, none of the methods check for overflow or
|
||||
* underflow; that is the responsibility of the caller.
|
||||
*
|
||||
* In the case of methods which wrap the C++ 'splice()' method, the
|
||||
* semantics of splice are followed wrt invalid/out-of-range/etc
|
||||
* iterators. See the applicable documentation for such behaviour.
|
||||
*
|
||||
* @author Stephen Anthony
|
||||
*/
|
||||
namespace Common {
|
||||
|
||||
template <class T, uInt32 CAPACITY = 100>
|
||||
class LinkedObjectPool
|
||||
{
|
||||
public:
|
||||
using iter = typename std::list<T>::iterator;
|
||||
using const_iter = typename std::list<T>::const_iterator;
|
||||
|
||||
/*
|
||||
* Create a pool of size CAPACITY; the active list starts out empty.
|
||||
*/
|
||||
LinkedObjectPool<T, CAPACITY>() {
|
||||
for(uInt32 i = 0; i < CAPACITY; ++i)
|
||||
myPool.emplace_back(T());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to the element at the first node in the active list.
|
||||
*/
|
||||
T& first() { return myList.front(); }
|
||||
|
||||
/**
|
||||
* Return a reference to the element at the last node in the active list.
|
||||
*/
|
||||
T& last() { return myList.back(); }
|
||||
|
||||
/**
|
||||
* Add a new node at beginning of the active list, and return a reference
|
||||
* to that nodes' data. The reference may then be modified; ie, you're
|
||||
* able to change the data located at that node.
|
||||
*/
|
||||
T& addFirst() {
|
||||
myList.splice(myList.begin(), myPool, myPool.begin());
|
||||
return myList.front();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new node at the end of the active list, and return a reference
|
||||
* to that nodes' data. The reference may then be modified; ie, you're
|
||||
* able to change the data located at that node.
|
||||
*/
|
||||
T& addLast() {
|
||||
myList.splice(myList.end(), myPool, myPool.begin());
|
||||
return myList.back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the first node of the active list.
|
||||
*/
|
||||
void removeFirst() {
|
||||
myPool.splice(myPool.end(), myList, myList.begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the last node of the active list.
|
||||
*/
|
||||
void removeLast() {
|
||||
myPool.splice(myPool.end(), myList, std::prev(myList.end(), 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to remove a single element from the active list at
|
||||
* position of the iterator +- the offset.
|
||||
*/
|
||||
void remove(const_iter i, Int32 offset = 0) {
|
||||
myPool.splice(myPool.end(), myList,
|
||||
offset >= 0 ? std::next(i, offset) : std::prev(i, -offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to remove a single element from the active list by
|
||||
* index, offset from the beginning of the list. (ie, '0' means first
|
||||
* element, '1' is second, and so on).
|
||||
*/
|
||||
void remove(uInt32 index) {
|
||||
myPool.splice(myPool.end(), myList, std::next(myList.begin(), index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to remove a range of elements from 'index' to the
|
||||
* end of the active list.
|
||||
*/
|
||||
void removeLast(uInt32 index) {
|
||||
myPool.splice(myPool.end(), myList, std::next(myList.begin(), index), myList.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase entire contents of active list.
|
||||
*/
|
||||
void clear() {
|
||||
myPool.splice(myPool.end(), myList, myList.begin(), myList.end());
|
||||
}
|
||||
|
||||
/** Access the list with iterators, just as you would a normal C++ STL list */
|
||||
iter begin() { return myList.begin(); }
|
||||
iter end() { return myList.end(); }
|
||||
const_iter begin() const { return myList.cbegin(); }
|
||||
const_iter end() const { return myList.cend(); }
|
||||
|
||||
uInt32 size() const { return myList.size(); }
|
||||
bool empty() const { return myList.size() == 0; }
|
||||
bool full() const { return myList.size() >= CAPACITY; }
|
||||
|
||||
private:
|
||||
std::list<T> myList, myPool;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
LinkedObjectPool(const LinkedObjectPool&) = delete;
|
||||
LinkedObjectPool(LinkedObjectPool&&) = delete;
|
||||
LinkedObjectPool& operator=(const LinkedObjectPool&) = delete;
|
||||
LinkedObjectPool& operator=(LinkedObjectPool&&) = delete;
|
||||
};
|
||||
|
||||
} // Namespace Common
|
||||
|
||||
#endif
|
@ -108,7 +108,7 @@ void PNGLibrary::loadImage(const string& filename, FBSurface& surface)
|
||||
// Cleanup
|
||||
done:
|
||||
if(png_ptr)
|
||||
png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : 0, 0);
|
||||
png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : nullptr, nullptr);
|
||||
|
||||
if(err_message)
|
||||
throw runtime_error(err_message);
|
||||
|
@ -46,9 +46,9 @@ class PNGLibrary
|
||||
@param filename The filename to load the PNG image
|
||||
@param surface The FBSurface into which to place the PNG data
|
||||
|
||||
@return On success, the FBSurface containing image data, otherwise a
|
||||
runtime_error is thrown containing a more detailed
|
||||
error message.
|
||||
@post On success, the FBSurface containing image data, otherwise a
|
||||
runtime_error is thrown containing a more detailed
|
||||
error message.
|
||||
*/
|
||||
void loadImage(const string& filename, FBSurface& surface);
|
||||
|
||||
@ -60,9 +60,9 @@ class PNGLibrary
|
||||
@param filename The filename to save the PNG image
|
||||
@param comments The text comments to add to the PNG image
|
||||
|
||||
@return On success, the PNG file has been saved to 'filename',
|
||||
otherwise a runtime_error is thrown containing a
|
||||
more detailed error message.
|
||||
@post On success, the PNG file has been saved to 'filename',
|
||||
otherwise a runtime_error is thrown containing a
|
||||
more detailed error message.
|
||||
*/
|
||||
void saveImage(const string& filename,
|
||||
const VariantList& comments = EmptyVarList);
|
||||
@ -75,9 +75,9 @@ class PNGLibrary
|
||||
@param rect The area of the surface to use
|
||||
@param comments The text comments to add to the PNG image
|
||||
|
||||
@return On success, the PNG file has been saved to 'filename',
|
||||
otherwise a runtime_error is thrown containing a
|
||||
more detailed error message.
|
||||
@post On success, the PNG file has been saved to 'filename',
|
||||
otherwise a runtime_error is thrown containing a
|
||||
more detailed error message.
|
||||
*/
|
||||
void saveImage(const string& filename, const FBSurface& surface,
|
||||
const GUI::Rect& rect = GUI::EmptyRect,
|
||||
@ -140,8 +140,8 @@ class PNGLibrary
|
||||
static void png_read_data(png_structp ctx, png_bytep area, png_size_t size);
|
||||
static void png_write_data(png_structp ctx, png_bytep area, png_size_t size);
|
||||
static void png_io_flush(png_structp ctx);
|
||||
static void png_user_warn(png_structp ctx, png_const_charp str);
|
||||
static void png_user_error(png_structp ctx, png_const_charp str);
|
||||
[[noreturn]] static void png_user_warn(png_structp ctx, png_const_charp str);
|
||||
[[noreturn]] static void png_user_error(png_structp ctx, png_const_charp str);
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
@ -15,6 +15,8 @@
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "Serializer.hxx"
|
||||
#include "StateManager.hxx"
|
||||
@ -25,23 +27,30 @@
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
|
||||
: myOSystem(system),
|
||||
myStateManager(statemgr)
|
||||
myStateManager(statemgr),
|
||||
myIsNTSC(true) // TODO
|
||||
// TODO: current is not valid
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RewindManager::addState(const string& message)
|
||||
{
|
||||
RewindPtr state = make_unique<RewindState>(); // TODO: get this from object pool
|
||||
Serializer& s = state->data;
|
||||
// TODO: remove following (preceding???) (all invalid) states
|
||||
// myStateList.removeToFront(); from current() + 1 (or - 1???)
|
||||
|
||||
if(myStateList.full())
|
||||
compressStates();
|
||||
|
||||
RewindState& state = myStateList.addFirst();
|
||||
// TODO: addFirst() must set current() to the just added element
|
||||
Serializer& s = state.data;
|
||||
|
||||
s.reset(); // rewind Serializer internal buffers
|
||||
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
|
||||
{
|
||||
state->message = "Rewind " + message;
|
||||
|
||||
// Add to the list TODO: should check against current size
|
||||
myStateList.emplace_front(std::move(state));
|
||||
state.message = message;
|
||||
state.cycle = myOSystem.console().tia().cycles();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -50,21 +59,104 @@ bool RewindManager::addState(const string& message)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RewindManager::rewindState()
|
||||
{
|
||||
if(myStateList.size() > 0)
|
||||
if(!myStateList.empty())
|
||||
{
|
||||
RewindPtr state = std::move(myStateList.front());
|
||||
myStateList.pop_front(); // TODO: add 'state' to object pool
|
||||
Serializer& s = state->data;
|
||||
// TODO: get state previous to the current state instead of first()
|
||||
// RewindState& state = myStateList.current();
|
||||
// myStateList.prev(); // moves current to the previous (older) element
|
||||
RewindState& state = myStateList.first(); // TOOD: remove
|
||||
Serializer& s = state.data;
|
||||
string message = getMessage(state);
|
||||
|
||||
s.reset(); // rewind Serializer internal buffers
|
||||
myStateManager.loadState(s);
|
||||
myOSystem.console().tia().loadDisplay(s);
|
||||
|
||||
// Show message indicating the rewind state
|
||||
myOSystem.frameBuffer().showMessage(state->message);
|
||||
myOSystem.frameBuffer().showMessage(message);
|
||||
|
||||
// TODO: Do NOT remove state (TODO later somewhere else: stop emulation)
|
||||
myStateList.removeFirst(); // TODO: delete this
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RewindManager::unwindState()
|
||||
{
|
||||
if(!atFirst()) // or last???
|
||||
{
|
||||
// TODO: get state next to the current state
|
||||
/*RewindState& state = myStateList.???()
|
||||
Serializer& s = state.data;
|
||||
string message = getMessage(state);
|
||||
|
||||
s.reset(); // rewind Serializer internal buffers
|
||||
myStateManager.loadState(s);
|
||||
myOSystem.console().tia().loadDisplay(s);
|
||||
|
||||
// Show message indicating the rewind state
|
||||
myOSystem.frameBuffer().showMessage(message);*/
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RewindManager::compressStates()
|
||||
{
|
||||
myStateList.removeLast(); // remove the oldest state file
|
||||
// TODO: add smart state removal
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string RewindManager::getMessage(RewindState& state)
|
||||
{
|
||||
const Int64 NTSC_FREQ = 1193182;
|
||||
const Int64 PAL_FREQ = 1182298;
|
||||
Int64 diff = myOSystem.console().tia().cycles() - state.cycle,
|
||||
freq = myIsNTSC ? NTSC_FREQ : PAL_FREQ,
|
||||
diffUnit;
|
||||
stringstream message;
|
||||
string unit;
|
||||
|
||||
message << (diff >= 0 ? "Rewind" : "Unwind");
|
||||
diff = abs(diff);
|
||||
|
||||
if(diff < 76 * 2)
|
||||
{
|
||||
unit = "cycle";
|
||||
diffUnit = diff;
|
||||
}
|
||||
else if(diff < 76 * 262 * 2)
|
||||
{
|
||||
unit = "scanline";
|
||||
diffUnit = diff / 76;
|
||||
}
|
||||
else if(diff < NTSC_FREQ * 2)
|
||||
{
|
||||
unit = "frame";
|
||||
diffUnit = diff / (76 * 262);
|
||||
}
|
||||
else if(diff < NTSC_FREQ * 60 * 2)
|
||||
{
|
||||
unit = "second";
|
||||
diffUnit = diff / NTSC_FREQ;
|
||||
}
|
||||
else
|
||||
{
|
||||
unit = "minute";
|
||||
diffUnit = diff / (NTSC_FREQ * 60);
|
||||
}
|
||||
message << " " << diffUnit << " " << unit;
|
||||
if(diffUnit != 1)
|
||||
message << "s";
|
||||
|
||||
// add optional message (TODO: when smart removal works, we have to do something smart with this part too)
|
||||
if(!state.message.empty())
|
||||
message << " (" << state.message << ")";
|
||||
return message.str();
|
||||
}
|
||||
|
@ -21,17 +21,12 @@
|
||||
class OSystem;
|
||||
class StateManager;
|
||||
|
||||
#include <list>
|
||||
#include "LinkedObjectPool.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
This class is used to save (and later 'rewind') system save states.
|
||||
|
||||
TODO: This will eventually be converted to use object pools
|
||||
Currently, it uses a C++ doubly-linked list as a stack, with
|
||||
add/remove happening at the front of the list
|
||||
Also, the additions are currently unbounded
|
||||
|
||||
@author Stephen Anthony
|
||||
*/
|
||||
class RewindManager
|
||||
@ -54,12 +49,19 @@ class RewindManager
|
||||
*/
|
||||
bool rewindState();
|
||||
|
||||
bool empty() const { return myStateList.size() == 0; }
|
||||
/**
|
||||
Unwind one level of the state list, and display the message associated
|
||||
with that state.
|
||||
*/
|
||||
bool unwindState();
|
||||
|
||||
bool atLast() const { return myStateList.empty(); }
|
||||
bool atFirst() const { return false; } // TODO
|
||||
void clear() { myStateList.clear(); }
|
||||
|
||||
private:
|
||||
// Maximum number of states to save
|
||||
static constexpr uInt32 MAX_SIZE = 100; // FIXME: use this
|
||||
static constexpr uInt32 MAX_SIZE = 100;
|
||||
|
||||
OSystem& myOSystem;
|
||||
StateManager& myStateManager;
|
||||
@ -67,10 +69,21 @@ class RewindManager
|
||||
struct RewindState {
|
||||
Serializer data;
|
||||
string message;
|
||||
uInt64 cycle;
|
||||
|
||||
// We do nothing on object instantiation or copy
|
||||
RewindState() { }
|
||||
RewindState(const RewindState&) { }
|
||||
};
|
||||
|
||||
using RewindPtr = unique_ptr<RewindState>;
|
||||
std::list<RewindPtr> myStateList;
|
||||
Common::LinkedObjectPool<RewindState, MAX_SIZE> myStateList;
|
||||
|
||||
bool myIsNTSC;
|
||||
|
||||
void compressStates();
|
||||
|
||||
string getMessage(RewindState& state);
|
||||
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
@ -18,13 +18,27 @@
|
||||
#ifndef SDL_LIB_HXX
|
||||
#define SDL_LIB_HXX
|
||||
|
||||
#include <SDL.h>
|
||||
/*
|
||||
* We can't control the quality of code from outside projects, so for now
|
||||
* just disable warnings for it.
|
||||
*/
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdocumentation"
|
||||
#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
|
||||
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro"
|
||||
#include <SDL.h>
|
||||
#pragma clang diagnostic pop
|
||||
#else
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Seems to be needed for ppc64le, doesn't hurt other archs
|
||||
Note that this is a problem in SDL2, which includes <altivec.h>
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=1419452
|
||||
*/
|
||||
* Seems to be needed for ppc64le, doesn't hurt other archs
|
||||
* Note that this is a problem in SDL2, which includes <altivec.h>
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=1419452
|
||||
*/
|
||||
#undef vector
|
||||
#undef pixel
|
||||
#undef bool
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "StateManager.hxx"
|
||||
|
||||
#define STATE_HEADER "05000302state"
|
||||
#define MOVIE_HEADER "03030000movie"
|
||||
// #define MOVIE_HEADER "03030000movie"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
StateManager::StateManager(OSystem& osystem)
|
||||
@ -134,6 +134,22 @@ void StateManager::toggleRewindMode()
|
||||
myOSystem.frameBuffer().showMessage("Continuous rewind disabled");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool StateManager::rewindState()
|
||||
{
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
// TODO: add parameter to indicate rewinding from within emulation
|
||||
return r.rewindState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool StateManager::unwindState()
|
||||
{
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
// TODO: add parameter to indicate unwinding from within emulation
|
||||
return r.unwindState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void StateManager::update()
|
||||
{
|
||||
|
@ -64,6 +64,16 @@ class StateManager
|
||||
*/
|
||||
void toggleRewindMode();
|
||||
|
||||
/**
|
||||
Rewinds one state; this uses the RewindManager for its functionality.
|
||||
*/
|
||||
bool rewindState();
|
||||
|
||||
/**
|
||||
Unwinds one state; this uses the RewindManager for its functionality.
|
||||
*/
|
||||
bool unwindState();
|
||||
|
||||
/**
|
||||
Updates the state of the system based on the currently active mode.
|
||||
*/
|
||||
|
@ -50,7 +50,7 @@ class StringParser
|
||||
@param str The string to split
|
||||
@param maxlen The maximum length of string to generate
|
||||
*/
|
||||
StringParser(const string& str, uInt16 maxlen)
|
||||
StringParser(const string& str, uInt32 maxlen)
|
||||
{
|
||||
istringstream buf(str);
|
||||
string line;
|
||||
|
@ -168,7 +168,6 @@ bool ZipHandler::stream_read(fstream* stream, void* buffer, uInt64 offset,
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
This file defines various basic data types and preprocessor variables
|
||||
that need to be defined for different operating systems.
|
||||
|
||||
@author Bradford W. Mott
|
||||
@author Bradford W. Mott and Stephen Anthony
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
@ -77,6 +77,7 @@ using std::memcpy;
|
||||
using IntArray = std::vector<Int32>;
|
||||
using BoolArray = std::vector<bool>;
|
||||
using ByteArray = std::vector<uInt8>;
|
||||
using ShortArray = std::vector<uInt16>;
|
||||
using StringList = std::vector<std::string>;
|
||||
using BytePtr = std::unique_ptr<uInt8[]>;
|
||||
|
||||
@ -87,12 +88,14 @@ namespace BSPF
|
||||
// Defines to help with path handling
|
||||
#if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)
|
||||
static const string PATH_SEPARATOR = "/";
|
||||
#define ATTRIBUTE_FMT_PRINTF __attribute__((__format__ (__printf__, 2, 0)))
|
||||
#elif defined(BSPF_WINDOWS)
|
||||
static const string PATH_SEPARATOR = "\\";
|
||||
#pragma warning (disable : 4146) // unary minus operator applied to unsigned type
|
||||
#pragma warning(2:4264) // no override available for virtual member function from base 'class'; function is hidden
|
||||
#pragma warning(2:4265) // class has virtual functions, but destructor is not virtual
|
||||
#pragma warning(2:4266) // no override available for virtual member function from base 'type'; function is hidden
|
||||
#define ATTRIBUTE_FMT_PRINTF
|
||||
#else
|
||||
#error Update src/common/bspf.hxx for path separator
|
||||
#endif
|
||||
@ -164,13 +167,13 @@ namespace BSPF
|
||||
|
||||
// Find location (if any) of the second string within the first,
|
||||
// starting from 'startpos' in the first string
|
||||
inline size_t findIgnoreCase(const string& s1, const string& s2, int startpos = 0)
|
||||
inline size_t findIgnoreCase(const string& s1, const string& s2, size_t startpos = 0)
|
||||
{
|
||||
auto pos = std::search(s1.cbegin()+startpos, s1.cend(),
|
||||
s2.cbegin(), s2.cend(), [](char ch1, char ch2) {
|
||||
return toupper(uInt8(ch1)) == toupper(uInt8(ch2));
|
||||
});
|
||||
return pos == s1.cend() ? string::npos : size_t(pos - (s1.cbegin()+startpos));
|
||||
return pos == s1.cend() ? string::npos : pos - (s1.cbegin()+startpos);
|
||||
}
|
||||
|
||||
// Test whether the first string ends with the second one (case insensitive)
|
||||
@ -189,6 +192,26 @@ namespace BSPF
|
||||
{
|
||||
return findIgnoreCase(s1, s2) != string::npos;
|
||||
}
|
||||
|
||||
// Test whether the first string matches the second one (case insensitive)
|
||||
// - the first character must match
|
||||
// - the following characters must appear in the order of the first string
|
||||
inline bool matches(const string& s1, const string& s2)
|
||||
{
|
||||
if(BSPF::startsWithIgnoreCase(s1, s2.substr(0, 1)))
|
||||
{
|
||||
size_t pos = 1;
|
||||
for(uInt32 j = 1; j < s2.size(); j++)
|
||||
{
|
||||
size_t found = BSPF::findIgnoreCase(s1, s2.substr(j, 1), pos);
|
||||
if(found == string::npos)
|
||||
return false;
|
||||
pos += found + 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace BSPF
|
||||
|
||||
#endif
|
||||
|
@ -38,18 +38,6 @@
|
||||
#include "CheatManager.hxx"
|
||||
#endif
|
||||
|
||||
// Pointer to the main parent osystem object or the null pointer
|
||||
unique_ptr<OSystem> theOSystem;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Does general Cleanup in case any operation failed (or at end of program)
|
||||
int Cleanup()
|
||||
{
|
||||
theOSystem->logMessage("Cleanup from main", 2);
|
||||
theOSystem->saveConfig();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
#if defined(BSPF_MAC_OSX)
|
||||
@ -61,10 +49,17 @@ int main(int argc, char* argv[])
|
||||
std::ios_base::sync_with_stdio(false);
|
||||
|
||||
// Create the parent OSystem object
|
||||
theOSystem = MediaFactory::createOSystem();
|
||||
unique_ptr<OSystem> theOSystem = MediaFactory::createOSystem();
|
||||
theOSystem->loadConfig();
|
||||
theOSystem->logMessage("Loading config options ...", 2);
|
||||
|
||||
auto Cleanup = [&theOSystem]() {
|
||||
theOSystem->logMessage("Cleanup from main", 2);
|
||||
theOSystem->saveConfig();
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Take care of commandline arguments
|
||||
theOSystem->logMessage("Loading commandline arguments ...", 2);
|
||||
string romfile = theOSystem->settings().loadCommandLine(argc, argv);
|
||||
|
@ -83,4 +83,4 @@ inline uInt8 smartmod<256>(uInt8 x)
|
||||
return x & 0xFF;
|
||||
}
|
||||
|
||||
#endif // SMARTMOD_HXX
|
||||
#endif // SMARTMOD_HXX
|
||||
|
@ -56,12 +56,12 @@ void AtariNTSC::initializePalette(const uInt8* palette)
|
||||
uInt32* kernel = myColorTable[entry];
|
||||
genKernel(myImpl, y, i, q, kernel);
|
||||
|
||||
for ( uInt32 i = 0; i < rgb_kernel_size / 2; i++ )
|
||||
for ( uInt32 c = 0; c < rgb_kernel_size / 2; ++c )
|
||||
{
|
||||
uInt32 error = rgb -
|
||||
kernel [i ] - kernel [(i+10)%14+14] -
|
||||
kernel [i + 7] - kernel [i + 3 +14];
|
||||
kernel [i + 3 + 14] += error;
|
||||
kernel [c ] - kernel [(c+10)%14+14] -
|
||||
kernel [c + 7] - kernel [c + 3 +14];
|
||||
kernel [c + 3 + 14] += error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ class AtariNTSC
|
||||
Used to calculate an averaged color for the 'phosphor' effect.
|
||||
|
||||
@param c RGB Color 1 (current frame)
|
||||
@param p RGB Color 2 (previous frame)
|
||||
@param cp RGB Color 2 (previous frame)
|
||||
|
||||
@return Averaged value of the two RGB colors
|
||||
*/
|
||||
|
@ -58,7 +58,7 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||
mySystemAddresses = LabelToAddr(sysCmp);
|
||||
|
||||
// Add Zero-page RAM addresses
|
||||
for(uInt32 i = 0x80; i <= 0xFF; ++i)
|
||||
for(uInt16 i = 0x80; i <= 0xFF; ++i)
|
||||
{
|
||||
myState.rport.push_back(i);
|
||||
myState.wport.push_back(i);
|
||||
@ -75,16 +75,17 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||
|
||||
BankInfo info;
|
||||
info.size = std::min(banksize, 4096u);
|
||||
for(int i = 0; i < myConsole.cartridge().bankCount(); ++i)
|
||||
for(uInt32 i = 0; i < myConsole.cartridge().bankCount(); ++i)
|
||||
myBankInfo.push_back(info);
|
||||
|
||||
info.size = 128; // ZP RAM
|
||||
myBankInfo.push_back(info);
|
||||
|
||||
// We know the address for the startup bank right now
|
||||
myBankInfo[myConsole.cartridge().startBank()].addressList.push_front(myDebugger.dpeek(0xfffc));
|
||||
myBankInfo[myConsole.cartridge().startBank()].addressList.push_front(
|
||||
myDebugger.dpeek(0xfffc));
|
||||
addLabel("Start", myDebugger.dpeek(0xfffc, DATA));
|
||||
|
||||
|
||||
// Add system equates
|
||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||
{
|
||||
@ -132,7 +133,7 @@ const DebuggerState& CartDebug::getState()
|
||||
{
|
||||
myState.ram.clear();
|
||||
for(uInt32 i = 0; i < myState.rport.size(); ++i)
|
||||
myState.ram.push_back(peek(myState.rport[i]));
|
||||
myState.ram.push_back(myDebugger.peek(myState.rport[i]));
|
||||
|
||||
if(myDebugWidget)
|
||||
myState.bank = myDebugWidget->bankState();
|
||||
@ -145,7 +146,7 @@ void CartDebug::saveOldState()
|
||||
{
|
||||
myOldState.ram.clear();
|
||||
for(uInt32 i = 0; i < myOldState.rport.size(); ++i)
|
||||
myOldState.ram.push_back(peek(myOldState.rport[i]));
|
||||
myOldState.ram.push_back(myDebugger.peek(myOldState.rport[i]));
|
||||
|
||||
if(myDebugWidget)
|
||||
{
|
||||
@ -274,7 +275,7 @@ bool CartDebug::disassemble(bool force)
|
||||
}
|
||||
// Otherwise, add the item at the end
|
||||
if (i == addresses.end())
|
||||
addresses.push_back(PC);
|
||||
addresses.push_back(PC);
|
||||
}
|
||||
|
||||
// Always attempt to resolve code sections unless it's been
|
||||
@ -723,7 +724,7 @@ string CartDebug::loadListFile()
|
||||
if(addr_s.length() == 0)
|
||||
continue;
|
||||
const char* p = addr_s[0] == 'U' ? addr_s.c_str() + 1 : addr_s.c_str();
|
||||
addr = int(strtoul(p, NULL, 16));
|
||||
addr = int(strtoul(p, nullptr, 16));
|
||||
|
||||
// For now, completely ignore ROM addresses
|
||||
if(!(addr & 0x1000))
|
||||
@ -786,7 +787,8 @@ string CartDebug::loadSymbolFile()
|
||||
if (iter == myUserLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
|
||||
{
|
||||
// Check for period, and strip leading number
|
||||
if(string::size_type pos = label.find_first_of(".", 0) != string::npos)
|
||||
string::size_type pos = label.find_first_of(".", 0);
|
||||
if(pos != string::npos)
|
||||
addLabel(label.substr(pos), value);
|
||||
else
|
||||
addLabel(label, value);
|
||||
@ -1005,7 +1007,7 @@ string CartDebug::saveDisassembly()
|
||||
disasm.list.clear();
|
||||
DiStella distella(*this, disasm.list, info, settings,
|
||||
myDisLabels, myDisDirectives, myReserved);
|
||||
|
||||
|
||||
if (myReserved.breakFound)
|
||||
addLabel("Break", myDebugger.dpeek(0xfffe));
|
||||
|
||||
@ -1055,7 +1057,7 @@ string CartDebug::saveDisassembly()
|
||||
break;
|
||||
}
|
||||
case CartDebug::DATA:
|
||||
{
|
||||
{
|
||||
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)";
|
||||
break;
|
||||
}
|
||||
@ -1063,7 +1065,7 @@ string CartDebug::saveDisassembly()
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // switch
|
||||
buf << "\n";
|
||||
}
|
||||
@ -1100,7 +1102,7 @@ string CartDebug::saveDisassembly()
|
||||
out << "\n;-----------------------------------------------------------\n"
|
||||
<< "; TIA and IO constants accessed\n"
|
||||
<< ";-----------------------------------------------------------\n\n";
|
||||
|
||||
|
||||
// TIA read access
|
||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr])
|
||||
@ -1129,9 +1131,9 @@ string CartDebug::saveDisassembly()
|
||||
}
|
||||
|
||||
addrUsed = false;
|
||||
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
||||
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80]
|
||||
|| (mySystem.getAccessFlags(addr) & (DATA | WRITE))
|
||||
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
||||
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80]
|
||||
|| (mySystem.getAccessFlags(addr) & (DATA | WRITE))
|
||||
|| (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
|
||||
if(addrUsed)
|
||||
{
|
||||
@ -1139,13 +1141,13 @@ string CartDebug::saveDisassembly()
|
||||
out << "\n\n;-----------------------------------------------------------\n"
|
||||
<< "; RIOT RAM (zero-page) labels\n"
|
||||
<< ";-----------------------------------------------------------\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));
|
||||
|
||||
if (myReserved.ZPRAM[addr - 0x80] &&
|
||||
|
||||
if (myReserved.ZPRAM[addr - 0x80] &&
|
||||
myUserLabels.find(addr) == myUserLabels.end()) {
|
||||
if (addLine)
|
||||
out << "\n";
|
||||
@ -1153,7 +1155,7 @@ string CartDebug::saveDisassembly()
|
||||
<< Base::HEX2 << right << (addr)
|
||||
<< (stackUsed|codeUsed ? "; (" : "")
|
||||
<< (codeUsed ? "c" : "")
|
||||
<< (stackUsed ? "s" : "")
|
||||
<< (stackUsed ? "s" : "")
|
||||
<< (stackUsed | codeUsed ? ")" : "")
|
||||
<< "\n";
|
||||
addLine = false;
|
||||
@ -1161,11 +1163,11 @@ string CartDebug::saveDisassembly()
|
||||
if (addLine)
|
||||
out << "\n";
|
||||
out << ALIGN(18) << ";" << "$"
|
||||
<< Base::HEX2 << right << (addr)
|
||||
<< " ("
|
||||
<< (ramUsed ? "i" : "")
|
||||
<< (codeUsed ? "c" : "")
|
||||
<< (stackUsed ? "s" : "")
|
||||
<< Base::HEX2 << right << (addr)
|
||||
<< " ("
|
||||
<< (ramUsed ? "i" : "")
|
||||
<< (codeUsed ? "c" : "")
|
||||
<< (stackUsed ? "s" : "")
|
||||
<< ")\n";
|
||||
addLine = false;
|
||||
} else
|
||||
@ -1278,23 +1280,23 @@ void CartDebug::getCompletions(const char* in, StringList& completions) const
|
||||
{
|
||||
// First scan system equates
|
||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||
if(ourTIAMnemonicR[addr] && BSPF::startsWithIgnoreCase(ourTIAMnemonicR[addr], in))
|
||||
if(ourTIAMnemonicR[addr] && BSPF::matches(ourTIAMnemonicR[addr], in))
|
||||
completions.push_back(ourTIAMnemonicR[addr]);
|
||||
for(uInt16 addr = 0x00; addr <= 0x3F; ++addr)
|
||||
if(ourTIAMnemonicW[addr] && BSPF::startsWithIgnoreCase(ourTIAMnemonicW[addr], in))
|
||||
if(ourTIAMnemonicW[addr] && BSPF::matches(ourTIAMnemonicW[addr], in))
|
||||
completions.push_back(ourTIAMnemonicW[addr]);
|
||||
for(uInt16 addr = 0; addr <= 0x297-0x280; ++addr)
|
||||
if(ourIOMnemonic[addr] && BSPF::startsWithIgnoreCase(ourIOMnemonic[addr], in))
|
||||
if(ourIOMnemonic[addr] && BSPF::matches(ourIOMnemonic[addr], in))
|
||||
completions.push_back(ourIOMnemonic[addr]);
|
||||
for(uInt16 addr = 0; addr <= 0x7F; ++addr)
|
||||
if(ourZPMnemonic[addr] && BSPF::startsWithIgnoreCase(ourZPMnemonic[addr], in))
|
||||
if(ourZPMnemonic[addr] && BSPF::matches(ourZPMnemonic[addr], in))
|
||||
completions.push_back(ourZPMnemonic[addr]);
|
||||
|
||||
// Now scan user-defined labels
|
||||
for(const auto& iter: myUserAddresses)
|
||||
{
|
||||
const char* l = iter.first.c_str();
|
||||
if(BSPF::startsWithIgnoreCase(l, in))
|
||||
if(BSPF::matches(l, in))
|
||||
completions.push_back(l);
|
||||
}
|
||||
}
|
||||
@ -1332,7 +1334,7 @@ void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const
|
||||
buf << "ORG " << Base::HEX4 << info.offset << endl;
|
||||
|
||||
// Now consider each byte
|
||||
uInt32 prev = info.offset, addr = prev + 1;
|
||||
uInt16 prev = info.offset, addr = prev + 1;
|
||||
DisasmType prevType = disasmTypeAbsolute(mySystem.getAccessFlags(prev));
|
||||
for( ; addr < info.offset + info.size; ++addr)
|
||||
{
|
||||
@ -1455,14 +1457,16 @@ const char* const CartDebug::ourTIAMnemonicW[64] = {
|
||||
"AUDF1", "AUDV0", "AUDV1", "GRP0", "GRP1", "ENAM0", "ENAM1", "ENABL",
|
||||
"HMP0", "HMP1", "HMM0", "HMM1", "HMBL", "VDELP0", "VDELP1", "VDELBL",
|
||||
"RESMP0", "RESMP1", "HMOVE", "HMCLR", "CXCLR", "$2d", "$2e", "$2f",
|
||||
"$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37",
|
||||
"$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37",
|
||||
"$38", "$39", "$3a", "$3b", "$3c", "$3d", "$3e", "$3f"
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const char* const CartDebug::ourIOMnemonic[24] = {
|
||||
"SWCHA", "SWACNT", "SWCHB", "SWBCNT", "INTIM", "TIMINT", 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, "TIM1T", "TIM8T", "TIM64T", "T1024T"
|
||||
"SWCHA", "SWACNT", "SWCHB", "SWBCNT", "INTIM", "TIMINT",
|
||||
"$286", "$287", "$288", "$289", "$28a", "$28b", "$28c",
|
||||
"$28d", "$28e", "$28f", "$290", "$291", "$292", "$293",
|
||||
"TIM1T", "TIM8T", "TIM64T", "T1024T"
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -30,6 +30,7 @@ class CartDebugWidget;
|
||||
#include "Cart.hxx"
|
||||
#include "DebuggerSystem.hxx"
|
||||
#include "System.hxx"
|
||||
#include "M6502.hxx"
|
||||
|
||||
// Function type for CartDebug instance methods
|
||||
class CartDebug;
|
||||
@ -38,10 +39,10 @@ using CartMethod = int (CartDebug::*)();
|
||||
class CartState : public DebuggerState
|
||||
{
|
||||
public:
|
||||
ByteArray ram; // The actual data values
|
||||
IntArray rport; // Address for reading from RAM
|
||||
IntArray wport; // Address for writing to RAM
|
||||
string bank; // Current banking layout
|
||||
ByteArray ram; // The actual data values
|
||||
ShortArray rport; // Address for reading from RAM
|
||||
ShortArray wport; // Address for writing to RAM
|
||||
string bank; // Current banking layout
|
||||
};
|
||||
|
||||
class CartDebug : public DebuggerSystem
|
||||
@ -112,13 +113,6 @@ class CartDebug : public DebuggerSystem
|
||||
CartDebugWidget* getDebugWidget() const { return myDebugWidget; }
|
||||
void setDebugWidget(CartDebugWidget* w) { myDebugWidget = w; }
|
||||
|
||||
// The following assume that the given addresses are using the
|
||||
// correct read/write port ranges; no checking will be done to
|
||||
// confirm this.
|
||||
uInt8 peek(uInt16 addr) { return mySystem.peek(addr); }
|
||||
uInt16 dpeek(uInt16 addr) { return mySystem.peek(addr) | (mySystem.peek(addr+1) << 8); }
|
||||
void poke(uInt16 addr, uInt8 value) { mySystem.poke(addr, value); }
|
||||
|
||||
// Indicate that a read from write port has occurred at the specified
|
||||
// address.
|
||||
void triggerReadFromWritePort(uInt16 address);
|
||||
@ -127,6 +121,11 @@ class CartDebug : public DebuggerSystem
|
||||
// write port area.
|
||||
int readFromWritePort();
|
||||
|
||||
// Return the base (= non-mirrored) address of the last CPU read
|
||||
int lastReadBaseAddress() { return mySystem.m6502().lastReadBaseAddress(); }
|
||||
// Return the base (= non-mirrored) address of the last CPU write
|
||||
int lastWriteBaseAddress() { return mySystem.m6502().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
|
||||
@ -289,7 +288,7 @@ class CartDebug : public DebuggerSystem
|
||||
uInt16 start; // start of address space
|
||||
uInt16 end; // end of address space
|
||||
uInt16 offset; // ORG value
|
||||
uInt16 size; // size of a bank (in bytes)
|
||||
uInt32 size; // size of a bank (in bytes)
|
||||
AddressList addressList; // addresses which PC has hit
|
||||
DirectiveList directiveList; // overrides for automatic code determination
|
||||
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "Settings.hxx"
|
||||
#include "DebuggerDialog.hxx"
|
||||
#include "DebuggerParser.hxx"
|
||||
#include "StateManager.hxx"
|
||||
|
||||
#include "Console.hxx"
|
||||
#include "System.hxx"
|
||||
@ -58,58 +57,6 @@
|
||||
|
||||
Debugger* Debugger::myStaticDebugger = nullptr;
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
static const char* const builtin_functions[][3] = {
|
||||
// { "name", "definition", "help text" }
|
||||
|
||||
// left joystick:
|
||||
{ "_joy0left", "!(*SWCHA & $40)", "Left joystick moved left" },
|
||||
{ "_joy0right", "!(*SWCHA & $80)", "Left joystick moved right" },
|
||||
{ "_joy0up", "!(*SWCHA & $10)", "Left joystick moved up" },
|
||||
{ "_joy0down", "!(*SWCHA & $20)", "Left joystick moved down" },
|
||||
{ "_joy0button", "!(*INPT4 & $80)", "Left joystick button pressed" },
|
||||
|
||||
// right joystick:
|
||||
{ "_joy1left", "!(*SWCHA & $04)", "Right joystick moved left" },
|
||||
{ "_joy1right", "!(*SWCHA & $08)", "Right joystick moved right" },
|
||||
{ "_joy1up", "!(*SWCHA & $01)", "Right joystick moved up" },
|
||||
{ "_joy1down", "!(*SWCHA & $02)", "Right joystick moved down" },
|
||||
{ "_joy1button", "!(*INPT5 & $80)", "Right joystick button pressed" },
|
||||
|
||||
// console switches:
|
||||
{ "_select", "!(*SWCHB & $02)", "Game Select pressed" },
|
||||
{ "_reset", "!(*SWCHB & $01)", "Game Reset pressed" },
|
||||
{ "_color", "*SWCHB & $08", "Color/BW set to Color" },
|
||||
{ "_bw", "!(*SWCHB & $08)", "Color/BW set to BW" },
|
||||
{ "_diff0b", "!(*SWCHB & $40)", "Left diff. set to B (easy)" },
|
||||
{ "_diff0a", "*SWCHB & $40", "Left diff. set to A (hard)" },
|
||||
{ "_diff1b", "!(*SWCHB & $80)", "Right diff. set to B (easy)" },
|
||||
{ "_diff1a", "*SWCHB & $80", "Right diff. set to A (hard)" },
|
||||
|
||||
// empty string marks end of list, do not remove
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Names are defined here, but processed in YaccParser
|
||||
static const char* const pseudo_registers[][2] = {
|
||||
// { "name", "help text" }
|
||||
|
||||
{ "_bank", "Currently selected bank" },
|
||||
{ "_cclocks", "Color clocks on current scanline" },
|
||||
{ "_fcount", "Number of frames since emulation started" },
|
||||
{ "_fcycles", "Number of cycles since frame started" },
|
||||
{ "_cyclesLo", "Lower 32 bits of number of cycles since emulation started"},
|
||||
{ "_cyclesHi", "Higher 32 bits of number of cycles since emulation started"},
|
||||
{ "_rwport", "Address at which a read from a write port occurred" },
|
||||
{ "_scan", "Current scanline count" },
|
||||
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
|
||||
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" },
|
||||
|
||||
// empty string marks end of list, do not remove
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Debugger::Debugger(OSystem& osystem, Console& console)
|
||||
: DialogContainer(osystem),
|
||||
@ -166,7 +113,7 @@ FBInitStatus Debugger::initializeVideo()
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::start(const string& message, int address)
|
||||
bool Debugger::start(const string& message, int address, bool read)
|
||||
{
|
||||
if(myOSystem.eventHandler().enterDebugMode())
|
||||
{
|
||||
@ -175,8 +122,7 @@ bool Debugger::start(const string& message, int address)
|
||||
ostringstream buf;
|
||||
buf << message;
|
||||
if(address > -1)
|
||||
buf << Common::Base::HEX4 << address;
|
||||
|
||||
buf << cartDebug().getLabel(address, read, 4);
|
||||
myDialog->message().setText(buf.str());
|
||||
return true;
|
||||
}
|
||||
@ -206,26 +152,26 @@ void Debugger::quit(bool exitrom)
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string Debugger::autoExec()
|
||||
string Debugger::autoExec(StringList* history)
|
||||
{
|
||||
ostringstream buf;
|
||||
|
||||
// autoexec.stella is always run
|
||||
FilesystemNode autoexec(myOSystem.baseDir() + "autoexec.stella");
|
||||
// autoexec.script is always run
|
||||
FilesystemNode autoexec(myOSystem.baseDir() + "autoexec.script");
|
||||
buf << "autoExec():" << endl
|
||||
<< myParser->exec(autoexec) << endl;
|
||||
<< myParser->exec(autoexec, history) << endl;
|
||||
|
||||
// Also, "romname.stella" if present
|
||||
FilesystemNode romname(myOSystem.romFile().getPathWithExt(".stella"));
|
||||
buf << myParser->exec(romname) << endl;
|
||||
// Also, "romname.script" if present
|
||||
FilesystemNode romname(myOSystem.romFile().getPathWithExt(".script"));
|
||||
buf << myParser->exec(romname, history) << endl;
|
||||
|
||||
// Init builtins
|
||||
for(int i = 0; builtin_functions[i][0] != 0; i++)
|
||||
for(uInt32 i = 0; i < NUM_BUILTIN_FUNCS; ++i)
|
||||
{
|
||||
// TODO - check this for memory leaks
|
||||
int res = YaccParser::parse(builtin_functions[i][1]);
|
||||
int res = YaccParser::parse(ourBuiltinFunctions[i].defn);
|
||||
if(res == 0)
|
||||
addFunction(builtin_functions[i][0], builtin_functions[i][1],
|
||||
addFunction(ourBuiltinFunctions[i].name, ourBuiltinFunctions[i].defn,
|
||||
YaccParser::getResult(), true);
|
||||
else
|
||||
cerr << "ERROR in builtin function!" << endl;
|
||||
@ -367,24 +313,43 @@ bool Debugger::breakPoint(uInt16 bp)
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::toggleReadTrap(uInt16 t)
|
||||
void Debugger::addReadTrap(uInt16 t)
|
||||
{
|
||||
readTraps().initialize();
|
||||
readTraps().toggle(t);
|
||||
readTraps().add(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::toggleWriteTrap(uInt16 t)
|
||||
void Debugger::addWriteTrap(uInt16 t)
|
||||
{
|
||||
writeTraps().initialize();
|
||||
writeTraps().toggle(t);
|
||||
writeTraps().add(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::toggleTrap(uInt16 t)
|
||||
void Debugger::addTrap(uInt16 t)
|
||||
{
|
||||
toggleReadTrap(t);
|
||||
toggleWriteTrap(t);
|
||||
addReadTrap(t);
|
||||
addWriteTrap(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::removeReadTrap(uInt16 t)
|
||||
{
|
||||
readTraps().initialize();
|
||||
readTraps().remove(t);
|
||||
}
|
||||
|
||||
void Debugger::removeWriteTrap(uInt16 t)
|
||||
{
|
||||
writeTraps().initialize();
|
||||
writeTraps().remove(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::removeTrap(uInt16 t)
|
||||
{
|
||||
removeReadTrap(t);
|
||||
removeWriteTrap(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -399,6 +364,50 @@ bool Debugger::writeTrap(uInt16 t)
|
||||
return writeTraps().isInitialized() && writeTraps().isSet(t);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 Debugger::getBaseAddress(uInt32 addr, bool read)
|
||||
{
|
||||
if((addr & 0x1080) == 0x0000) // (addr & 0b 0001 0000 1000 0000) == 0b 0000 0000 0000 0000
|
||||
{
|
||||
if(read)
|
||||
// ADDR_TIA read (%xxx0 xxxx 0xxx ????)
|
||||
return addr & 0x000f; // 0b 0000 0000 0000 1111
|
||||
else
|
||||
// ADDR_TIA write (%xxx0 xxxx 0x?? ????)
|
||||
return addr & 0x003f; // 0b 0000 0000 0011 1111
|
||||
}
|
||||
|
||||
// ADDR_ZPRAM (%xxx0 xx0x 1??? ????)
|
||||
if((addr & 0x1280) == 0x0080) // (addr & 0b 0001 0010 1000 0000) == 0b 0000 0000 1000 0000
|
||||
return addr & 0x00ff; // 0b 0000 0000 1111 1111
|
||||
|
||||
// ADDR_ROM
|
||||
if(addr & 0x1000)
|
||||
return addr & 0x1fff; // 0b 0001 1111 1111 1111
|
||||
|
||||
// ADDR_IO read/write I/O registers (%xxx0 xx1x 1xxx x0??)
|
||||
if((addr & 0x1284) == 0x0280) // (addr & 0b 0001 0010 1000 0100) == 0b 0000 0010 1000 0000
|
||||
return addr & 0x0283; // 0b 0000 0010 1000 0011
|
||||
|
||||
// ADDR_IO write timers (%xxx0 xx1x 1xx1 ?1??)
|
||||
if(!read && (addr & 0x1294) == 0x0294) // (addr & 0b 0001 0010 1001 0100) == 0b 0000 0010 1001 0100
|
||||
return addr & 0x029f; // 0b 0000 0010 1001 1111
|
||||
|
||||
// ADDR_IO read timers (%xxx0 xx1x 1xxx ?1x0)
|
||||
if(read && (addr & 0x1285) == 0x0284) // (addr & 0b 0001 0010 1000 0101) == 0b 0000 0010 1000 0100
|
||||
return addr & 0x028c; // 0b 0000 0010 1000 1100
|
||||
|
||||
// ADDR_IO read timer/PA7 interrupt (%xxx0 xx1x 1xxx x1x1)
|
||||
if(read && (addr & 0x1285) == 0x0285) // (addr & 0b 0001 0010 1000 0101) == 0b 0000 0010 1000 0101
|
||||
return addr & 0x0285; // 0b 0000 0010 1000 0101
|
||||
|
||||
// ADDR_IO write PA7 edge control (%xxx0 xx1x 1xx0 x1??)
|
||||
if(!read && (addr & 0x1294) == 0x0284) // (addr & 0b 0001 0010 1001 0100) == 0b 0000 0010 1000 0100
|
||||
return addr & 0x0287; // 0b 0000 0010 1000 0111
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::nextScanline(int lines)
|
||||
{
|
||||
@ -442,21 +451,39 @@ void Debugger::nextFrame(int frames)
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::rewindState()
|
||||
void Debugger::updateRewindbuttons(const RewindManager& r)
|
||||
{
|
||||
myDialog->rewindButton().setEnabled(!r.atLast());
|
||||
myDialog->unwindButton().setEnabled(!r.atFirst());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::windState(bool unwind)
|
||||
{
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
|
||||
mySystem.clearDirtyPages();
|
||||
|
||||
unlockBankswitchState();
|
||||
bool result = r.rewindState();
|
||||
bool result = unwind ? r.unwindState() : r.rewindState();
|
||||
lockBankswitchState();
|
||||
|
||||
myDialog->rewindButton().setEnabled(!r.empty());
|
||||
|
||||
updateRewindbuttons(r);
|
||||
return result;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::rewindState()
|
||||
{
|
||||
return windState(false);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::unwindState()
|
||||
{
|
||||
return windState(true);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::clearAllBreakPoints()
|
||||
{
|
||||
@ -495,7 +522,7 @@ void Debugger::saveOldState(string rewindMsg)
|
||||
{
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
r.addState(rewindMsg);
|
||||
myDialog->rewindButton().setEnabled(!r.empty());
|
||||
updateRewindbuttons(r);
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,11 +532,8 @@ void Debugger::setStartState()
|
||||
// Lock the bus each time the debugger is entered, so we don't disturb anything
|
||||
lockBankswitchState();
|
||||
|
||||
// If rewinding is not enabled, always start the debugger with a clean list
|
||||
RewindManager& r = myOSystem.state().rewindManager();
|
||||
if(myOSystem.state().mode() == StateManager::Mode::Off)
|
||||
r.clear();
|
||||
myDialog->rewindButton().setEnabled(!r.empty());
|
||||
updateRewindbuttons(r);
|
||||
|
||||
// Save initial state, but don't add it to the rewind list
|
||||
saveOldState();
|
||||
@ -524,6 +548,9 @@ void Debugger::setQuitState()
|
||||
// Bus must be unlocked for normal operation when leaving debugger mode
|
||||
unlockBankswitchState();
|
||||
|
||||
// Save state when leaving the debugger
|
||||
saveOldState("exit debugger");
|
||||
|
||||
// execute one instruction on quit. If we're
|
||||
// sitting at a breakpoint/trap, this will get us past it.
|
||||
// Somehow this feels like a hack to me, but I don't know why
|
||||
@ -541,6 +568,15 @@ bool Debugger::addFunction(const string& name, const string& definition,
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::isBuiltinFunction(const string& name)
|
||||
{
|
||||
for(uInt32 i = 0; i < NUM_BUILTIN_FUNCS; ++i)
|
||||
if(name == ourBuiltinFunctions[i].name)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Debugger::delFunction(const string& name)
|
||||
{
|
||||
@ -549,8 +585,7 @@ bool Debugger::delFunction(const string& name)
|
||||
return false;
|
||||
|
||||
// We never want to delete built-in functions
|
||||
for(int i = 0; builtin_functions[i][0] != 0; ++i)
|
||||
if(name == builtin_functions[i][0])
|
||||
if(isBuiltinFunction(name))
|
||||
return false;
|
||||
|
||||
myFunctions.erase(name);
|
||||
@ -590,39 +625,39 @@ string Debugger::builtinHelp() const
|
||||
uInt16 len, c_maxlen = 0, i_maxlen = 0;
|
||||
|
||||
// Get column widths for aligned output (functions)
|
||||
for(int i = 0; builtin_functions[i][0] != 0; ++i)
|
||||
for(uInt32 i = 0; i < NUM_BUILTIN_FUNCS; ++i)
|
||||
{
|
||||
len = strlen(builtin_functions[i][0]);
|
||||
len = ourBuiltinFunctions[i].name.size();
|
||||
if(len > c_maxlen) c_maxlen = len;
|
||||
len = strlen(builtin_functions[i][1]);
|
||||
len = ourBuiltinFunctions[i].defn.size();
|
||||
if(len > i_maxlen) i_maxlen = len;
|
||||
}
|
||||
|
||||
buf << std::setfill(' ') << endl << "Built-in functions:" << endl;
|
||||
for(int i = 0; builtin_functions[i][0] != 0; ++i)
|
||||
for(uInt32 i = 0; i < NUM_BUILTIN_FUNCS; ++i)
|
||||
{
|
||||
buf << std::setw(c_maxlen) << std::left << builtin_functions[i][0]
|
||||
buf << std::setw(c_maxlen) << std::left << ourBuiltinFunctions[i].name
|
||||
<< std::setw(2) << std::right << "{"
|
||||
<< std::setw(i_maxlen) << std::left << builtin_functions[i][1]
|
||||
<< std::setw(i_maxlen) << std::left << ourBuiltinFunctions[i].defn
|
||||
<< std::setw(4) << "}"
|
||||
<< builtin_functions[i][2]
|
||||
<< ourBuiltinFunctions[i].help
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// Get column widths for aligned output (pseudo-registers)
|
||||
c_maxlen = 0;
|
||||
for(int i = 0; pseudo_registers[i][0] != 0; ++i)
|
||||
for(uInt32 i = 0; i < NUM_PSEUDO_REGS; ++i)
|
||||
{
|
||||
len = strlen(pseudo_registers[i][0]);
|
||||
len = ourPseudoRegisters[i].name.size();
|
||||
if(len > c_maxlen) c_maxlen = len;
|
||||
}
|
||||
|
||||
buf << endl << "Pseudo-registers:" << endl;
|
||||
for(int i = 0; pseudo_registers[i][0] != 0; ++i)
|
||||
for(uInt32 i = 0; i < NUM_PSEUDO_REGS; ++i)
|
||||
{
|
||||
buf << std::setw(c_maxlen) << std::left << pseudo_registers[i][0]
|
||||
buf << std::setw(c_maxlen) << std::left << ourPseudoRegisters[i].name
|
||||
<< std::setw(2) << " "
|
||||
<< std::setw(i_maxlen) << std::left << pseudo_registers[i][1]
|
||||
<< std::setw(i_maxlen) << std::left << ourPseudoRegisters[i].help
|
||||
<< endl;
|
||||
}
|
||||
|
||||
@ -632,16 +667,20 @@ string Debugger::builtinHelp() const
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::getCompletions(const char* in, StringList& list) const
|
||||
{
|
||||
for(const auto& iter: myFunctions)
|
||||
// skip if filter equals "_" only
|
||||
if(!BSPF::equalsIgnoreCase(in, "_"))
|
||||
{
|
||||
const char* l = iter.first.c_str();
|
||||
if(BSPF::startsWithIgnoreCase(l, in))
|
||||
list.push_back(l);
|
||||
}
|
||||
for(const auto& iter : myFunctions)
|
||||
{
|
||||
const char* l = iter.first.c_str();
|
||||
if(BSPF::matches(l, in))
|
||||
list.push_back(l);
|
||||
}
|
||||
|
||||
for(int i = 0; pseudo_registers[i][0] != 0; ++i)
|
||||
if(BSPF::startsWithIgnoreCase(pseudo_registers[i][0], in))
|
||||
list.push_back(pseudo_registers[i][0]);
|
||||
for(uInt32 i = 0; i < NUM_PSEUDO_REGS; ++i)
|
||||
if(BSPF::matches(ourPseudoRegisters[i].name, in))
|
||||
list.push_back(ourPseudoRegisters[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -657,3 +696,49 @@ void Debugger::unlockBankswitchState()
|
||||
mySystem.unlockDataBus();
|
||||
myConsole.cartridge().unlockBank();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Debugger::BuiltinFunction Debugger::ourBuiltinFunctions[NUM_BUILTIN_FUNCS] = {
|
||||
// left joystick:
|
||||
{ "_joy0left", "!(*SWCHA & $40)", "Left joystick moved left" },
|
||||
{ "_joy0right", "!(*SWCHA & $80)", "Left joystick moved right" },
|
||||
{ "_joy0up", "!(*SWCHA & $10)", "Left joystick moved up" },
|
||||
{ "_joy0down", "!(*SWCHA & $20)", "Left joystick moved down" },
|
||||
{ "_joy0button", "!(*INPT4 & $80)", "Left joystick button pressed" },
|
||||
|
||||
// right joystick:
|
||||
{ "_joy1left", "!(*SWCHA & $04)", "Right joystick moved left" },
|
||||
{ "_joy1right", "!(*SWCHA & $08)", "Right joystick moved right" },
|
||||
{ "_joy1up", "!(*SWCHA & $01)", "Right joystick moved up" },
|
||||
{ "_joy1down", "!(*SWCHA & $02)", "Right joystick moved down" },
|
||||
{ "_joy1button", "!(*INPT5 & $80)", "Right joystick button pressed" },
|
||||
|
||||
// console switches:
|
||||
{ "_select", "!(*SWCHB & $02)", "Game Select pressed" },
|
||||
{ "_reset", "!(*SWCHB & $01)", "Game Reset pressed" },
|
||||
{ "_color", "*SWCHB & $08", "Color/BW set to Color" },
|
||||
{ "_bw", "!(*SWCHB & $08)", "Color/BW set to BW" },
|
||||
{ "_diff0b", "!(*SWCHB & $40)", "Left diff. set to B (easy)" },
|
||||
{ "_diff0a", "*SWCHB & $40", "Left diff. set to A (hard)" },
|
||||
{ "_diff1b", "!(*SWCHB & $80)", "Right diff. set to B (easy)" },
|
||||
{ "_diff1a", "*SWCHB & $80", "Right diff. set to A (hard)" }
|
||||
};
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Names are defined here, but processed in YaccParser
|
||||
Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = {
|
||||
{ "_bank", "Currently selected bank" },
|
||||
{ "_cclocks", "Color clocks on current scanline" },
|
||||
{ "_cycleshi", "Higher 32 bits of number of cycles since emulation started" },
|
||||
{ "_cycleslo", "Lower 32 bits of number of cycles since emulation started" },
|
||||
{ "_fcount", "Number of frames since emulation started" },
|
||||
{ "_fcycles", "Number of cycles since frame started" },
|
||||
{ "_rwport", "Address at which a read from a write port occurred" },
|
||||
{ "_scan", "Current scanline count" },
|
||||
{ "_scycles", "Number of cycles in current scanline" },
|
||||
{ "_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" },*/
|
||||
};
|
||||
|
@ -36,6 +36,7 @@ class ButtonWidget;
|
||||
#include "DialogContainer.hxx"
|
||||
#include "DebuggerDialog.hxx"
|
||||
#include "DebuggerParser.hxx"
|
||||
#include "StateManager.hxx"
|
||||
#include "M6502.hxx"
|
||||
#include "System.hxx"
|
||||
#include "Stack.hxx"
|
||||
@ -88,7 +89,7 @@ class Debugger : public DialogContainer
|
||||
@param message Message to display when entering debugger
|
||||
@param address An address associated with the message
|
||||
*/
|
||||
bool start(const string& message = "", int address = -1);
|
||||
bool start(const string& message = "", int address = -1, bool read = true);
|
||||
bool startWithFatalError(const string& message = "");
|
||||
|
||||
/**
|
||||
@ -99,6 +100,7 @@ class Debugger : public DialogContainer
|
||||
|
||||
bool addFunction(const string& name, const string& def,
|
||||
Expression* exp, bool builtin = false);
|
||||
bool isBuiltinFunction(const string& name);
|
||||
bool delFunction(const string& name);
|
||||
const Expression& getFunction(const string& name) const;
|
||||
|
||||
@ -145,15 +147,15 @@ class Debugger : public DialogContainer
|
||||
TiaOutputWidget& tiaOutput() const { return myDialog->tiaOutput(); }
|
||||
|
||||
PackedBitArray& breakPoints() const { return mySystem.m6502().breakPoints(); }
|
||||
PackedBitArray& readTraps() const { return mySystem.m6502().readTraps(); }
|
||||
PackedBitArray& writeTraps() const { return mySystem.m6502().writeTraps(); }
|
||||
TrapArray& readTraps() const { return mySystem.m6502().readTraps(); }
|
||||
TrapArray& writeTraps() const { return mySystem.m6502().writeTraps(); }
|
||||
|
||||
/**
|
||||
Run the debugger command and return the result.
|
||||
*/
|
||||
const string run(const string& command);
|
||||
|
||||
string autoExec();
|
||||
string autoExec(StringList* history);
|
||||
|
||||
string showWatches();
|
||||
|
||||
@ -168,9 +170,9 @@ class Debugger : public DialogContainer
|
||||
static uInt8 set_bit(uInt8 input, uInt8 bit, bool on)
|
||||
{
|
||||
if(on)
|
||||
return input | (1 << bit);
|
||||
return uInt8(input | (1 << bit));
|
||||
else
|
||||
return input & ~(1 << bit);
|
||||
return uInt8(input & ~(1 << bit));
|
||||
}
|
||||
static void set_bits(uInt8 reg, BoolArray& bits)
|
||||
{
|
||||
@ -192,7 +194,7 @@ class Debugger : public DialogContainer
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Invert given input if it differs from its previous value */
|
||||
/** Invert given input if it differs from its previous value */
|
||||
const string invIfChanged(int reg, int oldReg);
|
||||
|
||||
/**
|
||||
@ -205,15 +207,32 @@ class Debugger : public DialogContainer
|
||||
*/
|
||||
static Debugger& debugger() { return *myStaticDebugger; }
|
||||
|
||||
/* These are now exposed so Expressions can use them. */
|
||||
int peek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags); }
|
||||
int dpeek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8); }
|
||||
/** Convenience methods to access peek/poke from System */
|
||||
uInt8 peek(uInt16 addr, uInt8 flags = 0) {
|
||||
return mySystem.peek(addr, flags);
|
||||
}
|
||||
uInt16 dpeek(uInt16 addr, uInt8 flags = 0) {
|
||||
return uInt16(mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8));
|
||||
}
|
||||
void poke(uInt16 addr, uInt8 value, uInt8 flags = 0) {
|
||||
mySystem.poke(addr, value, flags);
|
||||
}
|
||||
|
||||
/** These are now exposed so Expressions can use them. */
|
||||
int peekAsInt(int addr, uInt8 flags = 0) {
|
||||
return mySystem.peek(uInt16(addr), flags);
|
||||
}
|
||||
int dpeekAsInt(int addr, uInt8 flags = 0) {
|
||||
return mySystem.peek(uInt16(addr), flags) |
|
||||
(mySystem.peek(uInt16(addr+1), flags) << 8);
|
||||
}
|
||||
int getAccessFlags(uInt16 addr) const
|
||||
{ return mySystem.getAccessFlags(addr); }
|
||||
void setAccessFlags(uInt16 addr, uInt8 flags)
|
||||
{ mySystem.setAccessFlags(addr, flags); }
|
||||
|
||||
void setBreakPoint(uInt16 bp, bool set);
|
||||
uInt32 getBaseAddress(uInt32 addr, bool read);
|
||||
|
||||
bool patchROM(uInt16 addr, uInt8 value);
|
||||
|
||||
@ -252,13 +271,17 @@ class Debugger : public DialogContainer
|
||||
void nextScanline(int lines);
|
||||
void nextFrame(int frames);
|
||||
bool rewindState();
|
||||
bool unwindState();
|
||||
|
||||
void toggleBreakPoint(uInt16 bp);
|
||||
|
||||
bool breakPoint(uInt16 bp);
|
||||
void toggleReadTrap(uInt16 t);
|
||||
void toggleWriteTrap(uInt16 t);
|
||||
void toggleTrap(uInt16 t);
|
||||
void addReadTrap(uInt16 t);
|
||||
void addWriteTrap(uInt16 t);
|
||||
void addTrap(uInt16 t);
|
||||
void removeReadTrap(uInt16 t);
|
||||
void removeWriteTrap(uInt16 t);
|
||||
void removeTrap(uInt16 t);
|
||||
bool readTrap(uInt16 t);
|
||||
bool writeTrap(uInt16 t);
|
||||
void clearAllTraps();
|
||||
@ -292,7 +315,24 @@ class Debugger : public DialogContainer
|
||||
uInt32 myWidth;
|
||||
uInt32 myHeight;
|
||||
|
||||
// Various builtin functions and operations
|
||||
struct BuiltinFunction {
|
||||
string name, defn, help;
|
||||
};
|
||||
struct PseudoRegister {
|
||||
string name, help;
|
||||
};
|
||||
static const uInt32 NUM_BUILTIN_FUNCS = 18;
|
||||
static const uInt32 NUM_PSEUDO_REGS = 11;
|
||||
static BuiltinFunction ourBuiltinFunctions[NUM_BUILTIN_FUNCS];
|
||||
static PseudoRegister ourPseudoRegisters[NUM_PSEUDO_REGS];
|
||||
|
||||
private:
|
||||
// rewind/unwind one state
|
||||
bool windState(bool unwind);
|
||||
// update the rewind/unwind button state
|
||||
void updateRewindbuttons(const RewindManager& r);
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
Debugger() = delete;
|
||||
Debugger(const Debugger&) = delete;
|
||||
|
@ -337,7 +337,7 @@ class WordDerefExpression : public Expression
|
||||
public:
|
||||
WordDerefExpression(Expression* left) : Expression(left) { }
|
||||
Int32 evaluate() const override
|
||||
{ return Debugger::debugger().dpeek(myLHS->evaluate()); }
|
||||
{ return Debugger::debugger().dpeekAsInt(myLHS->evaluate()); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -110,7 +110,10 @@ string DebuggerParser::run(const string& command)
|
||||
if(BSPF::equalsIgnoreCase(verb, commands[i].cmdString))
|
||||
{
|
||||
if(validateArgs(i))
|
||||
{
|
||||
myCommand = i;
|
||||
commands[i].executor(this);
|
||||
}
|
||||
|
||||
if(commands[i].refreshRequired)
|
||||
debugger.myBaseDialog->loadConfig();
|
||||
@ -119,17 +122,17 @@ string DebuggerParser::run(const string& command)
|
||||
}
|
||||
}
|
||||
|
||||
return "No such command (try \"help\")";
|
||||
return red("No such command (try \"help\")");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string DebuggerParser::exec(const FilesystemNode& file)
|
||||
string DebuggerParser::exec(const FilesystemNode& file, StringList* history)
|
||||
{
|
||||
if(file.exists())
|
||||
{
|
||||
ifstream in(file.getPath());
|
||||
if(!in.is_open())
|
||||
return red("autoexec file \'" + file.getShortPath() + "\' not found");
|
||||
return red("script file \'" + file.getShortPath() + "\' not found");
|
||||
|
||||
ostringstream buf;
|
||||
int count = 0;
|
||||
@ -140,15 +143,27 @@ string DebuggerParser::exec(const FilesystemNode& file)
|
||||
break;
|
||||
|
||||
run(command);
|
||||
if (history != nullptr)
|
||||
history->push_back(command);
|
||||
count++;
|
||||
}
|
||||
buf << "Executed " << count << " commands from \""
|
||||
buf << "\nExecuted " << count << " commands from \""
|
||||
<< file.getShortPath() << "\"";
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
else
|
||||
return red("autoexec file \'" + file.getShortPath() + "\' not found");
|
||||
return red("script file \'" + file.getShortPath() + "\' not found");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerParser::outputCommandError(const string& errorMsg, int command)
|
||||
{
|
||||
string example = commands[command].extendedDesc.substr(commands[command].extendedDesc.find("Example:"));
|
||||
|
||||
commandResult << red(errorMsg);
|
||||
if(!example.empty())
|
||||
commandResult << endl << example;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -159,7 +174,7 @@ void DebuggerParser::getCompletions(const char* in, StringList& completions) con
|
||||
// cerr << "Attempting to complete \"" << in << "\"" << endl;
|
||||
for(int i = 0; i < kNumCommands; ++i)
|
||||
{
|
||||
if(BSPF::startsWithIgnoreCase(commands[i].cmdString.c_str(), in))
|
||||
if(BSPF::matches(commands[i].cmdString, in))
|
||||
completions.push_back(commands[i].cmdString);
|
||||
}
|
||||
}
|
||||
@ -396,7 +411,8 @@ bool DebuggerParser::validateArgs(int cmd)
|
||||
{
|
||||
if(required)
|
||||
{
|
||||
commandResult.str(red("missing required argument(s)"));
|
||||
commandResult.str();
|
||||
outputCommandError("missing required argument(s)", cmd);
|
||||
return false; // needed args. didn't get 'em.
|
||||
}
|
||||
else
|
||||
@ -427,6 +443,14 @@ bool DebuggerParser::validateArgs(int cmd)
|
||||
|
||||
switch(*p)
|
||||
{
|
||||
case kARG_DWORD:
|
||||
if(curArgInt > 0xffffffff)
|
||||
{
|
||||
commandResult.str(red("invalid word argument (must be 0-$ffffffff)"));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case kARG_WORD:
|
||||
if(curArgInt > 0xffff)
|
||||
{
|
||||
@ -484,12 +508,14 @@ cerr << "curCount = " << curCount << endl
|
||||
|
||||
if(curCount < argRequiredCount)
|
||||
{
|
||||
commandResult.str(red("missing required argument(s)"));
|
||||
commandResult.str();
|
||||
outputCommandError("missing required argument(s)", cmd);
|
||||
return false;
|
||||
}
|
||||
else if(argCount > curCount)
|
||||
{
|
||||
commandResult.str(red("too many arguments"));
|
||||
commandResult.str();
|
||||
outputCommandError("too many arguments", cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -502,28 +528,29 @@ string DebuggerParser::eval()
|
||||
ostringstream buf;
|
||||
for(uInt32 i = 0; i < argCount; ++i)
|
||||
{
|
||||
string rlabel = debugger.cartDebug().getLabel(args[i], true);
|
||||
string wlabel = debugger.cartDebug().getLabel(args[i], false);
|
||||
bool validR = rlabel != "" && rlabel[0] != '$',
|
||||
validW = wlabel != "" && wlabel[0] != '$';
|
||||
if(validR && validW)
|
||||
if(args[i] < 0x10000)
|
||||
{
|
||||
if(rlabel == wlabel)
|
||||
buf << rlabel << "(R/W): ";
|
||||
else
|
||||
buf << rlabel << "(R) / " << wlabel << "(W): ";
|
||||
string rlabel = debugger.cartDebug().getLabel(args[i], true);
|
||||
string wlabel = debugger.cartDebug().getLabel(args[i], false);
|
||||
bool validR = rlabel != "" && rlabel[0] != '$',
|
||||
validW = wlabel != "" && wlabel[0] != '$';
|
||||
if(validR && validW)
|
||||
{
|
||||
if(rlabel == wlabel)
|
||||
buf << rlabel << "(R/W): ";
|
||||
else
|
||||
buf << rlabel << "(R) / " << wlabel << "(W): ";
|
||||
}
|
||||
else if(validR)
|
||||
buf << rlabel << "(R): ";
|
||||
else if(validW)
|
||||
buf << wlabel << "(W): ";
|
||||
}
|
||||
else if(validR)
|
||||
buf << rlabel << "(R): ";
|
||||
else if(validW)
|
||||
buf << wlabel << "(W): ";
|
||||
|
||||
if(args[i] < 0x100)
|
||||
buf << "$" << Base::toString(args[i], Base::F_16_2)
|
||||
<< " %" << Base::toString(args[i], Base::F_2_8);
|
||||
else
|
||||
buf << "$" << Base::toString(args[i], Base::F_16_4)
|
||||
<< " %" << Base::toString(args[i], Base::F_2_16);
|
||||
buf << "$" << Base::toString(args[i], Base::F_16);
|
||||
|
||||
if(args[i] < 0x10000)
|
||||
buf << " %" << Base::toString(args[i], Base::F_2);
|
||||
|
||||
buf << " #" << int(args[i]);
|
||||
if(i != argCount - 1)
|
||||
@ -534,70 +561,117 @@ string DebuggerParser::eval()
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string DebuggerParser::trapStatus(uInt32 addr, bool& enabled)
|
||||
void DebuggerParser::listTraps(bool listCond)
|
||||
{
|
||||
string result;
|
||||
result += Base::toString(addr);
|
||||
result += ": ";
|
||||
bool r = debugger.readTrap(addr);
|
||||
bool w = debugger.writeTrap(addr);
|
||||
enabled = r || w;
|
||||
if(r && w)
|
||||
result += "read|write";
|
||||
else if(r)
|
||||
result += "read";
|
||||
else if(w)
|
||||
result += "write";
|
||||
else
|
||||
result += "none";
|
||||
StringList names = debugger.cpuDebug().m6502().getCondTrapNames();
|
||||
|
||||
const string& l = debugger.cartDebug().getLabel(addr, !w);
|
||||
if(l != "") {
|
||||
result += " (";
|
||||
result += l;
|
||||
result += ")";
|
||||
commandResult << (listCond ? "trapifs:" : "traps:") << endl;
|
||||
for(uInt32 i = 0; i < names.size(); i++)
|
||||
{
|
||||
bool hasCond = names[i] != "";
|
||||
if(hasCond == listCond)
|
||||
{
|
||||
commandResult << Base::toString(i) << ": ";
|
||||
if(myTraps[i]->read && myTraps[i]->write)
|
||||
commandResult << "read|write";
|
||||
else if(myTraps[i]->read)
|
||||
commandResult << "read ";
|
||||
else if(myTraps[i]->write)
|
||||
commandResult << " write";
|
||||
else
|
||||
commandResult << "none";
|
||||
|
||||
if(hasCond)
|
||||
commandResult << " " << names[i];
|
||||
commandResult << " " << debugger.cartDebug().getLabel(myTraps[i]->begin, true, 4);
|
||||
if(myTraps[i]->begin != myTraps[i]->end)
|
||||
commandResult << " " << debugger.cartDebug().getLabel(myTraps[i]->end, true, 4);
|
||||
commandResult << trapStatus(*myTraps[i]);
|
||||
commandResult << " + mirrors";
|
||||
if(i != (names.size() - 1)) commandResult << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool DebuggerParser::saveScriptFile(string file)
|
||||
string DebuggerParser::trapStatus(const Trap& trap)
|
||||
{
|
||||
if( file.find_last_of('.') == string::npos )
|
||||
file += ".stella";
|
||||
stringstream result;
|
||||
string lblb = debugger.cartDebug().getLabel(trap.begin, !trap.write);
|
||||
string lble = debugger.cartDebug().getLabel(trap.end, !trap.write);
|
||||
|
||||
ofstream out(file);
|
||||
if(lblb != "") {
|
||||
result << " (";
|
||||
result << lblb;
|
||||
}
|
||||
|
||||
if(trap.begin != trap.end)
|
||||
{
|
||||
if(lble != "")
|
||||
{
|
||||
if (lblb != "")
|
||||
result << " ";
|
||||
else
|
||||
result << " (";
|
||||
result << lble;
|
||||
}
|
||||
}
|
||||
if (lblb != "" || lble != "")
|
||||
result << ")";
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string DebuggerParser::saveScriptFile(string file)
|
||||
{
|
||||
// Append 'script' extension when necessary
|
||||
if(file.find_last_of('.') == string::npos)
|
||||
file += ".script";
|
||||
|
||||
FilesystemNode node(debugger.myOSystem.defaultSaveDir() + file);
|
||||
ofstream out(node.getPath());
|
||||
if(!out.is_open())
|
||||
return "Unable to save script to " + node.getShortPath();
|
||||
|
||||
FunctionDefMap funcs = debugger.getFunctionDefMap();
|
||||
for(const auto& f: funcs)
|
||||
out << "function " << f.first << " { " << f.second << " }" << endl;
|
||||
if (!debugger.isBuiltinFunction(f.first))
|
||||
out << "function " << f.first << " {" << f.second << "}" << endl;
|
||||
|
||||
for(const auto& w: myWatches)
|
||||
out << "watch " << w << endl;
|
||||
|
||||
for(uInt32 i = 0; i < 0x10000; ++i)
|
||||
if(debugger.breakPoint(i))
|
||||
out << "break #" << i << endl;
|
||||
|
||||
for(uInt32 i = 0; i < 0x10000; ++i)
|
||||
{
|
||||
bool r = debugger.readTrap(i);
|
||||
bool w = debugger.writeTrap(i);
|
||||
|
||||
if(r && w)
|
||||
out << "trap #" << i << endl;
|
||||
else if(r)
|
||||
out << "trapread #" << i << endl;
|
||||
else if(w)
|
||||
out << "trapwrite #" << i << endl;
|
||||
}
|
||||
out << "break " << Base::toString(i) << endl;
|
||||
|
||||
StringList conds = debugger.cpuDebug().m6502().getCondBreakNames();
|
||||
for(const auto& cond: conds)
|
||||
for(const auto& cond : conds)
|
||||
out << "breakif {" << cond << "}" << endl;
|
||||
|
||||
return out.good();
|
||||
StringList names = debugger.cpuDebug().m6502().getCondTrapNames();
|
||||
for(uInt32 i = 0; i < myTraps.size(); ++i)
|
||||
{
|
||||
bool read = myTraps[i]->read;
|
||||
bool write = myTraps[i]->write;
|
||||
bool hasCond = names[i] != "";
|
||||
|
||||
if(read && write)
|
||||
out << "trap";
|
||||
else if(read)
|
||||
out << "trapread";
|
||||
else if(write)
|
||||
out << "trapwrite";
|
||||
if(hasCond)
|
||||
out << "if {" << names[i] << "}";
|
||||
out << " " << Base::toString(myTraps[i]->begin);
|
||||
if(myTraps[i]->begin != myTraps[i]->end)
|
||||
out << " " << Base::toString(myTraps[i]->end);
|
||||
out << endl;
|
||||
}
|
||||
|
||||
return "saved " + node.getShortPath() + " OK";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -695,7 +769,7 @@ void DebuggerParser::executeCheat()
|
||||
#ifdef CHEATCODE_SUPPORT
|
||||
if(argCount == 0)
|
||||
{
|
||||
commandResult << red("Missing cheat code");
|
||||
outputCommandError("missing cheat code", myCommand);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -705,7 +779,7 @@ void DebuggerParser::executeCheat()
|
||||
if(debugger.myOSystem.cheat().add("DBG", cheat))
|
||||
commandResult << "Cheat code " << cheat << " enabled" << endl;
|
||||
else
|
||||
commandResult << red("Invalid cheat code ") << cheat << endl;
|
||||
commandResult << red("invalid cheat code ") << cheat << endl;
|
||||
}
|
||||
#else
|
||||
commandResult << red("Cheat support not enabled\n");
|
||||
@ -735,8 +809,9 @@ void DebuggerParser::executeClearconfig()
|
||||
// "cleartraps"
|
||||
void DebuggerParser::executeCleartraps()
|
||||
{
|
||||
myTraps.clear();
|
||||
debugger.clearAllTraps();
|
||||
debugger.cpuDebug().m6502().clearCondTraps();
|
||||
myTraps.clear();
|
||||
commandResult << "all traps cleared";
|
||||
}
|
||||
|
||||
@ -762,12 +837,12 @@ void DebuggerParser::executeCode()
|
||||
{
|
||||
if(argCount != 2)
|
||||
{
|
||||
commandResult << red("Specify start and end of range only");
|
||||
outputCommandError("specify start and end of range only", myCommand);
|
||||
return;
|
||||
}
|
||||
else if(args[1] < args[0])
|
||||
{
|
||||
commandResult << red("Start address must be <= end address");
|
||||
commandResult << red("start address must be <= end address");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -803,12 +878,12 @@ void DebuggerParser::executeData()
|
||||
{
|
||||
if(argCount != 2)
|
||||
{
|
||||
commandResult << red("Specify start and end of range only");
|
||||
outputCommandError("specify start and end of range only", myCommand);
|
||||
return;
|
||||
}
|
||||
else if(args[1] < args[0])
|
||||
{
|
||||
commandResult << red("Start address must be <= end address");
|
||||
commandResult << red("start address must be <= end address");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -839,7 +914,10 @@ void DebuggerParser::executeDefine()
|
||||
// "delbreakif"
|
||||
void DebuggerParser::executeDelbreakif()
|
||||
{
|
||||
debugger.cpuDebug().m6502().delCondBreak(args[0]);
|
||||
if (debugger.cpuDebug().m6502().delCondBreak(args[0]))
|
||||
commandResult << "removed breakif " << Base::toString(args[0]);
|
||||
else
|
||||
commandResult << red("no such breakif");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -852,6 +930,24 @@ void DebuggerParser::executeDelfunction()
|
||||
commandResult << "function " << argStrings[0] << " built-in or not found";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "deltrap"
|
||||
void DebuggerParser::executeDeltrap()
|
||||
{
|
||||
int index = args[0];
|
||||
|
||||
if(debugger.cpuDebug().m6502().delCondTrap(index))
|
||||
{
|
||||
for(uInt32 addr = myTraps[index]->begin; addr <= myTraps[index]->end; ++addr)
|
||||
executeTrapRW(addr, myTraps[index]->read, myTraps[index]->write, false);
|
||||
// @sa666666: please check this:
|
||||
Vec::removeAt(myTraps, index);
|
||||
commandResult << "removed trap " << Base::toString(index);
|
||||
}
|
||||
else
|
||||
commandResult << red("no such trap");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "delwatch"
|
||||
void DebuggerParser::executeDelwatch()
|
||||
@ -863,7 +959,7 @@ void DebuggerParser::executeDelwatch()
|
||||
commandResult << "removed watch";
|
||||
}
|
||||
else
|
||||
commandResult << "no such watch";
|
||||
commandResult << red("no such watch");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -880,7 +976,7 @@ void DebuggerParser::executeDisasm()
|
||||
start = args[0];
|
||||
lines = args[1];
|
||||
} else {
|
||||
commandResult << "wrong number of arguments";
|
||||
outputCommandError("wrong number of arguments", myCommand);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -910,7 +1006,7 @@ void DebuggerParser::executeDump()
|
||||
// Error checking
|
||||
if(argCount > 1 && args[1] < args[0])
|
||||
{
|
||||
commandResult << red("Start address must be <= end address");
|
||||
commandResult << red("start address must be <= end address");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -920,7 +1016,7 @@ void DebuggerParser::executeDump()
|
||||
dump(args[0], args[1]);
|
||||
else
|
||||
{
|
||||
commandResult << "wrong number of arguments";
|
||||
outputCommandError("wrong number of arguments", myCommand);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -929,8 +1025,13 @@ void DebuggerParser::executeDump()
|
||||
// "exec"
|
||||
void DebuggerParser::executeExec()
|
||||
{
|
||||
FilesystemNode file(argStrings[0]);
|
||||
commandResult << exec(file);
|
||||
// Append 'script' extension when necessary
|
||||
string file = argStrings[0];
|
||||
if(file.find_last_of('.') == string::npos)
|
||||
file += ".script";
|
||||
|
||||
FilesystemNode node(debugger.myOSystem.defaultSaveDir() + file);
|
||||
commandResult << exec(node);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -976,12 +1077,12 @@ void DebuggerParser::executeGfx()
|
||||
{
|
||||
if(argCount != 2)
|
||||
{
|
||||
commandResult << red("Specify start and end of range only");
|
||||
outputCommandError("specify start and end of range only", myCommand);
|
||||
return;
|
||||
}
|
||||
else if(args[1] < args[0])
|
||||
{
|
||||
commandResult << red("Start address must be <= end address");
|
||||
commandResult << red("start address must be <= end address");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1061,26 +1162,21 @@ void DebuggerParser::executeListbreaks()
|
||||
if(debugger.breakPoints().isSet(i))
|
||||
{
|
||||
buf << debugger.cartDebug().getLabel(i, true, 4) << " ";
|
||||
if(! (++count % 8) ) buf << "\n";
|
||||
if(! (++count % 8) ) buf << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if(count)
|
||||
return ret;
|
||||
else
|
||||
return "no breakpoints set";
|
||||
*/
|
||||
if(count)
|
||||
commandResult << "breaks:\n" << buf.str();
|
||||
commandResult << "breaks:" << endl << buf.str();
|
||||
|
||||
StringList conds = debugger.cpuDebug().m6502().getCondBreakNames();
|
||||
if(conds.size() > 0)
|
||||
{
|
||||
commandResult << "\nbreakifs:\n";
|
||||
if(count)
|
||||
commandResult << endl;
|
||||
commandResult << "breakifs:" << endl;
|
||||
for(uInt32 i = 0; i < conds.size(); i++)
|
||||
{
|
||||
commandResult << i << ": " << conds[i];
|
||||
commandResult << Base::toString(i) << ": " << conds[i];
|
||||
if(i != (conds.size() - 1)) commandResult << endl;
|
||||
}
|
||||
}
|
||||
@ -1118,11 +1214,27 @@ void DebuggerParser::executeListfunctions()
|
||||
// "listtraps"
|
||||
void DebuggerParser::executeListtraps()
|
||||
{
|
||||
if(myTraps.size() > 0)
|
||||
StringList names = debugger.cpuDebug().m6502().getCondTrapNames();
|
||||
|
||||
if(myTraps.size() != names.size())
|
||||
{
|
||||
bool enabled = true;
|
||||
for(const auto& trap: myTraps)
|
||||
commandResult << trapStatus(trap, enabled) << " + mirrors" << endl;
|
||||
commandResult << "Internal error! Different trap sizes.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (names.size() > 0)
|
||||
{
|
||||
bool trapFound = false, trapifFound = false;
|
||||
for(uInt32 i = 0; i < names.size(); i++)
|
||||
if(names[i] == "")
|
||||
trapFound = true;
|
||||
else
|
||||
trapifFound = true;
|
||||
|
||||
if(trapFound)
|
||||
listTraps(false);
|
||||
if(trapifFound)
|
||||
listTraps(true);
|
||||
}
|
||||
else
|
||||
commandResult << "no traps set";
|
||||
@ -1175,12 +1287,12 @@ void DebuggerParser::executePGfx()
|
||||
{
|
||||
if(argCount != 2)
|
||||
{
|
||||
commandResult << red("Specify start and end of range only");
|
||||
outputCommandError("specify start and end of range only", myCommand);
|
||||
return;
|
||||
}
|
||||
else if(args[1] < args[0])
|
||||
{
|
||||
commandResult << red("Start address must be <= end address");
|
||||
commandResult << red("start address must be <= end address");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1267,12 +1379,12 @@ void DebuggerParser::executeRow()
|
||||
{
|
||||
if(argCount != 2)
|
||||
{
|
||||
commandResult << red("Specify start and end of range only");
|
||||
outputCommandError("specify start and end of range only", myCommand);
|
||||
return;
|
||||
}
|
||||
else if(args[1] < args[0])
|
||||
{
|
||||
commandResult << red("Start address must be <= end address");
|
||||
commandResult << red("start address must be <= end address");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1373,10 +1485,7 @@ void DebuggerParser::executeS()
|
||||
// "save"
|
||||
void DebuggerParser::executeSave()
|
||||
{
|
||||
if(saveScriptFile(argStrings[0]))
|
||||
commandResult << "saved script to file " << argStrings[0];
|
||||
else
|
||||
commandResult << red("I/O error");
|
||||
commandResult << saveScriptFile(argStrings[0]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -1473,71 +1582,153 @@ void DebuggerParser::executeTrace()
|
||||
// "trap"
|
||||
void DebuggerParser::executeTrap()
|
||||
{
|
||||
if(argCount > 2)
|
||||
{
|
||||
commandResult << red("Command takes one or two arguments") << endl;
|
||||
return;
|
||||
}
|
||||
executeTraps(true, true, "trap");
|
||||
}
|
||||
|
||||
uInt32 beg = args[0];
|
||||
uInt32 end = argCount == 2 ? args[1] : beg;
|
||||
if(beg > 0xFFFF || end > 0xFFFF)
|
||||
{
|
||||
commandResult << red("One or more addresses are invalid") << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for(uInt32 addr = beg; addr <= end; ++addr)
|
||||
executeTrapRW(addr, true, true);
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "trapif"
|
||||
void DebuggerParser::executeTrapif()
|
||||
{
|
||||
executeTraps(true, true, "trapif", true);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "trapread"
|
||||
void DebuggerParser::executeTrapread()
|
||||
{
|
||||
if(argCount > 2)
|
||||
{
|
||||
commandResult << red("Command takes one or two arguments") << endl;
|
||||
return;
|
||||
}
|
||||
executeTraps(true, false, "trapread");
|
||||
}
|
||||
|
||||
uInt32 beg = args[0];
|
||||
uInt32 end = argCount == 2 ? args[1] : beg;
|
||||
if(beg > 0xFFFF || end > 0xFFFF)
|
||||
{
|
||||
commandResult << red("One or more addresses are invalid") << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for(uInt32 addr = beg; addr <= end; ++addr)
|
||||
executeTrapRW(addr, true, false);
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "trapreadif"
|
||||
void DebuggerParser::executeTrapreadif()
|
||||
{
|
||||
executeTraps(true, false, "trapreadif", true);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "trapwrite"
|
||||
void DebuggerParser::executeTrapwrite()
|
||||
{
|
||||
if(argCount > 2)
|
||||
{
|
||||
commandResult << red("Command takes one or two arguments") << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
uInt32 beg = args[0];
|
||||
uInt32 end = argCount == 2 ? args[1] : beg;
|
||||
if(beg > 0xFFFF || end > 0xFFFF)
|
||||
{
|
||||
commandResult << red("One or more addresses are invalid") << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for(uInt32 addr = beg; addr <= end; ++addr)
|
||||
executeTrapRW(addr, false, true);
|
||||
executeTraps(false, true, "trapwrite");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// wrapper function for trap/trapread/trapwrite commands
|
||||
void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||
// "trapwriteif"
|
||||
void DebuggerParser::executeTrapwriteif()
|
||||
{
|
||||
executeTraps(false, true, "trapwriteif", true);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Wrapper function for trap(if)s
|
||||
void DebuggerParser::executeTraps(bool read, bool write, const string& command,
|
||||
bool hasCond)
|
||||
{
|
||||
uInt32 ofs = hasCond ? 1 : 0;
|
||||
uInt32 begin = args[ofs];
|
||||
uInt32 end = argCount == 2 + ofs ? args[1 + ofs] : begin;
|
||||
|
||||
if(argCount < 1 + ofs)
|
||||
{
|
||||
outputCommandError("missing required argument(s)", myCommand);
|
||||
return;
|
||||
}
|
||||
if(argCount > 2 + ofs)
|
||||
{
|
||||
outputCommandError("too many arguments", myCommand);
|
||||
return;
|
||||
}
|
||||
if(begin > 0xFFFF || end > 0xFFFF)
|
||||
{
|
||||
commandResult << red("invalid word argument(s) (must be 0-$ffff)");
|
||||
return;
|
||||
}
|
||||
if(begin > end)
|
||||
{
|
||||
commandResult << red("start address must be <= end address");
|
||||
return;
|
||||
}
|
||||
|
||||
// base addresses of mirrors
|
||||
uInt32 beginRead = debugger.getBaseAddress(begin, true);
|
||||
uInt32 endRead = debugger.getBaseAddress(end, true);
|
||||
uInt32 beginWrite = debugger.getBaseAddress(begin, false);
|
||||
uInt32 endWrite = debugger.getBaseAddress(end, false);
|
||||
stringstream conditionBuf;
|
||||
|
||||
// parenthesize provided and address range condition(s) (begin)
|
||||
if(hasCond)
|
||||
conditionBuf << "(" << argStrings[0] << ")&&(";
|
||||
|
||||
// add address range condition(s) to provided condition
|
||||
if(read)
|
||||
{
|
||||
if(beginRead != endRead)
|
||||
conditionBuf << "__lastread>=" << Base::toString(beginRead) << "&&__lastread<=" << Base::toString(endRead);
|
||||
else
|
||||
conditionBuf << "__lastread==" << Base::toString(beginRead);
|
||||
}
|
||||
if(read && write)
|
||||
conditionBuf << "||";
|
||||
if(write)
|
||||
{
|
||||
if(beginWrite != endWrite)
|
||||
conditionBuf << "__lastwrite>=" << Base::toString(beginWrite) << "&&__lastwrite<=" << Base::toString(endWrite);
|
||||
else
|
||||
conditionBuf << "__lastwrite==" << Base::toString(beginWrite);
|
||||
}
|
||||
// parenthesize provided condition (end)
|
||||
if(hasCond)
|
||||
conditionBuf << ")";
|
||||
|
||||
const string condition = conditionBuf.str();
|
||||
|
||||
int res = YaccParser::parse(condition.c_str());
|
||||
if(res == 0)
|
||||
{
|
||||
// duplicates will remove each other
|
||||
bool add = true;
|
||||
for(uInt32 i = 0; i < myTraps.size(); i++)
|
||||
{
|
||||
if(myTraps[i]->begin == begin && myTraps[i]->end == end &&
|
||||
myTraps[i]->read == read && myTraps[i]->write == write &&
|
||||
myTraps[i]->condition == condition)
|
||||
{
|
||||
if(debugger.cpuDebug().m6502().delCondTrap(i))
|
||||
{
|
||||
add = false;
|
||||
// @sa666666: please check this:
|
||||
Vec::removeAt(myTraps, i);
|
||||
commandResult << "Removed trap " << Base::toString(i);
|
||||
break;
|
||||
}
|
||||
commandResult << "Internal error! Duplicate trap removal failed!";
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(add)
|
||||
{
|
||||
uInt32 ret = debugger.cpuDebug().m6502().addCondTrap(
|
||||
YaccParser::getResult(), hasCond ? argStrings[0] : "");
|
||||
commandResult << "Added trap " << Base::toString(ret);
|
||||
|
||||
// @sa666666: please check this:
|
||||
myTraps.emplace_back(new Trap{ read, write, begin, end, condition });
|
||||
}
|
||||
|
||||
for(uInt32 addr = begin; addr <= end; ++addr)
|
||||
executeTrapRW(addr, read, write, add);
|
||||
}
|
||||
else
|
||||
{
|
||||
commandResult << red("invalid expression");
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// wrapper function for trap(if)/trapread(if)/trapwrite(if) commands
|
||||
void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write, bool add)
|
||||
{
|
||||
switch(debugger.cartDebug().addressType(addr))
|
||||
{
|
||||
@ -1547,10 +1738,11 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||
{
|
||||
if((i & 0x1080) == 0x0000)
|
||||
{
|
||||
if(read && (i & 0x000F) == addr)
|
||||
debugger.toggleReadTrap(i);
|
||||
if(write && (i & 0x003F) == addr)
|
||||
debugger.toggleWriteTrap(i);
|
||||
// @sa666666: This seems wrong. E.g. trapread 40 4f will never trigger
|
||||
if(read && (i & 0x000F) == (addr & 0x000F))
|
||||
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||
if(write && (i & 0x003F) == (addr & 0x003F))
|
||||
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1559,10 +1751,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||
{
|
||||
for(uInt32 i = 0; i <= 0xFFFF; ++i)
|
||||
{
|
||||
if((i & 0x1080) == 0x0080 && (i & 0x0200) != 0x0000 && (i & 0x02FF) == addr)
|
||||
if((i & 0x1280) == 0x0280 && (i & 0x029F) == (addr & 0x029F))
|
||||
{
|
||||
if(read) debugger.toggleReadTrap(i);
|
||||
if(write) debugger.toggleWriteTrap(i);
|
||||
if(read)
|
||||
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||
if(write)
|
||||
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1571,10 +1765,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||
{
|
||||
for(uInt32 i = 0; i <= 0xFFFF; ++i)
|
||||
{
|
||||
if((i & 0x1080) == 0x0080 && (i & 0x0200) == 0x0000 && (i & 0x00FF) == addr)
|
||||
if((i & 0x1280) == 0x0080 && (i & 0x00FF) == (addr & 0x00FF))
|
||||
{
|
||||
if(read) debugger.toggleReadTrap(i);
|
||||
if(write) debugger.toggleWriteTrap(i);
|
||||
if(read)
|
||||
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||
if(write)
|
||||
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1587,21 +1783,16 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||
{
|
||||
if((i % 0x2000 >= 0x1000) && (i & 0x0FFF) == (addr & 0x0FFF))
|
||||
{
|
||||
if(read) debugger.toggleReadTrap(i);
|
||||
if(write) debugger.toggleWriteTrap(i);
|
||||
if(read)
|
||||
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||
if(write)
|
||||
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool trapEnabled = false;
|
||||
const string& result = trapStatus(addr, trapEnabled);
|
||||
if(trapEnabled) myTraps.insert(addr);
|
||||
else myTraps.erase(addr);
|
||||
|
||||
commandResult << result << " + mirrors" << endl;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -1646,6 +1837,19 @@ void DebuggerParser::executeUndef()
|
||||
commandResult << red("no such label");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "unwind"
|
||||
void DebuggerParser::executeUnwind()
|
||||
{
|
||||
if(debugger.unwindState())
|
||||
{
|
||||
debugger.rom().invalidate();
|
||||
commandResult << "unwind by one level";
|
||||
}
|
||||
else
|
||||
commandResult << "no states left to rewind";
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// "v"
|
||||
void DebuggerParser::executeV()
|
||||
@ -1688,7 +1892,6 @@ void DebuggerParser::executeZ()
|
||||
debugger.cpuDebug().setZ(args[0]);
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// List of all commands available to the parser
|
||||
DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
@ -1883,6 +2086,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
std::mem_fn(&DebuggerParser::executeDelfunction)
|
||||
},
|
||||
|
||||
{
|
||||
"deltrap",
|
||||
"Delete trap <xx>",
|
||||
"Example: deltrap 0",
|
||||
true,
|
||||
false,
|
||||
{ kARG_WORD, kARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeDeltrap)
|
||||
},
|
||||
|
||||
{
|
||||
"delwatch",
|
||||
"Delete watch <xx>",
|
||||
@ -1907,7 +2120,7 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
{
|
||||
"dump",
|
||||
"Dump data at address <xx> [to yy]",
|
||||
"Examples:\n"
|
||||
"Example:\n"
|
||||
" dump f000 - dumps 128 bytes @ f000\n"
|
||||
" dump f000 f0ff - dumps all bytes from f000 to f0ff",
|
||||
true,
|
||||
@ -1949,7 +2162,7 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
{
|
||||
"function",
|
||||
"Define function name xx for expression yy",
|
||||
"Example: define FUNC1 { ... }",
|
||||
"Example: function FUNC1 { ... }",
|
||||
true,
|
||||
false,
|
||||
{ kARG_LABEL, kARG_WORD, kARG_END_ARGS },
|
||||
@ -2094,7 +2307,7 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
"Example: print pc, print f000",
|
||||
true,
|
||||
false,
|
||||
{ kARG_WORD, kARG_END_ARGS },
|
||||
{ kARG_DWORD, kARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executePrint)
|
||||
},
|
||||
|
||||
@ -2325,6 +2538,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
std::mem_fn(&DebuggerParser::executeTrap)
|
||||
},
|
||||
|
||||
{
|
||||
"trapif",
|
||||
"On <condition> trap R/W access to address(es) xx [yy]",
|
||||
"Set a conditional R/W trap on the given address(es) and all mirrors\nCondition can include multiple items.\n"
|
||||
"Example: trapif _scan>#100 GRP0, trapif _bank==1 f000 f100",
|
||||
true,
|
||||
false,
|
||||
{ kARG_WORD, kARG_MULTI_BYTE },
|
||||
std::mem_fn(&DebuggerParser::executeTrapif)
|
||||
},
|
||||
|
||||
{
|
||||
"trapread",
|
||||
"Trap read access to address(es) xx [yy]",
|
||||
@ -2336,6 +2560,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
std::mem_fn(&DebuggerParser::executeTrapread)
|
||||
},
|
||||
|
||||
{
|
||||
"trapreadif",
|
||||
"On <condition> trap read access to address(es) xx [yy]",
|
||||
"Set a conditional read trap on the given address(es) and all mirrors\nCondition can include multiple items.\n"
|
||||
"Example: trapreadif _scan>#100 GRP0, trapreadif _bank==1 f000 f100",
|
||||
true,
|
||||
false,
|
||||
{ kARG_WORD, kARG_MULTI_BYTE },
|
||||
std::mem_fn(&DebuggerParser::executeTrapreadif)
|
||||
},
|
||||
|
||||
{
|
||||
"trapwrite",
|
||||
"Trap write access to address(es) xx [yy]",
|
||||
@ -2347,6 +2582,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
std::mem_fn(&DebuggerParser::executeTrapwrite)
|
||||
},
|
||||
|
||||
{
|
||||
"trapwriteif",
|
||||
"On <condition> trap write access to address(es) xx [yy]",
|
||||
"Set a conditional write trap on the given address(es) and all mirrors\nCondition can include multiple items.\n"
|
||||
"Example: trapwriteif _scan>#100 GRP0, trapwriteif _bank==1 f000 f100",
|
||||
true,
|
||||
false,
|
||||
{ kARG_WORD, kARG_MULTI_BYTE },
|
||||
std::mem_fn(&DebuggerParser::executeTrapwriteif)
|
||||
},
|
||||
|
||||
{
|
||||
"type",
|
||||
"Show disassembly type for address xx [yy]",
|
||||
@ -2378,6 +2624,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||
std::mem_fn(&DebuggerParser::executeUndef)
|
||||
},
|
||||
|
||||
{
|
||||
"unwind",
|
||||
"Unwind state to last step/trace/scanline/frame",
|
||||
"Unwind currently only works in the debugger",
|
||||
false,
|
||||
true,
|
||||
{ kARG_END_ARGS },
|
||||
std::mem_fn(&DebuggerParser::executeUnwind)
|
||||
},
|
||||
|
||||
{
|
||||
"v",
|
||||
"Overflow Flag: set (0 or 1), or toggle (no arg)",
|
||||
|
@ -39,7 +39,7 @@ class DebuggerParser
|
||||
string run(const string& command);
|
||||
|
||||
/** Execute parser commands given in 'file' */
|
||||
string exec(const FilesystemNode& file);
|
||||
string exec(const FilesystemNode& file, StringList* history = nullptr);
|
||||
|
||||
/** Given a substring, determine matching substrings from the list
|
||||
of available commands. Used in the debugger prompt for tab-completion */
|
||||
@ -65,10 +65,10 @@ class DebuggerParser
|
||||
bool getArgs(const string& command, string& verb);
|
||||
bool validateArgs(int cmd);
|
||||
string eval();
|
||||
bool saveScriptFile(string file);
|
||||
string saveScriptFile(string file);
|
||||
|
||||
private:
|
||||
enum { kNumCommands = 72 };
|
||||
enum { kNumCommands = 77 };
|
||||
|
||||
// Constants for argument processing
|
||||
enum {
|
||||
@ -80,6 +80,7 @@ class DebuggerParser
|
||||
|
||||
enum parameters {
|
||||
kARG_WORD, // single 16-bit value
|
||||
kARG_DWORD, // single 32-bit value
|
||||
kARG_MULTI_WORD, // multiple 16-bit values (must occur last)
|
||||
kARG_BYTE, // single 8-bit value
|
||||
kARG_MULTI_BYTE, // multiple 8-bit values (must occur last)
|
||||
@ -99,6 +100,14 @@ class DebuggerParser
|
||||
parameters parms[10];
|
||||
std::function<void (DebuggerParser*)> executor;
|
||||
};
|
||||
struct Trap
|
||||
{
|
||||
bool read;
|
||||
bool write;
|
||||
uInt32 begin;
|
||||
uInt32 end;
|
||||
string condition;
|
||||
};
|
||||
|
||||
// Reference to our debugger object
|
||||
Debugger& debugger;
|
||||
@ -109,6 +118,8 @@ class DebuggerParser
|
||||
// The results of the currently running command
|
||||
ostringstream commandResult;
|
||||
|
||||
// currently execute command id
|
||||
int myCommand;
|
||||
// Arguments in 'int' and 'string' format for the currently running command
|
||||
IntArray args;
|
||||
StringList argStrings;
|
||||
@ -117,8 +128,12 @@ class DebuggerParser
|
||||
StringList myWatches;
|
||||
|
||||
// Keep track of traps (read and/or write)
|
||||
std::set<uInt32> myTraps;
|
||||
string trapStatus(uInt32 addr, bool& enabled);
|
||||
vector<unique_ptr<Trap>> myTraps;
|
||||
void listTraps(bool listCond);
|
||||
string trapStatus(const Trap& trap);
|
||||
|
||||
// output the error with the example provided for the command
|
||||
void outputCommandError(const string& errorMsg, int command);
|
||||
|
||||
// List of available command methods
|
||||
void executeA();
|
||||
@ -140,6 +155,7 @@ class DebuggerParser
|
||||
void executeDefine();
|
||||
void executeDelbreakif();
|
||||
void executeDelfunction();
|
||||
void executeDeltrap();
|
||||
void executeDelwatch();
|
||||
void executeDisasm();
|
||||
void executeDump();
|
||||
@ -183,12 +199,17 @@ class DebuggerParser
|
||||
void executeTia();
|
||||
void executeTrace();
|
||||
void executeTrap();
|
||||
void executeTrapif();
|
||||
void executeTrapread();
|
||||
void executeTrapreadif();
|
||||
void executeTrapwrite();
|
||||
void executeTrapRW(uInt32 addr, bool read, bool write); // not exposed by debugger
|
||||
void executeTrapwriteif();
|
||||
void executeTraps(bool read, bool write, const string& command, bool cond = false);
|
||||
void executeTrapRW(uInt32 addr, bool read, bool write, bool add = true); // not exposed by debugger
|
||||
void executeType();
|
||||
void executeUHex();
|
||||
void executeUndef();
|
||||
void executeUnwind();
|
||||
void executeV();
|
||||
void executeWatch();
|
||||
void executeX();
|
||||
|
@ -120,6 +120,12 @@ void DiStella::disasm(uInt32 distart, int pass)
|
||||
myPC = distart - myOffset;
|
||||
while (myPC <= myAppData.end) {
|
||||
|
||||
// since -1 is used in m6502.m4 for clearing the last peek
|
||||
// and this results into an access at e.g. 0xffff,
|
||||
// we have to fix the consequences here (ugly!).
|
||||
if(myPC == myAppData.end)
|
||||
goto FIX_LAST;
|
||||
|
||||
if (checkBits(myPC, CartDebug::GFX | CartDebug::PGFX,
|
||||
CartDebug::CODE)) {
|
||||
if (pass == 2)
|
||||
@ -137,6 +143,7 @@ void DiStella::disasm(uInt32 distart, int pass)
|
||||
myPC++;
|
||||
} else if (checkBits(myPC, CartDebug::ROW,
|
||||
CartDebug::CODE | CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) {
|
||||
FIX_LAST:
|
||||
if (pass == 2)
|
||||
mark(myPC + myOffset, CartDebug::VALID_ENTRY);
|
||||
|
||||
@ -713,6 +720,7 @@ void DiStella::disasmFromAddress(uInt32 distart)
|
||||
myPCEnd = myAppData.end + myOffset;
|
||||
return;
|
||||
}
|
||||
break; // TODO - is this the intent?
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -349,8 +349,8 @@ bool TIADebug::collision(CollisionBit id) const
|
||||
case Cx_BLPF: return myTIA.collCXBLPF() & 0x80;
|
||||
case Cx_P0P1: return myTIA.collCXPPMM() & 0x80;
|
||||
case Cx_M0M1: return myTIA.collCXPPMM() & 0x40;
|
||||
default: return false; // make compiler happy
|
||||
}
|
||||
return false; // make compiler happy
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -703,13 +703,13 @@ int TIADebug::frameCycles() const
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int TIADebug::cyclesLo() const
|
||||
{
|
||||
return (int)myTIA.cycles();
|
||||
return int(myTIA.cycles());
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int TIADebug::cyclesHi() const
|
||||
{
|
||||
return (int)(myTIA.cycles() >> 32);
|
||||
return int(myTIA.cycles() >> 32);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -730,6 +730,12 @@ int TIADebug::clocksThisLine() const
|
||||
return myTIA.clocksThisLine();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int TIADebug::cyclesThisLine() const
|
||||
{
|
||||
return myTIA.clocksThisLine()/3;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool TIADebug::vsync() const
|
||||
{
|
||||
|
@ -163,6 +163,7 @@ class TIADebug : public DebuggerSystem
|
||||
int cyclesLo() const;
|
||||
int cyclesHi() const;
|
||||
int clocksThisLine() const;
|
||||
int cyclesThisLine() const;
|
||||
bool vsync() const;
|
||||
bool vblank() const;
|
||||
int vsyncAsInt() const { return int(vsync()); } // so we can use _vsync pseudo-register
|
||||
|
59
src/debugger/TrapArray.hxx
Normal file
59
src/debugger/TrapArray.hxx
Normal file
@ -0,0 +1,59 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef TRAP_ARRAY_HXX
|
||||
#define TRAP_ARRAY_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
class TrapArray
|
||||
{
|
||||
public:
|
||||
TrapArray() : myInitialized(false) {}
|
||||
|
||||
bool isSet(const uInt16 address) const { return myCount[address]; }
|
||||
bool isClear(const uInt16 address) const { return myCount[address] == 0; }
|
||||
|
||||
void add(const uInt16 address) { myCount[address]++; }
|
||||
void remove(const uInt16 address) { myCount[address]--; }
|
||||
//void toggle(uInt16 address) { myCount[address] ? remove(address) : add(address); } // TODO condition
|
||||
|
||||
void initialize() {
|
||||
if(!myInitialized)
|
||||
memset(myCount, 0, sizeof(myCount));
|
||||
myInitialized = true;
|
||||
}
|
||||
void clearAll() { myInitialized = false; memset(myCount, 0, sizeof(myCount)); }
|
||||
|
||||
bool isInitialized() const { return myInitialized; }
|
||||
|
||||
private:
|
||||
// The actual counts
|
||||
uInt8 myCount[0x10000];
|
||||
|
||||
// Indicates whether we should treat this array as initialized
|
||||
bool myInitialized;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
TrapArray(const TrapArray&) = delete;
|
||||
TrapArray(TrapArray&&) = delete;
|
||||
TrapArray& operator=(const TrapArray&) = delete;
|
||||
TrapArray& operator=(TrapArray&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
30
src/debugger/gui/AmigaMouseWidget.cxx
Normal file
30
src/debugger/gui/AmigaMouseWidget.cxx
Normal file
@ -0,0 +1,30 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "AmigaMouseWidget.hxx"
|
||||
|
||||
AmigaMouseWidget::AmigaMouseWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: PointingDeviceWidget(boss, font, x, y, controller)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 AmigaMouseWidget::getGrayCodeTable(const int index, const int direction)
|
||||
{
|
||||
return myGrayCodeTable[index];
|
||||
}
|
45
src/debugger/gui/AmigaMouseWidget.hxx
Normal file
45
src/debugger/gui/AmigaMouseWidget.hxx
Normal file
@ -0,0 +1,45 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef AMIGAMOUSE_WIDGET_HXX
|
||||
#define AMIGAMOUSE_WIDGET_HXX
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "PointingDeviceWidget.hxx"
|
||||
|
||||
class AmigaMouseWidget : public PointingDeviceWidget
|
||||
{
|
||||
public:
|
||||
AmigaMouseWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
||||
Controller& controller);
|
||||
|
||||
virtual ~AmigaMouseWidget() = default;
|
||||
|
||||
private:
|
||||
uInt8 myGrayCodeTable[4] = { 0b00, 0b10, 0b11, 0b01 };
|
||||
|
||||
uInt8 getGrayCodeTable(const int index, const int direction) override;
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
AmigaMouseWidget() = delete;
|
||||
AmigaMouseWidget(const AmigaMouseWidget&) = delete;
|
||||
AmigaMouseWidget(AmigaMouseWidget&&) = delete;
|
||||
AmigaMouseWidget& operator=(const AmigaMouseWidget&) = delete;
|
||||
AmigaMouseWidget& operator=(AmigaMouseWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
30
src/debugger/gui/AtariMouseWidget.cxx
Normal file
30
src/debugger/gui/AtariMouseWidget.cxx
Normal file
@ -0,0 +1,30 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "AtariMouseWidget.hxx"
|
||||
|
||||
AtariMouseWidget::AtariMouseWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: PointingDeviceWidget(boss, font, x, y, controller)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 AtariMouseWidget::getGrayCodeTable(const int index, const int direction)
|
||||
{
|
||||
return myGrayCodeTable[index];
|
||||
}
|
45
src/debugger/gui/AtariMouseWidget.hxx
Normal file
45
src/debugger/gui/AtariMouseWidget.hxx
Normal file
@ -0,0 +1,45 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef ATARIMOUSE_WIDGET_HXX
|
||||
#define ATARIMOUSE_WIDGET_HXX
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "PointingDeviceWidget.hxx"
|
||||
|
||||
class AtariMouseWidget : public PointingDeviceWidget
|
||||
{
|
||||
public:
|
||||
AtariMouseWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
||||
Controller& controller);
|
||||
|
||||
virtual ~AtariMouseWidget() = default;
|
||||
|
||||
private:
|
||||
uInt8 myGrayCodeTable[4] = { 0b00, 0b01, 0b11, 0b10 };
|
||||
|
||||
uInt8 getGrayCodeTable(const int index, const int direction) override;
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
AtariMouseWidget() = delete;
|
||||
AtariMouseWidget(const AtariMouseWidget&) = delete;
|
||||
AtariMouseWidget(AtariMouseWidget&&) = delete;
|
||||
AtariMouseWidget& operator=(const AtariMouseWidget&) = delete;
|
||||
AtariMouseWidget& operator=(AtariMouseWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
@ -16,56 +16,28 @@
|
||||
//============================================================================
|
||||
|
||||
#include "AtariVox.hxx"
|
||||
#include "MT24LC256.hxx"
|
||||
#include "AtariVoxWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AtariVoxWidget::AtariVoxWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
: FlashWidget(boss, font, x, y, controller)
|
||||
{
|
||||
bool leftport = myController.jack() == Controller::Left;
|
||||
const string& label = leftport ? "Left (AtariVox)" : "Right (AtariVox)";
|
||||
|
||||
const int fontHeight = font.getFontHeight(),
|
||||
lineHeight = font.getLineHeight(),
|
||||
bwidth = font.getStringWidth("Erase EEPROM") + 20,
|
||||
bheight = lineHeight + 4;
|
||||
|
||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (AtariVox)");
|
||||
StaticTextWidget* t;
|
||||
|
||||
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
|
||||
fontHeight, label, kTextAlignLeft);
|
||||
|
||||
ypos += t->getHeight() + 20;
|
||||
myEEPROMErase =
|
||||
new ButtonWidget(boss, font, xpos+10, ypos, bwidth, bheight,
|
||||
"Erase EEPROM", kEEPROMErase);
|
||||
myEEPROMErase->setTarget(this);
|
||||
ypos += lineHeight + 20;
|
||||
|
||||
const GUI::Font& ifont = instance().frameBuffer().infoFont();
|
||||
lwidth = ifont.getMaxCharWidth() * 20;
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
|
||||
fontHeight, "(*) This will erase", kTextAlignLeft);
|
||||
ypos += lineHeight + 2;
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
|
||||
fontHeight, "all EEPROM data, not", kTextAlignLeft);
|
||||
ypos += lineHeight + 2;
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
|
||||
fontHeight, "just the range used", kTextAlignLeft);
|
||||
ypos += lineHeight + 2;
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
|
||||
fontHeight, "for this ROM", kTextAlignLeft);
|
||||
init(boss, font, x, y);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariVoxWidget::handleCommand(CommandSender*, int cmd, int, int)
|
||||
void AtariVoxWidget::eraseCurrent()
|
||||
{
|
||||
if(cmd == kEEPROMErase)
|
||||
{
|
||||
AtariVox& avox = static_cast<AtariVox&>(myController);
|
||||
avox.myEEPROM->erase();
|
||||
}
|
||||
AtariVox& avox = static_cast<AtariVox&>(myController);
|
||||
|
||||
avox.eraseCurrent();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool AtariVoxWidget::isPageUsed(uInt32 page)
|
||||
{
|
||||
AtariVox& avox = static_cast<AtariVox&>(myController);
|
||||
|
||||
return avox.isPageUsed(page);
|
||||
}
|
||||
|
@ -18,12 +18,10 @@
|
||||
#ifndef ATARIVOX_WIDGET_HXX
|
||||
#define ATARIVOX_WIDGET_HXX
|
||||
|
||||
class ButtonWidget;
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "ControllerWidget.hxx"
|
||||
#include "FlashWidget.hxx"
|
||||
|
||||
class AtariVoxWidget : public ControllerWidget
|
||||
class AtariVoxWidget : public FlashWidget
|
||||
{
|
||||
public:
|
||||
AtariVoxWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
||||
@ -31,12 +29,8 @@ class AtariVoxWidget : public ControllerWidget
|
||||
virtual ~AtariVoxWidget() = default;
|
||||
|
||||
private:
|
||||
ButtonWidget* myEEPROMErase;
|
||||
enum { kEEPROMErase = 'eeER' };
|
||||
|
||||
private:
|
||||
void loadConfig() override { }
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
void eraseCurrent() override;
|
||||
bool isPageUsed(uInt32 page) override;
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
AtariVoxWidget() = delete;
|
||||
|
@ -24,8 +24,7 @@ BoosterWidget::BoosterWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
{
|
||||
bool leftport = myController.jack() == Controller::Left;
|
||||
const string& label = leftport ? "Left (Booster)" : "Right (Booster)";
|
||||
const string& label = isLeftPort() ? "Left (Booster)" : "Right (Booster)";
|
||||
|
||||
const int fontHeight = font.getFontHeight();
|
||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Booster)");
|
||||
@ -34,39 +33,46 @@ BoosterWidget::BoosterWidget(GuiObject* boss, const GUI::Font& font,
|
||||
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
|
||||
fontHeight, label, kTextAlignLeft);
|
||||
xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 10;
|
||||
myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJUp]->setID(kJUp);
|
||||
myPins[kJUp]->setTarget(this);
|
||||
|
||||
ypos += myPins[kJUp]->getHeight() * 2 + 10;
|
||||
myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJDown]->setID(kJDown);
|
||||
myPins[kJDown]->setTarget(this);
|
||||
|
||||
xpos -= myPins[kJUp]->getWidth() + 5;
|
||||
ypos -= myPins[kJUp]->getHeight() + 5;
|
||||
myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJLeft]->setID(kJLeft);
|
||||
myPins[kJLeft]->setTarget(this);
|
||||
|
||||
xpos += (myPins[kJUp]->getWidth() + 5) * 2;
|
||||
myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJRight]->setID(kJRight);
|
||||
myPins[kJRight]->setTarget(this);
|
||||
|
||||
xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
|
||||
ypos = 20 + (myPins[kJUp]->getHeight() + 10) * 3;
|
||||
myPins[kJFire] = new CheckboxWidget(boss, font, xpos, ypos, "Fire", kCheckActionCmd);
|
||||
myPins[kJFire] = new CheckboxWidget(boss, font, xpos, ypos, "Fire",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJFire]->setID(kJFire);
|
||||
myPins[kJFire]->setTarget(this);
|
||||
|
||||
ypos += myPins[kJFire]->getHeight() + 5;
|
||||
myPins[kJBooster] = new CheckboxWidget(boss, font, xpos, ypos, "Booster", kCheckActionCmd);
|
||||
myPins[kJBooster] = new CheckboxWidget(boss, font, xpos, ypos, "Booster",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJBooster]->setID(kJBooster);
|
||||
myPins[kJBooster]->setTarget(this);
|
||||
|
||||
ypos += myPins[kJBooster]->getHeight() + 5;
|
||||
myPins[kJTrigger] = new CheckboxWidget(boss, font, xpos, ypos, "Trigger", kCheckActionCmd);
|
||||
myPins[kJTrigger] = new CheckboxWidget(boss, font, xpos, ypos, "Trigger",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJTrigger]->setID(kJTrigger);
|
||||
myPins[kJTrigger]->setTarget(this);
|
||||
}
|
||||
@ -90,7 +96,7 @@ void BoosterWidget::loadConfig()
|
||||
void BoosterWidget::handleCommand(
|
||||
CommandSender* sender, int cmd, int data, int id)
|
||||
{
|
||||
if(cmd == kCheckActionCmd)
|
||||
if(cmd == CheckboxWidget::kCheckActionCmd)
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ Cartridge0840Widget::Cartridge0840Widget(
|
||||
for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < 2;
|
||||
++i, offset += 0x1000, spot += 0x40)
|
||||
{
|
||||
uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset];
|
||||
uInt16 start = uInt16((cart.myImage[offset+1] << 8) | cart.myImage[offset]);
|
||||
start -= start % 0x1000;
|
||||
info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - "
|
||||
<< "$" << (start + 0xFFF) << " (hotspot = $" << spot << ")\n";
|
||||
|
@ -324,7 +324,7 @@ void CartridgeBUSWidget::loadConfig()
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.myMusicCounters[i]);
|
||||
changed.push_back(myCart.myMusicCounters[i] != (uInt32)myOldState.mcounters[i]);
|
||||
changed.push_back(myCart.myMusicCounters[i] != uInt32(myOldState.mcounters[i]));
|
||||
}
|
||||
myMusicCounters->setList(alist, vlist, changed);
|
||||
|
||||
@ -332,7 +332,7 @@ void CartridgeBUSWidget::loadConfig()
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.myMusicFrequencies[i]);
|
||||
changed.push_back(myCart.myMusicFrequencies[i] != (uInt32)myOldState.mfreqs[i]);
|
||||
changed.push_back(myCart.myMusicFrequencies[i] != uInt32(myOldState.mfreqs[i]));
|
||||
}
|
||||
myMusicFrequencies->setList(alist, vlist, changed);
|
||||
|
||||
|
@ -24,6 +24,7 @@ class ButtonWidget;
|
||||
#include "Widget.hxx"
|
||||
#include "Command.hxx"
|
||||
|
||||
|
||||
class ControllerWidget : public Widget, public CommandSender
|
||||
{
|
||||
public:
|
||||
@ -44,6 +45,19 @@ class ControllerWidget : public Widget, public CommandSender
|
||||
protected:
|
||||
Controller& myController;
|
||||
|
||||
protected:
|
||||
bool isLeftPort()
|
||||
{
|
||||
bool swappedPorts = instance().console().properties().get(Console_SwapPorts) == "YES";
|
||||
|
||||
return (myController.jack() == Controller::Left) ^ swappedPorts;
|
||||
}
|
||||
|
||||
string getHeader()
|
||||
{
|
||||
return (isLeftPort() ? "Left (" : "Right (") + myController.name() + ")";
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void handleCommand(CommandSender* sender, int cmd, int data, int id) override { }
|
||||
|
||||
|
@ -540,9 +540,9 @@ void DataGridWidget::handleCommand(CommandSender* sender, int cmd,
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case kSetPositionCmd:
|
||||
case GuiObject::kSetPositionCmd:
|
||||
// Chain access; pass to parent
|
||||
sendCommand(kSetPositionCmd, data, _id);
|
||||
sendCommand(GuiObject::kSetPositionCmd, data, _id);
|
||||
break;
|
||||
|
||||
case kDGZeroCmd:
|
||||
|
@ -92,7 +92,10 @@ void DebuggerDialog::handleKeyDown(StellaKey key, StellaMod mod)
|
||||
switch(key)
|
||||
{
|
||||
case KBDK_R:
|
||||
doRewind();
|
||||
if(!instance().eventHandler().kbdShift(mod))
|
||||
doRewind();
|
||||
else
|
||||
doUnwind();
|
||||
break;
|
||||
case KBDK_S:
|
||||
doStep();
|
||||
@ -141,6 +144,10 @@ void DebuggerDialog::handleCommand(CommandSender* sender, int cmd,
|
||||
doRewind();
|
||||
break;
|
||||
|
||||
case kDDUnwindCmd:
|
||||
doUnwind();
|
||||
break;
|
||||
|
||||
case kDDExitCmd:
|
||||
doExitDebugger();
|
||||
break;
|
||||
@ -189,6 +196,12 @@ void DebuggerDialog::doRewind()
|
||||
instance().debugger().parser().run("rewind");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doUnwind()
|
||||
{
|
||||
instance().debugger().parser().run("unwind");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DebuggerDialog::doExitDebugger()
|
||||
{
|
||||
@ -375,7 +388,7 @@ void DebuggerDialog::addRomArea()
|
||||
bwidth, bheight, "Exit", kDDExitCmd);
|
||||
|
||||
bwidth = myLFont->getStringWidth("< ") + 4;
|
||||
bheight = bheight * 5 + 4*4;
|
||||
bheight = bheight * 3 + 4 * 2;
|
||||
buttonX -= (bwidth + 5);
|
||||
buttonY = r.top + 5;
|
||||
myRewindButton =
|
||||
@ -383,6 +396,14 @@ void DebuggerDialog::addRomArea()
|
||||
bwidth, bheight, "<", kDDRewindCmd);
|
||||
myRewindButton->clearFlags(WIDGET_ENABLED);
|
||||
|
||||
buttonY += bheight + 4;
|
||||
bheight = (myLFont->getLineHeight() + 2) * 2 + 4 * 1;
|
||||
myUnwindButton =
|
||||
new ButtonWidget(this, *myLFont, buttonX, buttonY,
|
||||
bwidth, bheight, ">", kDDUnwindCmd);
|
||||
myUnwindButton->clearFlags(WIDGET_ENABLED);
|
||||
|
||||
|
||||
int xpos = buttonX - 8*myLFont->getMaxCharWidth() - 20, ypos = 20;
|
||||
DataGridOpsWidget* ops = new DataGridOpsWidget(this, *myLFont, xpos, ypos);
|
||||
|
||||
|
@ -62,6 +62,7 @@ class DebuggerDialog : public Dialog
|
||||
CartRamWidget& cartRam() const { return *myCartRam; }
|
||||
EditTextWidget& message() const { return *myMessageBox; }
|
||||
ButtonWidget& rewindButton() const { return *myRewindButton; }
|
||||
ButtonWidget& unwindButton() const { return *myUnwindButton; }
|
||||
|
||||
void showFatalMessage(const string& msg);
|
||||
|
||||
@ -75,6 +76,7 @@ class DebuggerDialog : public Dialog
|
||||
void doScanlineAdvance();
|
||||
void doAdvance();
|
||||
void doRewind();
|
||||
void doUnwind();
|
||||
void doExitDebugger();
|
||||
void doExitRom();
|
||||
|
||||
@ -96,6 +98,7 @@ class DebuggerDialog : public Dialog
|
||||
kDDAdvCmd = 'DDav',
|
||||
kDDSAdvCmd = 'DDsv',
|
||||
kDDRewindCmd = 'DDrw',
|
||||
kDDUnwindCmd = 'DDuw',
|
||||
kDDExitCmd = 'DDex',
|
||||
kDDExitFatalCmd = 'DDer'
|
||||
};
|
||||
@ -113,6 +116,7 @@ class DebuggerDialog : public Dialog
|
||||
CartRamWidget* myCartRam;
|
||||
EditTextWidget* myMessageBox;
|
||||
ButtonWidget* myRewindButton;
|
||||
ButtonWidget* myUnwindButton;
|
||||
unique_ptr<GUI::MessageBox> myFatalError;
|
||||
|
||||
unique_ptr<GUI::Font> myLFont; // used for labels
|
||||
|
@ -22,13 +22,12 @@
|
||||
DrivingWidget::DrivingWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller),
|
||||
myGreyIndex(0)
|
||||
myGrayIndex(0)
|
||||
{
|
||||
bool leftport = myController.jack() == Controller::Left;
|
||||
const string& label = leftport ? "Left (Driving)" : "Right (Driving)";
|
||||
const string& label = getHeader();
|
||||
|
||||
const int fontHeight = font.getFontHeight(),
|
||||
bwidth = font.getStringWidth("Grey code +") + 10,
|
||||
bwidth = font.getStringWidth("Gray code +") + 10,
|
||||
bheight = font.getLineHeight() + 4;
|
||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Driving)");
|
||||
StaticTextWidget* t;
|
||||
@ -37,22 +36,22 @@ DrivingWidget::DrivingWidget(GuiObject* boss, const GUI::Font& font,
|
||||
fontHeight, label, kTextAlignLeft);
|
||||
|
||||
ypos += t->getHeight() + 20;
|
||||
myGreyUp = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"Grey code +", kGreyUpCmd);
|
||||
myGreyUp->setTarget(this);
|
||||
myGrayUp = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"Gray code +", kGrayUpCmd);
|
||||
myGrayUp->setTarget(this);
|
||||
|
||||
ypos += myGreyUp->getHeight() + 5;
|
||||
myGreyDown = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"Grey code -", kGreyDownCmd);
|
||||
myGreyDown->setTarget(this);
|
||||
ypos += myGrayUp->getHeight() + 5;
|
||||
myGrayDown = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||
"Gray code -", kGrayDownCmd);
|
||||
myGrayDown->setTarget(this);
|
||||
|
||||
xpos += myGreyDown->getWidth() + 10; ypos -= 10;
|
||||
myGreyValue = new DataGridWidget(boss, font, xpos, ypos,
|
||||
xpos += myGrayDown->getWidth() + 10; ypos -= 10;
|
||||
myGrayValue = new DataGridWidget(boss, font, xpos, ypos,
|
||||
1, 1, 2, 8, Common::Base::F_16);
|
||||
myGreyValue->setTarget(this);
|
||||
myGreyValue->setEditable(false);
|
||||
myGrayValue->setTarget(this);
|
||||
myGrayValue->setEditable(false);
|
||||
|
||||
xpos = x + 30; ypos += myGreyDown->getHeight() + 20;
|
||||
xpos = x + 30; ypos += myGrayDown->getHeight() + 20;
|
||||
myFire = new CheckboxWidget(boss, font, xpos, ypos, "Fire", kFireCmd);
|
||||
myFire->setTarget(this);
|
||||
}
|
||||
@ -60,16 +59,16 @@ DrivingWidget::DrivingWidget(GuiObject* boss, const GUI::Font& font,
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void DrivingWidget::loadConfig()
|
||||
{
|
||||
uInt8 grey = 0;
|
||||
if(myController.read(Controller::One)) grey += 1;
|
||||
if(myController.read(Controller::Two)) grey += 2;
|
||||
uInt8 gray = 0;
|
||||
if(myController.read(Controller::One)) gray += 1;
|
||||
if(myController.read(Controller::Two)) gray += 2;
|
||||
|
||||
for(myGreyIndex = 0; myGreyIndex < 4; ++myGreyIndex)
|
||||
if(ourGreyTable[myGreyIndex] == grey)
|
||||
for(myGrayIndex = 0; myGrayIndex < 4; ++myGrayIndex)
|
||||
if(ourGrayTable[myGrayIndex] == gray)
|
||||
break;
|
||||
|
||||
myFire->setState(!myController.read(Controller::Six));
|
||||
myGreyValue->setList(0, grey);
|
||||
setValue();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@ -78,17 +77,17 @@ void DrivingWidget::handleCommand(
|
||||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case kGreyUpCmd:
|
||||
myGreyIndex = (myGreyIndex + 1) % 4;
|
||||
myController.set(Controller::One, (ourGreyTable[myGreyIndex] & 0x1) != 0);
|
||||
myController.set(Controller::Two, (ourGreyTable[myGreyIndex] & 0x2) != 0);
|
||||
myGreyValue->setList(0, ourGreyTable[myGreyIndex]);
|
||||
case kGrayUpCmd:
|
||||
myGrayIndex = (myGrayIndex + 1) % 4;
|
||||
myController.set(Controller::One, (ourGrayTable[myGrayIndex] & 0x1) != 0);
|
||||
myController.set(Controller::Two, (ourGrayTable[myGrayIndex] & 0x2) != 0);
|
||||
setValue();
|
||||
break;
|
||||
case kGreyDownCmd:
|
||||
myGreyIndex = myGreyIndex == 0 ? 3 : myGreyIndex - 1;
|
||||
myController.set(Controller::One, (ourGreyTable[myGreyIndex] & 0x1) != 0);
|
||||
myController.set(Controller::Two, (ourGreyTable[myGreyIndex] & 0x2) != 0);
|
||||
myGreyValue->setList(0, ourGreyTable[myGreyIndex]);
|
||||
case kGrayDownCmd:
|
||||
myGrayIndex = myGrayIndex == 0 ? 3 : myGrayIndex - 1;
|
||||
myController.set(Controller::One, (ourGrayTable[myGrayIndex] & 0x1) != 0);
|
||||
myController.set(Controller::Two, (ourGrayTable[myGrayIndex] & 0x2) != 0);
|
||||
setValue();
|
||||
break;
|
||||
case kFireCmd:
|
||||
myController.set(Controller::Six, !myFire->getState());
|
||||
@ -97,4 +96,12 @@ void DrivingWidget::handleCommand(
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 DrivingWidget::ourGreyTable[4] = { 0x03, 0x01, 0x00, 0x02 };
|
||||
void DrivingWidget::setValue()
|
||||
{
|
||||
int grayCode = ourGrayTable[myGrayIndex];
|
||||
// FIXME * 8 = a nasty hack, because the DataGridWidget does not support 2 digit binary output
|
||||
myGrayValue->setList(0, (grayCode & 0b01) + (grayCode & 0b10) * 8);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 DrivingWidget::ourGrayTable[4] = { 0x03, 0x01, 0x00, 0x02 };
|
||||
|
@ -35,22 +35,24 @@ class DrivingWidget : public ControllerWidget
|
||||
|
||||
private:
|
||||
enum {
|
||||
kGreyUpCmd = 'DWup',
|
||||
kGreyDownCmd = 'DWdn',
|
||||
kGrayUpCmd = 'DWup',
|
||||
kGrayDownCmd = 'DWdn',
|
||||
kFireCmd = 'DWfr'
|
||||
};
|
||||
ButtonWidget *myGreyUp, *myGreyDown;
|
||||
DataGridWidget* myGreyValue;
|
||||
ButtonWidget *myGrayUp, *myGrayDown;
|
||||
DataGridWidget* myGrayValue;
|
||||
CheckboxWidget* myFire;
|
||||
|
||||
int myGreyIndex;
|
||||
int myGrayIndex;
|
||||
|
||||
static uInt8 ourGreyTable[4];
|
||||
static uInt8 ourGrayTable[4];
|
||||
|
||||
private:
|
||||
void loadConfig() override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
void setValue();
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
DrivingWidget() = delete;
|
||||
DrivingWidget(const DrivingWidget&) = delete;
|
||||
|
105
src/debugger/gui/FlashWidget.cxx
Normal file
105
src/debugger/gui/FlashWidget.cxx
Normal file
@ -0,0 +1,105 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "FlashWidget.hxx"
|
||||
#include "MT24LC256.hxx"
|
||||
#include "Base.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FlashWidget::FlashWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FlashWidget::init(GuiObject* boss, const GUI::Font& font, int x, int y)
|
||||
{
|
||||
const GUI::Font& ifont = instance().frameBuffer().infoFont();
|
||||
const int lineHeight = font.getLineHeight();
|
||||
int xpos = x, ypos = y;
|
||||
|
||||
new StaticTextWidget(boss, font, xpos, ypos + 2, getHeader());
|
||||
|
||||
ypos += lineHeight + 6;
|
||||
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, "Pages/Ranges used:");
|
||||
|
||||
ypos += lineHeight + 2;
|
||||
xpos += 8;
|
||||
|
||||
for(uInt32 page = 0; page < MAX_PAGES; ++page)
|
||||
{
|
||||
myPage[page] = new StaticTextWidget(boss, ifont, xpos, ypos,
|
||||
page ? " " : "none ");
|
||||
ypos += lineHeight;
|
||||
}
|
||||
|
||||
xpos -= 8; ypos += 2;
|
||||
myEEPROMEraseCurrent = new ButtonWidget(boss, font, xpos, ypos,
|
||||
"Erase used pages", kEEPROMEraseCurrent);
|
||||
myEEPROMEraseCurrent->setTarget(this);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FlashWidget::handleCommand(CommandSender*, int cmd, int, int)
|
||||
{
|
||||
if(cmd == kEEPROMEraseCurrent) {
|
||||
eraseCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// display the pages used by the current ROM and update erase button status
|
||||
void FlashWidget::loadConfig()
|
||||
{
|
||||
int useCount = 0, startPage = -1;
|
||||
for(uInt32 page = 0; page < MT24LC256::PAGE_NUM; ++page)
|
||||
{
|
||||
if(isPageUsed(page))
|
||||
{
|
||||
if (startPage == -1)
|
||||
startPage = page;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(startPage != -1)
|
||||
{
|
||||
int from = startPage * MT24LC256::PAGE_SIZE;
|
||||
int to = page * MT24LC256::PAGE_SIZE - 1;
|
||||
ostringstream label;
|
||||
|
||||
label.str("");
|
||||
label << Common::Base::HEX3 << startPage;
|
||||
|
||||
if(int(page) - 1 != startPage)
|
||||
label << "-" << Common::Base::HEX3 << page - 1;
|
||||
else
|
||||
label << " ";
|
||||
label << ": " << Common::Base::HEX4 << from << "-" << Common::Base::HEX4 << to;
|
||||
|
||||
myPage[useCount]->setLabel(label.str());
|
||||
|
||||
startPage = -1;
|
||||
if(++useCount == MAX_PAGES)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myEEPROMEraseCurrent->setEnabled(useCount != 0);
|
||||
}
|
65
src/debugger/gui/FlashWidget.hxx
Normal file
65
src/debugger/gui/FlashWidget.hxx
Normal file
@ -0,0 +1,65 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef FLASH_WIDGET_HXX
|
||||
#define FLASH_WIDGET_HXX
|
||||
|
||||
class ButtonWidget;
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "ControllerWidget.hxx"
|
||||
|
||||
class FlashWidget : public ControllerWidget
|
||||
{
|
||||
public:
|
||||
FlashWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
||||
Controller& controller);
|
||||
virtual ~FlashWidget() = default;
|
||||
|
||||
protected:
|
||||
void init(GuiObject* boss, const GUI::Font& font, int x, int y);
|
||||
|
||||
private:
|
||||
ButtonWidget* myEEPROMEraseCurrent;
|
||||
enum { kEEPROMEraseCurrent = 'eeEC' };
|
||||
|
||||
static constexpr uInt32 MAX_PAGES = 5;
|
||||
StaticTextWidget* myPage[MAX_PAGES];
|
||||
|
||||
private:
|
||||
void loadConfig() override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
/**
|
||||
Erase the EEPROM pages used by the current ROM
|
||||
*/
|
||||
virtual void eraseCurrent() = 0;
|
||||
|
||||
/**
|
||||
Check if a page is used by the current ROM
|
||||
*/
|
||||
virtual bool isPageUsed(uInt32 page) = 0;
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
FlashWidget() = delete;
|
||||
FlashWidget(const FlashWidget&) = delete;
|
||||
FlashWidget(FlashWidget&&) = delete;
|
||||
FlashWidget& operator=(const FlashWidget&) = delete;
|
||||
FlashWidget& operator=(FlashWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
@ -24,8 +24,7 @@ GenesisWidget::GenesisWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
{
|
||||
bool leftport = myController.jack() == Controller::Left;
|
||||
const string& label = leftport ? "Left (Genesis)" : "Right (Genesis)";
|
||||
const string& label = getHeader();
|
||||
|
||||
const int fontHeight = font.getFontHeight();
|
||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Genesis)");
|
||||
@ -34,34 +33,40 @@ GenesisWidget::GenesisWidget(GuiObject* boss, const GUI::Font& font,
|
||||
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
|
||||
fontHeight, label, kTextAlignLeft);
|
||||
xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 20;
|
||||
myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJUp]->setID(kJUp);
|
||||
myPins[kJUp]->setTarget(this);
|
||||
|
||||
ypos += myPins[kJUp]->getHeight() * 2 + 10;
|
||||
myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJDown]->setID(kJDown);
|
||||
myPins[kJDown]->setTarget(this);
|
||||
|
||||
xpos -= myPins[kJUp]->getWidth() + 5;
|
||||
ypos -= myPins[kJUp]->getHeight() + 5;
|
||||
myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJLeft]->setID(kJLeft);
|
||||
myPins[kJLeft]->setTarget(this);
|
||||
|
||||
xpos += (myPins[kJUp]->getWidth() + 5) * 2;
|
||||
myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJRight]->setID(kJRight);
|
||||
myPins[kJRight]->setTarget(this);
|
||||
|
||||
xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
|
||||
ypos = 30 + (myPins[kJUp]->getHeight() + 10) * 3;
|
||||
myPins[kJBbtn] = new CheckboxWidget(boss, font, xpos, ypos, "B button", kCheckActionCmd);
|
||||
myPins[kJBbtn] = new CheckboxWidget(boss, font, xpos, ypos, "B button",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJBbtn]->setID(kJBbtn);
|
||||
myPins[kJBbtn]->setTarget(this);
|
||||
|
||||
ypos += myPins[kJBbtn]->getHeight() + 5;
|
||||
myPins[kJCbtn] = new CheckboxWidget(boss, font, xpos, ypos, "C button", kCheckActionCmd);
|
||||
myPins[kJCbtn] = new CheckboxWidget(boss, font, xpos, ypos, "C button",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJCbtn]->setID(kJCbtn);
|
||||
myPins[kJCbtn]->setTarget(this);
|
||||
}
|
||||
@ -83,7 +88,7 @@ void GenesisWidget::loadConfig()
|
||||
void GenesisWidget::handleCommand(
|
||||
CommandSender* sender, int cmd, int data, int id)
|
||||
{
|
||||
if(cmd == kCheckActionCmd)
|
||||
if(cmd == CheckboxWidget::kCheckActionCmd)
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
|
@ -24,9 +24,7 @@ JoystickWidget::JoystickWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
{
|
||||
bool leftport = myController.jack() == Controller::Left;
|
||||
const string& label = leftport ? "Left (Joystick)" : "Right (Joystick)";
|
||||
|
||||
const string& label = getHeader();
|
||||
const int fontHeight = font.getFontHeight();
|
||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Joystick)");
|
||||
StaticTextWidget* t;
|
||||
@ -34,29 +32,34 @@ JoystickWidget::JoystickWidget(GuiObject* boss, const GUI::Font& font,
|
||||
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
|
||||
fontHeight, label, kTextAlignLeft);
|
||||
xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 20;
|
||||
myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJUp]->setID(kJUp);
|
||||
myPins[kJUp]->setTarget(this);
|
||||
|
||||
ypos += myPins[kJUp]->getHeight() * 2 + 10;
|
||||
myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJDown]->setID(kJDown);
|
||||
myPins[kJDown]->setTarget(this);
|
||||
|
||||
xpos -= myPins[kJUp]->getWidth() + 5;
|
||||
ypos -= myPins[kJUp]->getHeight() + 5;
|
||||
myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJLeft]->setID(kJLeft);
|
||||
myPins[kJLeft]->setTarget(this);
|
||||
|
||||
xpos += (myPins[kJUp]->getWidth() + 5) * 2;
|
||||
myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJRight]->setID(kJRight);
|
||||
myPins[kJRight]->setTarget(this);
|
||||
|
||||
xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
|
||||
ypos = 30 + (myPins[kJUp]->getHeight() + 10) * 3;
|
||||
myPins[kJFire] = new CheckboxWidget(boss, font, xpos, ypos, "Fire", kCheckActionCmd);
|
||||
myPins[kJFire] = new CheckboxWidget(boss, font, xpos, ypos, "Fire",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myPins[kJFire]->setID(kJFire);
|
||||
myPins[kJFire]->setTarget(this);
|
||||
}
|
||||
@ -75,7 +78,7 @@ void JoystickWidget::loadConfig()
|
||||
void JoystickWidget::handleCommand(
|
||||
CommandSender* sender, int cmd, int data, int id)
|
||||
{
|
||||
if(cmd == kCheckActionCmd)
|
||||
if(cmd == CheckboxWidget::kCheckActionCmd)
|
||||
myController.set(ourPinNo[id], !myPins[id]->getState());
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ KeyboardWidget::KeyboardWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
{
|
||||
bool leftport = myController.jack() == Controller::Left;
|
||||
bool leftport = isLeftPort();
|
||||
const string& label = leftport ? "Left (Keyboard)" : "Right (Keyboard)";
|
||||
|
||||
const int fontHeight = font.getFontHeight();
|
||||
@ -38,7 +38,8 @@ KeyboardWidget::KeyboardWidget(GuiObject* boss, const GUI::Font& font,
|
||||
|
||||
for(int i = 0; i < 12; ++i)
|
||||
{
|
||||
myBox[i] = new CheckboxWidget(boss, font, xpos, ypos, "", kCheckActionCmd);
|
||||
myBox[i] = new CheckboxWidget(boss, font, xpos, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myBox[i]->setID(i);
|
||||
myBox[i]->setTarget(this);
|
||||
xpos += myBox[i]->getWidth() + 5;
|
||||
@ -63,7 +64,7 @@ void KeyboardWidget::loadConfig()
|
||||
void KeyboardWidget::handleCommand(
|
||||
CommandSender* sender, int cmd, int data, int id)
|
||||
{
|
||||
if(cmd == kCheckActionCmd)
|
||||
if(cmd == CheckboxWidget::kCheckActionCmd)
|
||||
instance().eventHandler().handleEvent(myEvent[id], myBox[id]->getState());
|
||||
}
|
||||
|
||||
|
@ -29,10 +29,8 @@ class NullControlWidget : public ControllerWidget
|
||||
Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
{
|
||||
bool leftport = controller.jack() == Controller::Left;
|
||||
ostringstream buf;
|
||||
buf << (leftport ? "Left (" : "Right (")
|
||||
<< controller.name() << "):";
|
||||
buf << getHeader();
|
||||
const int fontHeight = font.getFontHeight(),
|
||||
lineHeight = font.getLineHeight(),
|
||||
lwidth = std::max(font.getStringWidth(buf.str()),
|
||||
|
@ -25,8 +25,8 @@ PaddleWidget::PaddleWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
{
|
||||
bool leftport = myController.jack() == Controller::Left;
|
||||
const string& label = leftport ? "Left (Paddles)" : "Right (Paddles)";
|
||||
bool leftport = isLeftPort();
|
||||
const string& label = getHeader();
|
||||
|
||||
const int fontWidth = font.getMaxCharWidth(),
|
||||
fontHeight = font.getFontHeight(),
|
||||
|
141
src/debugger/gui/PointingDeviceWidget.cxx
Normal file
141
src/debugger/gui/PointingDeviceWidget.cxx
Normal file
@ -0,0 +1,141 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "PointingDevice.hxx"
|
||||
#include "DataGridWidget.hxx"
|
||||
#include "PointingDeviceWidget.hxx"
|
||||
|
||||
PointingDeviceWidget::PointingDeviceWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
{
|
||||
int ypos = y;
|
||||
int xLeft = x + 10;
|
||||
int xMid = xLeft + 30;
|
||||
int xRight = xLeft + 60;
|
||||
int xValue = xLeft + 87;
|
||||
StaticTextWidget* t;
|
||||
|
||||
t = new StaticTextWidget(boss, font, x, y + 2, getHeader());
|
||||
ypos += t->getHeight() + 8;
|
||||
|
||||
// add gray code and up widgets
|
||||
myGrayValueV = new DataGridWidget(boss, font, xMid, ypos,
|
||||
1, 1, 2, 8, Common::Base::F_16);
|
||||
myGrayValueV->setTarget(this);
|
||||
myGrayValueV->setEditable(false);
|
||||
|
||||
ypos += myGrayValueV->getHeight() + 2;
|
||||
|
||||
myGrayUp = new ButtonWidget(boss, font, xMid, ypos, 17, "+", kTBUp);
|
||||
myGrayUp->setTarget(this);
|
||||
|
||||
ypos += myGrayUp->getHeight() + 5;
|
||||
|
||||
// add horizontal direction and gray code widgets
|
||||
myGrayLeft = new ButtonWidget(boss, font, xLeft, ypos, 17, "-", kTBLeft);
|
||||
myGrayLeft->setTarget(this);
|
||||
|
||||
myGrayRight = new ButtonWidget(boss, font, xRight, ypos, 17, "+", kTBRight);
|
||||
myGrayRight->setTarget(this);
|
||||
|
||||
myGrayValueH = new DataGridWidget(boss, font, xValue, ypos + 2,
|
||||
1, 1, 2, 8, Common::Base::F_16);
|
||||
myGrayValueH->setTarget(this);
|
||||
myGrayValueH->setEditable(false);
|
||||
|
||||
ypos += myGrayLeft->getHeight() + 5;
|
||||
|
||||
// add down widget
|
||||
myGrayDown = new ButtonWidget(boss, font, xMid, ypos, 17, "-", kTBDown);
|
||||
myGrayDown->setTarget(this);
|
||||
|
||||
ypos += myGrayDown->getHeight() + 8;
|
||||
|
||||
myFire = new CheckboxWidget(boss, font, xLeft, ypos, "Fire", kTBFire);
|
||||
myFire->setTarget(this);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PointingDeviceWidget::loadConfig()
|
||||
{
|
||||
setGrayCodeH();
|
||||
setGrayCodeV();
|
||||
myFire->setState(!myController.read(Controller::Six));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PointingDeviceWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||
{
|
||||
// since the PointingDevice uses its own, internal state (not reading the controller),
|
||||
// we have to communicate directly with it
|
||||
PointingDevice& pDev = static_cast<PointingDevice&>(myController);
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case kTBLeft:
|
||||
pDev.myCountH++;
|
||||
pDev.myTrackBallLeft = false;
|
||||
setGrayCodeH();
|
||||
break;
|
||||
case kTBRight:
|
||||
pDev.myCountH--;
|
||||
pDev.myTrackBallLeft = true;
|
||||
setGrayCodeH();
|
||||
break;
|
||||
case kTBUp:
|
||||
pDev.myCountV++;
|
||||
pDev.myTrackBallDown = true;
|
||||
setGrayCodeV();
|
||||
break;
|
||||
case kTBDown:
|
||||
pDev.myCountV--;
|
||||
pDev.myTrackBallDown = false;
|
||||
setGrayCodeV();
|
||||
break;
|
||||
case kTBFire:
|
||||
myController.set(Controller::Six, !myFire->getState());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PointingDeviceWidget::setGrayCodeH()
|
||||
{
|
||||
PointingDevice& pDev = static_cast<PointingDevice&>(myController);
|
||||
|
||||
pDev.myCountH &= 0b11;
|
||||
setValue(myGrayValueH, pDev.myCountH, pDev.myTrackBallLeft);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PointingDeviceWidget::setGrayCodeV()
|
||||
{
|
||||
PointingDevice& pDev = static_cast<PointingDevice&>(myController);
|
||||
|
||||
pDev.myCountV &= 0b11;
|
||||
setValue(myGrayValueV, pDev.myCountV, !pDev.myTrackBallDown);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PointingDeviceWidget::setValue(DataGridWidget* grayValue, const int index, const int direction)
|
||||
{
|
||||
uInt8 grayCode = getGrayCodeTable(index, direction);
|
||||
|
||||
// FIXME * 8 = a nasty hack, because the DataGridWidget does not support 2 digit binary output
|
||||
grayValue->setList(0, (grayCode & 0b01) + (grayCode & 0b10) * 8);
|
||||
}
|
66
src/debugger/gui/PointingDeviceWidget.hxx
Normal file
66
src/debugger/gui/PointingDeviceWidget.hxx
Normal file
@ -0,0 +1,66 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef POINTINGDEVICE_WIDGET_HXX
|
||||
#define POINTINGDEVICE_WIDGET_HXX
|
||||
|
||||
class DataGridWidget;
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "ControllerWidget.hxx"
|
||||
|
||||
class PointingDeviceWidget : public ControllerWidget
|
||||
{
|
||||
public:
|
||||
PointingDeviceWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
||||
Controller& controller);
|
||||
|
||||
virtual ~PointingDeviceWidget() = default;
|
||||
|
||||
private:
|
||||
enum {
|
||||
kTBLeft = 'TWlf',
|
||||
kTBRight = 'TWrt',
|
||||
kTBUp = 'TWup',
|
||||
kTBDown = 'TWdn',
|
||||
kTBFire = 'TWfr'
|
||||
};
|
||||
ButtonWidget *myGrayLeft, *myGrayRight;
|
||||
DataGridWidget* myGrayValueH;
|
||||
ButtonWidget *myGrayUp, *myGrayDown;
|
||||
DataGridWidget* myGrayValueV;
|
||||
CheckboxWidget* myFire;
|
||||
|
||||
private:
|
||||
virtual uInt8 getGrayCodeTable(const int index, const int direction) = 0;
|
||||
|
||||
void loadConfig() override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
void setGrayCodeH();
|
||||
void setGrayCodeV();
|
||||
void setValue(DataGridWidget* greyValue, const int index, const int direction);
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
PointingDeviceWidget() = delete;
|
||||
PointingDeviceWidget(const PointingDeviceWidget&) = delete;
|
||||
PointingDeviceWidget(PointingDeviceWidget&&) = delete;
|
||||
PointingDeviceWidget& operator=(const PointingDeviceWidget&) = delete;
|
||||
PointingDeviceWidget& operator=(PointingDeviceWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
@ -212,13 +212,15 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
str[i] = buffer(_promptStartPos + i) & 0x7f;
|
||||
if(strchr("{*@<> ", str[i]) != NULL )
|
||||
// whitespace characters
|
||||
if(strchr("{*@<> =[]()+-/&|!^~%", str[i]))
|
||||
{
|
||||
lastDelimPos = i;
|
||||
delimiter = str[i];
|
||||
}
|
||||
}
|
||||
str[len] = '\0';
|
||||
int strLen = len - lastDelimPos - 1;
|
||||
|
||||
StringList list;
|
||||
string completionList;
|
||||
@ -226,7 +228,7 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||
|
||||
if(lastDelimPos < 0)
|
||||
{
|
||||
// no delimiters, do command completion:
|
||||
// no delimiters, do only command completion:
|
||||
const DebuggerParser& parser = instance().debugger().parser();
|
||||
parser.getCompletions(str, list);
|
||||
|
||||
@ -237,7 +239,7 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||
completionList = list[0];
|
||||
for(uInt32 i = 1; i < list.size(); ++i)
|
||||
completionList += " " + list[i];
|
||||
prefix = getCompletionPrefix(list, str);
|
||||
prefix = getCompletionPrefix(list);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -248,11 +250,15 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||
}
|
||||
else
|
||||
{
|
||||
// we got a delimiter, so this must be a label or a function
|
||||
const Debugger& dbg = instance().debugger();
|
||||
// do not show ALL labels without any filter as it makes no sense
|
||||
if(strLen > 0)
|
||||
{
|
||||
// we got a delimiter, so this must be a label or a function
|
||||
const Debugger& dbg = instance().debugger();
|
||||
|
||||
dbg.cartDebug().getCompletions(str + lastDelimPos + 1, list);
|
||||
dbg.getCompletions(str + lastDelimPos + 1, list);
|
||||
dbg.cartDebug().getCompletions(str + lastDelimPos + 1, list);
|
||||
dbg.getCompletions(str + lastDelimPos + 1, list);
|
||||
}
|
||||
}
|
||||
|
||||
if(list.size() < 1)
|
||||
@ -262,9 +268,11 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||
completionList = list[0];
|
||||
for(uInt32 i = 1; i < list.size(); ++i)
|
||||
completionList += " " + list[i];
|
||||
prefix = getCompletionPrefix(list, str + lastDelimPos + 1);
|
||||
prefix = getCompletionPrefix(list);
|
||||
}
|
||||
|
||||
// TODO: tab through list
|
||||
|
||||
if(list.size() == 1)
|
||||
{
|
||||
// add to buffer as though user typed it (plus a space)
|
||||
@ -475,7 +483,7 @@ void PromptWidget::handleCommand(CommandSender* sender, int cmd,
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case kSetPositionCmd:
|
||||
case GuiObject::kSetPositionCmd:
|
||||
int newPos = int(data) + _linesPerPage - 1 + _firstLineInBuffer;
|
||||
if (newPos != _scrollLine)
|
||||
{
|
||||
@ -501,7 +509,14 @@ void PromptWidget::loadConfig()
|
||||
print(PROMPT);
|
||||
|
||||
// Take care of one-time debugger stuff
|
||||
print(instance().debugger().autoExec());
|
||||
// fill the history from the saved breaks, traps and watches commands
|
||||
StringList history;
|
||||
print(instance().debugger().autoExec(&history));
|
||||
for(uInt32 i = 0; i < history.size(); i++)
|
||||
{
|
||||
addToHistory(history[i].c_str());
|
||||
}
|
||||
history.clear();
|
||||
print(instance().debugger().cartDebug().loadConfigFile() + "\n");
|
||||
print(instance().debugger().cartDebug().loadListFile() + "\n");
|
||||
print(instance().debugger().cartDebug().loadSymbolFile() + "\n");
|
||||
@ -697,8 +712,9 @@ void PromptWidget::historyScroll(int direction)
|
||||
|
||||
// Advance to the next line in the history
|
||||
int line = _historyLine + direction;
|
||||
if ((direction < 0 && line < 0) || (direction > 0 && line > _historySize))
|
||||
return;
|
||||
if(line < 0)
|
||||
line += _historySize + 1;
|
||||
line %= (_historySize + 1);
|
||||
|
||||
// If they press arrow-up with anything in the buffer, search backwards
|
||||
// in the history.
|
||||
@ -903,28 +919,26 @@ bool PromptWidget::saveBuffer(const FilesystemNode& file)
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string PromptWidget::getCompletionPrefix(const StringList& completions, string prefix)
|
||||
string PromptWidget::getCompletionPrefix(const StringList& completions)
|
||||
{
|
||||
// Search for prefix in every string, progressively growing it
|
||||
// Once a mismatch is found or length is past one of the strings, we're done
|
||||
// We *could* use the longest common string algorithm, but for the lengths
|
||||
// of the strings we're dealing with, it's probably not worth it
|
||||
for(;;)
|
||||
// Find the number of characters matching for each of the completions provided
|
||||
for(uInt32 len = 1;; len++)
|
||||
{
|
||||
for(const auto& s: completions)
|
||||
for(uInt32 i = 0; i < completions.size(); i++)
|
||||
{
|
||||
if(s.length() < prefix.length())
|
||||
return prefix; // current prefix is the best we're going to get
|
||||
else if(!BSPF::startsWithIgnoreCase(s, prefix))
|
||||
string s1 = completions[i];
|
||||
if(s1.length() < len)
|
||||
{
|
||||
prefix.erase(prefix.length()-1);
|
||||
return prefix;
|
||||
return s1.substr(0, len - 1);
|
||||
}
|
||||
string find = s1.substr(0, len);
|
||||
|
||||
for(uInt32 j = i + 1; j < completions.size(); j++)
|
||||
{
|
||||
if(!BSPF::startsWithIgnoreCase(completions[j], find))
|
||||
return s1.substr(0, len - 1);
|
||||
}
|
||||
}
|
||||
if(completions[0].length() > prefix.length())
|
||||
prefix = completions[0].substr(0, prefix.length() + 1);
|
||||
else
|
||||
return prefix;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,8 @@ class PromptWidget : public Widget, public CommandSender
|
||||
virtual ~PromptWidget() = default;
|
||||
|
||||
public:
|
||||
int printf(const char* format, ...);
|
||||
int vprintf(const char* format, va_list argptr);
|
||||
ATTRIBUTE_FMT_PRINTF int printf(const char* format, ...);
|
||||
ATTRIBUTE_FMT_PRINTF int vprintf(const char* format, va_list argptr);
|
||||
void print(const string& str);
|
||||
void printPrompt();
|
||||
bool saveBuffer(const FilesystemNode& file);
|
||||
@ -85,7 +85,7 @@ class PromptWidget : public Widget, public CommandSender
|
||||
|
||||
private:
|
||||
// Get the longest prefix (initially 's') that is in every string in the list
|
||||
string getCompletionPrefix(const StringList& completions, string s);
|
||||
string getCompletionPrefix(const StringList& completions);
|
||||
|
||||
private:
|
||||
enum {
|
||||
|
@ -257,7 +257,7 @@ void RamWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||
break;
|
||||
}
|
||||
|
||||
case kSetPositionCmd:
|
||||
case GuiObject::kSetPositionCmd:
|
||||
myCurrentRamBank = data;
|
||||
showSearchResults();
|
||||
fillGrid(false);
|
||||
@ -383,11 +383,11 @@ string RamWidget::doSearch(const string& str)
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string RamWidget::doCompare(const string& str)
|
||||
{
|
||||
bool comparitiveSearch = false;
|
||||
bool comparativeSearch = false;
|
||||
int searchVal = 0, offset = 0;
|
||||
|
||||
if(str.length() == 0)
|
||||
return "Enter an absolute or comparitive value";
|
||||
return "Enter an absolute or comparative value";
|
||||
|
||||
// Do some pre-processing on the string
|
||||
string::size_type pos = str.find_first_of("+-", 0);
|
||||
@ -397,11 +397,11 @@ string RamWidget::doCompare(const string& str)
|
||||
return "Input must be [+|-]NUM";
|
||||
}
|
||||
|
||||
// A comparitive search searches memory for locations that have changed by
|
||||
// A comparative search searches memory for locations that have changed by
|
||||
// the specified amount, vs. for exact values
|
||||
if(str[0] == '+' || str[0] == '-')
|
||||
{
|
||||
comparitiveSearch = true;
|
||||
comparativeSearch = true;
|
||||
bool negative = false;
|
||||
if(str[0] == '-')
|
||||
negative = true;
|
||||
@ -425,7 +425,7 @@ string RamWidget::doCompare(const string& str)
|
||||
|
||||
for(uInt32 i = 0; i < mySearchAddr.size(); ++i)
|
||||
{
|
||||
if(comparitiveSearch)
|
||||
if(comparativeSearch)
|
||||
{
|
||||
searchVal = mySearchValue[i] + offset;
|
||||
if(searchVal < 0 || searchVal > 255)
|
||||
|
@ -32,14 +32,14 @@ RiotRamWidget::RiotRamWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
uInt8 RiotRamWidget::getValue(int addr) const
|
||||
{
|
||||
const CartState& state = static_cast<const CartState&>(myDbg.getState());
|
||||
return myDbg.peek(state.rport[addr]);
|
||||
return instance().debugger().peek(state.rport[addr]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RiotRamWidget::setValue(int addr, uInt8 value)
|
||||
{
|
||||
const CartState& state = static_cast<const CartState&>(myDbg.getState());
|
||||
myDbg.poke(state.wport[addr], value);
|
||||
instance().debugger().poke(state.wport[addr], value);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -35,6 +35,9 @@
|
||||
#include "KeyboardWidget.hxx"
|
||||
#include "AtariVoxWidget.hxx"
|
||||
#include "SaveKeyWidget.hxx"
|
||||
#include "AmigaMouseWidget.hxx"
|
||||
#include "AtariMouseWidget.hxx"
|
||||
#include "TrakBallWidget.hxx"
|
||||
|
||||
#include "RiotWidget.hxx"
|
||||
|
||||
@ -82,7 +85,7 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
|
||||
// SWCHA bits in 'peek' mode
|
||||
xpos = 10; ypos += lineHeight + 5;
|
||||
CREATE_IO_REGS("SWCHA(R)", mySWCHAReadBits, 0, false);
|
||||
CREATE_IO_REGS("SWCHA(R)", mySWCHAReadBits, kSWCHARBitsID, true);
|
||||
|
||||
// SWCHB bits in 'poke' mode
|
||||
xpos = 10; ypos += 2 * lineHeight;
|
||||
@ -199,13 +202,13 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// Select and Reset
|
||||
xpos += myP0Diff->getWidth() + 20; ypos = col2_ypos + lineHeight;
|
||||
mySelect = new CheckboxWidget(boss, lfont, xpos, ypos, "Select",
|
||||
kCheckActionCmd);
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
mySelect->setID(kSelectID);
|
||||
mySelect->setTarget(this);
|
||||
addFocusWidget(mySelect);
|
||||
ypos += mySelect->getHeight() + 5;
|
||||
myReset = new CheckboxWidget(boss, lfont, xpos, ypos, "Reset",
|
||||
kCheckActionCmd);
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
myReset->setID(kResetID);
|
||||
myReset->setTarget(this);
|
||||
addFocusWidget(myReset);
|
||||
@ -219,7 +222,7 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// Randomize RAM
|
||||
xpos += 30; ypos += lineHeight + 4;
|
||||
myRandomizeRAM = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"Randomize zero-page and extended RAM", kCheckActionCmd);
|
||||
"Randomize zero-page and extended RAM", CheckboxWidget::kCheckActionCmd);
|
||||
myRandomizeRAM->setID(kRandRAMID);
|
||||
myRandomizeRAM->setTarget(this);
|
||||
addFocusWidget(myRandomizeRAM);
|
||||
@ -234,7 +237,7 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
for(int i = 0; i < 5; ++i)
|
||||
{
|
||||
myRandomizeCPU[i] = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
cpuregs[i], kCheckActionCmd);
|
||||
cpuregs[i], CheckboxWidget::kCheckActionCmd);
|
||||
myRandomizeCPU[i]->setID(kRandCPUID);
|
||||
myRandomizeCPU[i]->setTarget(this);
|
||||
addFocusWidget(myRandomizeCPU[i]);
|
||||
@ -395,10 +398,24 @@ void RiotWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||
value = Debugger::get_bits(mySWBCNTBits->getState());
|
||||
riot.swbcnt(value & 0xff);
|
||||
break;
|
||||
case kSWCHARBitsID:
|
||||
{
|
||||
// TODO: Check if there is a nicer way to do this
|
||||
value = Debugger::get_bits(mySWCHAReadBits->getState());
|
||||
riot.controller(Controller::Left).set(Controller::One, value & 0b00010000);
|
||||
riot.controller(Controller::Left).set(Controller::Two, value & 0b00100000);
|
||||
riot.controller(Controller::Left).set(Controller::Three, value & 0b01000000);
|
||||
riot.controller(Controller::Left).set(Controller::Four, value & 0b10000000);
|
||||
riot.controller(Controller::Right).set(Controller::One, value & 0b00000001);
|
||||
riot.controller(Controller::Right).set(Controller::Two, value & 0b00000010);
|
||||
riot.controller(Controller::Right).set(Controller::Three, value & 0b00000100);
|
||||
riot.controller(Controller::Right).set(Controller::Four, value & 0b00001000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kCheckActionCmd:
|
||||
case CheckboxWidget::kCheckActionCmd:
|
||||
switch(id)
|
||||
{
|
||||
case kSelectID:
|
||||
@ -436,16 +453,14 @@ ControllerWidget* RiotWidget::addControlWidget(GuiObject* boss, const GUI::Font&
|
||||
{
|
||||
switch(controller.type())
|
||||
{
|
||||
case Controller::AmigaMouse: // TODO - implement this
|
||||
return new NullControlWidget(boss, font, x, y, controller);
|
||||
case Controller::AtariMouse: // TODO - implement this
|
||||
return new NullControlWidget(boss, font, x, y, controller);
|
||||
case Controller::AmigaMouse:
|
||||
return new AmigaMouseWidget(boss, font, x, y, controller);
|
||||
case Controller::AtariMouse:
|
||||
return new AtariMouseWidget(boss, font, x, y, controller);
|
||||
case Controller::AtariVox:
|
||||
return new AtariVoxWidget(boss, font, x, y, controller);
|
||||
case Controller::BoosterGrip:
|
||||
return new BoosterWidget(boss, font, x, y, controller);
|
||||
case Controller::CompuMate: // TODO - implement this
|
||||
return new NullControlWidget(boss, font, x, y, controller);
|
||||
case Controller::Driving:
|
||||
return new DrivingWidget(boss, font, x, y, controller);
|
||||
case Controller::Genesis:
|
||||
@ -454,18 +469,16 @@ ControllerWidget* RiotWidget::addControlWidget(GuiObject* boss, const GUI::Font&
|
||||
return new JoystickWidget(boss, font, x, y, controller);
|
||||
case Controller::Keyboard:
|
||||
return new KeyboardWidget(boss, font, x, y, controller);
|
||||
case Controller::KidVid: // TODO - implement this
|
||||
return new NullControlWidget(boss, font, x, y, controller);
|
||||
case Controller::MindLink: // TODO - implement this
|
||||
return new NullControlWidget(boss, font, x, y, controller);
|
||||
// case Controller::KidVid: // TODO - implement this
|
||||
// case Controller::MindLink: // TODO - implement this
|
||||
case Controller::Paddles:
|
||||
return new PaddleWidget(boss, font, x, y, controller);
|
||||
case Controller::SaveKey:
|
||||
return new SaveKeyWidget(boss, font, x, y, controller);
|
||||
case Controller::TrakBall: // TODO - implement this
|
||||
return new NullControlWidget(boss, font, x, y, controller);
|
||||
case Controller::TrakBall:
|
||||
return new TrakBallWidget(boss, font, x, y, controller);
|
||||
default:
|
||||
return nullptr; // make compiler happy
|
||||
return new NullControlWidget(boss, font, x, y, controller);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ class RiotWidget : public Widget, public CommandSender
|
||||
kTim1TID, kTim8TID, kTim64TID, kTim1024TID, kTimWriteID,
|
||||
kSWCHABitsID, kSWACNTBitsID, kSWCHBBitsID, kSWBCNTBitsID,
|
||||
kP0DiffChanged, kP1DiffChanged, kTVTypeChanged, kSelectID, kResetID,
|
||||
kRandCPUID, kRandRAMID
|
||||
kRandCPUID, kRandRAMID, kSWCHARBitsID
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -80,7 +80,8 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
CheckboxWidget* t = nullptr;
|
||||
for(int i = 0; i < _rows; ++i)
|
||||
{
|
||||
t = new CheckboxWidget(boss, lfont, _x + 2, ypos, "", kCheckActionCmd);
|
||||
t = new CheckboxWidget(boss, lfont, _x + 2, ypos, "",
|
||||
CheckboxWidget::kCheckActionCmd);
|
||||
t->setTarget(this);
|
||||
t->setID(i);
|
||||
t->setFill(CheckboxWidget::Circle);
|
||||
@ -114,7 +115,6 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
default: // TODO - properly handle all other cases
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
setTextFilter(f);
|
||||
}
|
||||
@ -414,14 +414,14 @@ void RomListWidget::handleCommand(CommandSender* sender, int cmd, int data, int
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case kCheckActionCmd:
|
||||
case CheckboxWidget::kCheckActionCmd:
|
||||
// We let the parent class handle this
|
||||
// Pass it as a kRLBreakpointChangedCmd command, since that's the intent
|
||||
sendCommand(RomListWidget::kBPointChangedCmd, _currentPos+id,
|
||||
myCheckList[id]->getState());
|
||||
break;
|
||||
|
||||
case kSetPositionCmd:
|
||||
case GuiObject::kSetPositionCmd:
|
||||
if (_currentPos != data)
|
||||
{
|
||||
_currentPos = data;
|
||||
|
@ -16,56 +16,28 @@
|
||||
//============================================================================
|
||||
|
||||
#include "SaveKey.hxx"
|
||||
#include "MT24LC256.hxx"
|
||||
#include "SaveKeyWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
SaveKeyWidget::SaveKeyWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: ControllerWidget(boss, font, x, y, controller)
|
||||
int x, int y, Controller& controller)
|
||||
: FlashWidget(boss, font, x, y, controller)
|
||||
{
|
||||
bool leftport = myController.jack() == Controller::Left;
|
||||
const string& label = leftport ? "Left (SaveKey)" : "Right (SaveKey)";
|
||||
|
||||
const int fontHeight = font.getFontHeight(),
|
||||
lineHeight = font.getLineHeight(),
|
||||
bwidth = font.getStringWidth("Erase EEPROM") + 20,
|
||||
bheight = lineHeight + 4;
|
||||
|
||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (SaveKey)");
|
||||
StaticTextWidget* t;
|
||||
|
||||
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
|
||||
fontHeight, label, kTextAlignLeft);
|
||||
|
||||
ypos += t->getHeight() + 20;
|
||||
myEEPROMErase =
|
||||
new ButtonWidget(boss, font, xpos+10, ypos, bwidth, bheight,
|
||||
"Erase EEPROM", kEEPROMErase);
|
||||
myEEPROMErase->setTarget(this);
|
||||
ypos += lineHeight + 20;
|
||||
|
||||
const GUI::Font& ifont = instance().frameBuffer().infoFont();
|
||||
lwidth = ifont.getMaxCharWidth() * 20;
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
|
||||
fontHeight, "(*) This will erase", kTextAlignLeft);
|
||||
ypos += lineHeight + 2;
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
|
||||
fontHeight, "all EEPROM data, not", kTextAlignLeft);
|
||||
ypos += lineHeight + 2;
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
|
||||
fontHeight, "just the range used", kTextAlignLeft);
|
||||
ypos += lineHeight + 2;
|
||||
new StaticTextWidget(boss, ifont, xpos, ypos, lwidth,
|
||||
fontHeight, "for this ROM", kTextAlignLeft);
|
||||
init(boss, font, x, y);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void SaveKeyWidget::handleCommand(CommandSender*, int cmd, int, int)
|
||||
void SaveKeyWidget::eraseCurrent()
|
||||
{
|
||||
if(cmd == kEEPROMErase)
|
||||
{
|
||||
SaveKey& skey = static_cast<SaveKey&>(myController);
|
||||
skey.myEEPROM->erase();
|
||||
}
|
||||
SaveKey& skey = static_cast<SaveKey&>(myController);
|
||||
|
||||
skey.eraseCurrent();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool SaveKeyWidget::isPageUsed(uInt32 page)
|
||||
{
|
||||
SaveKey& skey = static_cast<SaveKey&>(myController);
|
||||
|
||||
return skey.isPageUsed(page);
|
||||
}
|
||||
|
@ -18,12 +18,10 @@
|
||||
#ifndef SAVEKEY_WIDGET_HXX
|
||||
#define SAVEKEY_WIDGET_HXX
|
||||
|
||||
class ButtonWidget;
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "ControllerWidget.hxx"
|
||||
#include "FlashWidget.hxx"
|
||||
|
||||
class SaveKeyWidget : public ControllerWidget
|
||||
class SaveKeyWidget : public FlashWidget
|
||||
{
|
||||
public:
|
||||
SaveKeyWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
||||
@ -31,12 +29,8 @@ class SaveKeyWidget : public ControllerWidget
|
||||
virtual ~SaveKeyWidget() = default;
|
||||
|
||||
private:
|
||||
ButtonWidget* myEEPROMErase;
|
||||
enum { kEEPROMErase = 'eeER' };
|
||||
|
||||
private:
|
||||
void loadConfig() override { }
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
void eraseCurrent() override;
|
||||
bool isPageUsed(uInt32 page) override;
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
SaveKeyWidget() = delete;
|
||||
|
@ -202,7 +202,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// P0 reflect
|
||||
xpos += myHMP0->getWidth() + 15;
|
||||
myRefP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"Reflect", kCheckActionCmd);
|
||||
"Reflect", CheckboxWidget::kCheckActionCmd);
|
||||
myRefP0->setTarget(this);
|
||||
myRefP0->setID(kRefP0ID);
|
||||
addFocusWidget(myRefP0);
|
||||
@ -226,7 +226,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// P0 delay
|
||||
xpos += myGRP0Old->getWidth() + 12;
|
||||
myDelP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"VDel", kCheckActionCmd);
|
||||
"VDel", CheckboxWidget::kCheckActionCmd);
|
||||
myDelP0->setTarget(this);
|
||||
myDelP0->setID(kDelP0ID);
|
||||
addFocusWidget(myDelP0);
|
||||
@ -287,7 +287,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// P1 reflect
|
||||
xpos += myHMP1->getWidth() + 15;
|
||||
myRefP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"Reflect", kCheckActionCmd);
|
||||
"Reflect", CheckboxWidget::kCheckActionCmd);
|
||||
myRefP1->setTarget(this);
|
||||
myRefP1->setID(kRefP1ID);
|
||||
addFocusWidget(myRefP1);
|
||||
@ -310,7 +310,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// P1 delay
|
||||
xpos += myGRP1Old->getWidth() + 12;
|
||||
myDelP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"VDel", kCheckActionCmd);
|
||||
"VDel", CheckboxWidget::kCheckActionCmd);
|
||||
myDelP1->setTarget(this);
|
||||
myDelP1->setID(kDelP1ID);
|
||||
addFocusWidget(myDelP1);
|
||||
@ -382,7 +382,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// M0 reset to player 0
|
||||
xpos += myNusizM0->getWidth() + 15;
|
||||
myResMP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"Reset to P0", kCheckActionCmd);
|
||||
"Reset to P0", CheckboxWidget::kCheckActionCmd);
|
||||
myResMP0->setTarget(this);
|
||||
myResMP0->setID(kResMP0ID);
|
||||
addFocusWidget(myResMP0);
|
||||
@ -445,7 +445,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// M1 reset to player 0
|
||||
xpos += myNusizM1->getWidth() + 15;
|
||||
myResMP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"Reset to P1", kCheckActionCmd);
|
||||
"Reset to P1", CheckboxWidget::kCheckActionCmd);
|
||||
myResMP1->setTarget(this);
|
||||
myResMP1->setID(kResMP1ID);
|
||||
addFocusWidget(myResMP1);
|
||||
@ -523,7 +523,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// Ball delay
|
||||
xpos += myEnaBLOld->getWidth() + 12;
|
||||
myDelBL = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"VDel", kCheckActionCmd);
|
||||
"VDel", CheckboxWidget::kCheckActionCmd);
|
||||
myDelBL->setTarget(this);
|
||||
myDelBL->setID(kDelBLID);
|
||||
addFocusWidget(myDelBL);
|
||||
@ -561,7 +561,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
addFocusWidget(myPF[2]);
|
||||
|
||||
// PFx bit labels
|
||||
auto start = [&](int w) { return (w - sfWidth) / 2; };
|
||||
auto start = [&](int sw) { return (sw - sfWidth) / 2; };
|
||||
int colw = myPF[0]->getWidth() / 4;
|
||||
xpos = 10 + 2*fontWidth + 5 + start(colw);
|
||||
int _ypos = ypos - sfHeight;
|
||||
@ -590,21 +590,21 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
// PF reflect, score, priority
|
||||
xpos = 10 + 4*fontWidth; ypos += lineHeight + 6;
|
||||
myRefPF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"Reflect", kCheckActionCmd);
|
||||
"Reflect", CheckboxWidget::kCheckActionCmd);
|
||||
myRefPF->setTarget(this);
|
||||
myRefPF->setID(kRefPFID);
|
||||
addFocusWidget(myRefPF);
|
||||
|
||||
xpos += myRefPF->getWidth() + 15;
|
||||
myScorePF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"Score", kCheckActionCmd);
|
||||
"Score", CheckboxWidget::kCheckActionCmd);
|
||||
myScorePF->setTarget(this);
|
||||
myScorePF->setID(kScorePFID);
|
||||
addFocusWidget(myScorePF);
|
||||
|
||||
xpos += myScorePF->getWidth() + 15;
|
||||
myPriorityPF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||
"Priority", kCheckActionCmd);
|
||||
"Priority", CheckboxWidget::kCheckActionCmd);
|
||||
myPriorityPF->setTarget(this);
|
||||
myPriorityPF->setID(kPriorityPFID);
|
||||
addFocusWidget(myPriorityPF);
|
||||
@ -833,7 +833,7 @@ void TiaWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||
}
|
||||
break;
|
||||
|
||||
case kCheckActionCmd:
|
||||
case CheckboxWidget::kCheckActionCmd:
|
||||
switch(id)
|
||||
{
|
||||
case kRefP0ID:
|
||||
|
@ -202,7 +202,7 @@ void ToggleWidget::handleCommand(CommandSender* sender, int cmd,
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case kSetPositionCmd:
|
||||
case GuiObject::kSetPositionCmd:
|
||||
if (_selectedItem != data)
|
||||
{
|
||||
_selectedItem = data;
|
||||
|
30
src/debugger/gui/TrakBallWidget.cxx
Normal file
30
src/debugger/gui/TrakBallWidget.cxx
Normal file
@ -0,0 +1,30 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "TrakBallWidget.hxx"
|
||||
|
||||
TrakBallWidget::TrakBallWidget(GuiObject* boss, const GUI::Font& font,
|
||||
int x, int y, Controller& controller)
|
||||
: PointingDeviceWidget(boss, font, x, y, controller)
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 TrakBallWidget::getGrayCodeTable(const int index, const int direction)
|
||||
{
|
||||
return myGrayCodeTable[(index & 0b1) + direction * 2];
|
||||
}
|
45
src/debugger/gui/TrakBallWidget.hxx
Normal file
45
src/debugger/gui/TrakBallWidget.hxx
Normal file
@ -0,0 +1,45 @@
|
||||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2017 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef TRAKBALL_WIDGET_HXX
|
||||
#define TRAKBALL_WIDGET_HXX
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "PointingDeviceWidget.hxx"
|
||||
|
||||
class TrakBallWidget : public PointingDeviceWidget
|
||||
{
|
||||
public:
|
||||
TrakBallWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
||||
Controller& controller);
|
||||
|
||||
virtual ~TrakBallWidget() = default;
|
||||
|
||||
private:
|
||||
uInt8 myGrayCodeTable[4] = { 0b00, 0b10, 0b01, 0b11 };
|
||||
|
||||
uInt8 getGrayCodeTable(const int index, const int direction) override;
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
TrakBallWidget() = delete;
|
||||
TrakBallWidget(const TrakBallWidget&) = delete;
|
||||
TrakBallWidget(TrakBallWidget&&) = delete;
|
||||
TrakBallWidget& operator=(const TrakBallWidget&) = delete;
|
||||
TrakBallWidget& operator=(TrakBallWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,76 +1,81 @@
|
||||
MODULE := src/debugger/gui
|
||||
|
||||
MODULE_OBJS := \
|
||||
src/debugger/gui/AmigaMouseWidget.o \
|
||||
src/debugger/gui/AtariMouseWidget.o \
|
||||
src/debugger/gui/AtariVoxWidget.o \
|
||||
src/debugger/gui/AudioWidget.o \
|
||||
src/debugger/gui/CpuWidget.o \
|
||||
src/debugger/gui/PromptWidget.o \
|
||||
src/debugger/gui/RamWidget.o \
|
||||
src/debugger/gui/RiotWidget.o \
|
||||
src/debugger/gui/RiotRamWidget.o \
|
||||
src/debugger/gui/RomWidget.o \
|
||||
src/debugger/gui/RomListWidget.o \
|
||||
src/debugger/gui/RomListSettings.o \
|
||||
src/debugger/gui/TiaWidget.o \
|
||||
src/debugger/gui/TiaInfoWidget.o \
|
||||
src/debugger/gui/TiaOutputWidget.o \
|
||||
src/debugger/gui/TiaZoomWidget.o \
|
||||
src/debugger/gui/DataGridOpsWidget.o \
|
||||
src/debugger/gui/DataGridWidget.o \
|
||||
src/debugger/gui/DebuggerDialog.o \
|
||||
src/debugger/gui/ToggleBitWidget.o \
|
||||
src/debugger/gui/TogglePixelWidget.o \
|
||||
src/debugger/gui/ToggleWidget.o \
|
||||
src/debugger/gui/CartRamWidget.o \
|
||||
src/debugger/gui/BoosterWidget.o \
|
||||
src/debugger/gui/Cart0840Widget.o \
|
||||
src/debugger/gui/Cart2KWidget.o \
|
||||
src/debugger/gui/Cart3EWidget.o \
|
||||
src/debugger/gui/Cart3EPlusWidget.o \
|
||||
src/debugger/gui/Cart3EWidget.o \
|
||||
src/debugger/gui/Cart3FWidget.o \
|
||||
src/debugger/gui/Cart4A50Widget.o \
|
||||
src/debugger/gui/Cart4KWidget.o \
|
||||
src/debugger/gui/Cart4KSCWidget.o \
|
||||
src/debugger/gui/Cart4KWidget.o \
|
||||
src/debugger/gui/CartARWidget.o \
|
||||
src/debugger/gui/CartBFSCWidget.o \
|
||||
src/debugger/gui/CartBFWidget.o \
|
||||
src/debugger/gui/CartBUSWidget.o \
|
||||
src/debugger/gui/CartCDFWidget.o \
|
||||
src/debugger/gui/CartCMWidget.o \
|
||||
src/debugger/gui/CartCTYWidget.o \
|
||||
src/debugger/gui/CartCVWidget.o \
|
||||
src/debugger/gui/CartCVPlusWidget.o \
|
||||
src/debugger/gui/CartCVWidget.o \
|
||||
src/debugger/gui/CartDASHWidget.o \
|
||||
src/debugger/gui/CartDPCWidget.o \
|
||||
src/debugger/gui/CartDFSCWidget.o \
|
||||
src/debugger/gui/CartDFWidget.o \
|
||||
src/debugger/gui/CartDPCPlusWidget.o \
|
||||
src/debugger/gui/CartDPCWidget.o \
|
||||
src/debugger/gui/CartE0Widget.o \
|
||||
src/debugger/gui/CartE7Widget.o \
|
||||
src/debugger/gui/CartEFWidget.o \
|
||||
src/debugger/gui/CartEFSCWidget.o \
|
||||
src/debugger/gui/CartBFWidget.o \
|
||||
src/debugger/gui/CartBFSCWidget.o \
|
||||
src/debugger/gui/CartDFWidget.o \
|
||||
src/debugger/gui/CartDFSCWidget.o \
|
||||
src/debugger/gui/CartEFWidget.o \
|
||||
src/debugger/gui/CartF0Widget.o \
|
||||
src/debugger/gui/CartF4Widget.o \
|
||||
src/debugger/gui/CartF6Widget.o \
|
||||
src/debugger/gui/CartF8Widget.o \
|
||||
src/debugger/gui/CartF4SCWidget.o \
|
||||
src/debugger/gui/CartF4Widget.o \
|
||||
src/debugger/gui/CartF6SCWidget.o \
|
||||
src/debugger/gui/CartF6Widget.o \
|
||||
src/debugger/gui/CartF8SCWidget.o \
|
||||
src/debugger/gui/CartFAWidget.o \
|
||||
src/debugger/gui/CartF8Widget.o \
|
||||
src/debugger/gui/CartFA2Widget.o \
|
||||
src/debugger/gui/CartFAWidget.o \
|
||||
src/debugger/gui/CartFEWidget.o \
|
||||
src/debugger/gui/CartMDMWidget.o \
|
||||
src/debugger/gui/CartRamWidget.o \
|
||||
src/debugger/gui/CartSBWidget.o \
|
||||
src/debugger/gui/CartUAWidget.o \
|
||||
src/debugger/gui/CartWDWidget.o \
|
||||
src/debugger/gui/CartX07Widget.o \
|
||||
src/debugger/gui/JoystickWidget.o \
|
||||
src/debugger/gui/PaddleWidget.o \
|
||||
src/debugger/gui/BoosterWidget.o \
|
||||
src/debugger/gui/CpuWidget.o \
|
||||
src/debugger/gui/DataGridOpsWidget.o \
|
||||
src/debugger/gui/DataGridWidget.o \
|
||||
src/debugger/gui/DebuggerDialog.o \
|
||||
src/debugger/gui/DelayQueueWidget.o \
|
||||
src/debugger/gui/DrivingWidget.o \
|
||||
src/debugger/gui/KeyboardWidget.o \
|
||||
src/debugger/gui/FlashWidget.o \
|
||||
src/debugger/gui/GenesisWidget.o \
|
||||
src/debugger/gui/AtariVoxWidget.o \
|
||||
src/debugger/gui/JoystickWidget.o \
|
||||
src/debugger/gui/KeyboardWidget.o \
|
||||
src/debugger/gui/PaddleWidget.o \
|
||||
src/debugger/gui/PointingDeviceWidget.o \
|
||||
src/debugger/gui/PromptWidget.o \
|
||||
src/debugger/gui/RamWidget.o \
|
||||
src/debugger/gui/RiotRamWidget.o \
|
||||
src/debugger/gui/RiotWidget.o \
|
||||
src/debugger/gui/RomListSettings.o \
|
||||
src/debugger/gui/RomListWidget.o \
|
||||
src/debugger/gui/RomWidget.o \
|
||||
src/debugger/gui/SaveKeyWidget.o \
|
||||
src/debugger/gui/DelayQueueWidget.o
|
||||
src/debugger/gui/TiaInfoWidget.o \
|
||||
src/debugger/gui/TiaOutputWidget.o \
|
||||
src/debugger/gui/TiaWidget.o \
|
||||
src/debugger/gui/TiaZoomWidget.o \
|
||||
src/debugger/gui/ToggleBitWidget.o \
|
||||
src/debugger/gui/TogglePixelWidget.o \
|
||||
src/debugger/gui/ToggleWidget.o \
|
||||
src/debugger/gui/TrakBallWidget.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
src/debugger/gui
|
||||
|
@ -38,8 +38,8 @@ class AmigaMouse : public PointingDevice
|
||||
protected:
|
||||
uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
|
||||
{
|
||||
static constexpr uInt32 ourTableH[4] = { 0x00, 0x80, 0xa0, 0x20 };
|
||||
static constexpr uInt32 ourTableV[4] = { 0x00, 0x10, 0x50, 0x40 };
|
||||
static constexpr uInt32 ourTableH[4] = { 0b0000, 0b1000, 0b1010, 0b0010 };
|
||||
static constexpr uInt32 ourTableV[4] = { 0b0000, 0b0100, 0b0101, 0b0001 };
|
||||
|
||||
return ourTableH[countH] | ourTableV[countV];
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ class AtariMouse : public PointingDevice
|
||||
protected:
|
||||
uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
|
||||
{
|
||||
static constexpr uInt32 ourTableH[4] = { 0x00, 0x10, 0x30, 0x20 };
|
||||
static constexpr uInt32 ourTableV[4] = { 0x00, 0x80, 0xc0, 0x40 };
|
||||
static constexpr uInt32 ourTableH[4] = { 0b0000, 0b0001, 0b0011, 0b0010 };
|
||||
static constexpr uInt32 ourTableV[4] = { 0b0000, 0b0100, 0b1100, 0b1000 };
|
||||
|
||||
return ourTableH[countH] | ourTableV[countV];
|
||||
}
|
||||
|
@ -15,7 +15,6 @@
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#include "MT24LC256.hxx"
|
||||
#include "SerialPort.hxx"
|
||||
#include "System.hxx"
|
||||
#include "AtariVox.hxx"
|
||||
@ -24,7 +23,7 @@
|
||||
AtariVox::AtariVox(Jack jack, const Event& event, const System& system,
|
||||
const SerialPort& port, const string& portname,
|
||||
const string& eepromfile)
|
||||
: Controller(jack, event, system, Controller::AtariVox),
|
||||
: SaveKey(jack, event, system, eepromfile, Controller::AtariVox),
|
||||
mySerialPort(const_cast<SerialPort&>(port)),
|
||||
myShiftCount(0),
|
||||
myShiftRegister(0),
|
||||
@ -35,9 +34,6 @@ AtariVox::AtariVox(Jack jack, const Event& event, const System& system,
|
||||
else
|
||||
myAboutString = " (invalid serial port \'" + portname + "\')";
|
||||
|
||||
myEEPROM = make_unique<MT24LC256>(eepromfile, system);
|
||||
|
||||
myDigitalPinState[One] = myDigitalPinState[Two] =
|
||||
myDigitalPinState[Three] = myDigitalPinState[Four] = true;
|
||||
}
|
||||
|
||||
@ -54,13 +50,8 @@ bool AtariVox::read(DigitalPin pin)
|
||||
// For now, we just assume the device is always ready
|
||||
return myDigitalPinState[Two] = true;
|
||||
|
||||
// Pin 3: EEPROM SDA
|
||||
// input data from the 24LC256 EEPROM using the I2C protocol
|
||||
case Three:
|
||||
return myDigitalPinState[Three] = myEEPROM->readSDA();
|
||||
|
||||
default:
|
||||
return Controller::read(pin);
|
||||
return SaveKey::read(pin);
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,22 +68,8 @@ void AtariVox::write(DigitalPin pin, bool value)
|
||||
clockDataIn(value);
|
||||
break;
|
||||
|
||||
// Pin 3: EEPROM SDA
|
||||
// output data to the 24LC256 EEPROM using the I2C protocol
|
||||
case Three:
|
||||
myDigitalPinState[Three] = value;
|
||||
myEEPROM->writeSDA(value);
|
||||
break;
|
||||
|
||||
// Pin 4: EEPROM SCL
|
||||
// output clock data to the 24LC256 EEPROM using the I2C protocol
|
||||
case Four:
|
||||
myDigitalPinState[Four] = value;
|
||||
myEEPROM->writeSCL(value);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
SaveKey::write(pin, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,18 +118,5 @@ void AtariVox::clockDataIn(bool value)
|
||||
void AtariVox::reset()
|
||||
{
|
||||
myLastDataWriteCycle = 0;
|
||||
myEEPROM->systemReset();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void AtariVox::close()
|
||||
{
|
||||
// Force the EEPROM object to cleanup
|
||||
myEEPROM.reset();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string AtariVox::about() const
|
||||
{
|
||||
return Controller::about() + myAboutString;
|
||||
SaveKey::reset();
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
class SerialPort;
|
||||
|
||||
#include "Control.hxx"
|
||||
#include "SaveKey.hxx"
|
||||
#include "MT24LC256.hxx"
|
||||
|
||||
/**
|
||||
@ -32,10 +33,8 @@ class SerialPort;
|
||||
|
||||
@author B. Watson
|
||||
*/
|
||||
class AtariVox : public Controller
|
||||
class AtariVox : public SaveKey
|
||||
{
|
||||
friend class AtariVoxWidget;
|
||||
|
||||
public:
|
||||
/**
|
||||
Create a new AtariVox controller plugged into the specified jack
|
||||
@ -86,18 +85,10 @@ class AtariVox : public Controller
|
||||
*/
|
||||
void reset() override;
|
||||
|
||||
/**
|
||||
Notification method invoked by the system indicating that the
|
||||
console is about to be destroyed. It may be necessary to override
|
||||
this method for controllers that need cleanup before exiting.
|
||||
*/
|
||||
void close() override;
|
||||
|
||||
string about() const override;
|
||||
string about(bool swappedPorts) const override { return Controller::about(swappedPorts) + myAboutString; }
|
||||
|
||||
private:
|
||||
void clockDataIn(bool value);
|
||||
void shiftIn(bool value);
|
||||
|
||||
private:
|
||||
// Instance of an real serial port on the system
|
||||
@ -105,9 +96,6 @@ class AtariVox : public Controller
|
||||
// bytes directly to it
|
||||
SerialPort& mySerialPort;
|
||||
|
||||
// The EEPROM used in the AtariVox
|
||||
unique_ptr<MT24LC256> myEEPROM;
|
||||
|
||||
// How many bits have been shifted into the shift register?
|
||||
uInt8 myShiftCount;
|
||||
|
||||
|
@ -178,7 +178,7 @@ bool Cartridge3E::bank(uInt16 bank)
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
|
||||
access.directPeekBase = 0;
|
||||
access.directPeekBase = nullptr;
|
||||
access.type = System::PA_WRITE;
|
||||
|
||||
// Map write-port RAM image into the system
|
||||
|
@ -152,12 +152,17 @@ class Cartridge4A50 : public Cartridge
|
||||
|
||||
private:
|
||||
/**
|
||||
Query/change the given address type to use the given disassembly flags
|
||||
Query the given address type for the associated disassembly flags.
|
||||
|
||||
@param address The address to modify
|
||||
@param flags A bitfield of DisasmType directives for the given address
|
||||
@param address The address to query
|
||||
*/
|
||||
uInt8 getAccessFlags(uInt16 address) const override;
|
||||
/**
|
||||
Change the given address to use the given disassembly flags.
|
||||
|
||||
@param address The address to modify
|
||||
@param flags A bitfield of DisasmType directives for the given address
|
||||
*/
|
||||
void setAccessFlags(uInt16 address, uInt8 flags) override;
|
||||
|
||||
/**
|
||||
|
@ -53,7 +53,7 @@ void Cartridge4KSC::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -156,12 +156,17 @@ class CartridgeAR : public Cartridge
|
||||
|
||||
private:
|
||||
/**
|
||||
Query/change the given address type to use the given disassembly flags
|
||||
Query the given address type for the associated disassembly flags.
|
||||
|
||||
@param address The address to modify
|
||||
@param flags A bitfield of DisasmType directives for the given address
|
||||
@param address The address to query
|
||||
*/
|
||||
uInt8 getAccessFlags(uInt16 address) const override;
|
||||
/**
|
||||
Change the given address to use the given disassembly flags.
|
||||
|
||||
@param address The address to modify
|
||||
@param flags A bitfield of DisasmType directives for the given address
|
||||
*/
|
||||
void setAccessFlags(uInt16 address, uInt8 flags) override;
|
||||
|
||||
// Handle a change to the bank configuration
|
||||
|
@ -58,7 +58,7 @@ void CartridgeBFSC::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -65,7 +65,8 @@ CartridgeBUS::CartridgeBUS(const BytePtr& image, uInt32 size,
|
||||
|
||||
#ifdef THUMB_SUPPORT
|
||||
// Create Thumbulator ARM emulator
|
||||
myThumbEmulator = make_unique<Thumbulator>((uInt16*)myImage, (uInt16*)myBUSRAM,
|
||||
myThumbEmulator = make_unique<Thumbulator>(
|
||||
reinterpret_cast<uInt16*>(myImage), reinterpret_cast<uInt16*>(myBUSRAM),
|
||||
settings.getBool("thumb.trapfatal"), Thumbulator::ConfigureFor::BUS, this);
|
||||
#endif
|
||||
setInitialState();
|
||||
@ -528,7 +529,6 @@ uInt32 CartridgeBUS::thumbCallback(uInt8 function, uInt32 value1, uInt32 value2)
|
||||
// _GetWavePtr - return the counter
|
||||
case 2:
|
||||
return myMusicCounters[value1];
|
||||
break;
|
||||
|
||||
// _SetWaveSize - set size of waveform buffer
|
||||
case 3:
|
||||
|
@ -69,9 +69,9 @@ CartridgeCDF::CartridgeCDF(const BytePtr& image, uInt32 size,
|
||||
#ifdef THUMB_SUPPORT
|
||||
// Create Thumbulator ARM emulator
|
||||
myThumbEmulator = make_unique<Thumbulator>(
|
||||
(uInt16*)myImage, (uInt16*)myCDFRAM, settings.getBool("thumb.trapfatal"),
|
||||
myVersion ? Thumbulator::ConfigureFor::CDF1 : Thumbulator::ConfigureFor::CDF,
|
||||
this);
|
||||
reinterpret_cast<uInt16*>(myImage), reinterpret_cast<uInt16*>(myCDFRAM),
|
||||
settings.getBool("thumb.trapfatal"), myVersion ?
|
||||
Thumbulator::ConfigureFor::CDF1 : Thumbulator::ConfigureFor::CDF, this);
|
||||
#endif
|
||||
setInitialState();
|
||||
}
|
||||
@ -465,7 +465,6 @@ uInt32 CartridgeCDF::thumbCallback(uInt8 function, uInt32 value1, uInt32 value2)
|
||||
// _GetWavePtr - return the counter
|
||||
case 2:
|
||||
return myMusicCounters[value1];
|
||||
break;
|
||||
|
||||
// _SetWaveSize - set size of waveform buffer
|
||||
case 3:
|
||||
|
@ -143,7 +143,7 @@ bool CartridgeCM::bank(uInt16 bank)
|
||||
if((mySWCHA & 0x30) == 0x20)
|
||||
access.directPokeBase = &myRAM[addr & 0x7FF];
|
||||
else
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
|
||||
mySystem->setPageAccess(addr, access);
|
||||
}
|
||||
|
@ -74,8 +74,8 @@ void CartridgeCV::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM writing pages
|
||||
access.directPeekBase = 0;
|
||||
access.codeAccessBase = 0;
|
||||
access.directPeekBase = nullptr;
|
||||
access.codeAccessBase = nullptr;
|
||||
access.type = System::PA_WRITE;
|
||||
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
|
||||
{
|
||||
@ -84,7 +84,7 @@ void CartridgeCV::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -58,8 +58,8 @@ void CartridgeCVPlus::install(System& system)
|
||||
mySystem->setPageAccess(addr, access);
|
||||
|
||||
// Set the page accessing method for the RAM writing pages
|
||||
access.directPeekBase = 0;
|
||||
access.codeAccessBase = 0;
|
||||
access.directPeekBase = nullptr;
|
||||
access.codeAccessBase = nullptr;
|
||||
access.type = System::PA_WRITE;
|
||||
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
|
||||
{
|
||||
@ -69,7 +69,7 @@ void CartridgeCVPlus::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ void CartridgeDFSC::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -57,7 +57,7 @@ void CartridgeE0::install(System& system)
|
||||
myCurrentSlice[3] = 7;
|
||||
|
||||
// Set the page accessing methods for the hot spots in the last segment
|
||||
access.directPeekBase = 0;
|
||||
access.directPeekBase = nullptr;
|
||||
access.codeAccessBase = &myCodeAccessBase[8128];
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
|
||||
|
@ -162,7 +162,7 @@ void CartridgeE7::bankRAM(uInt16 bank)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the 256 bytes of RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1900; addr < 0x1A00; addr += System::PAGE_SIZE)
|
||||
{
|
||||
@ -208,7 +208,7 @@ bool CartridgeE7::bank(uInt16 slice)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the 1K slice of RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ void CartridgeEFSC::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ void CartridgeF4SC::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ void CartridgeF6SC::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ void CartridgeF8SC::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ void CartridgeFA::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ void CartridgeFA2::install(System& system)
|
||||
}
|
||||
|
||||
// Set the page accessing method for the RAM reading pages
|
||||
access.directPokeBase = 0;
|
||||
access.directPokeBase = nullptr;
|
||||
access.type = System::PA_READ;
|
||||
for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE)
|
||||
{
|
||||
|
@ -132,8 +132,6 @@ uInt8 CartridgeWD::peek(uInt16 address)
|
||||
else
|
||||
return mySegment3[address & 0x03FF];
|
||||
}
|
||||
|
||||
return 0; // Make the compiler happy; we'll never reach this
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -61,7 +61,6 @@ void CompuMate::update()
|
||||
Controller& lp = myConsole.leftController();
|
||||
Controller& rp = myConsole.rightController();
|
||||
|
||||
|
||||
lp.myAnalogPinValue[Controller::Nine] = Controller::maximumResistance;
|
||||
lp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance;
|
||||
lp.myDigitalPinState[Controller::Six] = true;
|
||||
|
@ -109,8 +109,6 @@ class CompuMate
|
||||
Called after *all* digital pins have been written on Port A.
|
||||
Only update on the left controller; the right controller will
|
||||
happen at the same cycle and is redundant.
|
||||
|
||||
@param value The entire contents of the SWCHA register
|
||||
*/
|
||||
void controlWrite(uInt8) override {
|
||||
if(myJack == Controller::Left) myHandler.update();
|
||||
|
@ -189,8 +189,9 @@ Console::Console(OSystem& osystem, unique_ptr<Cartridge>& cart,
|
||||
// Finally, add remaining info about the console
|
||||
myConsoleInfo.CartName = myProperties.get(Cartridge_Name);
|
||||
myConsoleInfo.CartMD5 = myProperties.get(Cartridge_MD5);
|
||||
myConsoleInfo.Control0 = myLeftControl->about();
|
||||
myConsoleInfo.Control1 = myRightControl->about();
|
||||
bool swappedPorts = properties().get(Console_SwapPorts) == "YES";
|
||||
myConsoleInfo.Control0 = myLeftControl->about(swappedPorts);
|
||||
myConsoleInfo.Control1 = myRightControl->about(swappedPorts);
|
||||
myConsoleInfo.BankSwitch = myCart->about();
|
||||
|
||||
myCart->setRomName(myConsoleInfo.CartName);
|
||||
@ -724,13 +725,9 @@ void Console::setTIAProperties()
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Console::setControllers(const string& rommd5)
|
||||
{
|
||||
// Setup the controllers based on properties
|
||||
const string& left = myProperties.get(Controller_Left);
|
||||
const string& right = myProperties.get(Controller_Right);
|
||||
|
||||
// Check for CompuMate controllers; they are special in that a handler
|
||||
// creates them for us, and also that they must be used in both ports
|
||||
if(left == "COMPUMATE" || right == "COMPUMATE")
|
||||
// Check for CompuMate scheme; it is special in that a handler creates both
|
||||
// controllers for us, and associates them with the bankswitching class
|
||||
if(myCart->detectedType() == "CM")
|
||||
{
|
||||
myCMHandler = make_shared<CompuMate>(*this, myEvent, *mySystem);
|
||||
|
||||
@ -743,153 +740,114 @@ void Console::setControllers(const string& rommd5)
|
||||
|
||||
myLeftControl = std::move(myCMHandler->leftController());
|
||||
myRightControl = std::move(myCMHandler->rightController());
|
||||
return;
|
||||
}
|
||||
|
||||
unique_ptr<Controller> leftC = std::move(myLeftControl),
|
||||
rightC = std::move(myRightControl);
|
||||
|
||||
// Also check if we should swap the paddles plugged into a jack
|
||||
bool swapPaddles = myProperties.get(Controller_SwapPaddles) == "YES";
|
||||
|
||||
// Construct left controller
|
||||
if(left == "JOYSTICK")
|
||||
{
|
||||
// Already created in c'tor
|
||||
// We save some time by not looking at all the other types
|
||||
if(!leftC)
|
||||
leftC = make_unique<Joystick>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "BOOSTERGRIP")
|
||||
{
|
||||
leftC = make_unique<BoosterGrip>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "DRIVING")
|
||||
{
|
||||
leftC = make_unique<Driving>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if((left == "KEYBOARD") || (left == "KEYPAD"))
|
||||
{
|
||||
leftC = make_unique<Keyboard>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(BSPF::startsWithIgnoreCase(left, "PADDLES"))
|
||||
{
|
||||
bool swapAxis = false, swapDir = false;
|
||||
if(left == "PADDLES_IAXIS")
|
||||
swapAxis = true;
|
||||
else if(left == "PADDLES_IDIR")
|
||||
swapDir = true;
|
||||
else if(left == "PADDLES_IAXDR")
|
||||
swapAxis = swapDir = true;
|
||||
leftC = make_unique<Paddles>(Controller::Left, myEvent, *mySystem,
|
||||
swapPaddles, swapAxis, swapDir);
|
||||
}
|
||||
else if(left == "AMIGAMOUSE")
|
||||
{
|
||||
leftC = make_unique<AmigaMouse>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "ATARIMOUSE")
|
||||
{
|
||||
leftC = make_unique<AtariMouse>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "TRAKBALL")
|
||||
{
|
||||
leftC = make_unique<TrakBall>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "GENESIS")
|
||||
{
|
||||
leftC = make_unique<Genesis>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "MINDLINK")
|
||||
{
|
||||
leftC = make_unique<MindLink>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
|
||||
// Construct right controller
|
||||
if(right == "JOYSTICK")
|
||||
{
|
||||
// Already created in c'tor
|
||||
// We save some time by not looking at all the other types
|
||||
if(!rightC)
|
||||
rightC = make_unique<Joystick>(Controller::Right, myEvent, *mySystem);
|
||||
}
|
||||
else if(right == "BOOSTERGRIP")
|
||||
{
|
||||
rightC = make_unique<BoosterGrip>(Controller::Right, myEvent, *mySystem);
|
||||
}
|
||||
else if(right == "DRIVING")
|
||||
{
|
||||
rightC = make_unique<Driving>(Controller::Right, myEvent, *mySystem);
|
||||
}
|
||||
else if((right == "KEYBOARD") || (right == "KEYPAD"))
|
||||
{
|
||||
rightC = make_unique<Keyboard>(Controller::Right, myEvent, *mySystem);
|
||||
}
|
||||
else if(BSPF::startsWithIgnoreCase(right, "PADDLES"))
|
||||
{
|
||||
bool swapAxis = false, swapDir = false;
|
||||
if(right == "PADDLES_IAXIS")
|
||||
swapAxis = true;
|
||||
else if(right == "PADDLES_IDIR")
|
||||
swapDir = true;
|
||||
else if(right == "PADDLES_IAXDR")
|
||||
swapAxis = swapDir = true;
|
||||
rightC = make_unique<Paddles>(Controller::Right, myEvent, *mySystem,
|
||||
swapPaddles, swapAxis, swapDir);
|
||||
}
|
||||
else if(left == "AMIGAMOUSE")
|
||||
{
|
||||
rightC = make_unique<AmigaMouse>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "ATARIMOUSE")
|
||||
{
|
||||
rightC = make_unique<AtariMouse>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(left == "TRAKBALL")
|
||||
{
|
||||
rightC = make_unique<TrakBall>(Controller::Left, myEvent, *mySystem);
|
||||
}
|
||||
else if(right == "ATARIVOX")
|
||||
{
|
||||
const string& nvramfile = myOSystem.nvramDir() + "atarivox_eeprom.dat";
|
||||
rightC = make_unique<AtariVox>(Controller::Right, myEvent,
|
||||
*mySystem, myOSystem.serialPort(),
|
||||
myOSystem.settings().getString("avoxport"), nvramfile);
|
||||
}
|
||||
else if(right == "SAVEKEY")
|
||||
{
|
||||
const string& nvramfile = myOSystem.nvramDir() + "savekey_eeprom.dat";
|
||||
rightC = make_unique<SaveKey>(Controller::Right, myEvent, *mySystem,
|
||||
nvramfile);
|
||||
}
|
||||
else if(right == "GENESIS")
|
||||
{
|
||||
rightC = make_unique<Genesis>(Controller::Right, myEvent, *mySystem);
|
||||
}
|
||||
else if(right == "KIDVID")
|
||||
{
|
||||
rightC = make_unique<KidVid>(Controller::Right, myEvent, *mySystem, rommd5);
|
||||
}
|
||||
else if(right == "MINDLINK")
|
||||
{
|
||||
rightC = make_unique<MindLink>(Controller::Right, myEvent, *mySystem);
|
||||
}
|
||||
|
||||
// Swap the ports if necessary
|
||||
if(myProperties.get(Console_SwapPorts) == "NO")
|
||||
{
|
||||
myLeftControl = std::move(leftC);
|
||||
myRightControl = std::move(rightC);
|
||||
}
|
||||
else
|
||||
{
|
||||
myLeftControl = std::move(rightC);
|
||||
myRightControl = std::move(leftC);
|
||||
// Setup the controllers based on properties
|
||||
const string& left = myProperties.get(Controller_Left);
|
||||
const string& right = myProperties.get(Controller_Right);
|
||||
|
||||
unique_ptr<Controller> leftC = getControllerPort(rommd5, left, Controller::Left),
|
||||
rightC = getControllerPort(rommd5, right, Controller::Right);
|
||||
|
||||
// Swap the ports if necessary
|
||||
if(myProperties.get(Console_SwapPorts) == "NO")
|
||||
{
|
||||
myLeftControl = std::move(leftC);
|
||||
myRightControl = std::move(rightC);
|
||||
}
|
||||
else
|
||||
{
|
||||
myLeftControl = std::move(rightC);
|
||||
myRightControl = std::move(leftC);
|
||||
}
|
||||
}
|
||||
|
||||
myTIA->bindToControllers();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
unique_ptr<Controller> Console::getControllerPort(const string& rommd5,
|
||||
const string& controllerName, Controller::Jack port)
|
||||
{
|
||||
unique_ptr<Controller> controller = std::move(myLeftControl);
|
||||
|
||||
if(controllerName == "JOYSTICK")
|
||||
{
|
||||
// Already created in c'tor
|
||||
// We save some time by not looking at all the other types
|
||||
if(!controller)
|
||||
controller = make_unique<Joystick>(port, myEvent, *mySystem);
|
||||
}
|
||||
else if(controllerName == "BOOSTERGRIP")
|
||||
{
|
||||
controller = make_unique<BoosterGrip>(port, myEvent, *mySystem);
|
||||
}
|
||||
else if(controllerName == "DRIVING")
|
||||
{
|
||||
controller = make_unique<Driving>(port, myEvent, *mySystem);
|
||||
}
|
||||
else if((controllerName == "KEYBOARD") || (controllerName == "KEYPAD"))
|
||||
{
|
||||
controller = make_unique<Keyboard>(port, myEvent, *mySystem);
|
||||
}
|
||||
else if(BSPF::startsWithIgnoreCase(controllerName, "PADDLES"))
|
||||
{
|
||||
// Also check if we should swap the paddles plugged into a jack
|
||||
bool swapPaddles = myProperties.get(Controller_SwapPaddles) == "YES";
|
||||
bool swapAxis = false, swapDir = false;
|
||||
if(controllerName == "PADDLES_IAXIS")
|
||||
swapAxis = true;
|
||||
else if(controllerName == "PADDLES_IDIR")
|
||||
swapDir = true;
|
||||
else if(controllerName == "PADDLES_IAXDR")
|
||||
swapAxis = swapDir = true;
|
||||
controller = make_unique<Paddles>(port, myEvent, *mySystem,
|
||||
swapPaddles, swapAxis, swapDir);
|
||||
}
|
||||
else if(controllerName == "AMIGAMOUSE")
|
||||
{
|
||||
controller = make_unique<AmigaMouse>(port, myEvent, *mySystem);
|
||||
}
|
||||
else if(controllerName == "ATARIMOUSE")
|
||||
{
|
||||
controller = make_unique<AtariMouse>(port, myEvent, *mySystem);
|
||||
}
|
||||
else if(controllerName == "TRAKBALL")
|
||||
{
|
||||
controller = make_unique<TrakBall>(port, myEvent, *mySystem);
|
||||
}
|
||||
else if(controllerName == "ATARIVOX")
|
||||
{
|
||||
const string& nvramfile = myOSystem.nvramDir() + "atarivox_eeprom.dat";
|
||||
controller = make_unique<AtariVox>(port, myEvent,
|
||||
*mySystem, myOSystem.serialPort(),
|
||||
myOSystem.settings().getString("avoxport"), nvramfile);
|
||||
}
|
||||
else if(controllerName == "SAVEKEY")
|
||||
{
|
||||
const string& nvramfile = myOSystem.nvramDir() + "savekey_eeprom.dat";
|
||||
controller = make_unique<SaveKey>(port, myEvent, *mySystem,
|
||||
nvramfile);
|
||||
}
|
||||
else if(controllerName == "GENESIS")
|
||||
{
|
||||
controller = make_unique<Genesis>(port, myEvent, *mySystem);
|
||||
}
|
||||
else if(controllerName == "KIDVID")
|
||||
{
|
||||
controller = make_unique<KidVid>(port, myEvent, *mySystem, rommd5);
|
||||
}
|
||||
else if(controllerName == "MINDLINK")
|
||||
{
|
||||
controller = make_unique<MindLink>(port, myEvent, *mySystem);
|
||||
}
|
||||
else // What else can we do?
|
||||
controller = make_unique<Joystick>(port, myEvent, *mySystem);
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Console::loadUserPalette()
|
||||
{
|
||||
@ -953,7 +911,7 @@ void Console::generateColorLossPalette()
|
||||
uInt32* palette[9] = {
|
||||
&ourNTSCPalette[0], &ourPALPalette[0], &ourSECAMPalette[0],
|
||||
&ourNTSCPaletteZ26[0], &ourPALPaletteZ26[0], &ourSECAMPaletteZ26[0],
|
||||
0, 0, 0
|
||||
nullptr, nullptr, nullptr
|
||||
};
|
||||
if(myUserPaletteDefined)
|
||||
{
|
||||
@ -964,7 +922,7 @@ void Console::generateColorLossPalette()
|
||||
|
||||
for(int i = 0; i < 9; ++i)
|
||||
{
|
||||
if(palette[i] == 0)
|
||||
if(palette[i] == nullptr)
|
||||
continue;
|
||||
|
||||
// Fill the odd numbered palette entries with gray values (calculated
|
||||
|
@ -326,6 +326,12 @@ class Console : public Serializable
|
||||
*/
|
||||
void setControllers(const string& rommd5);
|
||||
|
||||
/**
|
||||
Selects the left or right controller depending on ROM properties
|
||||
*/
|
||||
unique_ptr<Controller> getControllerPort(const string& rommd5,
|
||||
const string& controllerName, Controller::Jack port);
|
||||
|
||||
/**
|
||||
Loads a user-defined palette file (from OSystem::paletteFile), filling the
|
||||
appropriate user-defined palette arrays.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user