It is currently Sat Aug 18, 2018 5:41 am

All times are UTC - 7 hours



Forum rules


Related:



Post new topic Reply to topic  [ 15 posts ] 
Author Message
PostPosted: Tue Mar 20, 2018 3:31 pm 
Offline
User avatar

Joined: Sun Jul 01, 2012 6:44 am
Posts: 341
Location: Lion's den :3
Okay, so this has been driving me nuts for days. :?

Though I'm still convinced it's just me, myself and/or I (it always has, so it's got to be this time, too!), I thought I'd seek professional help before I involuntarily zero out, you know, the zero page. :mrgreen:

Consider this bit of SNES-65816, native-mode code (Accu is 8 bits, X/Y are 16 bits):

Code:
CardCheckError:
   lda   CARDSTATUS                  ; get card status, check for general error
   sta   errorCode
   and   #%00000001
   cmp   #%00000001
   beq   CardError
   rts

CardError:
   ClearLine 21
   ClearLine 22
   ClearLine 23
   SetCursorPos 21, 1

   ldy   #errorCode

   PrintString "Error $%x - CF card status"

FYI, CARDSTATUS is a 24-bit address, errorCode is a direct page variable, and ClearLine, SetCursorPos and PrintString are all macros, none of which messes with the contents of errorCode.

Those who know me might recognize this as a code snippet from my unofficial SNES PowerPak firmware. What you might not know is that I'm currently working on v3.01, which will feature a lot of improvements over v3.00. :D

So, here's the deal: As CardCheckError gets called very often (i. e., more than every 512 bytes of data transferred to or from the CF card), I thought it would be a good idea to optimize this subroutine a tiny little bit.

Just like so:

Code:
CardCheckError:
   lda   CARDSTATUS                  ; get card status, check for general error
   sta   errorCode
   and   #%00000001
   bne   CardError
   rts

As there's only the LSB, aka one single bit being tested, I thought it'd be nothing to write home about.

We-heh-heh-hell. Yes it is. :!:

The routine being shortened like this, the PowerPak would give me a card error message right upon power-up.

Strange? Yes, but wait 'til you hear this ...

It would even laugh me in the face by telling me

Quote:
Error $50 - CF card status


Can you believe it? Bit 0 of errorCode is clear/zero, as it apparently has been all the time, and still, the branch was taken regardless whenever I went from AND #1/CMP #1/BEQ SOMEWHERE to AND #1/BNE SOMEWHERE.

WTF's happening here?? :?:

I spent 3+ hours googling for a 65X(X)X AND quirk, but didn't come up with anything.

Please help me, as I'm beginning to lose my sanity over this (but luckily not my mane, which is hairdcoded). :lol:

Thanks!!

_________________
Some of my projects:
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)


Top
 Profile  
 
PostPosted: Tue Mar 20, 2018 5:42 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3479
Location: Mountain View, CA
There's nothing wrong with your understanding the opcodes. But I'll go over them anyway:

lda modifies N/Z flags, as you know.
sta does not modify N/Z flags, as you know.
and modifies N/Z flags appropriately -- if MSB of result is set, N=1 else N=0. If result is zero, Z=1 else Z=0.
cmp modifies N/Z/C -- it operates similar to sbc but there's no saving of the result, instead only flags get changed. If MSB of result set, N=1 else N=0. If result is zero, Z=1 else Z=0. If borrow is required (accumulator value >= result), C=1, else C=0.
bne checks against Z flag; if Z=1, branch is taken.

You don't state where CARDSTATUS lives, but you imply it's in direct page because you propose "zeroing out zero page" as a solution. Keep reading.

My gut feeling is that your lda CARDSTATUS isn't using 24-bit addressing but instead absolute or direct page addressing, resulting in a value read from wherever B is at the time. It varies per assembler, but I would expect to see lda.l CARDSTATUS or some assembler equivalent. Generate an assembly listing if you can and verify it's using 24-bit addressing; if you can't generate a listing, stick some identifier bytes near the routine (like .db $ca,$fe,$ba,$be, open up the resulting ROM in a hex editor, search for $cafebabe, then manually check each opcode of the routine in question to see which is being used.

opcode $ad = lda absolute (16-bit)
opcode $af = lda absolute long (24-bit)
opcode $a5 = lda direct page

And as a general mode of operation -- if applicable, of course! -- your program should zero direct page / RAM anyway. I won't harp on that though, everyone's needs/situations are different.

Other weird things that might be be happening, but I have no way to confirm this (only you would know):

* Possibly where CARDSTATUS is resides somewhere around where the stack pointer might be (or might overflow or underflow into)
* Possibly NMI routine is modifying some part of memory and changing values to something you don't expect
* Possibly there's a general bug in your program elsewhere writing a value to where CARDSTATUS lives without you realising it. A common situation is a program that intends to write an 8-bit value to direct page (say address $0123), but the accumulator is 16-bit, so it writes to addresses $0123 and $0124 instead; if CARDSTATUS was at $0124... you get the idea

