Creating Loops (Pt. 2)
Creating Loops Pt. 2

Part 2: Complex memcpy loops

NOTICE: This will be for veteran ASM coders, that are writing a code with multiple loops within...

If you have a very complex assembly code that has multiple loops. It may be best to use what are called memcpy loops. Instead of writing a bunch of separate loops, you will jump (call) to the game's built-in looping function every time a loop is needed to be executed.

Chapter 1. Required Knowledge

To have a good understanding of what is being explained in this tutorial. I recommend reading this thread HERE about function calls. The memcpy is a generic C++ function call that MKWii has which can be utilized to create loops for the purpose of moving large amounts of data. You simply backup registers that need that values preserved, provide the function's arguments, then call the function.

Chapter 2. Backing up  Registers

The memcpy function makes use of the following registers: r0, r4, r5, r6. It would make sense to backup the original values of these registers beforehand. There are multiple ways to do that. After reading the providing thread about function calls in Chapter 1, you should have this snippet of code already..

stwu r1, -0x80 (r1) #Push stack, make space for 29 registers
stmw r3, 0x8 (r1)


lmw r3, 0x8 (r1)
addi r1, r1, 0x80 #Pop stack

Chapter 3. Arguments for memcpy; Function Address of memcpy

The memcpy has 3 arguments...
r3 = Starting Destination Memory Address
r4 = Starting Source Memory Address
r5 = Amount of Bytes to Copy & Paste

The address to call and re-link (via the LR or CTR) is the same for every region of MKWii. It is 0x80005F34. As you can see the arguments are easy to understand and the function call address is universal and easy to remember.

Chapter 4. Calling memcpy

Here's an example snippet of source setting up the arguments of memcpy then calling the function

addi r3, r9, 0x00C0 #Setup Dest. Start Address; Argument 1
mr r4, r31 #Setup Source. Start Address; Argument 2
li r5, 0x0020 #Setup Amount of Bytes to Copy; Argument 3

lis r12, 0x8000
ori r12, r12, 0x5F34
mtlr r12 #Move memcpy's function call address to the Link Register
blrl #Call memcpy and re-link

Chapter 5. Memcpy return values

Once the memcpy is finished, you have 5 return values

r0 = Last byte that was copied over
r3 = Same as before the function was called (Destination Start Address)
r4 = Address for final byte of Source
r5 = 0x0
r6 = Address for final byte of Destination

These return values may come handy for later instructions in your ASM code.

Chapter 6. Conclusion

So if you have a code with multiple loops that use a generic subic. type loop format or bdnz type loop format, it may be simpler for you to simply call the memcpy function instead of creating a loop from scratch every time. You can also put the calling of the memcpy into in its own subroutine, like this...

##Some instructions for setting up loop1 memcpy arguments

bl memcpy_subroutine

##Some instructions for setting up loop2 memcpy arguments

bl memcpy_subroutine

##Some instructions for setting up loop3 memcpy arguments

bl memcpy_subroutine

##Other instructions

mflr r11 #Backup Link Register from initial Branch & Link
lis r12, 0x8000
ori r12, r12, 0x5F34
mtlr r12
blrl #Call memcpy and re-link
mtlr r11 #Restore Link Register from initial Branch & Link
blr #Escape memcpy subroutine

And there you go. You should have adequate knowledge now of utilizing all sort of methods for creating loops for your ASM codes.

Forum Jump:

Users browsing this thread: 1 Guest(s)