8x16 and whatever else unreg wants to know

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

3gengames
Formerly 65024U
Posts: 2284
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

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. :)
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

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: Select all

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: Select all

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: Select all

     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: Select all

zeropageinitialvalues:  incbin "zeropagebinary.bin"
Then you run code like what 3gengames wrote.

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
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.
3gengames
Formerly 65024U
Posts: 2284
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

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.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

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: Select all

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: Select all

enum $0000

;(...)
oX .dsb 1
oY .dsb 1
And then, before using those variables in the program you have to initialize them:

Code: Select all

	lda #$8b
	sta oX
	sta oY
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

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: Select all

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: Select all

enum $0000

;(...)
oX .dsb 1
oY .dsb 1
And then, before using those variables in the program you have to initialize them:

Code: Select all

	lda #$8b
	sta oX
	sta oY
I understand at least most of that, but for this code:
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.
3gengames
Formerly 65024U
Posts: 2284
Joined: Sat Mar 27, 2010 12:57 pm

Post by 3gengames »

LDA #$NUMBER
STA Label

Wil make it equal what you need it to, you HAVE TO do that.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

unregistered wrote:
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.
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.
User avatar
booker
Posts: 10
Joined: Sun Jul 31, 2011 11:53 am
Location: Canada

Post by booker »

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.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

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.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

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.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

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. : )
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

ahhh, the girl starts at (#$8b, #$8b) now!!!!!!!!!!!!!!!!!!! Tomorrow is going to be great! S cr oll in g!!! :)
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

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. :?
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

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.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

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.
[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.
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? :)
Last edited by unregistered on Sat Aug 27, 2011 4:37 pm, edited 1 time in total.
Post Reply