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

unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

tokumaru wrote:RTS without JSR is indeed a nasty bug, you have to be careful about that. If a return address wasn't put on the stack, the RTS will get anything that is at the top of the stack and jump to a bad location.
Yes, thank you :) , I agree... maybe the same thing happens here... it reaches the rts at the bottom and then pulls $37 and $C0 off the stack and goes to $C201 ???? Why?????????????????????????

Then $C201 is listed as "UNDEFINED" (because that instruction starts at $C200) and so then it runs an incorrect byte again ($C203, shows "PLP"). Then it runs the code at $C204
sta $0029. Something happens next I don't understand why! :( It ends up at $C336 RTI and never does anything else... :?

Code: Select all

0C15E                           see:  
0C15E                           
0C15E A0 00                       ldy #$00
0C160 A2 00                       ldx #$00
0C162 A9 91                       lda #<lvl1Screen1start
0C164 85 10                       sta $10
0C166 A9 C8                       lda #>lvl1Screen1start
0C168 85 11                       sta $11
0C16A                           
0C16A                           
0C16A A9 20                       lda #$20
0C16C 8D 06 20                    sta $2006;Sets the high byte of the address $2007 will write to.
0C16F A9 00                       lda #$00
0C171 8D 06 20                    sta $2006;Sets the low bylte of the address $2007 will write to.
0C174                             
0C174                             ;a is still 0
0C174 85 20                       sta r 
0C176 48                          pha ;--------------------------->
0C177                           
0C177 B6 10                     -- ldx ($10), y
0C179 BD 57 C3                    lda MetatileTile0, x
0C17C 8D 07 20                    sta $2007;Writes to PPU address $2000. (which is the first tile of the first name table)
0C17F BD 36 C4                    lda MetatileTile1, x
0C182 8D 07 20                    sta $2007;Writes to PPU address $2001. (which is the tile to the right of the first tile)
0C185 C8                          iny
0C186 E6 20                       inc r
0C188                           ;  pla ;<--------------------------
0C188                           ;  tax
0C188                           ;  inx
0C188                           ;  txa
0C188                           ;  pha ;-------------------------->
0C188 A5 20                       lda r
0C18A 29 0F                       and #00001111b
0C18C F0 03                       beq +          ;branch if it a multiple of 16
0C18E 4C 77 C1                    jmp --
0C191                             
0C191                           
0C191 C8                        +  iny  
0C192                             
0C192 B6 10                     -  ldx ($10), y
0C194 BD 15 C5                    lda MetatileTile2, x
0C197 8D 07 20                    sta $2007;Writes to PPU address $2010. (which is the third tile, first tile on second row, of the first name table)
0C19A BD F4 C5                    lda MetatileTile3, x
0C19D 8D 07 20                    sta $2007;Writes to PPU address $2011. (which is the tile to the right of the third tile)
0C1A0 C8                          iny
0C1A1 E6 20                       inc r
0C1A3                           ;  pla ;<--------------------------
0C1A3                           ;  tax
0C1A3                           ;  inx
0C1A3                           ;  txa
0C1A3                           ;  pha ;--------------------------->
0C1A3 A5 20                       lda r
0C1A5 C9 F0                       cmp #11110000b ;if (r >= 240)
0C1A7 90 07                       bcc +done
0C1A9 29 0F                       and #00001111b
0C1AB F0 CA                       beq --
0C1AD 4C 92 C1                    jmp -
0C1B0                           
0C1B0                           +done:  
0C1B0 60                          rts 0C1B1    
Kasumi wrote:I'm not 100% clear. You're saying fceux's debugger is stopping your code at $C336 despite you not having any active breakpoints? That's pretty strange. Is break on bad opcode checked? That's about my only guess. Are there any problems on a different emulator? Does anything else "run into" that RTI?
Something like:

Code: Select all

NMI:
   ;NMI code here, without an rti
IRQ
   RTI
?
No, break on bad opcode isn't checked. No, right before the rti is an rts.
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

Code: Select all

