What is the free space zero page can be used for? Can we use it?

drexegar

Member
I can't understand how zero page ram works if a number has been set and uses up 2 bytes, we can store two variables? How is something called from the zero page ram?

All I know about it its the top of the address with one less number to worry about making it faster than non zero addresses. right?
 

Mugi

Member
zero page ram works the same way as user variables does.
you define a var "potatovariable"

which you can then use in code as such:
LDA potatovariable

zeropage ram is the first memory area, (thus the name) and is faster to load from than normal memory, hence why it is usually reserved for things that require speedy execution.

if you set up a variable to use 2 bytes, you can use it in code
with the +1 suffix, to indicate that you are doing things to the second byte of this variable.

i requested the byte count feature to be added to the user variables too in the 5.0 requests thread, so we'll see if that happens :p
 

Kasumi

New member
The 6502 CPU mostly treats everything it can see (addresses $0000-$FFFF) exactly the same, because the 6502 is a generic CPU. On NES, writing to specific addresses and reading from specific addresses can cause the NES to do certain things, or return certain information about the state of the NES hardware, but it's sort of invisible to the CPU. You can write to a place where the write won't have an effect, and the 6502 doesn't know this. You can read from places that return "garbage" values and the 6502 doesn't know the value is garbage. You can execute code from RAM, just like you can from ROM.

The zero page is just addresses $0000-$00FF. It's faster solely because it's one fewer byte to read for the CPU. "LDA" in code can actually be any one of several different bytes for the CPU: http://www.obelisk.me.uk/6502/reference.html#LDA

If you type LDA $0200, that gets assembled as $AD $00, $02. (The opcode for absolute addressing for LDA is $AD.) If you type LDA $00 that gets assembled $A5, $00. (The opcode for zero page addressing for LDA is $A5).

So a way to think about it is there are actually two different instructions to load a value from an address. One is faster because it doesn't have to read an extra byte. (The different instruction tells the CPU the byte is zero.) This is the reason the zero page is faster. There's usually an alternate byte for instructions that deal with it.

LDA $0000 ($AD, $00, $00) can be used instead of LDA $00 ($A5, $00) and the A will be the same value after either. But the $A5 version is ever so slightly faster. There are certain kinds of actions that can only be done on the zero page (mainly pointer things).

Zero page variables in NES Maker reside in "Routines\Basic\\Variables\ZP_and_vars.asm

The 6502 is unaware of which "variables" are 2 bytes, because the 6502 is unaware of the intent of your program. It does what it's told. What you'd consider to be a two byte variable does not even need to have both bytes to be contiguous (except for pointers) because the 6502 will only deal with them one at a time anyway. ($00 and $01 to store a 16 bit position is just as valid as $40 and $0206 to store that 16bit position.) NES Maker positions are actually an example of two byte variables that are not contiguous. (Object_x_lo for object 0 might be at $04A8, and Object_x_hi for object 0 might be at $049E)

What the assembler does is take all names given to it and turn them into the numbers they represent. The names only help you, the programmer. The 6502 doesn't see them.

Code:
lowByte = $04

lda lowByte
Gets assembled at LDA $04, which is $A5, $04
Code:
lowByte = $0200

lda lowByte
Gets assembled as LDA $0200, which is $AD, $00, $02.

Code:
lowByte = $0200

lda lowByte
lda lowByte+1
Gets assembled as LDA $0200, LDA $0201: $AD, $00, $02, $AD, $01, $02

