8x16 and whatever else unreg wants to know
Moderator: Moderators
Okay. Here's a quick crash course.
So this is what an assembler does: It creates a sequence of bytes based on the instructions you give it.
becomes $78, $A2, $00. This is rom. If you opened your assembled rom in a hex editor and searched for this byte sequence you would find it. A guide like this: http://www.obelisk.demon.co.uk/6502/reference.html
Tells you what byte each instruction is assembled as, but that is not that important.
The next thing to know, is a label doesn't actually take any rom. What takes up space are references to it. In the code above, reset takes no rom. References to it are actually stored with the instruction.
So this:
would be assembled as
$78, $A2, $00, $AD, (low byte of reset), (high byte of reset).
All these bytes are actually part of your games binary (the .nes rom), so they are rom. To further bring this home, you can actually load an instruction's opcode. Remember how I said sei becomes $78?
So what do you think is stored in the accumulator when I lda reset in the code above? $78. lda reset+1? $A2.
When you directly load a number (lda #$00), the actual number (here it's 0) is stored in rom. $A9, $00 would be what is assembled. When you're referring to an address, you don't include the # part.
RAM is $0000-$07FF. Whenever you load a number from any of those locations, you're loading from RAM. These numbers can be changed. To put actual code in RAM is easy. You just look up the opcodes. Remember the byte stream of the code above?
$78, $A2, $00 was sei, ldx #$00
This stores code into RAM, then jmps there and runs it. The NES CPU makes no distinction between RAM and ROM when it's running through instructions.
RAM can't be changed before the program is run. If you want a location in RAM to be a certain number, you need to set it to that number at startup. It's as easy as loading the number you want, and storing it there. If you want to load the number from rom, you can incbin a byte stream, and load each value then store it in RAM, but I just use immediate addressing. What I think is being suggested to you is something like this:
You want ram locations $00, $01, $02, $03 to contain $F3, $FD, $08, $23 respectively. So you create a binary file that contains the bytes $F3, $FD, $08, and $23.
Then you incbin that file after an address.
Then you run code like what 3gengames wrote.
For reference, I'd just do this:
since it's easier to change a number, and you won't necessarily be storing numbers so sequentially.
If I were you, I would try to read and understand thing like the difference between lda #$00 and lda $00 before doing anything else. I might also try to completely rewrite whatever you've got, since if you didn't know this stuff, it has gotta be messy.
So this is what an assembler does: It creates a sequence of bytes based on the instructions you give it.
Code: Select all
reset:
sei
ldx #$00
Tells you what byte each instruction is assembled as, but that is not that important.
The next thing to know, is a label doesn't actually take any rom. What takes up space are references to it. In the code above, reset takes no rom. References to it are actually stored with the instruction.
So this:
Code: Select all
reset:
sei
ldx #$00
lda reset
$78, $A2, $00, $AD, (low byte of reset), (high byte of reset).
All these bytes are actually part of your games binary (the .nes rom), so they are rom. To further bring this home, you can actually load an instruction's opcode. Remember how I said sei becomes $78?
So what do you think is stored in the accumulator when I lda reset in the code above? $78. lda reset+1? $A2.
When you directly load a number (lda #$00), the actual number (here it's 0) is stored in rom. $A9, $00 would be what is assembled. When you're referring to an address, you don't include the # part.
RAM is $0000-$07FF. Whenever you load a number from any of those locations, you're loading from RAM. These numbers can be changed. To put actual code in RAM is easy. You just look up the opcodes. Remember the byte stream of the code above?
$78, $A2, $00 was sei, ldx #$00
Code: Select all
lda #$78
sta $00
lda #$A2
sta $01
lda #$00
sta $02
jmp $0000
RAM can't be changed before the program is run. If you want a location in RAM to be a certain number, you need to set it to that number at startup. It's as easy as loading the number you want, and storing it there. If you want to load the number from rom, you can incbin a byte stream, and load each value then store it in RAM, but I just use immediate addressing. What I think is being suggested to you is something like this:
You want ram locations $00, $01, $02, $03 to contain $F3, $FD, $08, $23 respectively. So you create a binary file that contains the bytes $F3, $FD, $08, and $23.
Then you incbin that file after an address.
Code: Select all
zeropageinitialvalues: incbin "zeropagebinary.bin"
For reference, I'd just do this:
Code: Select all
lda #$F3
sta $00
lda #$FD
sta $01
lda #$08
sta $02
lda #$23
sta $03
If I were you, I would try to read and understand thing like the difference between lda #$00 and lda $00 before doing anything else. I might also try to completely rewrite whatever you've got, since if you didn't know this stuff, it has gotta be messy.
unregistered, you appear to be very lost, and not clear enough about what you want.
RAM is where your variables (i.e. dynamic data) sit. Variables are values that will change as the program runs, such as the positions of objects, number of lives, things like that. RAM is always "empty" (it's not really empty, but since its contents are somewhat random we should think of it as empty, although the correct term is "uninitialized") when the NES first starts. Before using our variables, we must initialize them.
When you do this:
You are just telling the assembler where your variables should be stored. currControllerButtons will be at memory location $0000 and lastControllerButtons will be at memory location $0001. This simply declares the variables but they will be uninitiated when the program starts, so you have to initialize them yourself in the code. Nobody is gonna do it for you. So in order to do what you want you have to first declare the variables:
And then, before using those variables in the program you have to initialize them:
RAM is where your variables (i.e. dynamic data) sit. Variables are values that will change as the program runs, such as the positions of objects, number of lives, things like that. RAM is always "empty" (it's not really empty, but since its contents are somewhat random we should think of it as empty, although the correct term is "uninitialized") when the NES first starts. Before using our variables, we must initialize them.
When you do this:
Code: Select all
enum $0000
currControllerButtons .dsb 1
lastControllerButtons .dsb 1
Code: Select all
enum $0000
;(...)
oX .dsb 1
oY .dsb 1
Code: Select all
lda #$8b
sta oX
sta oY
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Thank you everyone for helping.
I understand at least most of that, but for this code:tokumaru wrote:unregistered, you appear to be very lost, and not clear enough about what you want.
RAM is where your variables (i.e. dynamic data) sit. Variables are values that will change as the program runs, such as the positions of objects, number of lives, things like that. RAM is always "empty" (it's not really empty, but since its contents are somewhat random we should think of it as empty, although the correct term is "uninitialized") when the NES first starts. Before using our variables, we must initialize them.
When you do this:
You are just telling the assembler where your variables should be stored. currControllerButtons will be at memory location $0000 and lastControllerButtons will be at memory location $0001. This simply declares the variables but they will be uninitiated when the program starts, so you have to initialize them yourself in the code. Nobody is gonna do it for you. So in order to do what you want you have to first declare the variables:Code: Select all
enum $0000 currControllerButtons .dsb 1 lastControllerButtons .dsb 1
And then, before using those variables in the program you have to initialize them:Code: Select all
enum $0000 ;(...) oX .dsb 1 oY .dsb 1
Code: Select all
lda #$8b sta oX sta oY
How could one get that code to work successfully? Why doesn't oX equal #$8b? Those are the two questions that went through my head... I'm sorry for my muddiness tonight. My time sheet says I've worked over 10 hours on the "game" today... too long... time to sleep.oX .dsb 1,#$8b
Forget about this code, this is not how you do it! You simply can't declare the variable and give it a value at the same time, in assembly this is impossible (if someone mentions machines that load code into RAM only to confuse unregistered even more, I'll kill you). This has to be done in two steps: first declare the variable and later in the code you give it a value.unregistered wrote:How could one get that code to work successfully?oX .dsb 1,#$8b
Because RAM is uninitialized on start up, period. There's no way to change that. No matter what value you try to assign it, the variable will always contain an unpredictable value on start up, this is just how RAM works. You absolutely must use LDA / STA to assign values to your variables.Why doesn't oX equal #$8b?
I'll do my take on this.
Imagine a big deal of equally-sized boxes, like at a post office.
That's RAM.
When the "world starts", they're all empty. Completely empty, with nothing in them*. All the boxes are numbered, of course, but these numbers... are not terribly helpful. What we need are some labels. So, we take out the dymo-tape...
...and start labeling! In ASM6, when you do .dsb and .dsw in the .enum range of $0000-$07FF, this is exactly what you're doing: labeling. That way, when you get your instructions, they can be written in the form "put this letter in the box for Mr. Howe" as opposed to "put this letter in the 53rd box." Note that you can reserve multiple boxes this way.
Of course, the act of putting a letter in to the box doesn't just happen. You have to do it yourself! The world starts and all the boxes are empty (or "uninitialiazed" as tokumaru pointed out).
As before, in your initiation code before any of the actual action happens, just load whatever value into the accumulator (LDA #letter) you want and then store it in the RAM (sta MR_HOWE).
Finally note that .dsb and .dsw are general purpose and can be used to flood the ROM (the part of the game that is "written in stone") with values. That's what you're trying to do in RAM but this operation only works for ROM. In other words, that use of those directives only works on addresses $8000-$FFFF (or if you use more than one PRG bank and/or a mapper, whatever is applicable then).
* - not necessarily true; may have garbage values that are not zero. Check standard init code. The samples you'll find have a place to reset all RAM to zero.
Imagine a big deal of equally-sized boxes, like at a post office.
That's RAM.
When the "world starts", they're all empty. Completely empty, with nothing in them*. All the boxes are numbered, of course, but these numbers... are not terribly helpful. What we need are some labels. So, we take out the dymo-tape...
...and start labeling! In ASM6, when you do .dsb and .dsw in the .enum range of $0000-$07FF, this is exactly what you're doing: labeling. That way, when you get your instructions, they can be written in the form "put this letter in the box for Mr. Howe" as opposed to "put this letter in the 53rd box." Note that you can reserve multiple boxes this way.
Of course, the act of putting a letter in to the box doesn't just happen. You have to do it yourself! The world starts and all the boxes are empty (or "uninitialiazed" as tokumaru pointed out).
As before, in your initiation code before any of the actual action happens, just load whatever value into the accumulator (LDA #letter) you want and then store it in the RAM (sta MR_HOWE).
Finally note that .dsb and .dsw are general purpose and can be used to flood the ROM (the part of the game that is "written in stone") with values. That's what you're trying to do in RAM but this operation only works for ROM. In other words, that use of those directives only works on addresses $8000-$FFFF (or if you use more than one PRG bank and/or a mapper, whatever is applicable then).
* - not necessarily true; may have garbage values that are not zero. Check standard init code. The samples you'll find have a place to reset all RAM to zero.
Load and run addresses for segment ".DATA". Kill Ullrich von Bassewitz.tokumaru wrote:You simply can't declare the variable and give it a value at the same time, in assembly this is impossible (if someone mentions machines that load code into RAM only to confuse unregistered even more, I'll kill you).
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
Ok, so I'm at the point now where I'm tryiing to write the code. My first goal is to get the screen to scroll to the next nametable as our character makes her way across the floor she starts on. This is susposed to be an easy goal to achieve. So far:
1.) I've set the PPU to mirror the nametables vertically.
2.) Both nametables have been set up correctly.
3.) Our lady character moves forward and backward very easily because the sound really works now.
The next step to reach my goal is to check if the lady character is far enough over to the right of the screen (then scrollling starts). I'm going to use an iterative construct to acomplish that. Is scroll always at the bottom left corner of the screen? If scroll is incremented every frame the screen scrolls over to the left. If the screen can make it over to 255 most of all of the second nametable would be shown. But you have to switch which nametable is on the left to get the rest of the second nametable to appear.
1.) I've set the PPU to mirror the nametables vertically.
2.) Both nametables have been set up correctly.
3.) Our lady character moves forward and backward very easily because the sound really works now.
The next step to reach my goal is to check if the lady character is far enough over to the right of the screen (then scrollling starts). I'm going to use an iterative construct to acomplish that. Is scroll always at the bottom left corner of the screen? If scroll is incremented every frame the screen scrolls over to the left. If the screen can make it over to 255 most of all of the second nametable would be shown. But you have to switch which nametable is on the left to get the rest of the second nametable to appear.
The X,Y coordinate in the scroll register is that of the pixel at the top left corner of the screen, which does happen to be more or less equivalent to the bottom left corner but only in single-screen or vertical mirroring. To switch which nametable is at the top left corner, use bits 1 and 0 of PPUCTRL ($2000). One might think of these as the high bits of the scroll register.
-
- Posts: 1318
- Joined: Thu Apr 23, 2009 11:21 pm
- Location: cypress, texas
I still don't understand why does the nametable on the left have to be switched for the right side of the second nametable to appear? I stopped my scroll at 255 and it is already showing most all of the second nametable. I'm so confused.
Thank you for reminding me it's the top left pixel! That helps! And it's nice to know that I can think of it being the bottom left corner because I'm not horizontally mirroring.
Thank you for reminding me it's the top left pixel! That helps! And it's nice to know that I can think of it being the bottom left corner because I'm not horizontally mirroring.
[url=http://www.nintendoage.com/forum/messageview.cfm?catid=22&threadid=36958]Here,[/url] bunnyboy wrote:To set the starting nametable, change bit 0 of the PPU control register at $2000. Clearing it to 0 will put nametables 0 and 2 on the left side of the screen with 1 and 3 to the right. Setting it to 1 will put 1 and 3 on the left, and 0 and 2 on the right.
So setting bits 1 and 0 of PPUCTRL to 10 will put nametables 2 and 0 on the left and 3 and 1 to the right? And setting PPUCTRL to xxxxxx11 will put nametables 3 and 1 on the left and 2 and 0 on the right?tepples wrote:To switch which nametable is at the top left corner, use bits 1 and 0 of PPUCTRL ($2000).
Last edited by unregistered on Sat Aug 27, 2011 4:37 pm, edited 1 time in total.