0C1A3                           ;  pha ;--------------------------->
0C1A3 A5 20                       lda r
0C1A5 C9 F0                       cmp #11110000b ;if (r >= 240)
0C1A7 90 07                       bcc +done
0C1A9 29 0F                       and #00001111b
0C1AB F0 CA                       beq --
0C1AD 4C 92 C1                    jmp -
0C1B0                           
0C1B0                           +done:  
0C1B0 60                          rts 0C1B1    
I could be wrong about this (I sorta have trouble following + and - branches):

Edit: CPOW points out the PHA here is commented out. I don't believe in mangling my posts even when I'm wrong, so see my next post for another guess.

Let's pretend we're at this point in the code. We push a value to the stack. We load 'r'. 'r' is less than #%11110000. We brach to done because the carry is clear. We RTS.

But the value we pushed to the stack is never pulled off. This is super bad, because then we return to the wrong place.

Example:

We jsr to the routine. On the top of the stack is: $00 $80. If we RTS'd right away, we'd return there.

But if you push something else to the stack (like $56 or whatever else) without pulling it off, your stack looks like this. $56 $00 $80. And you'll RTS to $0056(-1?) instead of where you jsr'd from.

Edit: I don't see much need to use pha and pla at all, but I may be missing something in the logic. It seems that a zero page variable would work just as well for this code, and would actually end up faster (but larger) and you wouldn't need to worry about stack corruption. PHA would become sta sometempvariable, and PLA would become lda sometempvariable. And I think it would work exactly the same.
Last edited by Kasumi on Fri May 04, 2012 4:14 pm, edited 2 times in total.
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

Kasumi wrote:

Code: Select all

0C1A3                           ;  pha ;--------------------------->
0C1A3 A5 20                       lda r
[/quote]

The [code]pha
is commented out...
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

Oh, weird. Sorry, then. I assumed it was a disassembly, so I wasn't looking for comments. The addresses should have still been a clue, though. I'll keep looking then.

Edit: Maybe the issue is that he forgot to comment out one pha, then? There's one pha still uncommented, and I don't see a corresponding uncommented pla.
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

Kasumi wrote: Edit: Maybe the issue is that he forgot to comment out one pha, then? There's one pha still uncommented, and I don't see a corresponding uncommented pla.
Certainly looks that way.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

unregistered, it seems to me that all your problems are stack-related. Double check everything you do with it (pay attention to all PHA, PLA, JSR, RTS and RTI instructions) and make sure that everything that's put on the stack is pulled back in the proper order.

Avoid using PHA/PLA in places with lots of decisions (conditional branches), because depending on the combination of taken branches it's easy to forget data on the stack or pull more than was put there in the first place.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

cpow wrote:
Kasumi wrote: Edit: Maybe the issue is that he forgot to comment out one pha, then? There's one pha still uncommented, and I don't see a corresponding uncommented pla.
Certainly looks that way.
Thank you so much Kasumi! :D All your work is really helpful to me. And thank you cpow for helping us again too; you're quite kind. :)
It was that way... now after commenting out that pha it works kind of well! There's a screen now... it's not displaying correctly but it shows up and you can see/move the character again. :)

tokumaru wrote:unregistered, it seems to me that all your problems are stack-related. Double check everything you do with it (pay attention to all PHA, PLA, JSR, RTS and RTI instructions) and make sure that everything that's put on the stack is pulled back in the proper order.

Avoid using PHA/PLA in places with lots of decisions (conditional branches), because depending on the combination of taken branches it's easy to forget data on the stack or pull more than was put there in the first place.
Thank you so much tokumaru! :D I will try tomorrow, what you've told me here, to make the screen appear correctly, i hope.

Yall are awesome! :D
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

