diff --git a/docs/codehandler.s b/docs/codehandler.s index f80f22729c..0582fe124a 100644 --- a/docs/codehandler.s +++ b/docs/codehandler.s @@ -1,1101 +1,1048 @@ -#MIT License - -#Copyright (c) 2010-2017 Nuke, brkirch, Y.S, Kenobi, gamemasterplc - -#Permission is hereby granted, free of charge, to any person obtaining a copy -#of this software and associated documentation files (the "Software"), to deal -#in the Software without restriction, including without limitation the rights -#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -#copies of the Software, and to permit persons to whom the Software is -#furnished to do so, subject to the following conditions: - -#The above copyright notice and this permission notice shall be included in all -#copies or substantial portions of the Software. - -#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -#SOFTWARE. - -#Based off of codehandleronly.s from Gecko OS source code. -# Example command to build: -# powerpc-elf-gcc -mpowerpc -mpaired -mbig codehandler.s -nostartfiles -nodefaultlibs -nostdlib -T codehandler.ld -o codehandler.bin - -.text -#Register Defines - -.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 -.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 -.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 -.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 -.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 -.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 -.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 - -.globl _start - -gameid: -.long 0,0 -cheatdata: -.long frozenvalue -.space 39*4 - -_start: - stwu r1,-172(r1) # stores sp - stw r0,8(r1) # stores r0 - - mflr r0 - stw r0,176(r1) # stores lr - - mfcr r0 - stw r0,12(r1) # stores cr - - mfctr r0 - stw r0,16(r1) # stores ctr - - mfxer r0 - stw r0,20(r1) # stores xer - - stmw r3,24(r1) # saves r3-r31 - - mfmsr r25 - stw r25,168(r1) # save msr - - ori r26,r25,0x2000 #enable floating point ? - andi. r26,r26,0xF9FF - mtmsr r26 - - - stfd f2,152(r1) # stores f2 - stfd f3,160(r1) # stores f3 - - - - lis r31,cheatdata@h #0x8000 - - lis r20, 0xCC00 - lhz r28, 0x4010(r20) - ori r21, r28, 0xFF - sth r21, 0x4010(r20) # disable MP3 memory protection - - lis r15, codelist@h - ori r15, r15, codelist@l - - ori r7, r31, cheatdata@l # set pointer for storing data (before the codelist) - - lis r6,0x8000 # default base address = 0x80000000 (code handler) - - mr r16,r6 # default pointer =0x80000000 (code handler) - - li r8,0 # code execution status set to true (code handler) - - lis r3,0x00D0 - ori r3,r3,0xC0DE - - lwz r4,0(r15) - cmpw r3,r4 - bne- _exitcodehandler - lwz r4,4(r15) - cmpw r3,r4 - bne- _exitcodehandler # lf no code list skip code handler - addi r15,r15,8 - b _readcodes -_exitcodehandler: - - sth r28,0x4010(r20) # restore memory protection value - - lfd f2,152(r1) # loads f2 - lfd f3,160(r1) # loads f3 - - lwz r25,168(r1) - mtmsr r25 - - lwz r0,176(r1) - mtlr r0 # restores lr - - lwz r0,12(r1) - mtcr r0 # restores cr - - lwz r0,16(r1) - mtctr r0 # restores ctr - - lwz r0,20(r1) - mtxer r0 # restores xer - - lmw r3,24(r1) # restores r3-r31 - - lwz r0,8(r1) # loads r0 - - addi r1,r1,172 - - isync - - blr # return back to game - -_readcodes: - - lwz r3,0(r15) #load code address - lwz r4,4(r15) #load code value - - addi r15,r15,8 #r15 points to next code - - andi. r9,r8,1 - cmpwi cr7,r9,0 #check code execution status in cr7. eq = true, ne = false - - li r9,0 #Clears r9 - - rlwinm r10,r3,3,29,31 #r10 = extract code type, 3 bits - rlwinm r5,r3,7,29,31 #r5 = extract sub code type 3 bits - - andis. r11,r3,0x1000 #test pointer - rlwinm r3,r3,0,7,31 #r3 = extract address in r3 (code type 0/1/2) #0x01FFFFFF - - bne +12 #jump lf the pointer is used - - rlwinm r12,r6,0,0,6 #lf pointer is not used, address = base address - b +8 - - mr r12,r16 #lf pointer is used, address = pointer - - - cmpwi cr4,r5,0 #compares sub code type with 0 in cr4 - - cmpwi r10,1 - blt+ _write #code type 0 : write - beq+ _conditional #code type 1 : conditional - - cmpwi r10,3 - blt+ _ba_pointer #Code type 2 : base address operation - - beq- _repeat_goto #Code type 3 : Repeat & goto - - cmpwi r10,5 - blt- _operation_rN #Code type 4 : rN Operation - beq+ _compare16_NM_counter #Code type 5 : compare [rN] with [rM] - - cmpwi r10,7 - blt+ _hook_execute #Code type 6 : hook, execute code - - b _terminator_onoff_ #code type 7 : End of code list - -#CT0============================================================================= -#write 8bits (0): 00XXXXXX YYYY00ZZ -#write 16bits (1): 02XXXXXX YYYYZZZZ -#write 32bits (2): 04XXXXXX ZZZZZZZZ -#string code (3): 06XXXXXX YYYYYYYY, d1d1d1d1 d2d2d2d2, d3d3d3d3 .... -#Serial Code (4): 08XXXXXX YYYYYYYY TNNNZZZZ VVVVVVVV - -_write: - add r12,r12,r3 #address = (ba/po)+(XXXXXX) - cmpwi r5,3 - beq- _write_string #r5 == 3, goto string code - bgt- _write_serial #r5 >= 4, goto serial code - - bne- cr7,_readcodes #lf code execution set to false skip code - - cmpwi cr4,r5,1 #compares sub code type and 1 in cr4 - - bgt- cr4,_write32 #lf sub code type == 2, goto write32 - -#lf sub code type = 0 or 1 (8/16bits) - rlwinm r10,r4,16,16,31 #r10 = extract number of times to write (16bits value) - -_write816: - beq cr4,+32 #lf r5 = 1 then 16 bits write - stbx r4,r9,r12 #write byte - add r21, r9, r12 - icbi r0, r21 - sync - isync - addi r9,r9,1 - b +28 - sthx r4,r9,r12 #write halfword - add r21, r9, r12 #Get Real Memory Offset - icbi r0, r21 #Invalidate Icache around real memory offset - sync - isync - addi r9,r9,2 - subic. r10,r10,1 #number of times to write -1 - bge- _write816 - b _readcodes - -_write32: - rlwinm r12,r12,0,0,29 #32bits align adress - stw r4,0(r12) #write word to address - icbi r0, r12 #Invalidate icache around address - sync - isync - b _readcodes - -_write_string: #endianess ? - mr r9,r4 - bne- cr7,_skip_and_align #lf code execution is false, skip string code data - - - _stb: - subic. r9,r9,1 #r9 -= 1 (and compares r9 with 0) - blt- _skip_and_align #lf r9 < 0 then exit - lbzx r5,r9,r15 - stbx r5,r9,r12 #loop until all the data has been written - add r21, r9, r12 #Get Real Memory Offset - icbi r0, r21 #Invalidate Icache around real memory offset - sync - isync - b _stb - -_write_serial: - - addi r15,r15,8 #r15 points to the code after the serial code - bne- cr7,_readcodes #lf code execution is false, skip serial code - - lwz r5,-8(r15) #load TNNNZZZZ - lwz r11,-4(r15) #r11 = load VVVVVVVV - - rlwinm r17,r5,0,16,31 #r17 = ZZZZ - rlwinm r10,r5,16,20,31 #r10 = NNN (# of times to write -1) - rlwinm r5,r5,4,28,31 #r5 = T (0:8bits/1:16bits/2:32bits) - - -_loop_serial: - cmpwi cr5,r5,1 - beq- cr5,+16 #lf 16bits - bgt+ cr5,+20 #lf 32bits - - stbx r4,r9,r12 #write serial byte (CT04,T=0) - b +16 - - sthx r4,r9,r12 #write serial halfword (CT04,T=1) - b +8 - - stwx r4,r9,r12 #write serial word (CT04,T>=2) - add r21, r9, r12 #Get Real Memory Offset - icbi r0, r21 #Invalidate Icache around real memory offset - sync - isync - add r4,r4,r11 #value +=VVVVVVVV - add r9,r9,r17 #address +=ZZZZ - subic. r10,r10,1 - bge+ _loop_serial #loop until all the data has been written - - b _readcodes - -#CT1============================================================================= -#32bits conditional (0,1,2,3): 20XXXXXX YYYYYYYY -#16bits conditional (4,5,6,7): 28XXXXXX ZZZZYYYY - -#PS : 31 bit of address = endlf. - -_conditional: - rlwinm. r9,r3,0,31,31 #r10 = (bit31 & 1) (endlf enabled?) - - beq +16 #jump lf endlf is not enabled - - rlwinm r8,r8,31,1,31 #Endlf (r8>>1) - andi. r9,r8,1 #r9=code execution status - cmpwi cr7,r9,0 #check code execution status in cr7 - cmpwi cr5,r5,4 #compares sub code type and 4 in cr5 - cmpwi cr3,r10,5 #compares code type and 5 in cr3 - - rlwimi r8,r8,1,0,30 #r8<<1 and current execution status = old execution status - bne- cr7,_true_end #lf code execution is set to false -> exit - - bgt cr3,_addresscheck2 #lf code type==6 -> address check - add r12,r12,r3 #address = (ba/po)+(XXXXXX) - - - - blt cr3,+12 #jump lf code type <5 (==1) - blt cr5,_condition_sub #compare [rN][rM] - b _conditional16_2 #counter compare - bge cr5,_conditional16 #lf sub code type>=4 -> 16 bits conditional - -_conditional32: - rlwinm r12,r12,0,0,29 #32bits align - lwz r11,0(r12) - b _condition_sub - -_conditional16: - rlwinm r12,r12,0,0,30 #16bits align - lhz r11,0(r12) -_conditional16_2: - nor r9,r4,r4 - rlwinm r9,r9,16,16,31 #r9 = extract mask - and r11,r11,r9 #r11 &= r9 - rlwinm r4,r4,0,16,31 #r4 = extract data to check against - -_condition_sub: - cmpl cr6,r11,r4 #Unsigned compare. r11=data at address, r4=YYYYYYYY - andi. r9,r5,3 - beq _skip_NE #lf sub code (type & 3) == 0 - cmpwi r9,2 - beq _skip_LE #lf sub code (type & 3) == 2 - bgt _skip_GE #lf sub code (type & 3) == 3 - -_skip_EQ:#1 - bne- cr6,_true_end #CT21, CT25, CT29 or CT2D (lf !=) - b _skip - -_skip_NE:#0 - beq- cr6,_true_end #CT20, CT24, CT28 or CT2C (lf==) - b _skip - -_skip_LE:#2 - bgt- cr6,_true_end #CT22, CT26, CT2A or CT2E (lf r4>[]) - b _skip - -_skip_GE:#3 - blt- cr6,_true_end #CT23, CT27, CT2B or CT2F (lf r4 5 - blt cr5,_readcodes - lwz r11,-8(r15) #load counter - bne cr7,_clearcounter #lf previous code execution false clear counter - andi. r12,r3,0x8 #else lf clear counter bit not set increase counter - beq _increase_counter - andi. r12,r8,0x1 #else lf.. code result true clear counter - beq _clearcounter - - -_increase_counter: - addi r12,r11,0x10 #else increase the counter - rlwimi r11,r12,0,12,27 #update counter - b _savecounter - -_clearcounter: - rlwinm r11,r11,0,28,11 #clear the counter -_savecounter: - stw r11,-8(r15) #save counter - b _readcodes - - -#CT2============================================================================ - -#load base adress (0): 40TYZ00N XXXXXXXX = (load/add:T) ba from [(ba/po:Y)+XXXXXXXX(+rN:Z)] - -#set base address (1): 42TYZ00N XXXXXXXX = (set/add:T) ba to (ba/po:Y)+XXXXXXXX(+rN:Z) - -#store base address (2): 440Y0000 XXXXXXXX = store base address to [(ba/po)+XXXXXXXX] -#set base address to (3): 4600XXXX 00000000 = set base address to code address+XXXXXXXX -#load pointer (4): 48TYZ00N XXXXXXXX = (load/add:T) po from [(ba/po:Y)+XXXXXXXX(+rN:Z)] - -#set pointer (5): 4ATYZ00N XXXXXXXX = (set/add:T) po to (ba/po:Y)+XXXXXXXX(+rN:Y) - -#store pointer (6): 4C0Y0000 XXXXXXXX = store pointer to [(ba/po)+XXXXXXXX] -#set pointer to (7): 4E00XXXX 00000000 = set pointer to code address+XXXXXXXX - -_ba_pointer: - - bne- cr7,_readcodes - - - rlwinm r9,r3,2,26,29 #r9 = extract N, makes N*4 - - rlwinm r14,r3,16,31,31 #r3 = add ba/po flag bit (Y) - cmpwi cr3,r14,0 - - cmpwi cr4,r5,4 #cr4 = compare sub code type with 4 (ba/po) - andi. r14,r5,3 #r14 = sub code type and 3 - - cmpwi cr5,r14,2 #compares sub code type and 2 - - blt- cr5,_p01 - beq- cr5,_p2 #sub code type 2 - -_p3: - extsh r4,r3 - add r4,r4,r15 #r4=XXXXXXXX+r15 (code location in memory) - b _pend - -_p01: - - rlwinm. r5,r3,20,31,31 #r3 = rN use bit (Z) - beq +12 #flag is not set(=0), address = XXXXXXXX - - lwzx r9,r7,r9 #r9 = load register N - add r4,r4,r9 #flag is set (=1), address = XXXXXXXX+rN - - beq cr3,+8 #(Y) flag is not set(=0), address = XXXXXXXX (+rN) - - add r4,r12,r4 #address = XXXXXXXX (+rN) + (ba/po) - - - cmpwi cr5,r14,1 - beq cr5,+8 #address = (ba/po)+XXXXXXXX(+rN) - lwz r4,0(r4) #address = [(ba/po)+XXXXXXXX(+rN)] - - rlwinm. r3,r3,12,31,31 #r5 = add/replace flag (T) - beq _pend #flag is not set (=0), (ba/po)= XXXXXXXX (+rN) + (ba/po) - bge cr4,+12 - add r4,r4,r6 #ba += XXXXXXXX (+rN) + (ba/po) - b _pend - add r4,r4,r16 #po += XXXXXXXX (+rN) + (ba/po) - b _pend - - - -_p2: - rlwinm. r5,r3,20,31,31 #r3 = rN use bit (Z) - beq +12 #flag is not set(=0), address = XXXXXXXX - - lwzx r9,r7,r9 #r9 = load register N - add r4,r4,r9 #flag is set (=1), address = XXXXXXXX+rN - - bge cr4,+12 - stwx r6,r12,r4 #[(ba/po)+XXXXXXXX] = base address - b _readcodes - stwx r16,r12,r4 #[(ba/po)+XXXXXXXX] = pointer - b _readcodes - - -_pend: - bge cr4,+12 - mr r6,r4 #store result to base address - b _readcodes - mr r16,r4 #store result to pointer - b _readcodes - - -#CT3============================================================================ -#set repeat (0): 6000ZZZZ 0000000P = set repeat -#execute repeat (1): 62000000 0000000P = execute repeat -#return (2): 64S00000 0000000P = return (lf true/false/always) -#goto (3): 66S0XXXX 00000000 = goto (lf true/false/always) -#gosub (4): 68S0XXXX 0000000P = gosub (lf true/false/always) - - -_repeat_goto: - rlwinm r9,r4,3,25,28 #r9 = extract P, makes P*8 - addi r9,r9,0x40 #offset that points to block P's - cmpwi r5,2 #compares sub code type with 2 - blt- _repeat - - - rlwinm. r11,r3,10,0,1 #extract (S&3) - beq +20 #S=0, skip lf true, don't skip lf false - bgt +8 - b _b_bl_blr_nocheck #S=2/3, always skip (code exec status turned to true) - beq- cr7,_readcodes #S=1, skip lf false, don't skip lf true - b _b_bl_blr_nocheck - - -_b_bl_blr: - bne- cr7,_readcodes #lf code execution set to false skip code - -_b_bl_blr_nocheck: - cmpwi r5,3 - - bgt- _bl #sub code type >=4, bl - beq+ _b #sub code type ==3, b - -_blr: - lwzx r15,r7,r9 #loads the next code address - b _readcodes - -_bl: - stwx r15,r7,r9 #stores the next code address in block P's address -_b: - extsh r4,r3 #XXXX becomes signed - rlwinm r4,r4,3,9,28 - - add r15,r15,r4 #next code address +/-=line XXXX - b _readcodes - - - -_repeat: - bne- cr7,_readcodes #lf code execution set to false skip code - - add r5,r7,r9 #r5 points to P address - bne- cr4,_execute_repeat #branch lf sub code type == 1 - -_set_repeat: - rlwinm r4,r3,0,16,31 #r4 = extract NNNNN - stw r15,0(r5) #store current code address to [bP's address] - stw r4,4(r5) #store NNNN to [bP's address+4] - - b _readcodes - -_execute_repeat: - lwz r9,4(r5) #load NNNN from [M+4] - cmpwi r9,0 - beq- _readcodes - subi r9,r9,1 - stw r9,4(r5) #saves (NNNN-1) to [bP's address+4] - lwz r15,0(r5) #load next code address from [bP's address] - b _readcodes - -#CT4============================================================================ -#set/add to rN(0) : 80SY000N XXXXXXXX = rN = (ba/po) + XXXXXXXX -#load rN (1) : 82UY000N XXXXXXXX = rN = [XXXXXXXX] (offset support) (U:8/16/32) -#store rN (2) : 84UYZZZN XXXXXXXX = store rN in [XXXXXXXX] (offset support) (8/16/32) - -#operation 1 (3) : 86TY000N XXXXXXXX = operation rN?XXXXXXXX ([rN]?XXXXXXXX) -#operation 2 (4) : 88TY000N 0000000M = operation rN?rM ([rN]?rM, rN?[rM], [rN]?[rM]) - -#copy1 (5) : 8AYYYYNM XXXXXXXX = copy YYYY bytes from [rN] to ([rM]+)XXXXXXXX -#copy2 (6) : 8CYYYYNM XXXXXXXX = copy YYYY bytes from ([rN]+)XXXXXX to [rM] - - -#for copy1/copy2, lf register == 0xF, base address is used. - -#of course, sub codes types 0/1, 2/3 and 4/5 can be put together lf we need more subtypes. - - -_operation_rN: - - bne- cr7,_readcodes - - rlwinm r11,r3,2,26,29 #r11 = extract N, makes N*4 - add r26,r7,r11 #1st value address = rN's address - lwz r9,0(r26) #r9 = rN - - rlwinm r14,r3,12,30,31 #extracts S, U, T (3bits) - - beq- cr4,_op0 #lf sub code type = 0 - - cmpwi cr4,r5,5 - bge- cr4,_op56 #lf sub code type = 5/6 - - cmpwi cr4,r5,3 - bge- cr4,_op34 #lf sub code type = 3/4 - - - cmpwi cr4,r5,1 - -_op12: #load/store - rlwinm. r5,r3,16,31,31 #+(ba/po) flag : Y - beq +8 #address = XXXXXXXX - add r4,r12,r4 - - cmpwi cr6,r14,1 - bne- cr4,_store - -_load: - bgt+ cr6,+24 - beq- cr6,+12 - - lbz r4,0(r4) #load byte at address - b _store_reg - - lhz r4,0(r4) #load halfword at address - b _store_reg - - lwz r4,0(r4) #load word at address - b _store_reg - -_store: - - rlwinm r19,r3,28,20,31 #r9=r3 ror 12 (N84UYZZZ) - -_storeloop: - bgt+ cr6,+32 - beq- cr6,+16 - - stb r9,0(r4) #store byte at address - addi r4,r4,1 - b _storeloopend - - sth r9,0(r4) #store byte at address - addi r4,r4,2 - b _storeloopend - - stw r9,0(r4) #store byte at address - icbi r0, r4 #Invalidate at offset given by storing gecko register - sync - isync - addi r4,r4,4 -_storeloopend: - subic. r19,r19,1 - bge _storeloop - b _readcodes - - -_op0: - rlwinm. r5,r3,16,31,31 #+(ba/po) flag : Y - beq +8 #value = XXXXXXXX - add r4,r4,r12 #value = XXXXXXXX+(ba/po) - - - - andi. r5,r14,1 #add flag : S - beq _store_reg #add flag not set (=0), rN=value - add r4,r4,r9 #add flag set (=1), rN=rN+value - b _store_reg - - - - - -_op34: #operation 1 & 2 - - - rlwinm r10,r3,16,30,31 #extracts Y - - rlwinm r14,r4,2,26,29 #r14 = extract M (in r4), makes M*=4 - - add r19,r7,r14 #2nd value address = rM's address - bne cr4,+8 - subi r19,r15,4 #lf CT3, 2nd value address = XXXXXXXX's address - - - lwz r4,0(r26) #1st value = rN - - lwz r9,0(r19) #2nd value = rM/XXXXXXXX - - - andi. r11,r10,1 #lf [] for 1st value - beq +8 - mr r26,r4 - - - andi. r11,r10,2 #lf [] for 2nd value - beq +16 - mr r19,r9 - bne+ cr4,+8 - add r19,r12,r19 #lf CT3, 2nd value address = XXXXXXXX+(ba/op) - - - - rlwinm. r5,r3,12,28,31 #operation # flag : T - - - cmpwi r5,9 - bge _op_float - - -_operation_bl: - bl _operation_bl_return - -_op450: - add r4,r9,r4 #N + M - b _store_reg - -_op451: - mullw r4,r9,r4 #N * M - b _store_reg - -_op452: - or r4,r9,r4 #N | M - b _store_reg - -_op453: - and r4,r9,r4 #N & M - b _store_reg - -_op454: - xor r4,r9,r4 #N ^ M - b _store_reg - -_op455: - slw r4,r9,r4 #N << M - b _store_reg - -_op456: - srw r4,r9,r4 #N >> M - b _store_reg - -_op457: - rlwnm r4,r9,r4,0,31 #N rol M - b _store_reg - -_op458: - sraw r4,r9,r4 #N asr M - -_store_reg: - stw r4,0(r26) #Store result in rN/[rN] - b _readcodes - -_op_float: - cmpwi r5,0xA - bgt _readcodes - - lfs f2,0(r26) #f2 = load 1st value - lfs f3,0(r19) #f3 = load 2nd value - beq- _op45A - - -_op459: - fadds f2,f3,f2 #N = N + M (float) - b _store_float - -_op45A: - fmuls f2,f3,f2 #N = N * M (float) - -_store_float: - stfs f2,0(r26) #Store result in rN/[rN] - b _readcodes - -_operation_bl_return: - mflr r10 - rlwinm r5,r5,3,25,28 #r5 = T*8 - add r10,r10,r5 #jumps to _op5: + r5 - - lwz r4,0(r26) #load [rN] - lwz r9,0(r19) #2nd value address = rM/XXXXXXXX - - mtlr r10 - blr - - -#copy1 (5) : 8AYYYYNM XXXXXXXX = copy YYYY bytes from [rN] to ([rM]+)XXXXXXXX -#copy2 (6) : 8CYYYYNM XXXXXXXX = copy YYYY bytes from ([rN]+)XXXXXX to [rM] - -_op56: - - bne- cr7,_readcodes #lf code execution set to false skip code - - rlwinm r9,r3,24,0,31 #r9=r3 ror 8 (NM8AYYYY, NM8CYYYY) - mr r14,r12 #r14=(ba/po) - bl _load_NM - - beq- cr4,+12 - add r17,r17,r4 #lf sub code type==0 then source+=XXXXXXXX - b +8 - add r9,r9,r4 #lf sub code type==1 then destination+=XXXXXXXX - - rlwinm. r4,r3,24,16,31 #Extracts YYYY, compares it with 0 - li r5,0 - - _copy_loop: - beq _readcodes #Loop until all bytes have been copied. - lbzx r10,r5,r17 - stbx r10,r5,r9 - addi r5,r5,1 - cmpw r5,r4 - b _copy_loop - - - -#=============================================================================== -#This is a routine called by _memory_copy and _compare_NM_16 - -_load_NM: - - cmpwi cr5,r10,4 #compare code type and 4(rn Operations) in cr5 - - rlwinm r17,r9,6,26,29 #Extracts N*4 - cmpwi r17,0x3C - lwzx r17,r7,r17 #Loads rN value in r17 - bne +8 - mr r17,r14 #lf N==0xF then source address=(ba/po)(+XXXXXXXX, CT5) - - beq cr5,+8 - lhz r17,0(r17) #...and lf CT5 then N = 16 bits at [XXXXXX+base address] - - rlwinm r9,r9,10,26,29 #Extracts M*4 - cmpwi r9,0x3C - lwzx r9,r7,r9 #Loads rM value in r9 - bne +8 - mr r9,r14 #lf M==0xF then dest address=(ba/po)(+XXXXXXXX, CT5) - - beq cr5,+8 - lhz r9,0(r9) #...and lf CT5 then M = 16 bits at [XXXXXX+base address] - - - blr - -#CT5============================================================================ -#16bits conditional (0,1,2,3): A0XXXXXX NM00YYYY (unknown values) -#16bits conditional (4,5,6,7): A8XXXXXX ZZZZYYYY (counter) - -#sub codes types 0,1,2,3 compare [rN] with [rM] (both 16bits values) -#lf register == 0xF, the value at [base address+XXXXXXXX] is used. - -_compare16_NM_counter: - cmpwi r5,4 - bge _compare16_counter - -_compare16_NM: - - mr r9,r4 #r9=NM00YYYY - - add r14,r3,r12 #r14 = XXXXXXXX+(ba/po) - - rlwinm r14,r14,0,0,30 #16bits align (base address+XXXXXXXX) - - bl _load_NM #r17 = N's value, r9 = M's value - - nor r4,r4,r4 #r4=!r4 - rlwinm r4,r4,0,16,31 #Extracts !YYYY - - and r11,r9,r4 #r3 = (M AND !YYYY) - and r4,r17,r4 #r4 = (N AND !YYYY) - - b _conditional - - -_compare16_counter: - rlwinm r11,r3,28,16,31 #extract counter value from r3 in r11 - b _conditional - -#=============================================================================== -#execute (0) : C0000000 NNNNNNNN = execute -#hook1 (2) : C4XXXXXX NNNNNNNN = insert instructions at XXXXXX -#hook2 (3) : C6XXXXXX YYYYYYYY = branch from XXXXXX to YYYYYY -#on/off (6) : CC000000 00000000 = on/off switch -#range check (7) : CE000000 XXXXYYYY = is ba/po in XXXX0000-YYYY0000 - -_hook_execute: - mr r26,r4 #r18 = 0YYYYYYY - rlwinm r4,r4,3,0,28 #r4 = NNNNNNNN*8 = number of lines (and not number of bytes) - bne- cr4,_hook_addresscheck #lf sub code type != 0 - bne- cr7,_skip_and_align - -_execute: - mtlr r15 - blrl - -_skip_and_align: - add r15,r4,r15 - addi r15,r15,7 - rlwinm r15,r15,0,0,28 #align 64-bit - b _readcodes - - -_hook_addresscheck: - - cmpwi cr4,r5,3 - bgt- cr4,_addresscheck1 #lf sub code type ==6 or 7 - lis r5,0x4800 - add r12,r3,r12 - rlwinm r12,r12,0,0,29 #align address - - bne- cr4,_hook1 #lf sub code type ==2 - - -_hook2: - bne- cr7,_readcodes - - rlwinm r4,r26,0,0,29 #address &=0x01FFFFFC - - sub r4,r4,r12 #r4 = to-from - rlwimi r5,r4,0,6,29 #r5 = (r4 AND 0x03FFFFFC) OR 0x48000000 - rlwimi r5,r3,0,31,31 #restore lr bit - stw r5,0(r12) #store opcode - icbi r0, r12 #Invalidate at branch - sync - isync - b _readcodes - -_hook1: - bne- cr7,_skip_and_align - - sub r9,r15,r12 #r9 = to-from - rlwimi r5,r9,0,6,29 #r5 = (r9 AND 0x03FFFFFC) OR 0x48000000 - stw r5,0(r12) #stores b at the hook place (over original instruction) - icbi r0, r12 #Invalidate at hook location - sync - isync - addi r12,r12,4 - add r11,r15,r4 - subi r11,r11,4 #r11 = address of the last word of the hook1 code - sub r9,r12,r11 - rlwimi r5,r9,0,6,29 #r5 = (r9 AND 0x03FFFFFC) OR 0x48000000 - stw r5,0(r11) #stores b at the last word of the hook1 code - icbi r0, r12 #Invalidate at last instruction of hook - sync - isync - b _skip_and_align - - -_addresscheck1: - cmpwi cr4,r5,6 - beq cr4,_onoff - b _conditional -_addresscheck2: - - rlwinm r12,r12,16,16,31 - rlwinm r4,r26,16,16,31 - rlwinm r26,r26,0,16,31 - cmpw r12,r4 - blt _skip - cmpw r12,r26 - bge _skip - b _readcodes - - -_onoff: - rlwinm r5,r26,31,31,31 #extracts old exec status (x b a) - xori r5,r5,1 - andi. r3,r8,1 #extracts current exec status - cmpw r5,r3 - beq _onoff_end - rlwimi r26,r8,1,30,30 - xori r26,r26,2 - - - - rlwinm. r5,r26,31,31,31 #extracts b - beq +8 - - xori r26,r26,1 - - - stw r26,-4(r15) #updates the code value in the code list - - -_onoff_end: - rlwimi r8,r26,0,31,31 #current execution status = a - - b _readcodes - -#=============================================================================== -#Full terminator (0) = E0000000 XXXXXXXX = full terminator -#Endlfs/Else (1) = E2T000VV XXXXXXXX = endlfs (+else) -#End code handler = F0000000 00000000 - -_terminator_onoff_: - cmpwi r11,0 #lf code type = 0xF - beq _notTerminator - cmpwi r5,1 - beq _asmTypeba - cmpwi r5,2 - beq _asmTypepo - cmpwi r5,3 - beq _patchType - b _exitcodehandler - _asmTypeba: - rlwinm r12,r6,0,0,6 # use base address - _asmTypepo: - rlwinm r23,r4,8,24,31 # extract number of half words to XOR - rlwinm r24,r4,24,16,31 # extract XOR checksum - rlwinm r4,r4,0,24,31 # set code value to number of ASM lines only - bne cr7,_goBackToHandler #skip code if code execution is set to false - rlwinm. r25,r23,0,24,24 # check for negative number of half words - mr r26,r12 # copy ba/po address - add r26,r3,r26 # add code offset to ba/po code address - rlwinm r26,r26,0,0,29 # clear last two bits to align address to 32-bit - beq _positiveOffset # if number of half words is negative, extra setup needs to be done - extsb r23,r23 - neg r23,r23 - mulli r25,r23,2 - addi r25,r25,4 - subf r26,r25,r26 - _positiveOffset: - cmpwi r23,0 - beq _endXORLoop - li r25,0 - mtctr r23 - _XORLoop: - lhz r27,4(r26) - xor r25,r27,r25 - addi r26,r26,2 - bdnz _XORLoop - _endXORLoop: - cmpw r24,r25 - bne _goBackToHandler - b _hook_execute - _patchType: - rlwimi r8,r8,1,0,30 #r8<<1 and current execution status = old execution status - bne cr7,_exitpatch #lf code execution is set to false -> exit - rlwinm. r23,r3,22,0,1 - bgt _patchfail - blt _copytopo - _runpatch: - rlwinm r30,r3,0,24,31 - mulli r30,r30,2 - rlwinm r23,r4,0,0,15 - xoris r24,r23,0x8000 - cmpwi r24,0 - bne- _notincodehandler - ori r23,r23,0x3000 - _notincodehandler: - rlwinm r24,r4,16,0,15 - mulli r25,r30,4 - subf r24,r25,r24 - _patchloop: - li r25,0 - _patchloopnext: - mulli r26,r25,4 - lwzx r27,r15,r26 - lwzx r26,r23,r26 - addi r25,r25,1 - cmplw r23,r24 - bgt _failpatchloop - cmpw r25,r30 - bgt _foundaddress - cmpw r26,r27 - beq _patchloopnext - addi r23,r23,4 - b _patchloop - _foundaddress: - lwz r3,-8(r15) - ori r3,r3,0x300 - stw r3,-8(r15) - stw r23,-4(r15) - mr r16,r23 - b _exitpatch - _failpatchloop: - lwz r3,-8(r15) - ori r3,r3,0x100 - stw r3,-8(r15) - _patchfail: - ori r8,r8,1 #r8|=1 (execution status set to false) - b _exitpatch - _copytopo: - mr r16,r4 - _exitpatch: - rlwinm r4,r3,0,24,31 # set code to number of lines only - _goBackToHandler: - mulli r4,r4,8 - add r15,r4,r15 # skip the lines of the code - b _readcodes - _notTerminator: - -_terminator: - bne cr4,+12 #check lf sub code type == 0 - li r8,0 #clear whole code execution status lf T=0 - b +20 - - rlwinm. r9,r3,0,27,31 #extract VV -# bne +8 #lf VV!=0 -# bne- cr7,+16 - - rlwinm r5,r3,12,31,31 #extract "else" bit - - srw r8,r8,r9 #r8>>VV, meaning endlf VV lfs - - rlwinm. r23,r8,31,31,31 - bne +8 # execution is false if code execution >>, so don't invert code status - xor r8,r8,r5 #lf 'else' is set then invert current code status - -_load_baseaddress: - rlwinm. r5,r4,0,0,15 - beq +8 - mr r6,r5 #base address = r4 - rlwinm. r5,r4,16,0,15 - beq +8 - mr r16,r5 #pointer = r4 - b _readcodes - -#=============================================================================== - -frozenvalue: #frozen value, then LR -.long 0,0 -dwordbuffer: -.long 0,0 -rem: -.long 0 -bpbuffer: -.long 0 #int address to bp on -.long 0 #data address to bp on -.long 0 #alignement check -.long 0 #counter for alignement - -regbuffer: -.space 72*4 - -.align 3 - -codelist: -.space 2*4 -.end - - +#MIT License + +#Copyright (c) 2010-2017 Nuke, brkirch, Y.S, Kenobi, gamemasterplc + +#Permission is hereby granted, free of charge, to any person obtaining a copy +#of this software and associated documentation files (the "Software"), to deal +#in the Software without restriction, including without limitation the rights +#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +#copies of the Software, and to permit persons to whom the Software is +#furnished to do so, subject to the following conditions: + +#The above copyright notice and this permission notice shall be included in all +#copies or substantial portions of the Software. + +#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +#SOFTWARE. + +# Based off of codehandleronly.s from Gecko OS source code. +# Example command to build: +# powerpc-elf-gcc -mpowerpc -mpaired -mbig codehandler.s -nostartfiles -nodefaultlibs -nostdlib -T codehandler.ld -o codehandler.bin + +.text +#Register Defines + +.set r0,0; .set r1,1; .set r2,2; .set r3,3; .set r4,4 +.set r5,5; .set r6,6; .set r7,7; .set r8,8; .set r9,9 +.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14 +.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19 +.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24 +.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29 +.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3 + +.globl _start + +gameid: +.long 0,0 +cheatdata: +.long frozenvalue +.space 39*4 + +_start: + stwu r1,-172(r1) # stores sp + stw r0,8(r1) # stores r0 + + mflr r0 + stw r0,176(r1) # stores lr + + mfcr r0 + stw r0,12(r1) # stores cr + + mfctr r0 + stw r0,16(r1) # stores ctr + + mfxer r0 + stw r0,20(r1) # stores xer + + stmw r3,24(r1) # saves r3-r31 + + mfmsr r25 + stw r25,168(r1) # save msr + + ori r26,r25,0x2000 #enable floating point ? + andi. r26,r26,0xF9FF + mtmsr r26 + + stfd f2,152(r1) # stores f2 + stfd f3,160(r1) # stores f3 + + lis r31,cheatdata@h #0x8000 + + lis r20, 0xCC00 + lhz r28, 0x4010(r20) + + ori r21, r28, 0xFF + sth r21, 0x4010(r20) # disable MP3 memory protection + + lis r15, codelist@h + ori r15, r15, codelist@l + + ori r7, r31, cheatdata@l # set pointer for storing data (before the codelist) + + lis r6,0x8000 # default base address = 0x80000000 (code handler) + + mr r16,r6 # default pointer =0x80000000 (code handler) + + li r8,0 # code execution status set to true (code handler) + + lis r3,0x00D0 + ori r3,r3,0xC0DE + + lwz r4,0(r15) + cmpw r3,r4 + bne- _exitcodehandler + lwz r4,4(r15) + cmpw r3,r4 + bne- _exitcodehandler # lf no code list skip code handler + addi r15,r15,8 + b _readcodes + +_exitcodehandler: + sth r28,0x4010(r20) # restore memory protection value + + lfd f2,152(r1) # loads f2 + lfd f3,160(r1) # loads f3 + + lwz r25,168(r1) + mtmsr r25 + + lwz r0,176(r1) + mtlr r0 # restores lr + + lwz r0,12(r1) + mtcr r0 # restores cr + + lwz r0,16(r1) + mtctr r0 # restores ctr + + lwz r0,20(r1) + mtxer r0 # restores xer + + lmw r3,24(r1) # restores r3-r31 + + lwz r0,8(r1) # loads r0 + + addi r1,r1,172 + + isync + + blr # return back to game + +_readcodes: + + lwz r3,0(r15) #load code address + lwz r4,4(r15) #load code value + + addi r15,r15,8 #r15 points to next code + + andi. r9,r8,1 + cmpwi cr7,r9,0 #check code execution status in cr7. eq = true, ne = false + + li r9,0 #Clears r9 + + rlwinm r10,r3,3,29,31 #r10 = extract code type, 3 bits + rlwinm r5,r3,7,29,31 #r5 = extract sub code type 3 bits + + andis. r11,r3,0x1000 #test pointer + rlwinm r3,r3,0,7,31 #r3 = extract address in r3 (code type 0/1/2) #0x01FFFFFF + + bne +12 #jump lf the pointer is used + + rlwinm r12,r6,0,0,6 #lf pointer is not used, address = base address + b +8 + + mr r12,r16 #lf pointer is used, address = pointer + + cmpwi cr4,r5,0 #compares sub code type with 0 in cr4 + + cmpwi r10,1 + blt+ _write #code type 0 : write + beq+ _conditional #code type 1 : conditional + + cmpwi r10,3 + blt+ _ba_pointer #Code type 2 : base address operation + + beq- _repeat_goto #Code type 3 : Repeat & goto + + cmpwi r10,5 + blt- _operation_rN #Code type 4 : rN Operation + beq+ _compare16_NM_counter #Code type 5 : compare [rN] with [rM] + + cmpwi r10,7 + blt+ _hook_execute #Code type 6 : hook, execute code + + b _terminator_onoff_ #code type 7 : End of code list + +#CT0============================================================================= +#write 8bits (0): 00XXXXXX YYYY00ZZ +#write 16bits (1): 02XXXXXX YYYYZZZZ +#write 32bits (2): 04XXXXXX ZZZZZZZZ +#string code (3): 06XXXXXX YYYYYYYY, d1d1d1d1 d2d2d2d2, d3d3d3d3 .... +#Serial Code (4): 08XXXXXX YYYYYYYY TNNNZZZZ VVVVVVVV + +_write: + add r12,r12,r3 #address = (ba/po)+(XXXXXX) + cmpwi r5,3 + beq- _write_string #r5 == 3, goto string code + bgt- _write_serial #r5 >= 4, goto serial code + + bne- cr7,_readcodes #lf code execution set to false skip code + + cmpwi cr4,r5,1 #compares sub code type and 1 in cr4 + + bgt- cr4,_write32 #lf sub code type == 2, goto write32 + +#lf sub code type = 0 or 1 (8/16bits) + rlwinm r10,r4,16,16,31 #r10 = extract number of times to write (16bits value) + +_write816: + beq cr4,+32 #lf r5 = 1 then 16 bits write + stbx r4,r9,r12 #write byte + add r21, r9, r12 + icbi r0, r21 + sync + isync + addi r9,r9,1 + b +28 + sthx r4,r9,r12 #write halfword + add r21, r9, r12 #Get Real Memory Offset + icbi r0, r21 #Invalidate Icache around real memory offset + sync + isync + addi r9,r9,2 + subic. r10,r10,1 #number of times to write -1 + bge- _write816 + b _readcodes + +_write32: + rlwinm r12,r12,0,0,29 #32bits align adress + stw r4,0(r12) #write word to address + icbi r0, r12 #Invalidate icache around address + sync + isync + b _readcodes + +_write_string: #endianess ? + mr r9,r4 + bne- cr7,_skip_and_align #lf code execution is false, skip string code data + +_stb: + subic. r9,r9,1 #r9 -= 1 (and compares r9 with 0) + blt- _skip_and_align #lf r9 < 0 then exit + lbzx r5,r9,r15 + stbx r5,r9,r12 #loop until all the data has been written + add r21, r9, r12 #Get Real Memory Offset + icbi r0, r21 #Invalidate Icache around real memory offset + sync + isync + b _stb + +_write_serial: + + addi r15,r15,8 #r15 points to the code after the serial code + bne- cr7,_readcodes #lf code execution is false, skip serial code + + lwz r5,-8(r15) #load TNNNZZZZ + lwz r11,-4(r15) #r11 = load VVVVVVVV + + rlwinm r17,r5,0,16,31 #r17 = ZZZZ + rlwinm r10,r5,16,20,31 #r10 = NNN (# of times to write -1) + rlwinm r5,r5,4,28,31 #r5 = T (0:8bits/1:16bits/2:32bits) + +_loop_serial: + cmpwi cr5,r5,1 + beq- cr5,+16 #lf 16bits + bgt+ cr5,+20 #lf 32bits + + stbx r4,r9,r12 #write serial byte (CT04,T=0) + b +16 + + sthx r4,r9,r12 #write serial halfword (CT04,T=1) + b +8 + + stwx r4,r9,r12 #write serial word (CT04,T>=2) + add r21, r9, r12 #Get Real Memory Offset + icbi r0, r21 #Invalidate Icache around real memory offset + sync + isync + add r4,r4,r11 #value +=VVVVVVVV + add r9,r9,r17 #address +=ZZZZ + subic. r10,r10,1 + bge+ _loop_serial #loop until all the data has been written + + b _readcodes + +#CT1============================================================================= +#32bits conditional (0,1,2,3): 20XXXXXX YYYYYYYY +#16bits conditional (4,5,6,7): 28XXXXXX ZZZZYYYY + +#PS : 31 bit of address = endlf. + +_conditional: + rlwinm. r9,r3,0,31,31 #r10 = (bit31 & 1) (endlf enabled?) + + beq +16 #jump lf endlf is not enabled + + rlwinm r8,r8,31,1,31 #Endlf (r8>>1) + andi. r9,r8,1 #r9=code execution status + cmpwi cr7,r9,0 #check code execution status in cr7 + cmpwi cr5,r5,4 #compares sub code type and 4 in cr5 + cmpwi cr3,r10,5 #compares code type and 5 in cr3 + + rlwimi r8,r8,1,0,30 #r8<<1 and current execution status = old execution status + bne- cr7,_true_end #lf code execution is set to false -> exit + + bgt cr3,_addresscheck2 #lf code type==6 -> address check + add r12,r12,r3 #address = (ba/po)+(XXXXXX) + + blt cr3,+12 #jump lf code type <5 (==1) + blt cr5,_condition_sub #compare [rN][rM] + b _conditional16_2 #counter compare + bge cr5,_conditional16 #lf sub code type>=4 -> 16 bits conditional + +_conditional32: + rlwinm r12,r12,0,0,29 #32bits align + lwz r11,0(r12) + b _condition_sub + +_conditional16: + rlwinm r12,r12,0,0,30 #16bits align + lhz r11,0(r12) +_conditional16_2: + nor r9,r4,r4 + rlwinm r9,r9,16,16,31 #r9 = extract mask + and r11,r11,r9 #r11 &= r9 + rlwinm r4,r4,0,16,31 #r4 = extract data to check against + +_condition_sub: + cmpl cr6,r11,r4 #Unsigned compare. r11=data at address, r4=YYYYYYYY + andi. r9,r5,3 + beq _skip_NE #lf sub code (type & 3) == 0 + cmpwi r9,2 + beq _skip_LE #lf sub code (type & 3) == 2 + bgt _skip_GE #lf sub code (type & 3) == 3 + +_skip_EQ:#1 + bne- cr6,_true_end #CT21, CT25, CT29 or CT2D (lf !=) + b _skip + +_skip_NE:#0 + beq- cr6,_true_end #CT20, CT24, CT28 or CT2C (lf==) + b _skip + +_skip_LE:#2 + bgt- cr6,_true_end #CT22, CT26, CT2A or CT2E (lf r4>[]) + b _skip + +_skip_GE:#3 + blt- cr6,_true_end #CT23, CT27, CT2B or CT2F (lf r4 5 + blt cr5,_readcodes + lwz r11,-8(r15) #load counter + bne cr7,_clearcounter #lf previous code execution false clear counter + andi. r12,r3,0x8 #else lf clear counter bit not set increase counter + beq _increase_counter + andi. r12,r8,0x1 #else lf.. code result true clear counter + beq _clearcounter + +_increase_counter: + addi r12,r11,0x10 #else increase the counter + rlwimi r11,r12,0,12,27 #update counter + b _savecounter + +_clearcounter: + rlwinm r11,r11,0,28,11 #clear the counter +_savecounter: + stw r11,-8(r15) #save counter + b _readcodes + +#CT2============================================================================ + +#load base adress (0): 40TYZ00N XXXXXXXX = (load/add:T) ba from [(ba/po:Y)+XXXXXXXX(+rN:Z)] + +#set base address (1): 42TYZ00N XXXXXXXX = (set/add:T) ba to (ba/po:Y)+XXXXXXXX(+rN:Z) + +#store base address (2): 440Y0000 XXXXXXXX = store base address to [(ba/po)+XXXXXXXX] +#set base address to (3): 4600XXXX 00000000 = set base address to code address+XXXXXXXX +#load pointer (4): 48TYZ00N XXXXXXXX = (load/add:T) po from [(ba/po:Y)+XXXXXXXX(+rN:Z)] + +#set pointer (5): 4ATYZ00N XXXXXXXX = (set/add:T) po to (ba/po:Y)+XXXXXXXX(+rN:Y) + +#store pointer (6): 4C0Y0000 XXXXXXXX = store pointer to [(ba/po)+XXXXXXXX] +#set pointer to (7): 4E00XXXX 00000000 = set pointer to code address+XXXXXXXX + +_ba_pointer: + + bne- cr7,_readcodes + + rlwinm r9,r3,2,26,29 #r9 = extract N, makes N*4 + + rlwinm r14,r3,16,31,31 #r3 = add ba/po flag bit (Y) + cmpwi cr3,r14,0 + + cmpwi cr4,r5,4 #cr4 = compare sub code type with 4 (ba/po) + andi. r14,r5,3 #r14 = sub code type and 3 + + cmpwi cr5,r14,2 #compares sub code type and 2 + + blt- cr5,_p01 + beq- cr5,_p2 #sub code type 2 + +_p3: + extsh r4,r3 + add r4,r4,r15 #r4=XXXXXXXX+r15 (code location in memory) + b _pend + +_p01: + + rlwinm. r5,r3,20,31,31 #r3 = rN use bit (Z) + beq +12 #flag is not set(=0), address = XXXXXXXX + + lwzx r9,r7,r9 #r9 = load register N + add r4,r4,r9 #flag is set (=1), address = XXXXXXXX+rN + + beq cr3,+8 #(Y) flag is not set(=0), address = XXXXXXXX (+rN) + + add r4,r12,r4 #address = XXXXXXXX (+rN) + (ba/po) + + cmpwi cr5,r14,1 + beq cr5,+8 #address = (ba/po)+XXXXXXXX(+rN) + lwz r4,0(r4) #address = [(ba/po)+XXXXXXXX(+rN)] + + rlwinm. r3,r3,12,31,31 #r5 = add/replace flag (T) + beq _pend #flag is not set (=0), (ba/po)= XXXXXXXX (+rN) + (ba/po) + bge cr4,+12 + add r4,r4,r6 #ba += XXXXXXXX (+rN) + (ba/po) + b _pend + add r4,r4,r16 #po += XXXXXXXX (+rN) + (ba/po) + b _pend + +_p2: + rlwinm. r5,r3,20,31,31 #r3 = rN use bit (Z) + beq +12 #flag is not set(=0), address = XXXXXXXX + + lwzx r9,r7,r9 #r9 = load register N + add r4,r4,r9 #flag is set (=1), address = XXXXXXXX+rN + + bge cr4,+12 + stwx r6,r12,r4 #[(ba/po)+XXXXXXXX] = base address + b _readcodes + stwx r16,r12,r4 #[(ba/po)+XXXXXXXX] = pointer + b _readcodes + +_pend: + bge cr4,+12 + mr r6,r4 #store result to base address + b _readcodes + mr r16,r4 #store result to pointer + b _readcodes + +#CT3============================================================================ +#set repeat (0): 6000ZZZZ 0000000P = set repeat +#execute repeat (1): 62000000 0000000P = execute repeat +#return (2): 64S00000 0000000P = return (lf true/false/always) +#goto (3): 66S0XXXX 00000000 = goto (lf true/false/always) +#gosub (4): 68S0XXXX 0000000P = gosub (lf true/false/always) + + +_repeat_goto: + rlwinm r9,r4,3,25,28 #r9 = extract P, makes P*8 + addi r9,r9,0x40 #offset that points to block P's + cmpwi r5,2 #compares sub code type with 2 + blt- _repeat + + + rlwinm. r11,r3,10,0,1 #extract (S&3) + beq +20 #S=0, skip lf true, don't skip lf false + bgt +8 + b _b_bl_blr_nocheck #S=2/3, always skip (code exec status turned to true) + beq- cr7,_readcodes #S=1, skip lf false, don't skip lf true + b _b_bl_blr_nocheck + +_b_bl_blr: + bne- cr7,_readcodes #lf code execution set to false skip code + +_b_bl_blr_nocheck: + cmpwi r5,3 + + bgt- _bl #sub code type >=4, bl + beq+ _b #sub code type ==3, b + +_blr: + lwzx r15,r7,r9 #loads the next code address + b _readcodes + +_bl: + stwx r15,r7,r9 #stores the next code address in block P's address +_b: + extsh r4,r3 #XXXX becomes signed + rlwinm r4,r4,3,9,28 + + add r15,r15,r4 #next code address +/-=line XXXX + b _readcodes + +_repeat: + bne- cr7,_readcodes #lf code execution set to false skip code + + add r5,r7,r9 #r5 points to P address + bne- cr4,_execute_repeat #branch lf sub code type == 1 + +_set_repeat: + rlwinm r4,r3,0,16,31 #r4 = extract NNNNN + stw r15,0(r5) #store current code address to [bP's address] + stw r4,4(r5) #store NNNN to [bP's address+4] + + b _readcodes + +_execute_repeat: + lwz r9,4(r5) #load NNNN from [M+4] + cmpwi r9,0 + beq- _readcodes + subi r9,r9,1 + stw r9,4(r5) #saves (NNNN-1) to [bP's address+4] + lwz r15,0(r5) #load next code address from [bP's address] + b _readcodes + +#CT4============================================================================ +#set/add to rN(0) : 80SY000N XXXXXXXX = rN = (ba/po) + XXXXXXXX +#load rN (1) : 82UY000N XXXXXXXX = rN = [XXXXXXXX] (offset support) (U:8/16/32) +#store rN (2) : 84UYZZZN XXXXXXXX = store rN in [XXXXXXXX] (offset support) (8/16/32) + +#operation 1 (3) : 86TY000N XXXXXXXX = operation rN?XXXXXXXX ([rN]?XXXXXXXX) +#operation 2 (4) : 88TY000N 0000000M = operation rN?rM ([rN]?rM, rN?[rM], [rN]?[rM]) + +#copy1 (5) : 8AYYYYNM XXXXXXXX = copy YYYY bytes from [rN] to ([rM]+)XXXXXXXX +#copy2 (6) : 8CYYYYNM XXXXXXXX = copy YYYY bytes from ([rN]+)XXXXXX to [rM] + + +#for copy1/copy2, lf register == 0xF, base address is used. + +#of course, sub codes types 0/1, 2/3 and 4/5 can be put together lf we need more subtypes. + + +_operation_rN: + bne- cr7,_readcodes + + rlwinm r11,r3,2,26,29 #r11 = extract N, makes N*4 + add r26,r7,r11 #1st value address = rN's address + lwz r9,0(r26) #r9 = rN + + rlwinm r14,r3,12,30,31 #extracts S, U, T (3bits) + + beq- cr4,_op0 #lf sub code type = 0 + + cmpwi cr4,r5,5 + bge- cr4,_op56 #lf sub code type = 5/6 + + cmpwi cr4,r5,3 + bge- cr4,_op34 #lf sub code type = 3/4 + + cmpwi cr4,r5,1 + +_op12: #load/store + rlwinm. r5,r3,16,31,31 #+(ba/po) flag : Y + beq +8 #address = XXXXXXXX + add r4,r12,r4 + + cmpwi cr6,r14,1 + bne- cr4,_store + +_load: + bgt+ cr6,+24 + beq- cr6,+12 + + lbz r4,0(r4) #load byte at address + b _store_reg + + lhz r4,0(r4) #load halfword at address + b _store_reg + + lwz r4,0(r4) #load word at address + b _store_reg + +_store: + rlwinm r19,r3,28,20,31 #r9=r3 ror 12 (N84UYZZZ) + +_storeloop: + bgt+ cr6,+32 + beq- cr6,+16 + + stb r9,0(r4) #store byte at address + addi r4,r4,1 + b _storeloopend + + sth r9,0(r4) #store byte at address + addi r4,r4,2 + b _storeloopend + + stw r9,0(r4) #store byte at address + icbi r0, r4 #Invalidate at offset given by storing gecko register + sync + isync + addi r4,r4,4 +_storeloopend: + subic. r19,r19,1 + bge _storeloop + b _readcodes + +_op0: + rlwinm. r5,r3,16,31,31 #+(ba/po) flag : Y + beq +8 #value = XXXXXXXX + add r4,r4,r12 #value = XXXXXXXX+(ba/po) + + andi. r5,r14,1 #add flag : S + beq _store_reg #add flag not set (=0), rN=value + add r4,r4,r9 #add flag set (=1), rN=rN+value + b _store_reg + +_op34: #operation 1 & 2 + rlwinm r10,r3,16,30,31 #extracts Y + + rlwinm r14,r4,2,26,29 #r14 = extract M (in r4), makes M*=4 + + add r19,r7,r14 #2nd value address = rM's address + bne cr4,+8 + subi r19,r15,4 #lf CT3, 2nd value address = XXXXXXXX's address + + lwz r4,0(r26) #1st value = rN + + lwz r9,0(r19) #2nd value = rM/XXXXXXXX + + andi. r11,r10,1 #lf [] for 1st value + beq +8 + mr r26,r4 + + andi. r11,r10,2 #lf [] for 2nd value + beq +16 + mr r19,r9 + bne+ cr4,+8 + add r19,r12,r19 #lf CT3, 2nd value address = XXXXXXXX+(ba/op) + + rlwinm. r5,r3,12,28,31 #operation # flag : T + + cmpwi r5,9 + bge _op_float + +_operation_bl: + bl _operation_bl_return + +_op450: + add r4,r9,r4 #N + M + b _store_reg + +_op451: + mullw r4,r9,r4 #N * M + b _store_reg + +_op452: + or r4,r9,r4 #N | M + b _store_reg + +_op453: + and r4,r9,r4 #N & M + b _store_reg + +_op454: + xor r4,r9,r4 #N ^ M + b _store_reg + +_op455: + slw r4,r9,r4 #N << M + b _store_reg + +_op456: + srw r4,r9,r4 #N >> M + b _store_reg + +_op457: + rlwnm r4,r9,r4,0,31 #N rol M + b _store_reg + +_op458: + sraw r4,r9,r4 #N asr M + +_store_reg: + stw r4,0(r26) #Store result in rN/[rN] + b _readcodes + +_op_float: + cmpwi r5,0xA + bgt _readcodes + + lfs f2,0(r26) #f2 = load 1st value + lfs f3,0(r19) #f3 = load 2nd value + beq- _op45A + + +_op459: + fadds f2,f3,f2 #N = N + M (float) + b _store_float + +_op45A: + fmuls f2,f3,f2 #N = N * M (float) + +_store_float: + stfs f2,0(r26) #Store result in rN/[rN] + b _readcodes + +_operation_bl_return: + mflr r10 + rlwinm r5,r5,3,25,28 #r5 = T*8 + add r10,r10,r5 #jumps to _op5: + r5 + + lwz r4,0(r26) #load [rN] + lwz r9,0(r19) #2nd value address = rM/XXXXXXXX + + mtlr r10 + blr + +#copy1 (5) : 8AYYYYNM XXXXXXXX = copy YYYY bytes from [rN] to ([rM]+)XXXXXXXX +#copy2 (6) : 8CYYYYNM XXXXXXXX = copy YYYY bytes from ([rN]+)XXXXXX to [rM] + +_op56: + + bne- cr7,_readcodes #lf code execution set to false skip code + + rlwinm r9,r3,24,0,31 #r9=r3 ror 8 (NM8AYYYY, NM8CYYYY) + mr r14,r12 #r14=(ba/po) + bl _load_NM + + beq- cr4,+12 + add r17,r17,r4 #lf sub code type==0 then source+=XXXXXXXX + b +8 + add r9,r9,r4 #lf sub code type==1 then destination+=XXXXXXXX + + rlwinm. r4,r3,24,16,31 #Extracts YYYY, compares it with 0 + li r5,0 + + _copy_loop: + beq _readcodes #Loop until all bytes have been copied. + lbzx r10,r5,r17 + stbx r10,r5,r9 + addi r5,r5,1 + cmpw r5,r4 + b _copy_loop + +#=============================================================================== +#This is a routine called by _memory_copy and _compare_NM_16 + +_load_NM: + + cmpwi cr5,r10,4 #compare code type and 4(rn Operations) in cr5 + + rlwinm r17,r9,6,26,29 #Extracts N*4 + cmpwi r17,0x3C + lwzx r17,r7,r17 #Loads rN value in r17 + bne +8 + mr r17,r14 #lf N==0xF then source address=(ba/po)(+XXXXXXXX, CT5) + + beq cr5,+8 + lhz r17,0(r17) #...and lf CT5 then N = 16 bits at [XXXXXX+base address] + + rlwinm r9,r9,10,26,29 #Extracts M*4 + cmpwi r9,0x3C + lwzx r9,r7,r9 #Loads rM value in r9 + bne +8 + mr r9,r14 #lf M==0xF then dest address=(ba/po)(+XXXXXXXX, CT5) + + beq cr5,+8 + lhz r9,0(r9) #...and lf CT5 then M = 16 bits at [XXXXXX+base address] + + blr + +#CT5============================================================================ +#16bits conditional (0,1,2,3): A0XXXXXX NM00YYYY (unknown values) +#16bits conditional (4,5,6,7): A8XXXXXX ZZZZYYYY (counter) + +#sub codes types 0,1,2,3 compare [rN] with [rM] (both 16bits values) +#lf register == 0xF, the value at [base address+XXXXXXXX] is used. + +_compare16_NM_counter: + cmpwi r5,4 + bge _compare16_counter + +_compare16_NM: + + mr r9,r4 #r9=NM00YYYY + + add r14,r3,r12 #r14 = XXXXXXXX+(ba/po) + + rlwinm r14,r14,0,0,30 #16bits align (base address+XXXXXXXX) + + bl _load_NM #r17 = N's value, r9 = M's value + + nor r4,r4,r4 #r4=!r4 + rlwinm r4,r4,0,16,31 #Extracts !YYYY + + and r11,r9,r4 #r3 = (M AND !YYYY) + and r4,r17,r4 #r4 = (N AND !YYYY) + + b _conditional + +_compare16_counter: + rlwinm r11,r3,28,16,31 #extract counter value from r3 in r11 + b _conditional + +#=============================================================================== +#execute (0) : C0000000 NNNNNNNN = execute +#hook1 (2) : C4XXXXXX NNNNNNNN = insert instructions at XXXXXX +#hook2 (3) : C6XXXXXX YYYYYYYY = branch from XXXXXX to YYYYYY +#on/off (6) : CC000000 00000000 = on/off switch +#range check (7) : CE000000 XXXXYYYY = is ba/po in XXXX0000-YYYY0000 + +_hook_execute: + mr r26,r4 #r18 = 0YYYYYYY + rlwinm r4,r4,3,0,28 #r4 = NNNNNNNN*8 = number of lines (and not number of bytes) + bne- cr4,_hook_addresscheck #lf sub code type != 0 + bne- cr7,_skip_and_align + +_execute: + mtlr r15 + blrl + +_skip_and_align: + add r15,r4,r15 + addi r15,r15,7 + rlwinm r15,r15,0,0,28 #align 64-bit + b _readcodes + + +_hook_addresscheck: + + cmpwi cr4,r5,3 + bgt- cr4,_addresscheck1 #lf sub code type ==6 or 7 + lis r5,0x4800 + add r12,r3,r12 + rlwinm r12,r12,0,0,29 #align address + + bne- cr4,_hook1 #lf sub code type ==2 + +_hook2: + bne- cr7,_readcodes + + rlwinm r4,r26,0,0,29 #address &=0x01FFFFFC + + sub r4,r4,r12 #r4 = to-from + rlwimi r5,r4,0,6,29 #r5 = (r4 AND 0x03FFFFFC) OR 0x48000000 + rlwimi r5,r3,0,31,31 #restore lr bit + stw r5,0(r12) #store opcode + icbi r0, r12 #Invalidate at branch + sync + isync + b _readcodes + +_hook1: + bne- cr7,_skip_and_align + + sub r9,r15,r12 #r9 = to-from + rlwimi r5,r9,0,6,29 #r5 = (r9 AND 0x03FFFFFC) OR 0x48000000 + stw r5,0(r12) #stores b at the hook place (over original instruction) + icbi r0, r12 #Invalidate at hook location + sync + isync + addi r12,r12,4 + add r11,r15,r4 + subi r11,r11,4 #r11 = address of the last word of the hook1 code + sub r9,r12,r11 + rlwimi r5,r9,0,6,29 #r5 = (r9 AND 0x03FFFFFC) OR 0x48000000 + stw r5,0(r11) #stores b at the last word of the hook1 code + icbi r0, r12 #Invalidate at last instruction of hook + sync + isync + b _skip_and_align + +_addresscheck1: + cmpwi cr4,r5,6 + beq cr4,_onoff + b _conditional +_addresscheck2: + + rlwinm r12,r12,16,16,31 + rlwinm r4,r26,16,16,31 + rlwinm r26,r26,0,16,31 + cmpw r12,r4 + blt _skip + cmpw r12,r26 + bge _skip + b _readcodes + +_onoff: + rlwinm r5,r26,31,31,31 #extracts old exec status (x b a) + xori r5,r5,1 + andi. r3,r8,1 #extracts current exec status + cmpw r5,r3 + beq _onoff_end + rlwimi r26,r8,1,30,30 + xori r26,r26,2 + rlwinm. r5,r26,31,31,31 #extracts b + beq +8 + + xori r26,r26,1 + + stw r26,-4(r15) #updates the code value in the code list + +_onoff_end: + rlwimi r8,r26,0,31,31 #current execution status = a + + b _readcodes + +#=============================================================================== +#Full terminator (0) = E0000000 XXXXXXXX = full terminator +#Endlfs/Else (1) = E2T000VV XXXXXXXX = endlfs (+else) +#End code handler = F0000000 00000000 + +_terminator_onoff_: + cmpwi r11,0 #lf code type = 0xF + beq _notTerminator + cmpwi r5,1 + beq _asmTypeba + cmpwi r5,2 + beq _asmTypepo + cmpwi r5,3 + beq _patchType + b _exitcodehandler + _asmTypeba: + rlwinm r12,r6,0,0,6 # use base address + _asmTypepo: + rlwinm r23,r4,8,24,31 # extract number of half words to XOR + rlwinm r24,r4,24,16,31 # extract XOR checksum + rlwinm r4,r4,0,24,31 # set code value to number of ASM lines only + bne cr7,_goBackToHandler #skip code if code execution is set to false + rlwinm. r25,r23,0,24,24 # check for negative number of half words + mr r26,r12 # copy ba/po address + add r26,r3,r26 # add code offset to ba/po code address + rlwinm r26,r26,0,0,29 # clear last two bits to align address to 32-bit + beq _positiveOffset # if number of half words is negative, extra setup needs to be done + extsb r23,r23 + neg r23,r23 + mulli r25,r23,2 + addi r25,r25,4 + subf r26,r25,r26 + _positiveOffset: + cmpwi r23,0 + beq _endXORLoop + li r25,0 + mtctr r23 + _XORLoop: + lhz r27,4(r26) + xor r25,r27,r25 + addi r26,r26,2 + bdnz _XORLoop + _endXORLoop: + cmpw r24,r25 + bne _goBackToHandler + b _hook_execute + _patchType: + rlwimi r8,r8,1,0,30 #r8<<1 and current execution status = old execution status + bne cr7,_exitpatch #lf code execution is set to false -> exit + rlwinm. r23,r3,22,0,1 + bgt _patchfail + blt _copytopo + _runpatch: + rlwinm r30,r3,0,24,31 + mulli r30,r30,2 + rlwinm r23,r4,0,0,15 + xoris r24,r23,0x8000 + cmpwi r24,0 + bne- _notincodehandler + ori r23,r23,0x3000 + _notincodehandler: + rlwinm r24,r4,16,0,15 + mulli r25,r30,4 + subf r24,r25,r24 + _patchloop: + li r25,0 + _patchloopnext: + mulli r26,r25,4 + lwzx r27,r15,r26 + lwzx r26,r23,r26 + addi r25,r25,1 + cmplw r23,r24 + bgt _failpatchloop + cmpw r25,r30 + bgt _foundaddress + cmpw r26,r27 + beq _patchloopnext + addi r23,r23,4 + b _patchloop + _foundaddress: + lwz r3,-8(r15) + ori r3,r3,0x300 + stw r3,-8(r15) + stw r23,-4(r15) + mr r16,r23 + b _exitpatch + _failpatchloop: + lwz r3,-8(r15) + ori r3,r3,0x100 + stw r3,-8(r15) + _patchfail: + ori r8,r8,1 #r8|=1 (execution status set to false) + b _exitpatch + _copytopo: + mr r16,r4 + _exitpatch: + rlwinm r4,r3,0,24,31 # set code to number of lines only + _goBackToHandler: + mulli r4,r4,8 + add r15,r4,r15 # skip the lines of the code + b _readcodes + _notTerminator: + +_terminator: + bne cr4,+12 #check lf sub code type == 0 + li r8,0 #clear whole code execution status lf T=0 + b +20 + + rlwinm. r9,r3,0,27,31 #extract VV +# bne +8 #lf VV!=0 +# bne- cr7,+16 + + rlwinm r5,r3,12,31,31 #extract "else" bit + + srw r8,r8,r9 #r8>>VV, meaning endlf VV lfs + + rlwinm. r23,r8,31,31,31 + bne +8 # execution is false if code execution >>, so don't invert code status + xor r8,r8,r5 #lf 'else' is set then invert current code status + +_load_baseaddress: + rlwinm. r5,r4,0,0,15 + beq +8 + mr r6,r5 #base address = r4 + rlwinm. r5,r4,16,0,15 + beq +8 + mr r16,r5 #pointer = r4 + b _readcodes + +#=============================================================================== + +frozenvalue: #frozen value, then LR +.long 0,0 +dwordbuffer: +.long 0,0 +rem: +.long 0 +bpbuffer: +.long 0 #int address to bp on +.long 0 #data address to bp on +.long 0 #alignement check +.long 0 #counter for alignement + +regbuffer: +.space 72*4 + +.align 3 + +codelist: +.space 2*4 +.end