If this is a program you can run on an emulator, or "simulate" on an emulator through some predetermined ways (i.e. "emulate" the environment/thing you're working with by pre-initialising RAM/etc. with some values), then you could debug it easily (break on reads or writes exactly where CARDSTATUS lives, and/or break on execute on the questionable piece of code). But on actual hardware, you'd need an ICE.

Another option would be to write a small little test program of your own, run it in an emulator with debugging support (ex. bsnes-plus), and step through the code and look at behaviour/registers/bits yourself. Change the value in RAM before the routine starts then see how it changes. You get the idea.


Top
 Profile  
 
PostPosted: Tue Mar 20, 2018 5:57 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3479
Location: Mountain View, CA
BTW, if you don't believe me, go to Easy 6502 and throw in this code (note the first few commented-out lines):

Code:
; pick one of the below 2:
; lda #$ff   ; this should cause brk to happen (bit 0 = 1)
; lda #$00   ; this should cause a pixel to show up (bit 0 = 0)
  sta $0f

  lda #$11   ; just a bogus value in the accumulator

CardCheckError:
  lda $0f
  sta $10
  and #1
  bne CardError

noerror:
  lda #5       ; green colour
  sta $330     ; graphical RAM
  jmp noerror

CardError:
  brk

Then try changing and #1 / bne CardError to and #1 / cmp #1 / beq CardError and note that there's no difference in behaviour. You can use the disassembler and/or the debugger (see checkbox under little graphical window) + step through your code and see what happens. The assembler does not support binary immediate syntax (i.e. #%).

This is a simple 6502 emulator, but the 65816 is identical in opcode behaviour in this case, so it's a valid test.

Edit: fix URL to Easy 6502.


Last edited by koitsu on Wed Mar 21, 2018 10:46 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Tue Mar 20, 2018 9:51 pm 
Offline

Joined: Tue Feb 07, 2017 2:03 am
Posts: 515
Code:
   ldy   #errorCode
         ^


Top
 Profile  
 
PostPosted: Wed Mar 21, 2018 10:40 am 
Offline

Joined: Sun Sep 19, 2004 11:07 pm
Posts: 162
That is probably just loading a pointer to errorCode into Y, that gets parsed out by the Printf-like macro afterwards.

A disassembly of the two cases, with the actual instruction bytes interspersed, might indeed shed some light on things.

Is this function anywhere near a 64K boundary?


Top
 Profile  
 
PostPosted: Tue Mar 27, 2018 2:45 pm 
Offline
User avatar

Joined: Sun Jul 01, 2012 6:44 am
Posts: 341
Location: Lion's den :3
Thank you all, especially koitsu, for your invaluable feedback! :)

But, according to the Furry saying™, "Sometimes an octopus sees more than a primate's visual field can cover," after days and days of reflecting the matter I still don't get what's happening, and why AND #1/CMP #1/BEQ SOMEWHERE in this case yields a different result (i. e., carry bit) than AND #1/BNE SOMEWHERE does.

koitsu wrote:
You don't state where CARDSTATUS lives

Yes I did. Please re-read my original post.

koitsu wrote:
but you imply it's in direct page

No.

koitsu wrote:
because you propose "zeroing out zero page" as a solution.

*Sigh* That was a silly joke. Sorry about confusing the confu page out of you. :wink:

koitsu wrote:
My gut feeling is that your lda CARDSTATUS isn't using 24-bit addressing

But it duuuuzz (see above) :mrgreen:

koitsu wrote:
Other weird things that might be be happening, but I have no way to confirm this (only you would know):

No, please. No. The mothf** eh code has been on GitHub for quite some time now, so no, not just me but hole wurlde, you n0.

koitsu wrote:
* Possibly where CARDSTATUS is resides somewhere around where the stack pointer might be (or might overflow or underflow into)
* Possibly NMI routine is modifying some part of memory and changing values to something you don't expect

Checked it all, but unfortunately, no.

koitsu wrote:
* Possibly there's a general bug in your program elsewhere writing a value to where CARDSTATUS lives without you realising it.

Have thought of this before, but like it or not ... no.

koitsu wrote:
A common situation is a program that intends to write an 8-bit value to direct page (say address $0123), but the accumulator is 16-bit, so it writes to addresses $0123 and $0124 instead; if CARDSTATUS was at $0124... you get the idea