About Attribute Tables
Kasumi[color=brown], on page 29,[/color] wrote:For attributes, you do kind of the same thing. Write the address of the attribute tile you want to update to $2006, then write the actual attribute to $2007. Because of your metatile format, this might actually be really easy for you to figure out. (It's hard as hell to do in my format :lol: ... I digress)

That's... about all I will say. Good luck! Try it, and post some code if you get stuck!
[color=violet]...from [/color][url=http://wiki.nesdev.com/w/index.php/Attribute_table]here[/url] wrote:

Code: Select all

value = (topleft << 0) | (topright << 2) | (bottomleft << 4) | (bottomright << 6)

Code: Select all

,---+---+---+---.
|   |   |   |   |
+ D1-D0 + D3-D2 +
|   |   |   |   |
+---+---+---+---+
|   |   |   |   |
+ D5-D4 + D7-D6 +
|   |   |   |   |
`---+---+---+---'
Ok this is how I understand this now...
1.) Each byte has bits in this order: 76543210

2.) So starting with each corner palette being a binary 2bit value (0,1,2,or 3) at the bottom of a byte (i.e. #000000XXb)

3.) and from the first line of code in the ...from box, each << X means shift left X spaces.
And each | means or.
TRUE or TRUE = TRUE
TRUE or FALSE = TRUE
FALSE or TRUE = TRUE
FALSE or FALSE = FALSE

4.) Starting out
top left = #000000XXb
top right = #000000XXb
bottom left =#000000XXb
bottom right =#000000XXb

5.) After shifting left
top left = #000000XXb
top right = #0000XX00b
bottom left =#00XX0000b
bottom right =#XX000000b

6.) After oring
value = #XXXXXXXXb

...this is here to remind me of this cause I always get confused over this. Hope it helps a few of yall too. :)
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

Is there an assembly case statement? How would you code this:

Code: Select all

case bla
    0: (run code for zero) 
    1: (run code for one)
    2: (run code for two)
    3: (run code for three)
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Yes. It's called a jump table.
User avatar
cpow
NESICIDE developer
Posts: 1097
Joined: Mon Oct 13, 2008 7:55 pm
Location: Minneapolis, MN
Contact:

Post by cpow »

unregistered wrote:Is there an assembly case statement? How would you code this:

Code: Select all

case bla
    0: (run code for zero) 
    1: (run code for one)
    2: (run code for two)
    3: (run code for three)
I decided to find out what CC65 does. I borrowed AlterEgo code and added a simple switch statement to see. Note, the assembly displayed is not contiguous...almost to the point of being utterly confusing. But that's what you get with mixed-mode disassembly/source views.

$9ABF: load switch comparison value into A.
$9AC2-$9ACA: case comparisons with compare and branch-if-equal to case handling code.
$9ACD-$9AD4: case 1 handling code.
$9AD7-$9AE1: case 2 handling code.
$9AE2: default fall-through.

Image

There certainly are many other ways to skin this cat. EDIT: The previous statement is meant as a deterrent to those quick to reply that the solution I posted is suboptimal. :D
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

unregistered wrote:Is there an assembly case statement?
Assembly doesn't have this kind of complex structures. In assembly, everything is branches and jumps based on the results of calculations/comparisons.

If you have just a few cases you can just use a few CMPs and branches, but with lots of possible cases it's better to use a jump table, or else it will be too slow.
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

Code: Select all

;y contains the case number
lda jumptablelow,y
sta tempaddress
lda jumptablehigh,y
sta tempaddress+1

jmp [tempaddress]

jumptablehigh:
.db high(case0)
.db high(case1)
.db high(case2)
jumptablelow:
.db low(case0)
.db low(case1)
.db low(case2)
case0:

case1:

case2:
Underneath each case label would be the code corresponding to the case. Then, we store the addresses of all the cases in two tables. We load the low and high byte of the address we want, and store them in two contiguous bytes in low/high order. Then we jmp indirect to byte where the low part of the address was stored which will take us to the case label.

There's actually a small bug with the 6502 jmp indirection instruction. From here:

An original 6502 has does not correctly fetch the target address if the indirect vector falls on a page boundary (e.g. $xxFF where xx is and value from $00 to $FF). In this case fetches the LSB from $xxFF as expected but takes the MSB from $xx00. This is fixed in some later chips like the 65SC02 so for compatibility always ensure the indirect vector is not at the end of the page.
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

When using jump tables, be very careful about safety. Don't allow out-of-range values to be used. Use bounds checking, or bit masking and dummy entries.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Dwedit wrote:When using jump tables, be very careful about safety. Don't allow out-of-range values to be used. Use bounds checking, or bit masking and dummy entries.
I was gonna say something like that... Jump tables are great when your cases are all consecutive numbers (and you should always try to make it so, since it's easier that way), but when the cases are scattered values or ranges of different sizes, jump tables are not so good.
Post Reply