Closed binary1230 closed 9 months ago
Not too experienced with the official specs myself. I think the first bug is a consequence of treating BRL just like BRA and limiting the range to its possible signed values. I think this makes sense for BRA (pretty sure branches that are outside the range of -128 to 127 are invalid), but I suppose the correct behavior for BRL instead would be to not care about signed value overflows and just "wrap around", as long as the destination address stays within the same bank? I don't know, as I said, not familiar with the offical specs.
As for the second bug, probably a consequence of Asar implicitly casting numbers down to whatever size is necessary to fit the command being used. Fixing that one might be tricky, and technically, I'm not sure if we can consider that a bug, since it's the intended behavior. I suppose we might have to treat BRL differentl from other commands. Then again, I'm not sure how important that bug would be to fix, anyways, because while directly using numbers with branch commands is technically valid, I'm not sure if that's an actual use case for anything. Normally you would use labels with branch commands. Though I suppose if the bug also occurs while using labels, then it's worth investigating further.
Yeah I think you are correct about the correct behavior being it should overflow and wrap around the bank. The actual 2 bytes written to the file are correct and will do that. it's only the error check that is messing up the conversion back to signed short and falsely flagging it as an error when it was actually ok.
Bug 1 is happening for me with labels on a disassembly project I'm working on.
bug 2 is more hypothetical and probably comes into play only if someone is typing in addresses by hand instead of using labels. Like you said that seems pretty unlikely. I actually only mentioned it here because when I tried to implement a fix for the first bug it occurred to me that it might introduce the second bug.
On Tue, Sep 8, 2020, 3:49 AM RPG Hacker notifications@github.com wrote:
Not too experienced with the official specs myself. I think the first bug is a consequence of treating BRL just like BRA and limiting the range to its possible signed values. I think this makes sense for BRA (pretty sure branches that are outside the range of -128 to 127 are invalid), but I suppose the correct behavior for BRL instead would be to not care about signed value overflows and just "wrap around", as long as the destination address stays within the same bank? I don't know, as I said, not familiar with the offical specs.
As for the second bug, probably a consequence of Asar implicitly casting numbers down to whatever size is necessary to fit the command being used. Fixing that one might be tricky, and technically, I'm not sure if we can consider that a bug, since it's the intended behavior. I suppose we might have to treat BRL differentl from other commands. Then again, I'm not sure how important that bug would be to fix, anyways, because while directly using numbers with branch commands is technically valid, I'm not sure if that's an actual use case for anything. Normally you would use labels with branch commands. Though I suppose if the bug also occurs while using labels, then it's worth investigating further.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/RPGHacker/asar/issues/170#issuecomment-688687816, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABJJRSFZ3XT6WDMDLHT5WCLSEXO2HANCNFSM4Q7L4YPQ .
Got around to checking into this more. I extracted the relative addressing function into a separate project and built a few unit test cases, played around with it til I got my test cases all working.
Next move I'll integrate that as a PR if it looks like it's in the right ballpark, add some more tests on your asm testing scaffolding, and probably study it in a SNES debugger to make sure the output ROM is doing the right thing. I -THINK- it's doing the right thing, but I'm not an expert.
My two questions are:
1) You should use &0xFFFF0000 in err_banks_differ, top byte is a freespace ID. I don't know what happens if the question 'are labels A and B in same bank?' gets different answers between pass 2 and 3, and I'd recommend not finding out. 2) Doesn't matter. Most opcodes already throw before writing; for example, LDA LabelThatDoesntExist,x succeeds on first pass, but errors before writing on second. 3) what rpg said
the PR's logic was implemented in asar_2_beta, so i'm considering this done
First, apologies, this is an incomplete bug report. Working on a pull request, but, figured I'd put what I have here in case any 65816 gurus knew how to fix this quickly. I have some good repro cases though.
Bugs: Instructions that use "relative addressing", like BRL [16bit] and BRA [8bit] can sometimes throw errors incorrectly for valid assembly. Here I'll use BRL as the example, but I think all this happens with BRA too.
This all seems to revolve around issues converting back and forth between 4 byte unsigned numbers and 2 byte signed numbers.
Bug 1:
bug1.asm
Expected result: Output ROM is: 82 93 B1 which is BRL $B193
Actual result: Error message:
Analysis: Funny story: Asar actually does the right thing and outputs the correct bytes, but, afterwards a different bounds check fails. that check is located in https://github.com/RPGHacker/asar/blob/master/src/asar/arch-65816.cpp#L55 , in macro
as_rel2()
.Here's that code with annotation:
int pos = (int)num - ((snespos&0xFFFFFF)+3); $0000B193 = $00C0B271 - ($00C000DB + 3)
this section writes the bytes to the ROM:
"BRL $B193" is interpreted the same as: "BRL -20,077"
so far so good. but now here's the error: going into this, pass=2, foundlabel=true
specifically this check is the problem:
At first glance, the intention seems right. The range of a signed 2-byte word which is 0x0000 thru 0xFFFF or -32768 thru 32767), so checking for it makes sense.
However, it causes this to incorrectly print:
If our
pos
variable really was a signed word (2 bytes) this would be fine because: $B193 => interpreted as signed word =>-20,077, and that's in range of the bounds check.-20,077 is the correct value we're looking for.
The issue is:
pos
here is actually a 4 byte unsigned int. In hex, its value is: $0000B193That contains the right bytes (B193), but it's not quite good enough. Interpreting this 4 byte unsigned int as a 4 byte signed int gives us an incorrect result of: 45,459
We're trying to get it to output -20,077.
The hex representation of that is: $FFFFB193 as signed int = -20,077
Takeaways:
That leads to the question of: what's the point of the check? If it's to validate the parsed input to make sure the user hasn't typed in a value > $FFFF, then, see below for the next bug:
Bug 2. If you pass in too large a value for BRL or BRA, asar will fail to throw an error but still write out the lower two bytes of the number.
bug2.asm
EXPECTED: fatal error thrown saying $01B193 is too large, max is $FFFF (2 bytes) ACTUAL: no error thrown, and it outputs (wait.. twice in the ROM? seems even weirder) the following bytes: 82 93 B1 BRL $B193
There's a check (same as the above one) that looks like it might catch this value being out of range, but, it's not called because we're not using a label here.
going into this, pass=2, foundlabel=false
we skip the:
(pos<-32768 || pos>32767)
check, and continue with assembly, incorrectly not throwing an error.So, we need to add a check that if
pos > 0xFFFF
then it throws an error.More stuff to check, any bugfixes should add these as a test suite and need to make sure these work. (Disclaimer: from my reading of the CPU manual, I'm not super-familiar with 65816, so double check me)
expected (I think?) should throw an error that you can't BRL into a label in a different bank. even though the destination ROM address is less than 32k bytes away.
That's only 256 bytes away in ROM, so it's in range of a 2 byte offset, BUT, [I think?] BRL is only for intra-bank transfers.
could add a check like:
Other stuff:
freespace
? Does it use 0xFF000000 addresses or something? Do we need to deal with that in these checks?Anyway, I thought this might be easy but it turned into a rabbit hole :)
I was planning on writing some tests to cover all the cases. It seems like if this gets more complex, we'll want to extract macros
as_rel2()
andas_rel1()
into functions. The only difference is as_rel1() operates on 1 byte like this:https://wiki.nesdev.com/w/images/7/76/Programmanual.pdf
So, probably they could both call a new function like relative_address(offset, num_bytes), and it only needs to change the range check and # of bytes written.
Phew. OK, lemme know what you think. Open to suggestions.