You use a zero page variable the same way you would any other variable, or any other address. (A named variable is really just an address anyway.) ASM6 will use the faster LDA for them automatically (some assemblers won't!).

Even then, it's usually only marginally faster.
lda $0200 is four cycles.
lda $00 is three cycles.
So you get can get four zero page reads in the same time as three absolute reads. But the times it would help the most is dealing with arrays, and it's usually not faster for this.
 

drexegar

Member
Mugi said:
zero page ram works the same way as user variables does.
you define a var "potatovariable"

which you can then use in code as such:
LDA potatovariable

zeropage ram is the first memory area, (thus the name) and is faster to load from than normal memory, hence why it is usually reserved for things that require speedy execution.

if you set up a variable to use 2 bytes, you can use it in code
with the +1 suffix, to indicate that you are doing things to the second byte of this variable.

i requested the byte count feature to be added to the user variables too in the 5.0 requests thread, so we'll see if that happens :p

So does that mean with a 2 byte variable you can store 2 vaules? 1 vaule in potatoStorage and another in potatoStorage + 1?
 

drexegar

Member
Kasumi said:
So you get can get four zero page reads in the same time as three absolute reads. But the times it would help the most is dealing with arrays, and it's usually not faster for this.

Thanks for the information Kasumi!
 

Kasumi

New member
drexegar said:
So does that mean with a 2 byte variable you can store 2 vaules? 1 vaule in potatoStorage and another in potatoStorage + 1?
Any address can hold exactly one byte. A "variable" is a named address in RAM. Suppose you define storage in RAM for potatoStorage, and the address it ends up referring to is $00D4. potatoStorage+1 is just $00D5.

$00D5 can store a byte like any other RAM address, the only thing you have to be careful of is if something else uses that address. (Because, again, the names mean nothing to the CPU.)

I guess I could have named a better file in the other post. ZP_and_vars.asm just ends up including GameData/ZP_RAM.asm.

But anyone, open both! And open demo.txt in GameEngineData.

Inside ZP_and_vars.asm you will see the following:
Code:
.enum $0000
This sets a counter to $0000. Then, variables are defined by typing a name, and then .dsb, and then the number of bytes
Code:
sound_region .dsb 1
sound_disable_update .dsb 1
sound_local_byte_0 .dsb 1
sound_local_byte_1 .dsb 1
sound_local_byte_2 .dsb 1
sound_local_word_0 .dsb 2
sound_local_word_1 .dsb 2
sound_local_word_2 .dsb 2
sound_param_byte_0 .dsb 1
Everytime a name is paired with .dsb, it makes that name equivalent to typing the current value of the counter, then adds the number after the .dsb to the counter.

So say the counter was $0000 and the above list of .dsb statements was encountered. sound_region becomes $0000 (the current value of the counter) and one is added to the counter. Now the current value of the counter is $0001. sound_disable_update becomes $0001 (the current value of the counter), and one is added to the counter.

sound_local_word_2 becomes $0009, but TWO is added to the counter this time. So sound_param_byte_0 becomes $000B. $000A doesn't have a name.

But it can be accessed with sound_local_word_2+1, because the .dsb makes typing sound_local_word_2 the same as typing $0009, and $0009+1 is $000A. That's how multibyte variables are set up, and that's how they work. you could do .dsb 10, even if you wanted 10 bytes all accessed through the same name.

Or you could do two .dsb 1 names instead of one .dsb 2 name.

(sound_local_word_2_lo .dsb 1 and sound_local_word_2_hi .dsb 1 accessed with lda sound_local_word_2_lo, and sound_local_word_2_hi
instead of
sound_local_word_2 .dsb 2 accessed with lda sound_local_word_2, and lda sound_local_word_2+1)
The assembler would actually create the exact same code in both cases.

You can actually see this happening (how the counter works) in demo.txt:
Code:
                                	.enum $0000
00000                           ;;;;;;ZERO PAGE VARIABLES
00000                           
00000                           	.include GameData/ZP_RAM.asm                        
00000                           sound_region .dsb 1
00001                           sound_disable_update .dsb 1
00002                           sound_local_byte_0 .dsb 1
00003                           sound_local_byte_1 .dsb 1
00004                           sound_local_byte_2 .dsb 1
00005                           sound_local_word_0 .dsb 2
00007                           sound_local_word_1 .dsb 2
00009                           sound_local_word_2 .dsb 2
0000B                           sound_param_byte_0 .dsb 1
On the left are the addresses the names got assigned to. So you can imagine that if you added potatoStorage .dsb 1, but then used potatoStorage+1, you'd actually be changing the variable after it!

Mugi's complaint is that you can't force NES Maker to do .dsb 2 from the UI, only .dsb 1 for user variables.
 
Top Bottom