mirror of https://github.com/stella-emu/stella.git
Tweaked ContextMenu so that an item is selected/committed only when the
left mouse button is pressed and released on the item (should fix problems with accidentally selecting an item). Also added 'Escape' key to mean "cancel/remove context menu". Updated '-help' commandline argument to recent additions. Huge amount of work on the documentation. It's probably not complete, but it's turning into a project in itself. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@776 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
09a8f8f10d
commit
8aed4f81a9
|
@ -1,753 +0,0 @@
|
||||||
|
|
||||||
20050717 bkw
|
|
||||||
|
|
||||||
This alpha build of Stella contains an incomplete version of the debugger.
|
|
||||||
|
|
||||||
What the debugger can do:
|
|
||||||
- Display registers and memory
|
|
||||||
- Dump state of TIA and RIOT, with things like joystick directions and
|
|
||||||
NUSIZx decoded into English (more-or-less).
|
|
||||||
- Change registers/memory, including toggles for flags in P register
|
|
||||||
- Single step/trace
|
|
||||||
- Breakpoints - break running program and enter debugger when the
|
|
||||||
Program Counter hits a predefined address. You can set as many
|
|
||||||
breakpoints as you want.
|
|
||||||
- Conditional breakpoints - Break running program when some arbitrary
|
|
||||||
condition is true (e.g. "breakif {a == $7f && c}" will break when the
|
|
||||||
Accumulator value is $7f and the Carry flag is true, no matter where
|
|
||||||
in the program this happens). Unlike the cond breaks in PCAE, Stella's
|
|
||||||
are *fast*: the emulation will run at full speed unless you use lots
|
|
||||||
of breakif's at the same time, or have a slow CPU
|
|
||||||
- Watches - View contents of a location/register before every
|
|
||||||
debugger prompt.
|
|
||||||
- Traps - Like breakpoints, but break on read/write/any access to
|
|
||||||
*any* memory location.
|
|
||||||
- Frame advance (automatic breakpoint at beginning of next frame)
|
|
||||||
You can advance multiple frames with one command.
|
|
||||||
- Disassembly
|
|
||||||
- Support for DASM symbol files (created with DASM's -s option),
|
|
||||||
including automatically loading symbol files if they're named
|
|
||||||
romname.sym
|
|
||||||
- Built-in VCS.H symbols, if no symbol file is loaded
|
|
||||||
- Symbolic names in disassembly
|
|
||||||
- Symbolic names accepted as input
|
|
||||||
- Tab completion for commands and symbol names
|
|
||||||
- Graphical editor for RIOT RAM. Acts a lot like a spreadsheet.
|
|
||||||
Input in hex, with displays for label/decimal/binary for
|
|
||||||
currently-selected location.
|
|
||||||
- GUI CPU state window
|
|
||||||
- Cheat system (similar to MAME) (still needs a way to save/load cheats)
|
|
||||||
- Reset the 6502
|
|
||||||
- Input and output in hex, decimal, or binary
|
|
||||||
- Start emulator in debugger (via command-line option "-debug")
|
|
||||||
- Save CLI session to a text file.
|
|
||||||
- Supports hex, decimal, and binary input and output almost everywhere.
|
|
||||||
(disassembly is still hex)
|
|
||||||
- Support for bank switching. You can see how many banks a cart has,
|
|
||||||
and switch banks. There's still more to be done here though.
|
|
||||||
- Patching ROM in-place. Currently there's no way to save the patched
|
|
||||||
ROM though.
|
|
||||||
- Registers/memory that get changed by the CPU during debugging are
|
|
||||||
highlighted when they're displayed
|
|
||||||
- Scanline advance (like frame advance, break at beginning
|
|
||||||
of next scanline).
|
|
||||||
- TIA display is updated during step/trace, so we can see our
|
|
||||||
scanlines being drawn as it happens. This isn't 100% perfect: unlike
|
|
||||||
a real TIA, the one in Stella only updates when it's written to.
|
|
||||||
- Script (batch) file support, including auto-running a script file
|
|
||||||
named after the ROM image.
|
|
||||||
- Saving the current debugger state to a script file (including
|
|
||||||
breakpoints, traps, etc).
|
|
||||||
- Built-in functions for use with "breakif", to support common conditions
|
|
||||||
(such as breaking when the user presses Game Select...)
|
|
||||||
- Save patched ROM ("saverom filename.bin").
|
|
||||||
|
|
||||||
Planned features for Stella 2.0 release:
|
|
||||||
- Graphical TIA tab, with register names and GUI buttons for
|
|
||||||
various bits (e.g. click ENAM0 to turn it on). This has been started
|
|
||||||
on already.
|
|
||||||
- GUI Disassembly window, scrollable, with checkboxes for breakpoints
|
|
||||||
(also perhaps 2 panes in this window so you can see 2 parts of the
|
|
||||||
code at once)
|
|
||||||
- Bankswitch support in the debugger for the few remaining cart types
|
|
||||||
that aren't supported.
|
|
||||||
- Patch ROM support for a few cart types doesn't work. Must fix.
|
|
||||||
- Some way to control joystick/etc. input from within the debugger.
|
|
||||||
- Source-level debugging: if a DASM .lst file is available, we'll show
|
|
||||||
the listing in the ROM tab instead of a disassembly. This is already
|
|
||||||
availabe in a very crude form ("loadlist" and "list" commands).
|
|
||||||
- More "special variables" for the expression parser. Currently, you can
|
|
||||||
use all the CPU registers and flags in expressions (e.g. "print a+1" does
|
|
||||||
what you expect), and the pseudo-variables "_scan" and "_bank" (which
|
|
||||||
evaluate the the current scanline and bank number). Need to add more TIA,
|
|
||||||
RIOT registers too. Also, more functions for the builtin function lib.
|
|
||||||
|
|
||||||
Future plans (post 2.0):
|
|
||||||
- Possibly a mini-assembler
|
|
||||||
- Support for extra RAM in Supercharger and other cart types.
|
|
||||||
- Possibly support for recording and playing back input files, like
|
|
||||||
MAME. This isn't a debugger feature per se, but it'll make it easier
|
|
||||||
to reliably trigger a bug so you can debug it
|
|
||||||
- Graphics ROM view, so you can see your sprite data (it might still
|
|
||||||
be upside-down though :)
|
|
||||||
- Various new GUI enhancements
|
|
||||||
|
|
||||||
How to use the debugger
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
Pressing ` (aka backtick, backquote, grave accent) toggles the debugger on
|
|
||||||
& off. When you exit the debugger, the emulation resumes at the current
|
|
||||||
program counter, and continues until either a breakpoint/trap is hit,
|
|
||||||
or the ` key is pressed again. Pressing Ctrl-Tab cycles between tabs
|
|
||||||
from left to right, and Shift-Ctrl-Tab cycles from right to left.
|
|
||||||
Pressing Tab cycles between widgets in the current tab.
|
|
||||||
|
|
||||||
You can also enter the debugger by giving a breakpoint on the command line:
|
|
||||||
|
|
||||||
; will enter the debugger the first time the instruction at "kernel" runs
|
|
||||||
stella -break kernel mygame.bin
|
|
||||||
|
|
||||||
; $fffc is the 6502/6507 init vector. This command will break and enter the
|
|
||||||
; debugger before the first 6507 instruction runs, so you can debug the
|
|
||||||
; startup code:
|
|
||||||
stella -break "*($fffc)" mygame.bin
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Tabs:
|
|
||||||
|
|
||||||
The top-level user interface uses tabs to select the current debugger
|
|
||||||
mode. Not all the tabs are implemented yet: those that aren't will just
|
|
||||||
show up as a blank tab.
|
|
||||||
|
|
||||||
The tabs that are implemented so far:
|
|
||||||
|
|
||||||
- Prompt tab
|
|
||||||
|
|
||||||
This is a command-line interface, similar to the DOS DEBUG command
|
|
||||||
or Supermon for the C=64. It shows you the current CPU state, including
|
|
||||||
the disassembly of the instruction pointed to by the Program Counter.
|
|
||||||
This instruction is the NEXT one that will execute, NOT the one that
|
|
||||||
just executed!
|
|
||||||
|
|
||||||
Editing keys work about like you'd expect them to: Home, End, Delete,
|
|
||||||
arrows, etc. To scroll with the keyboard, use Shift-PageUp and
|
|
||||||
Shift-PageDown or Shift-Up and Shift-Down arrow keys. You can also
|
|
||||||
scroll with the mouse. Copy and paste is not (yet?) supported.
|
|
||||||
|
|
||||||
To see the available commands, enter "help" or "?". Most commands can
|
|
||||||
be abbreviated: instead of "clearbreaks", you can type "clear" or
|
|
||||||
even just "cl". However, "c" by itself is the Toggle Carry command.
|
|
||||||
|
|
||||||
Bash-style tab completion is supported for commands and labels (see below)
|
|
||||||
|
|
||||||
For now, there are some functions that only exist in the prompt. We
|
|
||||||
intend to add GUI equivalents for all (or almost all?) of the prompt
|
|
||||||
commands by the time we release Stella 2.0. People who like command
|
|
||||||
prompts will be able to use the prompt, but people who hate them will
|
|
||||||
have a fully functional debugger without typing (or without typing
|
|
||||||
much, anyway).
|
|
||||||
|
|
||||||
- Status
|
|
||||||
|
|
||||||
Before each prompt, you'll see a dump of the current processor
|
|
||||||
status, plus any watches you've set (see section on watches
|
|
||||||
below), plus a disassembly of the instruction at the current
|
|
||||||
Program Counter. This is the next instruction that will execute;
|
|
||||||
it hasn't been executed yet.
|
|
||||||
|
|
||||||
PC=f000 A=01 X=02 Y=03 S=ff P=21/nv-bdizC Cycle 12345
|
|
||||||
$f000 a2 ff LDX #ff ; 2
|
|
||||||
>
|
|
||||||
|
|
||||||
This is telling us a lot of information:
|
|
||||||
|
|
||||||
- PC=f000 A=01 X=02 Y=03 S=ff
|
|
||||||
The Program Counter, Accumulator, X, Y, and Stack Pointer registers.
|
|
||||||
|
|
||||||
- P=21/nv-bdizC
|
|
||||||
The Processor Status register. The "21" is the hex value of the
|
|
||||||
register, and the "nv-bdizC" shows us the individual flags. Flags
|
|
||||||
with capital letters are set, and lowercase means clear. In this
|
|
||||||
example, only the Carry bit is set.
|
|
||||||
|
|
||||||
- Cycle 12345
|
|
||||||
This counter gets reset at the beginning of each frame, when
|
|
||||||
VSYNC is strobed. In this example, we're 12345 (decimal) cycles
|
|
||||||
past the beginning of the frame.
|
|
||||||
|
|
||||||
- $f000 a2 ff LDX #ff ; 2
|
|
||||||
Disassembly of the instruction the PC points to. This is the next
|
|
||||||
instruction that will execute (when we exit the debugger, or via the
|
|
||||||
"step" or "trace" commands). The "a2 ff" is the raw machine code
|
|
||||||
for this instruction. The "; 2" is a cycle count: this instruction
|
|
||||||
will take 2 cycles to execute.
|
|
||||||
|
|
||||||
WARNING: the cycle count in the disassembly does NOT include extra
|
|
||||||
cycles caused by crossing page boundaries. Also, Branch instructions
|
|
||||||
are shown as 2 cycles, as though they're not going to be taken. A
|
|
||||||
branch that's taken adds a cycle, of course.
|
|
||||||
|
|
||||||
The ">" is where your commands will appear as you type them.
|
|
||||||
|
|
||||||
|
|
||||||
- Tab completion
|
|
||||||
|
|
||||||
While entering a command or label, you can type a partial name and
|
|
||||||
press the Tab key to attempt to auto-complete it. If you've ever used
|
|
||||||
"bash", this will be immediately familiar. If not, try it: load up
|
|
||||||
a ROM, go to the debugger, type "print w" (but don't press Enter),
|
|
||||||
then hit Tab. The "w" will change to "WSYNC" (since this is the only
|
|
||||||
built-in label starting with a "w"). If there are multiple possible
|
|
||||||
completions (try with "v" instead of "w"), you'll see a list of them,
|
|
||||||
and your partial name will be completed as far as possible.
|
|
||||||
|
|
||||||
Tab completion works on all labels: built-in, loaded from a symbol file,
|
|
||||||
or set during debugging with the "define" command. However, it does not
|
|
||||||
yet work on functions defined with the "function" command, nor does it
|
|
||||||
work on filenames.
|
|
||||||
|
|
||||||
- Expressions
|
|
||||||
|
|
||||||
Almost every command takes a value: the "a" command takes a
|
|
||||||
byte to stuff into the accumulator, the "break" command
|
|
||||||
takes an address to set/clear a breakpoint at. These values
|
|
||||||
can be as a hex constant ($ff, $1234), or as complex as
|
|
||||||
"the low byte of the 16-bit value located at the address
|
|
||||||
pointed to by the binary number 1010010110100101" (which
|
|
||||||
would be "@<\1010010110100101"). You can also use registers
|
|
||||||
and labels in expressions.
|
|
||||||
|
|
||||||
You can use arithmetic and boolean operators in expressions. The
|
|
||||||
syntax is very C-like. The operators supported are:
|
|
||||||
|
|
||||||
+ - * / (add, subtract, multiply, divide: 2+2 is 4)
|
|
||||||
% (modulus/remainder: 3%2 is 1)
|
|
||||||
& | ^ ~ (bitwise AND, OR, XOR, NOT: 2&3 is 2)
|
|
||||||
&& || ! (logical AND, OR, NOT: 2&&3 is 1, 2||0 is 0)
|
|
||||||
( ) (parentheses for grouping: (2+2)*3 is 12)
|
|
||||||
* @ (byte and word pointer dereference: *$80 is the byte stored
|
|
||||||
at location $80)
|
|
||||||
[ ] (array-style byte pointer dereference: $80[1] is the byte
|
|
||||||
stored at location ($80+1) or $81)
|
|
||||||
< > (prefix versions: low and high byte. <$abcd is $cd)
|
|
||||||
== < > <= >= !=
|
|
||||||
(comparison: equality, less-than, greater-than, less-or-equals,
|
|
||||||
greater-or-equals, not-equals)
|
|
||||||
<< >> (bit shifts, left and right: 1<<1 is 2, 2>>1 is 1)
|
|
||||||
|
|
||||||
Division by zero is not an error: it results in zero instead.
|
|
||||||
|
|
||||||
None of the operators change the values of their operands. There
|
|
||||||
are no variable-assignment or increment/decrement operators. This
|
|
||||||
may change in the future, which is why we used "==" for equality
|
|
||||||
instead of just "=".
|
|
||||||
|
|
||||||
The bitwise and logical boolean operators are different in that the
|
|
||||||
bitwise operators operate on all the bits of the operand (just like
|
|
||||||
AND, ORA, EOR in 6502 asm), while the logical operators treat their
|
|
||||||
operands as 0 for false, non-zero for true, and return either 0 or 1.
|
|
||||||
So $1234&$5678 results in $1230, whereas $1234&&$5678 results in 1.
|
|
||||||
This is just like C or C++...
|
|
||||||
|
|
||||||
Like some programming languages, the debugger uses prefixed characters
|
|
||||||
to change the meaning of an expression. The prefixes are:
|
|
||||||
|
|
||||||
- Dereference prefixes:
|
|
||||||
|
|
||||||
- "*"
|
|
||||||
Dereference a byte pointer. "*a" means "the byte at the address that
|
|
||||||
the A register points to". If A is 255 (hex $ff), the result will be
|
|
||||||
the value currently stored in memory location 255. This operator
|
|
||||||
will be very familiar to you if you're a C or C++ programmer. It's
|
|
||||||
equivalent to the PEEK() function in most 8-bit BASICs. Also, the
|
|
||||||
debugger supports array-like byte dereferences: *address can be
|
|
||||||
written as address[0]. *(address+1) can be written as address[1],
|
|
||||||
etc.
|
|
||||||
|
|
||||||
- "@"
|
|
||||||
Dereference a pointer to a word. This is just like the "*" byte deref,
|
|
||||||
except it refers to a 16-bit value, occupying 2 locations, in
|
|
||||||
low-byte-first format (standard for the 6507).
|
|
||||||
|
|
||||||
The following are equivalent:
|
|
||||||
|
|
||||||
@address
|
|
||||||
*address+$100**(address+1)
|
|
||||||
address[0]+#256*address[1]
|
|
||||||
|
|
||||||
(TODO: add (indirect),y and (indirect,x) syntax)
|
|
||||||
|
|
||||||
- Hi/Lo Byte Prefixes
|
|
||||||
|
|
||||||
- "<"
|
|
||||||
Take the low byte of a 16-bit value. This has no effect on an 8-bit
|
|
||||||
value: "a" is equal to "<a". However, "<$1234" equals "$34".
|
|
||||||
|
|
||||||
- ">"
|
|
||||||
Take the high byte of a 16-bit value. For 8-bit values such as
|
|
||||||
the Accumulator, this will always result in zero. For 16-bit values,
|
|
||||||
"<$1234" = "$12".
|
|
||||||
|
|
||||||
- Number Base Prefixes
|
|
||||||
|
|
||||||
- "#"
|
|
||||||
Treat the input as a decimal number.
|
|
||||||
|
|
||||||
- "$"
|
|
||||||
Treat the input as a hex number.
|
|
||||||
|
|
||||||
- "\"
|
|
||||||
Treat the input as a binary number.
|
|
||||||
|
|
||||||
These only have meaning when they come before a number, not a
|
|
||||||
label or a register. "\1010" means 10 decimal. So do "$0a" and
|
|
||||||
"#10". "a" by itself is always the Accumulator, no matter what
|
|
||||||
the default base is set to.
|
|
||||||
|
|
||||||
If you don't specify any number base prefix, the number is
|
|
||||||
assumed to be in the default base. When you first start Stella,
|
|
||||||
the default base is 16 (hexadecimal). You can change it with the
|
|
||||||
"base" command.
|
|
||||||
|
|
||||||
Remember, you can use arbitrarily complex expressions with any
|
|
||||||
command that takes arguments (except the ones that take filenames,
|
|
||||||
like "loadsym").
|
|
||||||
|
|
||||||
|
|
||||||
- Breakpoints, watches and traps, oh my!
|
|
||||||
|
|
||||||
- Breakpoints
|
|
||||||
|
|
||||||
A breakpoint is a "hotspot" in your program that causes the emulator
|
|
||||||
to stop emulating and jump into the debugger. You can set as many
|
|
||||||
breakpoints as you like. The command is "break xx" where xx is any
|
|
||||||
expression. If you've created a symbol file, you can use labels.
|
|
||||||
|
|
||||||
Example: you've got a label called "kernel". To break there,
|
|
||||||
the command is "break kernel". After you've set the breakpoint,
|
|
||||||
exit the debugger ("quit" or click the Exit button). The emulator
|
|
||||||
will run until it gets to the breakpoint, then it will enter the
|
|
||||||
debugger with the Program Counter pointing to the instruction
|
|
||||||
at the breakpoint.
|
|
||||||
|
|
||||||
Breakpoints happen *before* an instruction is executed: the
|
|
||||||
instruction at the breakpoint location will be the "next"
|
|
||||||
instruction.
|
|
||||||
|
|
||||||
To remove a breakpoint, you just run the same command you used to
|
|
||||||
set it. In the example, "break kernel" will remove the breakpoint.
|
|
||||||
The "break" command can be thought of as a *toggle*: it turns the
|
|
||||||
breakpoint on & off, like a light switch.
|
|
||||||
|
|
||||||
You could also use "clearbreaks" to remove all the breakpoints. Also,
|
|
||||||
there is a "listbreaks" command that will list them all.
|
|
||||||
|
|
||||||
- Conditional Breaks
|
|
||||||
|
|
||||||
A conditional breakpoint causes the emulator to enter the debugger when
|
|
||||||
some arbitrary condition becomes true. "True" means "not zero" here:
|
|
||||||
"2+2" is considered true because it's not zero. "2-2" is false, because
|
|
||||||
it evaluates to zero. This is exactly how things work in C and lots
|
|
||||||
of other languages, but it might take some getting used to if you've
|
|
||||||
never used such a language.
|
|
||||||
|
|
||||||
Suppose you want to enter the debugger when the Game Reset switch is
|
|
||||||
pressed. Looking at the Stella Programmers' Guide, we see that this
|
|
||||||
switch is read at bit 0 of SWCHB. This bit will be 0 if the switch is
|
|
||||||
pressed, or 1 otherwise.
|
|
||||||
|
|
||||||
To have an expression read the contents of an address, we use the
|
|
||||||
dereference operator "*". Since we're looking at SWCHB, we need
|
|
||||||
"*SWCHB".
|
|
||||||
|
|
||||||
We're only wanting to look at bit 0, so let's mask off all the other
|
|
||||||
bits: "*SWCHB&1". The expression now evaluates to bit 0 of SWCHB. We're
|
|
||||||
almost there: this will be 1 (true) if the switch is NOT pressed. We
|
|
||||||
want to break if it IS pressed...
|
|
||||||
|
|
||||||
So we invert the sense of the test with a logical NOT operator (which
|
|
||||||
is the "!" operator): !(*SWCHB&1). The parentheses are necessary as
|
|
||||||
we want to apply the ! to the result of the &, not just the first term
|
|
||||||
(the "*SWCHB").
|
|
||||||
|
|
||||||
"breakif !(*SWCHB&1)" will do the job for us. However, it's an ugly mess
|
|
||||||
of letters, numbers, and punctuation. We can do a little better:
|
|
||||||
|
|
||||||
"breakif { !(*SWCHB & 1 ) }" is a lot more readable, isn't it? If
|
|
||||||
you're going to use readable expressions with spaces in them,
|
|
||||||
enclose the entire expression in curly braces {}.
|
|
||||||
|
|
||||||
There is one annoyance about this complex expression: once we
|
|
||||||
remove the conditional break with "delbreakif" or "clearbreaks",
|
|
||||||
we'd have to retype it (or search backwards with the up-arrow key)
|
|
||||||
if we wanted to use it again.
|
|
||||||
|
|
||||||
We can avoid this by defining the expression as a function, then using
|
|
||||||
"breakif function_name":
|
|
||||||
|
|
||||||
function gameReset { !(*SWCHB & 1 ) }
|
|
||||||
breakif gameReset
|
|
||||||
|
|
||||||
Now we have a meaningful name for the condition, so we can use it again.
|
|
||||||
Not only that: we can use the function as part of a bigger expression.
|
|
||||||
Suppose we've also defined a gameSelect function that evaluates to true
|
|
||||||
if the Game Select switch is pressed. We want to break when the user
|
|
||||||
presses both Select and Reset:
|
|
||||||
|
|
||||||
breakif { gameReset && gameSelect }
|
|
||||||
|
|
||||||
If you've defined a lot of complex functions, you probably will
|
|
||||||
want to re-use them in future runs of the debugger. You can save
|
|
||||||
all your functions, breakpoints, conditional breaks, and watches
|
|
||||||
with the "save" command. If you name your saved file the same
|
|
||||||
as the ROM filename, it'll be auto-loaded next time you load the
|
|
||||||
same ROM in Stella. The save file is just a plain text file called
|
|
||||||
"filename.stella", so you can edit it and add new functions, etc.
|
|
||||||
|
|
||||||
Conditional breaks appear in "listbreaks", numbered starting from
|
|
||||||
zero. You can remove a cond. break with "delbreakif number", where
|
|
||||||
the number comes from "listbreaks".
|
|
||||||
|
|
||||||
- Watches
|
|
||||||
|
|
||||||
A watch is an expression that gets evaluated and printed before
|
|
||||||
every prompt. This is useful for e.g. tracking the contents of a
|
|
||||||
memory location while stepping through code that modifies it.
|
|
||||||
|
|
||||||
You can set up to 10 watches (in future the number will be unlimited).
|
|
||||||
Since the expression isn't evaluated until it's used, you can include
|
|
||||||
registers: "watch *y" will show you the contents of the location
|
|
||||||
pointed to by the Y register, even if the Y register changes.
|
|
||||||
|
|
||||||
The watches are numbered. The numbers are printed along with the
|
|
||||||
watches, so you can tell which is which. To delete a watch use the
|
|
||||||
"delwatch" command with the watch number (1 to whatever). You can
|
|
||||||
also delete them all with the "clearwatches" command.
|
|
||||||
|
|
||||||
Note that there's no real point in watching a label or CPU register
|
|
||||||
without dereferencing it: Labels are constants, and CPU registers
|
|
||||||
are already visible in the prompt status.
|
|
||||||
|
|
||||||
- Traps
|
|
||||||
|
|
||||||
A trap is similar to a breakpoint, except that it catches
|
|
||||||
accesses to a memory address, rather than specific location in the
|
|
||||||
program. They're useful for finding code that modifies TIA registers
|
|
||||||
or memory.
|
|
||||||
|
|
||||||
An example: you are debugging a game, and you want to stop the
|
|
||||||
emulation and enter the debugger whenever RESP0 is strobed. You'd use
|
|
||||||
the command "trap RESP0" to set the trap, then exit the debugger. The
|
|
||||||
emulator will run until the next time RESP0 is accessed (either read
|
|
||||||
or write). Once the trap is hit, you can examine the TIA state to
|
|
||||||
see what the actual player 0 position is, in color clocks (or you
|
|
||||||
can in the future when we implement that feature in the TIA dump!)
|
|
||||||
|
|
||||||
Unlike breakpoints, traps stop the emulation *after* the instruction
|
|
||||||
that triggered the trap. The reason for this is simple: until the
|
|
||||||
instruction is executed, the emulator can't know it's going to hit
|
|
||||||
a trap. After the trap is hit, the instruction is done executing,
|
|
||||||
and whatever effects it may have had on e.g. the TIA state have
|
|
||||||
already happened... so we don't have a way to run the emulated CPU
|
|
||||||
in reverse.
|
|
||||||
|
|
||||||
Traps come in two varieties: read access traps and write access traps.
|
|
||||||
It is possible to set both types of trap on the same address (that's
|
|
||||||
what the plain "trap" command does). To set a read or write only trap,
|
|
||||||
use "trapread" or "trapwrite". To remove a trap, you just attempt
|
|
||||||
to set it again: the commands actually toggle the trap on & off. You
|
|
||||||
can also get rid of all traps at once with the "cleartraps" command.
|
|
||||||
|
|
||||||
Use "listtraps" to see all enabled traps.
|
|
||||||
|
|
||||||
- Prompt commands:
|
|
||||||
|
|
||||||
a - Set Accumulator to value xx
|
|
||||||
bank - Show # of banks (with no args), Switch to bank (with
|
|
||||||
1 arg)
|
|
||||||
base - Set default base (hex, dec, or bin)
|
|
||||||
break - Set/clear breakpoint at address (default=pc)
|
|
||||||
c - Carry Flag: set (to 0 or 1), or toggle (no arg)
|
|
||||||
clearbreaks - Clear all breakpoints
|
|
||||||
cleartraps - Clear all traps
|
|
||||||
clearwatches - Clear all watches
|
|
||||||
colortest - Color Test
|
|
||||||
d - Decimal Flag: set (to 0 or 1), or toggle (no arg)
|
|
||||||
define - Define label
|
|
||||||
delwatch - Delete watch
|
|
||||||
disasm - Disassemble from address (default=pc)
|
|
||||||
dump - Dump 128 bytes of memory at address
|
|
||||||
frame - Advance emulation by xx frames (default=1)
|
|
||||||
help - This cruft
|
|
||||||
listbreaks - List breakpoints
|
|
||||||
listtraps - List traps
|
|
||||||
listwatches - List watches
|
|
||||||
loadstate - Load emulator state (0-9)
|
|
||||||
loadsym - Load symbol file
|
|
||||||
n - Negative Flag: set (to 0 or 1), or toggle (no arg)
|
|
||||||
pc - Set Program Counter to address
|
|
||||||
print - Evaluate and print expression in hex/dec/binary
|
|
||||||
ram - Show RAM contents (no args), or set RAM address xx to
|
|
||||||
value yy
|
|
||||||
reload - Reload ROM and symbol file
|
|
||||||
reset - Reset 6507 to init vector (does not reset TIA, RIOT)
|
|
||||||
riot - Show RIOT timer/input status
|
|
||||||
rom - Change ROM contents
|
|
||||||
run - Exit debugger, return to emulator
|
|
||||||
s - Set Stack Pointer to value xx
|
|
||||||
saveses - Save console session to file
|
|
||||||
savestate - Save emulator state (valid args 0-9)
|
|
||||||
savesym - Save symbols to file
|
|
||||||
step - Single step CPU (optionally, with count)
|
|
||||||
tia - Show TIA state
|
|
||||||
trace - Single step CPU (optionally, with count), subroutines
|
|
||||||
count as one instruction
|
|
||||||
trap - Trap read and write accesses to address
|
|
||||||
trapread - Trap read accesses to address
|
|
||||||
trapwrite - Trap write accesses to address
|
|
||||||
undef - Undefine label (if defined)
|
|
||||||
v - Overflow Flag: set (to 0 or 1), or toggle (no arg)
|
|
||||||
watch - Print contents of address before every prompt
|
|
||||||
x - Set X Register to value xx
|
|
||||||
y - Set Y Register to value xx
|
|
||||||
z - Zero Flag: set (to 0 or 1), or toggle (no arg)
|
|
||||||
|
|
||||||
This list may be outdated: see the output of the "help" command
|
|
||||||
for the current list. Commands marked with a * are unimplemented.
|
|
||||||
Commands marked with a + are partially implemented. Most commands can
|
|
||||||
be abbreviated just by typing a partial command: "st" for "step", or
|
|
||||||
"f" for "frame". Where there are conflicts, generally the shortest
|
|
||||||
name is chosen (so "tra" is "trap", not "trapread").
|
|
||||||
|
|
||||||
|
|
||||||
- CPU tab
|
|
||||||
|
|
||||||
(TODO: document this, when it's close enough to finished)
|
|
||||||
|
|
||||||
|
|
||||||
- RAM tab
|
|
||||||
|
|
||||||
This is a spreadsheet-like GUI for inspecting and changing the contents
|
|
||||||
of the 2600's RAM. All 128 bytes of RAM are visible on the screen at
|
|
||||||
once. You can navigate with either the mouse or the keyboard arrow keys.
|
|
||||||
To change a RAM location, either double-click on it or press Enter while
|
|
||||||
it's highlighted. Enter the new value (hex only for now, sorry), then
|
|
||||||
press Enter to make the change. If you change your mind, press Escape
|
|
||||||
and the original value will be restored.
|
|
||||||
|
|
||||||
On the right there are also some buttons to do various things to the
|
|
||||||
currently-selected memory location. The buttons are:
|
|
||||||
|
|
||||||
0 - Set the current location to zero.
|
|
||||||
Inv - Invert the current location (toggle all its bits).
|
|
||||||
Neg - Negate the current location (twos' complement negative).
|
|
||||||
++ - Increment the current location
|
|
||||||
-- - Decrement the current location
|
|
||||||
<< - Shift the current location left. Any bits shifted off the left
|
|
||||||
are lost (they will NOT end up in the Carry flag).
|
|
||||||
>> - Shift the current location right, like << above.
|
|
||||||
|
|
||||||
- Cheat tab
|
|
||||||
|
|
||||||
This tab lets you search memory for values such as lives or remaining
|
|
||||||
energy, but it's also very useful when debugging to determine which
|
|
||||||
memory location holds which quantity.
|
|
||||||
|
|
||||||
Currently, input must be in decimal format, and search results will be
|
|
||||||
shown in decimal (with hex addresses).
|
|
||||||
|
|
||||||
Enter a byte value into the search editbox (0-255) and click 'Search'.
|
|
||||||
All matching address/value pairs will be shown in the listbox to the
|
|
||||||
right. The values in the listbox may be changed using the normal
|
|
||||||
editing operations, and the RAM will be immediately updated. If
|
|
||||||
'Search' is clicked and the inputbox is empty, all RAM locations
|
|
||||||
are returned.
|
|
||||||
|
|
||||||
The 'Compare' button is used to compare the given value using all
|
|
||||||
addresses in the listbox. This may be an absolute number (such as 2),
|
|
||||||
or a comparitive number (such as -1). Using a '+' or '-' operator
|
|
||||||
means 'search addresses for values that have changed by that amount'.
|
|
||||||
|
|
||||||
The following is an example of inspecting all addresses that have
|
|
||||||
decreased by 1:
|
|
||||||
|
|
||||||
Click 'Search' with an empty inputbox. All 128 address/values are
|
|
||||||
returned
|
|
||||||
|
|
||||||
Exit debugger mode and lose a life, let your energy decrease, or
|
|
||||||
do whatever it is you're trying to debug
|
|
||||||
|
|
||||||
Enter debugger mode again, and enter a '-1' in the inputbox
|
|
||||||
|
|
||||||
Click the 'Compare' button, which compares all addresses in the
|
|
||||||
listbox with RAM, and finds all values that have decreased by 1
|
|
||||||
(as compared to their value in the listbox).
|
|
||||||
|
|
||||||
Repeatedly following these steps may help to narrow number of
|
|
||||||
addresses under consideration, and eventually you'll find the
|
|
||||||
memory address you're looking for
|
|
||||||
|
|
||||||
The 'Restart' button restarts the whole procedure (ie, clear the
|
|
||||||
input and listboxes, and allows another search.
|
|
||||||
|
|
||||||
(TODO: need a way to name and save/load the cheats)
|
|
||||||
|
|
||||||
- TIA tab (TODO)
|
|
||||||
|
|
||||||
- ROM tab (TODO)
|
|
||||||
|
|
||||||
Global Buttons:
|
|
||||||
|
|
||||||
There are also buttons on the right that always show up no matter which
|
|
||||||
tab you're looking at. These are always active. They are: Step, Trace,
|
|
||||||
Frame+1, and Exit.
|
|
||||||
|
|
||||||
When you use these buttons, the prompt doesn't change. This means the
|
|
||||||
status lines with the registers and disassembly will be "stale". You
|
|
||||||
can update them just by pressing Enter in the prompt.
|
|
||||||
|
|
||||||
You can also use the Step, Trace and Frame+1 buttons from anywhere in
|
|
||||||
the GUI via the keyboard, with Alt-S, Alt-T and Alt-F.
|
|
||||||
|
|
||||||
|
|
||||||
Tutorial: How to hack a ROM
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
Here is a step-by-step guide that shows you how to use the debugger to
|
|
||||||
actually do something useful. No experience with debuggers is necessary,
|
|
||||||
but it helps to know at least a little about 6502 programming.
|
|
||||||
|
|
||||||
Step 1: get the Atari Battlezone ROM image. Make sure you've got the
|
|
||||||
regular NTSC version. Load it up in Stella and press TAB to get to
|
|
||||||
the main menu. From there, click on "Game Information". For "Name", it
|
|
||||||
should say "Battlezone (1983) (Atari) [!]" and for MD5Sum it should say
|
|
||||||
"41f252a66c6301f1e8ab3612c19bc5d4". The rest of this tutorial assumes
|
|
||||||
you're using this version of the ROM; it may or may not work with the
|
|
||||||
PAL version, or with any of the various "hacked" versions floating around
|
|
||||||
on the 'net.
|
|
||||||
|
|
||||||
Step 2: Start the game. You begin the game with 5 lives (count the tank
|
|
||||||
symbols at the bottom of the screen).
|
|
||||||
|
|
||||||
Step 3: Enter the debugger by pressing the ` (backquote) key. Don't get
|
|
||||||
killed before you do this, though. You should still have all 5 lives.
|
|
||||||
|
|
||||||
Step 4: Go to the Cheat tab (click on Cheat). The Cheat tab will allow you
|
|
||||||
to search RAM for values such as the number of remaining lives.
|
|
||||||
|
|
||||||
Step 5: In the Cheat tab, enter "5" in the "Enter a value" box and click
|
|
||||||
on Search. This searches RAM for your value and displays the results in
|
|
||||||
the Address/Value list to the right. You should see two results: "00a5:
|
|
||||||
05" and "00ba: 05". These are the only two addresses that currently have
|
|
||||||
the value 5, so they're the most likely candidates for "number of lives"
|
|
||||||
counter. (However, some games might actually store one less than the real
|
|
||||||
number of lives, or one more, so you might have to experiment a bit.
|
|
||||||
Since this is a "rigged demo", I already know Battlezone stores the
|
|
||||||
actual number of lives. Most games do, actually).
|
|
||||||
|
|
||||||
Step 6: Exit the debugger by pressing ` (backquote) again. The game will
|
|
||||||
pick up where you left off.
|
|
||||||
|
|
||||||
Step 7: Get killed! Ram an enemy tank, or let him shoot you. Wait for
|
|
||||||
the explosion to finish. You will now have 4 lives.
|
|
||||||
|
|
||||||
Step 8: Enter the debugger again. The Cheat tab will still be showing.
|
|
||||||
In the "Enter a value" box, delete the 5 you entered earlier, and replace
|
|
||||||
it with a 4. Click "Compare". Now the Address/Value list should only
|
|
||||||
show one result: "00ba: 04". What we did was search within our previous
|
|
||||||
results (the ones that were 5 before) for the new value 4. Address $00ba
|
|
||||||
used to have the value 5, but now it has 4. This means that Battlezone
|
|
||||||
(almost certainly) stores the current number of lives at address $00ba.
|
|
||||||
|
|
||||||
Step 9: Test your theory. Go to the RAM tab and change address $ba to
|
|
||||||
some high number like $ff (you could use the Prompt instead: enter "ram
|
|
||||||
$ba $ff"). Exit the debugger again. You should now see lots of lives
|
|
||||||
at the bottom of the screen (of course, there isn't room to display $ff
|
|
||||||
(255) of them!)... play the game, get killed a few times, notice that
|
|
||||||
you have lots of lives.
|
|
||||||
|
|
||||||
Step 10: Now it's time to decide what sort of "ROM hack" we want to
|
|
||||||
accomplish. We've found the "lives" counter for the game, so we can
|
|
||||||
either have the game start with lots of lives, or change the game
|
|
||||||
code so we can't get killed (AKA immortality), or change the code
|
|
||||||
so we always have the same number of lives (so we never run out, AKA
|
|
||||||
infinite lives). Let's go for infinite lives: it's a little harder than
|
|
||||||
just starting with lots of lives, but not as difficult as immortality
|
|
||||||
(for that, we have to disable the collision checking code, which means
|
|
||||||
we have to find and understand it first!)
|
|
||||||
|
|
||||||
Step 11: Set a Write Trap on the lives counter address: "trapwrite $ba"
|
|
||||||
in the Prompt. Exit the debugger and play until you get killed. When
|
|
||||||
you die, the trap will cause the emulator to enter the debugger with the
|
|
||||||
Program Counter pointing to the instruction *after* the one that wrote
|
|
||||||
to location $ba.
|
|
||||||
|
|
||||||
Step 12: Once in the debugger, press Enter to refresh your prompt. The PC
|
|
||||||
should be at address $f238, instruction "LDA $e1". You want to disassemble
|
|
||||||
the ROM starting a few addresses before this to find the instruction
|
|
||||||
that actually caused the write trap, so enter the command "disasm pc-5"
|
|
||||||
(you may need to press Shift-PageUp afterwards to see the beginning of
|
|
||||||
the disassembly). Take a look at the first few instructions. Do you see
|
|
||||||
the one that affects the lives counter? That's right, it's the "DEC $ba"
|
|
||||||
at location $f236.
|
|
||||||
|
|
||||||
Step 13: Let's stop the DEC $ba from happening. We can't just delete the
|
|
||||||
instruction (it would mess up the addressing of everything afterwards,
|
|
||||||
if it were even possible), but we can replace it with some other
|
|
||||||
instruction(s).
|
|
||||||
|
|
||||||
Since we just want to get rid of the instruction, we can replace it with
|
|
||||||
NOP (no operation). From looking at the disassembly, you can see that
|
|
||||||
"DEC $ba" is a 2-byte long instruction, so we will need two one-byte
|
|
||||||
NOP instructions to replace it. From reading the prompt help (the "help"
|
|
||||||
command), you can see that the "rom" command is what we use to patch ROM.
|
|
||||||
|
|
||||||
Unfortunately, Stella doesn't contain an assembler, so we can't just
|
|
||||||
type NOP to put a NOP instruction in the code. We'll have to use the
|
|
||||||
hex opcode instead.
|
|
||||||
|
|
||||||
Now crack open your 6502 reference manual and look up the NOP
|
|
||||||
instruction's opcode... OK, OK, I'll just tell you what it is: it's $EA
|
|
||||||
(234 decimal). We need two of them, starting at address $f236, so our
|
|
||||||
prompt command looks like:
|
|
||||||
|
|
||||||
rom $f236 $ea $ea
|
|
||||||
|
|
||||||
The debugger should respond with "changed 02 locations". If you run
|
|
||||||
"disasm pc-5" again, you should see the two NOPs at $f236 and $f237.
|
|
||||||
|
|
||||||
Step 14: Test your patch. First, set location $ba to some number of
|
|
||||||
lives that can be displayed on the screen ("poke $ba 3" will do). Now
|
|
||||||
exit the debugger and play the game. You should see 3 lives on the screen.
|
|
||||||
|
|
||||||
Step 15: The crucial test: get killed again! After the explosion, you
|
|
||||||
will *still* see 3 lives: Success! We've hacked Battlezone to give us
|
|
||||||
infinite lives.
|
|
||||||
|
|
||||||
Step 16: Save your work. In the prompt: "saverom bzhack.bin". You now
|
|
||||||
have your very own infinite-lives version of Battlezone. The file will
|
|
||||||
be saved in the current directory (NOT your ROM directory), so you might
|
|
||||||
want to move it to your ROM directory if it isn't the current directory.
|
|
||||||
|
|
||||||
Step 17: Test the new ROM: exit Stella, and re-run it. Open your ROM
|
|
||||||
(or give its name on the command line) and play the game. You can play
|
|
||||||
forever! It worked.
|
|
||||||
|
|
||||||
Now, try the same techniques on some other ROM image (try Pac-Man). Some
|
|
||||||
games store (lives+1) or (lives-1) instead of the actual number,
|
|
||||||
so try searching for those if you can't seem to make it work. Also,
|
|
||||||
some cartridge types include their own RAM. The debugger doesn't (yet)
|
|
||||||
know how to access on-cartridge RAM, so you'll have to use the "bank" and
|
|
||||||
"ram" commands to manually search the address space for the value you're
|
|
||||||
looking for (future versions of the debugger will be smarter about this).
|
|
||||||
|
|
||||||
If you successfully patch a ROM in the debugger, but the saved version
|
|
||||||
won't work, or looks funny, you might need to add an entry to the
|
|
||||||
stella.pro file, to tell Stella what bankswitch and/or TV type to use.
|
|
||||||
That's outside the scope of this tutorial :)
|
|
||||||
|
|
||||||
Of course, the debugger is useful for a lot more than cheating and
|
|
||||||
hacking ROMs. Remember, with great power comes great responsibility,
|
|
||||||
so you have no excuse to avoid writing that game you've been thinking
|
|
||||||
about for so long now :)
|
|
|
@ -0,0 +1,760 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Stella Debugger</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Stella Integrated Debugger (a work in progress)</h1>
|
||||||
|
|
||||||
|
<p>The debugger in Stella may never be complete, as we're constantly
|
||||||
|
adding new features requested by homebrew developers. However, even in its
|
||||||
|
current form it's still quite powerful, and is able to boast at least one
|
||||||
|
feature that no other 2600 debugger has; it's <b>completely</b> cross-platform.</p>
|
||||||
|
|
||||||
|
<h2>Here's a list of what the debugger can do so far:</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Display registers and memory</li>
|
||||||
|
<li>Dump state of TIA and RIOT, with things like joystick directions and
|
||||||
|
NUSIZx decoded into English (more-or-less).</li>
|
||||||
|
<li>Change registers/memory, including toggles for flags in P register</li>
|
||||||
|
<li>Single step/trace</li>
|
||||||
|
<li>Breakpoints - break running program and enter debugger when the
|
||||||
|
Program Counter hits a predefined address. You can set as many
|
||||||
|
breakpoints as you want.</li>
|
||||||
|
<li>Conditional breakpoints - Break running program when some arbitrary
|
||||||
|
condition is true (e.g. "breakif {a == $7f && c}" will break when the
|
||||||
|
Accumulator value is $7f and the Carry flag is true, no matter where
|
||||||
|
in the program this happens). Unlike the cond breaks in PCAE, Stella's
|
||||||
|
are *fast*: the emulation will run at full speed unless you use lots
|
||||||
|
of breakif's at the same time, or have a slow CPU.</li>
|
||||||
|
<li>Watches - View contents of a location/register before every
|
||||||
|
debugger prompt.</li>
|
||||||
|
<li>Traps - Like breakpoints, but break on read/write/any access to
|
||||||
|
*any* memory location.</li>
|
||||||
|
<li>Frame advance (automatic breakpoint at beginning of next frame)
|
||||||
|
You can advance multiple frames with one command.</li>
|
||||||
|
<li>Disassembly</li>
|
||||||
|
<li>Support for DASM symbol files (created with DASM's -s option),
|
||||||
|
including automatically loading symbol files if they're named
|
||||||
|
romname.sym</li>
|
||||||
|
<li>Built-in VCS.H symbols, if no symbol file is loaded</li>
|
||||||
|
<li>Symbolic names in disassembly</li>
|
||||||
|
<li>Symbolic names accepted as input</li>
|
||||||
|
<li>Tab completion for commands and symbol names</li>
|
||||||
|
<li>Graphical editor for RIOT RAM. Acts a lot like a spreadsheet.
|
||||||
|
Input in hex, with displays for label/decimal/binary for
|
||||||
|
currently-selected location.</li>
|
||||||
|
<li>GUI CPU state window</li>
|
||||||
|
<!--Cheat system (similar to MAME) (still needs a way to save/load cheats)-->
|
||||||
|
<li>Reset the 6502</li>
|
||||||
|
<li>Start emulator in debugger (via command-line option "-debug")</li>
|
||||||
|
<li>Save CLI session to a text file.</li>
|
||||||
|
<li>Supports hex, decimal, and binary input and output almost everywhere.
|
||||||
|
(disassembly is still hex)</li>
|
||||||
|
<li>Support for bank switching. You can see how many banks a cart has,
|
||||||
|
and switch banks. There's still more to be done here though.</li>
|
||||||
|
<li>Registers/memory that get changed by the CPU during debugging are
|
||||||
|
highlighted when they're displayed.<li>
|
||||||
|
<li>Scanline advance (like frame advance, break at beginning
|
||||||
|
of next scanline).</li>
|
||||||
|
<li>TIA display is updated during step/trace, so we can see our
|
||||||
|
scanlines being drawn as it happens. This isn't 100% perfect: unlike
|
||||||
|
a real TIA, the one in Stella only updates when it's written to.</li>
|
||||||
|
<li>Graphical TIA tab, with register names and GUI buttons for
|
||||||
|
various bits (e.g. click ENAM0 to turn it on).</li>
|
||||||
|
<li>GUI Disassembly window, scrollable, with checkboxes for breakpoints.</li>
|
||||||
|
<li>Script (batch) file support, including auto-running a script file
|
||||||
|
named after the ROM image.</li>
|
||||||
|
<li>Saving the current debugger state to a script file (including
|
||||||
|
breakpoints, traps, etc).</li>
|
||||||
|
<li>Built-in functions for use with "breakif", to support common conditions
|
||||||
|
(such as breaking when the user presses Game Select...)</li>
|
||||||
|
<li>Patching ROM in-place.</li>
|
||||||
|
<li>Save patched ROM ("saverom filename.bin").</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Future planned features (post 2.0):</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>GUI for cheat codes (Cheetah and normal codes).</li>
|
||||||
|
<li>Perhaps 2 panes in the disassembly window (so you can see 2 parts of the
|
||||||
|
code at once).</li>
|
||||||
|
<li>Add bookmark support to disassembly window.</li>
|
||||||
|
<li>Bankswitch support in the debugger for the few remaining cart types
|
||||||
|
that aren't supported.</li>
|
||||||
|
<li>Patch ROM support for a few cart types doesn't work. Must fix.</li>
|
||||||
|
<li>Some way to control joystick/etc. input from within the debugger.</li>
|
||||||
|
<li>Source-level debugging: if a DASM .lst file is available, we'll show
|
||||||
|
the listing in the ROM tab instead of a disassembly. This is already
|
||||||
|
available in a very crude form ("loadlist" and "list" commands).</li>
|
||||||
|
<li>More "special variables" for the expression parser. Currently, you can
|
||||||
|
use all the CPU registers and flags in expressions (e.g. "print a+1" does
|
||||||
|
what you expect), and the pseudo-variables "_scan" and "_bank" (which
|
||||||
|
evaluate the the current scanline and bank number). Need to add more TIA,
|
||||||
|
RIOT registers too. Also, more functions for the builtin function lib.</li>
|
||||||
|
<li>Possibly a mini-assembler</li>
|
||||||
|
<li>Support for extra RAM in Supercharger and other cart types.</li>
|
||||||
|
<li>Possibly support for recording and playing back input files, like
|
||||||
|
MAME. This isn't a debugger feature per se, but it'll make it easier
|
||||||
|
to reliably trigger a bug so you can debug it.</li>
|
||||||
|
<li>Graphics ROM view, so you can see your sprite data (it might still
|
||||||
|
be upside-down though :)</li>
|
||||||
|
<li>Various new GUI enhancements</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>How to use the debugger</h2>
|
||||||
|
|
||||||
|
<p>Pressing ` (aka backtick, backquote, grave accent) toggles the debugger on
|
||||||
|
& off. When you exit the debugger, the emulation resumes at the current
|
||||||
|
program counter, and continues until either a breakpoint/trap is hit,
|
||||||
|
or the ` key is pressed again. Pressing Ctrl-Tab cycles between tabs
|
||||||
|
from left to right, and Shift-Ctrl-Tab cycles from right to left.
|
||||||
|
Pressing Tab cycles between widgets in the current tab.</p>
|
||||||
|
|
||||||
|
<p>You can also enter the debugger by giving a breakpoint on the command line:
|
||||||
|
<pre>
|
||||||
|
; will enter the debugger the first time the instruction at "kernel" runs
|
||||||
|
stella -break kernel mygame.bin
|
||||||
|
|
||||||
|
; $fffc is the 6502/6507 init vector. This command will break and enter the
|
||||||
|
; debugger before the first 6507 instruction runs, so you can debug the
|
||||||
|
; startup code:
|
||||||
|
stella -break "*($fffc)" mygame.bin
|
||||||
|
</pre>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Prompt tab</h2>
|
||||||
|
|
||||||
|
<p>This is a command-line interface, similar to the DOS DEBUG command
|
||||||
|
or Supermon for the C=64. It shows you the current CPU state, including
|
||||||
|
the disassembly of the instruction pointed to by the Program Counter.
|
||||||
|
This instruction is the NEXT one that will execute, NOT the one that
|
||||||
|
just executed!</p>
|
||||||
|
|
||||||
|
<p>Editing keys work about like you'd expect them to: Home, End, Delete,
|
||||||
|
arrows, etc. To scroll with the keyboard, use Shift-PageUp and
|
||||||
|
Shift-PageDown or Shift-Up and Shift-Down arrow keys. You can also
|
||||||
|
scroll with the mouse. Copy and paste is not (yet?) supported.</p>
|
||||||
|
|
||||||
|
<p>To see the available commands, enter "help" or "?". Most commands can
|
||||||
|
be abbreviated: instead of "clearbreaks", you can type "clear" or
|
||||||
|
even just "cl". However, "c" by itself is the Toggle Carry command.</p>
|
||||||
|
|
||||||
|
<p>Bash-style tab completion is supported for commands and labels (see below)</p>
|
||||||
|
|
||||||
|
<p>For now, there are some functions that only exist in the prompt. We
|
||||||
|
intend to add GUI equivalents for all (or almost all?) of the prompt
|
||||||
|
commands by the time we release Stella 2.0. People who like command
|
||||||
|
prompts will be able to use the prompt, but people who hate them will
|
||||||
|
have a fully functional debugger without typing (or without typing
|
||||||
|
much, anyway).</p>
|
||||||
|
|
||||||
|
<h4>Status</h4>
|
||||||
|
|
||||||
|
<p>Before each prompt, you'll see a dump of the current processor
|
||||||
|
status, plus any watches you've set (see section on watches
|
||||||
|
below), plus a disassembly of the instruction at the current
|
||||||
|
Program Counter. This is the next instruction that will execute;
|
||||||
|
it hasn't been executed yet.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
PC=f000 A=01 X=02 Y=03 S=ff P=21/nv-bdizC Cycle 12345
|
||||||
|
$f000 a2 ff LDX #ff ; 2
|
||||||
|
>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>This is telling us a lot of information:
|
||||||
|
<pre>
|
||||||
|
- PC=f000 A=01 X=02 Y=03 S=ff
|
||||||
|
The Program Counter, Accumulator, X, Y, and Stack Pointer registers.
|
||||||
|
|
||||||
|
- P=21/nv-bdizC
|
||||||
|
The Processor Status register. The "21" is the hex value of the
|
||||||
|
register, and the "nv-bdizC" shows us the individual flags. Flags
|
||||||
|
with capital letters are set, and lowercase means clear. In this
|
||||||
|
example, only the Carry bit is set.
|
||||||
|
|
||||||
|
- Cycle 12345
|
||||||
|
This counter gets reset at the beginning of each frame, when
|
||||||
|
VSYNC is strobed. In this example, we're 12345 (decimal) cycles
|
||||||
|
past the beginning of the frame.
|
||||||
|
|
||||||
|
- $f000 a2 ff LDX #ff ; 2
|
||||||
|
Disassembly of the instruction the PC points to. This is the next
|
||||||
|
instruction that will execute (when we exit the debugger, or via the
|
||||||
|
"step" or "trace" commands). The "a2 ff" is the raw machine code
|
||||||
|
for this instruction. The "; 2" is a cycle count: this instruction
|
||||||
|
will take 2 cycles to execute.
|
||||||
|
|
||||||
|
WARNING: the cycle count in the disassembly does NOT include extra
|
||||||
|
cycles caused by crossing page boundaries. Also, Branch instructions
|
||||||
|
are shown as 2 cycles, as though they're not going to be taken. A
|
||||||
|
branch that's taken adds a cycle, of course.
|
||||||
|
|
||||||
|
The ">" is where your commands will appear as you type them.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h4>Tab completion</h4>
|
||||||
|
|
||||||
|
<p>While entering a command or label, you can type a partial name and
|
||||||
|
press the Tab key to attempt to auto-complete it. If you've ever used
|
||||||
|
"bash", this will be immediately familiar. If not, try it: load up
|
||||||
|
a ROM, go to the debugger, type "print w" (but don't press Enter),
|
||||||
|
then hit Tab. The "w" will change to "WSYNC" (since this is the only
|
||||||
|
built-in label starting with a "w"). If there are multiple possible
|
||||||
|
completions (try with "v" instead of "w"), you'll see a list of them,
|
||||||
|
and your partial name will be completed as far as possible.</p>
|
||||||
|
|
||||||
|
<p>Tab completion works on all labels: built-in, loaded from a symbol file,
|
||||||
|
or set during debugging with the "define" command. However, it does not
|
||||||
|
yet work on functions defined with the "function" command, nor does it
|
||||||
|
work on filenames.</p>
|
||||||
|
|
||||||
|
<h4>Expressions</h4>
|
||||||
|
|
||||||
|
<p>Almost every command takes a value: the "a" command takes a
|
||||||
|
byte to stuff into the accumulator, the "break" command
|
||||||
|
takes an address to set/clear a breakpoint at. These values
|
||||||
|
can be as a hex constant ($ff, $1234), or as complex as
|
||||||
|
"the low byte of the 16-bit value located at the address
|
||||||
|
pointed to by the binary number 1010010110100101" (which
|
||||||
|
would be "@<\1010010110100101"). You can also use registers
|
||||||
|
and labels in expressions.</p>
|
||||||
|
|
||||||
|
<p>You can use arithmetic and boolean operators in expressions. The
|
||||||
|
syntax is very C-like. The operators supported are:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
+ - * / (add, subtract, multiply, divide: 2+2 is 4)
|
||||||
|
% (modulus/remainder: 3%2 is 1)
|
||||||
|
& | ^ ~ (bitwise AND, OR, XOR, NOT: 2&3 is 2)
|
||||||
|
&& || ! (logical AND, OR, NOT: 2&&3 is 1, 2||0 is 0)
|
||||||
|
( ) (parentheses for grouping: (2+2)*3 is 12)
|
||||||
|
* @ (byte and word pointer dereference: *$80 is the byte stored
|
||||||
|
at location $80)
|
||||||
|
[ ] (array-style byte pointer dereference: $80[1] is the byte
|
||||||
|
stored at location ($80+1) or $81)
|
||||||
|
< > (prefix versions: low and high byte. <$abcd is $cd)
|
||||||
|
== < > <= >= !=
|
||||||
|
(comparison: equality, less-than, greater-than, less-or-equals,
|
||||||
|
greater-or-equals, not-equals)
|
||||||
|
<< >> (bit shifts, left and right: 1<<1 is 2, 2>>1 is 1)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Division by zero is not an error: it results in zero instead.</p>
|
||||||
|
|
||||||
|
<p>None of the operators change the values of their operands. There
|
||||||
|
are no variable-assignment or increment/decrement operators. This
|
||||||
|
may change in the future, which is why we used "==" for equality
|
||||||
|
instead of just "=".</p>
|
||||||
|
|
||||||
|
<p>The bitwise and logical boolean operators are different in that the
|
||||||
|
bitwise operators operate on all the bits of the operand (just like
|
||||||
|
AND, ORA, EOR in 6502 asm), while the logical operators treat their
|
||||||
|
operands as 0 for false, non-zero for true, and return either 0 or 1.
|
||||||
|
So $1234&$5678 results in $1230, whereas $1234&&$5678 results in 1.
|
||||||
|
This is just like C or C++...</p>
|
||||||
|
|
||||||
|
<h4>Prefixes</h4>
|
||||||
|
|
||||||
|
<p>Like some programming languages, the debugger uses prefixed characters
|
||||||
|
to change the meaning of an expression. The prefixes are:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Dereference prefixes:<br>
|
||||||
|
|
||||||
|
<p>"*"<br>
|
||||||
|
Dereference a byte pointer. "*a" means "the byte at the address that
|
||||||
|
the A register points to". If A is 255 (hex $ff), the result will be
|
||||||
|
the value currently stored in memory location 255. This operator
|
||||||
|
will be very familiar to you if you're a C or C++ programmer. It's
|
||||||
|
equivalent to the PEEK() function in most 8-bit BASICs. Also, the
|
||||||
|
debugger supports array-like byte dereferences: *address can be
|
||||||
|
written as address[0]. *(address+1) can be written as address[1],
|
||||||
|
etc.</p>
|
||||||
|
|
||||||
|
<p>"@"<br>
|
||||||
|
Dereference a pointer to a word. This is just like the "*" byte deref,
|
||||||
|
except it refers to a 16-bit value, occupying 2 locations, in
|
||||||
|
low-byte-first format (standard for the 6507).</p>
|
||||||
|
|
||||||
|
<p>The following are equivalent:</p>
|
||||||
|
<pre>
|
||||||
|
@address
|
||||||
|
*address+$100**(address+1)
|
||||||
|
address[0]+#256*address[1]
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>(TODO: add (indirect),y and (indirect,x) syntax)</p>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>Hi/Lo Byte Prefixes:<br>
|
||||||
|
<p>"<"<br>
|
||||||
|
Take the low byte of a 16-bit value. This has no effect on an 8-bit
|
||||||
|
value: "a" is equal to "<a". However, "<$1234" equals "$34".</p>
|
||||||
|
|
||||||
|
<p>">"<br>
|
||||||
|
Take the high byte of a 16-bit value. For 8-bit values such as
|
||||||
|
the Accumulator, this will always result in zero. For 16-bit values,
|
||||||
|
"<$1234" = "$12".</p>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>Number Base Prefixes:<br>
|
||||||
|
<p>"#"<br>
|
||||||
|
Treat the input as a decimal number.</p>
|
||||||
|
|
||||||
|
<p>"$"<br>
|
||||||
|
Treat the input as a hex number.</p>
|
||||||
|
|
||||||
|
<p>"\"<br>
|
||||||
|
Treat the input as a binary number.</p>
|
||||||
|
|
||||||
|
<p>These only have meaning when they come before a number, not a
|
||||||
|
label or a register. "\1010" means 10 decimal. So do "$0a" and
|
||||||
|
"#10". "a" by itself is always the Accumulator, no matter what
|
||||||
|
the default base is set to.</p>
|
||||||
|
|
||||||
|
<p>If you don't specify any number base prefix, the number is
|
||||||
|
assumed to be in the default base. When you first start Stella,
|
||||||
|
the default base is 16 (hexadecimal). You can change it with the
|
||||||
|
"base" command.</p>
|
||||||
|
|
||||||
|
<p>Remember, you can use arbitrarily complex expressions with any
|
||||||
|
command that takes arguments (except the ones that take filenames,
|
||||||
|
like "loadsym").</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Breakpoints, watches and traps, oh my!</h3>
|
||||||
|
|
||||||
|
<h4>Breakpoints</h4>
|
||||||
|
|
||||||
|
<p>A breakpoint is a "hotspot" in your program that causes the emulator
|
||||||
|
to stop emulating and jump into the debugger. You can set as many
|
||||||
|
breakpoints as you like. The command is "break xx" where xx is any
|
||||||
|
expression. If you've created a symbol file, you can use labels.</p>
|
||||||
|
|
||||||
|
<p>Example: you've got a label called "kernel". To break there,
|
||||||
|
the command is "break kernel". After you've set the breakpoint,
|
||||||
|
exit the debugger ("quit" or click the Exit button). The emulator
|
||||||
|
will run until it gets to the breakpoint, then it will enter the
|
||||||
|
debugger with the Program Counter pointing to the instruction
|
||||||
|
at the breakpoint.</p>
|
||||||
|
|
||||||
|
<p>Breakpoints happen *before* an instruction is executed: the
|
||||||
|
instruction at the breakpoint location will be the "next"
|
||||||
|
instruction.</p>
|
||||||
|
|
||||||
|
<p>To remove a breakpoint, you just run the same command you used to
|
||||||
|
set it. In the example, "break kernel" will remove the breakpoint.
|
||||||
|
The "break" command can be thought of as a *toggle*: it turns the
|
||||||
|
breakpoint on & off, like a light switch.</p>
|
||||||
|
|
||||||
|
<p>You could also use "clearbreaks" to remove all the breakpoints. Also,
|
||||||
|
there is a "listbreaks" command that will list them all.</p>
|
||||||
|
|
||||||
|
<h4>Conditional Breaks</h4>
|
||||||
|
|
||||||
|
<p>A conditional breakpoint causes the emulator to enter the debugger when
|
||||||
|
some arbitrary condition becomes true. "True" means "not zero" here:
|
||||||
|
"2+2" is considered true because it's not zero. "2-2" is false, because
|
||||||
|
it evaluates to zero. This is exactly how things work in C and lots
|
||||||
|
of other languages, but it might take some getting used to if you've
|
||||||
|
never used such a language.</p>
|
||||||
|
|
||||||
|
<p>Suppose you want to enter the debugger when the Game Reset switch is
|
||||||
|
pressed. Looking at the Stella Programmers' Guide, we see that this
|
||||||
|
switch is read at bit 0 of SWCHB. This bit will be 0 if the switch is
|
||||||
|
pressed, or 1 otherwise.</p>
|
||||||
|
|
||||||
|
<p>To have an expression read the contents of an address, we use the
|
||||||
|
dereference operator "*". Since we're looking at SWCHB, we need
|
||||||
|
"*SWCHB".</p>
|
||||||
|
|
||||||
|
<p>We're only wanting to look at bit 0, so let's mask off all the other
|
||||||
|
bits: "*SWCHB&1". The expression now evaluates to bit 0 of SWCHB. We're
|
||||||
|
almost there: this will be 1 (true) if the switch is NOT pressed. We
|
||||||
|
want to break if it IS pressed...</p>
|
||||||
|
|
||||||
|
<p>So we invert the sense of the test with a logical NOT operator (which
|
||||||
|
is the "!" operator): !(*SWCHB&1). The parentheses are necessary as
|
||||||
|
we want to apply the ! to the result of the &, not just the first term
|
||||||
|
(the "*SWCHB").</p>
|
||||||
|
|
||||||
|
<p>"breakif !(*SWCHB&1)" will do the job for us. However, it's an ugly mess
|
||||||
|
of letters, numbers, and punctuation. We can do a little better:</p>
|
||||||
|
|
||||||
|
<p>"breakif { !(*SWCHB & 1 ) }" is a lot more readable, isn't it? If
|
||||||
|
you're going to use readable expressions with spaces in them,
|
||||||
|
enclose the entire expression in curly braces {}.</p>
|
||||||
|
|
||||||
|
<p>There is one annoyance about this complex expression: once we
|
||||||
|
remove the conditional break with "delbreakif" or "clearbreaks",
|
||||||
|
we'd have to retype it (or search backwards with the up-arrow key)
|
||||||
|
if we wanted to use it again.</p>
|
||||||
|
|
||||||
|
<p>We can avoid this by defining the expression as a function, then using
|
||||||
|
"breakif function_name":</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
function gameReset { !(*SWCHB & 1 ) }
|
||||||
|
breakif gameReset
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Now we have a meaningful name for the condition, so we can use it again.
|
||||||
|
Not only that: we can use the function as part of a bigger expression.
|
||||||
|
Suppose we've also defined a gameSelect function that evaluates to true
|
||||||
|
if the Game Select switch is pressed. We want to break when the user
|
||||||
|
presses both Select and Reset:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
breakif { gameReset && gameSelect }
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>If you've defined a lot of complex functions, you probably will
|
||||||
|
want to re-use them in future runs of the debugger. You can save
|
||||||
|
all your functions, breakpoints, conditional breaks, and watches
|
||||||
|
with the "save" command. If you name your saved file the same
|
||||||
|
as the ROM filename, it'll be auto-loaded next time you load the
|
||||||
|
same ROM in Stella. The save file is just a plain text file called
|
||||||
|
"filename.stella", so you can edit it and add new functions, etc.</p>
|
||||||
|
|
||||||
|
<p>Conditional breaks appear in "listbreaks", numbered starting from
|
||||||
|
zero. You can remove a cond. break with "delbreakif number", where
|
||||||
|
the number comes from "listbreaks".</p>
|
||||||
|
|
||||||
|
<h4>Watches</h4>
|
||||||
|
|
||||||
|
<p>A watch is an expression that gets evaluated and printed before
|
||||||
|
every prompt. This is useful for e.g. tracking the contents of a
|
||||||
|
memory location while stepping through code that modifies it.</p>
|
||||||
|
|
||||||
|
<p>You can set up to 10 watches (in future the number will be unlimited).
|
||||||
|
Since the expression isn't evaluated until it's used, you can include
|
||||||
|
registers: "watch *y" will show you the contents of the location
|
||||||
|
pointed to by the Y register, even if the Y register changes.</p>
|
||||||
|
|
||||||
|
<p>The watches are numbered. The numbers are printed along with the
|
||||||
|
watches, so you can tell which is which. To delete a watch use the
|
||||||
|
"delwatch" command with the watch number (1 to whatever). You can
|
||||||
|
also delete them all with the "clearwatches" command.</p>
|
||||||
|
|
||||||
|
<p>Note that there's no real point in watching a label or CPU register
|
||||||
|
without dereferencing it: Labels are constants, and CPU registers
|
||||||
|
are already visible in the prompt status.</p>
|
||||||
|
|
||||||
|
<h4>Traps</h4>
|
||||||
|
|
||||||
|
<p>A trap is similar to a breakpoint, except that it catches
|
||||||
|
accesses to a memory address, rather than specific location in the
|
||||||
|
program. They're useful for finding code that modifies TIA registers
|
||||||
|
or memory.</p>
|
||||||
|
|
||||||
|
<p>An example: you are debugging a game, and you want to stop the
|
||||||
|
emulation and enter the debugger whenever RESP0 is strobed. You'd use
|
||||||
|
the command "trap RESP0" to set the trap, then exit the debugger. The
|
||||||
|
emulator will run until the next time RESP0 is accessed (either read
|
||||||
|
or write). Once the trap is hit, you can examine the TIA state to
|
||||||
|
see what the actual player 0 position is, in color clocks (or you
|
||||||
|
can in the future when we implement that feature in the TIA dump!)</p>
|
||||||
|
|
||||||
|
<p>Unlike breakpoints, traps stop the emulation *after* the instruction
|
||||||
|
that triggered the trap. The reason for this is simple: until the
|
||||||
|
instruction is executed, the emulator can't know it's going to hit
|
||||||
|
a trap. After the trap is hit, the instruction is done executing,
|
||||||
|
and whatever effects it may have had on e.g. the TIA state have
|
||||||
|
already happened... so we don't have a way to run the emulated CPU
|
||||||
|
in reverse.</p>
|
||||||
|
|
||||||
|
<p>Traps come in two varieties: read access traps and write access traps.
|
||||||
|
It is possible to set both types of trap on the same address (that's
|
||||||
|
what the plain "trap" command does). To set a read or write only trap,
|
||||||
|
use "trapread" or "trapwrite". To remove a trap, you just attempt
|
||||||
|
to set it again: the commands actually toggle the trap on & off. You
|
||||||
|
can also get rid of all traps at once with the "cleartraps" command.</p>
|
||||||
|
|
||||||
|
<p>Use "listtraps" to see all enabled traps.</p>
|
||||||
|
|
||||||
|
<h3>Prompt commands:</h3>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
a - Set Accumulator to value xx
|
||||||
|
bank - Show # of banks (with no args), Switch to bank (with
|
||||||
|
1 arg)
|
||||||
|
base - Set default base (hex, dec, or bin)
|
||||||
|
break - Set/clear breakpoint at address (default=pc)
|
||||||
|
c - Carry Flag: set (to 0 or 1), or toggle (no arg)
|
||||||
|
clearbreaks - Clear all breakpoints
|
||||||
|
cleartraps - Clear all traps
|
||||||
|
clearwatches - Clear all watches
|
||||||
|
colortest - Color Test
|
||||||
|
d - Decimal Flag: set (to 0 or 1), or toggle (no arg)
|
||||||
|
define - Define label
|
||||||
|
delwatch - Delete watch
|
||||||
|
disasm - Disassemble from address (default=pc)
|
||||||
|
dump - Dump 128 bytes of memory at address
|
||||||
|
frame - Advance emulation by xx frames (default=1)
|
||||||
|
help - This cruft
|
||||||
|
listbreaks - List breakpoints
|
||||||
|
listtraps - List traps
|
||||||
|
listwatches - List watches
|
||||||
|
loadstate - Load emulator state (0-9)
|
||||||
|
loadsym - Load symbol file
|
||||||
|
n - Negative Flag: set (to 0 or 1), or toggle (no arg)
|
||||||
|
pc - Set Program Counter to address
|
||||||
|
print - Evaluate and print expression in hex/dec/binary
|
||||||
|
ram - Show RAM contents (no args), or set RAM address xx to
|
||||||
|
value yy
|
||||||
|
reload - Reload ROM and symbol file
|
||||||
|
reset - Reset 6507 to init vector (does not reset TIA, RIOT)
|
||||||
|
riot - Show RIOT timer/input status
|
||||||
|
rom - Change ROM contents
|
||||||
|
run - Exit debugger, return to emulator
|
||||||
|
s - Set Stack Pointer to value xx
|
||||||
|
saveses - Save console session to file
|
||||||
|
savestate - Save emulator state (valid args 0-9)
|
||||||
|
savesym - Save symbols to file
|
||||||
|
step - Single step CPU (optionally, with count)
|
||||||
|
tia - Show TIA state
|
||||||
|
trace - Single step CPU (optionally, with count), subroutines
|
||||||
|
count as one instruction
|
||||||
|
trap - Trap read and write accesses to address
|
||||||
|
trapread - Trap read accesses to address
|
||||||
|
trapwrite - Trap write accesses to address
|
||||||
|
undef - Undefine label (if defined)
|
||||||
|
v - Overflow Flag: set (to 0 or 1), or toggle (no arg)
|
||||||
|
watch - Print contents of address before every prompt
|
||||||
|
x - Set X Register to value xx
|
||||||
|
y - Set Y Register to value xx
|
||||||
|
z - Zero Flag: set (to 0 or 1), or toggle (no arg)
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
<p>This list may be outdated: see the output of the "help" command
|
||||||
|
for the current list. Commands marked with a * are unimplemented.
|
||||||
|
Commands marked with a + are partially implemented. Most commands can
|
||||||
|
be abbreviated just by typing a partial command: "st" for "step", or
|
||||||
|
"f" for "frame". Where there are conflicts, generally the shortest
|
||||||
|
name is chosen (so "tra" is "trap", not "trapread").</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>CPU Widget</h2>
|
||||||
|
|
||||||
|
<p>FIXME: document this</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>RAM Widget</h2>
|
||||||
|
|
||||||
|
<p>This is a spreadsheet-like GUI for inspecting and changing the contents
|
||||||
|
of the 2600's RAM. All 128 bytes of RAM are visible on the screen at
|
||||||
|
once. You can navigate with either the mouse or the keyboard arrow keys.
|
||||||
|
To change a RAM location, either double-click on it or press Enter while
|
||||||
|
it's highlighted. Enter the new value (hex only for now, sorry), then
|
||||||
|
press Enter to make the change. If you change your mind, press Escape
|
||||||
|
and the original value will be restored.</p>
|
||||||
|
|
||||||
|
<p>Nearby there are also some buttons to do various things to the
|
||||||
|
currently-selected memory location. The buttons are:</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
0 - Set the current location to zero.
|
||||||
|
Inv - Invert the current location (toggle all its bits).
|
||||||
|
Neg - Negate the current location (twos' complement negative).
|
||||||
|
++ - Increment the current location
|
||||||
|
-- - Decrement the current location
|
||||||
|
<< - Shift the current location left. Any bits shifted off the left
|
||||||
|
are lost (they will NOT end up in the Carry flag).
|
||||||
|
>> - Shift the current location right, like << above.
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>This widget also lets you search memory for values such as lives or remaining
|
||||||
|
energy, but it's also very useful when debugging to determine which
|
||||||
|
memory location holds which quantity.</p>
|
||||||
|
|
||||||
|
<p>To search RAM, click 'Search' and enter a byte value into the search editbox (0-255).
|
||||||
|
All matching values will be highlighted in the RAM widget. If 'Search' is clicked
|
||||||
|
and input is empty, all RAM locations are searched.</p>
|
||||||
|
|
||||||
|
<p>The 'Compare' button is used to compare the given value using all
|
||||||
|
addresses currently highlighted. This may be an absolute number (such as 2),
|
||||||
|
or a comparitive number (such as -1). Using a '+' or '-' operator
|
||||||
|
means 'search addresses for values that have changed by that amount'.</p>
|
||||||
|
|
||||||
|
<p>The following is an example of inspecting all addresses that have
|
||||||
|
decreased by 1:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Click 'Search' with empty input. All 128 address/values are highlighted</li>
|
||||||
|
<li>Exit debugger mode and lose a life, let your energy decrease, or
|
||||||
|
do whatever it is you're trying to debug</li>
|
||||||
|
<li>Enter debugger mode again, click 'Compare' and and enter a '-1' for input.
|
||||||
|
This finds all values that have decreased by 1 (as compared to their current
|
||||||
|
values)</li>
|
||||||
|
<li>Repeatedly following these steps may help to narrow number of
|
||||||
|
addresses under consideration, and eventually you'll find the
|
||||||
|
memory address you're looking for</li>
|
||||||
|
<li>The 'Reset' button restarts the whole procedure (ie, clear the highlighted
|
||||||
|
addresses and allow another search</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>TIA Tab</h2>
|
||||||
|
|
||||||
|
<p>FIXME</p>
|
||||||
|
|
||||||
|
<h2>ROM Widget</h2>
|
||||||
|
|
||||||
|
<p>FIXME</p>
|
||||||
|
|
||||||
|
<h2>Global Buttons</h2>
|
||||||
|
|
||||||
|
<p>There are also buttons on the right that always show up no matter which
|
||||||
|
tab you're looking at. These are always active. They are: Step, Trace,
|
||||||
|
Frame+1, Scan+1 and Exit.</p>
|
||||||
|
|
||||||
|
<p>When you use these buttons, the prompt doesn't change. This means the
|
||||||
|
status lines with the registers and disassembly will be "stale". You
|
||||||
|
can update them just by pressing Enter in the prompt.</p>
|
||||||
|
|
||||||
|
<p>You can also use the Step, Trace, Frame+1 and Scan+1 buttons from anywhere in
|
||||||
|
the GUI via the keyboard, with Alt-S, Alt-T, Alt-F and Alt-L.</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>Tutorial: How to hack a ROM</h2>
|
||||||
|
|
||||||
|
<p>Here is a step-by-step guide that shows you how to use the debugger to
|
||||||
|
actually do something useful. No experience with debuggers is necessary,
|
||||||
|
but it helps to know at least a little about 6502 programming.</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>get the Atari Battlezone ROM image. Make sure you've got the
|
||||||
|
regular NTSC version. Load it up in Stella and press TAB to get to
|
||||||
|
the main menu. From there, click on "Game Information". For "Name", it
|
||||||
|
should say "Battlezone (1983) (Atari) [!]" and for MD5Sum it should say
|
||||||
|
"41f252a66c6301f1e8ab3612c19bc5d4". The rest of this tutorial assumes
|
||||||
|
you're using this version of the ROM; it may or may not work with the
|
||||||
|
PAL version, or with any of the various "hacked" versions floating around
|
||||||
|
on the 'net.</li>
|
||||||
|
|
||||||
|
<li>Start the game. You begin the game with 5 lives (count the tank
|
||||||
|
symbols at the bottom of the screen).</li>
|
||||||
|
|
||||||
|
<li>Enter the debugger by pressing the ` (backquote) key. Don't get
|
||||||
|
killed before you do this, though. You should still have all 5 lives.</li>
|
||||||
|
|
||||||
|
<li>In the RAM Widget, click the "Search" button and enter "5" for input.
|
||||||
|
This searches RAM for your value and highlights all addresses that match
|
||||||
|
the input. You should see two addresses highlighted: "00a5" and "00ba".
|
||||||
|
These are the only two addresses that currently have the value 5, so they're
|
||||||
|
the most likely candidates for "number of lives" counter. (However, some
|
||||||
|
games might actually store one less than the real number of lives, or
|
||||||
|
one more, so you might have to experiment a bit. Since this is a "rigged
|
||||||
|
demo", I already know Battlezone stores the actual number of lives.
|
||||||
|
Most games do, actually).</li>
|
||||||
|
|
||||||
|
<li>Exit the debugger by pressing ` (backquote) again. The game will
|
||||||
|
pick up where you left off.</li>
|
||||||
|
|
||||||
|
<li>Get killed! Ram an enemy tank, or let him shoot you. Wait for
|
||||||
|
the explosion to finish. You will now have 4 lives.</li>
|
||||||
|
|
||||||
|
<li>Enter the debugger again. Click the "Compare" button in RAM widget and enter
|
||||||
|
a value of 4. Now the RAM widget should only show one highlighted address:
|
||||||
|
"00ba". What we did was search within our previous results (the ones that
|
||||||
|
were 5 before) for the new value 4. Address $00ba used to have the value 5,
|
||||||
|
but now it has 4. This means that Battlezone (almost certainly) stores the
|
||||||
|
current number of lives at address $00ba.</li>
|
||||||
|
|
||||||
|
<li>Test your theory. Go to the RAM widget and change address $ba to
|
||||||
|
some high number like $ff (you could use the Prompt instead: enter "ram
|
||||||
|
$ba $ff"). Exit the debugger again. You should now see lots of lives
|
||||||
|
at the bottom of the screen (of course, there isn't room to display $ff
|
||||||
|
(255) of them!)... play the game, get killed a few times, notice that
|
||||||
|
you have lots of lives.</li>
|
||||||
|
|
||||||
|
<li>Now it's time to decide what sort of "ROM hack" we want to
|
||||||
|
accomplish. We've found the "lives" counter for the game, so we can
|
||||||
|
either have the game start with lots of lives, or change the game
|
||||||
|
code so we can't get killed (AKA immortality), or change the code
|
||||||
|
so we always have the same number of lives (so we never run out, AKA
|
||||||
|
infinite lives). Let's go for infinite lives: it's a little harder than
|
||||||
|
just starting with lots of lives, but not as difficult as immortality
|
||||||
|
(for that, we have to disable the collision checking code, which means
|
||||||
|
we have to find and understand it first!)</li>
|
||||||
|
|
||||||
|
<li>Set a Write Trap on the lives counter address: "trapwrite $ba"
|
||||||
|
in the Prompt. Exit the debugger and play until you get killed. When
|
||||||
|
you die, the trap will cause the emulator to enter the debugger with the
|
||||||
|
Program Counter pointing to the instruction *after* the one that wrote
|
||||||
|
to location $ba.</li>
|
||||||
|
|
||||||
|
<li>Once in the debugger, look at the ROM widget. The PC should be at address
|
||||||
|
$f238, instruction "LDA $e1". You want to examine a few instructions before
|
||||||
|
the PC, so scroll up using the mouse or arrow keys. Do you see
|
||||||
|
the one that affects the lives counter? That's right, it's the "DEC $ba"
|
||||||
|
at location $f236.</li>
|
||||||
|
|
||||||
|
<li>Let's stop the DEC $ba from happening. We can't just delete the
|
||||||
|
instruction (it would mess up the addressing of everything afterwards,
|
||||||
|
if it were even possible), but we can replace it with some other
|
||||||
|
instruction(s).
|
||||||
|
|
||||||
|
<p>Since we just want to get rid of the instruction, we can replace it with
|
||||||
|
NOP (no operation). From looking at the disassembly, you can see that
|
||||||
|
"DEC $ba" is a 2-byte long instruction, so we will need two one-byte
|
||||||
|
NOP instructions to replace it. From reading the prompt help (the "help"
|
||||||
|
command), you can see that the "rom" command is what we use to patch ROM.
|
||||||
|
|
||||||
|
<p>Unfortunately, Stella doesn't contain an assembler, so we can't just
|
||||||
|
type NOP to put a NOP instruction in the code. We'll have to use the
|
||||||
|
hex opcode instead.
|
||||||
|
|
||||||
|
<p>Now crack open your 6502 reference manual and look up the NOP
|
||||||
|
instruction's opcode... OK, OK, I'll just tell you what it is: it's $EA
|
||||||
|
(234 decimal). We need two of them, so the bytes to insert will look like:
|
||||||
|
|
||||||
|
<pre> $ea $ea</pre>
|
||||||
|
|
||||||
|
<p>Select the line at address $f236 and enter 'ROM patch' mode. This is done
|
||||||
|
by either double-clicking the line, or pressing enter. Then delete the bytes
|
||||||
|
with backspace key and enter "ea ea". Another way to do this would have been
|
||||||
|
to enter "rom $f236 $ea $ea" in the Prompt widget.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>Test your patch. First, set location $ba to some number of
|
||||||
|
lives that can be displayed on the screen ("poke $ba 3" or enter directly into
|
||||||
|
the RAM widget). Now exit the debugger and play the game. You should see 3
|
||||||
|
lives on the screen.</li>
|
||||||
|
|
||||||
|
<li>The crucial test: get killed again! After the explosion, you
|
||||||
|
will *still* see 3 lives: Success! We've hacked Battlezone to give us
|
||||||
|
infinite lives.</li>
|
||||||
|
|
||||||
|
<li>Save your work. In the prompt: "saverom bzhack.bin". You now
|
||||||
|
have your very own infinite-lives version of Battlezone. The file will
|
||||||
|
be saved in the current directory (NOT your ROM directory), so you might
|
||||||
|
want to move it to your ROM directory if it isn't the current directory.
|
||||||
|
This can also be accomplished by right-clicking on the ROM widget and
|
||||||
|
selected 'Save ROM'.</li>
|
||||||
|
|
||||||
|
<li>Test the new ROM: exit Stella, and re-run it. Open your ROM
|
||||||
|
(or give its name on the command line) and play the game. You can play
|
||||||
|
forever! It worked.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>Now, try the same techniques on some other ROM image (try Pac-Man). Some
|
||||||
|
games store (lives+1) or (lives-1) instead of the actual number,
|
||||||
|
so try searching for those if you can't seem to make it work. Also,
|
||||||
|
some cartridge types include their own RAM. The debugger doesn't (yet)
|
||||||
|
know how to access on-cartridge RAM, so you'll have to use the "bank" and
|
||||||
|
"ram" commands to manually search the address space for the value you're
|
||||||
|
looking for (future versions of the debugger will be smarter about this).</p>
|
||||||
|
|
||||||
|
<p>If you successfully patch a ROM in the debugger, but the saved version
|
||||||
|
won't work, or looks funny, you might need to add an entry to the
|
||||||
|
stella.pro file, to tell Stella what bankswitch and/or TV type to use.
|
||||||
|
That's outside the scope of this tutorial :)</p>
|
||||||
|
|
||||||
|
<p>Of course, the debugger is useful for a lot more than cheating and
|
||||||
|
hacking ROMs. Remember, with great power comes great responsibility,
|
||||||
|
so you have no excuse to avoid writing that game you've been thinking
|
||||||
|
about for so long now :)</p>
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
<br><br><br>
|
<br><br><br>
|
||||||
|
|
||||||
<center><b>February 1999 - (FIXME)February 2005</b></center>
|
<center><b>February 1999 - September 2005</b></center>
|
||||||
<center><b>The Stella Team</b></center>
|
<center><b>The Stella Team</b></center>
|
||||||
<center><b><a href="http://stella.sourceforge.net">Stella Homepage</a></b></center>
|
<center><b><a href="http://stella.sourceforge.net">Stella Homepage</a></b></center>
|
||||||
|
|
||||||
|
@ -230,14 +230,22 @@
|
||||||
(the Windows and Linux frontends) have been discontinued. The OSX
|
(the Windows and Linux frontends) have been discontinued. The OSX
|
||||||
port now uses the launcher as well.</li>
|
port now uses the launcher as well.</li>
|
||||||
|
|
||||||
<li>FIXME - add info about integrated debugger</li>
|
<li>Added an integrated debugger for game developers. This is currently
|
||||||
|
the first version of a debugger in Stella, but it's already quite
|
||||||
|
usable.</li>
|
||||||
|
|
||||||
<li>Further consolidation and integration of SDL. This should lead to
|
<li>Added new sound subsystem, which is much faster and more accurate. Related
|
||||||
faster operation and a more consistent look for all ports.</li>
|
to this, added stereo sound output (used by some homebrew games).
|
||||||
|
|
||||||
<li>Added ZIP support. Stella can now open ROM's compressed in zip
|
<li>Added ZIP support. Stella can now open ROM's compressed in zip
|
||||||
format.</li>
|
format.</li>
|
||||||
|
|
||||||
|
<li>Reworked properties system to use both a system-wide 'stella.pro' and
|
||||||
|
a per-user 'user.pro' properties files. Changes made by the user
|
||||||
|
and stored in 'user.pro' are no longer erased when upgrading Stella.</li>
|
||||||
|
|
||||||
|
<li>Added support for cartridges with 3E bankswitching format.</li>
|
||||||
|
|
||||||
<li>Added <b>Alt/Shift-Cmd z, x, c, v, b, n</b> keys to enable/disable the
|
<li>Added <b>Alt/Shift-Cmd z, x, c, v, b, n</b> keys to enable/disable the
|
||||||
P0, P1, M0, M1, BL, PL bits in the TIA, respectively.</li>
|
P0, P1, M0, M1, BL, PL bits in the TIA, respectively.</li>
|
||||||
|
|
||||||
|
@ -266,15 +274,22 @@
|
||||||
<li>Removed <b>mergeprops</b> commandline argument, since there are now
|
<li>Removed <b>mergeprops</b> commandline argument, since there are now
|
||||||
dedicated keys to do either save or merge game properties.</li>
|
dedicated keys to do either save or merge game properties.</li>
|
||||||
|
|
||||||
<li>Removed <b>grabmouse</b> and <b>hidecursor</b> commandline arguments.
|
<li>Removed <b>hidecursor</b> commandline argument. Stella will now
|
||||||
Stella will now automatically decide when to use these settings.
|
automatically decide when to use this setting.</li>
|
||||||
You can still use <b>Ctrl/Cmd g</b> to grab/ungrab the mouse.</li>
|
|
||||||
|
|
||||||
<li>Fixed framerate when switching between NTSC and PAL modes. Stella
|
<li>Fixed framerate when switching between NTSC and PAL modes. Stella
|
||||||
now uses the correct framerate based on the format of the ROM.</li>
|
now uses the correct framerate based on the format of the ROM,
|
||||||
|
in terms of both video <b>and</b> audio.</li>
|
||||||
|
|
||||||
|
<li>Added 'configure' support to the build process for both Linux and
|
||||||
|
Win32 (using MinGW). Developers can now use the familiar 'configure;
|
||||||
|
make; make install' commands to compile Stella.</li>
|
||||||
|
|
||||||
|
<li>Further consolidation and integration of SDL. This should lead to
|
||||||
|
faster operation and a more consistent look for all ports.</li>
|
||||||
|
|
||||||
<li>Fixed some 64-bit issues. Stella now compiles and runs correctly
|
<li>Fixed some 64-bit issues. Stella now compiles and runs correctly
|
||||||
on AMD64 and PPC64 systems.</li>
|
on AMD64 and PPC64 Linux systems.</li>
|
||||||
|
|
||||||
<li>Updated the Stella manual with pictures of the new integrated GUI.</li>
|
<li>Updated the Stella manual with pictures of the new integrated GUI.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -284,8 +299,8 @@
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>High speed emulation using optimized C++ code</li>
|
<li>High speed emulation using optimized C++ code</li>
|
||||||
<li>Supports high quality sound emulation using Ron Fries' TIA Sound Emulation
|
<li>Supports high quality sound emulation using code derived from Ron Fries'
|
||||||
library</li>
|
TIA Sound Emulation library, including stereo sound support</li>
|
||||||
<li>Emulates the Atari 2600 Joystick Controllers using your computer's keyboard
|
<li>Emulates the Atari 2600 Joystick Controllers using your computer's keyboard
|
||||||
or joysticks</li>
|
or joysticks</li>
|
||||||
<li>Emulates the Atari 2600 Keyboard Controllers using your computer's keyboard</li>
|
<li>Emulates the Atari 2600 Keyboard Controllers using your computer's keyboard</li>
|
||||||
|
@ -349,7 +364,7 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li>Linux Kernel 2.4.x, Linux Kernel 2.6.x is highly recommended</li>
|
<li>Linux Kernel 2.4.x, Linux Kernel 2.6.x is highly recommended</li>
|
||||||
<li>GNU C++ compiler version 2.95 and the make utility are required for compiling
|
<li>GNU C++ compiler version 2.95 and the make utility are required for compiling
|
||||||
the Stella source code; GNU C++ compiler version 3.2.x or later is highly
|
the Stella source code; GNU C++ compiler version 3.2.x/4.x or later is highly
|
||||||
recommended</li>
|
recommended</li>
|
||||||
<li>Pentium class machine required (Stella <b>may</b> compile on other
|
<li>Pentium class machine required (Stella <b>may</b> compile on other
|
||||||
architectures, but it hasn't been extensively tested)</li>
|
architectures, but it hasn't been extensively tested)</li>
|
||||||
|
@ -364,6 +379,8 @@
|
||||||
<li>Mac OSX 10.1 or Above</li>
|
<li>Mac OSX 10.1 or Above</li>
|
||||||
<li>500 MHz G4 PPC processor or above (Stella <b>may</b> work with a G3
|
<li>500 MHz G4 PPC processor or above (Stella <b>may</b> work with a G3
|
||||||
processor, but this is still a work-in-progress)</li>
|
processor, but this is still a work-in-progress)</li>
|
||||||
|
<li>OpenGL capable video card. Software rendering mode is still available,
|
||||||
|
but as of OSX 10.4 is substandard compared to OpenGL.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -402,15 +419,14 @@
|
||||||
<ol>
|
<ol>
|
||||||
<li>Extract files from the distribution:
|
<li>Extract files from the distribution:
|
||||||
<pre> tar zxvf stella-release-src.tar.gz</pre></li>
|
<pre> tar zxvf stella-release-src.tar.gz</pre></li>
|
||||||
<li>Change directories to the stella-<i>release</i>/src/build directory</li>
|
<li>Change directories to the stella-<i>release</i> directory</li>
|
||||||
<li>Edit the <b>makefile</b> to meet your needs</li>
|
|
||||||
|
<li>Configure the build with the following command:
|
||||||
|
<pre> ./configure (--help for list of options)</pre></li>
|
||||||
<li>Build the executable with the following command:
|
<li>Build the executable with the following command:
|
||||||
<pre> make linux (or make linux-gl)</pre></li>
|
<pre> make</pre></li>
|
||||||
<li>Copy the executable to a directory that's in your path:
|
<li>Install the executable with the following command:
|
||||||
<pre> cp stella /usr/local/bin</pre></li>
|
<pre> make install</pre></li>
|
||||||
<li>Copy the supplied stella.pro properties file to the system-wide location:
|
|
||||||
<pre> cp stella.pro /etc</pre> or to your home directory:
|
|
||||||
<pre> mkdir ~/.stella<br> cp stella.pro ~/.stella</pre></li>
|
|
||||||
</ol>
|
</ol>
|
||||||
<li><b>Source RPM</b> (stella-<i>release</i>-1.src.rpm)</li>
|
<li><b>Source RPM</b> (stella-<i>release</i>-1.src.rpm)</li>
|
||||||
<ol>
|
<ol>
|
||||||
|
@ -442,19 +458,11 @@
|
||||||
<li>Extract files from the distribution using <b>Winzip</b>,
|
<li>Extract files from the distribution using <b>Winzip</b>,
|
||||||
<b>Total Commander</b>, or some other archiving program that supports
|
<b>Total Commander</b>, or some other archiving program that supports
|
||||||
gzipped tar files</li>
|
gzipped tar files</li>
|
||||||
<li>If compiling the Stella executable using MinGW:</li>
|
<li>If compiling the Stella executable using MinGW, use the same commands
|
||||||
<ul>
|
as specified under <i>Linux/UNIX - Compressed tarball</i></li>
|
||||||
<li>Change directories to the stella-<i>release</i>/src/build
|
|
||||||
directory</li>
|
|
||||||
<li>Edit the <b>makefile</b> to meet your needs</li>
|
|
||||||
<li>Build the executable with the following command:
|
|
||||||
<pre> make win32 (or make win32-gl)</pre></li>
|
|
||||||
<li>Copy the <b>Stella</b> (commandline executable) and <b>stella.pro</b>
|
|
||||||
files to some directory</li>
|
|
||||||
</ul>
|
|
||||||
<li>If compiling using Visual C++ 7:</li>
|
<li>If compiling using Visual C++ 7:</li>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Open the <b>stella-<i>release</i>/src/win32/Stella_Emulator.sln</b>
|
<li>Open the <b>stella-<i>release</i>/src/win32/Stella.sln</b>
|
||||||
file using Visual C++ 7</li>
|
file using Visual C++ 7</li>
|
||||||
<li>Build the 'Stella' solution</li>
|
<li>Build the 'Stella' solution</li>
|
||||||
<li>Copy the <b>Stella.exe</b> and <b>stella.pro</b> files
|
<li>Copy the <b>Stella.exe</b> and <b>stella.pro</b> files
|
||||||
|
@ -562,8 +570,8 @@
|
||||||
<img src="graphics/rom_browser.png"></p>
|
<img src="graphics/rom_browser.png"></p>
|
||||||
|
|
||||||
<p>Once a ROM directory has been selected, clicking 'Reload' will update the
|
<p>Once a ROM directory has been selected, clicking 'Reload' will update the
|
||||||
ROM listing. You can start emulation by selecting a ROM and pressing 'Enter',
|
ROM listing. You can start emulation by selecting a ROM and pressing 'Enter'
|
||||||
clicking 'Play' or double-clicking a ROM.</p>
|
or clicking 'Play', or double-clicking a ROM.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<h2><b>Command Line</b></h2>
|
<h2><b>Command Line</b></h2>
|
||||||
|
@ -589,12 +597,6 @@
|
||||||
<td>Use SDL software or OpenGL rendering mode.</td>
|
<td>Use SDL software or OpenGL rendering mode.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><pre>-video_driver <windib|directx></pre></td>
|
|
||||||
<td>Use the specified video driver. Windows works best with 'windib'.
|
|
||||||
Currently, only Windows makes use of this argument.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-gl_filter <nearest|linear></pre></td>
|
<td><pre>-gl_filter <nearest|linear></pre></td>
|
||||||
<td>OpenGL mode only. Use GL_NEAREST or GL_LINEAR filtering.
|
<td>OpenGL mode only. Use GL_NEAREST or GL_LINEAR filtering.
|
||||||
|
@ -627,6 +629,11 @@
|
||||||
<td>Play the game in fullscreen mode.</td>
|
<td>Play the game in fullscreen mode.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><pre>-center <0|1></pre></td>
|
||||||
|
<td>Centers game window (if possible).</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-grabmouse <0|1></pre></td>
|
<td><pre>-grabmouse <0|1></pre></td>
|
||||||
<td>Keeps the mouse in the game window.</td>
|
<td>Keeps the mouse in the game window.</td>
|
||||||
|
@ -645,8 +652,13 @@
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-sound <0|1></pre></td>
|
<td><pre>-sound <1|0></pre></td>
|
||||||
<td>Disable or enable sound.</td>
|
<td>Enable or disable sound generation.</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><pre>-channels <1|2></pre></td>
|
||||||
|
<td>Enable mono or stereo sound.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -670,12 +682,6 @@
|
||||||
<td>Shows some game info while Stella is running.</td>
|
<td>Shows some game info while Stella is running.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
|
||||||
<td><pre>-mergeprops <0|1></pre></td>
|
|
||||||
<td>Save the current properties to a separate file in the users' home directory,
|
|
||||||
or merge them into the users' stella.pro file.</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-accurate <0|1></pre></td>
|
<td><pre>-accurate <0|1></pre></td>
|
||||||
<td>Linux only, may be removed in future versions. Use this when
|
<td>Linux only, may be removed in future versions. Use this when
|
||||||
|
@ -723,6 +729,31 @@
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><pre>-debugheight <number></pre></td>
|
||||||
|
<td>Set height of debugger in lines of text (currently not 100% working)</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><pre>-debug</pre></td>
|
||||||
|
<td>Immediately jump to debugger mode when starting Stella.</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><pre>-holdreset</pre></td>
|
||||||
|
<td>Start the emulator with the Game Reset switch held down.</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><pre>-holdselect</pre></td>
|
||||||
|
<td>Start the emulator with the Game Select switch held down.</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td><pre>-holdbutton0</pre></td>
|
||||||
|
<td>Start the emulator with the left joystick button held down.</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre>-pro <props file></pre></td>
|
<td><pre>-pro <props file></pre></td>
|
||||||
<td>Use the given properties file instead of stella.pro.</td>
|
<td>Use the given properties file instead of stella.pro.</td>
|
||||||
|
@ -1483,7 +1514,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>Toggle fullscreen/windowed mode</td>
|
<td>Toggle fullscreen/windowed mode</td>
|
||||||
<td>Alt + Enter</td>
|
<td>Alt + Enter</td>
|
||||||
<td>Shift-Cmd + Enter(FIXME)</td>
|
<td>Cmd + Enter</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1585,7 +1616,9 @@
|
||||||
<p><h1>
|
<p><h1>
|
||||||
<a name="Debugger">10. Integrated Debugger</a></h1>
|
<a name="Debugger">10. Integrated Debugger</a></h1>
|
||||||
<hr>
|
<hr>
|
||||||
FIXME - add info and snapshots for debugger
|
|
||||||
|
<p>Have a look at <a href="debugger.html">this page</a> for integrated debugger
|
||||||
|
documentation.
|
||||||
|
|
||||||
<br><br><br>
|
<br><br><br>
|
||||||
<p><h1>
|
<p><h1>
|
||||||
|
@ -1597,20 +1630,27 @@ FIXME - add info and snapshots for debugger
|
||||||
You must use the included <b>stella.pro</b> file. Otherwise, the emulator
|
You must use the included <b>stella.pro</b> file. Otherwise, the emulator
|
||||||
will try to guess the best settings for the game.</p>
|
will try to guess the best settings for the game.</p>
|
||||||
|
|
||||||
|
<p>As of Stella 2.0, the properties file handling has changed. Stella now uses
|
||||||
|
two properties files; a system-wide <b>stella.pro</b> and a per-user <b>user.pro</b>.
|
||||||
|
The system-wide file will not be modified by Stella, and is used as a default
|
||||||
|
database of properties. The per-user file will contain all properties 'merged' by
|
||||||
|
the user (by pressing Alt-s while a game is running). So this means that when
|
||||||
|
you upgrade Stella and stella.pro, your personal profile settings are preserved.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<h2><b>Linux/Unix</b></h2>
|
<h2><b>Linux/Unix</b></h2>
|
||||||
<p>The Linux and Unix versions of Stella looks for the property file
|
<p>The Linux and Unix versions of Stella looks for the system properties file
|
||||||
in your <i>$HOME/.stella</i> directory. If this file is not found there,
|
in <i>/etc/stella.pro</i> and your personal properties file in
|
||||||
Stella will look in the <i>/etc/</i> directory.
|
<i>$HOME/.stella/user.pro</i>.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<h2><b>Macintosh</b></h2>
|
<h2><b>Macintosh</b></h2>
|
||||||
<p>The Mac version of Stella looks for the property file in the
|
<p>The Mac version of Stella looks for the properties file(s) in the
|
||||||
directory containing the application.</p>
|
directory containing the application.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<h2><b>Windows</b></h2>
|
<h2><b>Windows</b></h2>
|
||||||
<p>The Windows version of Stella looks for the property file in the same directory
|
<p>The Windows version of Stella looks for the properties file(s) in the directory
|
||||||
containing the application. Future versions of Stella for Windows may look in
|
containing the application. Future versions of Stella for Windows may look in
|
||||||
user-specific locations (C:\Documents and Settings\...).</p>
|
user-specific locations (C:\Documents and Settings\...).</p>
|
||||||
|
|
||||||
|
@ -1698,6 +1738,14 @@ FIXME - add info and snapshots for debugger
|
||||||
Stella will probably allow the user to view this information.</td>
|
Stella will probably allow the user to view this information.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td VALIGN="TOP"><i>Cartridge.Sound:</i></td>
|
||||||
|
<td>This property determines if the game should use 1 or 2 channels for
|
||||||
|
sound output. All original Atari 2600 machines supported 1 channel only,
|
||||||
|
but some homebrew games have been written to take advantage of stereo
|
||||||
|
sound. The value of this property must be Mono or Stereo.</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td VALIGN="TOP"><i>Cartridge.Type:</i></td>
|
<td VALIGN="TOP"><i>Cartridge.Type:</i></td>
|
||||||
<td>This property indicates the bank-switching type for the game.
|
<td>This property indicates the bank-switching type for the game.
|
||||||
|
@ -2028,7 +2076,9 @@ FIXME - add info and snapshots for debugger
|
||||||
<td VALIGN="TOP">Brian Watson</td>
|
<td VALIGN="TOP">Brian Watson</td>
|
||||||
<td>Helped with getting the illegal CPU instruction support working with Stella.
|
<td>Helped with getting the illegal CPU instruction support working with Stella.
|
||||||
Brian also submitted a number of other changes, such as debugger support, which
|
Brian also submitted a number of other changes, such as debugger support, which
|
||||||
will be integrated into the 1.5 release of Stella.</td>
|
have been finally integrated into the 2.0 release of Stella. Without
|
||||||
|
a doubt, there would be no debugger support in Stella if not for the
|
||||||
|
tireless work of Brian.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: FrameBufferGL.cxx,v 1.41 2005-09-06 19:42:35 stephena Exp $
|
// $Id: FrameBufferGL.cxx,v 1.42 2005-09-13 18:27:42 stephena Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#ifdef DISPLAY_OPENGL
|
#ifdef DISPLAY_OPENGL
|
||||||
|
@ -254,8 +254,6 @@ void FrameBufferGL::preFrameUpdate()
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void FrameBufferGL::postFrameUpdate()
|
void FrameBufferGL::postFrameUpdate()
|
||||||
{
|
{
|
||||||
// Do the following twice, since OpenGL mode is double-buffered,
|
|
||||||
// and we need the contents placed in both buffers
|
|
||||||
if(theRedrawTIAIndicator || myDirtyFlag)
|
if(theRedrawTIAIndicator || myDirtyFlag)
|
||||||
{
|
{
|
||||||
// Texturemap complete texture to surface so we have free scaling
|
// Texturemap complete texture to surface so we have free scaling
|
||||||
|
@ -272,7 +270,7 @@ void FrameBufferGL::postFrameUpdate()
|
||||||
glTexCoord2f(myTexCoord[0], myTexCoord[3]); glVertex2i(0, h);
|
glTexCoord2f(myTexCoord[0], myTexCoord[3]); glVertex2i(0, h);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
// Now show all changes made to the textures
|
// Now show all changes made to the texture
|
||||||
SDL_GL_SwapBuffers();
|
SDL_GL_SwapBuffers();
|
||||||
|
|
||||||
myDirtyFlag = false;
|
myDirtyFlag = false;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: DebuggerParser.cxx,v 1.76 2005-08-20 18:19:52 urchlay Exp $
|
// $Id: DebuggerParser.cxx,v 1.77 2005-09-13 18:27:42 stephena Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include "bspf.hxx"
|
#include "bspf.hxx"
|
||||||
|
@ -1534,7 +1534,7 @@ void DebuggerParser::executeRom() {
|
||||||
|
|
||||||
// "run"
|
// "run"
|
||||||
void DebuggerParser::executeRun() {
|
void DebuggerParser::executeRun() {
|
||||||
debugger->saveOldState(); // FIXME - why is this here?
|
debugger->saveOldState();
|
||||||
debugger->quit();
|
debugger->quit();
|
||||||
commandResult = "exiting debugger";
|
commandResult = "exiting debugger";
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: ContextMenu.cxx,v 1.1 2005-08-31 19:15:10 stephena Exp $
|
// $Id: ContextMenu.cxx,v 1.2 2005-09-13 18:27:42 stephena Exp $
|
||||||
//
|
//
|
||||||
// Based on code from ScummVM - Scumm Interpreter
|
// Based on code from ScummVM - Scumm Interpreter
|
||||||
// Copyright (C) 2002-2004 The ScummVM project
|
// Copyright (C) 2002-2004 The ScummVM project
|
||||||
|
@ -75,8 +75,15 @@ const string& ContextMenu::getSelectedString() const
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void ContextMenu::handleMouseDown(int x, int y, int button, int clickCount)
|
void ContextMenu::handleMouseDown(int x, int y, int button, int clickCount)
|
||||||
{
|
{
|
||||||
|
// Only do a selection when the left button is in the dialog
|
||||||
if(button == 1)
|
if(button == 1)
|
||||||
|
{
|
||||||
|
x += getAbsX(); y += getAbsY();
|
||||||
|
if(x >= _x && x <= _x+_w && y >= _y && y <= _y+_h)
|
||||||
sendSelection();
|
sendSelection();
|
||||||
|
else
|
||||||
|
parent()->removeDialog();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -105,6 +112,9 @@ void ContextMenu::handleKeyDown(int ascii, int keycode, int modifiers)
|
||||||
{
|
{
|
||||||
switch(keycode)
|
switch(keycode)
|
||||||
{
|
{
|
||||||
|
case 27: // escape
|
||||||
|
parent()->removeDialog();
|
||||||
|
break;
|
||||||
case '\n': // enter/return
|
case '\n': // enter/return
|
||||||
case '\r':
|
case '\r':
|
||||||
sendSelection();
|
sendSelection();
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: RomWidget.cxx,v 1.3 2005-09-07 18:34:52 stephena Exp $
|
// $Id: RomWidget.cxx,v 1.4 2005-09-13 18:27:42 stephena Exp $
|
||||||
//
|
//
|
||||||
// Based on code from ScummVM - Scumm Interpreter
|
// Based on code from ScummVM - Scumm Interpreter
|
||||||
// Copyright (C) 2002-2004 The ScummVM project
|
// Copyright (C) 2002-2004 The ScummVM project
|
||||||
|
@ -64,7 +64,7 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||||
switch(cmd)
|
switch(cmd)
|
||||||
{
|
{
|
||||||
case kListScrolledCmd:
|
case kListScrolledCmd:
|
||||||
incrementalUpdate();
|
incrementalUpdate(data, myRomList->rows());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kListItemChecked:
|
case kListItemChecked:
|
||||||
|
@ -92,21 +92,25 @@ void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void RomWidget::loadConfig()
|
void RomWidget::loadConfig()
|
||||||
{
|
{
|
||||||
|
cerr << " ==> RomWidget::loadConfig()\n";
|
||||||
|
|
||||||
|
Debugger& dbg = instance()->debugger();
|
||||||
|
|
||||||
// Only reload full bank when necessary
|
// Only reload full bank when necessary
|
||||||
// if(myFirstLoad || myCurrentBank != instance()->debugger().getBank())
|
if(myFirstLoad || myCurrentBank != instance()->debugger().getBank())
|
||||||
// FIXME - always do a full reload for now, will optimize later
|
|
||||||
if(true)
|
|
||||||
{
|
{
|
||||||
initialUpdate();
|
initialUpdate();
|
||||||
myFirstLoad = false;
|
myFirstLoad = false;
|
||||||
}
|
}
|
||||||
else // only reload what's in current view
|
else // only reload what's in current view
|
||||||
{
|
{
|
||||||
incrementalUpdate();
|
incrementalUpdate(myRomList->currentPos(), myRomList->rows());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myCurrentBank = dbg.getBank();
|
||||||
|
|
||||||
// Update romlist to point to current PC
|
// Update romlist to point to current PC
|
||||||
int pc = instance()->debugger().cpuDebug().pc();
|
int pc = dbg.cpuDebug().pc();
|
||||||
AddrToLine::iterator iter = myLineList.find(pc);
|
AddrToLine::iterator iter = myLineList.find(pc);
|
||||||
if(iter != myLineList.end())
|
if(iter != myLineList.end())
|
||||||
myRomList->setHighlighted(iter->second);
|
myRomList->setHighlighted(iter->second);
|
||||||
|
@ -117,8 +121,6 @@ void RomWidget::initialUpdate()
|
||||||
{
|
{
|
||||||
Debugger& dbg = instance()->debugger();
|
Debugger& dbg = instance()->debugger();
|
||||||
|
|
||||||
myCurrentBank = dbg.getBank();
|
|
||||||
|
|
||||||
// Fill romlist the current bank of source or disassembly
|
// Fill romlist the current bank of source or disassembly
|
||||||
if(mySourceAvailable)
|
if(mySourceAvailable)
|
||||||
; // FIXME
|
; // FIXME
|
||||||
|
@ -131,7 +133,7 @@ void RomWidget::initialUpdate()
|
||||||
StringList label, data, disasm;
|
StringList label, data, disasm;
|
||||||
BoolArray state;
|
BoolArray state;
|
||||||
|
|
||||||
// Disassemble entire bank (up to 4096 lines)
|
// Disassemble entire bank (up to 4096 lines) and invalidate all lines
|
||||||
dbg.disassemble(myAddrList, label, data, disasm, 0xf000, 4096);
|
dbg.disassemble(myAddrList, label, data, disasm, 0xf000, 4096);
|
||||||
for(unsigned int i = 0; i < data.size(); ++i)
|
for(unsigned int i = 0; i < data.size(); ++i)
|
||||||
state.push_back(false);
|
state.push_back(false);
|
||||||
|
@ -146,7 +148,7 @@ void RomWidget::initialUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void RomWidget::incrementalUpdate()
|
void RomWidget::incrementalUpdate(int line, int rows)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: RomWidget.hxx,v 1.2 2005-09-07 18:34:52 stephena Exp $
|
// $Id: RomWidget.hxx,v 1.3 2005-09-13 18:27:42 stephena Exp $
|
||||||
//
|
//
|
||||||
// Based on code from ScummVM - Scumm Interpreter
|
// Based on code from ScummVM - Scumm Interpreter
|
||||||
// Copyright (C) 2002-2004 The ScummVM project
|
// Copyright (C) 2002-2004 The ScummVM project
|
||||||
|
@ -47,7 +47,7 @@ class RomWidget : public Widget, public CommandSender
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initialUpdate();
|
void initialUpdate();
|
||||||
void incrementalUpdate();
|
void incrementalUpdate(int line, int rows);
|
||||||
|
|
||||||
void setBreak(int data);
|
void setBreak(int data);
|
||||||
void setPC(int data);
|
void setPC(int data);
|
||||||
|
@ -63,6 +63,10 @@ class RomWidget : public Widget, public CommandSender
|
||||||
/** List of line numbers indexed by address */
|
/** List of line numbers indexed by address */
|
||||||
AddrToLine myLineList;
|
AddrToLine myLineList;
|
||||||
|
|
||||||
|
/** Indicates whether a given line is valid or not;
|
||||||
|
Invalid lines need to be disassembled again */
|
||||||
|
BoolArray myLineValid;
|
||||||
|
|
||||||
bool myFirstLoad;
|
bool myFirstLoad;
|
||||||
bool mySourceAvailable;
|
bool mySourceAvailable;
|
||||||
int myCurrentBank;
|
int myCurrentBank;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: Settings.cxx,v 1.59 2005-09-11 15:44:51 stephena Exp $
|
// $Id: Settings.cxx,v 1.60 2005-09-13 18:27:42 stephena Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
@ -39,7 +39,6 @@ Settings::Settings(OSystem* osystem)
|
||||||
|
|
||||||
// Now fill it with options that are common to all versions of Stella
|
// Now fill it with options that are common to all versions of Stella
|
||||||
set("video", "soft");
|
set("video", "soft");
|
||||||
set("video_driver", "");
|
|
||||||
|
|
||||||
set("gl_filter", "nearest");
|
set("gl_filter", "nearest");
|
||||||
set("gl_aspect", "2.0");
|
set("gl_aspect", "2.0");
|
||||||
|
@ -47,8 +46,8 @@ Settings::Settings(OSystem* osystem)
|
||||||
|
|
||||||
set("zoom", "2");
|
set("zoom", "2");
|
||||||
set("fullscreen", "false");
|
set("fullscreen", "false");
|
||||||
set("grabmouse", "false");
|
|
||||||
set("center", "true");
|
set("center", "true");
|
||||||
|
set("grabmouse", "false");
|
||||||
set("palette", "standard");
|
set("palette", "standard");
|
||||||
set("debugheight", "0");
|
set("debugheight", "0");
|
||||||
|
|
||||||
|
@ -255,7 +254,6 @@ void Settings::usage()
|
||||||
<< " soft SDL software mode\n"
|
<< " soft SDL software mode\n"
|
||||||
#ifdef DISPLAY_OPENGL
|
#ifdef DISPLAY_OPENGL
|
||||||
<< " gl SDL OpenGL mode\n"
|
<< " gl SDL OpenGL mode\n"
|
||||||
<< " -video_driver <type> SDL Video driver (see manual).\n"
|
|
||||||
<< endl
|
<< endl
|
||||||
<< " -gl_filter <type> Type is one of the following:\n"
|
<< " -gl_filter <type> Type is one of the following:\n"
|
||||||
<< " nearest Normal scaling (GL_NEAREST)\n"
|
<< " nearest Normal scaling (GL_NEAREST)\n"
|
||||||
|
@ -266,22 +264,19 @@ void Settings::usage()
|
||||||
#endif
|
#endif
|
||||||
<< " -zoom <size> Makes window be 'size' times normal\n"
|
<< " -zoom <size> Makes window be 'size' times normal\n"
|
||||||
<< " -fullscreen <1|0> Play the game in fullscreen mode\n"
|
<< " -fullscreen <1|0> Play the game in fullscreen mode\n"
|
||||||
<< " -grabmouse <1|0> Keeps the mouse in the game window\n"
|
|
||||||
<< " -center <1|0> Centers game window (if possible)\n"
|
<< " -center <1|0> Centers game window (if possible)\n"
|
||||||
|
<< " -grabmouse <1|0> Keeps the mouse in the game window\n"
|
||||||
<< " -palette <original| Use the specified color palette\n"
|
<< " -palette <original| Use the specified color palette\n"
|
||||||
<< " standard|\n"
|
<< " standard|\n"
|
||||||
<< " z26>\n"
|
<< " z26>\n"
|
||||||
<< " -framerate <number> Display the given number of frames per second\n"
|
<< " -framerate <number> Display the given number of frames per second\n"
|
||||||
<< " -debug <1|0> Start in the debugger\n"
|
<< endl
|
||||||
<< " -debugheight <number> Set height of debugger in lines of text (NOT pixels)\n"
|
|
||||||
<< " -holdreset Start the emulator with the Game Reset switch held down\n"
|
|
||||||
<< " -holdselect Start the emulator with the Game Select switch held down\n"
|
|
||||||
<< " -holdbutton0 Start the emulator with the left joystick button held down\n"
|
|
||||||
#ifdef SOUND_SUPPORT
|
#ifdef SOUND_SUPPORT
|
||||||
<< " -sound <1|0> Enable sound generation\n"
|
<< " -sound <1|0> Enable sound generation\n"
|
||||||
<< " -channels <1|2> Enable mono or stereo sound\n"
|
<< " -channels <1|2> Enable mono or stereo sound\n"
|
||||||
<< " -fragsize <number> The size of sound fragments (must be a power of two)\n"
|
<< " -fragsize <number> The size of sound fragments (must be a power of two)\n"
|
||||||
<< " -volume <number> Set the volume (0 - 100)\n"
|
<< " -volume <number> Set the volume (0 - 100)\n"
|
||||||
|
<< endl
|
||||||
#endif
|
#endif
|
||||||
<< " -paddle <0|1|2|3> Indicates which paddle the mouse should emulate\n"
|
<< " -paddle <0|1|2|3> Indicates which paddle the mouse should emulate\n"
|
||||||
<< " -showinfo <1|0> Shows some game info\n"
|
<< " -showinfo <1|0> Shows some game info\n"
|
||||||
|
@ -292,6 +287,7 @@ void Settings::usage()
|
||||||
<< " -ssdir <path> The directory to save snapshot files to\n"
|
<< " -ssdir <path> The directory to save snapshot files to\n"
|
||||||
<< " -ssname <name> How to name the snapshot (romname or md5sum)\n"
|
<< " -ssname <name> How to name the snapshot (romname or md5sum)\n"
|
||||||
<< " -sssingle <1|0> Generate single snapshot instead of many\n"
|
<< " -sssingle <1|0> Generate single snapshot instead of many\n"
|
||||||
|
<< endl
|
||||||
#endif
|
#endif
|
||||||
<< " -listrominfo Display contents of stella.pro, one line per ROM entry\n"
|
<< " -listrominfo Display contents of stella.pro, one line per ROM entry\n"
|
||||||
<< " -help Show the text you're now reading\n"
|
<< " -help Show the text you're now reading\n"
|
||||||
|
@ -299,6 +295,12 @@ void Settings::usage()
|
||||||
<< " The following options are meant for developers\n"
|
<< " The following options are meant for developers\n"
|
||||||
<< " Arguments are more fully explained in the manual\n"
|
<< " Arguments are more fully explained in the manual\n"
|
||||||
<< endl
|
<< endl
|
||||||
|
<< " -debugheight <number> Set height of debugger in lines of text (NOT pixels)\n"
|
||||||
|
<< " -debug Start in debugger mode\n"
|
||||||
|
<< " -holdreset Start the emulator with the Game Reset switch held down\n"
|
||||||
|
<< " -holdselect Start the emulator with the Game Select switch held down\n"
|
||||||
|
<< " -holdbutton0 Start the emulator with the left joystick button held down\n"
|
||||||
|
<< endl
|
||||||
<< " -pro <props file> Use the given properties file instead of stella.pro\n"
|
<< " -pro <props file> Use the given properties file instead of stella.pro\n"
|
||||||
<< " -type <arg> Sets the 'Cartridge.Type' property\n"
|
<< " -type <arg> Sets the 'Cartridge.Type' property\n"
|
||||||
<< " -ld <arg> Sets the 'Console.LeftDifficulty' property\n"
|
<< " -ld <arg> Sets the 'Console.LeftDifficulty' property\n"
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: ListWidget.cxx,v 1.30 2005-09-07 18:34:52 stephena Exp $
|
// $Id: ListWidget.cxx,v 1.31 2005-09-13 18:27:42 stephena Exp $
|
||||||
//
|
//
|
||||||
// Based on code from ScummVM - Scumm Interpreter
|
// Based on code from ScummVM - Scumm Interpreter
|
||||||
// Copyright (C) 2002-2004 The ScummVM project
|
// Copyright (C) 2002-2004 The ScummVM project
|
||||||
|
@ -147,6 +147,7 @@ void ListWidget::scrollBarRecalc()
|
||||||
_scrollBar->recalc();
|
_scrollBar->recalc();
|
||||||
|
|
||||||
setDirty(); draw();
|
setDirty(); draw();
|
||||||
|
sendCommand(kListScrolledCmd, _currentPos, _id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -366,20 +367,16 @@ void ListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void ListWidget::scrollToCurrent(int item)
|
void ListWidget::scrollToCurrent(int item)
|
||||||
{
|
{
|
||||||
bool scrolled = false;
|
|
||||||
|
|
||||||
// Only do something if the current item is not in our view port
|
// Only do something if the current item is not in our view port
|
||||||
if (item < _currentPos)
|
if (item < _currentPos)
|
||||||
{
|
{
|
||||||
// it's above our view
|
// it's above our view
|
||||||
_currentPos = item;
|
_currentPos = item;
|
||||||
scrolled = true;
|
|
||||||
}
|
}
|
||||||
else if (item >= _currentPos + _rows )
|
else if (item >= _currentPos + _rows )
|
||||||
{
|
{
|
||||||
// it's below our view
|
// it's below our view
|
||||||
_currentPos = item - _rows + 1;
|
_currentPos = item - _rows + 1;
|
||||||
scrolled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_currentPos < 0 || _rows > (int)_list.size())
|
if (_currentPos < 0 || _rows > (int)_list.size())
|
||||||
|
@ -387,12 +384,13 @@ void ListWidget::scrollToCurrent(int item)
|
||||||
else if (_currentPos + _rows > (int)_list.size())
|
else if (_currentPos + _rows > (int)_list.size())
|
||||||
_currentPos = _list.size() - _rows;
|
_currentPos = _list.size() - _rows;
|
||||||
|
|
||||||
|
int oldScrollPos = _scrollBar->_currentPos;
|
||||||
_scrollBar->_currentPos = _currentPos;
|
_scrollBar->_currentPos = _currentPos;
|
||||||
_scrollBar->recalc();
|
_scrollBar->recalc();
|
||||||
|
|
||||||
setDirty(); draw();
|
setDirty(); draw();
|
||||||
|
|
||||||
if(scrolled)
|
if(oldScrollPos != _currentPos)
|
||||||
sendCommand(kListScrolledCmd, _currentPos, _id);
|
sendCommand(kListScrolledCmd, _currentPos, _id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: ListWidget.hxx,v 1.12 2005-08-26 16:44:17 stephena Exp $
|
// $Id: ListWidget.hxx,v 1.13 2005-09-13 18:27:42 stephena Exp $
|
||||||
//
|
//
|
||||||
// Based on code from ScummVM - Scumm Interpreter
|
// Based on code from ScummVM - Scumm Interpreter
|
||||||
// Copyright (C) 2002-2004 The ScummVM project
|
// Copyright (C) 2002-2004 The ScummVM project
|
||||||
|
@ -48,6 +48,9 @@ class ListWidget : public EditableWidget
|
||||||
int x, int y, int w, int h);
|
int x, int y, int w, int h);
|
||||||
virtual ~ListWidget();
|
virtual ~ListWidget();
|
||||||
|
|
||||||
|
int rows() const { return _rows; }
|
||||||
|
int currentPos() const { return _currentPos; }
|
||||||
|
|
||||||
int getSelected() const { return _selectedItem; }
|
int getSelected() const { return _selectedItem; }
|
||||||
void setSelected(int item);
|
void setSelected(int item);
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// See the file "license" for information on usage and redistribution of
|
// See the file "license" for information on usage and redistribution of
|
||||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||||
//
|
//
|
||||||
// $Id: SettingsWin32.cxx,v 1.17 2005-08-24 01:07:37 stephena Exp $
|
// $Id: SettingsWin32.cxx,v 1.18 2005-09-13 18:27:42 stephena Exp $
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -28,7 +28,6 @@
|
||||||
SettingsWin32::SettingsWin32(OSystem* osystem)
|
SettingsWin32::SettingsWin32(OSystem* osystem)
|
||||||
: Settings(osystem)
|
: Settings(osystem)
|
||||||
{
|
{
|
||||||
set("video_driver", "directx"); // This seems to be much faster than DirectX
|
|
||||||
set("fragsize", "2048"); // Anything less than this usually causes sound skipping
|
set("fragsize", "2048"); // Anything less than this usually causes sound skipping
|
||||||
set("video", "hard"); // Use software mode with hardware surface
|
set("video", "hard"); // Use software mode with hardware surface
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue