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 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
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
std::array<Debugger::PseudoRegister, 12> Debugger::ourPseudoRegisters = { {
std::array<Debugger::PseudoRegister, 14> Debugger::ourPseudoRegisters = { {
// 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" },
{ "_icycles", "Number of cycles of last instruction" },
{ "_scan", "Current scanline count" },
{ "_scanend", "Scanline count at end of last frame" },
{ "_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)" }
{ "_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" },
{ "_icycles", "Number of cycles of last instruction" },
{ "_scan", "Current scanline count" },
{ "_scanend", "Scanline count at end of last frame" },
{ "_scycles", "Number of cycles in current scanline" },
{ "_timwrapread", "Timer read wrapped on this cycle" },
{ "_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:
/*{ "_lastread", "last CPU read address" },
{ "_lastwrite", "last CPU write address" },
{ "__lastbaseread", "last CPU read base address" },
{ "__lastbasewrite", "last CPU write base address" }*/
} };
//

View File

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

View File

@ -23,6 +23,7 @@
#include "bspf.hxx"
#include "CartDebug.hxx"
#include "CpuDebug.hxx"
#include "RiotDebug.hxx"
#include "TIADebug.hxx"
#include "Debugger.hxx"
#include "Expression.hxx"
@ -310,6 +311,18 @@ class ShiftRightExpression : public Expression
{ 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
{

View File

@ -235,6 +235,18 @@ Int32 RiotDebug::timDivider() const
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)
{

View File

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

View File

@ -145,6 +145,10 @@ void M6532::updateEmulation()
}
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
if (!myWrappedThisCycle) myInterruptFlag &= ~TimerBit;
#ifdef DEBUGGER_SUPPORT
myTimWrappedOnRead = myWrappedThisCycle;
#endif
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
if (!myWrappedThisCycle) myInterruptFlag &= ~TimerBit;
#ifdef DEBUGGER_SUPPORT
myTimWrappedOnWrite = myWrappedThisCycle;
#endif
mySetTimerCycle = mySystem->cycles();
}

View File

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

View File

@ -228,6 +228,18 @@ CpuMethod getCpuSpecial(char* ch)
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
TiaMethod getTiaSpecial(char* ch)
@ -281,6 +293,7 @@ int yylex() {
{
CartMethod cartMeth;
CpuMethod cpuMeth;
RiotMethod riotMeth;
TiaMethod tiaMeth;
char *bufp = idbuf;
@ -309,6 +322,9 @@ int yylex() {
} else if( (cartMeth = getCartSpecial(idbuf)) ) {
yylval.cartMethod = cartMeth;
return CART_METHOD;
} else if( (riotMeth = getRiotSpecial(idbuf)) ) {
yylval.riotMethod = riotMeth;
return RIOT_METHOD;
} else if( (tiaMeth = getTiaSpecial(idbuf)) ) {
yylval.tiaMethod = tiaMeth;
return TIA_METHOD;

View File

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

View File

@ -30,6 +30,7 @@ void yyerror(const char *e) {
char* Equate;
CartMethod cartMethod;
CpuMethod cpuMethod;
RiotMethod riotMethod;
TiaMethod tiaMethod;
Expression* exp;
char* DefinedFunction;
@ -41,6 +42,7 @@ void yyerror(const char *e) {
%token <Equate> EQUATE
%token <cartMethod> CART_METHOD
%token <cpuMethod> CPU_METHOD
%token <riotMethod> RIOT_METHOD
%token <tiaMethod> TIA_METHOD
%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 = $$; }
| CPU_METHOD { if(DEBUG_EXP) fprintf(stderr, " (CpuMethod)"); $$ = new CpuMethodExpression($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 = $$; }
| 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; }

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
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
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
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
# define YY_YY_Y_TAB_H_INCLUDED
/* Debug traces. */
@ -50,19 +54,20 @@ extern int yydebug;
EQUATE = 260,
CART_METHOD = 261,
CPU_METHOD = 262,
TIA_METHOD = 263,
FUNCTION = 264,
LOG_OR = 265,
LOG_AND = 266,
LOG_NOT = 267,
SHR = 268,
SHL = 269,
GTE = 270,
LTE = 271,
NE = 272,
EQ = 273,
DEREF = 274,
UMINUS = 275
RIOT_METHOD = 263,
TIA_METHOD = 264,
FUNCTION = 265,
LOG_OR = 266,
LOG_AND = 267,
LOG_NOT = 268,
SHR = 269,
SHL = 270,
GTE = 271,
LTE = 272,
NE = 273,
EQ = 274,
DEREF = 275,
UMINUS = 276
};
#endif
/* Tokens. */
@ -71,38 +76,39 @@ extern int yydebug;
#define EQUATE 260
#define CART_METHOD 261
#define CPU_METHOD 262
#define TIA_METHOD 263
#define FUNCTION 264
#define LOG_OR 265
#define LOG_AND 266
#define LOG_NOT 267
#define SHR 268
#define SHL 269
#define GTE 270
#define LTE 271
#define NE 272
#define EQ 273
#define DEREF 274
#define UMINUS 275
#define RIOT_METHOD 263
#define TIA_METHOD 264
#define FUNCTION 265
#define LOG_OR 266
#define LOG_AND 267
#define LOG_NOT 268
#define SHR 269
#define SHL 270
#define GTE 271
#define LTE 272
#define NE 273
#define EQ 274
#define DEREF 275
#define UMINUS 276
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
#line 28 "stella.y" /* yacc.c:1909 */
#line 28 "stella.y"
int val;
char* Equate;
CartMethod cartMethod;
CpuMethod cpuMethod;
RiotMethod riotMethod;
TiaMethod tiaMethod;
Expression* exp;
char* DefinedFunction;
#line 104 "y.tab.h" /* yacc.c:1909 */
};
#line 110 "y.tab.h"
};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1