More minor tweaks to newfpu

This commit is contained in:
pruten 2014-10-07 22:37:22 -04:00
parent adc2e16ffd
commit c9adc49a82
1 changed files with 156 additions and 58 deletions

View File

@ -279,7 +279,7 @@ static float128 _extended_to_intermediate(uint8_t *e)
*/
static void _set_rounding_mode(enum rounding_mode_t mode)
{
const int8 rounding_map[4] = {
const int8_t rounding_map[4] = {
float_round_nearest_even, float_round_to_zero,
float_round_up, float_round_down
};
@ -411,7 +411,7 @@ got_address:
*result = _extended_to_intermediate(buf);
break;
case format_Ps:
case format_Pd:
// case format_Pd: // not possible as a src specifier
// FIXME: implement packed formats
assert(!"Somebody tried to use a packed format!\n");
// throw_illegal_instruction();
@ -428,6 +428,79 @@ got_data:
#pragma mark Second-hop instructions
static float128 _get_fmovecr_constant(const uint8_t offset)
{
float128 foo;
/*
* FYI: these constants are stored in the "intermediate" 85-bit
* format in the 6888x rom. This has the side effect that
* they are rounded according to fpcr.mc_rnd.
* We emulate the 85-bit format with float128.
*/
switch (offset) {
case 0x00: // pi
break;
case 0x0b: // log_10(2)
break;
case 0x0c: // e
break;
case 0x0d: // log_2(e)
break;
case 0x0e: // log_10(e)
break;
case 0x0f: // 0.0
break;
case 0x30: // ln(2)
break;
case 0x31: // ln(10)
break;
case 0x32: // 1 (68kprm has typesetting issues everywhere. This one says 100, but means 10^0.)
break;
case 0x33: // 10
break;
case 0x34: // 10^2
break;
case 0x35: // 10^4
break;
case 0x36: // 10^8
break;
case 0x37: // 10^16
break;
case 0x38: // 10^32
break;
case 0x39: // 10^64
break;
case 0x3a: // 10^128
break;
case 0x3b: // 10^256
break;
case 0x3c: // 10^512
break;
case 0x3d: // 10^1024
break;
case 0x3e: // 10^2048
break;
case 0x3f: // 10^4096
break;
default:
/*
* I wanted to include the actual values for the other ROM offsets,
* but they might be proprietary. Most of them are 0 anyways, and some
* cause FPU exceptions, even with all exceptions disabled... (?)
* (Also, looking at the micro/nanocode on a high res 68881/2 die pic,
* I can't figure out where these constants are stored.)
*/
// result = 0.0;
break;
}
return foo;
}
static void inst_fmath (const uint16_t ext)
{
fpu_get_state_ptr();
@ -494,14 +567,30 @@ static void inst_fmath (const uint16_t ext)
es_snan = 0; // Set if one of the inputs was a signaling NaN
es_bsun = 0; // never set here
/*
* All instructions with bit #6 set are illegal on
* 6888x. No other opcodes seem to be illegal.
*/
if (extension & ~b(1000000)) {
throw_illegal_instruction();
return ;
}
/* Handle fmovecr */
if (src_in_ea && (source_specifier == 7)) { // fmovecr
/*
* 68kprm says M should be ~b(000000), but apparently
* any value will work for fmovecr
*/
result = _get_fmovecr_constant(extension);
goto finalize;
}
switch (e) {
case ~b(1000000): // fsmove
case ~b(1000100): // fdmove
/* These are only legal on 68040 */
throw_illegal_instruction();
return ;
if (e == ~b(1000000)) rounding_prec = prec_single;
else if (e == ~b(1000100)) rounding_prec = prec_double;
else assert(0);
@ -522,9 +611,6 @@ static void inst_fmath (const uint16_t ext)
case ~b(1000001): // fssqrt
case ~b(1000101): // fdsqrt
/* These are only legal on 68040 */
throw_illegal_instruction();
return ;
if (e == ~b(1000001)) rounding_prec = prec_single;
else if (e == ~b(1000101)) rounding_prec = prec_double;
else assert(0);
@ -532,6 +618,8 @@ static void inst_fmath (const uint16_t ext)
break;
/* case ~b(0000101): // not documented, seems to be fsqrt again */
case ~b(0000110): // flognp1
break;
@ -544,6 +632,8 @@ static void inst_fmath (const uint16_t ext)
case ~b(0001010): // fatan
break;
/* case ~b(0001011): // not documented, seems to be fatan again */
case ~b(0001100): // fasin
break;
@ -565,6 +655,8 @@ static void inst_fmath (const uint16_t ext)
case ~b(0010010): // ftentox
break;
/* case ~b(0010011): // not documented, seems to be ftentox again */
case ~b(0010100): // flogn
break;
@ -573,13 +665,12 @@ static void inst_fmath (const uint16_t ext)
case ~b(0010110): // flog2
break;
/* case ~b(0010111): // not documented, seems to be flog2 again */
case ~b(1011000): // fsabs
case ~b(1011100): // fdabs
/* These are only legal on 68040 */
throw_illegal_instruction();
return ;
if (e == ~b(1011000)) rounding_prec = prec_single;
else if (e == ~b(1011100)) rounding_prec = prec_double;
else assert(0);
@ -593,16 +684,14 @@ static void inst_fmath (const uint16_t ext)
case ~b(1011010): // fsneg
case ~b(1011110): // fdneg
/* These are only legal on 68040 */
throw_illegal_instruction();
return ;
if (e == ~b(1011010)) rounding_prec = prec_single;
else if (e == ~b(1011110)) rounding_prec = prec_double;
else assert(0);
case ~b(0011010): // fneg
break;
/* case ~b(0011010): // not documented, seems to be fneg again */
case ~b(0011100): // facos
break;
@ -615,84 +704,93 @@ static void inst_fmath (const uint16_t ext)
case ~b(0011111): // fgetman
break;
case ~b(1100000): // fsdiv
case ~b(1100100): // fddiv
/* These are only legal on 68040 */
if (e == ~b(1100000)) rounding_prec = prec_single;
else if (e == ~b(1100100)) rounding_prec = prec_double;
else assert(0);
case ~b(0100000): // fdiv
break;
case ~b(0100001): // fmod
break;
/* case ~b(0100000): // not documented, seems to be fmod again */
case ~b(1100010): // fsadd
case ~b(1100110): // fdadd
/* These are only legal on 68040 */
throw_illegal_instruction();
return ;
if (e == ~b(1100010)) rounding_prec = prec_single;
else if (e == ~b(1100110)) rounding_prec = prec_double;
else assert(0);
case ~b(0100010): // fadd
break;
case ~b(1100011): // fsmul
case ~b(1100111): // fdmul
/* These are only legal on 68040 */
if (e == ~b(1100011)) rounding_prec = prec_single;
else if (e == ~b(1100111)) rounding_prec = prec_double;
else assert(0);
case ~b(0100011): // fmul
break;
case ~b(0100100): // fsgldiv
break;
case ~b(0100111): // fsglmul
break;
case ~b(0100101): // frem
break;
case ~b(0100110): // fscale
break;
case ~b(0111000): // fcmp
break;
case ~b(0111010): // ftst
break;
case ~b(1100000): // fsdiv
case ~b(1100100): // fddiv
/* These are only legal on 68040 */
throw_illegal_instruction();
return ;
if (e == ~b(1100000)) rounding_prec = prec_single;
else if (e == ~b(1100100)) rounding_prec = prec_double;
else assert(0);
case ~b(0100000): // fdiv
break;
case ~b(1100011): // fsmul
case ~b(1100111): // fdmul
/* These are only legal on 68040 */
throw_illegal_instruction();
return ;
if (e == ~b(1100011)) rounding_prec = prec_single;
else if (e == ~b(1100111)) rounding_prec = prec_double;
else assert(0);
case ~b(0100011): // fmul
case ~b(0100111): // fsglmul
break;
case ~b(1101000): // fssub
case ~b(1101100): // fdsub
/* These are only legal on 68040 */
throw_illegal_instruction();
return ;
if (e == ~b(1101000)) rounding_prec = prec_single;
else if (e == ~b(1101100)) rounding_prec = prec_double;
else assert(0);
case ~b(0101000): // fsub
break;
/* case ~b(0101000) through ~b(0101111): // not documented, seems to be fsub again */
case ~b(0110000):
case ~b(0110001):
case ~b(0110010):
case ~b(0110011):
case ~b(0110100):
case ~b(0110101):
case ~b(0110110):
case ~b(0110111): // fsincos
break;
case ~b(0111000): // fcmp
break;
case ~b(0111010): // ftst
break;
/*
* All the rest of these 0xxxxxx opcodes seem to be either fcmp or ftst.
* That's why the new 68040 opcodes have to use that high bit (1xxxxxx),
* none of the other ones throw illegal-instruction on 6888x.
*/
default:
/* Nonetheless, I'm just going to throw an f-trap. */
throw_illegal_instruction();
return;
}
finalize:
/*
* Now update all the exception flags,
* and determine whether we want to
* actually throw an exception.
* Now update all the exception flags, and determine
* whether we want to actually throw an exception.
*/
/*