08-15-2024, 02:58 AM
(This post was last modified: 08-15-2024, 03:56 AM by Fifty.
Edit Reason: tutorial update
)
Utilizing the Condition Register
For Advanced ASM Coders
Chapter 1: Intro
Requirements:
Are your codes ending up with "countless" branches and branch labels? Your codes are in need of some spring cleaning. Sometimes codes that have an excessive amount branches end up "unreadable", making it difficult for others to understand your code or help you debug any errors.
Chapter 2: Condition Register Fundamentals
When you execute any plane jane comparison instruction such as....
...you are actually telling Broadway to run a check and then place the result of said check in Condition Register Field 0.
What is Condition Register Field 0? First thing's first. The register you see in Dolphin that is named "CR" is the Condition Register. It contains the results of previously executed Compare Instructions. Conditional Branch Instructions (i.e. beq) read the data of the Condition Register to determine whether or not a branch route/jump is taken.
The Condition Register contains 7 fields. Field 0 (cr0) thru Field 7 (cr7).
STUVWXYZ
S = cr0
T = cr1
U = cr2
etc etc..
Each field (crF) takes up one DIGIT (half-byte) in the CR. Thus, each crF contains 4 bits of data. You can specify which crF to place the result of the compare instruction in. By default, if no crF is specified in your compare instruction, then cr0 will be used.
is short for...
If you wish to use cr7 instead of cr0, you would write the instruction like this...
An important thing that you must keep in mind is that if you make a comparison that is NOT using cr0, you must also specify the crF in the subsequent branch instruction.
Like this...
In conclusion, any crF that isn't cr0 must be specified in both compare and branch instructions.
Chapter 3: Condition Register Field Bits and Examining Branch Instructions
Now that you know there are 7 crF's and how to use each one in your comparison + branch instructions, let's cover the crF bits and what each bit represents.
Each crF has 4 bits of data that uses the following structure.
CR Bit Table
LT GT EQ SO crfX
0 1 2 3 crf0
4 5 6 7 crf1
8 9 10 11 crf2
12 13 14 15 crf3
16 17 18 19 crf4
20 21 22 23 crf5
24 25 26 27 crf6
28 29 30 31 crf7
Whenever a bit in the crF is high, the condition was true FROM THE MOST RECENT comparison instruction. Whenever a bit was low, the condition was false FROM THE MOST RECENT comparison.
Multiple bits can be flagged high and/or low from a comparison instruction. Now that you understand the crF bits, let's go over what branch instructions actually do.
The branch instruction checks the bits of the crF that is specified in the instruction.
Example: 'bge- cr7' checks LT bit of cr7. If low, branch is taken.
Chapter 4: Condition Register specific instructions
Before going into the CR specific instructions, we need to go over its 'format'. The 'format' of a typical CR instruction is this..
crXXX B, B, B #XXX = and, or, andc, orc, nor, xor, eqv
Under this format, you need to specify the exact bit of the entire Condtion Register. The problem with this is that it now becomes a memory game and you have to refer to the earlier CR bit table provided in Chapter 3. Instead of doing that non-sense, you can use this handy formula...
B = 4*crX+ZZ
X = field number (0 thru 7)
ZZ = lt, gt, eq, or so
With this formula, all you need to remember to which Field you want to use and what bit type. So now the easier-to-remember 'format' is this..
crXXX 4*crX+ZZ, 4*crX+ZZ, 4*crX+ZZ
---
CR Based Instructions:
Simplified Mnemonics:
Also, the following instructions may be handy for you...
Chapter 5: Cleaning up some Code
Let's go over some basic examples of some "CR trickery" to help clean up code. Some examples below won't shorten the source at all (will be same compiled length), but the amount of branches (plus label names) are reduced. This is accomplished by using multiple crF's and using Condition Register specific instructions.
Scenario 1:
If r4 = 1 and r10 = r31, then go to 'store_data'. Otherwise, go to 'dont_store'.
Typical Source
New Source
Scenario 2:
If r4 = 1 or r10 = r31, then go to 'store_data'. Otherwise, go to 'dont_store'.
Typical Source
New Source
Scenario 3:
If r4 = 1 and r10 =/= r31, then go to 'store_data'. Otherwise, end_code
Typical Source
New Source
Scenario 4:
If r4 = 1 or r10 =/= r31, then go to 'store_data'.
Typical Source
New Source
Scenario 5:
If r4 = 1 then r10 must =/= r31, or if r4 =/=1 then r10 must = r31. If all requirments met go to 'store_data'. If not, go to end_code.
Typical Source
New Source
Scenario 6:
If r4 = 1, then r10 must = r31. However r4 can =/= 1 as long as r10 =/= r31. If all requirements are met go to 'store_data'. If not, go to end_code.
Typical source
New source
Chapter 6: Final Example
Let's say you have a value in r3 and it must be a valid Memory Address. Meaning a valid mem80, mem81, or mem9 address. If the address is not valid in any way, branch to the LR. An efficient way to write it would be like this (pretend r4 thru r7 are safe)...
And that's pretty much it. Happy coding!
For Advanced ASM Coders
Chapter 1: Intro
Requirements:
- Understand the basics of using compare and branch instructions
- Understand binary/bits + Logical Operations
Are your codes ending up with "countless" branches and branch labels? Your codes are in need of some spring cleaning. Sometimes codes that have an excessive amount branches end up "unreadable", making it difficult for others to understand your code or help you debug any errors.
Chapter 2: Condition Register Fundamentals
When you execute any plane jane comparison instruction such as....
Code:
cmpwi r0, 100
...you are actually telling Broadway to run a check and then place the result of said check in Condition Register Field 0.
What is Condition Register Field 0? First thing's first. The register you see in Dolphin that is named "CR" is the Condition Register. It contains the results of previously executed Compare Instructions. Conditional Branch Instructions (i.e. beq) read the data of the Condition Register to determine whether or not a branch route/jump is taken.
The Condition Register contains 7 fields. Field 0 (cr0) thru Field 7 (cr7).
STUVWXYZ
S = cr0
T = cr1
U = cr2
etc etc..
Each field (crF) takes up one DIGIT (half-byte) in the CR. Thus, each crF contains 4 bits of data. You can specify which crF to place the result of the compare instruction in. By default, if no crF is specified in your compare instruction, then cr0 will be used.
Code:
cmpwi r0, 100
is short for...
Code:
cmpwi cr0, r0, 100
If you wish to use cr7 instead of cr0, you would write the instruction like this...
Code:
cmpwi cr7, r0, 100
An important thing that you must keep in mind is that if you make a comparison that is NOT using cr0, you must also specify the crF in the subsequent branch instruction.
Like this...
Code:
cmpwi cr7, r0, 100
beq- cr7, store_data #Notice the specification of cr7 in the instruction
In conclusion, any crF that isn't cr0 must be specified in both compare and branch instructions.
Chapter 3: Condition Register Field Bits and Examining Branch Instructions
Now that you know there are 7 crF's and how to use each one in your comparison + branch instructions, let's cover the crF bits and what each bit represents.
Each crF has 4 bits of data that uses the following structure.
- bit 0 = Less-Than flag (LT)
- bit 1 = Greater-Than flag (GT)
- bit 2 = Equal flag (EQ)
- bit 3 = Summary Overflow flag (SO)
CR Bit Table
LT GT EQ SO crfX
0 1 2 3 crf0
4 5 6 7 crf1
8 9 10 11 crf2
12 13 14 15 crf3
16 17 18 19 crf4
20 21 22 23 crf5
24 25 26 27 crf6
28 29 30 31 crf7
Whenever a bit in the crF is high, the condition was true FROM THE MOST RECENT comparison instruction. Whenever a bit was low, the condition was false FROM THE MOST RECENT comparison.
Multiple bits can be flagged high and/or low from a comparison instruction. Now that you understand the crF bits, let's go over what branch instructions actually do.
Code:
bge (branch if greater than or equal) = checks bits 0, if bit is low, branch is taken
bgt (branch if greater than) = checks bit 1, if bit is high, branch is taken
ble (branch if less than or equal) = checks bit 1, if bit is low, branch is taken
blt (branch if less than) = checks bit 0, if it is high, branch is taken
bne (branch if not equal) = checks bit 2, if bit is low, branch is taken
bng (branch if not greater than) = equivalent to ble
bnl (branch if not less than) = equivalent to bge
bns (branch if not summary overflow) = checks bit 3, if bit is low, branch is taken
bso (branch if summary overflow) = checks bit 3, if bit is high, branch is taken
The branch instruction checks the bits of the crF that is specified in the instruction.
Example: 'bge- cr7' checks LT bit of cr7. If low, branch is taken.
Chapter 4: Condition Register specific instructions
Before going into the CR specific instructions, we need to go over its 'format'. The 'format' of a typical CR instruction is this..
crXXX B, B, B #XXX = and, or, andc, orc, nor, xor, eqv
Under this format, you need to specify the exact bit of the entire Condtion Register. The problem with this is that it now becomes a memory game and you have to refer to the earlier CR bit table provided in Chapter 3. Instead of doing that non-sense, you can use this handy formula...
B = 4*crX+ZZ
X = field number (0 thru 7)
ZZ = lt, gt, eq, or so
With this formula, all you need to remember to which Field you want to use and what bit type. So now the easier-to-remember 'format' is this..
crXXX 4*crX+ZZ, 4*crX+ZZ, 4*crX+ZZ
---
CR Based Instructions:
- Condition Register Logical OR~
cror crfD, crfA, crfB #crfA bit is logically OR'd with crfB bit. Result is written to crfD bit.
- Condition Register Logical AND~
crand crfD, crfA, crfD #crfA bit is logically AND'd with crfB bit. Result is written to crfD bit.
- Condition Register Logical NOR~
crnor crfD, crfA, crfD #crfA bit is logically NOR'd with crfB bit. Result is written to crfD bit.
- Condition Register Logical XOR~
crxor crfD, crfA, crfD #crfA bit is logically XOR'd with crfB bit. Result is written to crfD bit.
- Condition Register Logical EQV (XNOR)~
creqv crfD, crfA, crfD #crfA bit is logically XNOR'd with crfB bit. Result is written to crfD bit. Technically, the instruction does a XOR of crfA with crfD, then this temp result is complemented, then writes that result to crfD.
- Condition Register Logical AND with Complement~
crandc crfD, crfA, crfD #crfA bit is logically AND'd with the complemented crfB bit. Result is written to crfD bit.
- Condition Register Logical OR with Complement~
crorc crfD, crfA, crfD #crfA bit is logically OR'd with the complemented crfB bit. Result is written to crfD bit.
Simplified Mnemonics:
- Setting a bit high (set cr0 EQ high)~
crset 4*cr0+eq #creqv 4*cr0+eq, 4*cr0+eq, 4*cr0+eq; crF bit is XNOR'd with itself and resutl written to same bit spot
- Setting a bit low (set cr0 EQ low)~
crclr 4*cr0+eq #crxor 4*cr0+eq, 4*cr0+eq, 4*cr0+eq; crF bit is XOR'd with itself and result written to same bit spot
- Copy-Pasting (Moving) a bit (copy cr0 EQ bit to cr7 EQ bit's spot)
crmove 4*cr7+eq, 4*cr0+eq #cror 4*cr7+eq, 4*cr0+eq, 4*cr0+eq; crF bit is Or'd with itself and result writen to crfD
- Flip a bit (flip cr0 EQ bit and place result in cr7 EQ bit's spot))
crnot 4*cr7+eq, 4*cr0+eq #crnor 4*cr0+eq, 4*cr0+eq, 4*cr0+eq; crF bit is NOR'd with itself and result written to crfD
Also, the following instructions may be handy for you...
- mfcr rD #Contents of the CR is copied to rD
- mtcr rD #Contents of rD is copied to the CR
- mcrf crD, crA #Condition Field A is copied to Condition Field D
Chapter 5: Cleaning up some Code
Let's go over some basic examples of some "CR trickery" to help clean up code. Some examples below won't shorten the source at all (will be same compiled length), but the amount of branches (plus label names) are reduced. This is accomplished by using multiple crF's and using Condition Register specific instructions.
Scenario 1:
If r4 = 1 and r10 = r31, then go to 'store_data'. Otherwise, go to 'dont_store'.
Typical Source
Code:
cmpwi r4, 1
bne- dont_store
cmpw r10, r31
beq- store_data
New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
crand 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data
Scenario 2:
If r4 = 1 or r10 = r31, then go to 'store_data'. Otherwise, go to 'dont_store'.
Typical Source
Code:
cmpwi r4, 1
beq- store_data
cmpwi r10, r31
bne- dont_store
New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
cror 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data
Scenario 3:
If r4 = 1 and r10 =/= r31, then go to 'store_data'. Otherwise, end_code
Typical Source
Code:
cmpwi r4, 1
bne- end_code
cmpw r10, r31
bne- store_data
New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
crandc 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data
Scenario 4:
If r4 = 1 or r10 =/= r31, then go to 'store_data'.
Typical Source
Code:
cmpwi r4, 1
beq- store_data
cmpw r10, r31
bne- store_data
New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
crorc 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data
Scenario 5:
If r4 = 1 then r10 must =/= r31, or if r4 =/=1 then r10 must = r31. If all requirments met go to 'store_data'. If not, go to end_code.
Typical Source
Code:
cmpwi r4, 1
bne- make_sure_next_true
#r4 = 1, r10 must =/= r31
cmpw r10, r31
bne- store_data
b end_code
#r4 =/= 1, r10 must = r31
make_sure_next_true:
cmpw r10, r31
beq- store_data
New Source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
crxor 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data
Scenario 6:
If r4 = 1, then r10 must = r31. However r4 can =/= 1 as long as r10 =/= r31. If all requirements are met go to 'store_data'. If not, go to end_code.
Typical source
Code:
cmpwi r4, 1
bne- make_sure_next_false
#r4 = 1, r10 must = r31
cmpw r10, r31
bne- store_data
b end_code
#r4 =/= 1, r10 must =/= r31
make_sure_next_false:
cmpw r10, r31
bne- store_data
New source
Code:
cmpwi r4, 1
cmpw cr7, r10, r31
creqv 4*cr0+eq, 4*cr0+eq, 4*cr7+eq
beq- store_data
Chapter 6: Final Example
Let's say you have a value in r3 and it must be a valid Memory Address. Meaning a valid mem80, mem81, or mem9 address. If the address is not valid in any way, branch to the LR. An efficient way to write it would be like this (pretend r4 thru r7 are safe)...
Code:
lis r4, 0x8000 #0x80000000
lis r5, 0x817F #0x817FFFFF
ori r5, r5, 0xFFFF
addis r6, r4, 0x1000 #0x90000000
addis r7, r5, 0x1280 #0x93FFFFFF
cmplw r3, r4
cmplw cr5, r3, r5
cmplw cr6, r3, r6
cmplw cr7, r3, r7
cror 4*cr0+eq, 4*cr0+lt, 4*cr7+gt #Check if less than 0x80000000 ***or*** greater than 0x93FFFFFF; place result in cr0
crand 4*cr5+eq, 4*cr5+gt, 4*cr6+lt #Now check if its in between 0x817FFFC0 ***and*** 0x90000000; place result in cr5
cror 4*cr0+eq, 4*cr0+eq, 4*cr5+eq #If *any* of the two above conditions (cr0 and cr5) were true, branch to LR
beqlr-
And that's pretty much it. Happy coding!