Page 1 of 1
I've been thinking, AND ... here's what happened (or not)
Posted: Tue Mar 20, 2018 3:31 pm
by Ramsis
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.
Consider this bit of SNES-65816, native-mode code (Accu is 8 bits, X/Y are 16 bits):
Code: Select all
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.
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: Select all
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
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).
Thanks!!
Re: I've been thinking, AND ... here's what happened (or not
Posted: Tue Mar 20, 2018 5:42 pm
by koitsu
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.
Re: I've been thinking, AND ... here's what happened (or not
Posted: Tue Mar 20, 2018 5:57 pm
by koitsu
BTW, if you don't believe me, go to
Easy 6502 and throw in this code (note the first few commented-out lines):
Code: Select all
; 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.
Re: I've been thinking, AND ... here's what happened (or not
Posted: Tue Mar 20, 2018 9:51 pm
by Oziphantom
Re: I've been thinking, AND ... here's what happened (or not
Posted: Wed Mar 21, 2018 10:40 am
by ReaperSMS
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?
Re: I've been thinking, AND ... here's what happened (or not
Posted: Tue Mar 27, 2018 2:45 pm
by Ramsis
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.
koitsu wrote:My gut feeling is that your lda CARDSTATUS isn't using 24-bit addressing
But it duuuuzz (see above)
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 ...)
Re: I've been thinking, AND ... here's what happened (or not
Posted: Tue Mar 27, 2018 3:36 pm
by ReaperSMS
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
Re: I've been thinking, AND ... here's what happened (or not
Posted: Tue Mar 27, 2018 8:48 pm
by nocash
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.
Re: I've been thinking, AND ... here's what happened (or not
Posted: Fri Mar 30, 2018 3:08 pm
by Ramsis
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
to
, and I'm f***ed.
To rephrase this: Although the SNES PowerPak is known to work fine with
called EVERY 512 BYTES read from the card, it refuses to even boot with
.
Magic!
Or (hopefully not, but) just me (again).

Re: I've been thinking, AND ... here's what happened (or not
Posted: Fri Mar 30, 2018 4:26 pm
by lidnariq
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.
Re: I've been thinking, AND ... here's what happened (or not
Posted: Fri Mar 30, 2018 7:05 pm
by Nicole
I can think of a couple things to try.
1. Try replacing
Code: Select all
and #%00000001
cmp #%00000001
beq CardError
with
Code: Select all
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.
Re: I've been thinking, AND ... here's what happened (or not
Posted: Sat Mar 31, 2018 5:42 am
by ReaperSMS
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: Select all
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.
Re: I've been thinking, AND ... here's what happened (or not
Posted: Mon Apr 02, 2018 11:10 am
by Ramsis
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: Select all
and #%00000001
cmp #%00000001
beq CardError
with
Code: Select all
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 ...
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.
But let's not forget:
ReaperSMS wrote:it does seem to generate the correct-looking bytes.
*plonk*
Re: I've been thinking, AND ... here's what happened (or not
Posted: Mon Apr 02, 2018 1:10 pm
by ReaperSMS
Did you try it with the extra nops, as suggested, or not?
Re: I've been thinking, AND ... here's what happened (or not
Posted: Mon Apr 02, 2018 1:39 pm
by 93143
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...