Assembly 101: Labels

Labeling memory addresses will save you a lot of hassle. It’s easier to remember and reference “Object_speed” rather than its physical memory address, which could be something like $0337. How does labeling work, when are labels applied, and what’s up with that “Label already defined” error message?

What is a label?

A label, in the most literal sense of the word, is a classifying name or phrase applied to a thing. In Assembly, this “thing” is a memory address. Each memory address in the NES holds a byte (or eight bits, hence the NES is called an 8-bit system) of data. This data can either be a variable or (part of) an instruction. Without labeling addresses, you’ll have to manually figure out which memory address holds the data you need or the instruction you want to execute. To make matters even worse, during development, these memory addresses may change, as extra instructions and data are being added inside the source code, shifting things in memory.

A snippet of code, viewed in the Mesen Debugger, showing unlabeled memory addresses and instructions

By giving these memory addresses a label, you can reference these addresses a lot easier, and on top of that, the memory addresses are more or less dynamic during development, which means you don’t have to update those when you’re writing your game’s code.

How do labels work?

Note: NESmaker uses ASM6 as its assembly code compiler; this tutorial is written with this in mind. Other compilers may have different syntaxes for labels, although the general idea is the same.

Applying a label to a memory address is as simple as typing the name of the label you want, optionally (but preferably) followed by a colon. A small example from the NESmaker source code, with its label-less counterpart next to it:

$C2A2    LoadSpritePal_NMI:
$C2A2        LDA sprPal,x             LDA $0625,X
$C2A5        STA $2007                STA $2007
$C2A8        INX                      INX
$C2A9        CPX #$10                 CPX #$10
$C2AB        BNE LoadSpritePal_NMI    BNE $C2A2

In the above example, LoadSpritePal_NMI is the label. The last line, BNE LoadSpritePal_NMI, allows the script to branch out to the memory address associated with that label. You may say LoadSpritePal_NMI is an alias for memory address $C2A2. As you can see in the example above, labels use no memory in ROM, but rather get replaced with the actual address upon compilation. Pop question: can you find another label in the above snippet?

Label naming conventions

You can use any name or value for your labels, although obviously you don’t want to use instructions as labels. For instance, LDA: is a really bad idea for a label name. Ideally, you want to name your labels according to what they stand for. So the label Object_speed should be used for the variable where object speeds are stored. Base rule: use common sense when naming things. Another important thing to keep in mind is that you can’t use label names more than once – unless they are special labels, mentioned below. If you use a label name more than once, the compiler won’t know which label to use when referencing it, resulting in a “Label already defined” error. So if you ever come across such error message, rename the label, or make it “special.”

Special labels

There are a few special labels in ASM6 though. Whenever you need a label for a branch or jump forward, you can prefix your label with the plus sign. The same goes for situations where you want to branch backward, in which case you can use a minus sign as a prefix instead. The biggest advantage of these labels is that, unlike “normally” named labels, you can use them multiple times. The compiler will branch out to the first next or previous prefixed label it encounters.

Using only a single or couple plus or minus signs is just as fine as well, although those should only be used in instances where it’s clearly obvious what they do. If there is the slightest hint of ambiguity going on, you’re best off giving your label an appropriate name though. A few quick examples:

Reset the game when your life counter hits zero:

    LDA myLives    ;; Load number of lives into accumulator
    BNE +          ;; If not zero, branch out to the next plus sign
        JMP RESET  ;; Number of lives is zero, so reset the game
    +              ;; Code branches out here if number of lives is not zero

Write sixteen palette byte values to the PPU register:

    LDX #$00      ;; Load zero into the X-register
-palLoop:         ;; The -palLoop label, which the code can branch to
    LDA sprPal,x  ;; Load the X'th byte from sprPal into the accumulator
    STA $2007     ;; Store its value to the PPU data register
    INX           ;; Add one to the X-register
    CPX #$10      ;; Check if the X-register's value equals sixteen
    BNE -palLoop  ;; If not, branch back to the -palLoop label

This basically is all you need to know about labels up at this point. If things are unclear, or if you still have some questions regarding labels, please feel free to contact me.