ASM explanations...

Started by Stuff, August 24, 2011, 02:19:59 AM

Previous topic - Next topic

dcx2

Yes, the example code you show works just fine.  Note that @ha should be used with addi/subi (this includes displacement operands, which are added), while @h should be used with ori.  They are not interchangeable.

Also, the app itself doesn't understand English.  It (and PyiiASMH) is a front-end for vdappc and powerpc-gekko-as.  as itself is what "understands" English.  Y.S. gave me this link when I asked about as.  http://sourceware.org/binutils/docs-2.18/as/

Regarding the two levels of testing (actually, three); there are two types of button activators.  One activator has a bit set for every button that is currently held down.  Another activator has a bit set only during the frame that a button became pressed; on the next frame the bit will be clear, even though the button is still held down.  I call these last ones "delta activators".

When using a roller code, you only want the value to roll once per press.  Otherwise, it will roll every 16 ms or so (60 Hz), which is bad if you want to dial in to a specific value.

The first test with andi. is on the delta activators.  If D pad up or D pad down were just pressed, then we will process the hack.  If they weren't just pressed, do nothing.

Once we know the up or down was just pressed, we'll test to make sure Z and up, or Z and down are being held.  Z is therefore the "enable" button; if Z isn't pressed then this test will prevent up or down from processing the hack accidentally.  If you're holding Z and press up, it will fire just once when you press up, even if you hold the buttons for a long time.

The third level of testing makes sure that when we increment to 52, it wraps around to 0.  And -1 wraps to 51.

Of note is that the code example is for a GameCube game, so some of the offsets and button values are different than for Wii games.

daijoda

Wow, that's a rather organized docs set for a homebrew app. They must've put a lot of efforts into that. I'm just glad that this is an open forum, it lowers the barrier to learning by this much by being accessible. :)

Still a little unclear about the terminology used... When people say something is sign extended, do they mean a case like when 0x8000 becomes 0xFFFF8000?

For the "delta activators", one of them would have a corresponding bit changed from "0" to "1" in the frame that button is pressed, and the other one of them would have the same bit changed in the frame the button's released?

dcx2

as is not a homebrew app.  It's the GNU assembler.  It's part of gcc.  We're using the same tools that anyone else targeting a PowerPC architecture could use; for instance, if you wanted to compile an app for an old MacBook, you could use gcc and as.

Sign extension does basically what you said.  It copies the sign bit to the left until it fills the remaining bits of the architecture's width.  So sign extending a 16-bit value to a 32-bit value would copy the sign bit 16 times.  That means 0x8000 -> 0xFFFF8000, and 0x7FFF -> 0x00007FFF.

Sign extension is used kinda like this.  Imagine you have an 16-bit value that represents -1 in two's complement.  This would be 0xFFFF.  What if you wanted this to be a 32-bit representation of -1?  That is 0xFFFFFFFF.  Sign extension "extends" the 16-bit value so that it represents the same value for a 32-bit value.  You can also using sign extension on 8-bit values, too.

Yes, there are two delta activators for the Wii, one for presses and one for releases.  They are usually located immediately after the "classic" button activator.  I'm not sure if there's release activators for the GC.

Stuff

#63
ah. Those are the delta activators your talkin about. I didn't see the 0x30 even though you mentioned it. >.<
That's clever. I guess I don't need to turbo activate XD.

Is it possible to lwz rA, d(SRR0)? I tried and pyiiasmh didn't complain, but instead it interpreted it as r26. :/ I was gonna branch over some ascii and then lwz them, but there isn't a reliable register that I can always use to point to it. But since SRR0 is always the address of the current instruction, it would've been awesome if I could just use that.
.make Stuff happen.
Dropbox. If you don't have one, get it NOW! +250MB free if you follow my link :p.

Mod code Generator ~50% complete but very usable:
http://dl.dropbox.com/u/24514984/modcodes/modcodes.htm

Stuff

cmpwi. I says the result is placed in crfD. But if we don't specify one(usually the case), I assume crf0 is where the result goes. Correct me if I'm wrong.

Now, I want to mtcr(f) so that bne- will branch. Making it always branch works fine, but I froze the game when I did li r27, 0 before a cmpwi r27, 0 oops >.>. Anyway, I still wonder what goes into crfD when a cmp happens.
.make Stuff happen.
Dropbox. If you don't have one, get it NOW! +250MB free if you follow my link :p.

Mod code Generator ~50% complete but very usable:
http://dl.dropbox.com/u/24514984/modcodes/modcodes.htm

dcx2

#65
The CR is split into eight fields, each four bits.  In the PowerPC EABI, on page 3, you can see that CR2, CR3, and CR4 are all non-volatile.  The others are volatile.  So if you make any modifications to the CR that affect these fields (2/3/4), you will want to push and pop the CR on the stack.  If you use 0/1/5/6/7 then you won't need to.  Preferably use 5/6/7 since 0/1 are used implicitly.

According to the Programmer's Reference Guide, page 13, each field has bits in this order from 0 to 3: less than/negative, greater than/positive, equal/zero, and overflow.

An integer instruction with a ., or a cmp with no cr specified, will use CR0.  A float instruction with a . or an fcmp with no cr will use CR1.

---

Regarding your older post that I missed because it was an edit, SRR0 is not one of the registers r0-r31.  Only a General Purpose Register (GPR) such as r0-r31 can be a pointer for lwz (and note that if you use r0, it actually uses address 0 instead of r0's contents).  Therefore you can't use SRR0 to do that.

In fact, SRR0 only reflects the current instruction during an interrupt.  During normal execution, SRR0 does not hold the instruction pointer.

The only way to figure out where you are in memory is to use bl and then mflr (aka bl trick).

EDIT:

I suppose I should add in case it's not clear.  SRR0 is a "Special Purpose Register" (SPR, as opposed to GPR).  There is a special instruction for reading/writing to SRR0; it's conveniently called mtsrr0.

When I said it only reflects the current instruction during an interrupt, I mean that...during an interrupt, well, "normal execution" is paused and the processor switches to supervisor mode.  During this transition, the address of the normal instruction that is executing is put into SRR0, and execution jumps to an interrupt handler.  If no interrupt happens, SRR0 is not updated.