-
Notifications
You must be signed in to change notification settings - Fork 8
debug console commands
This document is a list of commands that can be issued from the debug console. You can use these commands to write some semi-automated scripts for rearranging or hacking the ROM. These commands are low-level and ill-supported. Use at your own risk.
Load a .nes file or a .z2prj file. Optionally disable the default memory
moves performed by the loader. The type of file loaded (ROM or z2prj file) is
determined by the file extension.
- Load a project file
load filename.z2prj
- Load a ROM file (and perform memory moves by default)
load zelda2.nes
- Load a ROM and do not perform memory moves
load zelda2.nes move=0
- Reload the current ROM, discarding any changes
load _
Save a .nes, .ips or a .z2prj file.
Export the current ROM as either a .nes image or a .ips patch, or save the
current project.
save filename.nes
save patch.ips
save project.z2prj
The source command will read a file with a list of DebugConsole commands.
You can use this to prepare a script to do a bulk modification to a ROM.
source some/path/to/script.z2edit
The DebugConsole has some internal variables which can affect other commands.
The set command with no arguments will print the current variables.
- Set the default number base (e.g.
set ibase 16to default to hex). This will make all other commands which take numbers interpret the numbers in the supplied base.set ibasealways interprets its argument in base 10.
set ibase <value>
- Set the PRG bank. Many commands operate in different banks via the
b=<bank>parameter. This sets the default bank.
set bank <value>
- Set the CHR bank. Similarly, many commands operate on different CHR banks.
set chrbank <value>
- Set the text encoding. Many of the hexdump commands also show a character
dump. The text encoding determines whether the dump is in ASCII (
0) or the Zelda2 encoding (1).
set text 0 # ASCII
set text 1 # Zelda2
- Set the name of the emulator to run. When you click
Emulate, this is the emulator that is run.
set emulator <command>
There are a number of commands to hexdump data, and they all have a similar
form. Hexdump can either dump bytes or words (16-bits, little endian).
Hexdump can read memory via the mapper (not very useful) or directly from
PRG or CHR banks. All of the hexdump commands accept a b=<bank> as an
optional first argument to override the bank number.
dbp b=7 0x8000 32 # Dump 32 bytes from bank 7 at 0x8000
dbp 0x8500 0x40 # Dump 64 bytes from the default bank at 0x8500
dwp 0x8000 0x40 # Dump 64 words from the default bank
dbc b=0 0 8 # Dump 8 bytes from CHR bank 0
dbp b=7 0xc000
c000: a9 00 8d 01 20 8d 00 20 a9 05 20 cc ff 20 a0 a6 .... .. .. .. ..
c010: ad 36 07 c9 08 f0 04 c9 14 d0 f5 ad 6c 07 c9 01 .6..........l...
c020: d0 ee a9 40 8d 00 01 20 cb c4 a9 c0 8d 00 01 4c ...@... .......L
c030: 10 c0 a9 06 20 cc ff 20 00 80 4c 88 c3 02 03 63 .... .. ..L....c
Similar to the hexdump commands, there is a command to dump text from town NPCs. NPCs with enemy ids less than 10 do not have text.
dtt <towncode> <enemyid>
dtt 1 22
0 (@a507): GORIYA OF\TANTARI\STOLE OUR\TROPHY.
1 (@a52b): YOU SAVED\THE TROPHY_COME SEE\MY UNCLE.
You can write data into either PRG or CHR banks with the memory writing
commands. Similar to the dump commands, they accept a b=<bank> as an
optional first argument to override the bank number.
wbp b=7 0xcb32 0x3c 0x4b 0x4c # Write 3 bytes at 0xcb32 in bank 7
wwp 0x8500 0x8417 # Write a single word to address 0x8500
You can write Zelda2 encoded text into the ROM with wtp.
wtp b=0 0x92ca "FOOBAR" # Write the string "FOOBAR" in bank 0
Insert an empty PRG or CHR bank into the ROM. Existing banks get pushed up by one.
insertprg 7 # insert an empty bank at bank 7, pushing bank 7 to bank 8
Copy a PRG or CHR bank over the top of another bank.
copyprg 2 14 # Copy bank 2 to bank 14
You can move or copy blocks of memory around with the memmove, bcopy
and swap commands.
-
memmovemoves memory within a bank. -
swapswaps memory locations within a bank (moves a to b and b to a). -
bcopycopies memory between banks.
memmove b=<bank> <dstaddr> <srcaddr> <len>
swap b=<bank> <dstaddr> <srcaddr> <len>
bcopy <bank:dst> <bank:src> <len>
The char in each of the following commands is either a char id,
or a bank:char_id. If several chars may be provided in a comma separated
list, the list must not contain spaces.
You can clear or copy individual CHRROM character cells.
charclear [char{,char,char,...}] <with_id>
with_id is either true or false (absent). When true, the cleared
cell is replaced with a representation of it's hex code. For example,
charclear 0:f4,1:f4 true would clear chars F4 in CHR banks 0 and 1,
replacing them with a graphic that would be viewable in-game as F4.
You can copy character cells around with charcopy.
charcopy 1:f4 2:f4 # copy bank2's char F4 to bank1's F4
You can swap character cells with charswap.
charswap 1:f4 2:f4
You can disassemble code in the ROM with the u command.
For example, the Zelda2 reset vector is at 0xFF70:
u [b=<bank>] <address> [length]
u b=7 0xff70 10
u b=7 0xff70 10
ff70: 78 SEI
ff71: d8 CLD
ff72: a200 LDX #$00
ff74: 8e0020 STX $2000
ff77: e8 INX
ff78: ad0220 LDA $2002
ff7b: 10fb BPL $fb ;[dest=ff78]
ff7d: ca DEX
ff7e: f0f8 BEQ $f8 ;[dest=ff78]
ff80: 9a TXS
The asm command enters a 6502 assembler mode. When in the assembler mode,
only assembler mode commands are accepted until you .end and return to
normal mode.
The assembler is very basic (and probable buggy), but it does support equates and labels.
NOTE: The assembler mode currently will not apply label fixups across banks, and if you attempt to do so, you'll probably corrupt the ROM.
The .help command will show all of the instructions and directives
accepted in assembler mode.
asm 0x8000
Entering assembler mode (bank=0). '.end' to leave.
Instruction Abs AbX AbY Acc Imm Imp InX Ind InY Rel Zp ZpX ZpY Fake
----------- --------------------------------------------------------
.BANK ff
.DB ff
.DD ff
.DW ff
.END ff
.ORG ff
= ff
ADC 6d 7d 79 69 61 71 65 75
AND 2d 3d 39 29 21 31 25 35
ASL 0e 1e 0a 06 16
BCC 90 90
BCS b0 b0
BEQ f0 f0
BIT 2c 24
BMI 30 30
BNE d0 d0
BPL 10 10
BRK 00
BVC 50 50
BVS 70 70
CLC 18
CLD d8
CLI 58
CLV b8
CMP cd dd d9 c9 c1 d1 c5 d5
CPX ec e0 e4
CPY cc c0 c4
DEC ce de c6 d6
DEX ca
DEY 88
EOR 4d 5d 59 49 41 51 45 55
INC ee fe e6 f6
INX e8
INY c8
JMP 4c 6c
JSR 20
LDA ad bd b9 a9 a1 b1 a5 b5
LDX ae be a2 a6 b6
LDY ac bc a0 a4 b4
LSR 4e 5e 4a 46 56
NOP ea
ORA 0d 1d 19 09 01 11 05 15
PHA 48
PHP 08
PLA 68
PLP 28
ROL 2e 3e 2a 26 36
ROR 6e 7e 6a 66 76
RTI 40
RTS 60
SBC ed fd f9 e9 e1 f1 e5 f5
SEC 38
SED f8
SEI 78
STA 8d 9d 99 81 91 85 95
STX 8e 86 96
STY 8c 84 94
TAX aa
TAY a8
TSX ba
TXA 8a
TXS 9a
TYA 98
Typical 6502 conventions are followed:
; comments start with a semicolon
.org $8000 ; set the origin
bank7_enemy_every_frame = $d6ca ; label equate
ram = $6000
loop: ; label at current address
ldx #0 ; Load X immediate value 0
dex
bne loop ; branch to label target
lda ram,X ; absolute X (or Y) mode
lda ($20,Y) ; indirect Y (or X) mode
jmp ($000e) ; indirect mode (jmp instr only)
.db 1,2,$ff ; define byte
.dw 10,20,$FFEE ; define word
There is very little error checking, especially regarding label fixups. This
means the assembler will happily accept a branch instruction like
bne label where the label is too far away to be a valid branch target.
The assembler will silently create bad code for this condition.