mirror of https://github.com/stella-emu/stella.git
Added debugger pseudo-registers to detect timer access on wraparound (fixes #606).
This commit is contained in:
parent
ad6a930e83
commit
282e082862
|
@ -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).
|
||||
|
||||
|
|
|
@ -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" }*/
|
||||
} };
|
||||
//
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
956
src/yacc/y.tab.c
956
src/yacc/y.tab.c
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue