Skip to content

debug console commands

Chris Frantz edited this page Apr 14, 2019 · 1 revision

DebugConsole 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.

The load command

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 _

The save command

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

Read commands from a file with source

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

Setting runtime variables with set

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 16 to default to hex). This will make all other commands which take numbers interpret the numbers in the supplied base. set ibase always 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>

Hexdump data with dbp, dbc, dwp, dwc

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

Dumping townsperson text with dtt

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.

Writing data with wbp, wbc, wwp, wwc

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

Writing text with wtp

You can write Zelda2 encoded text into the ROM with wtp.

wtp b=0 0x92ca "FOOBAR"  # Write the string "FOOBAR" in bank 0

Bank manipulation commands

insertprg/insertchr

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

copyprg/copychr

Copy a PRG or CHR bank over the top of another bank.

copyprg 2 14 # Copy bank 2 to bank 14

Memory manipulation with memmove, bcopy and swap

You can move or copy blocks of memory around with the memmove, bcopy and swap commands.

  • memmove moves memory within a bank.
  • swap swaps memory locations within a bank (moves a to b and b to a).
  • bcopy copies memory between banks.
memmove b=<bank> <dstaddr> <srcaddr> <len>
swap b=<bank> <dstaddr> <srcaddr> <len>
bcopy <bank:dst> <bank:src> <len>

Character data manipulation with charclear, charcopy and charswap

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.

charclear

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.

charcopy

You can copy character cells around with charcopy.

charcopy 1:f4 2:f4   # copy bank2's char F4 to bank1's F4

charswap

You can swap character cells with charswap.

charswap 1:f4 2:f4

Disassemble ROM code with u

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

Assemble ROM code with asm

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.

Clone this wiki locally