began merging XD stuff

there are still bugs in the emulator core :(

[[Split portion of a mixed commit.]]
This commit is contained in:
zeromus 2006-07-19 05:57:00 +00:00
parent db8bdfb036
commit d94c7aa450
34 changed files with 6746 additions and 451 deletions

10
cdlogger.h Normal file
View File

@ -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;

412
conddebug.c Normal file
View File

@ -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;
}

62
conddebug.h Normal file
View File

@ -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

141
debugger.h Normal file
View File

@ -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

View File

@ -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);

210
drivers/win/asm.h Normal file
View File

@ -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;
}
}

299
drivers/win/cdlogger.c Normal file
View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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"

View File

@ -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

252
drivers/win/dasm.h Normal file
View File

@ -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;

1432
drivers/win/debugger.c Normal file

File diff suppressed because it is too large Load Diff

874
drivers/win/debuggersp.c Normal file
View File

@ -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
}

46
drivers/win/debuggersp.h Normal file
View File

@ -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);

View File

@ -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;

View File

@ -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

1668
drivers/win/memview.c Normal file

File diff suppressed because it is too large Load Diff

235
drivers/win/memviewsp.c Normal file
View File

@ -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;
}

34
drivers/win/memviewsp.h Normal file
View File

@ -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);

279
drivers/win/pref.c Normal file
View File

@ -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;
}

27
drivers/win/pref.h Normal file
View File

@ -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

24
drivers/win/resource.h Normal file
View File

@ -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

View File

@ -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))

View File

@ -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);

View File

@ -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
View File

@ -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;

14
memview.h Normal file
View File

@ -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
View File

@ -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
View File

@ -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);

16
tracer.h Normal file
View File

@ -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);