Exactly. But ... no. :(

koitsu wrote:
If this is a program you can run on an emulator, or "simulate" on an emulator through some predetermined ways (i.e. "emulate" the environment/thing you're working with by pre-initialising RAM/etc. with some values), then you could debug it easily (break on reads or writes exactly where CARDSTATUS lives, and/or break on execute on the questionable piece of code). But on actual hardware, you'd need an ICE.

You sh***ing me? I've been running this on actual SNES PowerPak hardware ever since.

@Oziphantom No, it's fine (even though the comments in lib_strings.inc.asm are completely obsolete, and have been ever since ...)

@ReaperSMS

ReaperSMS wrote:
That is probably just loading a pointer to errorCode into Y, that gets parsed out by the Printf-like macro afterwards.

This.

ReaperSMS wrote:
Is this function anywhere near a 64K boundary?

Good idea, will check on that. (It's probably not though ...)

_________________
Some of my projects:
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)


Top
 Profile  
 
PostPosted: Tue Mar 27, 2018 3:36 pm 
Offline

Joined: Sun Sep 19, 2004 11:07 pm
Posts: 162
I don't have a great feel for '816 accum/index bit shenanigans, but what I see from poking at github:

https://github.com/Ramsis-SNES/snes-pow ... iables.asm has most of the relevant definitions

CARDSTATUS is defined as $A0800E
errorcode looks to be defined as $0002

https://github.com/Ramsis-SNES/snes-pow ... ce.inc.asm has the suspicious code

accumulator appears to be assumed to be 8-bit here
index looks like it should be 16-bit for the whole file

a quick look didn't reveal any spot that might have made it to CardCheckError with a 16-bit accumulator, but if it did it would probably be doing much stranger things.

a dump of the bytes starting at CardCheckError would still probably be useful


Top
 Profile  
 
PostPosted: Tue Mar 27, 2018 8:48 pm 
Offline

Joined: Fri Feb 24, 2012 12:09 pm
Posts: 603
If you are sure that "Accu is 8 bits, X/Y are 16 bits" then you can sefely initialize it as so at the begin of the function. If you are still seeing the same error then you were probably right about it being initialized as so.

Another test would be to replace the "bne CardError" opcode by two dummy bytes (eg. two NOPs, or better: some 2-byte dummy instruction that has the same value as "bne CardError" in the second byte. If you still get the error then you know that something is wrong.

As already suggested by 1-2 people: You should really disassemble the binary code instead of just relying on your source code.


Top
 Profile  
 
PostPosted: Fri Mar 30, 2018 3:08 pm 
Offline
User avatar

Joined: Sun Jul 01, 2012 6:44 am
Posts: 341
Location: Lion's den :3
Thank you all (again, esp. koitsu).

What you guys all don't seem to realize though (good on you though, as working my way through the hell of a mess of the original SNES PowerPak firmware's code has been, and still is, a PITA, as opposed to my little thread here) is that CardCheckError isn't just any kind of subroutine with a presumed A8/16 issue. Instead, it's called (not only, but especially) every f**king 512 bytes (i. e., every sector) read from or written to the CF card.

So we know it's good in one case, but it immediately fails in the other.

IOW: I change
Code:
AND #1/CMP #1/BEQ SOMEWHERE
to
Code:
AND #1/BNE SOMEWHERE
, and I'm f***ed.

To rephrase this: Although the SNES PowerPak is known to work fine with
Code:
AND #1/CMP #1/BEQ SOMEWHERE
called EVERY 512 BYTES read from the card, it refuses to even boot with
Code:
AND #1/BNE SOMEWHERE
.

Magic!

Or (hopefully not, but) just me (again). :cry:

_________________
Some of my projects:
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)


Top
 Profile  
 
PostPosted: Fri Mar 30, 2018 4:26 pm 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7392
Location: Seattle
When I'm debugging embedded situations, the order I do things, from "easier to figure out what's going on" to "more guaranteed to work", is:
* Use a debugging simulator
* Use a captive debugger
* LED debugging
* LED debugging and a logic analyzer

The SNES does have a very small number of GPIO pins, and one's even present on the controller ports.


Top
 Profile  
 
PostPosted: Fri Mar 30, 2018 7:05 pm 
Offline

Joined: Sun Mar 27, 2016 7:56 pm
Posts: 161
I can think of a couple things to try.

1. Try replacing
Code:
   and   #%00000001
   cmp   #%00000001
   beq   CardError
with
Code:
   and   #%00000001
   nop
   nop
   bne   CardError
just to make certain there's nothing weird relying on how the code is positioned or its size.

2. Instead of lda CARDSTATUS, try some constant numbers to see how it behaves. What determines which branch it takes? Does it print the correct number?

If those fail, my general advice for debugging is this: Tear out every single bit of unrelated code until you have the absolute minimum needed to recreate the bug. Do not trust a single thing, even your print macros. Don't ignore things that "should" work, because the fact is your code doesn't work, or you wouldn't be here.


Top
 Profile  
 
PostPosted: Sat Mar 31, 2018 5:42 am 
Offline

Joined: Sun Sep 19, 2004 11:07 pm
Posts: 162
I'm feeling generous, so I pulled down the various tools from github and such.

wla-65816/wlalink's listing format is rather odd and suspect to the point of being nonsensical
main_rommapping.inc.asm produced some link errors, lines 44/46 referenced gameName.gCluster, which didn't exist. changing those to gameName.Cluster got it to get past that.

it does seem to generate the correct-looking bytes.

I might be hoping for too much, since your debugging approach so far has been you: "LOL THIS DOESN'T WORK" reasonable people: "Have you looked at they bytes?" you: "LOL THIS DOESN'T WORK", but...

does it die in the same fashion if you do

Code:
CardCheckError:
   lda CARDSTATUS
   sta errorCode
   and #%00000001
   bne CardError
   rts

CardError:
   nop
   nop
   ClearLine 21 ...


instead? That keeps the code after aligned, which spits out a rom that only differs in about 8 bytes -- a couple in the timestamp, the new cardcheckerror, and the checksum bytes. If that works, then something is expecting some alignment elsewhere, that is getting screwed up by chopping 2 bytes out of the middle.


Top
 Profile  
 
PostPosted: Mon Apr 02, 2018 11:10 am 
Offline
User avatar

Joined: Sun Jul 01, 2012 6:44 am
Posts: 341
Location: Lion's den :3
lidnariq wrote:
When I'm debugging embedded situations, the order I do things, from "easier to figure out what's going on" to "more guaranteed to work", is:
* Use a debugging simulator
* Use a captive debugger
* LED debugging
* LED debugging and a logic analyzer

The SNES does have a very small number of GPIO pins, and one's even present on the controller ports.

Thanks, but unfortunately I don't have access to hardware-level based debugging tools. :-(

Nicole wrote:
I can think of a couple things to try.

1. Try replacing
Code:
   and   #%00000001
   cmp   #%00000001
   beq   CardError
with
Code:
   and   #%00000001
   nop
   nop
   bne   CardError
just to make certain there's nothing weird relying on how the code is positioned or its size.

2. Instead of lda CARDSTATUS, try some constant numbers to see how it behaves. What determines which branch it takes? Does it print the correct number?

If those fail, my general advice for debugging is this: Tear out every single bit of unrelated code until you have the absolute minimum needed to recreate the bug. Do not trust a single thing, even your print macros. Don't ignore things that "should" work, because the fact is your code doesn't work, or you wouldn't be here.

Thanks indeed, Nicole, for your valuable input. I'll see how things turn out with a few NOPs here and there. :)

ReaperSMS wrote:
I'm feeling generous, so I pulled down the various tools from github and such.

In case of trouble assembling The Source™, I'm usually very responsive, and willing to point out to you what you're doing wrong. You'd have to contact and ask me in the first place though ... :P

ReaperSMS wrote:
wla-65816/wlalink's listing format is rather odd and suspect to the point of being nonsensical

Not my fault. Feel free to open an issue wherever if it bothers you that much.

ReaperSMS wrote:
main_rommapping.inc.asm produced some link errors, lines 44/46 referenced gameName.gCluster, which didn't exist. changing those to gameName.Cluster got it to get past that.

*sigh* The current master branch is WIP, so sorry that I forgot to commit some variable renaming stuff. ;-)

