#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

# Warning, _strip_and_align expects cheat codes to start on 0x0 or 0x8.
# Properly compiling it will add a nop if needed.
_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

 _Write_32:
	lwz r18, 0(r12)	#Load data from registry that will be written to
	cmpw r18, r5 	#Is data to be written equal to the data in memory
	beq+ +72 		#Skip if yes
	stw r5, 0(r12) 	#store opcode
	li r9, 0 		#safe, check r9 if more write_32's are linked.
    b +48
    
_Write_08x:
	lbzx r18, r9, r12
	rlwinm r0, r4, 0, 24,31	#Clears any other data with r4's byte, for compare
	cmpw r0, r18
	beq+ +44
	stbx r4,r9,r12
	b +24 

_Write_16x:
	lhzx r18, r9, r12
	rlwinm r0, r4, 0, 16,31	#Makes sure r4 is just a halfword for compare
	cmpw r0, r18
	beq+ +20
	sthx r4,r9,r12
	icbi r9, r12 #branch target. Clears cache. Need dcbf?
	sync
	isync
	blr

#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,+16   #lf r5 = 1 then 16 bits write
  bl _Write_08x
  addi r9,r9,1
  b +12
  bl _Write_16x
  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
  mr r5, r4
  bl _Write_32
  b _readcodes

_write_string:    #endianess ?
  mr r9,r4
  mr r22, 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
  mr r4, r5
  bl _Write_08x  #loop until all the data has been written
  mr r4, r22
  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

  bl _Write_08x
  b +40

  bl _Write_16x  #write serial halfword (CT04,T=1)
  b +32
  
  lwzx r18, r9, r12
  cmpw r4, r18
  beq+ +20
  stwx r4,r9,r12  #write serial word (CT04,T>=2)
  icbi r9, r12 #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<r4)

_skip:
  ori r8,r8,1   #r8|=1 (execution status set to false)
_true_end:
  bne+ cr3,_readcodes  #lf code type <> 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 address    (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)
  
  mr r12, r4
  mr r4, r9
  mr r5, r9
  li r9, 0
_storeloop:
  bgt+ cr6,+32
  beq- cr6,+16

  bl _Write_08x  #store byte at address
  addi r12,r12,1
  b _storeloopend

  bl _Write_16x  #store byte at address
  addi r12,r12,2
  b _storeloopend

  bl _Write_32
  addi r12,r12,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. End with 4E800020 00000000.
#hook1       (2) : C4XXXXXX NNNNNNNN = insert instructions at XXXXXX. Same as C2.
#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   #r26 = 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
  bl _Write_32
  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
  bl _Write_32
  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
  mr r12, r11
  bl _Write_32
  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