Search code examples
assembly6502nintendo

What does the byte directive do in 6502 assembler?


First off: sorry if this is a dupe! I have searched a bit and have not found a resource which satisfactorily explains this.

n00bish question here!

I am trying to understand what the .byte directive does. Different sources say different things, the gist of which is something like :

.db, DB, .byte, etc. lay down the exact bytes you specify, as data and not as instructions (http://forum.6502.org/viewtopic.php?f=2&t=2374)

The cc65 manual gives a similarly vague:

.byte: Define byte sized data. Must be followed by a sequence of (byte ranged) expressions or strings.

Example:

        .byte   "Hello "
        .byt    "world", $0D, $00

(http://www.cc65.org/doc/ca65-11.html)

I don't know what that means. I thought that all operations related to defining data were variations on reading and writing memory addresses. So something like this (from a tut on NES development)

; Number of PRG-ROM blocks
.byte $01
; Number of CHR-ROM blocks
.byte $01
; ROM control bytes: Horizontal mirroring, no SRAM
; or trainer, Mapper #0
.byte $00, $00

What is it doing exactly? Can it all be explained in terms of opcodes, or is it doing something fancier? To me, it looks like it is maybe writing sequential data, starting from the zero page, something like this??:

LDA #$01
STA $00
LDA #$01
STA $01
LDA #$00
STA $02
LDA #$00
STA $03

Am I way off here? I have been reading 6502 Software Design by Leo Scanlon and I have seen no reference to that ( or any ) directive. I am learning 6502 for the purpose of NES development and all example code is riddled with .byte , .ascii , and several other directives. I really wanted to try and get a solid foundation in 6502 from an academic text like the Scanlon book before trying to navigate the world of user-contributed NES tutorials, but this is becoming a road block to my understanding of NES 6502.


Solution

  • There is two different things to consider here. You are mixing the ROM memory location, where the values are always here (they can't, and shouldn't, be "loaded in"), and RAM, where the contents are undefined when the system is powered on, and where any data you'd want to use have to be effectively "loaded in" at some point.

    For example :

    .byte $00, $01, $02, $03
    

    Will add somewhere in the ROM those 4 bytes. They are not "loaded in", they are always here.

    As opposed to :

    ldx #$00
    stx somewhere
    inx
    stx somewhere+1
    inx
    stx somewhere+2
    inx
    stx somewhere+3
    

    If somewhere points to RAM, then this will load the bytes $00, $01, $02, $03 in this location. Those bytes are only here in the RAM location after you load those values, and until you overwrite the RAM with other values.

    Now, as for your example, this is actually a confusing one, because it defines bytes of the iNES header format, which is always 16 bytes long. Those bytes are NOT part of neither the ROM or the RAM, but are just a header convention for storing NES ROMs on PCs.

    The example you saw just tricks the assembler into thinking the header is part of the ROM when in fact it is not. It is just one of the ways to do it. Another way would be to generate a clean "raw" ROM image with the assembler and add the iNES header separately when building, this is how I do it personally.

    I hope this helped.