nesdev.com
https://forums.nesdev.com/

8x16 and whatever else unreg wants to know
https://forums.nesdev.com/viewtopic.php?f=10&t=7451
Page 17 of 93

Author:  3gengames [ Mon Aug 22, 2011 6:47 pm ]
Post subject: 

If you make the first byte a BRANCH to the part of the program you want, you can just so JMP Label and it'll run the code from RAM. :)

Author:  Kasumi [ Mon Aug 22, 2011 7:13 pm ]
Post subject: 

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.

Code:
reset:
     sei
     ldx #$00


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:
Code:
reset:
     sei
     ldx #$00
     lda reset

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

Code:
     lda #$78
     sta $00
     lda #$A2
     sta $01
     lda #$00
     sta $02
     jmp $0000

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.

Code:
zeropageinitialvalues:  incbin "zeropagebinary.bin"


Then you run code like what 3gengames wrote.

For reference, I'd just do this:
Code:
     lda #$F3
     sta $00
     lda #$FD
     sta $01
     lda #$08
     sta $02
     lda #$23
     sta $03

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.

Author:  3gengames [ Mon Aug 22, 2011 7:18 pm ]
Post subject: 

And also, I said use a branch because while you can only go about 127 bytes in either direction, the position doesn't matter wherever it is, while jumps will ALWAYS goto where it was compiled to go to weather it was moved or not.

Author:  tokumaru [ Mon Aug 22, 2011 8:01 pm ]
Post subject: 

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:

Code:
enum $0000

currControllerButtons .dsb 1
lastControllerButtons .dsb 1

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:
enum $0000

;(...)
oX .dsb 1
oY .dsb 1

And then, before using those variables in the program you have to initialize them:

Code:
   lda #$8b
   sta oX
   sta oY

Author:  unregistered [ Mon Aug 22, 2011 9:15 pm ]
Post subject: 

Thank you everyone for helping.

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:

Code:
enum $0000

currControllerButtons .dsb 1
lastControllerButtons .dsb 1

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:
enum $0000

;(...)
oX .dsb 1
oY .dsb 1

And then, before using those variables in the program you have to initialize them:

Code:
   lda #$8b
   sta oX
   sta oY


I understand at least most of that, but for this code:
Quote:
oX .dsb 1,#$8b
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.

Author:  3gengames [ Mon Aug 22, 2011 9:17 pm ]
Post subject: 

LDA #$NUMBER
STA Label

Wil make it equal what you need it to, you HAVE TO do that.

Author:  tokumaru [ Mon Aug 22, 2011 10:01 pm ]
Post subject: 

unregistered wrote:
Quote:
oX .dsb 1,#$8b
How could one get that code to work successfully?

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.

Quote:
Why doesn't oX equal #$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.

Author:  booker [ Mon Aug 22, 2011 11:39 pm ]
Post subject: 

I'll do my take on this.

Imagine a big deal of equally-sized boxes, like at a post office.

Image
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...
Image

...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.

Author:  tepples [ Tue Aug 23, 2011 5:30 am ]
Post subject: 

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).

Load and run addresses for segment ".DATA". Kill Ullrich von Bassewitz.

Author:  tokumaru [ Tue Aug 23, 2011 6:07 am ]
Post subject: 

That's a very good analogy, booker. Hopefully this ought to get message across.

BTW, tepples, I knew you'd be the one to do it.

Author:  unregistered [ Tue Aug 23, 2011 6:42 pm ]
Post subject: 

Ah! Yes, booker, great analogy! Thank you so much! :D It really helped me recieve the entire message that yall were trying to give me! RAM is not ROM, it always starts uninitalized. :)

tokumaru, my friend, please don't kill tepples. : ) I didn't follow his link. : )

Author:  unregistered [ Tue Aug 23, 2011 8:13 pm ]
Post subject: 

ahhh, the girl starts at (#$8b, #$8b) now!!!!!!!!!!!!!!!!!!! Tomorrow is going to be great! S cr oll in g!!! :)

Author:  unregistered [ Sat Aug 27, 2011 11:59 am ]
Post subject: 

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. :?

Author:  tepples [ Sat Aug 27, 2011 12:24 pm ]
Post subject: 

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.

Author:  unregistered [ Sat Aug 27, 2011 4:08 pm ]
Post subject: 

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! :D 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.

Here, 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.

tepples wrote:
To switch which nametable is at the top left corner, use bits 1 and 0 of PPUCTRL ($2000).

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? :)

Page 17 of 93 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/