mirror of https://github.com/stella-emu/stella.git
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
|
sometimes the image was 'double-blended', resulting in a snapshot that
|
||||||
was too dark.
|
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
|
* Added debugger pseudo-register '_fcycles', which gives the number of
|
||||||
CPU cycles that have occurred since the frame started.
|
CPU cycles that have occurred since the frame started.
|
||||||
|
|
||||||
|
@ -2676,7 +2680,7 @@
|
||||||
|
|
||||||
* Fixed crash when adding one-shot cheats.
|
* 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
|
* Fixed bug with setting snapshot naming type from the GUI (it was
|
||||||
always being set to 'romname').
|
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
|
ifdef HAVE_GCC
|
||||||
CXXFLAGS+= -Wno-multichar -Wunused -fno-rtti -Woverloaded-virtual -Wnon-virtual-dtor -std=c++14
|
CXXFLAGS+= -Wno-multichar -Wunused -fno-rtti -Woverloaded-virtual -Wnon-virtual-dtor -std=c++14
|
||||||
endif
|
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
|
ifdef PROFILE
|
||||||
PROF:= -g -pg -fprofile-arcs -ftest-coverage
|
PROF:= -g -pg -fprofile-arcs -ftest-coverage
|
||||||
|
@ -63,10 +70,6 @@ else
|
||||||
endif
|
endif
|
||||||
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 #
|
# Misc stuff - you should never have to edit this #
|
||||||
|
|
|
@ -386,14 +386,16 @@ cc_check_define __GNUC__ && have_gcc=yes
|
||||||
|
|
||||||
if test "$have_clang" = yes; then
|
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__ )
|
is_xcode=$( $CXX -dM -E -x c /dev/null | grep __apple_build_version__ )
|
||||||
|
|
||||||
|
# Need at least version 8
|
||||||
if test -n "$is_xcode"; then
|
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"
|
cxx_name="XCode $cxx_version"
|
||||||
|
|
||||||
if test $clang_major -ge 8; then
|
if test $clang_major -ge 8; then
|
||||||
|
@ -401,35 +403,23 @@ if test "$have_clang" = yes; then
|
||||||
cxx_verc_fail=no
|
cxx_verc_fail=no
|
||||||
else
|
else
|
||||||
cxx_version="$cxx_version, bad"
|
cxx_version="$cxx_version, bad"
|
||||||
cxx_verc_fail=bad
|
cxx_verc_fail=yes
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
cxx_name=`( $cc -v ) 2>&1 | tail -n 1 | cut -d ' ' -f 1`
|
# Need at least version 3.5
|
||||||
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 [ $clang_major -ge 4 ] || [ $clang_major -eq 3 -a $clang_minor -ge 5 ]; then
|
||||||
if test "$?" -gt 0; then
|
cxx_version="$cxx_version, ok"
|
||||||
cxx_version="not found"
|
cxx_verc_fail=no
|
||||||
|
else
|
||||||
|
cxx_version="$cxx_version, bad"
|
||||||
|
cxx_verc_fail=yes
|
||||||
fi
|
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
|
fi
|
||||||
CXXFLAGS="$CXXFLAGS"
|
CXXFLAGS="$CXXFLAGS"
|
||||||
_make_def_HAVE_GCC3='HAVE_GCC3 = 1'
|
_make_def_HAVE_GCC3='HAVE_GCC3 = 1'
|
||||||
add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP'
|
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_GCC='HAVE_GCC = 1'
|
||||||
|
_make_def_HAVE_CLANG='HAVE_CLANG = 1'
|
||||||
echo "$cxx_version"
|
echo "$cxx_version"
|
||||||
|
|
||||||
elif test "$have_gcc" = yes; then
|
elif test "$have_gcc" = yes; then
|
||||||
|
@ -505,7 +495,7 @@ fi
|
||||||
if test "$cxx_verc_fail" = yes ; then
|
if test "$cxx_verc_fail" = yes ; then
|
||||||
echo
|
echo
|
||||||
echo "The version of your compiler is not supported at this time"
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -827,6 +817,7 @@ PROFILE := $_build_profile
|
||||||
|
|
||||||
$_make_def_HAVE_GCC
|
$_make_def_HAVE_GCC
|
||||||
$_make_def_HAVE_GCC3
|
$_make_def_HAVE_GCC3
|
||||||
|
$_make_def_HAVE_CLANG
|
||||||
|
|
||||||
INCLUDES += $INCLUDES
|
INCLUDES += $INCLUDES
|
||||||
OBJS += $OBJS
|
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
|
<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),
|
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>
|
means 'search addresses for values that have changed by that amount'.</p>
|
||||||
<p>The 'Reset' button resets the entire operation; it clears the highlighted
|
<p>The 'Reset' button resets the entire operation; it clears the highlighted
|
||||||
addresses and allows another search.</p>
|
addresses and allows another search.</p>
|
||||||
|
|
|
@ -57,13 +57,13 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
|
||||||
xpos += myCheatList->getWidth() + 5; ypos = 15;
|
xpos += myCheatList->getWidth() + 5; ypos = 15;
|
||||||
|
|
||||||
b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
||||||
"Add", kAddCheatCmd);
|
"Add" + ELLIPSIS, kAddCheatCmd);
|
||||||
wid.push_back(b);
|
wid.push_back(b);
|
||||||
ypos += lineHeight + 10;
|
ypos += lineHeight + 10;
|
||||||
|
|
||||||
myEditButton =
|
myEditButton =
|
||||||
new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
||||||
"Edit", kEditCheatCmd);
|
"Edit" + ELLIPSIS, kEditCheatCmd);
|
||||||
wid.push_back(myEditButton);
|
wid.push_back(myEditButton);
|
||||||
ypos += lineHeight + 10;
|
ypos += lineHeight + 10;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
|
||||||
ypos += lineHeight + 10;
|
ypos += lineHeight + 10;
|
||||||
|
|
||||||
b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
|
||||||
"One shot", kAddOneShotCmd);
|
"One shot" + ELLIPSIS, kAddOneShotCmd);
|
||||||
wid.push_back(b);
|
wid.push_back(b);
|
||||||
|
|
||||||
// Inputbox which will pop up when adding/editing a cheat
|
// Inputbox which will pop up when adding/editing a cheat
|
||||||
|
@ -196,12 +196,12 @@ void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
|
||||||
{
|
{
|
||||||
switch(cmd)
|
switch(cmd)
|
||||||
{
|
{
|
||||||
case kOKCmd:
|
case GuiObject::kOKCmd:
|
||||||
saveConfig();
|
saveConfig();
|
||||||
close();
|
close();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kCloseCmd:
|
case GuiObject::kCloseCmd:
|
||||||
close();
|
close();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,11 @@ class Base
|
||||||
os.flags(myHexflags);
|
os.flags(myHexflags);
|
||||||
return os << std::setw(2) << std::setfill('0');
|
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) {
|
static inline std::ostream& HEX4(std::ostream& os) {
|
||||||
os.flags(myHexflags);
|
os.flags(myHexflags);
|
||||||
return os << std::setw(4) << std::setfill('0');
|
return os << std::setw(4) << std::setfill('0');
|
||||||
|
@ -93,6 +98,7 @@ class Base
|
||||||
|
|
||||||
// Format specifiers to use for sprintf (eventually we may convert
|
// Format specifiers to use for sprintf (eventually we may convert
|
||||||
// to C++ streams
|
// to C++ streams
|
||||||
|
static ostringstream buf;
|
||||||
static const char* const myLowerFmt[4];
|
static const char* const myLowerFmt[4];
|
||||||
static const char* const myUpperFmt[4];
|
static const char* const myUpperFmt[4];
|
||||||
static const char* const* myFmt;
|
static const char* const* myFmt;
|
||||||
|
|
|
@ -55,7 +55,7 @@ class FilesystemNodeFactory
|
||||||
return new FilesystemNodeZIP(path);
|
return new FilesystemNodeZIP(path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -42,7 +42,6 @@ class FilesystemNodeZIP : public AbstractFSNode
|
||||||
* Creates a FilesystemNodeZIP for a given path.
|
* Creates a FilesystemNodeZIP for a given path.
|
||||||
*
|
*
|
||||||
* @param path String with the path the new node should point to.
|
* @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);
|
FilesystemNodeZIP(const string& path);
|
||||||
|
|
||||||
|
|
|
@ -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
|
// Cleanup
|
||||||
done:
|
done:
|
||||||
if(png_ptr)
|
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)
|
if(err_message)
|
||||||
throw runtime_error(err_message);
|
throw runtime_error(err_message);
|
||||||
|
|
|
@ -46,9 +46,9 @@ class PNGLibrary
|
||||||
@param filename The filename to load the PNG image
|
@param filename The filename to load the PNG image
|
||||||
@param surface The FBSurface into which to place the PNG data
|
@param surface The FBSurface into which to place the PNG data
|
||||||
|
|
||||||
@return On success, the FBSurface containing image data, otherwise a
|
@post On success, the FBSurface containing image data, otherwise a
|
||||||
runtime_error is thrown containing a more detailed
|
runtime_error is thrown containing a more detailed
|
||||||
error message.
|
error message.
|
||||||
*/
|
*/
|
||||||
void loadImage(const string& filename, FBSurface& surface);
|
void loadImage(const string& filename, FBSurface& surface);
|
||||||
|
|
||||||
|
@ -60,9 +60,9 @@ class PNGLibrary
|
||||||
@param filename The filename to save the PNG image
|
@param filename The filename to save the PNG image
|
||||||
@param comments The text comments to add to 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',
|
@post On success, the PNG file has been saved to 'filename',
|
||||||
otherwise a runtime_error is thrown containing a
|
otherwise a runtime_error is thrown containing a
|
||||||
more detailed error message.
|
more detailed error message.
|
||||||
*/
|
*/
|
||||||
void saveImage(const string& filename,
|
void saveImage(const string& filename,
|
||||||
const VariantList& comments = EmptyVarList);
|
const VariantList& comments = EmptyVarList);
|
||||||
|
@ -75,9 +75,9 @@ class PNGLibrary
|
||||||
@param rect The area of the surface to use
|
@param rect The area of the surface to use
|
||||||
@param comments The text comments to add to 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',
|
@post On success, the PNG file has been saved to 'filename',
|
||||||
otherwise a runtime_error is thrown containing a
|
otherwise a runtime_error is thrown containing a
|
||||||
more detailed error message.
|
more detailed error message.
|
||||||
*/
|
*/
|
||||||
void saveImage(const string& filename, const FBSurface& surface,
|
void saveImage(const string& filename, const FBSurface& surface,
|
||||||
const GUI::Rect& rect = GUI::EmptyRect,
|
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_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_write_data(png_structp ctx, png_bytep area, png_size_t size);
|
||||||
static void png_io_flush(png_structp ctx);
|
static void png_io_flush(png_structp ctx);
|
||||||
static void png_user_warn(png_structp ctx, png_const_charp str);
|
[[noreturn]] 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_error(png_structp ctx, png_const_charp str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "OSystem.hxx"
|
#include "OSystem.hxx"
|
||||||
#include "Serializer.hxx"
|
#include "Serializer.hxx"
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
|
@ -25,23 +27,30 @@
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
|
RewindManager::RewindManager(OSystem& system, StateManager& statemgr)
|
||||||
: myOSystem(system),
|
: myOSystem(system),
|
||||||
myStateManager(statemgr)
|
myStateManager(statemgr),
|
||||||
|
myIsNTSC(true) // TODO
|
||||||
|
// TODO: current is not valid
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool RewindManager::addState(const string& message)
|
bool RewindManager::addState(const string& message)
|
||||||
{
|
{
|
||||||
RewindPtr state = make_unique<RewindState>(); // TODO: get this from object pool
|
// TODO: remove following (preceding???) (all invalid) states
|
||||||
Serializer& s = state->data;
|
// 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
|
s.reset(); // rewind Serializer internal buffers
|
||||||
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
|
if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s))
|
||||||
{
|
{
|
||||||
state->message = "Rewind " + message;
|
state.message = message;
|
||||||
|
state.cycle = myOSystem.console().tia().cycles();
|
||||||
// Add to the list TODO: should check against current size
|
|
||||||
myStateList.emplace_front(std::move(state));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -50,21 +59,104 @@ bool RewindManager::addState(const string& message)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool RewindManager::rewindState()
|
bool RewindManager::rewindState()
|
||||||
{
|
{
|
||||||
if(myStateList.size() > 0)
|
if(!myStateList.empty())
|
||||||
{
|
{
|
||||||
RewindPtr state = std::move(myStateList.front());
|
// TODO: get state previous to the current state instead of first()
|
||||||
myStateList.pop_front(); // TODO: add 'state' to object pool
|
// RewindState& state = myStateList.current();
|
||||||
Serializer& s = state->data;
|
// 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
|
s.reset(); // rewind Serializer internal buffers
|
||||||
myStateManager.loadState(s);
|
myStateManager.loadState(s);
|
||||||
myOSystem.console().tia().loadDisplay(s);
|
myOSystem.console().tia().loadDisplay(s);
|
||||||
|
|
||||||
// Show message indicating the rewind state
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return false;
|
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 OSystem;
|
||||||
class StateManager;
|
class StateManager;
|
||||||
|
|
||||||
#include <list>
|
#include "LinkedObjectPool.hxx"
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This class is used to save (and later 'rewind') system save states.
|
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
|
@author Stephen Anthony
|
||||||
*/
|
*/
|
||||||
class RewindManager
|
class RewindManager
|
||||||
|
@ -54,12 +49,19 @@ class RewindManager
|
||||||
*/
|
*/
|
||||||
bool rewindState();
|
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(); }
|
void clear() { myStateList.clear(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Maximum number of states to save
|
// Maximum number of states to save
|
||||||
static constexpr uInt32 MAX_SIZE = 100; // FIXME: use this
|
static constexpr uInt32 MAX_SIZE = 100;
|
||||||
|
|
||||||
OSystem& myOSystem;
|
OSystem& myOSystem;
|
||||||
StateManager& myStateManager;
|
StateManager& myStateManager;
|
||||||
|
@ -67,10 +69,21 @@ class RewindManager
|
||||||
struct RewindState {
|
struct RewindState {
|
||||||
Serializer data;
|
Serializer data;
|
||||||
string message;
|
string message;
|
||||||
|
uInt64 cycle;
|
||||||
|
|
||||||
|
// We do nothing on object instantiation or copy
|
||||||
|
RewindState() { }
|
||||||
|
RewindState(const RewindState&) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
using RewindPtr = unique_ptr<RewindState>;
|
Common::LinkedObjectPool<RewindState, MAX_SIZE> myStateList;
|
||||||
std::list<RewindPtr> myStateList;
|
|
||||||
|
bool myIsNTSC;
|
||||||
|
|
||||||
|
void compressStates();
|
||||||
|
|
||||||
|
string getMessage(RewindState& state);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
|
|
|
@ -18,13 +18,27 @@
|
||||||
#ifndef SDL_LIB_HXX
|
#ifndef SDL_LIB_HXX
|
||||||
#define 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
|
* Seems to be needed for ppc64le, doesn't hurt other archs
|
||||||
Note that this is a problem in SDL2, which includes <altivec.h>
|
* Note that this is a problem in SDL2, which includes <altivec.h>
|
||||||
https://bugzilla.redhat.com/show_bug.cgi?id=1419452
|
* https://bugzilla.redhat.com/show_bug.cgi?id=1419452
|
||||||
*/
|
*/
|
||||||
#undef vector
|
#undef vector
|
||||||
#undef pixel
|
#undef pixel
|
||||||
#undef bool
|
#undef bool
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "StateManager.hxx"
|
#include "StateManager.hxx"
|
||||||
|
|
||||||
#define STATE_HEADER "05000302state"
|
#define STATE_HEADER "05000302state"
|
||||||
#define MOVIE_HEADER "03030000movie"
|
// #define MOVIE_HEADER "03030000movie"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
StateManager::StateManager(OSystem& osystem)
|
StateManager::StateManager(OSystem& osystem)
|
||||||
|
@ -134,6 +134,22 @@ void StateManager::toggleRewindMode()
|
||||||
myOSystem.frameBuffer().showMessage("Continuous rewind disabled");
|
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()
|
void StateManager::update()
|
||||||
{
|
{
|
||||||
|
|
|
@ -64,6 +64,16 @@ class StateManager
|
||||||
*/
|
*/
|
||||||
void toggleRewindMode();
|
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.
|
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 str The string to split
|
||||||
@param maxlen The maximum length of string to generate
|
@param maxlen The maximum length of string to generate
|
||||||
*/
|
*/
|
||||||
StringParser(const string& str, uInt16 maxlen)
|
StringParser(const string& str, uInt32 maxlen)
|
||||||
{
|
{
|
||||||
istringstream buf(str);
|
istringstream buf(str);
|
||||||
string line;
|
string line;
|
||||||
|
|
|
@ -168,7 +168,6 @@ bool ZipHandler::stream_read(fstream* stream, void* buffer, uInt64 offset,
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
This file defines various basic data types and preprocessor variables
|
This file defines various basic data types and preprocessor variables
|
||||||
that need to be defined for different operating systems.
|
that need to be defined for different operating systems.
|
||||||
|
|
||||||
@author Bradford W. Mott
|
@author Bradford W. Mott and Stephen Anthony
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
@ -77,6 +77,7 @@ using std::memcpy;
|
||||||
using IntArray = std::vector<Int32>;
|
using IntArray = std::vector<Int32>;
|
||||||
using BoolArray = std::vector<bool>;
|
using BoolArray = std::vector<bool>;
|
||||||
using ByteArray = std::vector<uInt8>;
|
using ByteArray = std::vector<uInt8>;
|
||||||
|
using ShortArray = std::vector<uInt16>;
|
||||||
using StringList = std::vector<std::string>;
|
using StringList = std::vector<std::string>;
|
||||||
using BytePtr = std::unique_ptr<uInt8[]>;
|
using BytePtr = std::unique_ptr<uInt8[]>;
|
||||||
|
|
||||||
|
@ -87,12 +88,14 @@ namespace BSPF
|
||||||
// Defines to help with path handling
|
// Defines to help with path handling
|
||||||
#if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)
|
#if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX)
|
||||||
static const string PATH_SEPARATOR = "/";
|
static const string PATH_SEPARATOR = "/";
|
||||||
|
#define ATTRIBUTE_FMT_PRINTF __attribute__((__format__ (__printf__, 2, 0)))
|
||||||
#elif defined(BSPF_WINDOWS)
|
#elif defined(BSPF_WINDOWS)
|
||||||
static const string PATH_SEPARATOR = "\\";
|
static const string PATH_SEPARATOR = "\\";
|
||||||
#pragma warning (disable : 4146) // unary minus operator applied to unsigned type
|
#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: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: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
|
#pragma warning(2:4266) // no override available for virtual member function from base 'type'; function is hidden
|
||||||
|
#define ATTRIBUTE_FMT_PRINTF
|
||||||
#else
|
#else
|
||||||
#error Update src/common/bspf.hxx for path separator
|
#error Update src/common/bspf.hxx for path separator
|
||||||
#endif
|
#endif
|
||||||
|
@ -164,13 +167,13 @@ namespace BSPF
|
||||||
|
|
||||||
// Find location (if any) of the second string within the first,
|
// Find location (if any) of the second string within the first,
|
||||||
// starting from 'startpos' in the first string
|
// 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(),
|
auto pos = std::search(s1.cbegin()+startpos, s1.cend(),
|
||||||
s2.cbegin(), s2.cend(), [](char ch1, char ch2) {
|
s2.cbegin(), s2.cend(), [](char ch1, char ch2) {
|
||||||
return toupper(uInt8(ch1)) == toupper(uInt8(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)
|
// Test whether the first string ends with the second one (case insensitive)
|
||||||
|
@ -189,6 +192,26 @@ namespace BSPF
|
||||||
{
|
{
|
||||||
return findIgnoreCase(s1, s2) != string::npos;
|
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
|
} // namespace BSPF
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,18 +38,6 @@
|
||||||
#include "CheatManager.hxx"
|
#include "CheatManager.hxx"
|
||||||
#endif
|
#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)
|
#if defined(BSPF_MAC_OSX)
|
||||||
|
@ -61,10 +49,17 @@ int main(int argc, char* argv[])
|
||||||
std::ios_base::sync_with_stdio(false);
|
std::ios_base::sync_with_stdio(false);
|
||||||
|
|
||||||
// Create the parent OSystem object
|
// Create the parent OSystem object
|
||||||
theOSystem = MediaFactory::createOSystem();
|
unique_ptr<OSystem> theOSystem = MediaFactory::createOSystem();
|
||||||
theOSystem->loadConfig();
|
theOSystem->loadConfig();
|
||||||
theOSystem->logMessage("Loading config options ...", 2);
|
theOSystem->logMessage("Loading config options ...", 2);
|
||||||
|
|
||||||
|
auto Cleanup = [&theOSystem]() {
|
||||||
|
theOSystem->logMessage("Cleanup from main", 2);
|
||||||
|
theOSystem->saveConfig();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Take care of commandline arguments
|
// Take care of commandline arguments
|
||||||
theOSystem->logMessage("Loading commandline arguments ...", 2);
|
theOSystem->logMessage("Loading commandline arguments ...", 2);
|
||||||
string romfile = theOSystem->settings().loadCommandLine(argc, argv);
|
string romfile = theOSystem->settings().loadCommandLine(argc, argv);
|
||||||
|
|
|
@ -83,4 +83,4 @@ inline uInt8 smartmod<256>(uInt8 x)
|
||||||
return x & 0xFF;
|
return x & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SMARTMOD_HXX
|
#endif // SMARTMOD_HXX
|
||||||
|
|
|
@ -56,12 +56,12 @@ void AtariNTSC::initializePalette(const uInt8* palette)
|
||||||
uInt32* kernel = myColorTable[entry];
|
uInt32* kernel = myColorTable[entry];
|
||||||
genKernel(myImpl, y, i, q, kernel);
|
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 -
|
uInt32 error = rgb -
|
||||||
kernel [i ] - kernel [(i+10)%14+14] -
|
kernel [c ] - kernel [(c+10)%14+14] -
|
||||||
kernel [i + 7] - kernel [i + 3 +14];
|
kernel [c + 7] - kernel [c + 3 +14];
|
||||||
kernel [i + 3 + 14] += error;
|
kernel [c + 3 + 14] += error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ class AtariNTSC
|
||||||
Used to calculate an averaged color for the 'phosphor' effect.
|
Used to calculate an averaged color for the 'phosphor' effect.
|
||||||
|
|
||||||
@param c RGB Color 1 (current frame)
|
@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
|
@return Averaged value of the two RGB colors
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -58,7 +58,7 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||||
mySystemAddresses = LabelToAddr(sysCmp);
|
mySystemAddresses = LabelToAddr(sysCmp);
|
||||||
|
|
||||||
// Add Zero-page RAM addresses
|
// 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.rport.push_back(i);
|
||||||
myState.wport.push_back(i);
|
myState.wport.push_back(i);
|
||||||
|
@ -75,16 +75,17 @@ CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem)
|
||||||
|
|
||||||
BankInfo info;
|
BankInfo info;
|
||||||
info.size = std::min(banksize, 4096u);
|
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);
|
myBankInfo.push_back(info);
|
||||||
|
|
||||||
info.size = 128; // ZP RAM
|
info.size = 128; // ZP RAM
|
||||||
myBankInfo.push_back(info);
|
myBankInfo.push_back(info);
|
||||||
|
|
||||||
// We know the address for the startup bank right now
|
// 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));
|
addLabel("Start", myDebugger.dpeek(0xfffc, DATA));
|
||||||
|
|
||||||
// Add system equates
|
// Add system equates
|
||||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||||
{
|
{
|
||||||
|
@ -132,7 +133,7 @@ const DebuggerState& CartDebug::getState()
|
||||||
{
|
{
|
||||||
myState.ram.clear();
|
myState.ram.clear();
|
||||||
for(uInt32 i = 0; i < myState.rport.size(); ++i)
|
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)
|
if(myDebugWidget)
|
||||||
myState.bank = myDebugWidget->bankState();
|
myState.bank = myDebugWidget->bankState();
|
||||||
|
@ -145,7 +146,7 @@ void CartDebug::saveOldState()
|
||||||
{
|
{
|
||||||
myOldState.ram.clear();
|
myOldState.ram.clear();
|
||||||
for(uInt32 i = 0; i < myOldState.rport.size(); ++i)
|
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)
|
if(myDebugWidget)
|
||||||
{
|
{
|
||||||
|
@ -274,7 +275,7 @@ bool CartDebug::disassemble(bool force)
|
||||||
}
|
}
|
||||||
// Otherwise, add the item at the end
|
// Otherwise, add the item at the end
|
||||||
if (i == addresses.end())
|
if (i == addresses.end())
|
||||||
addresses.push_back(PC);
|
addresses.push_back(PC);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always attempt to resolve code sections unless it's been
|
// Always attempt to resolve code sections unless it's been
|
||||||
|
@ -723,7 +724,7 @@ string CartDebug::loadListFile()
|
||||||
if(addr_s.length() == 0)
|
if(addr_s.length() == 0)
|
||||||
continue;
|
continue;
|
||||||
const char* p = addr_s[0] == 'U' ? addr_s.c_str() + 1 : addr_s.c_str();
|
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
|
// For now, completely ignore ROM addresses
|
||||||
if(!(addr & 0x1000))
|
if(!(addr & 0x1000))
|
||||||
|
@ -786,7 +787,8 @@ string CartDebug::loadSymbolFile()
|
||||||
if (iter == myUserLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
|
if (iter == myUserLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second))
|
||||||
{
|
{
|
||||||
// Check for period, and strip leading number
|
// 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);
|
addLabel(label.substr(pos), value);
|
||||||
else
|
else
|
||||||
addLabel(label, value);
|
addLabel(label, value);
|
||||||
|
@ -1005,7 +1007,7 @@ string CartDebug::saveDisassembly()
|
||||||
disasm.list.clear();
|
disasm.list.clear();
|
||||||
DiStella distella(*this, disasm.list, info, settings,
|
DiStella distella(*this, disasm.list, info, settings,
|
||||||
myDisLabels, myDisDirectives, myReserved);
|
myDisLabels, myDisDirectives, myReserved);
|
||||||
|
|
||||||
if (myReserved.breakFound)
|
if (myReserved.breakFound)
|
||||||
addLabel("Break", myDebugger.dpeek(0xfffe));
|
addLabel("Break", myDebugger.dpeek(0xfffe));
|
||||||
|
|
||||||
|
@ -1055,7 +1057,7 @@ string CartDebug::saveDisassembly()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CartDebug::DATA:
|
case CartDebug::DATA:
|
||||||
{
|
{
|
||||||
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)";
|
buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1063,7 +1065,7 @@ string CartDebug::saveDisassembly()
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} // switch
|
} // switch
|
||||||
buf << "\n";
|
buf << "\n";
|
||||||
}
|
}
|
||||||
|
@ -1100,7 +1102,7 @@ string CartDebug::saveDisassembly()
|
||||||
out << "\n;-----------------------------------------------------------\n"
|
out << "\n;-----------------------------------------------------------\n"
|
||||||
<< "; TIA and IO constants accessed\n"
|
<< "; TIA and IO constants accessed\n"
|
||||||
<< ";-----------------------------------------------------------\n\n";
|
<< ";-----------------------------------------------------------\n\n";
|
||||||
|
|
||||||
// TIA read access
|
// TIA read access
|
||||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
||||||
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr])
|
if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr])
|
||||||
|
@ -1129,9 +1131,9 @@ string CartDebug::saveDisassembly()
|
||||||
}
|
}
|
||||||
|
|
||||||
addrUsed = false;
|
addrUsed = false;
|
||||||
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
for(uInt16 addr = 0x80; addr <= 0xFF; ++addr)
|
||||||
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80]
|
addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80]
|
||||||
|| (mySystem.getAccessFlags(addr) & (DATA | WRITE))
|
|| (mySystem.getAccessFlags(addr) & (DATA | WRITE))
|
||||||
|| (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
|
|| (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
|
||||||
if(addrUsed)
|
if(addrUsed)
|
||||||
{
|
{
|
||||||
|
@ -1139,13 +1141,13 @@ string CartDebug::saveDisassembly()
|
||||||
out << "\n\n;-----------------------------------------------------------\n"
|
out << "\n\n;-----------------------------------------------------------\n"
|
||||||
<< "; RIOT RAM (zero-page) labels\n"
|
<< "; RIOT RAM (zero-page) labels\n"
|
||||||
<< ";-----------------------------------------------------------\n\n";
|
<< ";-----------------------------------------------------------\n\n";
|
||||||
|
|
||||||
for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) {
|
for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) {
|
||||||
bool ramUsed = (mySystem.getAccessFlags(addr) & (DATA | WRITE));
|
bool ramUsed = (mySystem.getAccessFlags(addr) & (DATA | WRITE));
|
||||||
bool codeUsed = (mySystem.getAccessFlags(addr) & CODE);
|
bool codeUsed = (mySystem.getAccessFlags(addr) & CODE);
|
||||||
bool stackUsed = (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
|
bool stackUsed = (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE));
|
||||||
|
|
||||||
if (myReserved.ZPRAM[addr - 0x80] &&
|
if (myReserved.ZPRAM[addr - 0x80] &&
|
||||||
myUserLabels.find(addr) == myUserLabels.end()) {
|
myUserLabels.find(addr) == myUserLabels.end()) {
|
||||||
if (addLine)
|
if (addLine)
|
||||||
out << "\n";
|
out << "\n";
|
||||||
|
@ -1153,7 +1155,7 @@ string CartDebug::saveDisassembly()
|
||||||
<< Base::HEX2 << right << (addr)
|
<< Base::HEX2 << right << (addr)
|
||||||
<< (stackUsed|codeUsed ? "; (" : "")
|
<< (stackUsed|codeUsed ? "; (" : "")
|
||||||
<< (codeUsed ? "c" : "")
|
<< (codeUsed ? "c" : "")
|
||||||
<< (stackUsed ? "s" : "")
|
<< (stackUsed ? "s" : "")
|
||||||
<< (stackUsed | codeUsed ? ")" : "")
|
<< (stackUsed | codeUsed ? ")" : "")
|
||||||
<< "\n";
|
<< "\n";
|
||||||
addLine = false;
|
addLine = false;
|
||||||
|
@ -1161,11 +1163,11 @@ string CartDebug::saveDisassembly()
|
||||||
if (addLine)
|
if (addLine)
|
||||||
out << "\n";
|
out << "\n";
|
||||||
out << ALIGN(18) << ";" << "$"
|
out << ALIGN(18) << ";" << "$"
|
||||||
<< Base::HEX2 << right << (addr)
|
<< Base::HEX2 << right << (addr)
|
||||||
<< " ("
|
<< " ("
|
||||||
<< (ramUsed ? "i" : "")
|
<< (ramUsed ? "i" : "")
|
||||||
<< (codeUsed ? "c" : "")
|
<< (codeUsed ? "c" : "")
|
||||||
<< (stackUsed ? "s" : "")
|
<< (stackUsed ? "s" : "")
|
||||||
<< ")\n";
|
<< ")\n";
|
||||||
addLine = false;
|
addLine = false;
|
||||||
} else
|
} else
|
||||||
|
@ -1278,23 +1280,23 @@ void CartDebug::getCompletions(const char* in, StringList& completions) const
|
||||||
{
|
{
|
||||||
// First scan system equates
|
// First scan system equates
|
||||||
for(uInt16 addr = 0x00; addr <= 0x0F; ++addr)
|
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]);
|
completions.push_back(ourTIAMnemonicR[addr]);
|
||||||
for(uInt16 addr = 0x00; addr <= 0x3F; ++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]);
|
completions.push_back(ourTIAMnemonicW[addr]);
|
||||||
for(uInt16 addr = 0; addr <= 0x297-0x280; ++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]);
|
completions.push_back(ourIOMnemonic[addr]);
|
||||||
for(uInt16 addr = 0; addr <= 0x7F; ++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]);
|
completions.push_back(ourZPMnemonic[addr]);
|
||||||
|
|
||||||
// Now scan user-defined labels
|
// Now scan user-defined labels
|
||||||
for(const auto& iter: myUserAddresses)
|
for(const auto& iter: myUserAddresses)
|
||||||
{
|
{
|
||||||
const char* l = iter.first.c_str();
|
const char* l = iter.first.c_str();
|
||||||
if(BSPF::startsWithIgnoreCase(l, in))
|
if(BSPF::matches(l, in))
|
||||||
completions.push_back(l);
|
completions.push_back(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1332,7 +1334,7 @@ void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const
|
||||||
buf << "ORG " << Base::HEX4 << info.offset << endl;
|
buf << "ORG " << Base::HEX4 << info.offset << endl;
|
||||||
|
|
||||||
// Now consider each byte
|
// Now consider each byte
|
||||||
uInt32 prev = info.offset, addr = prev + 1;
|
uInt16 prev = info.offset, addr = prev + 1;
|
||||||
DisasmType prevType = disasmTypeAbsolute(mySystem.getAccessFlags(prev));
|
DisasmType prevType = disasmTypeAbsolute(mySystem.getAccessFlags(prev));
|
||||||
for( ; addr < info.offset + info.size; ++addr)
|
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",
|
"AUDF1", "AUDV0", "AUDV1", "GRP0", "GRP1", "ENAM0", "ENAM1", "ENABL",
|
||||||
"HMP0", "HMP1", "HMM0", "HMM1", "HMBL", "VDELP0", "VDELP1", "VDELBL",
|
"HMP0", "HMP1", "HMM0", "HMM1", "HMBL", "VDELP0", "VDELP1", "VDELBL",
|
||||||
"RESMP0", "RESMP1", "HMOVE", "HMCLR", "CXCLR", "$2d", "$2e", "$2f",
|
"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"
|
"$38", "$39", "$3a", "$3b", "$3c", "$3d", "$3e", "$3f"
|
||||||
};
|
};
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
const char* const CartDebug::ourIOMnemonic[24] = {
|
const char* const CartDebug::ourIOMnemonic[24] = {
|
||||||
"SWCHA", "SWACNT", "SWCHB", "SWBCNT", "INTIM", "TIMINT", 0, 0, 0, 0, 0,
|
"SWCHA", "SWACNT", "SWCHB", "SWBCNT", "INTIM", "TIMINT",
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, "TIM1T", "TIM8T", "TIM64T", "T1024T"
|
"$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 "Cart.hxx"
|
||||||
#include "DebuggerSystem.hxx"
|
#include "DebuggerSystem.hxx"
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
|
#include "M6502.hxx"
|
||||||
|
|
||||||
// Function type for CartDebug instance methods
|
// Function type for CartDebug instance methods
|
||||||
class CartDebug;
|
class CartDebug;
|
||||||
|
@ -38,10 +39,10 @@ using CartMethod = int (CartDebug::*)();
|
||||||
class CartState : public DebuggerState
|
class CartState : public DebuggerState
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ByteArray ram; // The actual data values
|
ByteArray ram; // The actual data values
|
||||||
IntArray rport; // Address for reading from RAM
|
ShortArray rport; // Address for reading from RAM
|
||||||
IntArray wport; // Address for writing to RAM
|
ShortArray wport; // Address for writing to RAM
|
||||||
string bank; // Current banking layout
|
string bank; // Current banking layout
|
||||||
};
|
};
|
||||||
|
|
||||||
class CartDebug : public DebuggerSystem
|
class CartDebug : public DebuggerSystem
|
||||||
|
@ -112,13 +113,6 @@ class CartDebug : public DebuggerSystem
|
||||||
CartDebugWidget* getDebugWidget() const { return myDebugWidget; }
|
CartDebugWidget* getDebugWidget() const { return myDebugWidget; }
|
||||||
void setDebugWidget(CartDebugWidget* w) { myDebugWidget = w; }
|
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
|
// Indicate that a read from write port has occurred at the specified
|
||||||
// address.
|
// address.
|
||||||
void triggerReadFromWritePort(uInt16 address);
|
void triggerReadFromWritePort(uInt16 address);
|
||||||
|
@ -127,6 +121,11 @@ class CartDebug : public DebuggerSystem
|
||||||
// write port area.
|
// write port area.
|
||||||
int readFromWritePort();
|
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
|
// The following two methods are meant to be used together
|
||||||
// First, a call is made to disassemble(), which updates the disassembly
|
// First, a call is made to disassemble(), which updates the disassembly
|
||||||
// list; it will figure out when an actual complete disassembly is
|
// 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 start; // start of address space
|
||||||
uInt16 end; // end of address space
|
uInt16 end; // end of address space
|
||||||
uInt16 offset; // ORG value
|
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
|
AddressList addressList; // addresses which PC has hit
|
||||||
DirectiveList directiveList; // overrides for automatic code determination
|
DirectiveList directiveList; // overrides for automatic code determination
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
#include "DebuggerDialog.hxx"
|
#include "DebuggerDialog.hxx"
|
||||||
#include "DebuggerParser.hxx"
|
#include "DebuggerParser.hxx"
|
||||||
#include "StateManager.hxx"
|
|
||||||
|
|
||||||
#include "Console.hxx"
|
#include "Console.hxx"
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
|
@ -58,58 +57,6 @@
|
||||||
|
|
||||||
Debugger* Debugger::myStaticDebugger = nullptr;
|
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)
|
Debugger::Debugger(OSystem& osystem, Console& console)
|
||||||
: DialogContainer(osystem),
|
: 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())
|
if(myOSystem.eventHandler().enterDebugMode())
|
||||||
{
|
{
|
||||||
|
@ -175,8 +122,7 @@ bool Debugger::start(const string& message, int address)
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
buf << message;
|
buf << message;
|
||||||
if(address > -1)
|
if(address > -1)
|
||||||
buf << Common::Base::HEX4 << address;
|
buf << cartDebug().getLabel(address, read, 4);
|
||||||
|
|
||||||
myDialog->message().setText(buf.str());
|
myDialog->message().setText(buf.str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -206,26 +152,26 @@ void Debugger::quit(bool exitrom)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
string Debugger::autoExec()
|
string Debugger::autoExec(StringList* history)
|
||||||
{
|
{
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
|
|
||||||
// autoexec.stella is always run
|
// autoexec.script is always run
|
||||||
FilesystemNode autoexec(myOSystem.baseDir() + "autoexec.stella");
|
FilesystemNode autoexec(myOSystem.baseDir() + "autoexec.script");
|
||||||
buf << "autoExec():" << endl
|
buf << "autoExec():" << endl
|
||||||
<< myParser->exec(autoexec) << endl;
|
<< myParser->exec(autoexec, history) << endl;
|
||||||
|
|
||||||
// Also, "romname.stella" if present
|
// Also, "romname.script" if present
|
||||||
FilesystemNode romname(myOSystem.romFile().getPathWithExt(".stella"));
|
FilesystemNode romname(myOSystem.romFile().getPathWithExt(".script"));
|
||||||
buf << myParser->exec(romname) << endl;
|
buf << myParser->exec(romname, history) << endl;
|
||||||
|
|
||||||
// Init builtins
|
// 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
|
// TODO - check this for memory leaks
|
||||||
int res = YaccParser::parse(builtin_functions[i][1]);
|
int res = YaccParser::parse(ourBuiltinFunctions[i].defn);
|
||||||
if(res == 0)
|
if(res == 0)
|
||||||
addFunction(builtin_functions[i][0], builtin_functions[i][1],
|
addFunction(ourBuiltinFunctions[i].name, ourBuiltinFunctions[i].defn,
|
||||||
YaccParser::getResult(), true);
|
YaccParser::getResult(), true);
|
||||||
else
|
else
|
||||||
cerr << "ERROR in builtin function!" << endl;
|
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().initialize();
|
||||||
readTraps().toggle(t);
|
readTraps().add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
void Debugger::addWriteTrap(uInt16 t)
|
||||||
void Debugger::toggleWriteTrap(uInt16 t)
|
|
||||||
{
|
{
|
||||||
writeTraps().initialize();
|
writeTraps().initialize();
|
||||||
writeTraps().toggle(t);
|
writeTraps().add(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Debugger::toggleTrap(uInt16 t)
|
void Debugger::addTrap(uInt16 t)
|
||||||
{
|
{
|
||||||
toggleReadTrap(t);
|
addReadTrap(t);
|
||||||
toggleWriteTrap(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);
|
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)
|
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();
|
RewindManager& r = myOSystem.state().rewindManager();
|
||||||
|
|
||||||
mySystem.clearDirtyPages();
|
mySystem.clearDirtyPages();
|
||||||
|
|
||||||
unlockBankswitchState();
|
unlockBankswitchState();
|
||||||
bool result = r.rewindState();
|
bool result = unwind ? r.unwindState() : r.rewindState();
|
||||||
lockBankswitchState();
|
lockBankswitchState();
|
||||||
|
|
||||||
myDialog->rewindButton().setEnabled(!r.empty());
|
updateRewindbuttons(r);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Debugger::rewindState()
|
||||||
|
{
|
||||||
|
return windState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool Debugger::unwindState()
|
||||||
|
{
|
||||||
|
return windState(true);
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Debugger::clearAllBreakPoints()
|
void Debugger::clearAllBreakPoints()
|
||||||
{
|
{
|
||||||
|
@ -495,7 +522,7 @@ void Debugger::saveOldState(string rewindMsg)
|
||||||
{
|
{
|
||||||
RewindManager& r = myOSystem.state().rewindManager();
|
RewindManager& r = myOSystem.state().rewindManager();
|
||||||
r.addState(rewindMsg);
|
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
|
// Lock the bus each time the debugger is entered, so we don't disturb anything
|
||||||
lockBankswitchState();
|
lockBankswitchState();
|
||||||
|
|
||||||
// If rewinding is not enabled, always start the debugger with a clean list
|
|
||||||
RewindManager& r = myOSystem.state().rewindManager();
|
RewindManager& r = myOSystem.state().rewindManager();
|
||||||
if(myOSystem.state().mode() == StateManager::Mode::Off)
|
updateRewindbuttons(r);
|
||||||
r.clear();
|
|
||||||
myDialog->rewindButton().setEnabled(!r.empty());
|
|
||||||
|
|
||||||
// Save initial state, but don't add it to the rewind list
|
// Save initial state, but don't add it to the rewind list
|
||||||
saveOldState();
|
saveOldState();
|
||||||
|
@ -524,6 +548,9 @@ void Debugger::setQuitState()
|
||||||
// Bus must be unlocked for normal operation when leaving debugger mode
|
// Bus must be unlocked for normal operation when leaving debugger mode
|
||||||
unlockBankswitchState();
|
unlockBankswitchState();
|
||||||
|
|
||||||
|
// Save state when leaving the debugger
|
||||||
|
saveOldState("exit debugger");
|
||||||
|
|
||||||
// execute one instruction on quit. If we're
|
// execute one instruction on quit. If we're
|
||||||
// sitting at a breakpoint/trap, this will get us past it.
|
// 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
|
// 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;
|
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)
|
bool Debugger::delFunction(const string& name)
|
||||||
{
|
{
|
||||||
|
@ -549,8 +585,7 @@ bool Debugger::delFunction(const string& name)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// We never want to delete built-in functions
|
// We never want to delete built-in functions
|
||||||
for(int i = 0; builtin_functions[i][0] != 0; ++i)
|
if(isBuiltinFunction(name))
|
||||||
if(name == builtin_functions[i][0])
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
myFunctions.erase(name);
|
myFunctions.erase(name);
|
||||||
|
@ -590,39 +625,39 @@ string Debugger::builtinHelp() const
|
||||||
uInt16 len, c_maxlen = 0, i_maxlen = 0;
|
uInt16 len, c_maxlen = 0, i_maxlen = 0;
|
||||||
|
|
||||||
// Get column widths for aligned output (functions)
|
// 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;
|
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;
|
if(len > i_maxlen) i_maxlen = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf << std::setfill(' ') << endl << "Built-in functions:" << endl;
|
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(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) << "}"
|
<< std::setw(4) << "}"
|
||||||
<< builtin_functions[i][2]
|
<< ourBuiltinFunctions[i].help
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get column widths for aligned output (pseudo-registers)
|
// Get column widths for aligned output (pseudo-registers)
|
||||||
c_maxlen = 0;
|
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;
|
if(len > c_maxlen) c_maxlen = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf << endl << "Pseudo-registers:" << endl;
|
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(2) << " "
|
||||||
<< std::setw(i_maxlen) << std::left << pseudo_registers[i][1]
|
<< std::setw(i_maxlen) << std::left << ourPseudoRegisters[i].help
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,16 +667,20 @@ string Debugger::builtinHelp() const
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Debugger::getCompletions(const char* in, StringList& list) 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();
|
for(const auto& iter : myFunctions)
|
||||||
if(BSPF::startsWithIgnoreCase(l, in))
|
{
|
||||||
list.push_back(l);
|
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)
|
for(uInt32 i = 0; i < NUM_PSEUDO_REGS; ++i)
|
||||||
if(BSPF::startsWithIgnoreCase(pseudo_registers[i][0], in))
|
if(BSPF::matches(ourPseudoRegisters[i].name, in))
|
||||||
list.push_back(pseudo_registers[i][0]);
|
list.push_back(ourPseudoRegisters[i].name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -657,3 +696,49 @@ void Debugger::unlockBankswitchState()
|
||||||
mySystem.unlockDataBus();
|
mySystem.unlockDataBus();
|
||||||
myConsole.cartridge().unlockBank();
|
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 "DialogContainer.hxx"
|
||||||
#include "DebuggerDialog.hxx"
|
#include "DebuggerDialog.hxx"
|
||||||
#include "DebuggerParser.hxx"
|
#include "DebuggerParser.hxx"
|
||||||
|
#include "StateManager.hxx"
|
||||||
#include "M6502.hxx"
|
#include "M6502.hxx"
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
#include "Stack.hxx"
|
#include "Stack.hxx"
|
||||||
|
@ -88,7 +89,7 @@ class Debugger : public DialogContainer
|
||||||
@param message Message to display when entering debugger
|
@param message Message to display when entering debugger
|
||||||
@param address An address associated with the message
|
@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 = "");
|
bool startWithFatalError(const string& message = "");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,6 +100,7 @@ class Debugger : public DialogContainer
|
||||||
|
|
||||||
bool addFunction(const string& name, const string& def,
|
bool addFunction(const string& name, const string& def,
|
||||||
Expression* exp, bool builtin = false);
|
Expression* exp, bool builtin = false);
|
||||||
|
bool isBuiltinFunction(const string& name);
|
||||||
bool delFunction(const string& name);
|
bool delFunction(const string& name);
|
||||||
const Expression& getFunction(const string& name) const;
|
const Expression& getFunction(const string& name) const;
|
||||||
|
|
||||||
|
@ -145,15 +147,15 @@ class Debugger : public DialogContainer
|
||||||
TiaOutputWidget& tiaOutput() const { return myDialog->tiaOutput(); }
|
TiaOutputWidget& tiaOutput() const { return myDialog->tiaOutput(); }
|
||||||
|
|
||||||
PackedBitArray& breakPoints() const { return mySystem.m6502().breakPoints(); }
|
PackedBitArray& breakPoints() const { return mySystem.m6502().breakPoints(); }
|
||||||
PackedBitArray& readTraps() const { return mySystem.m6502().readTraps(); }
|
TrapArray& readTraps() const { return mySystem.m6502().readTraps(); }
|
||||||
PackedBitArray& writeTraps() const { return mySystem.m6502().writeTraps(); }
|
TrapArray& writeTraps() const { return mySystem.m6502().writeTraps(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Run the debugger command and return the result.
|
Run the debugger command and return the result.
|
||||||
*/
|
*/
|
||||||
const string run(const string& command);
|
const string run(const string& command);
|
||||||
|
|
||||||
string autoExec();
|
string autoExec(StringList* history);
|
||||||
|
|
||||||
string showWatches();
|
string showWatches();
|
||||||
|
|
||||||
|
@ -168,9 +170,9 @@ class Debugger : public DialogContainer
|
||||||
static uInt8 set_bit(uInt8 input, uInt8 bit, bool on)
|
static uInt8 set_bit(uInt8 input, uInt8 bit, bool on)
|
||||||
{
|
{
|
||||||
if(on)
|
if(on)
|
||||||
return input | (1 << bit);
|
return uInt8(input | (1 << bit));
|
||||||
else
|
else
|
||||||
return input & ~(1 << bit);
|
return uInt8(input & ~(1 << bit));
|
||||||
}
|
}
|
||||||
static void set_bits(uInt8 reg, BoolArray& bits)
|
static void set_bits(uInt8 reg, BoolArray& bits)
|
||||||
{
|
{
|
||||||
|
@ -192,7 +194,7 @@ class Debugger : public DialogContainer
|
||||||
return result;
|
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);
|
const string invIfChanged(int reg, int oldReg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,15 +207,32 @@ class Debugger : public DialogContainer
|
||||||
*/
|
*/
|
||||||
static Debugger& debugger() { return *myStaticDebugger; }
|
static Debugger& debugger() { return *myStaticDebugger; }
|
||||||
|
|
||||||
/* These are now exposed so Expressions can use them. */
|
/** Convenience methods to access peek/poke from System */
|
||||||
int peek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags); }
|
uInt8 peek(uInt16 addr, uInt8 flags = 0) {
|
||||||
int dpeek(int addr, uInt8 flags = 0) { return mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8); }
|
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
|
int getAccessFlags(uInt16 addr) const
|
||||||
{ return mySystem.getAccessFlags(addr); }
|
{ return mySystem.getAccessFlags(addr); }
|
||||||
void setAccessFlags(uInt16 addr, uInt8 flags)
|
void setAccessFlags(uInt16 addr, uInt8 flags)
|
||||||
{ mySystem.setAccessFlags(addr, flags); }
|
{ mySystem.setAccessFlags(addr, flags); }
|
||||||
|
|
||||||
void setBreakPoint(uInt16 bp, bool set);
|
void setBreakPoint(uInt16 bp, bool set);
|
||||||
|
uInt32 getBaseAddress(uInt32 addr, bool read);
|
||||||
|
|
||||||
bool patchROM(uInt16 addr, uInt8 value);
|
bool patchROM(uInt16 addr, uInt8 value);
|
||||||
|
|
||||||
|
@ -252,13 +271,17 @@ class Debugger : public DialogContainer
|
||||||
void nextScanline(int lines);
|
void nextScanline(int lines);
|
||||||
void nextFrame(int frames);
|
void nextFrame(int frames);
|
||||||
bool rewindState();
|
bool rewindState();
|
||||||
|
bool unwindState();
|
||||||
|
|
||||||
void toggleBreakPoint(uInt16 bp);
|
void toggleBreakPoint(uInt16 bp);
|
||||||
|
|
||||||
bool breakPoint(uInt16 bp);
|
bool breakPoint(uInt16 bp);
|
||||||
void toggleReadTrap(uInt16 t);
|
void addReadTrap(uInt16 t);
|
||||||
void toggleWriteTrap(uInt16 t);
|
void addWriteTrap(uInt16 t);
|
||||||
void toggleTrap(uInt16 t);
|
void addTrap(uInt16 t);
|
||||||
|
void removeReadTrap(uInt16 t);
|
||||||
|
void removeWriteTrap(uInt16 t);
|
||||||
|
void removeTrap(uInt16 t);
|
||||||
bool readTrap(uInt16 t);
|
bool readTrap(uInt16 t);
|
||||||
bool writeTrap(uInt16 t);
|
bool writeTrap(uInt16 t);
|
||||||
void clearAllTraps();
|
void clearAllTraps();
|
||||||
|
@ -292,7 +315,24 @@ class Debugger : public DialogContainer
|
||||||
uInt32 myWidth;
|
uInt32 myWidth;
|
||||||
uInt32 myHeight;
|
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:
|
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
|
// Following constructors and assignment operators not supported
|
||||||
Debugger() = delete;
|
Debugger() = delete;
|
||||||
Debugger(const Debugger&) = delete;
|
Debugger(const Debugger&) = delete;
|
||||||
|
|
|
@ -337,7 +337,7 @@ class WordDerefExpression : public Expression
|
||||||
public:
|
public:
|
||||||
WordDerefExpression(Expression* left) : Expression(left) { }
|
WordDerefExpression(Expression* left) : Expression(left) { }
|
||||||
Int32 evaluate() const override
|
Int32 evaluate() const override
|
||||||
{ return Debugger::debugger().dpeek(myLHS->evaluate()); }
|
{ return Debugger::debugger().dpeekAsInt(myLHS->evaluate()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -110,7 +110,10 @@ string DebuggerParser::run(const string& command)
|
||||||
if(BSPF::equalsIgnoreCase(verb, commands[i].cmdString))
|
if(BSPF::equalsIgnoreCase(verb, commands[i].cmdString))
|
||||||
{
|
{
|
||||||
if(validateArgs(i))
|
if(validateArgs(i))
|
||||||
|
{
|
||||||
|
myCommand = i;
|
||||||
commands[i].executor(this);
|
commands[i].executor(this);
|
||||||
|
}
|
||||||
|
|
||||||
if(commands[i].refreshRequired)
|
if(commands[i].refreshRequired)
|
||||||
debugger.myBaseDialog->loadConfig();
|
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())
|
if(file.exists())
|
||||||
{
|
{
|
||||||
ifstream in(file.getPath());
|
ifstream in(file.getPath());
|
||||||
if(!in.is_open())
|
if(!in.is_open())
|
||||||
return red("autoexec file \'" + file.getShortPath() + "\' not found");
|
return red("script file \'" + file.getShortPath() + "\' not found");
|
||||||
|
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -140,15 +143,27 @@ string DebuggerParser::exec(const FilesystemNode& file)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
run(command);
|
run(command);
|
||||||
|
if (history != nullptr)
|
||||||
|
history->push_back(command);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
buf << "Executed " << count << " commands from \""
|
buf << "\nExecuted " << count << " commands from \""
|
||||||
<< file.getShortPath() << "\"";
|
<< file.getShortPath() << "\"";
|
||||||
|
|
||||||
return buf.str();
|
return buf.str();
|
||||||
}
|
}
|
||||||
else
|
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;
|
// cerr << "Attempting to complete \"" << in << "\"" << endl;
|
||||||
for(int i = 0; i < kNumCommands; ++i)
|
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);
|
completions.push_back(commands[i].cmdString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,7 +411,8 @@ bool DebuggerParser::validateArgs(int cmd)
|
||||||
{
|
{
|
||||||
if(required)
|
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.
|
return false; // needed args. didn't get 'em.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -427,6 +443,14 @@ bool DebuggerParser::validateArgs(int cmd)
|
||||||
|
|
||||||
switch(*p)
|
switch(*p)
|
||||||
{
|
{
|
||||||
|
case kARG_DWORD:
|
||||||
|
if(curArgInt > 0xffffffff)
|
||||||
|
{
|
||||||
|
commandResult.str(red("invalid word argument (must be 0-$ffffffff)"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case kARG_WORD:
|
case kARG_WORD:
|
||||||
if(curArgInt > 0xffff)
|
if(curArgInt > 0xffff)
|
||||||
{
|
{
|
||||||
|
@ -484,12 +508,14 @@ cerr << "curCount = " << curCount << endl
|
||||||
|
|
||||||
if(curCount < argRequiredCount)
|
if(curCount < argRequiredCount)
|
||||||
{
|
{
|
||||||
commandResult.str(red("missing required argument(s)"));
|
commandResult.str();
|
||||||
|
outputCommandError("missing required argument(s)", cmd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if(argCount > curCount)
|
else if(argCount > curCount)
|
||||||
{
|
{
|
||||||
commandResult.str(red("too many arguments"));
|
commandResult.str();
|
||||||
|
outputCommandError("too many arguments", cmd);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,28 +528,29 @@ string DebuggerParser::eval()
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
for(uInt32 i = 0; i < argCount; ++i)
|
for(uInt32 i = 0; i < argCount; ++i)
|
||||||
{
|
{
|
||||||
string rlabel = debugger.cartDebug().getLabel(args[i], true);
|
if(args[i] < 0x10000)
|
||||||
string wlabel = debugger.cartDebug().getLabel(args[i], false);
|
|
||||||
bool validR = rlabel != "" && rlabel[0] != '$',
|
|
||||||
validW = wlabel != "" && wlabel[0] != '$';
|
|
||||||
if(validR && validW)
|
|
||||||
{
|
{
|
||||||
if(rlabel == wlabel)
|
string rlabel = debugger.cartDebug().getLabel(args[i], true);
|
||||||
buf << rlabel << "(R/W): ";
|
string wlabel = debugger.cartDebug().getLabel(args[i], false);
|
||||||
else
|
bool validR = rlabel != "" && rlabel[0] != '$',
|
||||||
buf << rlabel << "(R) / " << wlabel << "(W): ";
|
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);
|
||||||
buf << "$" << Base::toString(args[i], Base::F_16_2)
|
|
||||||
<< " %" << Base::toString(args[i], Base::F_2_8);
|
if(args[i] < 0x10000)
|
||||||
else
|
buf << " %" << Base::toString(args[i], Base::F_2);
|
||||||
buf << "$" << Base::toString(args[i], Base::F_16_4)
|
|
||||||
<< " %" << Base::toString(args[i], Base::F_2_16);
|
|
||||||
|
|
||||||
buf << " #" << int(args[i]);
|
buf << " #" << int(args[i]);
|
||||||
if(i != argCount - 1)
|
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;
|
StringList names = debugger.cpuDebug().m6502().getCondTrapNames();
|
||||||
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";
|
|
||||||
|
|
||||||
const string& l = debugger.cartDebug().getLabel(addr, !w);
|
commandResult << (listCond ? "trapifs:" : "traps:") << endl;
|
||||||
if(l != "") {
|
for(uInt32 i = 0; i < names.size(); i++)
|
||||||
result += " (";
|
{
|
||||||
result += l;
|
bool hasCond = names[i] != "";
|
||||||
result += ")";
|
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 )
|
stringstream result;
|
||||||
file += ".stella";
|
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();
|
FunctionDefMap funcs = debugger.getFunctionDefMap();
|
||||||
for(const auto& f: funcs)
|
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)
|
for(const auto& w: myWatches)
|
||||||
out << "watch " << w << endl;
|
out << "watch " << w << endl;
|
||||||
|
|
||||||
for(uInt32 i = 0; i < 0x10000; ++i)
|
for(uInt32 i = 0; i < 0x10000; ++i)
|
||||||
if(debugger.breakPoint(i))
|
if(debugger.breakPoint(i))
|
||||||
out << "break #" << i << endl;
|
out << "break " << Base::toString(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringList conds = debugger.cpuDebug().m6502().getCondBreakNames();
|
StringList conds = debugger.cpuDebug().m6502().getCondBreakNames();
|
||||||
for(const auto& cond: conds)
|
for(const auto& cond : conds)
|
||||||
out << "breakif {" << cond << "}" << endl;
|
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
|
#ifdef CHEATCODE_SUPPORT
|
||||||
if(argCount == 0)
|
if(argCount == 0)
|
||||||
{
|
{
|
||||||
commandResult << red("Missing cheat code");
|
outputCommandError("missing cheat code", myCommand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -705,7 +779,7 @@ void DebuggerParser::executeCheat()
|
||||||
if(debugger.myOSystem.cheat().add("DBG", cheat))
|
if(debugger.myOSystem.cheat().add("DBG", cheat))
|
||||||
commandResult << "Cheat code " << cheat << " enabled" << endl;
|
commandResult << "Cheat code " << cheat << " enabled" << endl;
|
||||||
else
|
else
|
||||||
commandResult << red("Invalid cheat code ") << cheat << endl;
|
commandResult << red("invalid cheat code ") << cheat << endl;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
commandResult << red("Cheat support not enabled\n");
|
commandResult << red("Cheat support not enabled\n");
|
||||||
|
@ -735,8 +809,9 @@ void DebuggerParser::executeClearconfig()
|
||||||
// "cleartraps"
|
// "cleartraps"
|
||||||
void DebuggerParser::executeCleartraps()
|
void DebuggerParser::executeCleartraps()
|
||||||
{
|
{
|
||||||
myTraps.clear();
|
|
||||||
debugger.clearAllTraps();
|
debugger.clearAllTraps();
|
||||||
|
debugger.cpuDebug().m6502().clearCondTraps();
|
||||||
|
myTraps.clear();
|
||||||
commandResult << "all traps cleared";
|
commandResult << "all traps cleared";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -762,12 +837,12 @@ void DebuggerParser::executeCode()
|
||||||
{
|
{
|
||||||
if(argCount != 2)
|
if(argCount != 2)
|
||||||
{
|
{
|
||||||
commandResult << red("Specify start and end of range only");
|
outputCommandError("specify start and end of range only", myCommand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(args[1] < args[0])
|
else if(args[1] < args[0])
|
||||||
{
|
{
|
||||||
commandResult << red("Start address must be <= end address");
|
commandResult << red("start address must be <= end address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,12 +878,12 @@ void DebuggerParser::executeData()
|
||||||
{
|
{
|
||||||
if(argCount != 2)
|
if(argCount != 2)
|
||||||
{
|
{
|
||||||
commandResult << red("Specify start and end of range only");
|
outputCommandError("specify start and end of range only", myCommand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(args[1] < args[0])
|
else if(args[1] < args[0])
|
||||||
{
|
{
|
||||||
commandResult << red("Start address must be <= end address");
|
commandResult << red("start address must be <= end address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,7 +914,10 @@ void DebuggerParser::executeDefine()
|
||||||
// "delbreakif"
|
// "delbreakif"
|
||||||
void DebuggerParser::executeDelbreakif()
|
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";
|
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"
|
// "delwatch"
|
||||||
void DebuggerParser::executeDelwatch()
|
void DebuggerParser::executeDelwatch()
|
||||||
|
@ -863,7 +959,7 @@ void DebuggerParser::executeDelwatch()
|
||||||
commandResult << "removed watch";
|
commandResult << "removed watch";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
commandResult << "no such watch";
|
commandResult << red("no such watch");
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -880,7 +976,7 @@ void DebuggerParser::executeDisasm()
|
||||||
start = args[0];
|
start = args[0];
|
||||||
lines = args[1];
|
lines = args[1];
|
||||||
} else {
|
} else {
|
||||||
commandResult << "wrong number of arguments";
|
outputCommandError("wrong number of arguments", myCommand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -910,7 +1006,7 @@ void DebuggerParser::executeDump()
|
||||||
// Error checking
|
// Error checking
|
||||||
if(argCount > 1 && args[1] < args[0])
|
if(argCount > 1 && args[1] < args[0])
|
||||||
{
|
{
|
||||||
commandResult << red("Start address must be <= end address");
|
commandResult << red("start address must be <= end address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -920,7 +1016,7 @@ void DebuggerParser::executeDump()
|
||||||
dump(args[0], args[1]);
|
dump(args[0], args[1]);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
commandResult << "wrong number of arguments";
|
outputCommandError("wrong number of arguments", myCommand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -929,8 +1025,13 @@ void DebuggerParser::executeDump()
|
||||||
// "exec"
|
// "exec"
|
||||||
void DebuggerParser::executeExec()
|
void DebuggerParser::executeExec()
|
||||||
{
|
{
|
||||||
FilesystemNode file(argStrings[0]);
|
// Append 'script' extension when necessary
|
||||||
commandResult << exec(file);
|
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)
|
if(argCount != 2)
|
||||||
{
|
{
|
||||||
commandResult << red("Specify start and end of range only");
|
outputCommandError("specify start and end of range only", myCommand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(args[1] < args[0])
|
else if(args[1] < args[0])
|
||||||
{
|
{
|
||||||
commandResult << red("Start address must be <= end address");
|
commandResult << red("start address must be <= end address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1061,26 +1162,21 @@ void DebuggerParser::executeListbreaks()
|
||||||
if(debugger.breakPoints().isSet(i))
|
if(debugger.breakPoints().isSet(i))
|
||||||
{
|
{
|
||||||
buf << debugger.cartDebug().getLabel(i, true, 4) << " ";
|
buf << debugger.cartDebug().getLabel(i, true, 4) << " ";
|
||||||
if(! (++count % 8) ) buf << "\n";
|
if(! (++count % 8) ) buf << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if(count)
|
if(count)
|
||||||
return ret;
|
commandResult << "breaks:" << endl << buf.str();
|
||||||
else
|
|
||||||
return "no breakpoints set";
|
|
||||||
*/
|
|
||||||
if(count)
|
|
||||||
commandResult << "breaks:\n" << buf.str();
|
|
||||||
|
|
||||||
StringList conds = debugger.cpuDebug().m6502().getCondBreakNames();
|
StringList conds = debugger.cpuDebug().m6502().getCondBreakNames();
|
||||||
if(conds.size() > 0)
|
if(conds.size() > 0)
|
||||||
{
|
{
|
||||||
commandResult << "\nbreakifs:\n";
|
if(count)
|
||||||
|
commandResult << endl;
|
||||||
|
commandResult << "breakifs:" << endl;
|
||||||
for(uInt32 i = 0; i < conds.size(); i++)
|
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;
|
if(i != (conds.size() - 1)) commandResult << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1118,11 +1214,27 @@ void DebuggerParser::executeListfunctions()
|
||||||
// "listtraps"
|
// "listtraps"
|
||||||
void DebuggerParser::executeListtraps()
|
void DebuggerParser::executeListtraps()
|
||||||
{
|
{
|
||||||
if(myTraps.size() > 0)
|
StringList names = debugger.cpuDebug().m6502().getCondTrapNames();
|
||||||
|
|
||||||
|
if(myTraps.size() != names.size())
|
||||||
{
|
{
|
||||||
bool enabled = true;
|
commandResult << "Internal error! Different trap sizes.";
|
||||||
for(const auto& trap: myTraps)
|
return;
|
||||||
commandResult << trapStatus(trap, enabled) << " + mirrors" << endl;
|
}
|
||||||
|
|
||||||
|
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
|
else
|
||||||
commandResult << "no traps set";
|
commandResult << "no traps set";
|
||||||
|
@ -1175,12 +1287,12 @@ void DebuggerParser::executePGfx()
|
||||||
{
|
{
|
||||||
if(argCount != 2)
|
if(argCount != 2)
|
||||||
{
|
{
|
||||||
commandResult << red("Specify start and end of range only");
|
outputCommandError("specify start and end of range only", myCommand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(args[1] < args[0])
|
else if(args[1] < args[0])
|
||||||
{
|
{
|
||||||
commandResult << red("Start address must be <= end address");
|
commandResult << red("start address must be <= end address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1267,12 +1379,12 @@ void DebuggerParser::executeRow()
|
||||||
{
|
{
|
||||||
if(argCount != 2)
|
if(argCount != 2)
|
||||||
{
|
{
|
||||||
commandResult << red("Specify start and end of range only");
|
outputCommandError("specify start and end of range only", myCommand);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(args[1] < args[0])
|
else if(args[1] < args[0])
|
||||||
{
|
{
|
||||||
commandResult << red("Start address must be <= end address");
|
commandResult << red("start address must be <= end address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1373,10 +1485,7 @@ void DebuggerParser::executeS()
|
||||||
// "save"
|
// "save"
|
||||||
void DebuggerParser::executeSave()
|
void DebuggerParser::executeSave()
|
||||||
{
|
{
|
||||||
if(saveScriptFile(argStrings[0]))
|
commandResult << saveScriptFile(argStrings[0]);
|
||||||
commandResult << "saved script to file " << argStrings[0];
|
|
||||||
else
|
|
||||||
commandResult << red("I/O error");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -1473,71 +1582,153 @@ void DebuggerParser::executeTrace()
|
||||||
// "trap"
|
// "trap"
|
||||||
void DebuggerParser::executeTrap()
|
void DebuggerParser::executeTrap()
|
||||||
{
|
{
|
||||||
if(argCount > 2)
|
executeTraps(true, true, "trap");
|
||||||
{
|
}
|
||||||
commandResult << red("Command takes one or two arguments") << endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uInt32 beg = args[0];
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt32 end = argCount == 2 ? args[1] : beg;
|
// "trapif"
|
||||||
if(beg > 0xFFFF || end > 0xFFFF)
|
void DebuggerParser::executeTrapif()
|
||||||
{
|
{
|
||||||
commandResult << red("One or more addresses are invalid") << endl;
|
executeTraps(true, true, "trapif", true);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(uInt32 addr = beg; addr <= end; ++addr)
|
|
||||||
executeTrapRW(addr, true, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// "trapread"
|
// "trapread"
|
||||||
void DebuggerParser::executeTrapread()
|
void DebuggerParser::executeTrapread()
|
||||||
{
|
{
|
||||||
if(argCount > 2)
|
executeTraps(true, false, "trapread");
|
||||||
{
|
}
|
||||||
commandResult << red("Command takes one or two arguments") << endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uInt32 beg = args[0];
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt32 end = argCount == 2 ? args[1] : beg;
|
// "trapreadif"
|
||||||
if(beg > 0xFFFF || end > 0xFFFF)
|
void DebuggerParser::executeTrapreadif()
|
||||||
{
|
{
|
||||||
commandResult << red("One or more addresses are invalid") << endl;
|
executeTraps(true, false, "trapreadif", true);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(uInt32 addr = beg; addr <= end; ++addr)
|
|
||||||
executeTrapRW(addr, true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// "trapwrite"
|
// "trapwrite"
|
||||||
void DebuggerParser::executeTrapwrite()
|
void DebuggerParser::executeTrapwrite()
|
||||||
{
|
{
|
||||||
if(argCount > 2)
|
executeTraps(false, true, "trapwrite");
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// wrapper function for trap/trapread/trapwrite commands
|
// "trapwriteif"
|
||||||
void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
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))
|
switch(debugger.cartDebug().addressType(addr))
|
||||||
{
|
{
|
||||||
|
@ -1547,10 +1738,11 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||||
{
|
{
|
||||||
if((i & 0x1080) == 0x0000)
|
if((i & 0x1080) == 0x0000)
|
||||||
{
|
{
|
||||||
if(read && (i & 0x000F) == addr)
|
// @sa666666: This seems wrong. E.g. trapread 40 4f will never trigger
|
||||||
debugger.toggleReadTrap(i);
|
if(read && (i & 0x000F) == (addr & 0x000F))
|
||||||
if(write && (i & 0x003F) == addr)
|
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||||
debugger.toggleWriteTrap(i);
|
if(write && (i & 0x003F) == (addr & 0x003F))
|
||||||
|
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1559,10 +1751,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||||
{
|
{
|
||||||
for(uInt32 i = 0; i <= 0xFFFF; ++i)
|
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(read)
|
||||||
if(write) debugger.toggleWriteTrap(i);
|
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||||
|
if(write)
|
||||||
|
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1571,10 +1765,12 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||||
{
|
{
|
||||||
for(uInt32 i = 0; i <= 0xFFFF; ++i)
|
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(read)
|
||||||
if(write) debugger.toggleWriteTrap(i);
|
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||||
|
if(write)
|
||||||
|
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1587,21 +1783,16 @@ void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write)
|
||||||
{
|
{
|
||||||
if((i % 0x2000 >= 0x1000) && (i & 0x0FFF) == (addr & 0x0FFF))
|
if((i % 0x2000 >= 0x1000) && (i & 0x0FFF) == (addr & 0x0FFF))
|
||||||
{
|
{
|
||||||
if(read) debugger.toggleReadTrap(i);
|
if(read)
|
||||||
if(write) debugger.toggleWriteTrap(i);
|
add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i);
|
||||||
|
if(write)
|
||||||
|
add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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");
|
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"
|
// "v"
|
||||||
void DebuggerParser::executeV()
|
void DebuggerParser::executeV()
|
||||||
|
@ -1688,7 +1892,6 @@ void DebuggerParser::executeZ()
|
||||||
debugger.cpuDebug().setZ(args[0]);
|
debugger.cpuDebug().setZ(args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
// List of all commands available to the parser
|
// List of all commands available to the parser
|
||||||
DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
|
@ -1883,6 +2086,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
std::mem_fn(&DebuggerParser::executeDelfunction)
|
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",
|
"delwatch",
|
||||||
"Delete watch <xx>",
|
"Delete watch <xx>",
|
||||||
|
@ -1907,7 +2120,7 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
{
|
{
|
||||||
"dump",
|
"dump",
|
||||||
"Dump data at address <xx> [to yy]",
|
"Dump data at address <xx> [to yy]",
|
||||||
"Examples:\n"
|
"Example:\n"
|
||||||
" dump f000 - dumps 128 bytes @ f000\n"
|
" dump f000 - dumps 128 bytes @ f000\n"
|
||||||
" dump f000 f0ff - dumps all bytes from f000 to f0ff",
|
" dump f000 f0ff - dumps all bytes from f000 to f0ff",
|
||||||
true,
|
true,
|
||||||
|
@ -1949,7 +2162,7 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
{
|
{
|
||||||
"function",
|
"function",
|
||||||
"Define function name xx for expression yy",
|
"Define function name xx for expression yy",
|
||||||
"Example: define FUNC1 { ... }",
|
"Example: function FUNC1 { ... }",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
{ kARG_LABEL, kARG_WORD, kARG_END_ARGS },
|
{ kARG_LABEL, kARG_WORD, kARG_END_ARGS },
|
||||||
|
@ -2094,7 +2307,7 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
"Example: print pc, print f000",
|
"Example: print pc, print f000",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
{ kARG_WORD, kARG_END_ARGS },
|
{ kARG_DWORD, kARG_END_ARGS },
|
||||||
std::mem_fn(&DebuggerParser::executePrint)
|
std::mem_fn(&DebuggerParser::executePrint)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2325,6 +2538,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
std::mem_fn(&DebuggerParser::executeTrap)
|
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",
|
"trapread",
|
||||||
"Trap read access to address(es) xx [yy]",
|
"Trap read access to address(es) xx [yy]",
|
||||||
|
@ -2336,6 +2560,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
std::mem_fn(&DebuggerParser::executeTrapread)
|
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",
|
"trapwrite",
|
||||||
"Trap write access to address(es) xx [yy]",
|
"Trap write access to address(es) xx [yy]",
|
||||||
|
@ -2347,6 +2582,17 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
std::mem_fn(&DebuggerParser::executeTrapwrite)
|
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",
|
"type",
|
||||||
"Show disassembly type for address xx [yy]",
|
"Show disassembly type for address xx [yy]",
|
||||||
|
@ -2378,6 +2624,16 @@ DebuggerParser::Command DebuggerParser::commands[kNumCommands] = {
|
||||||
std::mem_fn(&DebuggerParser::executeUndef)
|
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",
|
"v",
|
||||||
"Overflow Flag: set (0 or 1), or toggle (no arg)",
|
"Overflow Flag: set (0 or 1), or toggle (no arg)",
|
||||||
|
|
|
@ -39,7 +39,7 @@ class DebuggerParser
|
||||||
string run(const string& command);
|
string run(const string& command);
|
||||||
|
|
||||||
/** Execute parser commands given in 'file' */
|
/** 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
|
/** Given a substring, determine matching substrings from the list
|
||||||
of available commands. Used in the debugger prompt for tab-completion */
|
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 getArgs(const string& command, string& verb);
|
||||||
bool validateArgs(int cmd);
|
bool validateArgs(int cmd);
|
||||||
string eval();
|
string eval();
|
||||||
bool saveScriptFile(string file);
|
string saveScriptFile(string file);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum { kNumCommands = 72 };
|
enum { kNumCommands = 77 };
|
||||||
|
|
||||||
// Constants for argument processing
|
// Constants for argument processing
|
||||||
enum {
|
enum {
|
||||||
|
@ -80,6 +80,7 @@ class DebuggerParser
|
||||||
|
|
||||||
enum parameters {
|
enum parameters {
|
||||||
kARG_WORD, // single 16-bit value
|
kARG_WORD, // single 16-bit value
|
||||||
|
kARG_DWORD, // single 32-bit value
|
||||||
kARG_MULTI_WORD, // multiple 16-bit values (must occur last)
|
kARG_MULTI_WORD, // multiple 16-bit values (must occur last)
|
||||||
kARG_BYTE, // single 8-bit value
|
kARG_BYTE, // single 8-bit value
|
||||||
kARG_MULTI_BYTE, // multiple 8-bit values (must occur last)
|
kARG_MULTI_BYTE, // multiple 8-bit values (must occur last)
|
||||||
|
@ -99,6 +100,14 @@ class DebuggerParser
|
||||||
parameters parms[10];
|
parameters parms[10];
|
||||||
std::function<void (DebuggerParser*)> executor;
|
std::function<void (DebuggerParser*)> executor;
|
||||||
};
|
};
|
||||||
|
struct Trap
|
||||||
|
{
|
||||||
|
bool read;
|
||||||
|
bool write;
|
||||||
|
uInt32 begin;
|
||||||
|
uInt32 end;
|
||||||
|
string condition;
|
||||||
|
};
|
||||||
|
|
||||||
// Reference to our debugger object
|
// Reference to our debugger object
|
||||||
Debugger& debugger;
|
Debugger& debugger;
|
||||||
|
@ -109,6 +118,8 @@ class DebuggerParser
|
||||||
// The results of the currently running command
|
// The results of the currently running command
|
||||||
ostringstream commandResult;
|
ostringstream commandResult;
|
||||||
|
|
||||||
|
// currently execute command id
|
||||||
|
int myCommand;
|
||||||
// Arguments in 'int' and 'string' format for the currently running command
|
// Arguments in 'int' and 'string' format for the currently running command
|
||||||
IntArray args;
|
IntArray args;
|
||||||
StringList argStrings;
|
StringList argStrings;
|
||||||
|
@ -117,8 +128,12 @@ class DebuggerParser
|
||||||
StringList myWatches;
|
StringList myWatches;
|
||||||
|
|
||||||
// Keep track of traps (read and/or write)
|
// Keep track of traps (read and/or write)
|
||||||
std::set<uInt32> myTraps;
|
vector<unique_ptr<Trap>> myTraps;
|
||||||
string trapStatus(uInt32 addr, bool& enabled);
|
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
|
// List of available command methods
|
||||||
void executeA();
|
void executeA();
|
||||||
|
@ -140,6 +155,7 @@ class DebuggerParser
|
||||||
void executeDefine();
|
void executeDefine();
|
||||||
void executeDelbreakif();
|
void executeDelbreakif();
|
||||||
void executeDelfunction();
|
void executeDelfunction();
|
||||||
|
void executeDeltrap();
|
||||||
void executeDelwatch();
|
void executeDelwatch();
|
||||||
void executeDisasm();
|
void executeDisasm();
|
||||||
void executeDump();
|
void executeDump();
|
||||||
|
@ -183,12 +199,17 @@ class DebuggerParser
|
||||||
void executeTia();
|
void executeTia();
|
||||||
void executeTrace();
|
void executeTrace();
|
||||||
void executeTrap();
|
void executeTrap();
|
||||||
|
void executeTrapif();
|
||||||
void executeTrapread();
|
void executeTrapread();
|
||||||
|
void executeTrapreadif();
|
||||||
void executeTrapwrite();
|
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 executeType();
|
||||||
void executeUHex();
|
void executeUHex();
|
||||||
void executeUndef();
|
void executeUndef();
|
||||||
|
void executeUnwind();
|
||||||
void executeV();
|
void executeV();
|
||||||
void executeWatch();
|
void executeWatch();
|
||||||
void executeX();
|
void executeX();
|
||||||
|
|
|
@ -120,6 +120,12 @@ void DiStella::disasm(uInt32 distart, int pass)
|
||||||
myPC = distart - myOffset;
|
myPC = distart - myOffset;
|
||||||
while (myPC <= myAppData.end) {
|
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,
|
if (checkBits(myPC, CartDebug::GFX | CartDebug::PGFX,
|
||||||
CartDebug::CODE)) {
|
CartDebug::CODE)) {
|
||||||
if (pass == 2)
|
if (pass == 2)
|
||||||
|
@ -137,6 +143,7 @@ void DiStella::disasm(uInt32 distart, int pass)
|
||||||
myPC++;
|
myPC++;
|
||||||
} else if (checkBits(myPC, CartDebug::ROW,
|
} else if (checkBits(myPC, CartDebug::ROW,
|
||||||
CartDebug::CODE | CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) {
|
CartDebug::CODE | CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) {
|
||||||
|
FIX_LAST:
|
||||||
if (pass == 2)
|
if (pass == 2)
|
||||||
mark(myPC + myOffset, CartDebug::VALID_ENTRY);
|
mark(myPC + myOffset, CartDebug::VALID_ENTRY);
|
||||||
|
|
||||||
|
@ -713,6 +720,7 @@ void DiStella::disasmFromAddress(uInt32 distart)
|
||||||
myPCEnd = myAppData.end + myOffset;
|
myPCEnd = myAppData.end + myOffset;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
break; // TODO - is this the intent?
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -349,8 +349,8 @@ bool TIADebug::collision(CollisionBit id) const
|
||||||
case Cx_BLPF: return myTIA.collCXBLPF() & 0x80;
|
case Cx_BLPF: return myTIA.collCXBLPF() & 0x80;
|
||||||
case Cx_P0P1: return myTIA.collCXPPMM() & 0x80;
|
case Cx_P0P1: return myTIA.collCXPPMM() & 0x80;
|
||||||
case Cx_M0M1: return myTIA.collCXPPMM() & 0x40;
|
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
|
int TIADebug::cyclesLo() const
|
||||||
{
|
{
|
||||||
return (int)myTIA.cycles();
|
return int(myTIA.cycles());
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
int TIADebug::cyclesHi() const
|
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();
|
return myTIA.clocksThisLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
int TIADebug::cyclesThisLine() const
|
||||||
|
{
|
||||||
|
return myTIA.clocksThisLine()/3;
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
bool TIADebug::vsync() const
|
bool TIADebug::vsync() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -163,6 +163,7 @@ class TIADebug : public DebuggerSystem
|
||||||
int cyclesLo() const;
|
int cyclesLo() const;
|
||||||
int cyclesHi() const;
|
int cyclesHi() const;
|
||||||
int clocksThisLine() const;
|
int clocksThisLine() const;
|
||||||
|
int cyclesThisLine() const;
|
||||||
bool vsync() const;
|
bool vsync() const;
|
||||||
bool vblank() const;
|
bool vblank() const;
|
||||||
int vsyncAsInt() const { return int(vsync()); } // so we can use _vsync pseudo-register
|
int vsyncAsInt() const { return int(vsync()); } // so we can use _vsync pseudo-register
|
||||||
|
|
|
@ -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
|
|
@ -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];
|
||||||
|
}
|
|
@ -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
|
|
@ -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];
|
||||||
|
}
|
|
@ -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 "AtariVox.hxx"
|
||||||
#include "MT24LC256.hxx"
|
|
||||||
#include "AtariVoxWidget.hxx"
|
#include "AtariVoxWidget.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
AtariVoxWidget::AtariVoxWidget(GuiObject* boss, const GUI::Font& font,
|
AtariVoxWidget::AtariVoxWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
int x, int y, Controller& controller)
|
int x, int y, Controller& controller)
|
||||||
: ControllerWidget(boss, font, x, y, controller)
|
: FlashWidget(boss, font, x, y, controller)
|
||||||
{
|
{
|
||||||
bool leftport = myController.jack() == Controller::Left;
|
init(boss, font, x, y);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void AtariVoxWidget::handleCommand(CommandSender*, int cmd, int, int)
|
void AtariVoxWidget::eraseCurrent()
|
||||||
{
|
{
|
||||||
if(cmd == kEEPROMErase)
|
AtariVox& avox = static_cast<AtariVox&>(myController);
|
||||||
{
|
|
||||||
AtariVox& avox = static_cast<AtariVox&>(myController);
|
avox.eraseCurrent();
|
||||||
avox.myEEPROM->erase();
|
}
|
||||||
}
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool AtariVoxWidget::isPageUsed(uInt32 page)
|
||||||
|
{
|
||||||
|
AtariVox& avox = static_cast<AtariVox&>(myController);
|
||||||
|
|
||||||
|
return avox.isPageUsed(page);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,10 @@
|
||||||
#ifndef ATARIVOX_WIDGET_HXX
|
#ifndef ATARIVOX_WIDGET_HXX
|
||||||
#define ATARIVOX_WIDGET_HXX
|
#define ATARIVOX_WIDGET_HXX
|
||||||
|
|
||||||
class ButtonWidget;
|
|
||||||
|
|
||||||
#include "Control.hxx"
|
#include "Control.hxx"
|
||||||
#include "ControllerWidget.hxx"
|
#include "FlashWidget.hxx"
|
||||||
|
|
||||||
class AtariVoxWidget : public ControllerWidget
|
class AtariVoxWidget : public FlashWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AtariVoxWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
AtariVoxWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
||||||
|
@ -31,12 +29,8 @@ class AtariVoxWidget : public ControllerWidget
|
||||||
virtual ~AtariVoxWidget() = default;
|
virtual ~AtariVoxWidget() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ButtonWidget* myEEPROMErase;
|
void eraseCurrent() override;
|
||||||
enum { kEEPROMErase = 'eeER' };
|
bool isPageUsed(uInt32 page) override;
|
||||||
|
|
||||||
private:
|
|
||||||
void loadConfig() override { }
|
|
||||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
|
||||||
|
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
AtariVoxWidget() = delete;
|
AtariVoxWidget() = delete;
|
||||||
|
|
|
@ -24,8 +24,7 @@ BoosterWidget::BoosterWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
int x, int y, Controller& controller)
|
int x, int y, Controller& controller)
|
||||||
: ControllerWidget(boss, font, x, y, controller)
|
: ControllerWidget(boss, font, x, y, controller)
|
||||||
{
|
{
|
||||||
bool leftport = myController.jack() == Controller::Left;
|
const string& label = isLeftPort() ? "Left (Booster)" : "Right (Booster)";
|
||||||
const string& label = leftport ? "Left (Booster)" : "Right (Booster)";
|
|
||||||
|
|
||||||
const int fontHeight = font.getFontHeight();
|
const int fontHeight = font.getFontHeight();
|
||||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Booster)");
|
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,
|
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
|
||||||
fontHeight, label, kTextAlignLeft);
|
fontHeight, label, kTextAlignLeft);
|
||||||
xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 10;
|
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]->setID(kJUp);
|
||||||
myPins[kJUp]->setTarget(this);
|
myPins[kJUp]->setTarget(this);
|
||||||
|
|
||||||
ypos += myPins[kJUp]->getHeight() * 2 + 10;
|
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]->setID(kJDown);
|
||||||
myPins[kJDown]->setTarget(this);
|
myPins[kJDown]->setTarget(this);
|
||||||
|
|
||||||
xpos -= myPins[kJUp]->getWidth() + 5;
|
xpos -= myPins[kJUp]->getWidth() + 5;
|
||||||
ypos -= myPins[kJUp]->getHeight() + 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]->setID(kJLeft);
|
||||||
myPins[kJLeft]->setTarget(this);
|
myPins[kJLeft]->setTarget(this);
|
||||||
|
|
||||||
xpos += (myPins[kJUp]->getWidth() + 5) * 2;
|
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]->setID(kJRight);
|
||||||
myPins[kJRight]->setTarget(this);
|
myPins[kJRight]->setTarget(this);
|
||||||
|
|
||||||
xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
|
xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
|
||||||
ypos = 20 + (myPins[kJUp]->getHeight() + 10) * 3;
|
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]->setID(kJFire);
|
||||||
myPins[kJFire]->setTarget(this);
|
myPins[kJFire]->setTarget(this);
|
||||||
|
|
||||||
ypos += myPins[kJFire]->getHeight() + 5;
|
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]->setID(kJBooster);
|
||||||
myPins[kJBooster]->setTarget(this);
|
myPins[kJBooster]->setTarget(this);
|
||||||
|
|
||||||
ypos += myPins[kJBooster]->getHeight() + 5;
|
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]->setID(kJTrigger);
|
||||||
myPins[kJTrigger]->setTarget(this);
|
myPins[kJTrigger]->setTarget(this);
|
||||||
}
|
}
|
||||||
|
@ -90,7 +96,7 @@ void BoosterWidget::loadConfig()
|
||||||
void BoosterWidget::handleCommand(
|
void BoosterWidget::handleCommand(
|
||||||
CommandSender* sender, int cmd, int data, int id)
|
CommandSender* sender, int cmd, int data, int id)
|
||||||
{
|
{
|
||||||
if(cmd == kCheckActionCmd)
|
if(cmd == CheckboxWidget::kCheckActionCmd)
|
||||||
{
|
{
|
||||||
switch(id)
|
switch(id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,7 +36,7 @@ Cartridge0840Widget::Cartridge0840Widget(
|
||||||
for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < 2;
|
for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < 2;
|
||||||
++i, offset += 0x1000, spot += 0x40)
|
++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;
|
start -= start % 0x1000;
|
||||||
info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - "
|
info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - "
|
||||||
<< "$" << (start + 0xFFF) << " (hotspot = $" << spot << ")\n";
|
<< "$" << (start + 0xFFF) << " (hotspot = $" << spot << ")\n";
|
||||||
|
|
|
@ -324,7 +324,7 @@ void CartridgeBUSWidget::loadConfig()
|
||||||
for(int i = 0; i < 3; ++i)
|
for(int i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
alist.push_back(0); vlist.push_back(myCart.myMusicCounters[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);
|
myMusicCounters->setList(alist, vlist, changed);
|
||||||
|
|
||||||
|
@ -332,7 +332,7 @@ void CartridgeBUSWidget::loadConfig()
|
||||||
for(int i = 0; i < 3; ++i)
|
for(int i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
alist.push_back(0); vlist.push_back(myCart.myMusicFrequencies[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);
|
myMusicFrequencies->setList(alist, vlist, changed);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ class ButtonWidget;
|
||||||
#include "Widget.hxx"
|
#include "Widget.hxx"
|
||||||
#include "Command.hxx"
|
#include "Command.hxx"
|
||||||
|
|
||||||
|
|
||||||
class ControllerWidget : public Widget, public CommandSender
|
class ControllerWidget : public Widget, public CommandSender
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -44,6 +45,19 @@ class ControllerWidget : public Widget, public CommandSender
|
||||||
protected:
|
protected:
|
||||||
Controller& myController;
|
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:
|
private:
|
||||||
virtual void handleCommand(CommandSender* sender, int cmd, int data, int id) override { }
|
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)
|
switch(cmd)
|
||||||
{
|
{
|
||||||
case kSetPositionCmd:
|
case GuiObject::kSetPositionCmd:
|
||||||
// Chain access; pass to parent
|
// Chain access; pass to parent
|
||||||
sendCommand(kSetPositionCmd, data, _id);
|
sendCommand(GuiObject::kSetPositionCmd, data, _id);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kDGZeroCmd:
|
case kDGZeroCmd:
|
||||||
|
|
|
@ -92,7 +92,10 @@ void DebuggerDialog::handleKeyDown(StellaKey key, StellaMod mod)
|
||||||
switch(key)
|
switch(key)
|
||||||
{
|
{
|
||||||
case KBDK_R:
|
case KBDK_R:
|
||||||
doRewind();
|
if(!instance().eventHandler().kbdShift(mod))
|
||||||
|
doRewind();
|
||||||
|
else
|
||||||
|
doUnwind();
|
||||||
break;
|
break;
|
||||||
case KBDK_S:
|
case KBDK_S:
|
||||||
doStep();
|
doStep();
|
||||||
|
@ -141,6 +144,10 @@ void DebuggerDialog::handleCommand(CommandSender* sender, int cmd,
|
||||||
doRewind();
|
doRewind();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kDDUnwindCmd:
|
||||||
|
doUnwind();
|
||||||
|
break;
|
||||||
|
|
||||||
case kDDExitCmd:
|
case kDDExitCmd:
|
||||||
doExitDebugger();
|
doExitDebugger();
|
||||||
break;
|
break;
|
||||||
|
@ -189,6 +196,12 @@ void DebuggerDialog::doRewind()
|
||||||
instance().debugger().parser().run("rewind");
|
instance().debugger().parser().run("rewind");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
void DebuggerDialog::doUnwind()
|
||||||
|
{
|
||||||
|
instance().debugger().parser().run("unwind");
|
||||||
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void DebuggerDialog::doExitDebugger()
|
void DebuggerDialog::doExitDebugger()
|
||||||
{
|
{
|
||||||
|
@ -375,7 +388,7 @@ void DebuggerDialog::addRomArea()
|
||||||
bwidth, bheight, "Exit", kDDExitCmd);
|
bwidth, bheight, "Exit", kDDExitCmd);
|
||||||
|
|
||||||
bwidth = myLFont->getStringWidth("< ") + 4;
|
bwidth = myLFont->getStringWidth("< ") + 4;
|
||||||
bheight = bheight * 5 + 4*4;
|
bheight = bheight * 3 + 4 * 2;
|
||||||
buttonX -= (bwidth + 5);
|
buttonX -= (bwidth + 5);
|
||||||
buttonY = r.top + 5;
|
buttonY = r.top + 5;
|
||||||
myRewindButton =
|
myRewindButton =
|
||||||
|
@ -383,6 +396,14 @@ void DebuggerDialog::addRomArea()
|
||||||
bwidth, bheight, "<", kDDRewindCmd);
|
bwidth, bheight, "<", kDDRewindCmd);
|
||||||
myRewindButton->clearFlags(WIDGET_ENABLED);
|
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;
|
int xpos = buttonX - 8*myLFont->getMaxCharWidth() - 20, ypos = 20;
|
||||||
DataGridOpsWidget* ops = new DataGridOpsWidget(this, *myLFont, xpos, ypos);
|
DataGridOpsWidget* ops = new DataGridOpsWidget(this, *myLFont, xpos, ypos);
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ class DebuggerDialog : public Dialog
|
||||||
CartRamWidget& cartRam() const { return *myCartRam; }
|
CartRamWidget& cartRam() const { return *myCartRam; }
|
||||||
EditTextWidget& message() const { return *myMessageBox; }
|
EditTextWidget& message() const { return *myMessageBox; }
|
||||||
ButtonWidget& rewindButton() const { return *myRewindButton; }
|
ButtonWidget& rewindButton() const { return *myRewindButton; }
|
||||||
|
ButtonWidget& unwindButton() const { return *myUnwindButton; }
|
||||||
|
|
||||||
void showFatalMessage(const string& msg);
|
void showFatalMessage(const string& msg);
|
||||||
|
|
||||||
|
@ -75,6 +76,7 @@ class DebuggerDialog : public Dialog
|
||||||
void doScanlineAdvance();
|
void doScanlineAdvance();
|
||||||
void doAdvance();
|
void doAdvance();
|
||||||
void doRewind();
|
void doRewind();
|
||||||
|
void doUnwind();
|
||||||
void doExitDebugger();
|
void doExitDebugger();
|
||||||
void doExitRom();
|
void doExitRom();
|
||||||
|
|
||||||
|
@ -96,6 +98,7 @@ class DebuggerDialog : public Dialog
|
||||||
kDDAdvCmd = 'DDav',
|
kDDAdvCmd = 'DDav',
|
||||||
kDDSAdvCmd = 'DDsv',
|
kDDSAdvCmd = 'DDsv',
|
||||||
kDDRewindCmd = 'DDrw',
|
kDDRewindCmd = 'DDrw',
|
||||||
|
kDDUnwindCmd = 'DDuw',
|
||||||
kDDExitCmd = 'DDex',
|
kDDExitCmd = 'DDex',
|
||||||
kDDExitFatalCmd = 'DDer'
|
kDDExitFatalCmd = 'DDer'
|
||||||
};
|
};
|
||||||
|
@ -113,6 +116,7 @@ class DebuggerDialog : public Dialog
|
||||||
CartRamWidget* myCartRam;
|
CartRamWidget* myCartRam;
|
||||||
EditTextWidget* myMessageBox;
|
EditTextWidget* myMessageBox;
|
||||||
ButtonWidget* myRewindButton;
|
ButtonWidget* myRewindButton;
|
||||||
|
ButtonWidget* myUnwindButton;
|
||||||
unique_ptr<GUI::MessageBox> myFatalError;
|
unique_ptr<GUI::MessageBox> myFatalError;
|
||||||
|
|
||||||
unique_ptr<GUI::Font> myLFont; // used for labels
|
unique_ptr<GUI::Font> myLFont; // used for labels
|
||||||
|
|
|
@ -22,13 +22,12 @@
|
||||||
DrivingWidget::DrivingWidget(GuiObject* boss, const GUI::Font& font,
|
DrivingWidget::DrivingWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
int x, int y, Controller& controller)
|
int x, int y, Controller& controller)
|
||||||
: ControllerWidget(boss, font, x, y, controller),
|
: ControllerWidget(boss, font, x, y, controller),
|
||||||
myGreyIndex(0)
|
myGrayIndex(0)
|
||||||
{
|
{
|
||||||
bool leftport = myController.jack() == Controller::Left;
|
const string& label = getHeader();
|
||||||
const string& label = leftport ? "Left (Driving)" : "Right (Driving)";
|
|
||||||
|
|
||||||
const int fontHeight = font.getFontHeight(),
|
const int fontHeight = font.getFontHeight(),
|
||||||
bwidth = font.getStringWidth("Grey code +") + 10,
|
bwidth = font.getStringWidth("Gray code +") + 10,
|
||||||
bheight = font.getLineHeight() + 4;
|
bheight = font.getLineHeight() + 4;
|
||||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Driving)");
|
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Driving)");
|
||||||
StaticTextWidget* t;
|
StaticTextWidget* t;
|
||||||
|
@ -37,22 +36,22 @@ DrivingWidget::DrivingWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
fontHeight, label, kTextAlignLeft);
|
fontHeight, label, kTextAlignLeft);
|
||||||
|
|
||||||
ypos += t->getHeight() + 20;
|
ypos += t->getHeight() + 20;
|
||||||
myGreyUp = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
myGrayUp = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||||
"Grey code +", kGreyUpCmd);
|
"Gray code +", kGrayUpCmd);
|
||||||
myGreyUp->setTarget(this);
|
myGrayUp->setTarget(this);
|
||||||
|
|
||||||
ypos += myGreyUp->getHeight() + 5;
|
ypos += myGrayUp->getHeight() + 5;
|
||||||
myGreyDown = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
myGrayDown = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight,
|
||||||
"Grey code -", kGreyDownCmd);
|
"Gray code -", kGrayDownCmd);
|
||||||
myGreyDown->setTarget(this);
|
myGrayDown->setTarget(this);
|
||||||
|
|
||||||
xpos += myGreyDown->getWidth() + 10; ypos -= 10;
|
xpos += myGrayDown->getWidth() + 10; ypos -= 10;
|
||||||
myGreyValue = new DataGridWidget(boss, font, xpos, ypos,
|
myGrayValue = new DataGridWidget(boss, font, xpos, ypos,
|
||||||
1, 1, 2, 8, Common::Base::F_16);
|
1, 1, 2, 8, Common::Base::F_16);
|
||||||
myGreyValue->setTarget(this);
|
myGrayValue->setTarget(this);
|
||||||
myGreyValue->setEditable(false);
|
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 = new CheckboxWidget(boss, font, xpos, ypos, "Fire", kFireCmd);
|
||||||
myFire->setTarget(this);
|
myFire->setTarget(this);
|
||||||
}
|
}
|
||||||
|
@ -60,16 +59,16 @@ DrivingWidget::DrivingWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void DrivingWidget::loadConfig()
|
void DrivingWidget::loadConfig()
|
||||||
{
|
{
|
||||||
uInt8 grey = 0;
|
uInt8 gray = 0;
|
||||||
if(myController.read(Controller::One)) grey += 1;
|
if(myController.read(Controller::One)) gray += 1;
|
||||||
if(myController.read(Controller::Two)) grey += 2;
|
if(myController.read(Controller::Two)) gray += 2;
|
||||||
|
|
||||||
for(myGreyIndex = 0; myGreyIndex < 4; ++myGreyIndex)
|
for(myGrayIndex = 0; myGrayIndex < 4; ++myGrayIndex)
|
||||||
if(ourGreyTable[myGreyIndex] == grey)
|
if(ourGrayTable[myGrayIndex] == gray)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
myFire->setState(!myController.read(Controller::Six));
|
myFire->setState(!myController.read(Controller::Six));
|
||||||
myGreyValue->setList(0, grey);
|
setValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -78,17 +77,17 @@ void DrivingWidget::handleCommand(
|
||||||
{
|
{
|
||||||
switch(cmd)
|
switch(cmd)
|
||||||
{
|
{
|
||||||
case kGreyUpCmd:
|
case kGrayUpCmd:
|
||||||
myGreyIndex = (myGreyIndex + 1) % 4;
|
myGrayIndex = (myGrayIndex + 1) % 4;
|
||||||
myController.set(Controller::One, (ourGreyTable[myGreyIndex] & 0x1) != 0);
|
myController.set(Controller::One, (ourGrayTable[myGrayIndex] & 0x1) != 0);
|
||||||
myController.set(Controller::Two, (ourGreyTable[myGreyIndex] & 0x2) != 0);
|
myController.set(Controller::Two, (ourGrayTable[myGrayIndex] & 0x2) != 0);
|
||||||
myGreyValue->setList(0, ourGreyTable[myGreyIndex]);
|
setValue();
|
||||||
break;
|
break;
|
||||||
case kGreyDownCmd:
|
case kGrayDownCmd:
|
||||||
myGreyIndex = myGreyIndex == 0 ? 3 : myGreyIndex - 1;
|
myGrayIndex = myGrayIndex == 0 ? 3 : myGrayIndex - 1;
|
||||||
myController.set(Controller::One, (ourGreyTable[myGreyIndex] & 0x1) != 0);
|
myController.set(Controller::One, (ourGrayTable[myGrayIndex] & 0x1) != 0);
|
||||||
myController.set(Controller::Two, (ourGreyTable[myGreyIndex] & 0x2) != 0);
|
myController.set(Controller::Two, (ourGrayTable[myGrayIndex] & 0x2) != 0);
|
||||||
myGreyValue->setList(0, ourGreyTable[myGreyIndex]);
|
setValue();
|
||||||
break;
|
break;
|
||||||
case kFireCmd:
|
case kFireCmd:
|
||||||
myController.set(Controller::Six, !myFire->getState());
|
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:
|
private:
|
||||||
enum {
|
enum {
|
||||||
kGreyUpCmd = 'DWup',
|
kGrayUpCmd = 'DWup',
|
||||||
kGreyDownCmd = 'DWdn',
|
kGrayDownCmd = 'DWdn',
|
||||||
kFireCmd = 'DWfr'
|
kFireCmd = 'DWfr'
|
||||||
};
|
};
|
||||||
ButtonWidget *myGreyUp, *myGreyDown;
|
ButtonWidget *myGrayUp, *myGrayDown;
|
||||||
DataGridWidget* myGreyValue;
|
DataGridWidget* myGrayValue;
|
||||||
CheckboxWidget* myFire;
|
CheckboxWidget* myFire;
|
||||||
|
|
||||||
int myGreyIndex;
|
int myGrayIndex;
|
||||||
|
|
||||||
static uInt8 ourGreyTable[4];
|
static uInt8 ourGrayTable[4];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadConfig() override;
|
void loadConfig() override;
|
||||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||||
|
|
||||||
|
void setValue();
|
||||||
|
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
DrivingWidget() = delete;
|
DrivingWidget() = delete;
|
||||||
DrivingWidget(const DrivingWidget&) = delete;
|
DrivingWidget(const DrivingWidget&) = delete;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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)
|
int x, int y, Controller& controller)
|
||||||
: ControllerWidget(boss, font, x, y, controller)
|
: ControllerWidget(boss, font, x, y, controller)
|
||||||
{
|
{
|
||||||
bool leftport = myController.jack() == Controller::Left;
|
const string& label = getHeader();
|
||||||
const string& label = leftport ? "Left (Genesis)" : "Right (Genesis)";
|
|
||||||
|
|
||||||
const int fontHeight = font.getFontHeight();
|
const int fontHeight = font.getFontHeight();
|
||||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Genesis)");
|
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,
|
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
|
||||||
fontHeight, label, kTextAlignLeft);
|
fontHeight, label, kTextAlignLeft);
|
||||||
xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 20;
|
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]->setID(kJUp);
|
||||||
myPins[kJUp]->setTarget(this);
|
myPins[kJUp]->setTarget(this);
|
||||||
|
|
||||||
ypos += myPins[kJUp]->getHeight() * 2 + 10;
|
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]->setID(kJDown);
|
||||||
myPins[kJDown]->setTarget(this);
|
myPins[kJDown]->setTarget(this);
|
||||||
|
|
||||||
xpos -= myPins[kJUp]->getWidth() + 5;
|
xpos -= myPins[kJUp]->getWidth() + 5;
|
||||||
ypos -= myPins[kJUp]->getHeight() + 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]->setID(kJLeft);
|
||||||
myPins[kJLeft]->setTarget(this);
|
myPins[kJLeft]->setTarget(this);
|
||||||
|
|
||||||
xpos += (myPins[kJUp]->getWidth() + 5) * 2;
|
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]->setID(kJRight);
|
||||||
myPins[kJRight]->setTarget(this);
|
myPins[kJRight]->setTarget(this);
|
||||||
|
|
||||||
xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
|
xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
|
||||||
ypos = 30 + (myPins[kJUp]->getHeight() + 10) * 3;
|
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]->setID(kJBbtn);
|
||||||
myPins[kJBbtn]->setTarget(this);
|
myPins[kJBbtn]->setTarget(this);
|
||||||
|
|
||||||
ypos += myPins[kJBbtn]->getHeight() + 5;
|
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]->setID(kJCbtn);
|
||||||
myPins[kJCbtn]->setTarget(this);
|
myPins[kJCbtn]->setTarget(this);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +88,7 @@ void GenesisWidget::loadConfig()
|
||||||
void GenesisWidget::handleCommand(
|
void GenesisWidget::handleCommand(
|
||||||
CommandSender* sender, int cmd, int data, int id)
|
CommandSender* sender, int cmd, int data, int id)
|
||||||
{
|
{
|
||||||
if(cmd == kCheckActionCmd)
|
if(cmd == CheckboxWidget::kCheckActionCmd)
|
||||||
{
|
{
|
||||||
switch(id)
|
switch(id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,9 +24,7 @@ JoystickWidget::JoystickWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
int x, int y, Controller& controller)
|
int x, int y, Controller& controller)
|
||||||
: ControllerWidget(boss, font, x, y, controller)
|
: ControllerWidget(boss, font, x, y, controller)
|
||||||
{
|
{
|
||||||
bool leftport = myController.jack() == Controller::Left;
|
const string& label = getHeader();
|
||||||
const string& label = leftport ? "Left (Joystick)" : "Right (Joystick)";
|
|
||||||
|
|
||||||
const int fontHeight = font.getFontHeight();
|
const int fontHeight = font.getFontHeight();
|
||||||
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Joystick)");
|
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Joystick)");
|
||||||
StaticTextWidget* t;
|
StaticTextWidget* t;
|
||||||
|
@ -34,29 +32,34 @@ JoystickWidget::JoystickWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
|
t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
|
||||||
fontHeight, label, kTextAlignLeft);
|
fontHeight, label, kTextAlignLeft);
|
||||||
xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 20;
|
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]->setID(kJUp);
|
||||||
myPins[kJUp]->setTarget(this);
|
myPins[kJUp]->setTarget(this);
|
||||||
|
|
||||||
ypos += myPins[kJUp]->getHeight() * 2 + 10;
|
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]->setID(kJDown);
|
||||||
myPins[kJDown]->setTarget(this);
|
myPins[kJDown]->setTarget(this);
|
||||||
|
|
||||||
xpos -= myPins[kJUp]->getWidth() + 5;
|
xpos -= myPins[kJUp]->getWidth() + 5;
|
||||||
ypos -= myPins[kJUp]->getHeight() + 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]->setID(kJLeft);
|
||||||
myPins[kJLeft]->setTarget(this);
|
myPins[kJLeft]->setTarget(this);
|
||||||
|
|
||||||
xpos += (myPins[kJUp]->getWidth() + 5) * 2;
|
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]->setID(kJRight);
|
||||||
myPins[kJRight]->setTarget(this);
|
myPins[kJRight]->setTarget(this);
|
||||||
|
|
||||||
xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
|
xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
|
||||||
ypos = 30 + (myPins[kJUp]->getHeight() + 10) * 3;
|
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]->setID(kJFire);
|
||||||
myPins[kJFire]->setTarget(this);
|
myPins[kJFire]->setTarget(this);
|
||||||
}
|
}
|
||||||
|
@ -75,7 +78,7 @@ void JoystickWidget::loadConfig()
|
||||||
void JoystickWidget::handleCommand(
|
void JoystickWidget::handleCommand(
|
||||||
CommandSender* sender, int cmd, int data, int id)
|
CommandSender* sender, int cmd, int data, int id)
|
||||||
{
|
{
|
||||||
if(cmd == kCheckActionCmd)
|
if(cmd == CheckboxWidget::kCheckActionCmd)
|
||||||
myController.set(ourPinNo[id], !myPins[id]->getState());
|
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)
|
int x, int y, Controller& controller)
|
||||||
: ControllerWidget(boss, font, x, y, 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 string& label = leftport ? "Left (Keyboard)" : "Right (Keyboard)";
|
||||||
|
|
||||||
const int fontHeight = font.getFontHeight();
|
const int fontHeight = font.getFontHeight();
|
||||||
|
@ -38,7 +38,8 @@ KeyboardWidget::KeyboardWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
|
|
||||||
for(int i = 0; i < 12; ++i)
|
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]->setID(i);
|
||||||
myBox[i]->setTarget(this);
|
myBox[i]->setTarget(this);
|
||||||
xpos += myBox[i]->getWidth() + 5;
|
xpos += myBox[i]->getWidth() + 5;
|
||||||
|
@ -63,7 +64,7 @@ void KeyboardWidget::loadConfig()
|
||||||
void KeyboardWidget::handleCommand(
|
void KeyboardWidget::handleCommand(
|
||||||
CommandSender* sender, int cmd, int data, int id)
|
CommandSender* sender, int cmd, int data, int id)
|
||||||
{
|
{
|
||||||
if(cmd == kCheckActionCmd)
|
if(cmd == CheckboxWidget::kCheckActionCmd)
|
||||||
instance().eventHandler().handleEvent(myEvent[id], myBox[id]->getState());
|
instance().eventHandler().handleEvent(myEvent[id], myBox[id]->getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,10 +29,8 @@ class NullControlWidget : public ControllerWidget
|
||||||
Controller& controller)
|
Controller& controller)
|
||||||
: ControllerWidget(boss, font, x, y, controller)
|
: ControllerWidget(boss, font, x, y, controller)
|
||||||
{
|
{
|
||||||
bool leftport = controller.jack() == Controller::Left;
|
|
||||||
ostringstream buf;
|
ostringstream buf;
|
||||||
buf << (leftport ? "Left (" : "Right (")
|
buf << getHeader();
|
||||||
<< controller.name() << "):";
|
|
||||||
const int fontHeight = font.getFontHeight(),
|
const int fontHeight = font.getFontHeight(),
|
||||||
lineHeight = font.getLineHeight(),
|
lineHeight = font.getLineHeight(),
|
||||||
lwidth = std::max(font.getStringWidth(buf.str()),
|
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)
|
int x, int y, Controller& controller)
|
||||||
: ControllerWidget(boss, font, x, y, controller)
|
: ControllerWidget(boss, font, x, y, controller)
|
||||||
{
|
{
|
||||||
bool leftport = myController.jack() == Controller::Left;
|
bool leftport = isLeftPort();
|
||||||
const string& label = leftport ? "Left (Paddles)" : "Right (Paddles)";
|
const string& label = getHeader();
|
||||||
|
|
||||||
const int fontWidth = font.getMaxCharWidth(),
|
const int fontWidth = font.getMaxCharWidth(),
|
||||||
fontHeight = font.getFontHeight(),
|
fontHeight = font.getFontHeight(),
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
str[i] = buffer(_promptStartPos + i) & 0x7f;
|
str[i] = buffer(_promptStartPos + i) & 0x7f;
|
||||||
if(strchr("{*@<> ", str[i]) != NULL )
|
// whitespace characters
|
||||||
|
if(strchr("{*@<> =[]()+-/&|!^~%", str[i]))
|
||||||
{
|
{
|
||||||
lastDelimPos = i;
|
lastDelimPos = i;
|
||||||
delimiter = str[i];
|
delimiter = str[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str[len] = '\0';
|
str[len] = '\0';
|
||||||
|
int strLen = len - lastDelimPos - 1;
|
||||||
|
|
||||||
StringList list;
|
StringList list;
|
||||||
string completionList;
|
string completionList;
|
||||||
|
@ -226,7 +228,7 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||||
|
|
||||||
if(lastDelimPos < 0)
|
if(lastDelimPos < 0)
|
||||||
{
|
{
|
||||||
// no delimiters, do command completion:
|
// no delimiters, do only command completion:
|
||||||
const DebuggerParser& parser = instance().debugger().parser();
|
const DebuggerParser& parser = instance().debugger().parser();
|
||||||
parser.getCompletions(str, list);
|
parser.getCompletions(str, list);
|
||||||
|
|
||||||
|
@ -237,7 +239,7 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||||
completionList = list[0];
|
completionList = list[0];
|
||||||
for(uInt32 i = 1; i < list.size(); ++i)
|
for(uInt32 i = 1; i < list.size(); ++i)
|
||||||
completionList += " " + list[i];
|
completionList += " " + list[i];
|
||||||
prefix = getCompletionPrefix(list, str);
|
prefix = getCompletionPrefix(list);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -248,11 +250,15 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we got a delimiter, so this must be a label or a function
|
// do not show ALL labels without any filter as it makes no sense
|
||||||
const Debugger& dbg = instance().debugger();
|
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.cartDebug().getCompletions(str + lastDelimPos + 1, list);
|
||||||
dbg.getCompletions(str + lastDelimPos + 1, list);
|
dbg.getCompletions(str + lastDelimPos + 1, list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(list.size() < 1)
|
if(list.size() < 1)
|
||||||
|
@ -262,9 +268,11 @@ bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod)
|
||||||
completionList = list[0];
|
completionList = list[0];
|
||||||
for(uInt32 i = 1; i < list.size(); ++i)
|
for(uInt32 i = 1; i < list.size(); ++i)
|
||||||
completionList += " " + list[i];
|
completionList += " " + list[i];
|
||||||
prefix = getCompletionPrefix(list, str + lastDelimPos + 1);
|
prefix = getCompletionPrefix(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: tab through list
|
||||||
|
|
||||||
if(list.size() == 1)
|
if(list.size() == 1)
|
||||||
{
|
{
|
||||||
// add to buffer as though user typed it (plus a space)
|
// add to buffer as though user typed it (plus a space)
|
||||||
|
@ -475,7 +483,7 @@ void PromptWidget::handleCommand(CommandSender* sender, int cmd,
|
||||||
{
|
{
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case kSetPositionCmd:
|
case GuiObject::kSetPositionCmd:
|
||||||
int newPos = int(data) + _linesPerPage - 1 + _firstLineInBuffer;
|
int newPos = int(data) + _linesPerPage - 1 + _firstLineInBuffer;
|
||||||
if (newPos != _scrollLine)
|
if (newPos != _scrollLine)
|
||||||
{
|
{
|
||||||
|
@ -501,7 +509,14 @@ void PromptWidget::loadConfig()
|
||||||
print(PROMPT);
|
print(PROMPT);
|
||||||
|
|
||||||
// Take care of one-time debugger stuff
|
// 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().loadConfigFile() + "\n");
|
||||||
print(instance().debugger().cartDebug().loadListFile() + "\n");
|
print(instance().debugger().cartDebug().loadListFile() + "\n");
|
||||||
print(instance().debugger().cartDebug().loadSymbolFile() + "\n");
|
print(instance().debugger().cartDebug().loadSymbolFile() + "\n");
|
||||||
|
@ -697,8 +712,9 @@ void PromptWidget::historyScroll(int direction)
|
||||||
|
|
||||||
// Advance to the next line in the history
|
// Advance to the next line in the history
|
||||||
int line = _historyLine + direction;
|
int line = _historyLine + direction;
|
||||||
if ((direction < 0 && line < 0) || (direction > 0 && line > _historySize))
|
if(line < 0)
|
||||||
return;
|
line += _historySize + 1;
|
||||||
|
line %= (_historySize + 1);
|
||||||
|
|
||||||
// If they press arrow-up with anything in the buffer, search backwards
|
// If they press arrow-up with anything in the buffer, search backwards
|
||||||
// in the history.
|
// 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
|
// Find the number of characters matching for each of the completions provided
|
||||||
// Once a mismatch is found or length is past one of the strings, we're done
|
for(uInt32 len = 1;; len++)
|
||||||
// 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(;;)
|
|
||||||
{
|
{
|
||||||
for(const auto& s: completions)
|
for(uInt32 i = 0; i < completions.size(); i++)
|
||||||
{
|
{
|
||||||
if(s.length() < prefix.length())
|
string s1 = completions[i];
|
||||||
return prefix; // current prefix is the best we're going to get
|
if(s1.length() < len)
|
||||||
else if(!BSPF::startsWithIgnoreCase(s, prefix))
|
|
||||||
{
|
{
|
||||||
prefix.erase(prefix.length()-1);
|
return s1.substr(0, len - 1);
|
||||||
return prefix;
|
}
|
||||||
|
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;
|
virtual ~PromptWidget() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int printf(const char* format, ...);
|
ATTRIBUTE_FMT_PRINTF int printf(const char* format, ...);
|
||||||
int vprintf(const char* format, va_list argptr);
|
ATTRIBUTE_FMT_PRINTF int vprintf(const char* format, va_list argptr);
|
||||||
void print(const string& str);
|
void print(const string& str);
|
||||||
void printPrompt();
|
void printPrompt();
|
||||||
bool saveBuffer(const FilesystemNode& file);
|
bool saveBuffer(const FilesystemNode& file);
|
||||||
|
@ -85,7 +85,7 @@ class PromptWidget : public Widget, public CommandSender
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Get the longest prefix (initially 's') that is in every string in the list
|
// 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:
|
private:
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -257,7 +257,7 @@ void RamWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case kSetPositionCmd:
|
case GuiObject::kSetPositionCmd:
|
||||||
myCurrentRamBank = data;
|
myCurrentRamBank = data;
|
||||||
showSearchResults();
|
showSearchResults();
|
||||||
fillGrid(false);
|
fillGrid(false);
|
||||||
|
@ -383,11 +383,11 @@ string RamWidget::doSearch(const string& str)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
string RamWidget::doCompare(const string& str)
|
string RamWidget::doCompare(const string& str)
|
||||||
{
|
{
|
||||||
bool comparitiveSearch = false;
|
bool comparativeSearch = false;
|
||||||
int searchVal = 0, offset = 0;
|
int searchVal = 0, offset = 0;
|
||||||
|
|
||||||
if(str.length() == 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
|
// Do some pre-processing on the string
|
||||||
string::size_type pos = str.find_first_of("+-", 0);
|
string::size_type pos = str.find_first_of("+-", 0);
|
||||||
|
@ -397,11 +397,11 @@ string RamWidget::doCompare(const string& str)
|
||||||
return "Input must be [+|-]NUM";
|
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
|
// the specified amount, vs. for exact values
|
||||||
if(str[0] == '+' || str[0] == '-')
|
if(str[0] == '+' || str[0] == '-')
|
||||||
{
|
{
|
||||||
comparitiveSearch = true;
|
comparativeSearch = true;
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
if(str[0] == '-')
|
if(str[0] == '-')
|
||||||
negative = true;
|
negative = true;
|
||||||
|
@ -425,7 +425,7 @@ string RamWidget::doCompare(const string& str)
|
||||||
|
|
||||||
for(uInt32 i = 0; i < mySearchAddr.size(); ++i)
|
for(uInt32 i = 0; i < mySearchAddr.size(); ++i)
|
||||||
{
|
{
|
||||||
if(comparitiveSearch)
|
if(comparativeSearch)
|
||||||
{
|
{
|
||||||
searchVal = mySearchValue[i] + offset;
|
searchVal = mySearchValue[i] + offset;
|
||||||
if(searchVal < 0 || searchVal > 255)
|
if(searchVal < 0 || searchVal > 255)
|
||||||
|
|
|
@ -32,14 +32,14 @@ RiotRamWidget::RiotRamWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
uInt8 RiotRamWidget::getValue(int addr) const
|
uInt8 RiotRamWidget::getValue(int addr) const
|
||||||
{
|
{
|
||||||
const CartState& state = static_cast<const CartState&>(myDbg.getState());
|
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)
|
void RiotRamWidget::setValue(int addr, uInt8 value)
|
||||||
{
|
{
|
||||||
const CartState& state = static_cast<const CartState&>(myDbg.getState());
|
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 "KeyboardWidget.hxx"
|
||||||
#include "AtariVoxWidget.hxx"
|
#include "AtariVoxWidget.hxx"
|
||||||
#include "SaveKeyWidget.hxx"
|
#include "SaveKeyWidget.hxx"
|
||||||
|
#include "AmigaMouseWidget.hxx"
|
||||||
|
#include "AtariMouseWidget.hxx"
|
||||||
|
#include "TrakBallWidget.hxx"
|
||||||
|
|
||||||
#include "RiotWidget.hxx"
|
#include "RiotWidget.hxx"
|
||||||
|
|
||||||
|
@ -82,7 +85,7 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
|
|
||||||
// SWCHA bits in 'peek' mode
|
// SWCHA bits in 'peek' mode
|
||||||
xpos = 10; ypos += lineHeight + 5;
|
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
|
// SWCHB bits in 'poke' mode
|
||||||
xpos = 10; ypos += 2 * lineHeight;
|
xpos = 10; ypos += 2 * lineHeight;
|
||||||
|
@ -199,13 +202,13 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// Select and Reset
|
// Select and Reset
|
||||||
xpos += myP0Diff->getWidth() + 20; ypos = col2_ypos + lineHeight;
|
xpos += myP0Diff->getWidth() + 20; ypos = col2_ypos + lineHeight;
|
||||||
mySelect = new CheckboxWidget(boss, lfont, xpos, ypos, "Select",
|
mySelect = new CheckboxWidget(boss, lfont, xpos, ypos, "Select",
|
||||||
kCheckActionCmd);
|
CheckboxWidget::kCheckActionCmd);
|
||||||
mySelect->setID(kSelectID);
|
mySelect->setID(kSelectID);
|
||||||
mySelect->setTarget(this);
|
mySelect->setTarget(this);
|
||||||
addFocusWidget(mySelect);
|
addFocusWidget(mySelect);
|
||||||
ypos += mySelect->getHeight() + 5;
|
ypos += mySelect->getHeight() + 5;
|
||||||
myReset = new CheckboxWidget(boss, lfont, xpos, ypos, "Reset",
|
myReset = new CheckboxWidget(boss, lfont, xpos, ypos, "Reset",
|
||||||
kCheckActionCmd);
|
CheckboxWidget::kCheckActionCmd);
|
||||||
myReset->setID(kResetID);
|
myReset->setID(kResetID);
|
||||||
myReset->setTarget(this);
|
myReset->setTarget(this);
|
||||||
addFocusWidget(myReset);
|
addFocusWidget(myReset);
|
||||||
|
@ -219,7 +222,7 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// Randomize RAM
|
// Randomize RAM
|
||||||
xpos += 30; ypos += lineHeight + 4;
|
xpos += 30; ypos += lineHeight + 4;
|
||||||
myRandomizeRAM = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
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->setID(kRandRAMID);
|
||||||
myRandomizeRAM->setTarget(this);
|
myRandomizeRAM->setTarget(this);
|
||||||
addFocusWidget(myRandomizeRAM);
|
addFocusWidget(myRandomizeRAM);
|
||||||
|
@ -234,7 +237,7 @@ RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
for(int i = 0; i < 5; ++i)
|
for(int i = 0; i < 5; ++i)
|
||||||
{
|
{
|
||||||
myRandomizeCPU[i] = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myRandomizeCPU[i] = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
cpuregs[i], kCheckActionCmd);
|
cpuregs[i], CheckboxWidget::kCheckActionCmd);
|
||||||
myRandomizeCPU[i]->setID(kRandCPUID);
|
myRandomizeCPU[i]->setID(kRandCPUID);
|
||||||
myRandomizeCPU[i]->setTarget(this);
|
myRandomizeCPU[i]->setTarget(this);
|
||||||
addFocusWidget(myRandomizeCPU[i]);
|
addFocusWidget(myRandomizeCPU[i]);
|
||||||
|
@ -395,10 +398,24 @@ void RiotWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||||
value = Debugger::get_bits(mySWBCNTBits->getState());
|
value = Debugger::get_bits(mySWBCNTBits->getState());
|
||||||
riot.swbcnt(value & 0xff);
|
riot.swbcnt(value & 0xff);
|
||||||
break;
|
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;
|
break;
|
||||||
|
|
||||||
case kCheckActionCmd:
|
case CheckboxWidget::kCheckActionCmd:
|
||||||
switch(id)
|
switch(id)
|
||||||
{
|
{
|
||||||
case kSelectID:
|
case kSelectID:
|
||||||
|
@ -436,16 +453,14 @@ ControllerWidget* RiotWidget::addControlWidget(GuiObject* boss, const GUI::Font&
|
||||||
{
|
{
|
||||||
switch(controller.type())
|
switch(controller.type())
|
||||||
{
|
{
|
||||||
case Controller::AmigaMouse: // TODO - implement this
|
case Controller::AmigaMouse:
|
||||||
return new NullControlWidget(boss, font, x, y, controller);
|
return new AmigaMouseWidget(boss, font, x, y, controller);
|
||||||
case Controller::AtariMouse: // TODO - implement this
|
case Controller::AtariMouse:
|
||||||
return new NullControlWidget(boss, font, x, y, controller);
|
return new AtariMouseWidget(boss, font, x, y, controller);
|
||||||
case Controller::AtariVox:
|
case Controller::AtariVox:
|
||||||
return new AtariVoxWidget(boss, font, x, y, controller);
|
return new AtariVoxWidget(boss, font, x, y, controller);
|
||||||
case Controller::BoosterGrip:
|
case Controller::BoosterGrip:
|
||||||
return new BoosterWidget(boss, font, x, y, controller);
|
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:
|
case Controller::Driving:
|
||||||
return new DrivingWidget(boss, font, x, y, controller);
|
return new DrivingWidget(boss, font, x, y, controller);
|
||||||
case Controller::Genesis:
|
case Controller::Genesis:
|
||||||
|
@ -454,18 +469,16 @@ ControllerWidget* RiotWidget::addControlWidget(GuiObject* boss, const GUI::Font&
|
||||||
return new JoystickWidget(boss, font, x, y, controller);
|
return new JoystickWidget(boss, font, x, y, controller);
|
||||||
case Controller::Keyboard:
|
case Controller::Keyboard:
|
||||||
return new KeyboardWidget(boss, font, x, y, controller);
|
return new KeyboardWidget(boss, font, x, y, controller);
|
||||||
case Controller::KidVid: // TODO - implement this
|
// case Controller::KidVid: // TODO - implement this
|
||||||
return new NullControlWidget(boss, font, x, y, controller);
|
// case Controller::MindLink: // TODO - implement this
|
||||||
case Controller::MindLink: // TODO - implement this
|
|
||||||
return new NullControlWidget(boss, font, x, y, controller);
|
|
||||||
case Controller::Paddles:
|
case Controller::Paddles:
|
||||||
return new PaddleWidget(boss, font, x, y, controller);
|
return new PaddleWidget(boss, font, x, y, controller);
|
||||||
case Controller::SaveKey:
|
case Controller::SaveKey:
|
||||||
return new SaveKeyWidget(boss, font, x, y, controller);
|
return new SaveKeyWidget(boss, font, x, y, controller);
|
||||||
case Controller::TrakBall: // TODO - implement this
|
case Controller::TrakBall:
|
||||||
return new NullControlWidget(boss, font, x, y, controller);
|
return new TrakBallWidget(boss, font, x, y, controller);
|
||||||
default:
|
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,
|
kTim1TID, kTim8TID, kTim64TID, kTim1024TID, kTimWriteID,
|
||||||
kSWCHABitsID, kSWACNTBitsID, kSWCHBBitsID, kSWBCNTBitsID,
|
kSWCHABitsID, kSWACNTBitsID, kSWCHBBitsID, kSWBCNTBitsID,
|
||||||
kP0DiffChanged, kP1DiffChanged, kTVTypeChanged, kSelectID, kResetID,
|
kP0DiffChanged, kP1DiffChanged, kTVTypeChanged, kSelectID, kResetID,
|
||||||
kRandCPUID, kRandRAMID
|
kRandCPUID, kRandRAMID, kSWCHARBitsID
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -80,7 +80,8 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
CheckboxWidget* t = nullptr;
|
CheckboxWidget* t = nullptr;
|
||||||
for(int i = 0; i < _rows; ++i)
|
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->setTarget(this);
|
||||||
t->setID(i);
|
t->setID(i);
|
||||||
t->setFill(CheckboxWidget::Circle);
|
t->setFill(CheckboxWidget::Circle);
|
||||||
|
@ -114,7 +115,6 @@ RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
default: // TODO - properly handle all other cases
|
default: // TODO - properly handle all other cases
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
setTextFilter(f);
|
setTextFilter(f);
|
||||||
}
|
}
|
||||||
|
@ -414,14 +414,14 @@ void RomListWidget::handleCommand(CommandSender* sender, int cmd, int data, int
|
||||||
{
|
{
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case kCheckActionCmd:
|
case CheckboxWidget::kCheckActionCmd:
|
||||||
// We let the parent class handle this
|
// We let the parent class handle this
|
||||||
// Pass it as a kRLBreakpointChangedCmd command, since that's the intent
|
// Pass it as a kRLBreakpointChangedCmd command, since that's the intent
|
||||||
sendCommand(RomListWidget::kBPointChangedCmd, _currentPos+id,
|
sendCommand(RomListWidget::kBPointChangedCmd, _currentPos+id,
|
||||||
myCheckList[id]->getState());
|
myCheckList[id]->getState());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSetPositionCmd:
|
case GuiObject::kSetPositionCmd:
|
||||||
if (_currentPos != data)
|
if (_currentPos != data)
|
||||||
{
|
{
|
||||||
_currentPos = data;
|
_currentPos = data;
|
||||||
|
|
|
@ -16,56 +16,28 @@
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include "SaveKey.hxx"
|
#include "SaveKey.hxx"
|
||||||
#include "MT24LC256.hxx"
|
|
||||||
#include "SaveKeyWidget.hxx"
|
#include "SaveKeyWidget.hxx"
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
SaveKeyWidget::SaveKeyWidget(GuiObject* boss, const GUI::Font& font,
|
SaveKeyWidget::SaveKeyWidget(GuiObject* boss, const GUI::Font& font,
|
||||||
int x, int y, Controller& controller)
|
int x, int y, Controller& controller)
|
||||||
: ControllerWidget(boss, font, x, y, controller)
|
: FlashWidget(boss, font, x, y, controller)
|
||||||
{
|
{
|
||||||
bool leftport = myController.jack() == Controller::Left;
|
init(boss, font, x, y);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void SaveKeyWidget::handleCommand(CommandSender*, int cmd, int, int)
|
void SaveKeyWidget::eraseCurrent()
|
||||||
{
|
{
|
||||||
if(cmd == kEEPROMErase)
|
SaveKey& skey = static_cast<SaveKey&>(myController);
|
||||||
{
|
|
||||||
SaveKey& skey = static_cast<SaveKey&>(myController);
|
skey.eraseCurrent();
|
||||||
skey.myEEPROM->erase();
|
}
|
||||||
}
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
bool SaveKeyWidget::isPageUsed(uInt32 page)
|
||||||
|
{
|
||||||
|
SaveKey& skey = static_cast<SaveKey&>(myController);
|
||||||
|
|
||||||
|
return skey.isPageUsed(page);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,10 @@
|
||||||
#ifndef SAVEKEY_WIDGET_HXX
|
#ifndef SAVEKEY_WIDGET_HXX
|
||||||
#define SAVEKEY_WIDGET_HXX
|
#define SAVEKEY_WIDGET_HXX
|
||||||
|
|
||||||
class ButtonWidget;
|
|
||||||
|
|
||||||
#include "Control.hxx"
|
#include "Control.hxx"
|
||||||
#include "ControllerWidget.hxx"
|
#include "FlashWidget.hxx"
|
||||||
|
|
||||||
class SaveKeyWidget : public ControllerWidget
|
class SaveKeyWidget : public FlashWidget
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SaveKeyWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
SaveKeyWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
||||||
|
@ -31,12 +29,8 @@ class SaveKeyWidget : public ControllerWidget
|
||||||
virtual ~SaveKeyWidget() = default;
|
virtual ~SaveKeyWidget() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ButtonWidget* myEEPROMErase;
|
void eraseCurrent() override;
|
||||||
enum { kEEPROMErase = 'eeER' };
|
bool isPageUsed(uInt32 page) override;
|
||||||
|
|
||||||
private:
|
|
||||||
void loadConfig() override { }
|
|
||||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
|
||||||
|
|
||||||
// Following constructors and assignment operators not supported
|
// Following constructors and assignment operators not supported
|
||||||
SaveKeyWidget() = delete;
|
SaveKeyWidget() = delete;
|
||||||
|
|
|
@ -202,7 +202,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// P0 reflect
|
// P0 reflect
|
||||||
xpos += myHMP0->getWidth() + 15;
|
xpos += myHMP0->getWidth() + 15;
|
||||||
myRefP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myRefP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"Reflect", kCheckActionCmd);
|
"Reflect", CheckboxWidget::kCheckActionCmd);
|
||||||
myRefP0->setTarget(this);
|
myRefP0->setTarget(this);
|
||||||
myRefP0->setID(kRefP0ID);
|
myRefP0->setID(kRefP0ID);
|
||||||
addFocusWidget(myRefP0);
|
addFocusWidget(myRefP0);
|
||||||
|
@ -226,7 +226,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// P0 delay
|
// P0 delay
|
||||||
xpos += myGRP0Old->getWidth() + 12;
|
xpos += myGRP0Old->getWidth() + 12;
|
||||||
myDelP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myDelP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"VDel", kCheckActionCmd);
|
"VDel", CheckboxWidget::kCheckActionCmd);
|
||||||
myDelP0->setTarget(this);
|
myDelP0->setTarget(this);
|
||||||
myDelP0->setID(kDelP0ID);
|
myDelP0->setID(kDelP0ID);
|
||||||
addFocusWidget(myDelP0);
|
addFocusWidget(myDelP0);
|
||||||
|
@ -287,7 +287,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// P1 reflect
|
// P1 reflect
|
||||||
xpos += myHMP1->getWidth() + 15;
|
xpos += myHMP1->getWidth() + 15;
|
||||||
myRefP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myRefP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"Reflect", kCheckActionCmd);
|
"Reflect", CheckboxWidget::kCheckActionCmd);
|
||||||
myRefP1->setTarget(this);
|
myRefP1->setTarget(this);
|
||||||
myRefP1->setID(kRefP1ID);
|
myRefP1->setID(kRefP1ID);
|
||||||
addFocusWidget(myRefP1);
|
addFocusWidget(myRefP1);
|
||||||
|
@ -310,7 +310,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// P1 delay
|
// P1 delay
|
||||||
xpos += myGRP1Old->getWidth() + 12;
|
xpos += myGRP1Old->getWidth() + 12;
|
||||||
myDelP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myDelP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"VDel", kCheckActionCmd);
|
"VDel", CheckboxWidget::kCheckActionCmd);
|
||||||
myDelP1->setTarget(this);
|
myDelP1->setTarget(this);
|
||||||
myDelP1->setID(kDelP1ID);
|
myDelP1->setID(kDelP1ID);
|
||||||
addFocusWidget(myDelP1);
|
addFocusWidget(myDelP1);
|
||||||
|
@ -382,7 +382,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// M0 reset to player 0
|
// M0 reset to player 0
|
||||||
xpos += myNusizM0->getWidth() + 15;
|
xpos += myNusizM0->getWidth() + 15;
|
||||||
myResMP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myResMP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"Reset to P0", kCheckActionCmd);
|
"Reset to P0", CheckboxWidget::kCheckActionCmd);
|
||||||
myResMP0->setTarget(this);
|
myResMP0->setTarget(this);
|
||||||
myResMP0->setID(kResMP0ID);
|
myResMP0->setID(kResMP0ID);
|
||||||
addFocusWidget(myResMP0);
|
addFocusWidget(myResMP0);
|
||||||
|
@ -445,7 +445,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// M1 reset to player 0
|
// M1 reset to player 0
|
||||||
xpos += myNusizM1->getWidth() + 15;
|
xpos += myNusizM1->getWidth() + 15;
|
||||||
myResMP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myResMP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"Reset to P1", kCheckActionCmd);
|
"Reset to P1", CheckboxWidget::kCheckActionCmd);
|
||||||
myResMP1->setTarget(this);
|
myResMP1->setTarget(this);
|
||||||
myResMP1->setID(kResMP1ID);
|
myResMP1->setID(kResMP1ID);
|
||||||
addFocusWidget(myResMP1);
|
addFocusWidget(myResMP1);
|
||||||
|
@ -523,7 +523,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// Ball delay
|
// Ball delay
|
||||||
xpos += myEnaBLOld->getWidth() + 12;
|
xpos += myEnaBLOld->getWidth() + 12;
|
||||||
myDelBL = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myDelBL = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"VDel", kCheckActionCmd);
|
"VDel", CheckboxWidget::kCheckActionCmd);
|
||||||
myDelBL->setTarget(this);
|
myDelBL->setTarget(this);
|
||||||
myDelBL->setID(kDelBLID);
|
myDelBL->setID(kDelBLID);
|
||||||
addFocusWidget(myDelBL);
|
addFocusWidget(myDelBL);
|
||||||
|
@ -561,7 +561,7 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
addFocusWidget(myPF[2]);
|
addFocusWidget(myPF[2]);
|
||||||
|
|
||||||
// PFx bit labels
|
// 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;
|
int colw = myPF[0]->getWidth() / 4;
|
||||||
xpos = 10 + 2*fontWidth + 5 + start(colw);
|
xpos = 10 + 2*fontWidth + 5 + start(colw);
|
||||||
int _ypos = ypos - sfHeight;
|
int _ypos = ypos - sfHeight;
|
||||||
|
@ -590,21 +590,21 @@ TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||||
// PF reflect, score, priority
|
// PF reflect, score, priority
|
||||||
xpos = 10 + 4*fontWidth; ypos += lineHeight + 6;
|
xpos = 10 + 4*fontWidth; ypos += lineHeight + 6;
|
||||||
myRefPF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myRefPF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"Reflect", kCheckActionCmd);
|
"Reflect", CheckboxWidget::kCheckActionCmd);
|
||||||
myRefPF->setTarget(this);
|
myRefPF->setTarget(this);
|
||||||
myRefPF->setID(kRefPFID);
|
myRefPF->setID(kRefPFID);
|
||||||
addFocusWidget(myRefPF);
|
addFocusWidget(myRefPF);
|
||||||
|
|
||||||
xpos += myRefPF->getWidth() + 15;
|
xpos += myRefPF->getWidth() + 15;
|
||||||
myScorePF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myScorePF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"Score", kCheckActionCmd);
|
"Score", CheckboxWidget::kCheckActionCmd);
|
||||||
myScorePF->setTarget(this);
|
myScorePF->setTarget(this);
|
||||||
myScorePF->setID(kScorePFID);
|
myScorePF->setID(kScorePFID);
|
||||||
addFocusWidget(myScorePF);
|
addFocusWidget(myScorePF);
|
||||||
|
|
||||||
xpos += myScorePF->getWidth() + 15;
|
xpos += myScorePF->getWidth() + 15;
|
||||||
myPriorityPF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
myPriorityPF = new CheckboxWidget(boss, lfont, xpos, ypos+1,
|
||||||
"Priority", kCheckActionCmd);
|
"Priority", CheckboxWidget::kCheckActionCmd);
|
||||||
myPriorityPF->setTarget(this);
|
myPriorityPF->setTarget(this);
|
||||||
myPriorityPF->setID(kPriorityPFID);
|
myPriorityPF->setID(kPriorityPFID);
|
||||||
addFocusWidget(myPriorityPF);
|
addFocusWidget(myPriorityPF);
|
||||||
|
@ -833,7 +833,7 @@ void TiaWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kCheckActionCmd:
|
case CheckboxWidget::kCheckActionCmd:
|
||||||
switch(id)
|
switch(id)
|
||||||
{
|
{
|
||||||
case kRefP0ID:
|
case kRefP0ID:
|
||||||
|
|
|
@ -202,7 +202,7 @@ void ToggleWidget::handleCommand(CommandSender* sender, int cmd,
|
||||||
{
|
{
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case kSetPositionCmd:
|
case GuiObject::kSetPositionCmd:
|
||||||
if (_selectedItem != data)
|
if (_selectedItem != data)
|
||||||
{
|
{
|
||||||
_selectedItem = data;
|
_selectedItem = data;
|
||||||
|
|
|
@ -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];
|
||||||
|
}
|
|
@ -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 := src/debugger/gui
|
||||||
|
|
||||||
MODULE_OBJS := \
|
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/AudioWidget.o \
|
||||||
src/debugger/gui/CpuWidget.o \
|
src/debugger/gui/BoosterWidget.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/Cart0840Widget.o \
|
src/debugger/gui/Cart0840Widget.o \
|
||||||
src/debugger/gui/Cart2KWidget.o \
|
src/debugger/gui/Cart2KWidget.o \
|
||||||
src/debugger/gui/Cart3EWidget.o \
|
|
||||||
src/debugger/gui/Cart3EPlusWidget.o \
|
src/debugger/gui/Cart3EPlusWidget.o \
|
||||||
|
src/debugger/gui/Cart3EWidget.o \
|
||||||
src/debugger/gui/Cart3FWidget.o \
|
src/debugger/gui/Cart3FWidget.o \
|
||||||
src/debugger/gui/Cart4A50Widget.o \
|
src/debugger/gui/Cart4A50Widget.o \
|
||||||
src/debugger/gui/Cart4KWidget.o \
|
|
||||||
src/debugger/gui/Cart4KSCWidget.o \
|
src/debugger/gui/Cart4KSCWidget.o \
|
||||||
|
src/debugger/gui/Cart4KWidget.o \
|
||||||
src/debugger/gui/CartARWidget.o \
|
src/debugger/gui/CartARWidget.o \
|
||||||
|
src/debugger/gui/CartBFSCWidget.o \
|
||||||
|
src/debugger/gui/CartBFWidget.o \
|
||||||
src/debugger/gui/CartBUSWidget.o \
|
src/debugger/gui/CartBUSWidget.o \
|
||||||
src/debugger/gui/CartCDFWidget.o \
|
src/debugger/gui/CartCDFWidget.o \
|
||||||
src/debugger/gui/CartCMWidget.o \
|
src/debugger/gui/CartCMWidget.o \
|
||||||
src/debugger/gui/CartCTYWidget.o \
|
src/debugger/gui/CartCTYWidget.o \
|
||||||
src/debugger/gui/CartCVWidget.o \
|
|
||||||
src/debugger/gui/CartCVPlusWidget.o \
|
src/debugger/gui/CartCVPlusWidget.o \
|
||||||
|
src/debugger/gui/CartCVWidget.o \
|
||||||
src/debugger/gui/CartDASHWidget.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/CartDPCPlusWidget.o \
|
||||||
|
src/debugger/gui/CartDPCWidget.o \
|
||||||
src/debugger/gui/CartE0Widget.o \
|
src/debugger/gui/CartE0Widget.o \
|
||||||
src/debugger/gui/CartE7Widget.o \
|
src/debugger/gui/CartE7Widget.o \
|
||||||
src/debugger/gui/CartEFWidget.o \
|
|
||||||
src/debugger/gui/CartEFSCWidget.o \
|
src/debugger/gui/CartEFSCWidget.o \
|
||||||
src/debugger/gui/CartBFWidget.o \
|
src/debugger/gui/CartEFWidget.o \
|
||||||
src/debugger/gui/CartBFSCWidget.o \
|
|
||||||
src/debugger/gui/CartDFWidget.o \
|
|
||||||
src/debugger/gui/CartDFSCWidget.o \
|
|
||||||
src/debugger/gui/CartF0Widget.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/CartF4SCWidget.o \
|
||||||
|
src/debugger/gui/CartF4Widget.o \
|
||||||
src/debugger/gui/CartF6SCWidget.o \
|
src/debugger/gui/CartF6SCWidget.o \
|
||||||
|
src/debugger/gui/CartF6Widget.o \
|
||||||
src/debugger/gui/CartF8SCWidget.o \
|
src/debugger/gui/CartF8SCWidget.o \
|
||||||
src/debugger/gui/CartFAWidget.o \
|
src/debugger/gui/CartF8Widget.o \
|
||||||
src/debugger/gui/CartFA2Widget.o \
|
src/debugger/gui/CartFA2Widget.o \
|
||||||
|
src/debugger/gui/CartFAWidget.o \
|
||||||
src/debugger/gui/CartFEWidget.o \
|
src/debugger/gui/CartFEWidget.o \
|
||||||
src/debugger/gui/CartMDMWidget.o \
|
src/debugger/gui/CartMDMWidget.o \
|
||||||
|
src/debugger/gui/CartRamWidget.o \
|
||||||
src/debugger/gui/CartSBWidget.o \
|
src/debugger/gui/CartSBWidget.o \
|
||||||
src/debugger/gui/CartUAWidget.o \
|
src/debugger/gui/CartUAWidget.o \
|
||||||
src/debugger/gui/CartWDWidget.o \
|
src/debugger/gui/CartWDWidget.o \
|
||||||
src/debugger/gui/CartX07Widget.o \
|
src/debugger/gui/CartX07Widget.o \
|
||||||
src/debugger/gui/JoystickWidget.o \
|
src/debugger/gui/CpuWidget.o \
|
||||||
src/debugger/gui/PaddleWidget.o \
|
src/debugger/gui/DataGridOpsWidget.o \
|
||||||
src/debugger/gui/BoosterWidget.o \
|
src/debugger/gui/DataGridWidget.o \
|
||||||
|
src/debugger/gui/DebuggerDialog.o \
|
||||||
|
src/debugger/gui/DelayQueueWidget.o \
|
||||||
src/debugger/gui/DrivingWidget.o \
|
src/debugger/gui/DrivingWidget.o \
|
||||||
src/debugger/gui/KeyboardWidget.o \
|
src/debugger/gui/FlashWidget.o \
|
||||||
src/debugger/gui/GenesisWidget.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/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 += \
|
MODULE_DIRS += \
|
||||||
src/debugger/gui
|
src/debugger/gui
|
||||||
|
|
|
@ -38,8 +38,8 @@ class AmigaMouse : public PointingDevice
|
||||||
protected:
|
protected:
|
||||||
uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
|
uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
|
||||||
{
|
{
|
||||||
static constexpr uInt32 ourTableH[4] = { 0x00, 0x80, 0xa0, 0x20 };
|
static constexpr uInt32 ourTableH[4] = { 0b0000, 0b1000, 0b1010, 0b0010 };
|
||||||
static constexpr uInt32 ourTableV[4] = { 0x00, 0x10, 0x50, 0x40 };
|
static constexpr uInt32 ourTableV[4] = { 0b0000, 0b0100, 0b0101, 0b0001 };
|
||||||
|
|
||||||
return ourTableH[countH] | ourTableV[countV];
|
return ourTableH[countH] | ourTableV[countV];
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,8 @@ class AtariMouse : public PointingDevice
|
||||||
protected:
|
protected:
|
||||||
uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
|
uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override
|
||||||
{
|
{
|
||||||
static constexpr uInt32 ourTableH[4] = { 0x00, 0x10, 0x30, 0x20 };
|
static constexpr uInt32 ourTableH[4] = { 0b0000, 0b0001, 0b0011, 0b0010 };
|
||||||
static constexpr uInt32 ourTableV[4] = { 0x00, 0x80, 0xc0, 0x40 };
|
static constexpr uInt32 ourTableV[4] = { 0b0000, 0b0100, 0b1100, 0b1000 };
|
||||||
|
|
||||||
return ourTableH[countH] | ourTableV[countV];
|
return ourTableH[countH] | ourTableV[countV];
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include "MT24LC256.hxx"
|
|
||||||
#include "SerialPort.hxx"
|
#include "SerialPort.hxx"
|
||||||
#include "System.hxx"
|
#include "System.hxx"
|
||||||
#include "AtariVox.hxx"
|
#include "AtariVox.hxx"
|
||||||
|
@ -24,7 +23,7 @@
|
||||||
AtariVox::AtariVox(Jack jack, const Event& event, const System& system,
|
AtariVox::AtariVox(Jack jack, const Event& event, const System& system,
|
||||||
const SerialPort& port, const string& portname,
|
const SerialPort& port, const string& portname,
|
||||||
const string& eepromfile)
|
const string& eepromfile)
|
||||||
: Controller(jack, event, system, Controller::AtariVox),
|
: SaveKey(jack, event, system, eepromfile, Controller::AtariVox),
|
||||||
mySerialPort(const_cast<SerialPort&>(port)),
|
mySerialPort(const_cast<SerialPort&>(port)),
|
||||||
myShiftCount(0),
|
myShiftCount(0),
|
||||||
myShiftRegister(0),
|
myShiftRegister(0),
|
||||||
|
@ -35,9 +34,6 @@ AtariVox::AtariVox(Jack jack, const Event& event, const System& system,
|
||||||
else
|
else
|
||||||
myAboutString = " (invalid serial port \'" + portname + "\')";
|
myAboutString = " (invalid serial port \'" + portname + "\')";
|
||||||
|
|
||||||
myEEPROM = make_unique<MT24LC256>(eepromfile, system);
|
|
||||||
|
|
||||||
myDigitalPinState[One] = myDigitalPinState[Two] =
|
|
||||||
myDigitalPinState[Three] = myDigitalPinState[Four] = true;
|
myDigitalPinState[Three] = myDigitalPinState[Four] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,13 +50,8 @@ bool AtariVox::read(DigitalPin pin)
|
||||||
// For now, we just assume the device is always ready
|
// For now, we just assume the device is always ready
|
||||||
return myDigitalPinState[Two] = true;
|
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:
|
default:
|
||||||
return Controller::read(pin);
|
return SaveKey::read(pin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,22 +68,8 @@ void AtariVox::write(DigitalPin pin, bool value)
|
||||||
clockDataIn(value);
|
clockDataIn(value);
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
SaveKey::write(pin, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,18 +118,5 @@ void AtariVox::clockDataIn(bool value)
|
||||||
void AtariVox::reset()
|
void AtariVox::reset()
|
||||||
{
|
{
|
||||||
myLastDataWriteCycle = 0;
|
myLastDataWriteCycle = 0;
|
||||||
myEEPROM->systemReset();
|
SaveKey::reset();
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void AtariVox::close()
|
|
||||||
{
|
|
||||||
// Force the EEPROM object to cleanup
|
|
||||||
myEEPROM.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
string AtariVox::about() const
|
|
||||||
{
|
|
||||||
return Controller::about() + myAboutString;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
class SerialPort;
|
class SerialPort;
|
||||||
|
|
||||||
#include "Control.hxx"
|
#include "Control.hxx"
|
||||||
|
#include "SaveKey.hxx"
|
||||||
#include "MT24LC256.hxx"
|
#include "MT24LC256.hxx"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,10 +33,8 @@ class SerialPort;
|
||||||
|
|
||||||
@author B. Watson
|
@author B. Watson
|
||||||
*/
|
*/
|
||||||
class AtariVox : public Controller
|
class AtariVox : public SaveKey
|
||||||
{
|
{
|
||||||
friend class AtariVoxWidget;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
Create a new AtariVox controller plugged into the specified jack
|
Create a new AtariVox controller plugged into the specified jack
|
||||||
|
@ -86,18 +85,10 @@ class AtariVox : public Controller
|
||||||
*/
|
*/
|
||||||
void reset() override;
|
void reset() override;
|
||||||
|
|
||||||
/**
|
string about(bool swappedPorts) const override { return Controller::about(swappedPorts) + myAboutString; }
|
||||||
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;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void clockDataIn(bool value);
|
void clockDataIn(bool value);
|
||||||
void shiftIn(bool value);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Instance of an real serial port on the system
|
// Instance of an real serial port on the system
|
||||||
|
@ -105,9 +96,6 @@ class AtariVox : public Controller
|
||||||
// bytes directly to it
|
// bytes directly to it
|
||||||
SerialPort& mySerialPort;
|
SerialPort& mySerialPort;
|
||||||
|
|
||||||
// The EEPROM used in the AtariVox
|
|
||||||
unique_ptr<MT24LC256> myEEPROM;
|
|
||||||
|
|
||||||
// How many bits have been shifted into the shift register?
|
// How many bits have been shifted into the shift register?
|
||||||
uInt8 myShiftCount;
|
uInt8 myShiftCount;
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,7 @@ bool Cartridge3E::bank(uInt16 bank)
|
||||||
mySystem->setPageAccess(addr, access);
|
mySystem->setPageAccess(addr, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
access.directPeekBase = 0;
|
access.directPeekBase = nullptr;
|
||||||
access.type = System::PA_WRITE;
|
access.type = System::PA_WRITE;
|
||||||
|
|
||||||
// Map write-port RAM image into the system
|
// Map write-port RAM image into the system
|
||||||
|
|
|
@ -152,12 +152,17 @@ class Cartridge4A50 : public Cartridge
|
||||||
|
|
||||||
private:
|
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 address The address to query
|
||||||
@param flags A bitfield of DisasmType directives for the given address
|
|
||||||
*/
|
*/
|
||||||
uInt8 getAccessFlags(uInt16 address) const override;
|
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;
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -156,12 +156,17 @@ class CartridgeAR : public Cartridge
|
||||||
|
|
||||||
private:
|
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 address The address to query
|
||||||
@param flags A bitfield of DisasmType directives for the given address
|
|
||||||
*/
|
*/
|
||||||
uInt8 getAccessFlags(uInt16 address) const override;
|
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;
|
void setAccessFlags(uInt16 address, uInt8 flags) override;
|
||||||
|
|
||||||
// Handle a change to the bank configuration
|
// 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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,7 +65,8 @@ CartridgeBUS::CartridgeBUS(const BytePtr& image, uInt32 size,
|
||||||
|
|
||||||
#ifdef THUMB_SUPPORT
|
#ifdef THUMB_SUPPORT
|
||||||
// Create Thumbulator ARM emulator
|
// 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);
|
settings.getBool("thumb.trapfatal"), Thumbulator::ConfigureFor::BUS, this);
|
||||||
#endif
|
#endif
|
||||||
setInitialState();
|
setInitialState();
|
||||||
|
@ -528,7 +529,6 @@ uInt32 CartridgeBUS::thumbCallback(uInt8 function, uInt32 value1, uInt32 value2)
|
||||||
// _GetWavePtr - return the counter
|
// _GetWavePtr - return the counter
|
||||||
case 2:
|
case 2:
|
||||||
return myMusicCounters[value1];
|
return myMusicCounters[value1];
|
||||||
break;
|
|
||||||
|
|
||||||
// _SetWaveSize - set size of waveform buffer
|
// _SetWaveSize - set size of waveform buffer
|
||||||
case 3:
|
case 3:
|
||||||
|
|
|
@ -69,9 +69,9 @@ CartridgeCDF::CartridgeCDF(const BytePtr& image, uInt32 size,
|
||||||
#ifdef THUMB_SUPPORT
|
#ifdef THUMB_SUPPORT
|
||||||
// Create Thumbulator ARM emulator
|
// Create Thumbulator ARM emulator
|
||||||
myThumbEmulator = make_unique<Thumbulator>(
|
myThumbEmulator = make_unique<Thumbulator>(
|
||||||
(uInt16*)myImage, (uInt16*)myCDFRAM, settings.getBool("thumb.trapfatal"),
|
reinterpret_cast<uInt16*>(myImage), reinterpret_cast<uInt16*>(myCDFRAM),
|
||||||
myVersion ? Thumbulator::ConfigureFor::CDF1 : Thumbulator::ConfigureFor::CDF,
|
settings.getBool("thumb.trapfatal"), myVersion ?
|
||||||
this);
|
Thumbulator::ConfigureFor::CDF1 : Thumbulator::ConfigureFor::CDF, this);
|
||||||
#endif
|
#endif
|
||||||
setInitialState();
|
setInitialState();
|
||||||
}
|
}
|
||||||
|
@ -465,7 +465,6 @@ uInt32 CartridgeCDF::thumbCallback(uInt8 function, uInt32 value1, uInt32 value2)
|
||||||
// _GetWavePtr - return the counter
|
// _GetWavePtr - return the counter
|
||||||
case 2:
|
case 2:
|
||||||
return myMusicCounters[value1];
|
return myMusicCounters[value1];
|
||||||
break;
|
|
||||||
|
|
||||||
// _SetWaveSize - set size of waveform buffer
|
// _SetWaveSize - set size of waveform buffer
|
||||||
case 3:
|
case 3:
|
||||||
|
|
|
@ -143,7 +143,7 @@ bool CartridgeCM::bank(uInt16 bank)
|
||||||
if((mySWCHA & 0x30) == 0x20)
|
if((mySWCHA & 0x30) == 0x20)
|
||||||
access.directPokeBase = &myRAM[addr & 0x7FF];
|
access.directPokeBase = &myRAM[addr & 0x7FF];
|
||||||
else
|
else
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
|
|
||||||
mySystem->setPageAccess(addr, access);
|
mySystem->setPageAccess(addr, access);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,8 +74,8 @@ void CartridgeCV::install(System& system)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the page accessing method for the RAM writing pages
|
// Set the page accessing method for the RAM writing pages
|
||||||
access.directPeekBase = 0;
|
access.directPeekBase = nullptr;
|
||||||
access.codeAccessBase = 0;
|
access.codeAccessBase = nullptr;
|
||||||
access.type = System::PA_WRITE;
|
access.type = System::PA_WRITE;
|
||||||
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
|
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,8 +58,8 @@ void CartridgeCVPlus::install(System& system)
|
||||||
mySystem->setPageAccess(addr, access);
|
mySystem->setPageAccess(addr, access);
|
||||||
|
|
||||||
// Set the page accessing method for the RAM writing pages
|
// Set the page accessing method for the RAM writing pages
|
||||||
access.directPeekBase = 0;
|
access.directPeekBase = nullptr;
|
||||||
access.codeAccessBase = 0;
|
access.codeAccessBase = nullptr;
|
||||||
access.type = System::PA_WRITE;
|
access.type = System::PA_WRITE;
|
||||||
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,7 +57,7 @@ void CartridgeE0::install(System& system)
|
||||||
myCurrentSlice[3] = 7;
|
myCurrentSlice[3] = 7;
|
||||||
|
|
||||||
// Set the page accessing methods for the hot spots in the last segment
|
// Set the page accessing methods for the hot spots in the last segment
|
||||||
access.directPeekBase = 0;
|
access.directPeekBase = nullptr;
|
||||||
access.codeAccessBase = &myCodeAccessBase[8128];
|
access.codeAccessBase = &myCodeAccessBase[8128];
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
|
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
|
// Set the page accessing method for the 256 bytes of RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1900; addr < 0x1A00; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the 1K slice of RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE)
|
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
|
// Set the page accessing method for the RAM reading pages
|
||||||
access.directPokeBase = 0;
|
access.directPokeBase = nullptr;
|
||||||
access.type = System::PA_READ;
|
access.type = System::PA_READ;
|
||||||
for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE)
|
for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -132,8 +132,6 @@ uInt8 CartridgeWD::peek(uInt16 address)
|
||||||
else
|
else
|
||||||
return mySegment3[address & 0x03FF];
|
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& lp = myConsole.leftController();
|
||||||
Controller& rp = myConsole.rightController();
|
Controller& rp = myConsole.rightController();
|
||||||
|
|
||||||
|
|
||||||
lp.myAnalogPinValue[Controller::Nine] = Controller::maximumResistance;
|
lp.myAnalogPinValue[Controller::Nine] = Controller::maximumResistance;
|
||||||
lp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance;
|
lp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance;
|
||||||
lp.myDigitalPinState[Controller::Six] = true;
|
lp.myDigitalPinState[Controller::Six] = true;
|
||||||
|
|
|
@ -109,8 +109,6 @@ class CompuMate
|
||||||
Called after *all* digital pins have been written on Port A.
|
Called after *all* digital pins have been written on Port A.
|
||||||
Only update on the left controller; the right controller will
|
Only update on the left controller; the right controller will
|
||||||
happen at the same cycle and is redundant.
|
happen at the same cycle and is redundant.
|
||||||
|
|
||||||
@param value The entire contents of the SWCHA register
|
|
||||||
*/
|
*/
|
||||||
void controlWrite(uInt8) override {
|
void controlWrite(uInt8) override {
|
||||||
if(myJack == Controller::Left) myHandler.update();
|
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
|
// Finally, add remaining info about the console
|
||||||
myConsoleInfo.CartName = myProperties.get(Cartridge_Name);
|
myConsoleInfo.CartName = myProperties.get(Cartridge_Name);
|
||||||
myConsoleInfo.CartMD5 = myProperties.get(Cartridge_MD5);
|
myConsoleInfo.CartMD5 = myProperties.get(Cartridge_MD5);
|
||||||
myConsoleInfo.Control0 = myLeftControl->about();
|
bool swappedPorts = properties().get(Console_SwapPorts) == "YES";
|
||||||
myConsoleInfo.Control1 = myRightControl->about();
|
myConsoleInfo.Control0 = myLeftControl->about(swappedPorts);
|
||||||
|
myConsoleInfo.Control1 = myRightControl->about(swappedPorts);
|
||||||
myConsoleInfo.BankSwitch = myCart->about();
|
myConsoleInfo.BankSwitch = myCart->about();
|
||||||
|
|
||||||
myCart->setRomName(myConsoleInfo.CartName);
|
myCart->setRomName(myConsoleInfo.CartName);
|
||||||
|
@ -724,13 +725,9 @@ void Console::setTIAProperties()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Console::setControllers(const string& rommd5)
|
void Console::setControllers(const string& rommd5)
|
||||||
{
|
{
|
||||||
// Setup the controllers based on properties
|
// Check for CompuMate scheme; it is special in that a handler creates both
|
||||||
const string& left = myProperties.get(Controller_Left);
|
// controllers for us, and associates them with the bankswitching class
|
||||||
const string& right = myProperties.get(Controller_Right);
|
if(myCart->detectedType() == "CM")
|
||||||
|
|
||||||
// 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")
|
|
||||||
{
|
{
|
||||||
myCMHandler = make_shared<CompuMate>(*this, myEvent, *mySystem);
|
myCMHandler = make_shared<CompuMate>(*this, myEvent, *mySystem);
|
||||||
|
|
||||||
|
@ -743,153 +740,114 @@ void Console::setControllers(const string& rommd5)
|
||||||
|
|
||||||
myLeftControl = std::move(myCMHandler->leftController());
|
myLeftControl = std::move(myCMHandler->leftController());
|
||||||
myRightControl = std::move(myCMHandler->rightController());
|
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
|
else
|
||||||
{
|
{
|
||||||
myLeftControl = std::move(rightC);
|
// Setup the controllers based on properties
|
||||||
myRightControl = std::move(leftC);
|
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();
|
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()
|
void Console::loadUserPalette()
|
||||||
{
|
{
|
||||||
|
@ -953,7 +911,7 @@ void Console::generateColorLossPalette()
|
||||||
uInt32* palette[9] = {
|
uInt32* palette[9] = {
|
||||||
&ourNTSCPalette[0], &ourPALPalette[0], &ourSECAMPalette[0],
|
&ourNTSCPalette[0], &ourPALPalette[0], &ourSECAMPalette[0],
|
||||||
&ourNTSCPaletteZ26[0], &ourPALPaletteZ26[0], &ourSECAMPaletteZ26[0],
|
&ourNTSCPaletteZ26[0], &ourPALPaletteZ26[0], &ourSECAMPaletteZ26[0],
|
||||||
0, 0, 0
|
nullptr, nullptr, nullptr
|
||||||
};
|
};
|
||||||
if(myUserPaletteDefined)
|
if(myUserPaletteDefined)
|
||||||
{
|
{
|
||||||
|
@ -964,7 +922,7 @@ void Console::generateColorLossPalette()
|
||||||
|
|
||||||
for(int i = 0; i < 9; ++i)
|
for(int i = 0; i < 9; ++i)
|
||||||
{
|
{
|
||||||
if(palette[i] == 0)
|
if(palette[i] == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Fill the odd numbered palette entries with gray values (calculated
|
// Fill the odd numbered palette entries with gray values (calculated
|
||||||
|
|
|
@ -326,6 +326,12 @@ class Console : public Serializable
|
||||||
*/
|
*/
|
||||||
void setControllers(const string& rommd5);
|
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
|
Loads a user-defined palette file (from OSystem::paletteFile), filling the
|
||||||
appropriate user-defined palette arrays.
|
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