began merging XD stuff
there are still bugs in the emulator core :( [[Split portion of a mixed commit.]]
This commit is contained in:
parent
db8bdfb036
commit
d94c7aa450
|
@ -0,0 +1,10 @@
|
|||
#include <windows.h>
|
||||
|
||||
void DoCDLogger();
|
||||
void UpdateCDLogger();
|
||||
void LogPCM(int romaddress);
|
||||
|
||||
extern HWND hCDLogger;
|
||||
extern volatile int codecount, datacount, undefinedcount;
|
||||
extern volatile int loggingcodedata;
|
||||
extern unsigned char *cdloggerdata;
|
|
@ -0,0 +1,412 @@
|
|||
/* FCEUXD SP - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 Sebastian Porst
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* The parser was heavily inspired by the following two websites:
|
||||
|
||||
* http://www.cs.utsa.edu/~wagner/CS5363/rdparse.html
|
||||
* http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
|
||||
*
|
||||
* Grammar of the parser:
|
||||
*
|
||||
* P -> Connect
|
||||
* Connect -> Compare {('||' | '&&') Compare}
|
||||
* Compare -> Sum {('==' | '!=' | '<=' | '>=' | '<' | '>') Sum}
|
||||
* Sum -> Product {('+' | '-') Product}
|
||||
* Product -> Primitive {('*' | '/') Primitive}
|
||||
* Primitive -> Number | Address | Register | Flag | '(' Connect ')'
|
||||
* Number -> '#' [1-9A-F]*
|
||||
* Address -> '$' [1-9A-F]* | '$' '[' Connect ']'
|
||||
* Register -> 'A' | 'X' | 'Y' | 'R'
|
||||
* Flag -> 'N' | 'C' | 'Z' | 'I' | 'B' | 'V'
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "conddebug.h"
|
||||
|
||||
// Next non-whitespace character in string
|
||||
char next;
|
||||
|
||||
int ishex(char c)
|
||||
{
|
||||
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
void scan(const char** str)
|
||||
{
|
||||
do
|
||||
{
|
||||
next = **str;
|
||||
(*str)++;
|
||||
} while (isspace(next));
|
||||
}
|
||||
|
||||
// Frees a condition and all of it's sub conditions
|
||||
void freeTree(Condition* c)
|
||||
{
|
||||
if (c->lhs) freeTree(c->lhs);
|
||||
if (c->rhs) freeTree(c->rhs);
|
||||
|
||||
free(c);
|
||||
}
|
||||
|
||||
// Generic function to handle all infix operators but the last one in the precedence hierarchy. : '(' E ')'
|
||||
Condition* InfixOperator(const char** str, Condition(*nextPart(const char**)), int(*operators)(const char**))
|
||||
{
|
||||
Condition* t = nextPart(str);
|
||||
Condition* t1;
|
||||
Condition* mid;
|
||||
int op;
|
||||
|
||||
while ((op = operators(str)))
|
||||
{
|
||||
scan(str);
|
||||
|
||||
t1 = nextPart(str);
|
||||
|
||||
if (t1 == 0)
|
||||
{
|
||||
freeTree(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mid = (Condition*)malloc(sizeof(Condition));
|
||||
memset(mid, 0, sizeof(Condition));
|
||||
|
||||
mid->lhs = t;
|
||||
mid->rhs = t1;
|
||||
mid->op = op;
|
||||
|
||||
t = mid;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
// Generic handler for two-character operators
|
||||
int TwoCharOperator(const char** str, char c1, char c2, int op)
|
||||
{
|
||||
if (next == c1 && **str == c2)
|
||||
{
|
||||
scan(str);
|
||||
return op;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Determines if a character is a flag
|
||||
int isFlag(char c)
|
||||
{
|
||||
return c == 'N' || c == 'I' || c == 'C' || c == 'V' || c == 'Z' || c == 'B' || c == 'U' || c == 'D';
|
||||
}
|
||||
|
||||
// Determines if a character is a register
|
||||
int isRegister(char c)
|
||||
{
|
||||
return c == 'A' || c == 'X' || c == 'Y' || c == 'P';
|
||||
}
|
||||
|
||||
// Reads a hexadecimal number from str
|
||||
int getNumber(unsigned int* number, const char** str)
|
||||
{
|
||||
// char buffer[5];
|
||||
|
||||
if (sscanf(*str, "%X", number) == EOF || *number > 0xFFFF)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Older, inferior version which doesn't work with leading zeros
|
||||
// sprintf(buffer, "%X", *number);
|
||||
// *str += strlen(buffer);
|
||||
while (ishex(**str)) (*str)++;
|
||||
scan(str);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
Condition* Connect(const char** str);
|
||||
|
||||
// Handles the following part of the grammar: '(' E ')'
|
||||
Condition* Parentheses(const char** str, Condition* c, char openPar, char closePar)
|
||||
{
|
||||
if (next == openPar)
|
||||
{
|
||||
scan(str);
|
||||
|
||||
c->lhs = Connect(str);
|
||||
|
||||
if (!c) return 0;
|
||||
|
||||
if (next == closePar)
|
||||
{
|
||||
scan(str);
|
||||
return c;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for primitives
|
||||
* Flags, Registers, Numbers, Addresses and parentheses
|
||||
*/
|
||||
Condition* Primitive(const char** str, Condition* c)
|
||||
{
|
||||
if (isFlag(next)) /* Flags */
|
||||
{
|
||||
if (c->type1 == TYPE_NO)
|
||||
{
|
||||
c->type1 = TYPE_FLAG;
|
||||
c->value1 = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->type2 = TYPE_FLAG;
|
||||
c->value2 = next;
|
||||
}
|
||||
|
||||
scan(str);
|
||||
|
||||
return c;
|
||||
}
|
||||
else if (isRegister(next)) /* Registers */
|
||||
{
|
||||
if (c->type1 == TYPE_NO)
|
||||
{
|
||||
c->type1 = TYPE_REG;
|
||||
c->value1 = next;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->type2 = TYPE_REG;
|
||||
c->value2 = next;
|
||||
}
|
||||
|
||||
scan(str);
|
||||
|
||||
return c;
|
||||
}
|
||||
else if (next == '#') /* Numbers */
|
||||
{
|
||||
unsigned int number = 0;
|
||||
if (!getNumber(&number, str))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c->type1 == TYPE_NO)
|
||||
{
|
||||
c->type1 = TYPE_NUM;
|
||||
c->value1 = number;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->type2 = TYPE_NUM;
|
||||
c->value2 = number;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
else if (next == '$') /* Addresses */
|
||||
{
|
||||
if ((**str >= '0' && **str <= '9') || (**str >= 'A' && **str <= 'F')) /* Constant addresses */
|
||||
{
|
||||
unsigned int number = 0;
|
||||
if (!getNumber(&number, str))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (c->type1 == TYPE_NO)
|
||||
{
|
||||
c->type1 = TYPE_ADDR;
|
||||
c->value1 = number;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->type2 = TYPE_ADDR;
|
||||
c->value2 = number;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
else if (**str == '[') /* Dynamic addresses */
|
||||
{
|
||||
scan(str);
|
||||
Parentheses(str, c, '[', ']');
|
||||
|
||||
if (c->type1 == TYPE_NO)
|
||||
{
|
||||
c->type1 = TYPE_ADDR;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->type2 = TYPE_ADDR;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (next == '(')
|
||||
{
|
||||
return Parentheses(str, c, '(', ')');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle * and / operators */
|
||||
Condition* Term(const char** str)
|
||||
{
|
||||
Condition* t = (Condition*)malloc(sizeof(Condition));
|
||||
Condition* t1;
|
||||
Condition* mid;
|
||||
|
||||
memset(t, 0, sizeof(Condition));
|
||||
|
||||
if (!Primitive(str, t))
|
||||
{
|
||||
freeTree(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (next == '*' || next == '/')
|
||||
{
|
||||
int op = next == '*' ? OP_MULT : OP_DIV;
|
||||
|
||||
scan(str);
|
||||
|
||||
t1 = (Condition*)malloc(sizeof(Condition));
|
||||
memset(t1, 0, sizeof(Condition));
|
||||
|
||||
if (!Primitive(str, t1))
|
||||
{
|
||||
freeTree(t);
|
||||
freeTree(t1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mid = (Condition*)malloc(sizeof(Condition));
|
||||
memset(mid, 0, sizeof(Condition));
|
||||
|
||||
mid->lhs = t;
|
||||
mid->rhs = t1;
|
||||
mid->op = op;
|
||||
|
||||
t = mid;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Check for + and - operators */
|
||||
int SumOperators(const char** str)
|
||||
{
|
||||
switch (next)
|
||||
{
|
||||
case '+': return OP_PLUS;
|
||||
case '-': return OP_MINUS;
|
||||
default: return OP_NO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle + and - operators */
|
||||
Condition* Sum(const char** str)
|
||||
{
|
||||
return InfixOperator(str, Term, SumOperators);
|
||||
}
|
||||
|
||||
/* Check for <=, =>, ==, !=, > and < operators */
|
||||
int CompareOperators(const char** str)
|
||||
{
|
||||
int val = TwoCharOperator(str, '=', '=', OP_EQ);
|
||||
if (val) return val;
|
||||
|
||||
val = TwoCharOperator(str, '!', '=', OP_NE);
|
||||
if (val) return val;
|
||||
|
||||
val = TwoCharOperator(str, '>', '=', OP_GE);
|
||||
if (val) return val;
|
||||
|
||||
val = TwoCharOperator(str, '<', '=', OP_LE);
|
||||
if (val) return val;
|
||||
|
||||
val = next == '>' ? OP_G : 0;
|
||||
if (val) return val;
|
||||
|
||||
val = next == '<' ? OP_L : 0;
|
||||
if (val) return val;
|
||||
|
||||
return OP_NO;
|
||||
}
|
||||
|
||||
/* Handle <=, =>, ==, !=, > and < operators */
|
||||
Condition* Compare(const char** str)
|
||||
{
|
||||
return InfixOperator(str, Sum, CompareOperators);
|
||||
}
|
||||
|
||||
/* Check for || or && operators */
|
||||
int ConnectOperators(const char** str)
|
||||
{
|
||||
int val = TwoCharOperator(str, '|', '|', OP_OR);
|
||||
if(val) return val;
|
||||
|
||||
val = TwoCharOperator(str, '&', '&', OP_AND);
|
||||
if(val) return val;
|
||||
|
||||
return OP_NO;
|
||||
}
|
||||
|
||||
/* Handle || and && operators */
|
||||
Condition* Connect(const char** str)
|
||||
{
|
||||
return InfixOperator(str, Compare, ConnectOperators);
|
||||
}
|
||||
|
||||
/* Root of the parser generator */
|
||||
Condition* generateCondition(const char* str)
|
||||
{
|
||||
Condition* c;
|
||||
|
||||
scan(&str);
|
||||
c = Connect(&str);
|
||||
|
||||
if (!c || next != 0) return 0;
|
||||
else return c;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/* FCEUXD SP - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 Sebastian Porst
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef CONDDEBUG_H
|
||||
#define CONDDEBUG_H
|
||||
|
||||
#define TYPE_NO 0
|
||||
#define TYPE_REG 1
|
||||
#define TYPE_FLAG 2
|
||||
#define TYPE_NUM 3
|
||||
#define TYPE_ADDR 4
|
||||
|
||||
#define OP_NO 0
|
||||
#define OP_EQ 1
|
||||
#define OP_NE 2
|
||||
#define OP_GE 3
|
||||
#define OP_LE 4
|
||||
#define OP_G 5
|
||||
#define OP_L 6
|
||||
#define OP_PLUS 7
|
||||
#define OP_MINUS 8
|
||||
#define OP_MULT 9
|
||||
#define OP_DIV 10
|
||||
#define OP_OR 11
|
||||
#define OP_AND 12
|
||||
|
||||
//mbg merge 7/18/06 turned into sane c++
|
||||
struct Condition
|
||||
{
|
||||
Condition* lhs;
|
||||
Condition* rhs;
|
||||
|
||||
unsigned int type1;
|
||||
unsigned int value1;
|
||||
|
||||
unsigned int op;
|
||||
|
||||
unsigned int type2;
|
||||
unsigned int value2;
|
||||
};
|
||||
|
||||
void freeTree(Condition* c);
|
||||
Condition* generateCondition(const char* str);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,141 @@
|
|||
#ifndef DEBUGGER_H
|
||||
#define DEBUGGER_H
|
||||
|
||||
//#define GetMem(x) (((x < 0x2000) || (x >= 0x4020))?ARead[x](x):0xFF)
|
||||
#include <windows.h>
|
||||
#include "conddebug.h"
|
||||
|
||||
//watchpoint stuffs
|
||||
#define WP_E 0x01 //watchpoint, enable
|
||||
#define WP_W 0x02 //watchpoint, write
|
||||
#define WP_R 0x04 //watchpoint, read
|
||||
#define WP_X 0x08 //watchpoint, execute
|
||||
|
||||
#define BT_C 0x00 //break type, cpu mem
|
||||
#define BT_P 0x10 //break type, ppu mem
|
||||
#define BT_S 0x20 //break type, sprite mem
|
||||
|
||||
typedef struct {
|
||||
uint16 address;
|
||||
uint16 endaddress;
|
||||
uint8 flags;
|
||||
// ################################## Start of SP CODE ###########################
|
||||
|
||||
Condition* cond;
|
||||
char* condText;
|
||||
char* desc;
|
||||
|
||||
// ################################## End of SP CODE ###########################
|
||||
} watchpointinfo;
|
||||
|
||||
//mbg merge 7/18/06 had to make this extern
|
||||
extern watchpointinfo watchpoint[65]; //64 watchpoints, + 1 reserved for step over
|
||||
|
||||
extern uint8 *vnapage[4],*VPage[8];
|
||||
extern uint8 PPU[4],PALRAM[0x20],SPRAM[0x100],VRAMBuffer,PPUGenLatch,XOffset;
|
||||
extern uint32 RefreshAddr;
|
||||
//extern volatile int userpause; //mbg merge 7/18/06 removed for merging
|
||||
extern int scanline; //current scanline! :D
|
||||
extern int badopbreak;
|
||||
extern HWND hDebug;
|
||||
|
||||
extern int step,stepout,jsrcount;
|
||||
extern int childwnd,numWPs; //mbg merge 7/18/06 had to make extern
|
||||
|
||||
BOOL CenterWindow(HWND hwndDlg);
|
||||
void DoPatcher(int address,HWND hParent);
|
||||
void UpdatePatcher(HWND hwndDlg);
|
||||
int GetNesFileAddress(int A);
|
||||
int GetPRGAddress(int A);
|
||||
int GetRomAddress(int A);
|
||||
int GetEditHex(HWND hwndDlg, int id);
|
||||
uint8 *GetNesPRGPointer(int A);
|
||||
uint8 *GetNesCHRPointer(int A);
|
||||
extern void AddBreakList();
|
||||
|
||||
char *BinToASM(int addr, uint8 *opcode);
|
||||
|
||||
void UpdateDebugger();
|
||||
void DoDebug(uint8 halt);
|
||||
void KillDebugger();
|
||||
uint8 GetMem(uint16 A);
|
||||
uint8 GetPPUMem(uint8 A);
|
||||
|
||||
|
||||
//the opsize table is used to quickly grab the instruction sizes (in bytes)
|
||||
static const uint8 opsize[256] = {
|
||||
/*0x00*/ 1,2,0,0,0,2,2,0,1,2,1,0,0,3,3,0,
|
||||
/*0x10*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
|
||||
/*0x20*/ 3,2,0,0,2,2,2,0,1,2,1,0,3,3,3,0,
|
||||
/*0x30*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
|
||||
/*0x40*/ 1,2,0,0,0,2,2,0,1,2,1,0,3,3,3,0,
|
||||
/*0x50*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
|
||||
/*0x60*/ 1,2,0,0,0,2,2,0,1,2,1,0,3,3,3,0,
|
||||
/*0x70*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
|
||||
/*0x80*/ 0,2,0,0,2,2,2,0,1,0,1,0,3,3,3,0,
|
||||
/*0x90*/ 2,2,0,0,2,2,2,0,1,3,1,0,0,3,0,0,
|
||||
/*0xA0*/ 2,2,2,0,2,2,2,0,1,2,1,0,3,3,3,0,
|
||||
/*0xB0*/ 2,2,0,0,2,2,2,0,1,3,1,0,3,3,3,0,
|
||||
/*0xC0*/ 2,2,0,0,2,2,2,0,1,2,1,0,3,3,3,0,
|
||||
/*0xD0*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0,
|
||||
/*0xE0*/ 2,2,0,0,2,2,2,0,1,2,1,0,3,3,3,0,
|
||||
/*0xF0*/ 2,2,0,0,0,2,2,0,1,3,0,0,0,3,3,0
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
the optype table is a quick way to grab the addressing mode for any 6502 opcode
|
||||
|
||||
0 = Implied\Accumulator\Immediate\Branch\NULL
|
||||
1 = (Indirect,X)
|
||||
2 = Zero Page
|
||||
3 = Absolute
|
||||
4 = (Indirect),Y
|
||||
5 = Zero Page,X
|
||||
6 = Absolute,Y
|
||||
7 = Absolute,X
|
||||
8 = Zero Page,Y
|
||||
*/
|
||||
static const uint8 optype[256] = {
|
||||
/*0x00*/ 0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0,
|
||||
/*0x10*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0x20*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0x30*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0x40*/ 0,1,0,0,0,2,2,0,0,0,0,0,0,3,3,0,
|
||||
/*0x50*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0x60*/ 0,1,0,0,0,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0x70*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0x80*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0x90*/ 0,4,0,0,5,5,8,0,0,6,0,0,0,7,0,0,
|
||||
/*0xA0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0xB0*/ 0,4,0,0,5,5,8,0,0,6,0,0,7,7,6,0,
|
||||
/*0xC0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0xD0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0,
|
||||
/*0xE0*/ 0,1,0,0,2,2,2,0,0,0,0,0,3,3,3,0,
|
||||
/*0xF0*/ 0,4,0,0,0,5,5,0,0,6,0,0,0,7,7,0
|
||||
};
|
||||
|
||||
|
||||
//opbrktype is used to grab the breakpoint type that each instruction will cause.
|
||||
//WP_X is not used because ALL opcodes will have the execute bit set.
|
||||
static const uint8 opbrktype[256] = {
|
||||
/*0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F*/
|
||||
/*0x00*/ 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0, 0, 0, 0, 0, 0, WP_R, WP_R|WP_W, 0,
|
||||
/*0x10*/ 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0, 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0,
|
||||
/*0x20*/ 0, WP_R, 0, 0, WP_R, WP_R, WP_R|WP_W, 0, 0, 0, 0, 0, WP_R, WP_R, WP_R|WP_W, 0,
|
||||
/*0x30*/ 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0, 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0,
|
||||
/*0x40*/ 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0, 0, 0, 0, 0, 0, WP_R, WP_R|WP_W, 0,
|
||||
/*0x50*/ 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0, 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0,
|
||||
/*0x60*/ 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0, 0, 0, 0, 0, WP_R, WP_R, WP_R|WP_W, 0,
|
||||
/*0x70*/ 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0, 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0,
|
||||
/*0x80*/ 0, WP_W, 0, 0, WP_W, WP_W, WP_W, 0, 0, 0, 0, 0, WP_W, WP_W, WP_W, 0,
|
||||
/*0x90*/ 0, WP_W, 0, 0, WP_W, WP_W, WP_W, 0, 0, WP_W, 0, 0, 0, WP_W, 0, 0,
|
||||
/*0xA0*/ 0, WP_R, 0, 0, WP_R, WP_R, WP_R, 0, 0, 0, 0, 0, WP_R, WP_R, WP_R, 0,
|
||||
/*0xB0*/ 0, WP_R, 0, 0, WP_R, WP_R, WP_R, 0, 0, WP_R, 0, 0, WP_R, WP_R, WP_R, 0,
|
||||
/*0xC0*/ 0, WP_R, 0, 0, WP_R, WP_R, WP_R|WP_W, 0, 0, 0, 0, 0, WP_R, WP_R, WP_R|WP_W, 0,
|
||||
/*0xD0*/ 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0, 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0,
|
||||
/*0xE0*/ 0, WP_R, 0, 0, WP_R, WP_R, WP_R|WP_W, 0, 0, 0, 0, 0, WP_R, WP_R, WP_R|WP_W, 0,
|
||||
/*0xF0*/ 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0, 0, WP_R, 0, 0, 0, WP_R, WP_R|WP_W, 0
|
||||
};
|
||||
|
||||
#endif
|
1
driver.h
1
driver.h
|
@ -276,6 +276,7 @@ void FCEUI_FDSSelect(void);
|
|||
int FCEUI_DatachSet(const uint8 *rcode);
|
||||
|
||||
int FCEUI_EmulationPaused(void);
|
||||
void FCEUI_SetEmulationPaused(int val); //mbg merge 7/18/06 added
|
||||
void FCEUI_ToggleEmulationPause(void);
|
||||
void FCEUI_FrameAdvance(void);
|
||||
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
|
||||
if (!strlen(astr)) {
|
||||
//Implied instructions
|
||||
if (!strcmp(ins,"BRK")) opcode[0] = 0x00;
|
||||
else if (!strcmp(ins,"PHP")) opcode[0] = 0x08;
|
||||
else if (!strcmp(ins,"ASL")) opcode[0] = 0x0A;
|
||||
else if (!strcmp(ins,"CLC")) opcode[0] = 0x18;
|
||||
else if (!strcmp(ins,"PLP")) opcode[0] = 0x28;
|
||||
else if (!strcmp(ins,"ROL")) opcode[0] = 0x2A;
|
||||
else if (!strcmp(ins,"SEC")) opcode[0] = 0x38;
|
||||
else if (!strcmp(ins,"RTI")) opcode[0] = 0x40;
|
||||
else if (!strcmp(ins,"PHA")) opcode[0] = 0x48;
|
||||
else if (!strcmp(ins,"LSR")) opcode[0] = 0x4A;
|
||||
else if (!strcmp(ins,"CLI")) opcode[0] = 0x58;
|
||||
else if (!strcmp(ins,"RTS")) opcode[0] = 0x60;
|
||||
else if (!strcmp(ins,"PLA")) opcode[0] = 0x68;
|
||||
else if (!strcmp(ins,"ROR")) opcode[0] = 0x6A;
|
||||
else if (!strcmp(ins,"SEI")) opcode[0] = 0x78;
|
||||
else if (!strcmp(ins,"DEY")) opcode[0] = 0x88;
|
||||
else if (!strcmp(ins,"TXA")) opcode[0] = 0x8A;
|
||||
else if (!strcmp(ins,"TYA")) opcode[0] = 0x98;
|
||||
else if (!strcmp(ins,"TXS")) opcode[0] = 0x9A;
|
||||
else if (!strcmp(ins,"TAY")) opcode[0] = 0xA8;
|
||||
else if (!strcmp(ins,"TAX")) opcode[0] = 0xAA;
|
||||
else if (!strcmp(ins,"CLV")) opcode[0] = 0xB8;
|
||||
else if (!strcmp(ins,"TSX")) opcode[0] = 0xBA;
|
||||
else if (!strcmp(ins,"INY")) opcode[0] = 0xC8;
|
||||
else if (!strcmp(ins,"DEX")) opcode[0] = 0xCA;
|
||||
else if (!strcmp(ins,"CLD")) opcode[0] = 0xD8;
|
||||
else if (!strcmp(ins,"INX")) opcode[0] = 0xE8;
|
||||
else if (!strcmp(ins,"NOP")) opcode[0] = 0xEA;
|
||||
else if (!strcmp(ins,"SED")) opcode[0] = 0xF8;
|
||||
else return 1;
|
||||
}
|
||||
else {
|
||||
//Instructions with Operands
|
||||
if (!strcmp(ins,"ORA")) opcode[0] = 0x01;
|
||||
else if (!strcmp(ins,"ASL")) opcode[0] = 0x06;
|
||||
else if (!strcmp(ins,"BPL")) opcode[0] = 0x10;
|
||||
else if (!strcmp(ins,"JSR")) opcode[0] = 0x20;
|
||||
else if (!strcmp(ins,"AND")) opcode[0] = 0x21;
|
||||
else if (!strcmp(ins,"BIT")) opcode[0] = 0x24;
|
||||
else if (!strcmp(ins,"ROL")) opcode[0] = 0x26;
|
||||
else if (!strcmp(ins,"BMI")) opcode[0] = 0x30;
|
||||
else if (!strcmp(ins,"EOR")) opcode[0] = 0x41;
|
||||
else if (!strcmp(ins,"LSR")) opcode[0] = 0x46;
|
||||
else if (!strcmp(ins,"JMP")) opcode[0] = 0x4C;
|
||||
else if (!strcmp(ins,"BVC")) opcode[0] = 0x50;
|
||||
else if (!strcmp(ins,"ADC")) opcode[0] = 0x61;
|
||||
else if (!strcmp(ins,"ROR")) opcode[0] = 0x66;
|
||||
else if (!strcmp(ins,"BVS")) opcode[0] = 0x70;
|
||||
else if (!strcmp(ins,"STA")) opcode[0] = 0x81;
|
||||
else if (!strcmp(ins,"STY")) opcode[0] = 0x84;
|
||||
else if (!strcmp(ins,"STX")) opcode[0] = 0x86;
|
||||
else if (!strcmp(ins,"BCC")) opcode[0] = 0x90;
|
||||
else if (!strcmp(ins,"LDY")) opcode[0] = 0xA0;
|
||||
else if (!strcmp(ins,"LDA")) opcode[0] = 0xA1;
|
||||
else if (!strcmp(ins,"LDX")) opcode[0] = 0xA2;
|
||||
else if (!strcmp(ins,"BCS")) opcode[0] = 0xB0;
|
||||
else if (!strcmp(ins,"CPY")) opcode[0] = 0xC0;
|
||||
else if (!strcmp(ins,"CMP")) opcode[0] = 0xC1;
|
||||
else if (!strcmp(ins,"DEC")) opcode[0] = 0xC6;
|
||||
else if (!strcmp(ins,"BNE")) opcode[0] = 0xD0;
|
||||
else if (!strcmp(ins,"CPX")) opcode[0] = 0xE0;
|
||||
else if (!strcmp(ins,"SBC")) opcode[0] = 0xE1;
|
||||
else if (!strcmp(ins,"INC")) opcode[0] = 0xE6;
|
||||
else if (!strcmp(ins,"BEQ")) opcode[0] = 0xF0;
|
||||
else return 1;
|
||||
|
||||
{
|
||||
//Parse Operands
|
||||
// It's not the sexiest thing ever, but it works well enough!
|
||||
|
||||
//TODO:
|
||||
// Add branches.
|
||||
// Fix certain instructions. (Setting bits is not 100% perfect.)
|
||||
// Fix instruction/operand matching. (Instructions like "jmp ($94),Y" are no good!)
|
||||
// Optimizations?
|
||||
int tmpint;
|
||||
char tmpchr,tmpstr[20];
|
||||
|
||||
if (sscanf(astr,"#$%2X%c",&tmpint,&tmpchr) == 1) { //#Immediate
|
||||
switch (opcode[0]) {
|
||||
case 0x20: case 0x4C: //Jumps
|
||||
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
|
||||
case 0x90: case 0xB0: case 0xD0: case 0xF0:
|
||||
case 0x06: case 0x24: case 0x26: case 0x46: //Other instructions incapable of #Immediate
|
||||
case 0x66: case 0x81: case 0x84: case 0x86:
|
||||
case 0xC6: case 0xE6:
|
||||
return 1;
|
||||
default:
|
||||
//cheap hack for certain instructions
|
||||
switch (opcode[0]) {
|
||||
case 0xA0: case 0xA2: case 0xC0: case 0xE0:
|
||||
break;
|
||||
default:
|
||||
opcode[0] |= 0x08;
|
||||
break;
|
||||
}
|
||||
opcode[1] = tmpint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (sscanf(astr,"$%4X%c",&tmpint,&tmpchr) == 1) { //Absolute, Zero Page, Branch, or Jump
|
||||
switch (opcode[0]) {
|
||||
case 0x20: case 0x4C: //Jumps
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
opcode[2] = (tmpint >> 8);
|
||||
break;
|
||||
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
|
||||
case 0x90: case 0xB0: case 0xD0: case 0xF0:
|
||||
tmpint -= (addr+2);
|
||||
if ((tmpint < -128) || (tmpint > 127)) return 1;
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
break;
|
||||
//return 1; //FIX ME
|
||||
default:
|
||||
if (tmpint > 0xFF) { //Absolute
|
||||
opcode[0] |= 0x0C;
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
opcode[2] = (tmpint >> 8);
|
||||
}
|
||||
else { //Zero Page
|
||||
opcode[0] |= 0x04;
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (sscanf(astr,"$%4X%s",&tmpint,tmpstr) == 2) { //Absolute,X, Zero Page,X, Absolute,Y or Zero Page,Y
|
||||
if (!strcmp(tmpstr,",X")) { //Absolute,X or Zero Page,X
|
||||
switch (opcode[0]) {
|
||||
case 0x20: case 0x4C: //Jumps
|
||||
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
|
||||
case 0x90: case 0xB0: case 0xD0: case 0xF0:
|
||||
case 0x24: case 0x86: case 0xA2: case 0xC0: //Other instructions incapable of Absolute,X or Zero Page,X
|
||||
case 0xE0:
|
||||
return 1;
|
||||
default:
|
||||
if (tmpint > 0xFF) { //Absolute
|
||||
if (opcode[0] == 0x84) return 1; //No STY Absolute,X!
|
||||
opcode[0] |= 0x1C;
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
opcode[2] = (tmpint >> 8);
|
||||
}
|
||||
else { //Zero Page
|
||||
opcode[0] |= 0x14;
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(tmpstr,",Y")) { //Absolute,Y or Zero Page,Y
|
||||
switch (opcode[0]) {
|
||||
case 0x20: case 0x4C: //Jumps
|
||||
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
|
||||
case 0x90: case 0xB0: case 0xD0: case 0xF0:
|
||||
case 0x06: case 0x24: case 0x26: case 0x46: //Other instructions incapable of Absolute,Y or Zero Page,Y
|
||||
case 0x66: case 0x84: case 0x86: case 0xA0:
|
||||
case 0xC0: case 0xC6: case 0xE0: case 0xE6:
|
||||
return 1;
|
||||
case 0xA2: //cheap hack for LDX
|
||||
opcode[0] |= 0x04;
|
||||
default:
|
||||
if (tmpint > 0xFF) { //Absolute
|
||||
if (opcode[0] == 0x86) return 1; //No STX Absolute,Y!
|
||||
opcode[0] |= 0x18;
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
opcode[2] = (tmpint >> 8);
|
||||
}
|
||||
else { //Zero Page
|
||||
if ((opcode[0] != 0x86) || (opcode[0] != 0xA2)) return 1; //only STX and LDX Absolute,Y!
|
||||
opcode[0] |= 0x10;
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else return 1;
|
||||
}
|
||||
else if (sscanf(astr,"($%4X%s",&tmpint,tmpstr) == 2) { //Jump (Indirect), (Indirect,X) or (Indirect),Y
|
||||
switch (opcode[0]) {
|
||||
case 0x20: //Jumps
|
||||
case 0x10: case 0x30: case 0x50: case 0x70: //Branches
|
||||
case 0x90: case 0xB0: case 0xD0: case 0xF0:
|
||||
case 0x06: case 0x24: case 0x26: case 0x46: //Other instructions incapable of Jump (Indirect), (Indirect,X) or (Indirect),Y
|
||||
case 0x66: case 0x84: case 0x86: case 0xA0:
|
||||
case 0xA2: case 0xC0: case 0xC6: case 0xE0:
|
||||
case 0xE6:
|
||||
return 1;
|
||||
default:
|
||||
if ((!strcmp(tmpstr,")")) && (opcode[0] == 0x4C)) { //Jump (Indirect)
|
||||
opcode[0] = 0x6C;
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
opcode[2] = (tmpint >> 8);
|
||||
}
|
||||
else if ((!strcmp(tmpstr,",X)")) && (tmpint <= 0xFF) && (opcode[0] != 0x4C)) { //(Indirect,X)
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
}
|
||||
else if ((!strcmp(tmpstr,"),Y")) && (tmpint <= 0xFF) && (opcode[0] != 0x4C)) { //(Indirect),Y
|
||||
opcode[0] |= 0x10;
|
||||
opcode[1] = (tmpint & 0xFF);
|
||||
}
|
||||
else return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
/* FCE Ultra - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2002 Ben Parnell
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "..\..\fceu.h"
|
||||
#include "..\..\cart.h" //mbg merge 7/18/06 moved beneath fceu.h
|
||||
#include "..\..\x6502.h"
|
||||
#include "..\..\debugger.h"
|
||||
#include "..\..\tracer.h"
|
||||
#include "..\..\cdlogger.h"
|
||||
|
||||
#define INESPRIV
|
||||
#include "..\..\ines.h"
|
||||
|
||||
void LoadCDLogFile();
|
||||
void SaveCDLogFileAs();
|
||||
void SaveCDLogFile();
|
||||
void SaveStrippedRom();
|
||||
|
||||
extern iNES_HEADER head; //defined in ines.c
|
||||
extern uint8 *trainerpoo;
|
||||
//extern uint8 *ROM;
|
||||
//extern uint8 *VROM;
|
||||
|
||||
volatile int loggingcodedata;
|
||||
//int cdlogger_open;
|
||||
volatile int codecount, datacount, undefinedcount;
|
||||
HWND hCDLogger=0;
|
||||
unsigned char *cdloggerdata;
|
||||
char *cdlogfilename;
|
||||
char loadedcdfile[MAX_PATH];
|
||||
|
||||
BOOL CALLBACK CDLoggerCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch(uMsg) {
|
||||
case WM_INITDIALOG:
|
||||
hCDLogger = hwndDlg;
|
||||
codecount = datacount = 0;
|
||||
undefinedcount = PRGsize[0];
|
||||
cdloggerdata = (unsigned char*)malloc(PRGsize[0]); //mbg merge 7/18/06 added cast
|
||||
ZeroMemory(cdloggerdata,PRGsize[0]);
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
case WM_QUIT:
|
||||
if((logging) && (logging_options & LOG_NEW_INSTRUCTIONS)){
|
||||
StopSound();
|
||||
MessageBox(hCDLogger,
|
||||
"The Trace logger is currently using this for some of its features.\
|
||||
Please turn the trace logger off and try again.","Unable to Pause Code/Data Logger",
|
||||
MB_OK);
|
||||
break;
|
||||
}
|
||||
loggingcodedata = 0;
|
||||
free(cdloggerdata);
|
||||
cdloggerdata=0;
|
||||
hCDLogger = 0;
|
||||
EndDialog(hwndDlg,0);
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch(HIWORD(wParam)) {
|
||||
case BN_CLICKED:
|
||||
switch(LOWORD(wParam)) {
|
||||
case 103:
|
||||
codecount = datacount = 0;
|
||||
undefinedcount = PRGsize[0];
|
||||
ZeroMemory(cdloggerdata,PRGsize[0]);
|
||||
UpdateCDLogger();
|
||||
break;
|
||||
case 104:
|
||||
LoadCDLogFile();
|
||||
break;
|
||||
case 105:
|
||||
if(loggingcodedata){
|
||||
if((logging) && (logging_options & LOG_NEW_INSTRUCTIONS)){
|
||||
MessageBox(hCDLogger,
|
||||
"The Trace logger is currently using this for some of its features.\
|
||||
Please turn the trace logger off and try again.","Unable to Pause Code/Data Logger",
|
||||
MB_OK);
|
||||
break;
|
||||
}
|
||||
loggingcodedata = 0;
|
||||
EnableTracerMenuItems();
|
||||
SetDlgItemText(hCDLogger, 105, "Start");
|
||||
}
|
||||
else{
|
||||
loggingcodedata = 1;
|
||||
EnableTracerMenuItems();
|
||||
SetDlgItemText(hCDLogger, 105, "Pause");
|
||||
}
|
||||
break;
|
||||
case 106:
|
||||
SaveCDLogFileAs();
|
||||
break;
|
||||
case 107:
|
||||
SaveCDLogFile();
|
||||
break;
|
||||
case 108:
|
||||
SaveStrippedRom();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WM_MOVING:
|
||||
StopSound();
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void LoadCDLogFile(){
|
||||
FILE *FP;
|
||||
int i, j;
|
||||
const char filter[]="Code Data Log File(*.CDL)\0*.cdl\0";
|
||||
char nameo[2048]; //todo: possibly no need for this? can lpstrfilter point to loadedcdfile instead?
|
||||
OPENFILENAME ofn;
|
||||
StopSound();
|
||||
memset(&ofn,0,sizeof(ofn));
|
||||
ofn.lStructSize=sizeof(ofn);
|
||||
ofn.hInstance=fceu_hInstance;
|
||||
ofn.lpstrTitle="Load Code Data Log File...";
|
||||
ofn.lpstrFilter=filter;
|
||||
nameo[0]=0;
|
||||
ofn.lpstrFile=nameo;
|
||||
ofn.nMaxFile=256;
|
||||
ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
|
||||
ofn.hwndOwner = hCDLogger;
|
||||
if(!GetOpenFileName(&ofn))return;
|
||||
strcpy(loadedcdfile,nameo);
|
||||
//FCEUD_PrintError(loadedcdfile);
|
||||
|
||||
//fseek(FP,0,SEEK_SET);
|
||||
//codecount = datacount = 0;
|
||||
//undefinedcount = PRGsize[0];
|
||||
|
||||
//cdloggerdata = malloc(PRGsize[0]);
|
||||
|
||||
|
||||
FP = fopen(loadedcdfile,"rb");
|
||||
if(FP == NULL){
|
||||
FCEUD_PrintError("Error Opening File");
|
||||
return;
|
||||
}
|
||||
|
||||
//codecount = datacount = 0;
|
||||
//undefinedcount = PRGsize[0];
|
||||
|
||||
for(i = 0;i < (int)PRGsize[0];i++){
|
||||
j = fgetc(FP);
|
||||
if(j == EOF)break;
|
||||
if((j & 1) && !(cdloggerdata[i] & 1))codecount++; //if the new byte has something logged and
|
||||
if((j & 2) && !(cdloggerdata[i] & 2))datacount++; //and the old one doesn't. Then increment
|
||||
if((j & 3) && !(cdloggerdata[i] & 3))undefinedcount--; //the appropriate counter.
|
||||
cdloggerdata[i] |= j;
|
||||
}
|
||||
fclose(FP);
|
||||
UpdateCDLogger();
|
||||
return;
|
||||
}
|
||||
|
||||
void SaveCDLogFileAs(){
|
||||
const char filter[]="Code Data Log File(*.CDL)\0*.cdl\0";
|
||||
char nameo[2048]; //todo: possibly no need for this? can lpstrfilter point to loadedcdfile instead?
|
||||
OPENFILENAME ofn;
|
||||
StopSound();
|
||||
memset(&ofn,0,sizeof(ofn));
|
||||
ofn.lStructSize=sizeof(ofn);
|
||||
ofn.hInstance=fceu_hInstance;
|
||||
ofn.lpstrTitle="Save Code Data Log File As...";
|
||||
ofn.lpstrFilter=filter;
|
||||
nameo[0]=0;
|
||||
ofn.lpstrFile=nameo;
|
||||
ofn.nMaxFile=256;
|
||||
ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
|
||||
ofn.hwndOwner = hCDLogger;
|
||||
if(!GetSaveFileName(&ofn))return;
|
||||
strcpy(loadedcdfile,nameo);
|
||||
SaveCDLogFile();
|
||||
return;
|
||||
}
|
||||
|
||||
void SaveCDLogFile(){ //todo make this button work before you've saved as
|
||||
FILE *FP;
|
||||
//if(loadedcdfile[0] == 0)SaveCDLogFileAs();
|
||||
//FCEUD_PrintError(loadedcdfile);
|
||||
|
||||
FP = fopen(loadedcdfile,"wb");
|
||||
if(FP == NULL){
|
||||
FCEUD_PrintError("Error Opening File");
|
||||
return;
|
||||
}
|
||||
fwrite(cdloggerdata,PRGsize[0],1,FP);
|
||||
fclose(FP);
|
||||
return;
|
||||
}
|
||||
|
||||
void DoCDLogger(){
|
||||
if (!GI) {
|
||||
FCEUD_PrintError("You must have a game loaded before you can use the Code Data Logger.");
|
||||
return;
|
||||
}
|
||||
if (GI->type==GIT_NSF) { //todo: NSF support!
|
||||
FCEUD_PrintError("Sorry, you can't yet use the Code Data Logger with NSFs.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!hCDLogger){
|
||||
CreateDialog(fceu_hInstance,"CDLOGGER",NULL,CDLoggerCallB);
|
||||
} else {
|
||||
SetWindowPos(hCDLogger,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateCDLogger(){
|
||||
char str[50];
|
||||
float fcodecount = codecount, fdatacount = datacount,
|
||||
fundefinedcount = undefinedcount, fromsize = PRGsize[0];
|
||||
if(!hCDLogger)return;
|
||||
sprintf(str,"0x%06x %.2f%%",codecount,fcodecount/fromsize*100);
|
||||
SetDlgItemText(hCDLogger,100,str);
|
||||
sprintf(str,"0x%06x %.2f%%",datacount,fdatacount/fromsize*100);
|
||||
SetDlgItemText(hCDLogger,101,str);
|
||||
sprintf(str,"0x%06x %.2f%%",undefinedcount,fundefinedcount/fromsize*100);
|
||||
SetDlgItemText(hCDLogger,102,str);
|
||||
return;
|
||||
}
|
||||
|
||||
void LogPCM(int romaddress){
|
||||
int i = GetPRGAddress(romaddress);
|
||||
if(i == -1)return;
|
||||
if(cdloggerdata[i] & 0x40)return;
|
||||
cdloggerdata[i] |= 0x40;
|
||||
|
||||
if(!(cdloggerdata[i] & 2)){
|
||||
datacount++;
|
||||
cdloggerdata[i] |= 2;
|
||||
if(!(cdloggerdata[i] & 1))undefinedcount--;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void SaveStrippedRom(){ //this is based off of iNesSave()
|
||||
//todo: make this support nsfs
|
||||
const char filter[]="Stripped iNes Rom file(*.NES)\0*.nes\0";
|
||||
char sromfilename[MAX_PATH];
|
||||
FILE *fp;
|
||||
OPENFILENAME ofn;
|
||||
int i;
|
||||
if(codecount == 0){
|
||||
MessageBox(NULL, "Unable to Generate Stripped Rom. Get Something Logged and try again.", "Error", MB_OK);
|
||||
return;
|
||||
}
|
||||
StopSound();
|
||||
memset(&ofn,0,sizeof(ofn));
|
||||
ofn.lStructSize=sizeof(ofn);
|
||||
ofn.hInstance=fceu_hInstance;
|
||||
ofn.lpstrTitle="Save Stripped Rom File As...";
|
||||
ofn.lpstrFilter=filter;
|
||||
sromfilename[0]=0;
|
||||
ofn.lpstrFile=sromfilename;
|
||||
ofn.nMaxFile=256;
|
||||
ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
|
||||
ofn.hwndOwner = hCDLogger;
|
||||
if(!GetSaveFileName(&ofn))return;
|
||||
|
||||
fp = fopen(sromfilename,"wb");
|
||||
|
||||
if(fwrite(&head,1,16,fp)!=16)return;
|
||||
|
||||
if(head.ROM_type&4) /* Trainer */
|
||||
{
|
||||
fwrite(trainerpoo,512,1,fp);
|
||||
}
|
||||
|
||||
for(i = 0;i < head.ROM_size*0x4000;i++){
|
||||
if(cdloggerdata[i] & 3)fputc(ROM[i],fp);
|
||||
else fputc(0,fp);
|
||||
}
|
||||
//fwrite(ROM,0x4000,head.ROM_size,fp);
|
||||
|
||||
if(head.VROM_size)fwrite(VROM,0x2000,head.VROM_size,fp);
|
||||
fclose(fp);
|
||||
}
|
1080
drivers/win/cheat.c
1080
drivers/win/cheat.c
File diff suppressed because it is too large
Load Diff
|
@ -1,2 +1,11 @@
|
|||
//--
|
||||
//mbg merge 7/18/06 had to make these extern
|
||||
extern int CheatWindow,CheatStyle; //bbit edited: this line added
|
||||
extern HWND hCheat;
|
||||
|
||||
void RedoCheatsLB(HWND hwndDlg);
|
||||
|
||||
void ConfigCheats(HWND hParent);
|
||||
void ConfigAddCheat(HWND wnd);
|
||||
void DoGGConv();
|
||||
void SetGGConvFocus(int address,int compare);
|
||||
//void ConfigAddCheat(HWND wnd); //bbit edited:commented out this line
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "../../driver.h"
|
||||
#include "../common/vidblit.h" //mbg merge 7/17/06 added
|
||||
#include "../common/config.h"
|
||||
#include "resource.h" //mbg merge 7/18/06 added
|
||||
|
||||
/* Message logging(non-netplay messages, usually) for all. */
|
||||
#include "log.h"
|
||||
|
|
|
@ -117,7 +117,7 @@ static CFGSTRUCT fceuconfig[]={
|
|||
AC(autoHoldClearKey),
|
||||
AC(frame_display),
|
||||
AC(input_display),
|
||||
ACS(MemWatchDir),
|
||||
//ACS(MemWatchDir), //mbg merge 7/18/06 removed
|
||||
ACS(BasicBotDir),
|
||||
AC(EnableBackgroundInput),
|
||||
ENDCFGSTRUCT
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
|
||||
#define relative(a) { \
|
||||
if (((a)=opcode[1])&0x80) (a) = addr-(((a)-1)^0xFF); \
|
||||
else (a)+=addr; \
|
||||
}
|
||||
#define absolute(a) { \
|
||||
(a) = opcode[1] | opcode[2]<<8; \
|
||||
}
|
||||
#define zpIndex(a,i) { \
|
||||
(a) = opcode[1]+(i); \
|
||||
}
|
||||
#define indirectX(a) { \
|
||||
(a) = (opcode[1]+X.X)&0xFF; \
|
||||
(a) = GetMem((a)) | (GetMem((a)+1))<<8; \
|
||||
}
|
||||
#define indirectY(a) { \
|
||||
(a) = GetMem(opcode[1]) | (GetMem(opcode[1]+1))<<8; \
|
||||
(a) += X.Y; \
|
||||
}
|
||||
|
||||
|
||||
//odd, 1-byte opcodes
|
||||
case 0x00: strcpy(str,"BRK"); break;
|
||||
case 0x08: strcpy(str,"PHP"); break;
|
||||
case 0x0A: strcpy(str,"ASL"); break;
|
||||
case 0x18: strcpy(str,"CLC"); break;
|
||||
case 0x28: strcpy(str,"PLP"); break;
|
||||
case 0x2A: strcpy(str,"ROL"); break;
|
||||
case 0x38: strcpy(str,"SEC"); break;
|
||||
case 0x40: strcpy(str,"RTI"); break;
|
||||
case 0x48: strcpy(str,"PHA"); break;
|
||||
case 0x4A: strcpy(str,"LSR"); break;
|
||||
case 0x58: strcpy(str,"CLI"); break;
|
||||
case 0x60: strcpy(str,"RTS"); break;
|
||||
case 0x68: strcpy(str,"PLA"); break;
|
||||
case 0x6A: strcpy(str,"ROR"); break;
|
||||
case 0x78: strcpy(str,"SEI"); break;
|
||||
case 0x88: strcpy(str,"DEY"); break;
|
||||
case 0x8A: strcpy(str,"TXA"); break;
|
||||
case 0x98: strcpy(str,"TYA"); break;
|
||||
case 0x9A: strcpy(str,"TXS"); break;
|
||||
case 0xA8: strcpy(str,"TAY"); break;
|
||||
case 0xAA: strcpy(str,"TAX"); break;
|
||||
case 0xB8: strcpy(str,"CLV"); break;
|
||||
case 0xBA: strcpy(str,"TSX"); break;
|
||||
case 0xC8: strcpy(str,"INY"); break;
|
||||
case 0xCA: strcpy(str,"DEX"); break;
|
||||
case 0xD8: strcpy(str,"CLD"); break;
|
||||
case 0xE8: strcpy(str,"INX"); break;
|
||||
case 0xEA: strcpy(str,"NOP"); break;
|
||||
case 0xF8: strcpy(str,"SED"); break;
|
||||
|
||||
//(Indirect,X)
|
||||
case 0x01: strcpy(chr,"ORA"); goto _indirectx;
|
||||
case 0x21: strcpy(chr,"AND"); goto _indirectx;
|
||||
case 0x41: strcpy(chr,"EOR"); goto _indirectx;
|
||||
case 0x61: strcpy(chr,"ADC"); goto _indirectx;
|
||||
case 0x81: strcpy(chr,"STA"); goto _indirectx;
|
||||
case 0xA1: strcpy(chr,"LDA"); goto _indirectx;
|
||||
case 0xC1: strcpy(chr,"CMP"); goto _indirectx;
|
||||
case 0xE1: strcpy(chr,"SBC"); goto _indirectx;
|
||||
_indirectx:
|
||||
indirectX(tmp);
|
||||
sprintf(str,"%s ($%02X,X) @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
|
||||
break;
|
||||
|
||||
//Zero Page
|
||||
case 0x05: strcpy(chr,"ORA"); goto _zeropage;
|
||||
case 0x06: strcpy(chr,"ASL"); goto _zeropage;
|
||||
case 0x24: strcpy(chr,"BIT"); goto _zeropage;
|
||||
case 0x25: strcpy(chr,"AND"); goto _zeropage;
|
||||
case 0x26: strcpy(chr,"ROL"); goto _zeropage;
|
||||
case 0x45: strcpy(chr,"EOR"); goto _zeropage;
|
||||
case 0x46: strcpy(chr,"LSR"); goto _zeropage;
|
||||
case 0x65: strcpy(chr,"ADC"); goto _zeropage;
|
||||
case 0x66: strcpy(chr,"ROR"); goto _zeropage;
|
||||
case 0x84: strcpy(chr,"STY"); goto _zeropage;
|
||||
case 0x85: strcpy(chr,"STA"); goto _zeropage;
|
||||
case 0x86: strcpy(chr,"STX"); goto _zeropage;
|
||||
case 0xA4: strcpy(chr,"LDY"); goto _zeropage;
|
||||
case 0xA5: strcpy(chr,"LDA"); goto _zeropage;
|
||||
case 0xA6: strcpy(chr,"LDX"); goto _zeropage;
|
||||
case 0xC4: strcpy(chr,"CPY"); goto _zeropage;
|
||||
case 0xC5: strcpy(chr,"CMP"); goto _zeropage;
|
||||
case 0xC6: strcpy(chr,"DEC"); goto _zeropage;
|
||||
case 0xE4: strcpy(chr,"CPX"); goto _zeropage;
|
||||
case 0xE5: strcpy(chr,"SBC"); goto _zeropage;
|
||||
case 0xE6: strcpy(chr,"INC"); goto _zeropage;
|
||||
_zeropage:
|
||||
// ################################## Start of SP CODE ###########################
|
||||
// Change width to %04X
|
||||
sprintf(str,"%s $%04X = #$%02X", chr,opcode[1],GetMem(opcode[1]));
|
||||
// ################################## End of SP CODE ###########################
|
||||
break;
|
||||
|
||||
//#Immediate
|
||||
case 0x09: strcpy(chr,"ORA"); goto _immediate;
|
||||
case 0x29: strcpy(chr,"AND"); goto _immediate;
|
||||
case 0x49: strcpy(chr,"EOR"); goto _immediate;
|
||||
case 0x69: strcpy(chr,"ADC"); goto _immediate;
|
||||
//case 0x89: strcpy(chr,"STA"); goto _immediate; //baka, no STA #imm!!
|
||||
case 0xA0: strcpy(chr,"LDY"); goto _immediate;
|
||||
case 0xA2: strcpy(chr,"LDX"); goto _immediate;
|
||||
case 0xA9: strcpy(chr,"LDA"); goto _immediate;
|
||||
case 0xC0: strcpy(chr,"CPY"); goto _immediate;
|
||||
case 0xC9: strcpy(chr,"CMP"); goto _immediate;
|
||||
case 0xE0: strcpy(chr,"CPX"); goto _immediate;
|
||||
case 0xE9: strcpy(chr,"SBC"); goto _immediate;
|
||||
_immediate:
|
||||
sprintf(str,"%s #$%02X", chr,opcode[1]);
|
||||
break;
|
||||
|
||||
//Absolute
|
||||
case 0x0D: strcpy(chr,"ORA"); goto _absolute;
|
||||
case 0x0E: strcpy(chr,"ASL"); goto _absolute;
|
||||
case 0x2C: strcpy(chr,"BIT"); goto _absolute;
|
||||
case 0x2D: strcpy(chr,"AND"); goto _absolute;
|
||||
case 0x2E: strcpy(chr,"ROL"); goto _absolute;
|
||||
case 0x4D: strcpy(chr,"EOR"); goto _absolute;
|
||||
case 0x4E: strcpy(chr,"LSR"); goto _absolute;
|
||||
case 0x6D: strcpy(chr,"ADC"); goto _absolute;
|
||||
case 0x6E: strcpy(chr,"ROR"); goto _absolute;
|
||||
case 0x8C: strcpy(chr,"STY"); goto _absolute;
|
||||
case 0x8D: strcpy(chr,"STA"); goto _absolute;
|
||||
case 0x8E: strcpy(chr,"STX"); goto _absolute;
|
||||
case 0xAC: strcpy(chr,"LDY"); goto _absolute;
|
||||
case 0xAD: strcpy(chr,"LDA"); goto _absolute;
|
||||
case 0xAE: strcpy(chr,"LDX"); goto _absolute;
|
||||
case 0xCC: strcpy(chr,"CPY"); goto _absolute;
|
||||
case 0xCD: strcpy(chr,"CMP"); goto _absolute;
|
||||
case 0xCE: strcpy(chr,"DEC"); goto _absolute;
|
||||
case 0xEC: strcpy(chr,"CPX"); goto _absolute;
|
||||
case 0xED: strcpy(chr,"SBC"); goto _absolute;
|
||||
case 0xEE: strcpy(chr,"INC"); goto _absolute;
|
||||
_absolute:
|
||||
absolute(tmp);
|
||||
sprintf(str,"%s $%04X = #$%02X", chr,tmp,GetMem(tmp));
|
||||
break;
|
||||
|
||||
//branches
|
||||
case 0x10: strcpy(chr,"BPL"); goto _branch;
|
||||
case 0x30: strcpy(chr,"BMI"); goto _branch;
|
||||
case 0x50: strcpy(chr,"BVC"); goto _branch;
|
||||
case 0x70: strcpy(chr,"BVS"); goto _branch;
|
||||
case 0x90: strcpy(chr,"BCC"); goto _branch;
|
||||
case 0xB0: strcpy(chr,"BCS"); goto _branch;
|
||||
case 0xD0: strcpy(chr,"BNE"); goto _branch;
|
||||
case 0xF0: strcpy(chr,"BEQ"); goto _branch;
|
||||
_branch:
|
||||
relative(tmp);
|
||||
sprintf(str,"%s $%04X", chr,tmp);
|
||||
break;
|
||||
|
||||
//(Indirect),Y
|
||||
case 0x11: strcpy(chr,"ORA"); goto _indirecty;
|
||||
case 0x31: strcpy(chr,"AND"); goto _indirecty;
|
||||
case 0x51: strcpy(chr,"EOR"); goto _indirecty;
|
||||
case 0x71: strcpy(chr,"ADC"); goto _indirecty;
|
||||
case 0x91: strcpy(chr,"STA"); goto _indirecty;
|
||||
case 0xB1: strcpy(chr,"LDA"); goto _indirecty;
|
||||
case 0xD1: strcpy(chr,"CMP"); goto _indirecty;
|
||||
case 0xF1: strcpy(chr,"SBC"); goto _indirecty;
|
||||
_indirecty:
|
||||
indirectY(tmp);
|
||||
sprintf(str,"%s ($%02X),Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
|
||||
break;
|
||||
|
||||
//Zero Page,X
|
||||
case 0x15: strcpy(chr,"ORA"); goto _zeropagex;
|
||||
case 0x16: strcpy(chr,"ASL"); goto _zeropagex;
|
||||
case 0x35: strcpy(chr,"AND"); goto _zeropagex;
|
||||
case 0x36: strcpy(chr,"ROL"); goto _zeropagex;
|
||||
case 0x55: strcpy(chr,"EOR"); goto _zeropagex;
|
||||
case 0x56: strcpy(chr,"LSR"); goto _zeropagex;
|
||||
case 0x75: strcpy(chr,"ADC"); goto _zeropagex;
|
||||
case 0x76: strcpy(chr,"ROR"); goto _zeropagex;
|
||||
case 0x94: strcpy(chr,"STY"); goto _zeropagex;
|
||||
case 0x95: strcpy(chr,"STA"); goto _zeropagex;
|
||||
case 0xB4: strcpy(chr,"LDY"); goto _zeropagex;
|
||||
case 0xB5: strcpy(chr,"LDA"); goto _zeropagex;
|
||||
case 0xD5: strcpy(chr,"CMP"); goto _zeropagex;
|
||||
case 0xD6: strcpy(chr,"DEC"); goto _zeropagex;
|
||||
case 0xF5: strcpy(chr,"SBC"); goto _zeropagex;
|
||||
case 0xF6: strcpy(chr,"INC"); goto _zeropagex;
|
||||
_zeropagex:
|
||||
zpIndex(tmp,X.X);
|
||||
// ################################## Start of SP CODE ###########################
|
||||
// Change width to %04X
|
||||
sprintf(str,"%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
|
||||
// ################################## End of SP CODE ###########################
|
||||
break;
|
||||
|
||||
//Absolute,Y
|
||||
case 0x19: strcpy(chr,"ORA"); goto _absolutey;
|
||||
case 0x39: strcpy(chr,"AND"); goto _absolutey;
|
||||
case 0x59: strcpy(chr,"EOR"); goto _absolutey;
|
||||
case 0x79: strcpy(chr,"ADC"); goto _absolutey;
|
||||
case 0x99: strcpy(chr,"STA"); goto _absolutey;
|
||||
case 0xB9: strcpy(chr,"LDA"); goto _absolutey;
|
||||
case 0xBE: strcpy(chr,"LDX"); goto _absolutey;
|
||||
case 0xD9: strcpy(chr,"CMP"); goto _absolutey;
|
||||
case 0xF9: strcpy(chr,"SBC"); goto _absolutey;
|
||||
_absolutey:
|
||||
absolute(tmp);
|
||||
tmp2=(tmp+X.Y);
|
||||
sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2));
|
||||
break;
|
||||
|
||||
//Absolute,X
|
||||
case 0x1D: strcpy(chr,"ORA"); goto _absolutex;
|
||||
case 0x1E: strcpy(chr,"ASL"); goto _absolutex;
|
||||
case 0x3D: strcpy(chr,"AND"); goto _absolutex;
|
||||
case 0x3E: strcpy(chr,"ROL"); goto _absolutex;
|
||||
case 0x5D: strcpy(chr,"EOR"); goto _absolutex;
|
||||
case 0x5E: strcpy(chr,"LSR"); goto _absolutex;
|
||||
case 0x7D: strcpy(chr,"ADC"); goto _absolutex;
|
||||
case 0x7E: strcpy(chr,"ROR"); goto _absolutex;
|
||||
case 0x9D: strcpy(chr,"STA"); goto _absolutex;
|
||||
case 0xBC: strcpy(chr,"LDY"); goto _absolutex;
|
||||
case 0xBD: strcpy(chr,"LDA"); goto _absolutex;
|
||||
case 0xDD: strcpy(chr,"CMP"); goto _absolutex;
|
||||
case 0xDE: strcpy(chr,"DEC"); goto _absolutex;
|
||||
case 0xFD: strcpy(chr,"SBC"); goto _absolutex;
|
||||
case 0xFE: strcpy(chr,"INC"); goto _absolutex;
|
||||
_absolutex:
|
||||
absolute(tmp);
|
||||
tmp2=(tmp+X.X);
|
||||
sprintf(str,"%s $%04X,X @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2));
|
||||
break;
|
||||
|
||||
//jumps
|
||||
case 0x20: strcpy(chr,"JSR"); goto _jump;
|
||||
case 0x4C: strcpy(chr,"JMP"); goto _jump;
|
||||
case 0x6C: absolute(tmp); sprintf(str,"JMP ($%04X) = $%04X", tmp,GetMem(tmp)|GetMem(tmp+1)<<8); break;
|
||||
_jump:
|
||||
absolute(tmp);
|
||||
sprintf(str,"%s $%04X", chr,tmp);
|
||||
break;
|
||||
|
||||
//Zero Page,Y
|
||||
case 0x96: strcpy(chr,"STX"); goto _zeropagey;
|
||||
case 0xB6: strcpy(chr,"LDX"); goto _zeropagey;
|
||||
_zeropagey:
|
||||
zpIndex(tmp,X.Y);
|
||||
// ################################## Start of SP CODE ###########################
|
||||
// Change width to %04X
|
||||
sprintf(str,"%s $%04X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp));
|
||||
// ################################## End of SP CODE ###########################
|
||||
break;
|
||||
|
||||
//UNDEFINED
|
||||
default: strcpy(str,"ERROR"); break;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,874 @@
|
|||
/* FCEUXD SP - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 Sebastian Porst
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "debuggersp.h"
|
||||
#include "..\..\debugger.h"
|
||||
#include "..\..\conddebug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
int GetNesFileAddress(int A);
|
||||
|
||||
Name* lastBankNames = 0;
|
||||
Name* loadedBankNames = 0;
|
||||
Name* ramBankNames = 0;
|
||||
int lastBank = -1;
|
||||
int loadedBank = -1;
|
||||
extern char LoadedRomFName[2048];
|
||||
char symbDebugEnabled = 0;
|
||||
int debuggerWasActive = 0;
|
||||
|
||||
/**
|
||||
* Tests whether a char is a valid hexadecimal character.
|
||||
*
|
||||
* @param c The char to test
|
||||
* @return True or false.
|
||||
**/
|
||||
int isHex(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all occurences of a substring in a string with a new string.
|
||||
* The maximum size of the string after replacing is 1000.
|
||||
* The caller must ensure that the src buffer is large enough.
|
||||
*
|
||||
* @param src Source string
|
||||
* @param r String to replace
|
||||
* @param w New string
|
||||
**/
|
||||
void replaceString(char* src, const char* r, const char* w)
|
||||
{
|
||||
char buff[1001] = {0};
|
||||
char* pos = src;
|
||||
char* beg = src;
|
||||
|
||||
// Check parameters
|
||||
|
||||
if (!src || !r || !w)
|
||||
{
|
||||
MessageBox(0, "Error: Invalid parameter in function replaceString", "Error", MB_OK | MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace sub strings
|
||||
|
||||
while ((pos = strstr(src, r)))
|
||||
{
|
||||
*pos = 0;
|
||||
strcat(buff, src);
|
||||
strcat(buff, w ? w : r);
|
||||
src = pos + strlen(r);
|
||||
}
|
||||
|
||||
strcat(buff, src);
|
||||
|
||||
strcpy(beg, buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bank for a given offset.
|
||||
* Technically speaking this function does not calculate the actual bank
|
||||
* where the offset resides but the 0x4000 bytes large chunk of the ROM of the offset.
|
||||
*
|
||||
* @param offs The offset
|
||||
* @return The bank of that offset or -1 if the offset is not part of the ROM.
|
||||
**/
|
||||
int getBank(int offs)
|
||||
{
|
||||
int addr = 0; //MBG TODO GetNesFileAddress(offs);
|
||||
return addr != -1 ? addr / 0x4000 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a line from a NL file.
|
||||
* @param line The line to parse
|
||||
* @param n The name structure to write the information to
|
||||
*
|
||||
* @return 0 if everything went OK. Otherwise an error code is returned.
|
||||
**/
|
||||
int parseLine(char* line, Name* n)
|
||||
{
|
||||
char* pos;
|
||||
int llen;
|
||||
|
||||
// Check parameters
|
||||
|
||||
if (!line)
|
||||
{
|
||||
MessageBox(0, "Invalid parameter \"line\" in function parseLine", "Error", MB_OK | MB_ICONERROR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!n)
|
||||
{
|
||||
MessageBox(0, "Invalid parameter \"n\" in function parseLine", "Error", MB_OK | MB_ICONERROR);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Allow empty lines
|
||||
if (*line == '\r' || *line == '\n')
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Attempt to tokenize the given line
|
||||
|
||||
pos = strstr(line, "#");
|
||||
|
||||
if (!pos)
|
||||
{
|
||||
// Found an invalid line
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Check if the first tokenized part (the offset) is valid
|
||||
|
||||
*pos = 0;
|
||||
|
||||
llen = (int)strlen(line);
|
||||
|
||||
if (llen == 5) // Offset size of normal lines of the form $XXXX
|
||||
{
|
||||
if (line[0] != '$'
|
||||
|| !isHex(line[1])
|
||||
|| !isHex(line[2])
|
||||
|| !isHex(line[3])
|
||||
|| !isHex(line[4])
|
||||
)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
else if (llen >= 7) // Offset size of array definition lines of the form $XXXX/YY
|
||||
{
|
||||
int i;
|
||||
if (line[0] != '$'
|
||||
|| !isHex(line[1])
|
||||
|| !isHex(line[2])
|
||||
|| !isHex(line[3])
|
||||
|| !isHex(line[4])
|
||||
|| line[5] != '/'
|
||||
)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
for (i=6;line[i];i++)
|
||||
{
|
||||
if (!isHex(line[i]))
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Lines that have an invalid size
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Validate if the offset is in the correct NL file.
|
||||
|
||||
// After validating the offset it's OK to store it
|
||||
n->offset = (char*)malloc(strlen(line) + 1);
|
||||
strcpy(n->offset, line);
|
||||
line = pos + 1;
|
||||
|
||||
// Attempt to tokenize the string again to find the name of the address
|
||||
|
||||
pos = strstr(line, "#");
|
||||
|
||||
if (!pos)
|
||||
{
|
||||
// Found an invalid line
|
||||
return 8;
|
||||
}
|
||||
|
||||
*pos = 0;
|
||||
|
||||
// The only requirement for a name of an address is that it's not of size 0
|
||||
|
||||
if (*line)
|
||||
{
|
||||
n->name = (char*)malloc(strlen(line) + 1);
|
||||
strcpy(n->name, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Properly initialize zero-length names too
|
||||
n->name = 0;
|
||||
}
|
||||
|
||||
// Now it's clear that the line was valid. The rest of the line is the comment
|
||||
// that belongs to that line. Once again a real string is required though.
|
||||
|
||||
line = pos + 1;
|
||||
|
||||
if (*line > 0x0D)
|
||||
{
|
||||
n->comment = (char*)malloc(strlen(line) + 1);
|
||||
strcpy(n->comment, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Properly initialize zero-length comments too
|
||||
n->comment = 0;
|
||||
}
|
||||
|
||||
// Everything went fine.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array of lines read from a NL file.
|
||||
* @param lines The lines to parse
|
||||
* @param filename The name of the file the lines were read from.
|
||||
*
|
||||
* @return A pointer to the first Name structure built from the parsed lines.
|
||||
**/
|
||||
Name* parse(char* lines, const char* filename)
|
||||
{
|
||||
char* pos, *size;
|
||||
Name* prev = 0, *cur, *first = 0;
|
||||
|
||||
// Check the parameters
|
||||
if (!lines)
|
||||
{
|
||||
MessageBox(0, "Invalid parameter \"lines\" in function parse", "Error", MB_OK | MB_ICONERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!filename)
|
||||
{
|
||||
MessageBox(0, "Invalid parameter \"filename\" in function parse", "Error", MB_OK | MB_ICONERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Begin the actual parsing
|
||||
|
||||
do
|
||||
{
|
||||
int fail;
|
||||
|
||||
// Allocate a name structure to hold the parsed data from the next line
|
||||
|
||||
cur = (Name*)malloc(sizeof(Name));
|
||||
cur->offset = 0;
|
||||
cur->next = 0;
|
||||
cur->name = 0;
|
||||
cur->comment = 0;
|
||||
|
||||
pos = lines;
|
||||
|
||||
// This first loop attempts to read potential multi-line comments and add them
|
||||
// into a single comment.
|
||||
for(;;)
|
||||
{
|
||||
// Get the end of the next line
|
||||
pos = strstr(pos, "\n");
|
||||
|
||||
// If there's no end of line or if the next line does not begin with a \ character
|
||||
// we can stop.
|
||||
if (!pos || pos[1] != '\\') break;
|
||||
|
||||
// At this point we have the following situation. pos[0] and pos[1] can be overwritten
|
||||
/*
|
||||
pos -1 0 1 2
|
||||
? \n \ ?
|
||||
*/
|
||||
|
||||
// \r\n is needed in text boxes
|
||||
if (pos[-1] != '\r')
|
||||
{
|
||||
pos[0] = '\r';
|
||||
pos[1] = '\n';
|
||||
pos += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove backslash
|
||||
pos[1] = ' ';
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pos)
|
||||
{
|
||||
// All lines were parsed
|
||||
break;
|
||||
}
|
||||
|
||||
*pos = 0;
|
||||
|
||||
// Attempt to parse the current line
|
||||
fail = parseLine(lines, cur);
|
||||
|
||||
if (fail == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (fail) // Show an error to allow the user to correct the defect line
|
||||
{
|
||||
const char* fmtString = "Error (Code: %d): Invalid line \"%s\" in NL file \"%s\"";
|
||||
char* msg = (char*)malloc(strlen(fmtString) + 8 + strlen(lines) + strlen(filename) + 1);
|
||||
sprintf(msg, fmtString, fail, lines, filename);
|
||||
MessageBox(0, msg, "Error", MB_OK | MB_ICONERROR);
|
||||
free(msg);
|
||||
lines = pos + 1;
|
||||
MessageBox(0, lines, "Error", MB_OK | MB_ICONERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
lines = pos + 1;
|
||||
|
||||
// Check if the line is an array definition line
|
||||
|
||||
size = strstr(cur->offset, "/");
|
||||
|
||||
if (size) // Array definition line
|
||||
{
|
||||
int arrlen, offset;
|
||||
|
||||
*size = 0;
|
||||
|
||||
// Attempt to read the length of the array and the array offset
|
||||
if (sscanf(size + 1, "%x", &arrlen) > 0 && sscanf(cur->offset + 1, "%x", &offset) > 0)
|
||||
{
|
||||
Name* nn = 0;
|
||||
int i;
|
||||
|
||||
// Create a node for each element of the array
|
||||
for (i=0;i<=arrlen;i++)
|
||||
{
|
||||
char numbuff[10] = {0};
|
||||
|
||||
nn = (Name*)malloc(sizeof(Name));
|
||||
nn->next = 0;
|
||||
|
||||
// The comment is the same for each array element
|
||||
nn->comment = strdup(cur->comment);
|
||||
|
||||
// The offset of the node
|
||||
nn->offset = (char*)malloc(10);
|
||||
sprintf(nn->offset, "$%04X", offset + i);
|
||||
|
||||
// The name of an array address is of the form NAME[INDEX]
|
||||
sprintf(numbuff, "[%X]", i);
|
||||
|
||||
nn->name = (char*)malloc(strlen(cur->name) + strlen(numbuff) + 1);
|
||||
strcpy(nn->name, cur->name);
|
||||
strcat(nn->name, numbuff);
|
||||
|
||||
// Add the new node to the list of address nodes
|
||||
if (prev)
|
||||
{
|
||||
prev->next = nn;
|
||||
prev = prev->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = prev = nn;
|
||||
}
|
||||
}
|
||||
|
||||
// Free the allocated node
|
||||
free(cur->name);
|
||||
free(cur->comment);
|
||||
free(cur->offset);
|
||||
free(cur);
|
||||
|
||||
cur = nn;
|
||||
}
|
||||
else
|
||||
{
|
||||
// I don't think it's possible to get here as the validity of
|
||||
// offset and array size has already been validated in parseLine
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the node to the list of address nodes
|
||||
if (prev)
|
||||
{
|
||||
prev->next = cur;
|
||||
prev = prev->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = prev = cur;
|
||||
}
|
||||
}
|
||||
} while (pos);
|
||||
|
||||
// Return the first node in the list of address nodes
|
||||
return first;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse an entire NL file
|
||||
* @param filename Name of the file to parse
|
||||
*
|
||||
* @return A pointer to the first Name structure built from the file data.
|
||||
**/
|
||||
Name* parseNameFile(const char* filename)
|
||||
{
|
||||
char* buffer;
|
||||
Name* n = 0;
|
||||
|
||||
// Attempt to read the file
|
||||
FILE* f = fopen(filename, "rb");
|
||||
|
||||
if (f)
|
||||
{
|
||||
// __asm (".byte 0xcc");
|
||||
// Get the file size
|
||||
int lSize;
|
||||
fseek (f , 0 , SEEK_END);
|
||||
lSize = ftell(f) + 1;
|
||||
|
||||
// Allocate sufficient buffer space
|
||||
rewind (f);
|
||||
|
||||
buffer = (char*)malloc(lSize);
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
// Read the file and parse it
|
||||
memset(buffer, 0, lSize);
|
||||
fread(buffer, 1, lSize - 1, f);
|
||||
n = parse(buffer, filename);
|
||||
|
||||
fclose(f);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees an entire list of Name nodes starting with the given node.
|
||||
*
|
||||
* @param n The node to start with (0 is a valid value)
|
||||
**/
|
||||
void freeList(Name* n)
|
||||
{
|
||||
Name* next;
|
||||
|
||||
while (n)
|
||||
{
|
||||
if (n->offset) free(n->offset);
|
||||
if (n->name) free(n->name);
|
||||
if (n->comment) free(n->comment);
|
||||
|
||||
next = n->next;
|
||||
free(n);
|
||||
n = next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all offsets in a string with the names that were given to those offsets
|
||||
* The caller needs to make sure that str is large enough.
|
||||
*
|
||||
* @param list NL list of address definitions
|
||||
* @param str The string where replacing takes place.
|
||||
**/
|
||||
void replaceNames(Name* list, char* str)
|
||||
{
|
||||
Name* beg = list;
|
||||
|
||||
if (!str)
|
||||
{
|
||||
MessageBox(0, "Error: Invalid parameter \"str\" in function replaceNames", "Error", MB_OK | MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
while (beg)
|
||||
{
|
||||
if (beg->name)
|
||||
{
|
||||
replaceString(str, beg->offset, beg->name);
|
||||
}
|
||||
|
||||
beg = beg->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches an address node in a list of address nodes. The found node
|
||||
* has the same offset as the passed parameter offs.
|
||||
*
|
||||
* @param node The address node list
|
||||
* @offs The offset to search
|
||||
* @return The node that has the given offset or 0.
|
||||
**/
|
||||
Name* searchNode(Name* node, const char* offs)
|
||||
{
|
||||
while (node)
|
||||
{
|
||||
if (!strcmp(node->offset, offs))
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the necessary NL files
|
||||
**/
|
||||
void loadNameFiles()
|
||||
{
|
||||
int cb;
|
||||
char* fn = (char*)malloc(strlen(LoadedRomFName) + 20);
|
||||
|
||||
if (ramBankNames)
|
||||
free(ramBankNames);
|
||||
|
||||
// The NL file for the RAM addresses has the name nesrom.nes.ram.nl
|
||||
strcpy(fn, LoadedRomFName);
|
||||
strcat(fn, ".ram.nl");
|
||||
|
||||
// Load the address descriptions for the RAM addresses
|
||||
ramBankNames = parseNameFile(fn);
|
||||
|
||||
free(fn);
|
||||
|
||||
// Find out which bank is loaded at 0xC000
|
||||
cb = getBank(0xC000);
|
||||
|
||||
if (cb == -1) // No bank was loaded at that offset
|
||||
{
|
||||
free(lastBankNames);
|
||||
lastBankNames = 0;
|
||||
}
|
||||
else if (cb != lastBank)
|
||||
{
|
||||
char* fn = (char*)malloc(strlen(LoadedRomFName) + 12);
|
||||
|
||||
// If the bank changed since loading the NL files the last time it's necessary
|
||||
// to load the address descriptions of the new bank.
|
||||
|
||||
lastBank = cb;
|
||||
|
||||
// Get the name of the NL file
|
||||
sprintf(fn, "%s.%X.nl", LoadedRomFName, lastBank);
|
||||
|
||||
if (lastBankNames)
|
||||
freeList(lastBankNames);
|
||||
|
||||
// Load new address definitions
|
||||
lastBankNames = parseNameFile(fn);
|
||||
|
||||
free(fn);
|
||||
}
|
||||
|
||||
// Find out which bank is loaded at 0x8000
|
||||
cb = getBank(0x8000);
|
||||
|
||||
if (cb == -1) // No bank is loaded at that offset
|
||||
{
|
||||
free(loadedBankNames);
|
||||
loadedBankNames = 0;
|
||||
}
|
||||
else if (cb != loadedBank)
|
||||
{
|
||||
char* fn = (char*)malloc(strlen(LoadedRomFName) + 12);
|
||||
|
||||
// If the bank changed since loading the NL files the last time it's necessary
|
||||
// to load the address descriptions of the new bank.
|
||||
|
||||
loadedBank = cb;
|
||||
|
||||
// Get the name of the NL file
|
||||
sprintf(fn, "%s.%X.nl", LoadedRomFName, loadedBank);
|
||||
|
||||
if (loadedBankNames)
|
||||
freeList(loadedBankNames);
|
||||
|
||||
// Load new address definitions
|
||||
loadedBankNames = parseNameFile(fn);
|
||||
|
||||
free(fn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds label and comment to an offset in the disassembly output string
|
||||
*
|
||||
* @param addr Address of the currently processed line
|
||||
* @param str Disassembly output string
|
||||
* @param chr Address in string format
|
||||
* @param decorate Flag that indicates whether label and comment should actually be added
|
||||
**/
|
||||
void decorateAddress(unsigned int addr, char* str, const char* chr, UINT decorate)
|
||||
{
|
||||
if (decorate)
|
||||
{
|
||||
Name* n;
|
||||
|
||||
if (addr < 0x8000)
|
||||
{
|
||||
// Search address definition node for a RAM address
|
||||
n = searchNode(ramBankNames, chr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search address definition node for a ROM address
|
||||
n = addr >= 0xC000 ? searchNode(lastBankNames, chr) : searchNode(loadedBankNames, chr);
|
||||
}
|
||||
|
||||
// If a node was found there's a name or comment to add do so
|
||||
if (n && (n->name || n->comment))
|
||||
{
|
||||
// Add name
|
||||
if (n->name && *n->name)
|
||||
{
|
||||
strcat(str, "Name: ");
|
||||
strcat(str, n->name);
|
||||
strcat(str,"\r\n");
|
||||
}
|
||||
|
||||
// Add comment
|
||||
if (n->comment && *n->comment)
|
||||
{
|
||||
strcat(str, "Comment: ");
|
||||
strcat(str, n->comment);
|
||||
strcat(str, "\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add address
|
||||
strcat(str, chr);
|
||||
strcat(str, ":");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a breakpoint condition is syntactically valid
|
||||
* and creates a breakpoint condition object if everything's OK.
|
||||
*
|
||||
* @param condition Condition to parse
|
||||
* @param num Number of the breakpoint in the BP list the condition belongs to
|
||||
* @return 0 in case of an error; 2 if everything went fine
|
||||
**/
|
||||
int checkCondition(char* condition, int num)
|
||||
{
|
||||
char* b = condition;
|
||||
|
||||
// Check if the condition isn't just all spaces.
|
||||
|
||||
int onlySpaces = 1;
|
||||
|
||||
while (*b)
|
||||
{
|
||||
if (*b != ' ')
|
||||
{
|
||||
onlySpaces = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
++b;
|
||||
}
|
||||
|
||||
// Remove the old breakpoint condition before
|
||||
// adding a new condition.
|
||||
|
||||
if (watchpoint[num].cond)
|
||||
{
|
||||
freeTree(watchpoint[num].cond);
|
||||
free(watchpoint[num].condText);
|
||||
|
||||
watchpoint[num].cond = 0;
|
||||
watchpoint[num].condText = 0;
|
||||
}
|
||||
|
||||
// If there's an actual condition create the BP condition object now
|
||||
|
||||
if (*condition && !onlySpaces)
|
||||
{
|
||||
Condition* c = generateCondition(condition);
|
||||
|
||||
// If the creation of the BP condition object was succesful
|
||||
// the condition is apparently valid. It can be added to the
|
||||
// breakpoint now.
|
||||
|
||||
if (c)
|
||||
{
|
||||
watchpoint[num].cond = c;
|
||||
watchpoint[num].condText = (char*)malloc(strlen(condition) + 1);
|
||||
strcpy(watchpoint[num].condText, condition);
|
||||
}
|
||||
else
|
||||
{
|
||||
watchpoint[num].cond = 0;
|
||||
}
|
||||
|
||||
return watchpoint[num].cond == 0 ? 2 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bookmark address of a CPU bookmark identified by its index.
|
||||
* The caller must make sure that the index is valid.
|
||||
*
|
||||
* @param hwnd HWND of the debugger window
|
||||
* @param index Index of the bookmark
|
||||
**/
|
||||
unsigned int getBookmarkAddress(HWND hwnd, unsigned int index)
|
||||
{
|
||||
int n;
|
||||
char buffer[5] = {0};
|
||||
|
||||
SendDlgItemMessage(hwnd, 701, LB_GETTEXT, index, (LPARAM)buffer);
|
||||
|
||||
sscanf(buffer, "%x", &n);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
unsigned int bookmarks;
|
||||
unsigned short* bookmarkData = 0;
|
||||
|
||||
/**
|
||||
* Stores all CPU bookmarks in a simple array to be able to store
|
||||
* them between debugging sessions.
|
||||
*
|
||||
* @param hwnd HWND of the debugger window.
|
||||
**/
|
||||
void dumpBookmarks(HWND hwnd)
|
||||
{
|
||||
unsigned int i;
|
||||
if (bookmarkData)
|
||||
free(bookmarkData);
|
||||
|
||||
bookmarks = SendDlgItemMessage(hwnd, 701, LB_GETCOUNT, 0, 0);
|
||||
bookmarkData = (unsigned short*)malloc(bookmarks * sizeof(unsigned short));
|
||||
|
||||
for (i=0;i<bookmarks;i++)
|
||||
{
|
||||
bookmarkData[i] = getBookmarkAddress(hwnd, i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a debugger bookmark to the list on the debugger window.
|
||||
*
|
||||
* @param hwnd HWMD of the debugger window
|
||||
* @param buffer Text of the debugger bookmark
|
||||
**/
|
||||
void AddDebuggerBookmark2(HWND hwnd, char* buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
{
|
||||
MessageBox(0, "Error: Invalid parameter \"buffer\" in function AddDebuggerBookmark2", "Error", MB_OK | MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
SendDlgItemMessage(hwnd, 701, LB_ADDSTRING, 0, (LPARAM)buffer);
|
||||
|
||||
dumpBookmarks(hwnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the offset from the debugger bookmark edit field and adds a debugger
|
||||
* bookmark with that offset to the bookmark list if the offset is valid.
|
||||
*
|
||||
* @param hwnd HWMD of the debugger window
|
||||
**/
|
||||
void AddDebuggerBookmark(HWND hwnd)
|
||||
{
|
||||
int result;
|
||||
unsigned int n;
|
||||
char buffer[5] = {0};
|
||||
|
||||
GetDlgItemText(hwnd, 312, buffer, 5);
|
||||
|
||||
result = sscanf(buffer, "%x", &n);
|
||||
|
||||
// Make sure the offset is valid
|
||||
if (result != 1 || n > 0xFFFF)
|
||||
{
|
||||
MessageBox(hwnd, "Invalid offset", "Error", MB_OK | MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
AddDebuggerBookmark2(hwnd, buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a debugger bookmark
|
||||
*
|
||||
* @param hwnd HWND of the debugger window
|
||||
**/
|
||||
void DeleteDebuggerBookmark(HWND hwnd)
|
||||
{
|
||||
// Get the selected bookmark
|
||||
int selectedItem = SendDlgItemMessage(hwnd, 701, LB_GETCURSEL, 0, 0);
|
||||
|
||||
if (selectedItem == LB_ERR)
|
||||
{
|
||||
MessageBox(hwnd, "Please select a bookmark from the list", "Error", MB_OK | MB_ICONERROR);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove the selected bookmark
|
||||
|
||||
SendDlgItemMessage(hwnd, 701, LB_DELETESTRING, selectedItem, 0);
|
||||
dumpBookmarks(hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
void Disassemble(HWND hWnd, int id, int scrollid, unsigned int addr);
|
||||
|
||||
/**
|
||||
* Shows the code at the bookmark address in the disassembly window
|
||||
*
|
||||
* @param hwnd HWND of the debugger window
|
||||
**/
|
||||
void GoToDebuggerBookmark(HWND hwnd)
|
||||
{
|
||||
unsigned int n;
|
||||
int selectedItem = SendDlgItemMessage(hwnd, 701, LB_GETCURSEL, 0, 0);
|
||||
|
||||
// If no bookmark is selected just return
|
||||
if (selectedItem == LB_ERR) return;
|
||||
|
||||
n = getBookmarkAddress(hwnd, selectedItem);
|
||||
|
||||
//Disassemble(hwnd, 300, 301, n);
|
||||
//MBG TODO
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* FCEUXD SP - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 Sebastian Porst
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
//mbg merge 7/17/06 made struct sane c++
|
||||
struct Name
|
||||
{
|
||||
Name* next;
|
||||
char* offset;
|
||||
char* name;
|
||||
char* comment;
|
||||
};
|
||||
|
||||
extern char symbDebugEnabled;
|
||||
extern unsigned int bookmarks;
|
||||
extern unsigned short* bookmarkData;
|
||||
extern int debuggerWasActive;
|
||||
|
||||
int checkCondition(char* buffer, int num);
|
||||
void loadNameFiles();
|
||||
void decorateAddress(unsigned int addr, char* str, const char* chr, UINT);
|
||||
void replaceNames(Name* list, char* str);
|
||||
void AddDebuggerBookmark(HWND hwnd);
|
||||
void AddDebuggerBookmark2(HWND hwnd, char* buffer);
|
||||
void DeleteDebuggerBookmark(HWND hwnd);
|
||||
void GoToDebuggerBookmark(HWND hwnd);
|
||||
int getBank(int offs);
|
||||
void dumpBookmarks(HWND hwmd);
|
|
@ -1016,6 +1016,7 @@ static BOOL CALLBACK InputConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARA
|
|||
|
||||
switch(uMsg) {
|
||||
case WM_INITDIALOG:
|
||||
SetDlgItemText(hwndDlg,65488,"Select the device you want to be enabled on input ports 1 and 2, and the Famicom expansion port. You may configure the device listed above each drop-down list by pressing \"Configure\", if applicable. The device currently being emulated on the each port is listed above the drop down list; loading certain games will override your settings, but only temporarily. If you select a device to be on the emulated Famicom Expansion Port, you should probably have emulated gamepads on the emulated NES-style input ports.");
|
||||
for(x=0;x<2;x++)
|
||||
{
|
||||
int y;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include "../../types.h" //mbg merge 7/17/06 added
|
||||
#include "../../fceu.h" //mbg merge 7/17/06 added
|
||||
#include "../../debugger.h" //mbg merge 7/18/06 added
|
||||
#include "input.h"
|
||||
#include "netplay.h"
|
||||
#include "joystick.h"
|
||||
|
@ -166,7 +167,8 @@ static int winwidth,winheight;
|
|||
static int ismaximized = 0;
|
||||
|
||||
static volatile int nofocus=0;
|
||||
static volatile int userpause=0;
|
||||
//static volatile int userpause=0; //mbg merge 7/18/06 removed. this has been replaced with FCEU_EmulationPaused stuff
|
||||
static volatile int _userpause=0; //mbg merge 7/18/06 changed tasbuild was using this only in a couple of places
|
||||
|
||||
#define SO_FORCE8BIT 1
|
||||
#define SO_SECONDARY 2
|
||||
|
@ -351,6 +353,12 @@ void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count);
|
|||
|
||||
void ApplyDefaultCommandMapping(void);
|
||||
|
||||
//mbg merge 7/18/06 - the function that contains the code that used to just be UpdateMemWatch()
|
||||
void _updateMemWatch() {
|
||||
//UpdateMemWatch()
|
||||
//but soon we will do more!
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
char *t;
|
||||
|
@ -435,7 +443,7 @@ doloopy:
|
|||
if(FCEUI_EmulationPaused() & 1)
|
||||
{
|
||||
if(stopCount==0)
|
||||
UpdateMemWatch();
|
||||
_updateMemWatch();
|
||||
|
||||
stopCount++;
|
||||
if(stopCount > 8)
|
||||
|
@ -459,7 +467,7 @@ doloopy:
|
|||
}
|
||||
else
|
||||
{
|
||||
//UpdateMemWatch();
|
||||
//_updateMemWatch();
|
||||
stopCount=0;
|
||||
}
|
||||
}
|
||||
|
@ -524,7 +532,7 @@ void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count)
|
|||
{
|
||||
skipcount = 0;
|
||||
FCEUD_BlitScreen(XBuf);
|
||||
UpdateMemWatch();
|
||||
_updateMemWatch();
|
||||
}
|
||||
else
|
||||
skipcount++;
|
||||
|
@ -563,7 +571,7 @@ void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count)
|
|||
{
|
||||
skipcount = 0;
|
||||
FCEUD_BlitScreen(XBuf);
|
||||
UpdateMemWatch();
|
||||
_updateMemWatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -647,7 +655,7 @@ void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count)
|
|||
if((!skipthis && !NoWaiting) || (skipcount >= maxskip))
|
||||
{
|
||||
FCEUD_BlitScreen(XBuf);
|
||||
UpdateMemWatch();
|
||||
_updateMemWatch();
|
||||
skipcount = 0;
|
||||
}
|
||||
else
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,235 @@
|
|||
/* FCEUXD SP - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 Sebastian Porst
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include "memviewsp.h"
|
||||
#include "common.h"
|
||||
|
||||
HexBookmark hexBookmarks[64];
|
||||
int nextBookmark = 0;
|
||||
|
||||
/**
|
||||
* Finds the bookmark for a given address
|
||||
*
|
||||
* @param address The address to find.
|
||||
* @return The index of the bookmark at that address or -1 if there's no bookmark at that address.
|
||||
**/
|
||||
int findBookmark(unsigned int address)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (address > 0xFFFF)
|
||||
{
|
||||
MessageBox(0, "Error: Invalid address was specified as parameter to findBookmark", "Error", MB_OK | MB_ICONERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0;i<nextBookmark;i++)
|
||||
{
|
||||
if (hexBookmarks[i].address == address)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char bookmarkDescription[51] = {0};
|
||||
|
||||
BOOL CenterWindow(HWND hwndDlg);
|
||||
|
||||
/**
|
||||
* Callback function for the name bookmark dialog
|
||||
**/
|
||||
BOOL CALLBACK nameBookmarkCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
// Limit bookmark descriptions to 50 characters
|
||||
SendDlgItemMessage(hwndDlg,1000,EM_SETLIMITTEXT,50,0);
|
||||
|
||||
// Put the current bookmark description into the edit field
|
||||
// and set focus to that edit field.
|
||||
SetDlgItemText(hwndDlg, 1000, bookmarkDescription);
|
||||
SetFocus(GetDlgItem(hwndDlg, 1000));
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
case WM_QUIT:
|
||||
// Update the bookmark description
|
||||
GetDlgItemText(hwndDlg, 1000, bookmarkDescription, 50);
|
||||
EndDialog(hwndDlg, 0);
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch(HIWORD(wParam))
|
||||
{
|
||||
case BN_CLICKED:
|
||||
switch(LOWORD(wParam))
|
||||
{
|
||||
case 1001:
|
||||
SendMessage(hwndDlg, WM_QUIT, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to add a new bookmark to the bookmark list.
|
||||
*
|
||||
* @param hwnd HWND of the FCEU window
|
||||
* @param address Address of the new bookmark
|
||||
* @return Returns 0 if everything's OK and an error flag otherwise.
|
||||
**/
|
||||
int addBookmark(HWND hwnd, unsigned int address)
|
||||
{
|
||||
// Enforce a maximum of 64 bookmarks
|
||||
if (nextBookmark < 64)
|
||||
{
|
||||
sprintf(bookmarkDescription, "%04X", address);
|
||||
|
||||
// Show the bookmark name dialog
|
||||
DialogBox(fceu_hInstance,"NAMEBOOKMARKDLG",hwnd,nameBookmarkCallB);
|
||||
|
||||
// Update the bookmark description
|
||||
hexBookmarks[nextBookmark].address = address;
|
||||
strcpy(hexBookmarks[nextBookmark].description, bookmarkDescription);
|
||||
|
||||
nextBookmark++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a bookmark from the bookmark list
|
||||
*
|
||||
* @param index Index of the bookmark to remove
|
||||
**/
|
||||
void removeBookmark(unsigned int index)
|
||||
{
|
||||
// TODO: Range checking
|
||||
|
||||
// At this point it's necessary to move the content of the bookmark list
|
||||
unsigned int i;
|
||||
for (i=index;i<nextBookmark - 1;i++)
|
||||
{
|
||||
hexBookmarks[i] = hexBookmarks[i+1];
|
||||
}
|
||||
|
||||
--nextBookmark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or removes a bookmark from a given address
|
||||
*
|
||||
* @param hwnd HWND of the emu window
|
||||
* @param address Address of the bookmark
|
||||
**/
|
||||
int toggleBookmark(HWND hwnd, unsigned int address)
|
||||
{
|
||||
int val = findBookmark(address);
|
||||
|
||||
// If there's no bookmark at the given address add one.
|
||||
if (val == -1)
|
||||
{
|
||||
return addBookmark(hwnd, address);
|
||||
}
|
||||
else // else remove the bookmark
|
||||
{
|
||||
removeBookmark(val);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the bookmark menu in the hex window
|
||||
*
|
||||
* @param menu Handle of the bookmark menu
|
||||
**/
|
||||
void updateBookmarkMenus(HMENU menu)
|
||||
{
|
||||
int i;
|
||||
MENUITEMINFO mi;
|
||||
mi.cbSize = sizeof(MENUITEMINFO);
|
||||
mi.fMask = MIIM_TYPE | MIIM_ID | MIIM_DATA;
|
||||
mi.fType = MF_STRING;
|
||||
|
||||
// Remove all bookmark menus
|
||||
for (i = 0;i<nextBookmark + 1;i++)
|
||||
{
|
||||
RemoveMenu(menu, 30 + i, MF_BYCOMMAND);
|
||||
}
|
||||
|
||||
// Add the menus again
|
||||
for (i = 0;i<nextBookmark;i++)
|
||||
{
|
||||
// Get the text of the menu
|
||||
char buffer[100];
|
||||
sprintf(buffer, i < 10 ? "$%04X - %s\tCTRL-%d" : "$%04X - %s", hexBookmarks[i].address, hexBookmarks[i].description, i);
|
||||
|
||||
mi.dwTypeData = buffer;
|
||||
mi.cch = strlen(buffer);
|
||||
mi.wID = 30 + i;
|
||||
|
||||
InsertMenuItem(menu, 2 + i , TRUE, &mi);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address to scroll to if a given bookmark was activated
|
||||
*
|
||||
* @param bookmark Index of the bookmark
|
||||
* @return The address to scroll to or -1 if the bookmark index is invalid.
|
||||
**/
|
||||
int handleBookmarkMenu(unsigned int bookmark)
|
||||
{
|
||||
if (bookmark < nextBookmark)
|
||||
{
|
||||
return hexBookmarks[bookmark].address - (hexBookmarks[bookmark].address % 0x10);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all bookmarks
|
||||
*
|
||||
* @param menu Handle of the bookmark menu
|
||||
**/
|
||||
void removeAllBookmarks(HMENU menu)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0;i<nextBookmark;i++)
|
||||
{
|
||||
RemoveMenu(menu, 30 + i, MF_BYCOMMAND);
|
||||
}
|
||||
|
||||
nextBookmark = 0;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/* FCEUXD SP - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 Sebastian Porst
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char description[51];
|
||||
unsigned int address;
|
||||
} HexBookmark;
|
||||
|
||||
extern HexBookmark hexBookmarks[64];
|
||||
extern int nextBookmark;
|
||||
|
||||
int toggleBookmark(HWND hwnd, unsigned int address);
|
||||
void updateBookmarkMenus(HMENU menu);
|
||||
int handleBookmarkMenu(unsigned int bookmark);
|
||||
void removeAllBookmarks(HMENU menu);
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
/* FCEUXD SP - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 Sebastian Porst
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "debuggersp.h"
|
||||
#include "memviewsp.h"
|
||||
#include "common.h"
|
||||
#include "../../debugger.h"
|
||||
|
||||
extern char symbDebugEnabled;
|
||||
|
||||
/**
|
||||
* Stores debugger preferences in a file
|
||||
*
|
||||
* @param f File to write the preferences to
|
||||
* @return 0 if everything went fine. An error code if something went wrong.
|
||||
**/
|
||||
int storeDebuggerPreferences(FILE* f)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Flag that says whether symbolic debugging should be enabled
|
||||
if (fwrite(&symbDebugEnabled, 1, 1, f) != 1) return 1;
|
||||
|
||||
// Write the number of active CPU bookmarks
|
||||
if (fwrite(&bookmarks, sizeof(unsigned int), 1, f) != 1) return 1;
|
||||
// Write the addresses of those bookmarks
|
||||
if (fwrite(bookmarkData, sizeof(unsigned short), bookmarks, f) != bookmarks) return 1;
|
||||
|
||||
// Write all breakpoints
|
||||
for (i=0;i<65;i++)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
// Write the start address of a BP
|
||||
if (fwrite(&watchpoint[i].address, sizeof(watchpoint[i].address), 1, f) != 1) return 1;
|
||||
// Write the end address of a BP
|
||||
if (fwrite(&watchpoint[i].endaddress, sizeof(watchpoint[i].endaddress), 1, f) != 1) return 1;
|
||||
// Write the flags of a BP
|
||||
if (fwrite(&watchpoint[i].flags, sizeof(watchpoint[i].flags), 1, f) != 1) return 1;
|
||||
|
||||
// Write the length of the BP condition
|
||||
len = watchpoint[i].condText ? strlen(watchpoint[i].condText) : 0;
|
||||
if (fwrite(&len, sizeof(len), 1, f) != 1) return 1;
|
||||
|
||||
// Write the text of the BP condition
|
||||
if (len)
|
||||
{
|
||||
if (fwrite(watchpoint[i].condText, 1, len, f) != len) return 1;
|
||||
}
|
||||
|
||||
len = watchpoint[i].desc ? strlen(watchpoint[i].desc) : 0;
|
||||
|
||||
// Write the length of the BP description
|
||||
if (fwrite(&len, sizeof(len), 1, f) != 1) return 1;
|
||||
|
||||
// Write the actual BP description
|
||||
if (len)
|
||||
{
|
||||
if (fwrite(watchpoint[i].desc, 1, len, f) != len) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the preferences from the Hex window
|
||||
*
|
||||
* @param f File to write the preferences to
|
||||
* @return 0 if everything went fine. An error code if something went wrong.
|
||||
**/
|
||||
int storeHexPreferences(FILE* f)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Writes the number of bookmarks to save
|
||||
if (fwrite(&nextBookmark, sizeof(nextBookmark), 1, f) != 1) return 1;
|
||||
|
||||
for (i=0;i<nextBookmark;i++)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
// Writes the bookmark address
|
||||
if (fwrite(&hexBookmarks[i].address, sizeof(hexBookmarks[i].address), 1, f) != 1) return 1;
|
||||
|
||||
len = strlen(hexBookmarks[i].description);
|
||||
// Writes the length of the bookmark description
|
||||
if (fwrite(&len, sizeof(len), 1, f) != 1) return 1;
|
||||
// Writes the actual bookmark description
|
||||
if (fwrite(hexBookmarks[i].description, 1, len, f) != len) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the debugging preferences to a file name romname.nes.deb
|
||||
*
|
||||
* @param romname Name of the ROM
|
||||
* @return 0 on success or an error code.
|
||||
**/
|
||||
int storePreferences(char* romname)
|
||||
{
|
||||
FILE* f;
|
||||
char* filename;
|
||||
|
||||
if (!debuggerWasActive)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
filename = (char*)malloc(strlen(romname) + 5);
|
||||
sprintf(filename, "%s.deb", romname);
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
|
||||
free(filename);
|
||||
|
||||
return !f || storeDebuggerPreferences(f) || storeHexPreferences(f);
|
||||
}
|
||||
|
||||
int myNumWPs = 0;
|
||||
int loadDebugDataFailed = 0;
|
||||
|
||||
/**
|
||||
* Loads debugger preferences from a file
|
||||
*
|
||||
* @param f File to write the preferences to
|
||||
* @return 0 if everything went fine. An error code if something went wrong.
|
||||
**/
|
||||
int loadDebuggerPreferences(FILE* f)
|
||||
{
|
||||
unsigned int i;
|
||||
// Read flag that says if symbolic debugging is enabled
|
||||
if (fread(&symbDebugEnabled, sizeof(symbDebugEnabled), 1, f) != 1) return 1;
|
||||
|
||||
// Read the number of CPU bookmarks
|
||||
if (fread(&bookmarks, sizeof(bookmarks), 1, f) != 1) return 1;
|
||||
|
||||
bookmarkData = (unsigned short*)malloc(bookmarks * sizeof(unsigned short));
|
||||
|
||||
// Read the offsets of the bookmarks
|
||||
for (i=0;i<bookmarks;i++)
|
||||
{
|
||||
if (fread(&bookmarkData[i], sizeof(bookmarkData[i]), 1, f) != 1) return 1;
|
||||
}
|
||||
|
||||
myNumWPs = 0;
|
||||
|
||||
// Read the breakpoints
|
||||
for (i=0;i<65;i++)
|
||||
{
|
||||
uint16 start, end;
|
||||
uint8 flags;
|
||||
unsigned int len;
|
||||
|
||||
// Read the start address of the BP
|
||||
if (fread(&start, sizeof(start), 1, f) != 1) return 1;
|
||||
// Read the end address of the BP
|
||||
if (fread(&end, sizeof(end), 1, f) != 1) return 1;
|
||||
// Read the flags of the BP
|
||||
if (fread(&flags, sizeof(flags), 1, f) != 1) return 1;
|
||||
|
||||
// Read the length of the BP description
|
||||
if (fread(&len, sizeof(len), 1, f) != 1) return 1;
|
||||
|
||||
if (len)
|
||||
{
|
||||
// Delete eventual older conditions
|
||||
if (watchpoint[myNumWPs].condText)
|
||||
free(watchpoint[myNumWPs].condText);
|
||||
|
||||
// Read the breakpoint condition
|
||||
watchpoint[myNumWPs].condText = (char*)malloc(len + 1);
|
||||
watchpoint[myNumWPs].condText[len] = 0;
|
||||
if (fread(watchpoint[myNumWPs].condText, 1, len, f) != len) return 1;
|
||||
|
||||
// TODO: Check return value
|
||||
checkCondition(watchpoint[myNumWPs].condText, myNumWPs);
|
||||
}
|
||||
|
||||
// Read length of the BP description
|
||||
if (fread(&len, sizeof(len), 1, f) != 1) return 1;
|
||||
|
||||
if (len)
|
||||
{
|
||||
// Delete eventual older description
|
||||
if (watchpoint[myNumWPs].desc)
|
||||
free(watchpoint[myNumWPs].desc);
|
||||
|
||||
// Read breakpoint description
|
||||
watchpoint[myNumWPs].desc = (char*)malloc(len + 1);
|
||||
watchpoint[myNumWPs].desc[len] = 0;
|
||||
if (fread(watchpoint[myNumWPs].desc, 1, len, f) != len) return 1;
|
||||
}
|
||||
|
||||
// Activate breapoint
|
||||
if (start || end || flags)
|
||||
{
|
||||
watchpoint[myNumWPs].address = start;
|
||||
watchpoint[myNumWPs].endaddress = end;
|
||||
watchpoint[myNumWPs].flags = flags;
|
||||
|
||||
myNumWPs++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads HexView preferences from a file
|
||||
*
|
||||
* @param f File to write the preferences to
|
||||
* @return 0 if everything went fine. An error code if something went wrong.
|
||||
**/
|
||||
int loadHexPreferences(FILE* f)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Read number of bookmarks
|
||||
fread(&nextBookmark, sizeof(nextBookmark), 1, f);
|
||||
|
||||
for (i=0;i<nextBookmark;i++)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
// Read address
|
||||
if (fread(&hexBookmarks[i].address, sizeof(hexBookmarks[i].address), 1, f) != 1) return 1;
|
||||
// Read length of description
|
||||
if (fread(&len, sizeof(len), 1, f) != 1) return 1;
|
||||
// Read the bookmark description
|
||||
if (fread(hexBookmarks[i].description, 1, len, f) != len) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the debugging preferences from disk
|
||||
*
|
||||
* @param romname Name of the active ROM file
|
||||
* @return 0 or an error code.
|
||||
**/
|
||||
int loadPreferences(char* romname)
|
||||
{
|
||||
FILE* f;
|
||||
// Get the name of the preferences file
|
||||
char* filename = (char*)malloc(strlen(romname) + 5);
|
||||
sprintf(filename, "%s.deb", romname);
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
free(filename);
|
||||
|
||||
// Attempt to load the preferences
|
||||
return f ? loadDebuggerPreferences(f) || loadHexPreferences(f) : 0;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/* FCEUXD SP - NES/Famicom Emulator
|
||||
*
|
||||
* Copyright notice for this file:
|
||||
* Copyright (C) 2005 Sebastian Porst
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
extern int myNumWPs;
|
||||
|
||||
int storePreferences(char* romname);
|
||||
int loadPreferences(char* romname);
|
||||
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
@ -0,0 +1,24 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by res.rc
|
||||
//
|
||||
#define IDI_ICON1 101
|
||||
#define IDI_ICON2 102
|
||||
#define ID_DEBUG_DEBUGGER 40053
|
||||
#define ID_DEBUG_PPUVIEWER 40054
|
||||
#define ID_DEBUG_NAMETABLEVIEWER 40055
|
||||
#define ID_DEBUG_HEXEDITOR 40056
|
||||
#define ID_DEBUG_TRACELOGGER 40057
|
||||
#define ID_DEBUG_CODE 40058
|
||||
#define ID_TOOLS_GAMEGENIEDECODER 40059
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40010
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
|
@ -148,7 +148,11 @@ static int RawWrite(void *data, uint32 len)
|
|||
{
|
||||
VOID *LockPtr[2]={0,0};
|
||||
DWORD LockLen[2]={0,0};
|
||||
uint32 curlen; //mbg merge 7/17/06 changed to uint
|
||||
|
||||
//mbg merge 7/17/06 changed to uint
|
||||
//mbg merge 7/18/06 was causing a crash when fastforwarding unless this was initialized to len
|
||||
uint32 curlen=len;
|
||||
|
||||
|
||||
// THIS LIMITS THE EMULATION SPEED
|
||||
if((!NoWaiting) || (soundoptions&SO_OLDUP))
|
||||
|
|
|
@ -934,7 +934,8 @@ BOOL CALLBACK VideoConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPara
|
|||
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
case WM_INITDIALOG:
|
||||
SetDlgItemText(hwndDlg,65454,"For the custom video mode settings to be in effect, the \"Custom\" video mode needs to be selected. If you select a sync method, and sound is disabled, you may want to disable speed throttling(in the \"Timing\" window). If you use \"wait for vblank\", you should use the \"lazy\" form.\x0AAllowing more than 8 sprites per scanline can cause graphics corruption in some games, including \"Solstice\".");
|
||||
for(x=0;x<11;x++)
|
||||
SendDlgItemMessage(hwndDlg,100,CB_ADDSTRING,0,(LPARAM)(LPSTR)vmstr[x]);
|
||||
SendDlgItemMessage(hwndDlg,100,CB_SETCURSEL,vmod,(LPARAM)(LPSTR)0);
|
||||
|
|
|
@ -507,6 +507,12 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
|
|||
}
|
||||
switch(wParam)
|
||||
{
|
||||
//-------
|
||||
//mbg merge 7/18/06 added XD tools
|
||||
case ID_DEBUG_DEBUGGER:
|
||||
DoDebug(0);
|
||||
break;
|
||||
|
||||
case 40004:
|
||||
SetAutoFirePattern(1,1);
|
||||
CheckedAutoFirePattern = wParam;
|
||||
|
@ -630,7 +636,7 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
|
|||
case 40003: FCEU_SetBotMode(1^FCEU_BotMode());
|
||||
UpdateMenu(); break;
|
||||
case 40002: CreateBasicBot();break;
|
||||
case 40028: DoMemmo(0); break;
|
||||
// case 40028: DoMemmo(0); break; //mbg merge 7/18/06 removed as part of old debugger
|
||||
case 320:StopSound();ConfigDirectories();break;
|
||||
case 327:StopSound();ConfigGUI();break;
|
||||
case 321:StopSound();ConfigInput(hWnd);break;
|
||||
|
@ -649,10 +655,10 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
|
|||
|
||||
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
case 203:BeginDSeq(hWnd);break;
|
||||
//case 203:BeginDSeq(hWnd);break; //mbg merge 7/18/06 removed as part of old debugger
|
||||
#endif
|
||||
|
||||
case 204:ConfigAddCheat(hWnd);break;
|
||||
//case 204:ConfigAddCheat(hWnd);break; //mbg merge TODO 7/17/06 - had to remove this
|
||||
//mbg merge TODO 7/17/06 - had to remove this
|
||||
//case 205:CreateMemWatch(hWnd);break;
|
||||
case 100:StopSound();
|
||||
|
@ -661,7 +667,7 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
|
|||
case 101:if(GI)
|
||||
{
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
KillDebugger();
|
||||
//KillDebugger(); //mbg merge 7/18/06 removed as part of old debugger
|
||||
#endif
|
||||
FCEUI_CloseGame();
|
||||
GI=0;
|
||||
|
@ -671,7 +677,7 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
|
|||
case 110:FCEUD_SaveStateAs();break;
|
||||
case 111:FCEUD_LoadStateFrom();break;
|
||||
|
||||
case 120:
|
||||
case 40120: //mbg merge 7/18/06 changed ID from 120
|
||||
{
|
||||
MENUITEMINFO mi;
|
||||
char *str;
|
||||
|
@ -885,7 +891,7 @@ void UpdateFCEUWindow(void)
|
|||
|
||||
BlockingCheck();
|
||||
#ifdef FCEUDEF_DEBUGGER
|
||||
UpdateDebugger();
|
||||
//UpdateDebugger(); //mbg merge 7/18/06 removed as part of old debugger
|
||||
#endif
|
||||
|
||||
if(!(eoptions&EO_BGRUN))
|
||||
|
@ -895,10 +901,10 @@ void UpdateFCEUWindow(void)
|
|||
Sleep(75);
|
||||
BlockingCheck();
|
||||
}
|
||||
if(userpause)
|
||||
if(_userpause) //mbg merge 7/18/06 this changed. even though theres nothing setting this..
|
||||
{
|
||||
StopSound();
|
||||
while(userpause)
|
||||
while(_userpause) //mbg merge 7/18/06 this changed. even though theres nothing setting this..
|
||||
{
|
||||
Sleep(50);
|
||||
BlockingCheck();
|
||||
|
@ -1260,6 +1266,7 @@ static BOOL CALLBACK DirConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM
|
|||
|
||||
switch(uMsg){
|
||||
case WM_INITDIALOG:
|
||||
SetDlgItemText(hwndDlg,65508,"The settings in the \"Individual Directory Overrides\" group will override the settings in the \"Base Directory Override\" group. To delete an override, delete the text from the text edit control. Note that the directory the configuration file is in cannot be overridden");
|
||||
for(x=0;x<6;x++)
|
||||
SetDlgItemText(hwndDlg,100+x,DOvers[x]);
|
||||
if(eoptions&EO_SNAPNAME)
|
||||
|
|
11
fceu.c
11
fceu.c
|
@ -68,7 +68,12 @@ writefunc BWrite[0x10000];
|
|||
static readfunc *AReadG;
|
||||
static writefunc *BWriteG;
|
||||
static int RWWrap=0;
|
||||
|
||||
//mbg merge 7/18/06 docs
|
||||
//bit0 indicates whether emulation is paused
|
||||
//bit1 indicates whether emulation is in frame step mode
|
||||
static int EmulationPaused=0;
|
||||
|
||||
static int RewindStatus[4] = {0, 0, 0, 0}; //is it safe to load rewind state
|
||||
static int RewindIndex = 0; //which rewind state we're on
|
||||
int EnableRewind = 0; //is rewind enabled
|
||||
|
@ -727,6 +732,12 @@ int FCEUI_EmulationPaused(void)
|
|||
return (EmulationPaused&1);
|
||||
}
|
||||
|
||||
//mbg merge 7/18/06 added
|
||||
//ideally maybe we shouldnt be using this, but i need it for quick merging
|
||||
void FCEUI_SetEmulationPaused(int val) {
|
||||
EmulationPaused = val;
|
||||
}
|
||||
|
||||
void FCEUI_ToggleEmulationPause(void)
|
||||
{
|
||||
EmulationPaused = (EmulationPaused&1)^1;
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
void DoMemView();
|
||||
void UpdateMemoryView(int draw_all);
|
||||
void UpdateColorTable();
|
||||
void ChangeMemViewFocus(int newEditingMode, int StartOffset,int EndOffset);
|
||||
|
||||
void ApplyPatch(int addr,int size, uint8* data);
|
||||
void UndoLastPatch();
|
||||
int GetFileData(int offset);
|
||||
int WriteFileData(int offset,int data);
|
||||
int GetRomFileSize();
|
||||
void FlushUndoBuffer();
|
||||
|
||||
extern HWND hMemView;
|
||||
extern int EditingMode;
|
2
nsf.c
2
nsf.c
|
@ -90,7 +90,7 @@ static uint16 PlayAddr;
|
|||
static uint16 InitAddr;
|
||||
static uint16 LoadAddr;
|
||||
|
||||
static NSF_HEADER NSFHeader;
|
||||
NSF_HEADER NSFHeader; //mbg merge 6/29/06 - needs to be global
|
||||
|
||||
void NSFMMC5_Close(void);
|
||||
static uint8 *ExWRAM=0;
|
||||
|
|
1
nsf.h
1
nsf.h
|
@ -42,6 +42,7 @@ typedef struct {
|
|||
} NSF_HEADER;
|
||||
void NSF_init(void);
|
||||
void DrawNSF(uint8 *XBuf);
|
||||
extern NSF_HEADER NSFHeader; //mbg merge 6/29/06
|
||||
void NSFDealloc(void);
|
||||
void NSFDodo(void);
|
||||
void DoNSFFrame(void);
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#define LOG_OPTION_SIZE 10
|
||||
#define LOG_REGISTERS 1
|
||||
#define LOG_PROCESSOR_STATUS 2
|
||||
#define LOG_NEW_INSTRUCTIONS 4
|
||||
#define LOG_NEW_DATA 8
|
||||
|
||||
extern HWND hTracer;
|
||||
extern int log_update_window;
|
||||
extern volatile int logtofile, logging;
|
||||
extern int logging_options;
|
||||
|
||||
void EnableTracerMenuItems(void);
|
||||
void LogInstruction(void);
|
||||
void DoTracer();
|
||||
//void PauseLoggingSequence();
|
||||
void UpdateLogWindow(void);
|
Loading…
Reference in New Issue