Is it possible to get .db to "evaluate" variables?
Moderator: Moderators
Is it possible to get .db to "evaluate" variables?
When I put variables in the .db command, it references back to the addresses of the variables. I tried putting # and #$ in front of them but it wouldn't assemble at all then.
So instead of the variable values, their literal addresses in memory are being swapped into the code: $0000, $0001, $0002 etc.
edit: Actually I think I was confused with that question. What I do want is the address in the .db part. Then the loop should get the value of that address and write it to the PPU, right? I don't get it. I'm getting numbers coming up as tiles.
If not, how can I slightly change the background without scrolling or using spirtes.
So instead of the variable values, their literal addresses in memory are being swapped into the code: $0000, $0001, $0002 etc.
edit: Actually I think I was confused with that question. What I do want is the address in the .db part. Then the loop should get the value of that address and write it to the PPU, right? I don't get it. I'm getting numbers coming up as tiles.
If not, how can I slightly change the background without scrolling or using spirtes.
Last edited by Primitive on Tue Dec 27, 2011 12:15 am, edited 2 times in total.
I want to replace tiles in the background with other pre-defined tiles in a loaded .chr during run-time, depending on the game state. I can't write out a different background for every possible game state.tokumaru wrote:Things that are computed at runtime (i.e. using 6502 code) obviously can't be stored in the ROM via .DB statements, because the results are not available when the ROM is assembled.
Please explain in more detail what you are trying to achieve, so that we can point you in the right direction.
It depends a lot on how your game states affect the background... If you have actual objects on the background that actively interact with everything else, you should consider assigning the task of updating the background to the individual background objects so that each of them takes care of their own graphics, instead of working with the basic concept of a big table for everything.
If that's not it, please give me some more information about how the game state can affect the background, preferably with examples.
If that's not it, please give me some more information about how the game state can affect the background, preferably with examples.
I have another question that I just can't seem to work out and is causing me a lot of confusion.
Why is it adding $100 to the address I put in for the background tiles? The background tiles seems to start at $100 in the .chr, and the sprites start $000. I don't have a problem with them using different sections of the chr, but I can't understand why the assembler is adding $100 for the background tiles. How does it even know these values are for background tiles? Does the act of writing to the PPU port for background data point it to starting at the address of $100 in the .chr as an offset? None of this is in the nerdynights tutorial...
edit: Okay, I think I'm starting to get it now. The data given to the .db are numbers and only treated as addresses in the .chr after they're put in RAM when DMA is used to get the actual data. This comment in the nerdynights tutorial in particular threw me off: "load data from address (sprites + x)"
That makes it sound like you are loading the actual data. But you're loading the address, you never touch the data. The DMA loads the data, not you, ever. You use the address, if he wanted to talk about the DMA loading it then it should be commented on the DMA line. In retrospect, it does seem silly that I thought the entire data of the tile was loaded into the 8-bit accumulator, but I was just blindly following the instructions assuming they were correct.
What confused me also is that you can only give the numbers as $xy to the .db directive. This makes them seem as addresses, when they are in fact numbers (numbers used as addresses later by DMA). And if you try to put # in front of them you get an error.
But the .db is still referring back to the address in RAM of the variables when I want the values of the addresses.... which is what confused me also.... so I guess I will have to do them manually as you suggest.
Why is it adding $100 to the address I put in for the background tiles? The background tiles seems to start at $100 in the .chr, and the sprites start $000. I don't have a problem with them using different sections of the chr, but I can't understand why the assembler is adding $100 for the background tiles. How does it even know these values are for background tiles? Does the act of writing to the PPU port for background data point it to starting at the address of $100 in the .chr as an offset? None of this is in the nerdynights tutorial...
edit: Okay, I think I'm starting to get it now. The data given to the .db are numbers and only treated as addresses in the .chr after they're put in RAM when DMA is used to get the actual data. This comment in the nerdynights tutorial in particular threw me off: "load data from address (sprites + x)"
That makes it sound like you are loading the actual data. But you're loading the address, you never touch the data. The DMA loads the data, not you, ever. You use the address, if he wanted to talk about the DMA loading it then it should be commented on the DMA line. In retrospect, it does seem silly that I thought the entire data of the tile was loaded into the 8-bit accumulator, but I was just blindly following the instructions assuming they were correct.
What confused me also is that you can only give the numbers as $xy to the .db directive. This makes them seem as addresses, when they are in fact numbers (numbers used as addresses later by DMA). And if you try to put # in front of them you get an error.
But the .db is still referring back to the address in RAM of the variables when I want the values of the addresses.... which is what confused me also.... so I guess I will have to do them manually as you suggest.
You mean $1000? Which half of your chr-rom/ram is used by sprites, and which half is used for backgrounds is controlled by the number you write to $2000: http://wiki.nesdev.com/w/index.php/PPU_ ... _.3E_writePrimitive wrote: The background tiles seems to start at $100 in the .chr, and the sprites start $000.
You can even use the same half for both.
Based on some recent posts from people who have learned from it, I am beginning to think that tutorial is not the best place to learn from since it does a lot (too much) for you. That may impede understanding more than just reading good docs like the wiki. You get the appearance of progressing quickly with it, but the second one wants to do something not described in it... bad things happen.None of this is in the nerdynights tutorial...
Don't refer to .db statements as .chr, because (at least in the case of the .db statements under the "sprites" label) that's just plain old ROM. CHR refers specifically to ROM or RAM that contains the actual data for the graphic tiles. (i.e. data that is 2 bits per pixel and contains an actual image) And as far as I know, the DMA doesn't deal with CHR data at all. It may pass info that refers to it to the PPU, though.edit: Okay, I think I'm starting to get it now. The data given to the .db are numbers and only treated as addresses in the .chr after they're put in RAM when DMA is used to get the actual data.
I will try to explain data to you:
When you make a .db statement, you are adding bytes to ROM. It is no different than when you write code, or incbin your CHR data. To prove it, change this code:
Code: Select all
LDX #$00 ; start out at 0
Code: Select all
.db $A2, $00
The reason "LDX/LDA/JSR"exists is to make things easier for the programmer, but the NES NEVER sees it.
You can even do something crazy like this:
Code: Select all
label:
ldx #$02
lda label;What ends up in the accumulator?
That's why it doesn't make sense to put # before .db statements. They're all numbers. That can't be changed while the program is run. Allowing the user to put a # before them would make it seems like there is a distinction, when there is not. And because there is not, it's just an extra character to type. Putting # before a value with lda/ldx/ldy is actually changing what byte the instruction is assembled to. (which changes its behavior.) It means it's loading that exact value, rather than value contained at that location in RAM or ROM.
You are loading the data. Or rather, you're moving it.This comment in the nerdynights tutorial in particular threw me off: "load data from address (sprites + x)" That makes it sound like you are loading the actual data
LDX #$00
LDA sprites,x
loads the byte immediately after sprites. As the loop continues, it keeps loading the bytes in the .db statements and storing them to $0200,x. You're doing this, because even if DMA CAN work from ROM, you have to waste 4 bytes for every sprite and they can't move. Nerdy Nights has four sprites, using 16 bytes. DMA copies 256 bytes from whatever address you give it. That means you would have to put 240 bytes of .db $00 following the 16 bytes already there, otherwise DMA would just copy the bytes from whatever code is following the last sprite .db statement. The NES, and the DMA doesn't really make a distinction between ROM and RAM, or what you think your data should be used for.
Incorrect, as explained above.But you're loading the address, you never touch the data.
You have to touch the data, so the DMA copies the right values. All the DMA does is keep you from writing all the bytes to the PPU individually.The DMA loads the data, not you, ever.
The DMA has nothing to do with tile data. A "hardware sprite" on the NES is 4 bytes that describe the position, palette, and number that refers to the tile the sprite will be draw with.In retrospect, it does seem silly that I thought the entire data of the tile was loaded into the 8-bit accumulator, but I was just blindly following the instructions assuming they were correct.
The actual graphic data is in your chr, and is 16 bytes per tile, 2 bits per pixel.
The only number in each hardware sprite that could be considered an address, is the one that tells the PPU which tile to draw. The others are actually used straight by the PPU.What confused me also is that you can only give the numbers as $xy to the .db directive. This makes them seem as addresses, when they are in fact numbers (numbers used as addresses later by DMA)
I know I write too much, so if any of that is confusing ask a question and someone more laconic may be able to do better.
Thank you, this is all very helpful.
The only thing is I think it's a little harsh to say it's incorrect to say you're loading the addresses and not the data.
The line is: " LDA sprites, x ; load data from address (sprites + x) "
I said this is badly commented because you are loading the address (sprites + x) into A, not the data. The data would be image data, ie. the CONTENTS of the address, the .chr data. That's what I meant. You don't copy image data. You don't see the exact cycles one-by-one where the .chr is copied in your code. You just refer to it, the DMA copies it.
It's like you intentionally are trying to contradict me on this, but what I mean is that all you do is point to the address. You also said the DMA has nothing to do with the tile data when I didn't make any claims that would lead to that statement. And I didn't refer to .db as .chr.... though maybe it sounded like I did.
The only thing is I think it's a little harsh to say it's incorrect to say you're loading the addresses and not the data.
The line is: " LDA sprites, x ; load data from address (sprites + x) "
I said this is badly commented because you are loading the address (sprites + x) into A, not the data. The data would be image data, ie. the CONTENTS of the address, the .chr data. That's what I meant. You don't copy image data. You don't see the exact cycles one-by-one where the .chr is copied in your code. You just refer to it, the DMA copies it.
It's like you intentionally are trying to contradict me on this, but what I mean is that all you do is point to the address. You also said the DMA has nothing to do with the tile data when I didn't make any claims that would lead to that statement. And I didn't refer to .db as .chr.... though maybe it sounded like I did.
I'm not trying to contradict you, just make sure you understand. I apologize if I seem mean. When you use a term, I have to make sure you have it right or I will provide help for something you don't need. Other posters probably handle this better than I do.It's like you intentionally are trying to contradict me on this, but what I mean is that all you do is point to the address.
You're totally right about that. You made no statements in that post that should have made me think you thought tile data had to do with the DMA. Sorry about that.You also said the DMA has nothing to do with the tile data when I didn't make any claims that would lead to that statement.
Primitive wrote: The line is: " LDA sprites, x ; load data from address (sprites + x) "
I said this is badly commented because you are loading the address (sprites + x) into A, not the data.
Being clear, this is the exact code we are talking about:
Code: Select all
sprites:
;vert tile attr horiz
.db $80, $32, $00, $80 ;sprite 0
.db $80, $33, $00, $88 ;sprite 1
.db $88, $34, $00, $80 ;sprite 2
.db $88, $35, $00, $88 ;sprite 3
;and
LoadSprites:
LDX #$00 ; start at 0
LoadSpritesLoop:
LDA sprites, x ; load data from address (sprites + x)
STA $0200, x ; store into RAM address ($0200 + x)
INX ; X = X + 1
CPX #$10 ; Compare X to hex $10, decimal 16
BNE LoadSpritesLoop ; Branch to LoadSpritesLoop if compare was Not Equal to zero
; if compare was equal to 16, continue down
This is the data you are loading: http://wiki.nesdev.com/w/index.php/OAM
One byte for the sprite's y position (vert), one byte for the sprite's tile number(tile), one byte for the sprite's attributes(attr), and one byte for its X position(horiz).
I said earlier that only one of these things can be considered an address, since it refers to something else. (tile) The rest of them are not addresses at all. So you are not loading an address, you are loading those values from the address "sprites" just as the comment says. The address "sprites" itself is never loaded into A like you said, and neither is any other address. I can't personally come up with any one line comment that's any better, since that one does successfully describe what is happening.
If I still have something wrong with what you're talking about, then I'm sorry.
What data? This data?The data would be image data
Code: Select all
sprites:
;vert tile attr horiz
.db $80, $32, $00, $80 ;sprite 0
.db $80, $33, $00, $88 ;sprite 1
.db $88, $34, $00, $80 ;sprite 2
.db $88, $35, $00, $88 ;sprite 3
If you mean something else, let me know. I honestly am trying to help and want to understand what you're asking. I am not trying to contradict you or be spiteful.
This is where I am getting confused. The DMA does not copy CHR, or image data. It copies OAM data to the OAM.where the .chr is copied in your code. You just refer to it, the DMA copies it.
Edit: For programs that don't use CHR-RAM, you almost never refer to the CHR's actual values nor its addresses. This is why I get confused when you say you refer to an image data address or the image data itself. You refer to them EXTREMELY indirectly with tile numbers, but the PPU is the only thing that really does anything with the image data addresses in a direct way.
A DMA copy from $0200 to the PPU's internal OAM memory is slightly more direct, but even then you don't refer to a PPU address at all. The DMA just "knows" where it goes. You only control where it comes from.
If you get that, just roll on to the next thing and we can help with that. I don't mean to question you if you understand.
Okay, it just makes sense to me to think of the data as being what the .chr holds. I see that NerdyNights has sprite data as being the code you referred to, which was different to how I was thinking of data.Kasumi wrote:I'm not trying to contradict you, just make sure you understand. I apologize if I seem mean. When you use a term, I have to make sure you have it right or I will provide help for something you don't need. Other posters probably handle this better than I do.
Background tiles are what I had in mind, where you just put the address of the "information" in the .chr and the attribute table. So I wasn't really thinking of those other values needed to put something on the screen, just the address itself in the .chr of the tile.Kasumi wrote:Being clear, this is the exact code we are talking about:Correct?Code: Select all
sprites: ;vert tile attr horiz .db $80, $32, $00, $80 ;sprite 0 .db $80, $33, $00, $88 ;sprite 1 .db $88, $34, $00, $80 ;sprite 2 .db $88, $35, $00, $88 ;sprite 3 ;and LoadSprites: LDX #$00 ; start at 0 LoadSpritesLoop: LDA sprites, x ; load data from address (sprites + x) STA $0200, x ; store into RAM address ($0200 + x) INX ; X = X + 1 CPX #$10 ; Compare X to hex $10, decimal 16 BNE LoadSpritesLoop ; Branch to LoadSpritesLoop if compare was Not Equal to zero ; if compare was equal to 16, continue down
Yes, however what confused me was that single comment after that single load to the accumulator.Kasumi wrote:This is the data you are loading: http://wiki.nesdev.com/w/index.php/OAM
One byte for the sprite's y position (vert), one byte for the sprite's tile number(tile), one byte for the sprite's attributes(attr), and one byte for its X position(horiz).
But the NerdyNights comment did say that the data was being loaded into A in the quote I posted above. Maybe he meant during the whole segment that's what would be done, but that comment put me off.Kasumi wrote:I said earlier that only one of these things can be considered an address, since it refers to something else. (tile) The rest of them are not addresses at all. So you are not loading an address, you are loading those values from the address "sprites" just as the comment says. The address "sprites" itself is never loaded into A like you said, and neither is any other address. I can't personally come up with any one line comment that's any better, since that one does successfully describe what is happening.
I agree of course it's not image data or addresses that refer to CHR data. I do not know what I would call it. Sprite "properties" maybe. If you call it "sprite data" it seems reasonable. If you talk about the data of a database, I would call the data the actual records, not the location of where it is on the disc, how it should be opened etc.... maybe what I was thinking of was "tile data" rather than "sprite data". But if sprite data is just the properties of that sprite, then you would have to say that it's the same sprite even if you change the .chr file or .bank...Kasumi wrote:
What data? This data?That is not image data. It is also not addresses that refer to CHR data.Code: Select all
sprites: ;vert tile attr horiz .db $80, $32, $00, $80 ;sprite 0 .db $80, $33, $00, $88 ;sprite 1 .db $88, $34, $00, $80 ;sprite 2 .db $88, $35, $00, $88 ;sprite 3
If you mean something else, let me know. I honestly am trying to help and want to understand what you're asking. I am not trying to contradict you or be spiteful.
I appreciate your input a lot, I find this way a much nicer way of becoming familiar with these concepts and operands etc. than just staring at the screen.
Something copies the CHR data because of what you point to into your code. I don't know if it's possible to "draw" the data yourself pixel-by-pixel without any CHR. I thought of sprite/image data as being like what you would see if you opened an uncompressed bitmap or tga file in a hex editor.Kasumi wrote:This is where I am getting confused. The DMA does not copy CHR, or image data. It copies OAM data to the OAM.
Kasumi wrote:Edit: For programs that don't use CHR-RAM, you almost never refer to the CHR's actual values nor its addresses. This is why I get confused when you say you refer to an image data address or the image data itself. You refer to them EXTREMELY indirectly with tile numbers, but the PPU is the only thing that really does anything with the image data addresses in a direct way.
A DMA copy from $0200 to the PPU's internal OAM memory is slightly more direct, but even then you don't refer to a PPU address at all. The DMA just "knows" where it goes. You only control where it comes from.
If you get that, just roll on to the next thing and we can help with that. I don't mean to question you if you understand.
Okay, I'm getting somewhere. Many thanks for your help. 8)
I assumed from some stuff that we were talking about sprites. So a lot of what I said wasn't helpful.
Let's start over.
Anytime you want to write a value anywhere in the PPU's memory, you write its address to $2006 in two writes. Then write the byte you want stored at that address to $2007.
Sets the PPU address you'll write or read from to $2000.
Then you load whatever value you want at that address and store it to $2007. Next time you write to $2007 it will either increment by one (to $2001 in this case), or 32 (to $2020 in this case) depending on bit 2 of $2000 (register $2000 on the CPU, not the PPU). This is done so you don't have to write to $2006 millions of time when you're updating a row or column of tiles.
You should only write to these register when rendering is disabled, or during your NMI routine. Otherwise your program will gloriously crash and burn.
I think that should sort of answer the question you had in your first post.
Now. The first 960 bytes of each nametable contain the tile NUMBERS to be displayed. If you want to change the tile at the top left of the screen, write #$20 then #$00 to $2006, and the tile number you want to change it to to $2007 like the above code. It's the same to update anything in the PPU memory (except sprites
). Address in $2006. Values to $2007.
While you can .db the addresses, it's not a great idea since it wastes space.
Anyway, with that in mind, if you want to change the actual tile's graphic data so that all bytes in the nametable that currently refer to that tile will change when the screen is next drawn: You write the address of the tile to $2006. ($0000 would be the first tile) Then write the 16 bytes of CHR-Data to $2007. Every tile is 16 bytes large, so if you want a specific one it's x * 16.
Fairly simple logic, but somewhat hard to program well. I would not recommend messing with it right now, but that's really most of the info you need+the below
Now. For updating the actual tiles you need to set the number of CHR-ROM banks to 0. (You can't change ROM, of course. This makes it so that the CHR is RAM and can be written to). Then you have to include your chr file in a bank dedicated to the actual program. Then you read from it, and write it to the CHR section of the PPU, and update it as desired at run time.
Again, I wouldn't mess with CHR-RAM right now, but that's how you do it.
Okay. Here's the PPU memory map. http://wiki.nesdev.com/w/index.php/PPU_memory_mapSo I wasn't really thinking of those other values needed to put something on the screen, just the address itself in the .chr of the tile.
Anytime you want to write a value anywhere in the PPU's memory, you write its address to $2006 in two writes. Then write the byte you want stored at that address to $2007.
Code: Select all
lda #$20
sta $2006
lda #$00
sta $2006
Then you load whatever value you want at that address and store it to $2007. Next time you write to $2007 it will either increment by one (to $2001 in this case), or 32 (to $2020 in this case) depending on bit 2 of $2000 (register $2000 on the CPU, not the PPU). This is done so you don't have to write to $2006 millions of time when you're updating a row or column of tiles.
You should only write to these register when rendering is disabled, or during your NMI routine. Otherwise your program will gloriously crash and burn.
I think that should sort of answer the question you had in your first post.
Now. The first 960 bytes of each nametable contain the tile NUMBERS to be displayed. If you want to change the tile at the top left of the screen, write #$20 then #$00 to $2006, and the tile number you want to change it to to $2007 like the above code. It's the same to update anything in the PPU memory (except sprites
While you can .db the addresses, it's not a great idea since it wastes space.
Anyway, with that in mind, if you want to change the actual tile's graphic data so that all bytes in the nametable that currently refer to that tile will change when the screen is next drawn: You write the address of the tile to $2006. ($0000 would be the first tile) Then write the 16 bytes of CHR-Data to $2007. Every tile is 16 bytes large, so if you want a specific one it's x * 16.
Fairly simple logic, but somewhat hard to program well. I would not recommend messing with it right now, but that's really most of the info you need+the below
Now. For updating the actual tiles you need to set the number of CHR-ROM banks to 0. (You can't change ROM, of course. This makes it so that the CHR is RAM and can be written to). Then you have to include your chr file in a bank dedicated to the actual program. Then you read from it, and write it to the CHR section of the PPU, and update it as desired at run time.
Again, I wouldn't mess with CHR-RAM right now, but that's how you do it.
As far as the CPU is concerned, it's loading data. The fact that this data is a value that will be used to index some other data (a CHR pattern, in the case of the 2nd byte of each OAM entry, the other bytes don't reference anything) is irrelevant to the CPU, it's just a technical aspect of the video hardware.Primitive wrote:I said this is badly commented because you are loading the address (sprites + x) into A, not the data.
The CHR patterns are not automatically copied by the NES, ever. They stay in one place the whole time, and whenever the PPU needs to draw them it looks for them in that place. For example, when redering backgrounds the PPU goes like "I see that you want to show tile number $3A because this is the value in the name table, so I'll just look for the correct pattern in the pattern tables and draw it to the screen", it doesn't copy anything. The same goes for sprites... when the PPU sees that you want to draw tile number $2B at coordinates (120, 72) it quickly fetches the patterns for tile $2B from the pattern tables and draws them to the screen.Something copies the CHR data because of what you point to into your code.