Added debugger pseudo-registers to detect timer access on wraparound (fixes #606).

This commit is contained in:
Stephen Anthony 2020-10-05 16:48:57 -02:30
parent ad6a930e83
commit 282e082862
13 changed files with 659 additions and 470 deletions

View File

@ -53,6 +53,10 @@
* Added option to disable aspect correct scaling. * Added option to disable aspect correct scaling.
* Added debugger pseudo-registers '_timwrapread' and '_timwrapwrite',
which are set when the RIOT timer is read/written on timer wraparound,
respectively.
* Bankswitching schemes BUS, DPC+ and CDFx now work when startup bank * Bankswitching schemes BUS, DPC+ and CDFx now work when startup bank
randomization is enabled (these schemes now ignore that setting). randomization is enabled (these schemes now ignore that setting).

View File

@ -877,23 +877,26 @@ std::array<Debugger::BuiltinFunction, 18> Debugger::ourBuiltinFunctions = { {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Names are defined here, but processed in YaccParser // Names are defined here, but processed in YaccParser
std::array<Debugger::PseudoRegister, 12> Debugger::ourPseudoRegisters = { { std::array<Debugger::PseudoRegister, 14> Debugger::ourPseudoRegisters = { {
// Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = { // Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = {
{ "_bank", "Currently selected bank" }, { "_bank", "Currently selected bank" },
{ "_cclocks", "Color clocks on current scanline" }, { "_cclocks", "Color clocks on current scanline" },
{ "_cycleshi", "Higher 32 bits of number of cycles since emulation started" }, { "_cycleshi", "Higher 32 bits of number of cycles since emulation started" },
{ "_cycleslo", "Lower 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" }, { "_fcount", "Number of frames since emulation started" },
{ "_fcycles", "Number of cycles since frame started" }, { "_fcycles", "Number of cycles since frame started" },
{ "_icycles", "Number of cycles of last instruction" }, { "_icycles", "Number of cycles of last instruction" },
{ "_scan", "Current scanline count" }, { "_scan", "Current scanline count" },
{ "_scanend", "Scanline count at end of last frame" }, { "_scanend", "Scanline count at end of last frame" },
{ "_scycles", "Number of cycles in current scanline" }, { "_scycles", "Number of cycles in current scanline" },
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" }, { "_timwrapread", "Timer read wrapped on this cycle" },
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" } { "_timwrapwrite", "Timer write wrapped on this cycle" },
{ "_vblank", "Whether vertical blank is enabled (1 or 0)" },
{ "_vsync", "Whether vertical sync is enabled (1 or 0)" }
// CPU address access functions: // CPU address access functions:
/*{ "_lastread", "last CPU read address" }, /*{ "_lastread", "last CPU read address" },
{ "_lastwrite", "last CPU write address" }, { "_lastwrite", "last CPU write address" },
{ "__lastbaseread", "last CPU read base address" }, { "__lastbaseread", "last CPU read base address" },
{ "__lastbasewrite", "last CPU write base address" }*/ { "__lastbasewrite", "last CPU write base address" }*/
} }; } };
//

View File

@ -363,7 +363,7 @@ class Debugger : public DialogContainer
string name, help; string name, help;
}; };
static std::array<BuiltinFunction, 18> ourBuiltinFunctions; static std::array<BuiltinFunction, 18> ourBuiltinFunctions;
static std::array<PseudoRegister, 12> ourPseudoRegisters; static std::array<PseudoRegister, 14> ourPseudoRegisters;
private: private:
// rewind/unwind n states // rewind/unwind n states

View File

@ -23,6 +23,7 @@
#include "bspf.hxx" #include "bspf.hxx"
#include "CartDebug.hxx" #include "CartDebug.hxx"
#include "CpuDebug.hxx" #include "CpuDebug.hxx"
#include "RiotDebug.hxx"
#include "TIADebug.hxx" #include "TIADebug.hxx"
#include "Debugger.hxx" #include "Debugger.hxx"
#include "Expression.hxx" #include "Expression.hxx"
@ -310,6 +311,18 @@ class ShiftRightExpression : public Expression
{ return myLHS->evaluate() >> myRHS->evaluate(); } { return myLHS->evaluate() >> myRHS->evaluate(); }
}; };
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class RiotMethodExpression : public Expression
{
public:
RiotMethodExpression(RiotMethod method) : Expression(), myMethod(std::mem_fn(method)) { }
Int32 evaluate() const override
{ return myMethod(Debugger::debugger().riotDebug()); }
private:
std::function<int(const RiotDebug&)> myMethod;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class TiaMethodExpression : public Expression class TiaMethodExpression : public Expression
{ {

View File

@ -235,6 +235,18 @@ Int32 RiotDebug::timDivider() const
return mySystem.m6532().myDivider; return mySystem.m6532().myDivider;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int RiotDebug::timWrappedOnRead() const
{
return mySystem.m6532().myTimWrappedOnRead;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int RiotDebug::timWrappedOnWrite() const
{
return mySystem.m6532().myTimWrappedOnWrite;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool RiotDebug::diffP0(int newVal) bool RiotDebug::diffP0(int newVal)
{ {

View File

@ -22,6 +22,10 @@ class M6532;
class Debugger; class Debugger;
class RiotDebug; class RiotDebug;
// Function type for RiotDebug instance methods
class RiotDebug;
using RiotMethod = int (RiotDebug::*)() const;
#include "DebuggerSystem.hxx" #include "DebuggerSystem.hxx"
class RiotState : public DebuggerState class RiotState : public DebuggerState
@ -75,6 +79,9 @@ class RiotDebug : public DebuggerSystem
Int32 timClocks() const; Int32 timClocks() const;
Int32 intimClocks() const; Int32 intimClocks() const;
Int32 timDivider() const; Int32 timDivider() const;
/* Debugger pseudo-registers for timer accesses */
int timWrappedOnRead() const;
int timWrappedOnWrite() const;
/* Console switches */ /* Console switches */
bool diffP0(int newVal = -1); bool diffP0(int newVal = -1);

View File

@ -145,6 +145,10 @@ void M6532::updateEmulation()
} }
myLastCycle = mySystem->cycles(); myLastCycle = mySystem->cycles();
#ifdef DEBUGGER_SUPPORT
myTimWrappedOnRead = myTimWrappedOnWrite = false;
#endif
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -220,7 +224,9 @@ uInt8 M6532::peek(uInt16 addr)
{ {
// Timer Flag is always cleared when accessing INTIM // Timer Flag is always cleared when accessing INTIM
if (!myWrappedThisCycle) myInterruptFlag &= ~TimerBit; if (!myWrappedThisCycle) myInterruptFlag &= ~TimerBit;
#ifdef DEBUGGER_SUPPORT
myTimWrappedOnRead = myWrappedThisCycle;
#endif
return myTimer; return myTimer;
} }
@ -316,6 +322,9 @@ void M6532::setTimerRegister(uInt8 value, uInt8 interval)
// Interrupt timer flag is cleared (and invalid) when writing to the timer // Interrupt timer flag is cleared (and invalid) when writing to the timer
if (!myWrappedThisCycle) myInterruptFlag &= ~TimerBit; if (!myWrappedThisCycle) myInterruptFlag &= ~TimerBit;
#ifdef DEBUGGER_SUPPORT
myTimWrappedOnWrite = myWrappedThisCycle;
#endif
mySetTimerCycle = mySystem->cycles(); mySetTimerCycle = mySystem->cycles();
} }

View File

@ -250,6 +250,10 @@ class M6532 : public Device
std::array<Device::AccessCounter, IO_SIZE * 2> myIOAccessCounter; std::array<Device::AccessCounter, IO_SIZE * 2> myIOAccessCounter;
// The array used to skip the first ZP access tracking // The array used to skip the first ZP access tracking
std::array<uInt8, RAM_SIZE> myZPAccessDelay; std::array<uInt8, RAM_SIZE> myZPAccessDelay;
// Detect timer being accessed on wraparound
bool myTimWrappedOnRead{false};
bool myTimWrappedOnWrite{false};
#endif // DEBUGGER_SUPPORT #endif // DEBUGGER_SUPPORT
private: private:

View File

@ -228,6 +228,18 @@ CpuMethod getCpuSpecial(char* ch)
return nullptr; return nullptr;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// special methods that get RIOT internal state
RiotMethod getRiotSpecial(char* ch)
{
if(BSPF::equalsIgnoreCase(ch, "_timwrapread"))
return &RiotDebug::timWrappedOnRead;
else if(BSPF::equalsIgnoreCase(ch, "_timwrapwrite"))
return &RiotDebug::timWrappedOnWrite;
else
return nullptr;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// special methods that get TIA internal state // special methods that get TIA internal state
TiaMethod getTiaSpecial(char* ch) TiaMethod getTiaSpecial(char* ch)
@ -281,6 +293,7 @@ int yylex() {
{ {
CartMethod cartMeth; CartMethod cartMeth;
CpuMethod cpuMeth; CpuMethod cpuMeth;
RiotMethod riotMeth;
TiaMethod tiaMeth; TiaMethod tiaMeth;
char *bufp = idbuf; char *bufp = idbuf;
@ -309,6 +322,9 @@ int yylex() {
} else if( (cartMeth = getCartSpecial(idbuf)) ) { } else if( (cartMeth = getCartSpecial(idbuf)) ) {
yylval.cartMethod = cartMeth; yylval.cartMethod = cartMeth;
return CART_METHOD; return CART_METHOD;
} else if( (riotMeth = getRiotSpecial(idbuf)) ) {
yylval.riotMethod = riotMeth;
return RIOT_METHOD;
} else if( (tiaMeth = getTiaSpecial(idbuf)) ) { } else if( (tiaMeth = getTiaSpecial(idbuf)) ) {
yylval.tiaMethod = tiaMeth; yylval.tiaMethod = tiaMeth;
return TIA_METHOD; return TIA_METHOD;

View File

@ -21,6 +21,7 @@
#include "Expression.hxx" #include "Expression.hxx"
#include "CartDebug.hxx" #include "CartDebug.hxx"
#include "CpuDebug.hxx" #include "CpuDebug.hxx"
#include "RiotDebug.hxx"
#include "TIADebug.hxx" #include "TIADebug.hxx"
#include "bspf.hxx" #include "bspf.hxx"
@ -37,6 +38,7 @@ namespace YaccParser
CartMethod getCartSpecial(char* ch); CartMethod getCartSpecial(char* ch);
CpuMethod getCpuSpecial(char* ch); CpuMethod getCpuSpecial(char* ch);
RiotMethod getRiotSpecial(char* ch);
TiaMethod getTiaSpecial(char* ch); TiaMethod getTiaSpecial(char* ch);
} }

View File

@ -30,6 +30,7 @@ void yyerror(const char *e) {
char* Equate; char* Equate;
CartMethod cartMethod; CartMethod cartMethod;
CpuMethod cpuMethod; CpuMethod cpuMethod;
RiotMethod riotMethod;
TiaMethod tiaMethod; TiaMethod tiaMethod;
Expression* exp; Expression* exp;
char* DefinedFunction; char* DefinedFunction;
@ -41,6 +42,7 @@ void yyerror(const char *e) {
%token <Equate> EQUATE %token <Equate> EQUATE
%token <cartMethod> CART_METHOD %token <cartMethod> CART_METHOD
%token <cpuMethod> CPU_METHOD %token <cpuMethod> CPU_METHOD
%token <riotMethod> RIOT_METHOD
%token <tiaMethod> TIA_METHOD %token <tiaMethod> TIA_METHOD
%token <DefinedFunction> FUNCTION %token <DefinedFunction> FUNCTION
@ -97,6 +99,7 @@ expression: expression '+' expression { if(DEBUG_EXP) fprintf(stderr, " +"); $$
| EQUATE { if(DEBUG_EXP) fprintf(stderr, "equate %s", $1); $$ = new EquateExpression($1); lastExp = $$; } | EQUATE { if(DEBUG_EXP) fprintf(stderr, "equate %s", $1); $$ = new EquateExpression($1); lastExp = $$; }
| CPU_METHOD { if(DEBUG_EXP) fprintf(stderr, " (CpuMethod)"); $$ = new CpuMethodExpression($1); lastExp = $$; } | CPU_METHOD { if(DEBUG_EXP) fprintf(stderr, " (CpuMethod)"); $$ = new CpuMethodExpression($1); lastExp = $$; }
| CART_METHOD { if(DEBUG_EXP) fprintf(stderr, " (CartMethod)"); $$ = new CartMethodExpression($1); lastExp = $$; } | CART_METHOD { if(DEBUG_EXP) fprintf(stderr, " (CartMethod)"); $$ = new CartMethodExpression($1); lastExp = $$; }
| RIOT_METHOD { if(DEBUG_EXP) fprintf(stderr, " (RiotMethod)"); $$ = new RiotMethodExpression($1); lastExp = $$; }
| TIA_METHOD { if(DEBUG_EXP) fprintf(stderr, " (TiaMethod)"); $$ = new TiaMethodExpression($1); lastExp = $$; } | TIA_METHOD { if(DEBUG_EXP) fprintf(stderr, " (TiaMethod)"); $$ = new TiaMethodExpression($1); lastExp = $$; }
| FUNCTION { if(DEBUG_EXP) fprintf(stderr, " (DefinedFunction)"); $$ = new FunctionExpression($1); lastExp = $$; } | FUNCTION { if(DEBUG_EXP) fprintf(stderr, " (DefinedFunction)"); $$ = new FunctionExpression($1); lastExp = $$; }
| ERR { if(DEBUG_EXP) fprintf(stderr, " ERR: "); yyerror((const char*)"Invalid label or constant"); return 1; } | ERR { if(DEBUG_EXP) fprintf(stderr, " ERR: "); yyerror((const char*)"Invalid label or constant"); return 1; }

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,9 @@
/* A Bison parser, made by GNU Bison 3.0.4. */ /* A Bison parser, made by GNU Bison 3.5.1. */
/* Bison interface for Yacc-like parsers in C /* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
Inc.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -30,6 +31,9 @@
This special exception was added by the Free Software Foundation in This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */ version 2.2 of Bison. */
/* Undocumented macros, especially those whose name start with YY_,
are private implementation details. Do not rely on them. */
#ifndef YY_YY_Y_TAB_H_INCLUDED #ifndef YY_YY_Y_TAB_H_INCLUDED
# define YY_YY_Y_TAB_H_INCLUDED # define YY_YY_Y_TAB_H_INCLUDED
/* Debug traces. */ /* Debug traces. */
@ -50,19 +54,20 @@ extern int yydebug;
EQUATE = 260, EQUATE = 260,
CART_METHOD = 261, CART_METHOD = 261,
CPU_METHOD = 262, CPU_METHOD = 262,
TIA_METHOD = 263, RIOT_METHOD = 263,
FUNCTION = 264, TIA_METHOD = 264,
LOG_OR = 265, FUNCTION = 265,
LOG_AND = 266, LOG_OR = 266,
LOG_NOT = 267, LOG_AND = 267,
SHR = 268, LOG_NOT = 268,
SHL = 269, SHR = 269,
GTE = 270, SHL = 270,
LTE = 271, GTE = 271,
NE = 272, LTE = 272,
EQ = 273, NE = 273,
DEREF = 274, EQ = 274,
UMINUS = 275 DEREF = 275,
UMINUS = 276
}; };
#endif #endif
/* Tokens. */ /* Tokens. */
@ -71,38 +76,39 @@ extern int yydebug;
#define EQUATE 260 #define EQUATE 260
#define CART_METHOD 261 #define CART_METHOD 261
#define CPU_METHOD 262 #define CPU_METHOD 262
#define TIA_METHOD 263 #define RIOT_METHOD 263
#define FUNCTION 264 #define TIA_METHOD 264
#define LOG_OR 265 #define FUNCTION 265
#define LOG_AND 266 #define LOG_OR 266
#define LOG_NOT 267 #define LOG_AND 267
#define SHR 268 #define LOG_NOT 268
#define SHL 269 #define SHR 269
#define GTE 270 #define SHL 270
#define LTE 271 #define GTE 271
#define NE 272 #define LTE 272
#define EQ 273 #define NE 273
#define DEREF 274 #define EQ 274
#define UMINUS 275 #define DEREF 275
#define UMINUS 276
/* Value type. */ /* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE union YYSTYPE
{ {
#line 28 "stella.y" /* yacc.c:1909 */ #line 28 "stella.y"
int val; int val;
char* Equate; char* Equate;
CartMethod cartMethod; CartMethod cartMethod;
CpuMethod cpuMethod; CpuMethod cpuMethod;
RiotMethod riotMethod;
TiaMethod tiaMethod; TiaMethod tiaMethod;
Expression* exp; Expression* exp;
char* DefinedFunction; char* DefinedFunction;
#line 104 "y.tab.h" /* yacc.c:1909 */ #line 110 "y.tab.h"
};
};
typedef union YYSTYPE YYSTYPE; typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1 # define YYSTYPE_IS_DECLARED 1