3
votes

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.

2
The directives put bytes directly in the output. There is no memory access. For example, LDA #1 is the same as .byte $A9, $01.Raymond Chen
what is "the output"?chiliNUT
It's the other way around. All opcodes are translatable into .byte directives. That's what an assembler does. it takes opcodes and converts them into bytes.Raymond Chen
Like it says in the article you quoted: "as data and not as instructions." If you need to put data in your program, you just want to put the bytes in the memory image.Raymond Chen
haha this was a bit drawn out...the "output" is the content of the program file. This all makes sense now. @RaymondChen thank you for your help in understanding thischiliNUT

2 Answers

2
votes

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.

1
votes

After reading the comments I try to give an answer:

In the memory of most computers all kind of data (including code) is stored in form of bytes.

This means that an assembler has to translate all instructions to bytes in the end.

The instruction "LDA $1234" would be stored as three bytes: $AD, $12 and $34.

Using the instructions ".byte", ".word" and ".long" (may be 6502 does not support ".long") you can directly instruct the assembler to put some given bytes to some memory location instead of the byte that represents some instruction.

Imagine the following piece of code which is part of the operating system:

LDX $2000
STA 0,X
...
JSR $2001

In this case the byte at address $2000 will contain an address in the zero page where the A register will be written to while the byte at address $2001 is the first byte of the actual code.

The assembler code for data starting at addresses $2000 may now look like this:

# Zero-page address where the OS will store the A register
.byte $12
# Actual code called by the OS
LDA $12
...
RTS

I hope this helps.

--- Edit ---

About your example with the '.ascii "iNES"' line:

These lines are only present in a program for a NES emulator, not in a program for a real NES device.

When using a very, very broad definition of the term "operating system" you might say that the NES emulator is some kind of "operating system". In this case the reason for the ".byte" lines in your example is the same one as described above:

The "operating system" (= NES emulator) will read the first 16 bytes of the file, check these bytes, do something with these bytes and then actually runs the code.

You may also have seen the following lines in the code:

.advance $FFFA
.word vblank, reset, irq

These two lines are also not 6502 assembler instructions but they are directives to the assembler:

They instruct the assembler to write six special bytes to address $FFFA. This is necessary because a 6502 CPU requires six bytes representing three special addresses at the addresses $FFFA-$FFFF.