Added a bunch of disassemblers for newfpu

This commit is contained in:
Peter Rutenbar 2014-11-05 18:31:33 -05:00
parent 688199cf6d
commit 2790b03327
4 changed files with 289 additions and 27 deletions

View File

@ -47,6 +47,12 @@ uint16_t dis_next_word (void)
return next;
}
uint32_t dis_next_long (void)
{
uint32_t next = dis_next_word();
return (next << 16) | dis_next_word();
}
//
// EA decoder routines
//
@ -269,8 +275,13 @@ char* decode_ea_rw (uint8_t mr, uint8_t sz)
} else if (sz == 2) {
sprintf(str, "0x%04x", ext);
} else {
const uint16_t ext2 = dis_next_word();
sprintf(str, "0x%04x%04x", ext, ext2);
uint32_t i;
assert((sz & 1) == 0);
sprintf(str, "0x%04x", ext);
for (i=2; i<sz; i+=2) {
const uint16_t ext2 = dis_next_word();
sprintf(str + strlen(str), "%04x", ext2);
}
}
return str;
}
@ -290,7 +301,8 @@ char* decode_ea_addr (uint8_t mr)
char *str = dis.ea_str_internal + dis.ea_last_pos_internal;
dis.ea_last_pos_internal = (dis.ea_last_pos_internal+256) % 1024;
switch (mode) {
case 0 ... 1: { // Data/address register direct mode
case 0:
case 1: { // Data/address register direct mode
sprintf(str, "???");
return str;
}
@ -299,11 +311,11 @@ char* decode_ea_addr (uint8_t mr)
return str;
}
case 3: { // address register indirect with postincrement mode
sprintf(str, "???");
sprintf(str, "(a%u)+", reg);
return str;
}
case 4: { // address register indirect with predecrement mode
sprintf(str, "???");
sprintf(str, "-(a%u)", reg);
return str;
}
case 5: { // address register indirect with displacement mode
@ -1428,19 +1440,24 @@ void dis_tas () {
void dis_trapcc() {
~decompose(dis_op, 0101 cccc 11111 ooo);
const char *condition_names[16] = {
"t", "ra", "hi", "ls", "cc", "cs", "ne", "eq",
"vc", "vs", "pl", "mi", "ge", "lt", "gt", "le"
};
uint32_t data;
switch (c) {
switch (o) {
case 2:
data = dis_next_word();
sprintf(dis.str, "trapcc.w 0x%04x", data);
sprintf(dis.str, "trap%s.w 0x%04x", condition_names[c], data);
break;
case 3:
data = dis_next_word();
data = (data << 16) | dis_next_word();
sprintf(dis.str, "trapcc.w 0x%08x", data);
data = dis_next_long();
sprintf(dis.str, "trap%s.l 0x%08x", condition_names[c], data);
break;
case 4:
sprintf(dis.str, "trapcc");
sprintf(dis.str, "trap%s", condition_names[c]);
break;
}
}
@ -1516,34 +1533,198 @@ void dis_mc68851_decode() {
assert(!"never get here");
}
const char *_fcc_names[32] = {
"f", "eq", "ogt", "oge", "olt", "ole", "ogl", "or",
"un", "ueq", "ugt", "uge", "ult", "ule", "ne", "t",
"sf", "seq", "gt", "ge", "lt", "le", "gl", "gle",
"ngle", "ngl", "nle", "nlt", "nge", "ngt", "sne", "st"
};
static void dis_fmove_to_mem(uint16_t ext)
{
const uint8_t _format_sizes[8] = {4, 4, 12, 12, 2, 8, 1, 12};
~decompose(dis_op, 1111 001 000 MMMMMM);
~decompose(ext, 011 fff sss kkkkkkk);
sprintf(dis.str, "fmove.%c", "lsxpwdbp"[f]);
if (f == 3)
sprintf(dis.str + strlen(dis.str), "{#%u}", k);
else
sprintf(dis.str + strlen(dis.str), "{d%u}", k >> 4);
sprintf(dis.str + strlen(dis.str), " fp%u,%s", s,
decode_ea_rw(M, _format_sizes[f]));
}
static void dis_fmovem_control(uint16_t ext)
{
~decompose(dis_op, 1111 001 000 MMMMMM);
~decompose(ext, 10 d CSI 0000 000000);
sprintf(dis.str, "fmovem.l ");
const uint16_t count = C + S + I;
if (count == 0)
sprintf(dis.str + strlen(dis.str), "0,");
if (C)
sprintf(dis.str + strlen(dis.str), "fpcr%s", (count > 1)?"&":",");
if (S)
sprintf(dis.str + strlen(dis.str), "fpsr%s", ((S+I) > 1)?"&":",");
if (I)
sprintf(dis.str + strlen(dis.str), "fpiar,");
sprintf(dis.str + strlen(dis.str), "%s", decode_ea_rw(M, count * 4));
}
static void dis_fmovem(uint16_t ext)
{
~decompose(dis_op, 1111 001 000 mmmrrr);
~decompose(dis_op, 1111 001 000 MMMMMM);
~decompose(ext, 11 d ps 000 LLLLLLLL); // Static register mask
~decompose(ext, 11 0 00 000 0yyy0000); // Register for dynamic mode
if (s) { // if dynamic mode
if (d) // mem -> reg
sprintf(dis.str, "fmovem.x %s,a%u", decode_ea_rw(M, 4), y);
else
sprintf(dis.str, "fmovem.x a%u,%s", y, decode_ea_rw(M, 4));
return;
}
uint32_t i, count=0;
char list[64] = "";
uint8_t oldmask = L, mask = L;
// for predecrement mode, the mask is reversed
if (m == 4) {
for (i=0; i<8; i++) {
mask <<= 1;
mask |= (oldmask & 1);
oldmask >>= 1;
count++;
}
}
for (i=0; i<8; i++) {
if (mask & 0x80)
sprintf(list + strlen(list), "fp%u.", i);
mask <<= 1;
}
if (d) // mem -> reg
sprintf(dis.str, "fmovem.x %s,%s", decode_ea_rw(M, 4), list);
else // reg -> mem
sprintf(dis.str, "fmovem.x %s,%s", list, decode_ea_rw(M, 4));
}
void dis_fscc () {
sprintf(dis.str, "fscc??");
~decompose(dis_op, 1111 001 001 MMMMMM);
const uint16_t ext = dis_next_word();
~decompose(ext, 0000 0000 00 0ccccc);
sprintf(dis.str, "fs%s.b %s", _fcc_names[c], decode_ea_rw(M, 1));
}
void dis_fbcc () {
sprintf(dis.str, "fbcc??");
~decompose(dis_op, 1111 001 01s 0ccccc);
uint32_t new_pc = dis.orig_pc + 2;
if (s == 0) {
const int16_t tmp = dis_next_word();
new_pc += tmp;
}
else
new_pc += dis_next_long();
sprintf(dis.str, "fb%s.%c *0x%08x", _fcc_names[c], "wl"[s], new_pc);
}
void dis_fsave () {
sprintf(dis.str, "fsave??");
~decompose(dis_op, 1111 001 100 MMMMMM);
sprintf(dis.str, "fsave %s", decode_ea_addr(M));
}
void dis_frestore () {
sprintf(dis.str, "frestore??");
~decompose(dis_op, 1111 001 101 MMMMMM);
sprintf(dis.str, "frestore %s", decode_ea_addr(M));
}
void dis_fpu_other () {
sprintf(dis.str, "fpu_other??");
~decompose(dis_op, 1111 001 000 MMMMMM);
const uint16_t ext = dis_next_word();
~decompose(ext, ccc xxx yyy eeeeeee);
switch (c) {
case 0: // Reg to reg
dis_fmath(dis_op, ext, dis.str);
return;
case 1: // unused
sprintf(dis.str, "f???");
return;
case 2: // Memory->reg & movec
dis_fmath(dis_op, ext, dis.str);
return;
case 3: // reg->mem
dis_fmove_to_mem(ext);
return;
case 4: // mem -> sys ctl registers
case 5: // sys ctl registers -> mem
dis_fmovem_control(ext);
return;
case 6: // movem to fp registers
case 7: // movem to memory
dis_fmovem(ext);
return;
}
}
void dis_fdbcc () {
sprintf(dis.str, "fdbcc??");
~decompose(dis_op, 1111 001 001 001 rrr);
const uint16_t ext = dis_next_word();
~decompose(ext, 0000 0000 00 0ccccc);
const int16_t disp = dis_next_word();
// FIXME: 68kprm is helpfully unclear about which address
// to add the displacement. Based on cpDBcc, dbcc, bcc, and fbcc,
// I'm guessing it starts at the address *of* the displacement
const uint32_t newpc = dis.orig_pc + 4 + disp;
sprintf(dis.str, "fdb%s d%u,0x%08x", _fcc_names[c], r, newpc);
}
void dis_ftrapcc () {
sprintf(dis.str, "ftrapcc??");
~decompose(dis_op, 1111 001 001 111 ooo);
const uint16_t ext = dis_next_word();
~decompose(ext, 0000 0000 00 0ccccc);
uint32_t data;
switch (o) {
case 2:
data = dis_next_word();
sprintf(dis.str, "ftrap%s.w 0x%04x", _fcc_names[c], data);
break;
case 3:
data = dis_next_long();
sprintf(dis.str, "ftrap%s.l 0x%08x", _fcc_names[c], data);
break;
case 4:
sprintf(dis.str, "ftrap%s", _fcc_names[c]);
break;
default:
sprintf(dis.str, "ftrap????");
break;
}
}
void dis_fnop () {
const uint16_t ext = dis_next_word();
sprintf(dis.str, "fnop");

View File

@ -506,12 +506,17 @@ static void inst_fmath_fmovecr (void)
fpu->result = _assemble_float128(0, 0x4000, 0x5bf0a8b14576, 0x95355fb8ac404e7a);
break;
case 0x0d: // log_2(e)
// FIXME: 68881 doesn't set inex2 for this one
// (are the three intermediate bits zeros? I didn't check)
fpu->result = _assemble_float128(0, 0x3fff, 0x71547652b82f, 0xe1777d0ffda0d23a);
break;
case 0x0e: // log_10(e)
fpu->result = _assemble_float128(0, 0x3ffd, 0xbcb7b1526e50, 0xe32a6ab7555f5a67);
// NOTE: 68881 doesn't set inex2 for this one
// Also note: that's bogus. 68881 uses 3 trailing mantissa bits to do rounding,
// and those bits are non-zero for this number, so it must actually be stored
// incorrectly in the ROM.
// I'll emulate this by truncating the float128 mantissa.
// fpu->result = _assemble_float128(0, 0x3ffd, 0xbcb7b1526e50, 0xe32a6ab7555f5a67);
fpu->result = _assemble_float128(0, 0x3ffd, 0xbcb7b1526e50, 0xe32a000000000000);
break;
case 0x0f: // 0.0
fpu->result = _assemble_float128(0, 0, 0, 0);
@ -713,6 +718,16 @@ static void inst_fmath_fmovecr (void)
}
$map_str .= "};\n";
$map_str .= "const char *_fmath_names[128] = {\n";
for (my $i=0; $i < 128; $i++) {
my $name = "f???";
if (exists $op_map->{$i}) {
$name = $op_map->{$i}->{name};
}
$map_str .= "\t\"" . $name . "\"\n";
}
$map_str .= "};\n";
return $map_str;
})
@ -1221,6 +1236,67 @@ static void _fmath_handle_nans ()
fpu->result.high |= 0x800000000000;
}
void dis_fmath (uint16_t op, uint16_t ext, char *output)
{
~decompose(op, 1111 001 000 MMMMMM);
~decompose(ext, 0 a 0 sss ddd eeeeeee);
const uint8_t src_in_ea = a;
const uint8_t source_specifier = s;
const uint8_t dest_register = d;
const uint8_t extension = e;
/* If this is fmovecr */
if (src_in_ea && (source_specifier == 7)) {
const char *name = NULL;
switch (extension) {
case 0x00: name = "pi"; break;
case 0x0b: name = "log_10(2)"; break;
case 0x0c: name = "c"; break;
case 0x0d: name = "log_2(e)"; break;
case 0x0e: name = "log_10(e)"; break;
case 0x0f: name = "0.0"; break;
case 0x30: name = "ln(2)"; break;
case 0x31: name = "ln(10)"; break;
case 0x32: name = "1.0"; break;
case 0x33: name = "10.0"; break;
case 0x34: name = "10.0^2"; break;
case 0x35: name = "10.0^4"; break;
case 0x36: name = "10.0^8"; break;
case 0x37: name = "10.0^16"; break;
case 0x38: name = "10.0^32"; break;
case 0x39: name = "10.0^64"; break;
case 0x3a: name = "10.0^128"; break;
case 0x3b: name = "10.0^256"; break;
case 0x3c: name = "10.0^512"; break;
case 0x3d: name = "10.0^1024"; break;
case 0x3e: name = "10.0^2048"; break;
case 0x3f: name = "10.0^4096"; break;
}
if (name == NULL)
sprintf(output, "fmovecr.x #%u,fp%u", extension, dest_register);
else
sprintf(output, "fmovecr.x %s,fp%u", name, dest_register);
return;
}
if (_fmath_map[e] == NULL) {
sprintf(output, "fmath???");
return;
}
if (src_in_ea) {
sprintf(output, "%s.%c %s,fp%u", _fmath_names[e], "lsxpwdb?"[source_specifier],
decode_ea_rw(M, _format_sizes[source_specifier]), dest_register);
return;
}
else {
sprintf(output, "%s.x fp%u,fp%u", _fmath_names[e],
source_specifier, dest_register);
return;
}
}
static void inst_fmath (const uint16_t ext)
{
fpu_get_state_ptr();
@ -1254,8 +1330,11 @@ static void inst_fmath (const uint16_t ext)
* FIXME: consider implementing this behavior.
*/
if (_fmath_map[e] == NULL) {
throw_illegal_instruction();
return ;
/* Unless this is fmovecr, where the extension doesn't matter */
if (!(src_in_ea && (source_specifier == 7))) {
throw_illegal_instruction();
return ;
}
}
/*

View File

@ -51,8 +51,9 @@
#include <machine/endian.h>
#include <libkern/OSByteOrder.h>
#ifndef ntohll
#define ntohll(x) OSSwapBigToHostInt64(x)
#endif
#else /* #if (defined __APPLE__) */
#if __BYTE_ORDER == __LITTLE_ENDIAN
@ -845,6 +846,7 @@ void dis_ftrapcc();
void dis_fdbcc();
void dis_fnop();
void dis_fpu_other();
void dis_fmath (uint16_t op, uint16_t ext, char *output);
void fpu_initialize();
void fpu_reset();

View File

@ -840,7 +840,7 @@ int main (int argc, char **argv)
config.debug_mode = 1;
config.aux_verbose = 1;
config.ram_size = 16 * 1024 * 1024;
config.ram_size = 4 * 1024 * 1024;
config.aux_kernel_path = "/unix";
config.rom_path = "../priv/macii.rom";
@ -864,8 +864,8 @@ int main (int argc, char **argv)
640, // 1024,
480); // 768,
uint8_t ethernet_addr[6] = {0x22, 0x33, 0x55, 0x77, 0xbb, 0xdd};
shoebill_install_ethernet_card(&config, 13, ethernet_addr);
// uint8_t ethernet_addr[6] = {0x22, 0x33, 0x55, 0x77, 0xbb, 0xdd};
// shoebill_install_ethernet_card(&config, 13, ethernet_addr);
// Start the VIA timer thread
shoebill_start();