COP1: Difference between revisions

803 bytes added ,  8 months ago
 
(5 intermediate revisions by 2 users not shown)
Line 16:
| Single || S || 32 bit float
|-
| Double || D || 64 bit doublefloat
|-
| Word || W || 32 bit integer
Line 192:
 
== Comparisons ==
The COP1 in total has 16 single compare instructions with some pretty confusing names (and another 16 for doubles). WhenThe implementing16 theminstructions inare anall emulator,possible it'scombinations bestof tothe ignorefollowing their names and just look at the4 bits of the instruction:
 
* Unordered (Bit 0): Comparison is considered true if one or both of the operands is NAN
* Equal (Bit 1): Comparison is considered true if both operands are equal (note that 0 is equal to -0, but NAN is always different from another NAN)
Line 201 ⟶ 200:
If multiple bits are set, the conditions are ORed together: For example, UEQ is considered true if the two operands are equal or unordered.
 
NotNote that inputs of qNAN as well as subnormals always signal Invalid Operation. Using all bit combinations, this gives the following instructions:
 
{| class="wikitable"
Line 208 ⟶ 207:
! SignalOnSNAN (Bit 3) !! Smaller (Bit 2) || Equal (Bit 1) || Unordered (Bit 0) || Name || Result formula || Invalid Operation Condition
|-
| 0 || 0 || 0 || 0 || F || Result = false || IsQNAN(arg1) OR isQNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 0 || 0 || 0 || 1 || UN || Result = unordered(arg1, arg2) || IsQNAN(arg1) OR isQNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 0 || 0 || 1 || 0 || EQ || Result = arg1 == arg2 || IsQNAN(arg1) OR isQNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 0 || 0 || 1 || 1 || UEQ || Result = unordered(arg1, arg2) OR (arg1 == arg2) || IsQNAN(arg1) OR isQNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 0 || 1 || 0 || 0 || OLT || Result = arg1 < arg2 || IsQNAN(arg1) OR isQNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 0 || 1 || 0 || 1 || ULT || Result = unordered(arg1, arg2) OR (arg1 < arg2) || IsQNAN(arg1) OR isQNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 0 || 1 || 1 || 0 || OLE || Result = arg1 <= arg2 || IsQNAN(arg1) OR isQNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 0 || 1 || 1 || 1 || ULE || Result = unordered(arg1, arg2) OR (arg1 <= arg2) || IsQNAN(arg1) OR isQNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 1 || 0 || 0 || 0 || SF || Result = false || IsNAN(arg1) OR isNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 1 || 0 || 0 || 1 || NGLE || Result = unordered(arg1, arg2) || IsNAN(arg1) OR isNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 1 || 0 || 1 || 0 || SEQ || Result = arg1 == arg2 || IsNAN(arg1) OR isNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 1 || 0 || 1 || 1 || NGL || Result = unordered(arg1, arg2) OR (arg1 == arg2) || IsNAN(arg1) OR isNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 1 || 1 || 0 || 0 || LT || Result = arg1 < arg2 || IsNAN(arg1) OR isNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 1 || 1 || 0 || 1 || NGE || Result = unordered(arg1, arg2) OR (arg1 < arg2) || IsNAN(arg1) OR isNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 1 || 1 || 1 || 0 || LE || Result = arg1 <= arg2 || IsNAN(arg1) OR isNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-
| 1 || 1 || 1 || 1 || NGT || Result = unordered(arg1, arg2) OR (arg1 <= arg2) || IsNAN(arg1) OR isNAN(arg2) OR isSubnormal(arg1) OR isSubnormal(arg2)
|-|}
 
== Full Mode vs Half Mode ==
The COP1 can run in one of two modes, which is controlled via COP0.Status Bit 26. In "Full Mode", the COP1 has 32 bit registers that are each 64 bits wide are available. In "Half Mode", only the 16 even registers are legal to be used; using odd numbered registers is considered undefined behavior.
 
Older software usually ran in "Half Mode". A reason for that could be that context switches (for multithreading) can be performed more cheaply, as only 16 FPU registers need to be stored.
 
When using "Half Mode" it is important to not use any FPU registers with odd indices. For compiled code this has to be configured accordingly ("+nooddspreg" in clang).
 
''The remainder of this section documents undefined behavior. Skip this unless you are an emulator developer who cares about accuracy a little bit too much.''
 
If software decides to use odd indices in "Half Mode", different things happen, depending on the instruction:
 
{| class="wikitable"
|+ Illegal register indexing in "Half Mode" (normally undocumented behavior - do not use)
|-
! Actual Register Index || MFC1/MTC1/LWC1/LDC1 || fd (32 bit), ft (32 bit) or any 64 bit || fs (32 bit)
|-
| 0 || 1 (high 32 bits) / 0 (low 32 bits) || 0 (low 32 bits) || 0 or 1
|-
| 1 || unused || 1 (low 32 bits) || unused
|-
| 2 || 3 (high 32 bits) / 2 (low 32 bits) || 2 (low 32 bits) || 2 or 3
|-
| 3 || unused || 3 (low 32 bits) || unused
|-
| 4 || 5 (high 32 bits) / 4 (low 32 bits) || 4 (low 32 bits) || 4 or 5
|-
| 5 || unused || 5 (low 32 bits) || unused
|}
14

edits