ReaperSMS wrote:
it does seem to generate the correct-looking bytes.

[irony]Ah. Really. That's so good to know indeed.[/irony]

ReaperSMS wrote:
I might be hoping for too much, since your debugging approach so far has been you: "LOL THIS DOESN'T WORK" reasonable people: "Have you looked at they bytes?" you: "LOL THIS DOESN'T WORK", but...

Right. :lol:

But let's not forget:

ReaperSMS wrote:
it does seem to generate the correct-looking bytes.

*plonk*

_________________
Some of my projects:
Furry RPG!
Unofficial SNES PowerPak firmware
(See my GitHub profile for more)


Top
 Profile  
 
PostPosted: Mon Apr 02, 2018 1:10 pm 
Offline

Joined: Sun Sep 19, 2004 11:07 pm
Posts: 162
Did you try it with the extra nops, as suggested, or not?


Top
 Profile  
 
PostPosted: Mon Apr 02, 2018 1:39 pm 
Offline

Joined: Fri Jul 04, 2014 9:31 pm
Posts: 960
He just said he was going to.

This issue reminds me of an HDMA table I made once, using .db to write it out in code. It was only a few bytes long, and it would not work unless I added a dummy byte (can't remember the value) right after the very first byte. To this day I have no idea why, and every other HDMA table I've made has worked great. Programming can be tricky...


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group