Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Libretro
SquirrelJME
Commits
e1f61725
Commit
e1f61725
authored
Jul 18, 2021
by
Stephanie Gawroriski
Browse files
Cherry pick soft math from SummerCoat WIP.
parent
66861fb7
Changes
22
Hide whitespace changes
Inline
Side-by-side
modules/cldc-compact/src/main/java/cc/squirreljme/jvm/SoftDouble.java
View file @
e1f61725
...
...
@@ -28,14 +28,14 @@ public class SoftDouble
/**
* Adds two values.
*
* @param __ah A high.
* @param __al A low.
* @param __
b
h
B
high.
* @param __
a
h
A
high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public
static
double
add
(
int
__a
h
,
int
__a
l
,
int
__b
h
,
int
__b
l
)
public
static
double
add
(
int
__a
l
,
int
__a
h
,
int
__b
l
,
int
__b
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -44,14 +44,14 @@ public class SoftDouble
/**
* Compares two values.
*
* @param __ah A high.
* @param __al A low.
* @param __
b
h
B
high.
* @param __
a
h
A
high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public
static
int
cmpl
(
int
__a
h
,
int
__a
l
,
int
__b
h
,
int
__b
l
)
public
static
int
cmpl
(
int
__a
l
,
int
__a
h
,
int
__b
l
,
int
__b
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -60,14 +60,14 @@ public class SoftDouble
/**
* Compares two values.
*
* @param __ah A high.
* @param __al A low.
* @param __
b
h
B
high.
* @param __
a
h
A
high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public
static
int
cmpg
(
int
__a
h
,
int
__a
l
,
int
__b
h
,
int
__b
l
)
public
static
int
cmpg
(
int
__a
l
,
int
__a
h
,
int
__b
l
,
int
__b
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -76,14 +76,14 @@ public class SoftDouble
/**
* Divides two values.
*
* @param __ah A high.
* @param __al A low.
* @param __
b
h
B
high.
* @param __
a
h
A
high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public
static
double
div
(
int
__a
h
,
int
__a
l
,
int
__b
h
,
int
__b
l
)
public
static
double
div
(
int
__a
l
,
int
__a
h
,
int
__b
l
,
int
__b
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -92,14 +92,14 @@ public class SoftDouble
/**
* Multiplies two values.
*
* @param __ah A high.
* @param __al A low.
* @param __
b
h
B
high.
* @param __
a
h
A
high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public
static
double
mul
(
int
__a
h
,
int
__a
l
,
int
__b
h
,
int
__b
l
)
public
static
double
mul
(
int
__a
l
,
int
__a
h
,
int
__b
l
,
int
__b
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -108,12 +108,12 @@ public class SoftDouble
/**
* Negates a value.
*
* @param __ah A high.
* @param __al A low.
* @param __ah A high.
* @return The result.
* @since 2019/05/24
*/
public
static
double
neg
(
int
__a
h
,
int
__a
l
)
public
static
double
neg
(
int
__a
l
,
int
__a
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -122,29 +122,29 @@ public class SoftDouble
/**
* ORs value, used for constants.
*
* @param __ah A high.
* @param __al A low.
* @param __
b
h
B
high.
* @param __
a
h
A
high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/27
*/
public
static
double
or
(
int
__a
h
,
int
__a
l
,
int
__b
h
,
int
__b
l
)
public
static
double
or
(
int
__a
l
,
int
__a
h
,
int
__b
l
,
int
__b
h
)
{
return
Assembly
.
doublePack
(
__a
h
|
__b
h
,
__a
l
|
__b
l
);
return
Assembly
.
doublePack
(
__a
l
|
__b
l
,
__a
h
|
__b
h
);
}
/**
* Remainders a value.
*
* @param __ah A high.
* @param __al A low.
* @param __
b
h
B
high.
* @param __
a
h
A
high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public
static
double
rem
(
int
__a
h
,
int
__a
l
,
int
__b
h
,
int
__b
l
)
public
static
double
rem
(
int
__a
l
,
int
__a
h
,
int
__b
l
,
int
__b
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -153,14 +153,14 @@ public class SoftDouble
/**
* Subtracts values.
*
* @param __ah A high.
* @param __al A low.
* @param __
b
h
B
high.
* @param __
a
h
A
high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public
static
double
sub
(
int
__a
h
,
int
__a
l
,
int
__b
h
,
int
__b
l
)
public
static
double
sub
(
int
__a
l
,
int
__a
h
,
int
__b
l
,
int
__b
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -169,12 +169,12 @@ public class SoftDouble
/**
* Converts to float.
*
* @param __ah A high.
* @param __al A low.
* @param __ah A high.
* @return The result.
* @since 2019/05/24
*/
public
static
float
toFloat
(
int
__a
h
,
int
__a
l
)
public
static
float
toFloat
(
int
__a
l
,
int
__a
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -183,12 +183,12 @@ public class SoftDouble
/**
* Converts to integer.
*
* @param __ah A high.
* @param __al A low.
* @param __ah A high.
* @return The result.
* @since 2019/05/24
*/
public
static
int
toInteger
(
int
__a
h
,
int
__a
l
)
public
static
int
toInteger
(
int
__a
l
,
int
__a
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
@@ -197,12 +197,12 @@ public class SoftDouble
/**
* Converts to long.
*
* @param __ah A high.
* @param __al A low.
* @param __ah A high.
* @return The result.
* @since 2019/05/24
*/
public
static
long
toLong
(
int
__a
h
,
int
__a
l
)
public
static
long
toLong
(
int
__a
l
,
int
__a
h
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
...
...
modules/cldc-compact/src/main/java/cc/squirreljme/jvm/SoftFloat.java
View file @
e1f61725
...
...
@@ -9,13 +9,55 @@
package
cc.squirreljme.jvm
;
import
cc.squirreljme.runtime.cldc.util.UnsignedInteger
;
/**
* Software math operations on 32-bit floats.
*
* This source file uses parts of the Berkeley SoftFloat Release 3e library,
* converted into Java. See the 3rd party licenses documentation.
*
* @since 2019/05/24
*/
public
class
SoftFloat
@SuppressWarnings
({
"CommentedOutCode"
,
"MagicNumber"
})
public
final
class
SoftFloat
{
/** The sign mask. */
public
static
final
int
SIGN_MASK
=
0b1000_0000_0000_0000__0000_0000_0000_0000
;
/** Exponent Mask. */
public
static
final
int
EXPONENT_MASK
=
0b0111_1111_1000_0000__0000_0000_0000_0000
;
/** Fraction Mask. */
public
static
final
int
FRACTION_MASK
=
0b0000_0000_0111_1111__1111_1111_1111_1111
;
/** The mask for NaN values. */
public
static
final
int
NAN_MASK
=
0b0111_1111_1000_0000__0000_0000_0000_0000
;
/** Exponent shift. */
private
static
final
byte
_EXP_SHIFT
=
23
;
/** Default NaN value. */
public
static
final
float
FLOAT_DEFAULT_NAN
=
Float
.
intBitsToFloat
(
0xFFC0_0000
);
/** Integer from negative overflow. */
private
static
final
int
_INT_FROM_NEGOVER
=
-
0x7FFFFFFF
-
1
;
/** Integer from positive overflow. */
private
static
final
int
_INT_FROM_POSOVER
=
-
0x7FFFFFFF
-
1
;
/** Round near even mode. */
private
static
final
int
_ROUND_NEAR_EVEN
=
0
;
/**
* Not used.
*
...
...
@@ -40,31 +82,37 @@ public class SoftFloat
}
/**
* Compares two values.
* Compares two values
, NaN returns {@code -1}
.
*
* @param __a A.
* @param __b B.
* @return The result.
* @since 2019/05/24
*/
@SuppressWarnings
(
"SpellCheckingInspection"
)
public
static
int
cmpl
(
int
__a
,
int
__b
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
if
(
SoftFloat
.
isNaN
(
__a
)
||
SoftFloat
.
isNaN
(
__b
))
return
-
1
;
return
SoftFloat
.
__cmp
(
__a
,
__b
);
}
/**
* Compares two values.
* Compares two values
, NaN returns {@code 1}
.
*
* @param __a A.
* @param __b B.
* @return The result.
* @since 2019/05/24
*/
@SuppressWarnings
(
"SpellCheckingInspection"
)
public
static
int
cmpg
(
int
__a
,
int
__b
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
if
(
SoftFloat
.
isNaN
(
__a
)
||
SoftFloat
.
isNaN
(
__b
))
return
1
;
return
SoftFloat
.
__cmp
(
__a
,
__b
);
}
/**
...
...
@@ -81,6 +129,18 @@ public class SoftFloat
throw
new
todo
.
TODO
();
}
/**
* Is this Not a Number?
*
* @param __a The value to check.
* @return If this is not a number.
* @since 2021/04/07
*/
public
static
boolean
isNaN
(
int
__a
)
{
return
SoftFloat
.
NAN_MASK
==
(
__a
&
SoftFloat
.
NAN_MASK
);
}
/**
* Multiplies two values.
*
...
...
@@ -91,8 +151,97 @@ public class SoftFloat
*/
public
static
float
mul
(
int
__a
,
int
__b
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
// First value
boolean
signA
=
SoftFloat
.
__signF32UI
(
__a
);
int
expA
=
SoftFloat
.
__expF32UI
(
__a
);
int
sigA
=
SoftFloat
.
__fracF32UI
(
__a
);
// Second value
boolean
signB
=
SoftFloat
.
__signF32UI
(
__b
);
int
expB
=
SoftFloat
.
__expF32UI
(
__b
);
int
sigB
=
SoftFloat
.
__fracF32UI
(
__b
);
// Will this result in a negative value?
boolean
signZ
=
signA
^
signB
;
boolean
returnInfinite
=
false
;
int
magBits
=
0
;
if
(
expA
==
0xFF
)
{
// if ( sigA || ((expB == 0xFF) && sigB) )
if
(
sigA
!=
0
||
((
expB
==
0xFF
)
&&
(
sigB
!=
0
)))
return
Float
.
intBitsToFloat
(
SoftFloat
.
__propagateNaNF32UI
(
__a
,
__b
));
magBits
=
expB
|
sigB
;
returnInfinite
=
true
;
}
if
(!
returnInfinite
&&
expB
==
0xFF
)
{
// if ( sigB )
if
(
sigB
!=
0
)
return
Float
.
intBitsToFloat
(
SoftFloat
.
__propagateNaNF32UI
(
__a
,
__b
));
magBits
=
expA
|
sigA
;
returnInfinite
=
true
;
}
// Returning infinite value?
if
(
returnInfinite
)
{
// if ( ! magBits )
if
(
magBits
==
0
)
return
SoftFloat
.
FLOAT_DEFAULT_NAN
;
return
Float
.
intBitsToFloat
(
SoftFloat
.
__packToF32UI
(
signZ
,
0xFF
,
0
));
}
// if ( ! expA )
if
(
expA
==
0
)
{
// if ( ! sigA )
if
(
sigA
==
0
)
return
Float
.
intBitsToFloat
(
SoftFloat
.
__packToF32UI
(
signZ
,
0
,
0
));
long
normExpSig
=
SoftFloat
.
__normSubnormalF32Sig
(
sigA
);
expA
=
(
short
)
Assembly
.
longUnpackHigh
(
normExpSig
);
sigA
=
Assembly
.
longUnpackLow
(
normExpSig
);
}
// if ( ! expB )
if
(
expB
==
0
)
{
// if ( ! sigB )
if
(
sigB
==
0
)
return
Float
.
intBitsToFloat
(
SoftFloat
.
__packToF32UI
(
signZ
,
0
,
0
));
long
normExpSig
=
SoftFloat
.
__normSubnormalF32Sig
(
sigB
);
expB
=
(
short
)
Assembly
.
longUnpackHigh
(
normExpSig
);
sigB
=
Assembly
.
longUnpackLow
(
normExpSig
);
}
int
expZ
=
(
short
)(
expA
+
expB
-
0x7F
);
sigA
=
(
sigA
|
0x0080_0000
)
<<
7
;
sigB
=
(
sigB
|
0x0080_0000
)
<<
8
;
// sigZ = softfloat_shortShiftRightJam64(
// (uint_fast64_t)sigA * sigB, 32); <-- unsigned multiply
int
sigZ
=
(
int
)
SoftFloat
.
__shortShiftRightJam64
(
(
sigA
&
0xFFFF_FFFF
L
)
*
(
sigB
&
0xFFFF_FFFF
L
),
32
);
// if ( sigZ < 0x40000000 )
if
(
UnsignedInteger
.
compareUnsigned
(
sigZ
,
0x4000_0000
)
<
0
)
{
expZ
=
(
short
)(
expZ
-
1
);
sigZ
<<=
1
;
}
return
Float
.
intBitsToFloat
(
SoftFloat
.
__roundPackToF32
(
signZ
,
expZ
,
sigZ
));
}
/**
...
...
@@ -171,8 +320,21 @@ public class SoftFloat
*/
public
static
int
toInteger
(
int
__a
)
{
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
boolean
sign
=
SoftFloat
.
__signF32UI
(
__a
);
int
exp
=
SoftFloat
.
__expF32UI
(
__a
);
int
sig
=
SoftFloat
.
__fracF32UI
(
__a
);
if
(
exp
!=
0
)
sig
|=
0x0080_0000
;
// sig64 = (uint_fast64_t) sig<<32;
long
sig64
=
Assembly
.
longPack
(
0
,
sig
);
int
shiftDist
=
0xAA
-
exp
;
if
(
UnsignedInteger
.
compareUnsigned
(
0
,
shiftDist
)
<
0
)
sig64
=
SoftFloat
.
__shiftRightJam64
(
sig64
,
shiftDist
);
return
SoftFloat
.
__roundToI32
(
sign
,
sig64
);
}
/**
...
...
@@ -187,5 +349,353 @@ public class SoftFloat
Assembly
.
breakpoint
();
throw
new
todo
.
TODO
();
}
}
/**
* Compares two values.
*
* @param __a A.
* @param __b B.
* @return The result.
* @since 2021/04/07
*/
private
static
int
__cmp
(
int
__a
,
int
__b
)
{
// Equality, note second means -0 == 0
// return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1);
if
(
__a
==
__b
||
((
__a
|
__b
)
<<
1
)
==
0
)
return
0
;
// Less than
// (signA != signB) ? signA && ((uint32_t) ((uiA | uiB)<<1) != 0)
// : (uiA != uiB) && (signA ^ (uiA < uiB));
boolean
signA
=
(
0
!=
(
__a
&
SoftFloat
.
SIGN_MASK
));
boolean
signB
=
(
0
!=
(
__b
&
SoftFloat
.
SIGN_MASK
));
if
(
signA
!=
signB
)
{
// signA && ((uint32_t) ((uiA | uiB)<<1) != 0)
if
(
signA
&&
((
__a
|
__b
)
<<
1
)
!=
0
)
return
-
1
;
}
// (uiA != uiB) && (signA ^ (uiA < uiB))
// ^^^ const ^^
else
if
(
signA
^
(
UnsignedInteger
.
compareUnsigned
(
__a
,
__b
)
<
0
))
return
-
1
;
// Anything else assume greater than
return
1
;
}
/**
* Returns the exponent.
*
* @param __a The float to read from.
* @return The exponent.
* @since 2021/04/10
*/
private
static
int
__expF32UI
(
int
__a
)
{
// ((int_fast16_t) ((a)>>23) & 0xFF)
return
(((
__a
)
>>>
SoftFloat
.
_EXP_SHIFT
)
&
0xFF
);
}
/**
* Returns the fraction/significand from the floating point value.
*
* @param __a The float to read from.
* @return The fraction/significand.
* @since 2021/04/10
*/
private
static
int
__fracF32UI
(
int
__a
)
{
return
(
__a
&
SoftFloat
.
FRACTION_MASK
);
}
/**
* Gets if this is a NaN.
*
* @param __a The value to check.
* @return If this is a NaN.
* @since 2021/04/10
*/
private
static
boolean
__isNaNF32UI
(
int
__a
)
{
return
((~(
__a
)
&
0x7F800000
)
==
0
)
&&
((
__a
)
&
0x007FFFFF
)
!=
0
;
}
/**
* Gets if this is a signaling NaN.
*
* @param __a The value to check.
* @return If this is a signaling NaN.
* @since 2021/04/10
*/
private
static
boolean
__isSigNaNF32UI
(
int
__a
)
{
return
((
__a
&
0x7FC00000
)
==
0x7F800000
)
&&
(
__a
&
0x003FFFFF
)
!=
0
;
}
/**
* Normalized round packed to 32-bit float.
*
* @param __sign The sign.
* @param __exp The exponent.
* @param __sig The significand.
* @return The resultant value.
* @since 2021/04/08
*/
protected
static
int
__normRoundPackToF32
(
boolean
__sign
,
int
__exp
,
int
__sig
)
{
int
shiftDist
;
// shiftDist = softfloat_countLeadingZeros32( __sig ) - 1;
shiftDist
=
Integer
.
numberOfLeadingZeros
(
__sig
)
-
1
;
__exp
-=
shiftDist
;
// if ( (7 <= shiftDist) && ((unsigned int) exp < 0xFD) ) {
if
(
7
<=
shiftDist
&&
UnsignedInteger
.
compareUnsigned
(
__exp
,
0xFD
)
<
0
)
{
// uZ.ui = packToF32UI( sign, sig ? exp : 0, sig<<(shiftDist - 7));
return
SoftFloat
.
__packToF32UI
(
__sign
,
(
__sig
!=
0
?
__exp
:
0
),
__sig
<<
(
shiftDist
-
7
));
}
// return softfloat_roundPackToF32( sign, exp, sig<<shiftDist );
return
SoftFloat
.
__roundPackToF32
(
__sign
,
__exp
,
__sig
<<
shiftDist
);
}
/**
* Normalizes a subnormal 32-bit float significand.
*
* @param __sig The significand.
* @return The normalized value, the exponent is the high value and
* the significand is the low value.
* @since 2021/04/10
*/
private
static
long
__normSubnormalF32Sig
(
int
__sig
)
{
// softfloat_countLeadingZeros32( sig ) - 8;
int
shiftDist
=
Integer
.
numberOfLeadingZeros
(
__sig
)
-
8
;
// struct exp16_sig32 { int_fast16_t exp; uint_fast32_t sig; };
// exp = 1 - shiftDist ,, sig = sig<<shiftDist
return
Assembly
.
longPack
(
__sig
<<
shiftDist
,
(
short
)(
1
-
shiftDist
));
}
/**
* Packs value to an unsigned integer, note that some of these values are
* perfectly fine to overflow into each other such as the significand
* being larger than the value.
*
* @param __sign Sign bit.
* @param __exp Exponent.
* @param __sig Significand.
* @return The packed value.