From b1e0fad8562ccddc927a4395f56135abbc5bdf44 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 17 Nov 2017 15:17:51 +0700 Subject: clipper: floating point improvements * switched to softfloat for fp * implemented fp macro instructions * implemented fp exceptions and rounding --- src/devices/cpu/clipper/clipper.cpp | 522 ++++++++++++++++++++++++++---------- src/devices/cpu/clipper/clipper.h | 52 ++-- 2 files changed, 410 insertions(+), 164 deletions(-) diff --git a/src/devices/cpu/clipper/clipper.cpp b/src/devices/cpu/clipper/clipper.cpp index c2d057d8d35..9b7a4721aab 100644 --- a/src/devices/cpu/clipper/clipper.cpp +++ b/src/devices/cpu/clipper/clipper.cpp @@ -4,12 +4,11 @@ /* * An implementation of the Fairchild/Intergraph CLIPPER CPU family. * - * Primary source: http://bitsavers.trailing-edge.com/pdf/fairchild/clipper/Clipper_Instruction_Set_Oct85.pdf + * Primary source: http://bitsavers.org/pdf/fairchild/clipper/Clipper_Instruction_Set_Oct85.pdf * * TODO: * - save/restore state - * - unimplemented instructions - * - C100, C300, C400 variants + * - unimplemented C400 instructions * - correct boot logic * - condition codes for multiply instructions * - most cpu traps/faults @@ -56,6 +55,8 @@ DEFINE_DEVICE_TYPE(CLIPPER_C100, clipper_c100_device, "clipper_c100", "C100 CLIP DEFINE_DEVICE_TYPE(CLIPPER_C300, clipper_c300_device, "clipper_c300", "C300 CLIPPER") DEFINE_DEVICE_TYPE(CLIPPER_C400, clipper_c400_device, "clipper_c400", "C400 CLIPPER") +ALLOW_SAVE_TYPE(clipper_device::fpregs); + clipper_c100_device::clipper_c100_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : clipper_device(mconfig, CLIPPER_C100, tag, owner, clock, 0) { } @@ -119,6 +120,8 @@ void clipper_device::device_start() save_item(NAME(m_ru)); save_item(NAME(m_rs)); save_item(NAME(m_f)); + save_item(NAME(m_fp_pc)); + save_item(NAME(m_fp_dst)); save_item(NAME(m_nmi)); save_item(NAME(m_irq)); @@ -150,26 +153,26 @@ void clipper_device::device_start() state_add(CLIPPER_R14, "r14", m_r[14]); state_add(CLIPPER_R15, "r15", m_r[15]); - state_add(CLIPPER_F0, "f0", m_f[0]); - state_add(CLIPPER_F1, "f1", m_f[1]); - state_add(CLIPPER_F2, "f2", m_f[2]); - state_add(CLIPPER_F3, "f3", m_f[3]); - state_add(CLIPPER_F4, "f4", m_f[4]); - state_add(CLIPPER_F5, "f5", m_f[5]); - state_add(CLIPPER_F6, "f6", m_f[6]); - state_add(CLIPPER_F7, "f7", m_f[7]); + state_add(CLIPPER_F0, "f0", m_f[0].d); + state_add(CLIPPER_F1, "f1", m_f[1].d); + state_add(CLIPPER_F2, "f2", m_f[2].d); + state_add(CLIPPER_F3, "f3", m_f[3].d); + state_add(CLIPPER_F4, "f4", m_f[4].d); + state_add(CLIPPER_F5, "f5", m_f[5].d); + state_add(CLIPPER_F6, "f6", m_f[6].d); + state_add(CLIPPER_F7, "f7", m_f[7].d); // C400 has 8 additional floating point registers if (type() == CLIPPER_C400) { - state_add(CLIPPER_F8, "f8", m_f[8]); - state_add(CLIPPER_F9, "f9", m_f[9]); - state_add(CLIPPER_F10, "f10", m_f[10]); - state_add(CLIPPER_F11, "f11", m_f[11]); - state_add(CLIPPER_F12, "f12", m_f[12]); - state_add(CLIPPER_F13, "f13", m_f[13]); - state_add(CLIPPER_F14, "f14", m_f[14]); - state_add(CLIPPER_F15, "f15", m_f[15]); + state_add(CLIPPER_F8, "f8", m_f[8].d); + state_add(CLIPPER_F9, "f9", m_f[9].d); + state_add(CLIPPER_F10, "f10", m_f[10].d); + state_add(CLIPPER_F11, "f11", m_f[11].d); + state_add(CLIPPER_F12, "f12", m_f[12].d); + state_add(CLIPPER_F13, "f13", m_f[13].d); + state_add(CLIPPER_F14, "f14", m_f[14].d); + state_add(CLIPPER_F15, "f15", m_f[15].d); } } @@ -181,14 +184,14 @@ void clipper_device::device_reset() * ssw: EI, TP, M, U, K, KU, UU, P cleared, ID set from hardware, others undefined */ m_psw = 0; + float_rounding_mode = float_round_nearest_even; + + // clear the ssw set_ssw(0); + // select the register file according to the ssw m_r = SSW(U) ? m_ru : m_rs; - // we'll opt to clear the integer and floating point registers too - memset(m_r, 0, sizeof(s32)*16); - memset(m_f, 0, sizeof(m_f)); - // FIXME: figure out how to branch to the boot code properly m_pc = 0x7f100000; m_irq = CLEAR_LINE; @@ -248,9 +251,16 @@ void clipper_device::execute_run() // decode instruction decode_instruction(insn); + // clear floating point exceptions + float_exception_flags = 0; + // execute instruction, return next pc m_pc = execute_instruction(); + // handle floating point exceptions + if (float_exception_flags) + fp_exception(); + // FIXME: some instructions take longer (significantly) than one cycle // and also the timings are often slower for the C100 and C300 m_icount--; @@ -321,8 +331,8 @@ void clipper_device::decode_instruction (u16 insn) } else { - // fetch 32 bit immediate and sign extend - m_info.imm = (s32)m_insn->read_dword_unaligned(m_pc + 2); + // fetch 32 bit immediate + m_info.imm = m_insn->read_dword_unaligned(m_pc + 2); m_info.size = 6; } } @@ -337,7 +347,7 @@ void clipper_device::decode_instruction (u16 insn) switch (insn & 0x00f0) { case ADDR_MODE_PC32: - m_info.address = m_pc + (s32)m_insn->read_dword_unaligned(m_pc + 2); + m_info.address = m_pc + m_insn->read_dword_unaligned(m_pc + 2); m_info.size = 6; break; @@ -348,7 +358,7 @@ void clipper_device::decode_instruction (u16 insn) case ADDR_MODE_REL32: m_info.r2 = m_insn->read_word(m_pc + 2) & 0xf; - m_info.address = m_r[insn & 0xf] + (s32)m_insn->read_dword_unaligned(m_pc + 4); + m_info.address = m_r[insn & 0xf] + m_insn->read_dword_unaligned(m_pc + 4); m_info.size = 8; break; @@ -429,7 +439,10 @@ int clipper_device::execute_instruction () // treated as a noop if target ssw in user mode // R1 == 3 means "fast" mode - avoids pipeline flush if (R1 == 0) + { m_psw = m_r[R2]; + fp_rounding(); + } else if (!SSW(U) && (R1 == 1 || R1 == 3)) { set_ssw(m_r[R2]); @@ -471,229 +484,278 @@ int clipper_device::execute_instruction () case 0x20: // adds: add single floating - *((float *)&m_f[R2]) += *((float *)&m_f[R1]); + m_fp_pc = m_pc; + m_fp_dst = m_f[R2].s; + + m_f[R2].s = float32_add(m_f[R2].s, m_f[R1].s); + m_ssw |= SSW_FRD; // TRAPS: F_IVUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x21: - // subs: subtract single floating - *((float *)&m_f[R2]) -= *((float *)&m_f[R1]); + // subs: subtract single floating (exception state not documented) + m_fp_pc = m_pc; + m_fp_dst = m_f[R2].s; + + m_f[R2].s = float32_sub(m_f[R2].s, m_f[R1].s); + m_ssw |= SSW_FRD; // TRAPS: F_IVUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x22: // addd: add double floating - m_f[R2] += m_f[R1]; + m_fp_pc = m_pc; + m_fp_dst = m_f[R2].d; + + m_f[R2].d = float64_add(m_f[R2].d, m_f[R1].d); + m_ssw |= SSW_FRD; // TRAPS: F_IVUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x23: - // subd: subtract double floating - m_f[R2] -= m_f[R1]; + // subd: subtract double floating (exception state not documented) + m_fp_pc = m_pc; + m_fp_dst = m_f[R2].d; + + m_f[R2].d = float64_sub(m_f[R2].d, m_f[R1].d); + m_ssw |= SSW_FRD; // TRAPS: F_IVUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x24: // movs: move single floating - *((float *)&m_f[R2]) = *((float *)&m_f[R1]); + m_f[R2].s = m_f[R1].s; + m_ssw |= SSW_FRD; break; case 0x25: // cmps: compare single floating - FLAGS(0, 0, *((float *)&m_f[R2]) == *((float *)&m_f[R1]), *((float *)&m_f[R2]) < *((float *)&m_f[R1])) + FLAGS(0, 0, float32_eq(m_f[R2].s, m_f[R1].s), float32_lt(m_f[R2].s, m_f[R1].s)) + if (float_exception_flags & float_flag_invalid) + m_psw |= PSW_Z | PSW_N; + float_exception_flags &= (0); break; case 0x26: // movd: move double floating - m_f[R2] = m_f[R1]; + m_f[R2].d = m_f[R1].d; + m_ssw |= SSW_FRD; break; case 0x27: // cmpd: compare double floating - FLAGS(0, 0, m_f[R2] == m_f[R1], m_f[R2] < m_f[R1]) - // FLAGS: 00ZN + FLAGS(0, 0, float64_eq(m_f[R2].d, m_f[R1].d), float64_lt(m_f[R2].d, m_f[R1].d)) + if (float_exception_flags & float_flag_invalid) + m_psw |= PSW_Z | PSW_N; + float_exception_flags &= (0); break; case 0x28: // muls: multiply single floating - *((float *)&m_f[R2]) *= *((float *)&m_f[R1]); + m_fp_pc = m_pc; + m_fp_dst = m_f[R2].s; + + m_f[R2].s = float32_mul(m_f[R2].s, m_f[R1].s); + m_ssw |= SSW_FRD; // TRAPS: F_IVUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x29: // divs: divide single floating - *((float *)&m_f[R2]) /= *((float *)&m_f[R1]); + m_fp_pc = m_pc; + m_fp_dst = m_f[R2].s; + + m_f[R2].s = float32_div(m_f[R2].s, m_f[R1].s); + m_ssw |= SSW_FRD; // TRAPS: F_IVDUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_divbyzero | float_flag_underflow | float_flag_inexact); break; case 0x2a: // muld: multiply double floating - m_f[R2] *= m_f[R1]; + m_fp_pc = m_pc; + m_fp_dst = m_f[R2].d; + + m_f[R2].d = float64_mul(m_f[R2].d, m_f[R1].d); + m_ssw |= SSW_FRD; // TRAPS: F_IVUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x2b: // divd: divide double floating - m_f[R2] /= m_f[R1]; + m_fp_pc = m_pc; + m_fp_dst = m_f[R2].d; + + m_f[R2].d = float64_div(m_f[R2].d, m_f[R1].d); + m_ssw |= SSW_FRD; // TRAPS: F_IVDUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_divbyzero | float_flag_underflow | float_flag_inexact); break; case 0x2c: // movsw: move single floating to word - m_r[R2] = *((s32 *)&m_f[R1]); + m_r[R2] = m_f[R1].s; break; case 0x2d: // movws: move word to single floating - *((s32 *)&m_f[R2]) = m_r[R1]; + m_f[R2].s = m_r[R1]; + m_ssw |= SSW_FRD; break; case 0x2e: // movdl: move double floating to longword - ((double *)m_r)[R2 >> 1] = m_f[R1]; + ((u64 *)m_r)[R2 >> 1] = m_f[R1].d; break; case 0x2f: // movld: move longword to double floating - m_f[R2] = ((double *)m_r)[R1 >> 1]; + m_f[R2].d = ((u64 *)m_r)[R1 >> 1]; + m_ssw |= SSW_FRD; break; case 0x30: // shaw: shift arithmetic word - if (m_r[R1] > 0) + if ((s32)m_r[R1] > 0) { // save the bits that will be shifted out plus new sign bit - s32 v = m_r[R2] >> (31 - m_r[R1]); + s32 v = (s32)m_r[R2] >> (31 - m_r[R1]); m_r[R2] <<= m_r[R1]; // overflow is set if sign changes during shift - FLAGS(0, v != 0 && v != -1, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, v != 0 && v != -1, m_r[R2] == 0, (s32)m_r[R2] < 0) } else { - m_r[R2] >>= -m_r[R1]; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + ((s32 *)m_r)[R2] >>= -m_r[R1]; + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) } // FLAGS: 0VZN break; case 0x31: // shal: shift arithmetic longword - if (m_r[R1] > 0) + if ((s32)m_r[R1] > 0) { // save the bits that will be shifted out plus new sign bit s64 v = ((s64 *)m_r)[R2 >> 1] >> (63 - m_r[R1]); - ((s64 *)m_r)[R2 >> 1] <<= m_r[R1]; + ((u64 *)m_r)[R2 >> 1] <<= m_r[R1]; // overflow is set if sign changes during shift - FLAGS(0, v != 0 && v != -1, ((s64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0) + FLAGS(0, v != 0 && v != -1, ((u64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0) } else { ((s64 *)m_r)[R2 >> 1] >>= -m_r[R1]; - FLAGS(0, 0, ((s64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0) + FLAGS(0, 0, ((u64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0) } // FLAGS: 0VZN break; case 0x32: // shlw: shift logical word - if (m_r[R1] > 0) + if ((s32)m_r[R1] > 0) m_r[R2] <<= m_r[R1]; else - ((u32 *)m_r)[R2] >>= -m_r[R1]; + m_r[R2] >>= -m_r[R1]; // FLAGS: 00ZN - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0); + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0); break; case 0x33: // shll: shift logical longword - if (m_r[R1] > 0) + if ((s32)m_r[R1] > 0) ((u64 *)m_r)[R2 >> 1] <<= m_r[R1]; else ((u64 *)m_r)[R2 >> 1] >>= -m_r[R1]; // FLAGS: 00ZN - FLAGS(0, 0, ((s64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0); + FLAGS(0, 0, ((u64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0); break; case 0x34: // rotw: rotate word - if (m_r[R1] > 0) + if ((s32)m_r[R1] > 0) m_r[R2] = rotl32(m_r[R2], m_r[R1]); else m_r[R2] = rotr32(m_r[R2], -m_r[R1]); // FLAGS: 00ZN - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0); + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0); break; case 0x35: // rotl: rotate longword - if (m_r[R1] > 0) + if ((s32)m_r[R1] > 0) ((u64 *)m_r)[R2 >> 1] = rotl64(((u64 *)m_r)[R2 >> 1], m_r[R1]); else ((u64 *)m_r)[R2 >> 1] = rotr64(((u64 *)m_r)[R2 >> 1], -m_r[R1]); // FLAGS: 00ZN - FLAGS(0, 0, ((s64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0); + FLAGS(0, 0, ((u64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0); break; case 0x38: // shai: shift arithmetic immediate - if (m_info.imm > 0) + if ((s32)m_info.imm > 0) { // save the bits that will be shifted out plus new sign bit - s32 v = m_r[R2] >> (31 - m_info.imm); + s32 v = (s32)m_r[R2] >> (31 - m_info.imm); m_r[R2] <<= m_info.imm; // overflow is set if sign changes during shift - FLAGS(0, v != 0 && v != -1, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, v != 0 && v != -1, m_r[R2] == 0, (s32)m_r[R2] < 0) } else { - m_r[R2] >>= -m_info.imm; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + ((s32 *)m_r)[R2] >>= -m_info.imm; + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) } // FLAGS: 0VZN // TRAPS: I break; case 0x39: // shali: shift arithmetic longword immediate - if (m_info.imm > 0) + if ((s32)m_info.imm > 0) { // save the bits that will be shifted out plus new sign bit s64 v = ((s64 *)m_r)[R2 >> 1] >> (63 - m_info.imm); - ((s64 *)m_r)[R2 >> 1] <<= m_info.imm; + ((u64 *)m_r)[R2 >> 1] <<= m_info.imm; // overflow is set if sign changes during shift - FLAGS(0, v != 0 && v != -1, ((s64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0) + FLAGS(0, v != 0 && v != -1, ((u64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0) } else { ((s64 *)m_r)[R2 >> 1] >>= -m_info.imm; - FLAGS(0, 0, ((s64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0) + FLAGS(0, 0, ((u64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0) } // FLAGS: 0VZN // TRAPS: I break; case 0x3a: // shli: shift logical immediate - if (m_info.imm > 0) + if ((s32)m_info.imm > 0) m_r[R2] <<= m_info.imm; else - ((u32 *)m_r)[R2] >>= -m_info.imm; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0); + m_r[R2] >>= -m_info.imm; + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0); // FLAGS: 00ZN // TRAPS: I break; case 0x3b: // shlli: shift logical longword immediate - if (m_info.imm > 0) + if ((s32)m_info.imm > 0) ((u64 *)m_r)[R2 >> 1] <<= m_info.imm; else ((u64 *)m_r)[R2 >> 1] >>= -m_info.imm; - FLAGS(0, 0, ((s64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0); + FLAGS(0, 0, ((u64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0); // FLAGS: 00ZN // TRAPS: I break; case 0x3c: // roti: rotate immediate - if (m_info.imm > 0) + if ((s32)m_info.imm > 0) m_r[R2] = rotl32(m_r[R2], m_info.imm); else m_r[R2] = rotr32(m_r[R2], -m_info.imm); - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0); + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0); // FLAGS: 00ZN // TRAPS: I break; case 0x3d: // rotli: rotate longword immediate - if (m_info.imm > 0) + if ((s32)m_info.imm > 0) ((u64 *)m_r)[R2 >> 1] = rotl64(((u64 *)m_r)[R2 >> 1], m_info.imm); else ((u64 *)m_r)[R2 >> 1] = rotr64(((u64 *)m_r)[R2 >> 1], -m_info.imm); - FLAGS(0, 0, ((s64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0); + FLAGS(0, 0, ((u64 *)m_r)[R2 >> 1] == 0, ((s64 *)m_r)[R2 >> 1] < 0); // FLAGS: 00ZN // TRAPS: I break; @@ -759,13 +821,15 @@ int clipper_device::execute_instruction () case 0x64: case 0x65: // loads: load single floating - ((u64 *)&m_f)[R2] = m_data->read_dword(m_info.address); + m_f[R2].s = m_data->read_dword(m_info.address); + m_ssw |= SSW_FRD; // TRAPS: C,U,A,P,R,I break; case 0x66: case 0x67: // loadd: load double floating - ((u64 *)&m_f)[R2] = m_data->read_qword(m_info.address); + m_f[R2].d = m_data->read_qword(m_info.address); + m_ssw |= SSW_FRD; // TRAPS: C,U,A,P,R,I break; case 0x68: @@ -808,13 +872,13 @@ int clipper_device::execute_instruction () case 0x74: case 0x75: // stors: store single floating - m_data->write_dword(m_info.address, *((u32 *)&m_f[R2])); + m_data->write_dword(m_info.address, m_f[R2].s); // TRAPS: A,P,W,I break; case 0x76: case 0x77: // stord: store double floating - m_data->write_qword(m_info.address, *((u64 *)&m_f[R2])); + m_data->write_qword(m_info.address, m_f[R2].d); // TRAPS: A,P,W,I break; case 0x78: @@ -835,7 +899,7 @@ int clipper_device::execute_instruction () // addw: add word FLAGS_CV(C_ADD(m_r[R2], m_r[R1]), V_ADD(m_r[R2], m_r[R1])) m_r[R2] += m_r[R1]; - FLAGS_ZN(m_r[R2] == 0, m_r[R2] < 0) + FLAGS_ZN(m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: CVZN break; @@ -843,21 +907,21 @@ int clipper_device::execute_instruction () // addq: add quick FLAGS_CV(C_ADD(m_r[R2], R1), V_ADD(m_r[R2], R1)) m_r[R2] += R1; - FLAGS_ZN(m_r[R2] == 0, m_r[R2] < 0) + FLAGS_ZN(m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: CVZN break; case 0x83: // addi: add immediate FLAGS_CV(C_ADD(m_r[R2], m_info.imm), V_ADD(m_r[R2], m_info.imm)) m_r[R2] += m_info.imm; - FLAGS_ZN(m_r[R2] == 0, m_r[R2] < 0) + FLAGS_ZN(m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: CVZN // TRAPS: I break; case 0x84: // movw: move word m_r[R2] = m_r[R1]; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: 00ZN break; @@ -870,35 +934,35 @@ int clipper_device::execute_instruction () case 0x87: // loadi: load immediate m_r[R2] = m_info.imm; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: 00ZN // TRAPS: I break; case 0x88: // andw: and word m_r[R2] &= m_r[R1]; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: 00ZN break; case 0x8b: // andi: and immediate m_r[R2] &= m_info.imm; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: 00ZN // TRAPS: I break; case 0x8c: // orw: or word m_r[R2] |= m_r[R1]; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: 00ZN break; case 0x8f: // ori: or immediate m_r[R2] |= m_info.imm; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: 00ZN // TRAPS: I break; @@ -906,14 +970,14 @@ int clipper_device::execute_instruction () // addwc: add word with carry FLAGS_CV(C_ADD(m_r[R2], (m_r[R1] + (PSW(C) ? 1 : 0))), V_ADD(m_r[R2], (m_r[R1] + (PSW(C) ? 1 : 0)))) m_r[R2] += m_r[R1] + (PSW(C) ? 1 : 0); - FLAGS_ZN(m_r[R2] == 0, m_r[R2] < 0) + FLAGS_ZN(m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: CVZN break; case 0x91: // subwc: subtract word with carry FLAGS_CV(C_SUB(m_r[R2], (m_r[R1] + (PSW(C) ? 1 : 0))), V_SUB(m_r[R2], (m_r[R1] + (PSW(C) ? 1 : 0)))) m_r[R2] -= m_r[R1] + (PSW(C) ? 1 : 0); - FLAGS_ZN(m_r[R2] == 0, m_r[R2] < 0) + FLAGS_ZN(m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: CVZN break; @@ -921,13 +985,13 @@ int clipper_device::execute_instruction () // negw: negate word FLAGS_CV(m_r[R1] != 0, m_r[R1] == INT32_MIN) m_r[R2] = -m_r[R1]; - FLAGS_ZN(m_r[R2] == 0, m_r[R2] < 0) + FLAGS_ZN(m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: CVZN break; case 0x98: // mulw: multiply word - m_r[R2] = m_r[R2] * m_r[R1]; + m_r[R2] = (s32)m_r[R2] * (s32)m_r[R1]; // FLAGS: 0V00 break; case 0x99: @@ -937,7 +1001,7 @@ int clipper_device::execute_instruction () break; case 0x9a: // mulwu: multiply word unsigned - m_r[R2] = (u32)m_r[R2] * (u32)m_r[R1]; + m_r[R2] = m_r[R2] * m_r[R1]; // FLAGS: 0V00 break; case 0x9b: @@ -950,7 +1014,7 @@ int clipper_device::execute_instruction () if (m_r[R1] != 0) { FLAGS(0, m_r[R2] == INT32_MIN && m_r[R1] == -1, 0, 0) - m_r[R2] = m_r[R2] / m_r[R1]; + m_r[R2] = (s32)m_r[R2] / (s32)m_r[R1]; } else next_pc = intrap(EXCEPTION_INTEGER_DIVIDE_BY_ZERO, next_pc, CTS_DIVIDE_BY_ZERO); @@ -962,7 +1026,7 @@ int clipper_device::execute_instruction () if (m_r[R1] != 0) { FLAGS(0, m_r[R2] == INT32_MIN && m_r[R1] == -1, 0, 0) - m_r[R2] = m_r[R2] % m_r[R1]; + m_r[R2] = (s32)m_r[R2] % (s32)m_r[R1]; } else next_pc = intrap(EXCEPTION_INTEGER_DIVIDE_BY_ZERO, next_pc, CTS_DIVIDE_BY_ZERO); @@ -971,8 +1035,8 @@ int clipper_device::execute_instruction () break; case 0x9e: // divwu: divide word unsigned - if ((u32)m_r[R1] != 0) - m_r[R2] = (u32)m_r[R2] / (u32)m_r[R1]; + if (m_r[R1] != 0) + m_r[R2] = m_r[R2] / m_r[R1]; else next_pc = intrap(EXCEPTION_INTEGER_DIVIDE_BY_ZERO, next_pc, CTS_DIVIDE_BY_ZERO); FLAGS(0, 0, 0, 0) @@ -981,8 +1045,8 @@ int clipper_device::execute_instruction () break; case 0x9f: // modwu: modulus word unsigned - if ((u32)m_r[R1] != 0) - m_r[R2] = (u32)m_r[R2] % (u32)m_r[R1]; + if (m_r[R1] != 0) + m_r[R2] = m_r[R2] % m_r[R1]; else next_pc = intrap(EXCEPTION_INTEGER_DIVIDE_BY_ZERO, next_pc, CTS_DIVIDE_BY_ZERO); FLAGS(0, 0, 0, 0) @@ -993,7 +1057,7 @@ int clipper_device::execute_instruction () // subw: subtract word FLAGS_CV(C_SUB(m_r[R2], m_r[R1]), V_SUB(m_r[R2], m_r[R1])) m_r[R2] -= m_r[R1]; - FLAGS_ZN(m_r[R2] == 0, m_r[R2] < 0) + FLAGS_ZN(m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: CVZN break; @@ -1001,52 +1065,52 @@ int clipper_device::execute_instruction () // subq: subtract quick FLAGS_CV(C_SUB(m_r[R2], R1), V_SUB(m_r[R2], R1)) m_r[R2] -= R1; - FLAGS_ZN(m_r[R2] == 0, m_r[R2] < 0) + FLAGS_ZN(m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: CVZN break; case 0xa3: // subi: subtract immediate FLAGS_CV(C_SUB(m_r[R2], m_info.imm), V_SUB(m_r[R2], m_info.imm)) m_r[R2] -= m_info.imm; - FLAGS_ZN(m_r[R2] == 0, m_r[R2] < 0) + FLAGS_ZN(m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: CVZN // TRAPS: I break; case 0xa4: // cmpw: compare word - FLAGS(C_SUB(m_r[R2], m_r[R1]), V_SUB(m_r[R2], m_r[R1]), m_r[R2] == m_r[R1], m_r[R2] < m_r[R1]) + FLAGS(C_SUB(m_r[R2], m_r[R1]), V_SUB(m_r[R2], m_r[R1]), m_r[R2] == m_r[R1], (s32)m_r[R2] < (s32)m_r[R1]) // FLAGS: CVZN break; case 0xa6: // cmpq: compare quick - FLAGS(C_SUB(m_r[R2], R1), V_SUB(m_r[R2], R1), m_r[R2] == (s32)R1, m_r[R2] < (s32)R1) + FLAGS(C_SUB(m_r[R2], R1), V_SUB(m_r[R2], R1), m_r[R2] == R1, (s32)m_r[R2] < (s32)R1) // FLAGS: CVZN break; case 0xa7: // cmpi: compare immediate - FLAGS(C_SUB(m_r[R2], m_info.imm), V_SUB(m_r[R2], m_info.imm), m_r[R2] == m_info.imm, m_r[R2] < m_info.imm) + FLAGS(C_SUB(m_r[R2], m_info.imm), V_SUB(m_r[R2], m_info.imm), m_r[R2] == m_info.imm, (s32)m_r[R2] < (s32)m_info.imm) // FLAGS: CVZN // TRAPS: I break; case 0xa8: // xorw: exclusive or word m_r[R2] ^= m_r[R1]; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: 00ZN break; case 0xab: // xori: exclusive or immediate m_r[R2] ^= m_info.imm; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: 00ZN // TRAPS: I break; case 0xac: // notw: not word m_r[R2] = ~m_r[R1]; - FLAGS(0, 0, m_r[R2] == 0, m_r[R2] < 0) + FLAGS(0, 0, m_r[R2] == 0, (s32)m_r[R2] < 0) // FLAGS: 00ZN break; @@ -1158,7 +1222,7 @@ int clipper_device::execute_instruction () // store fi at sp - 8 * (8 - i) for (int i = R2; i < 8; i++) - m_data->write_qword(m_r[15] - 8 * (8 - i), m_f[i]); + m_data->write_qword(m_r[15] - 8 * (8 - i), m_f[i].d); // decrement sp after push to allow restart on exceptions m_r[15] -= 8 * (8 - R2); @@ -1170,71 +1234,166 @@ int clipper_device::execute_instruction () // load fi from sp + 8 * (i - N) for (int i = R2; i < 8; i++) - m_f[i] = m_data->read_qword(m_r[15] + 8 * (i - R2)); + m_f[i].d = m_data->read_qword(m_r[15] + 8 * (i - R2)); + m_ssw |= SSW_FRD; // increment sp after pop to allow restart on exceptions m_r[15] += 8 * (8 - R2); // TRAPS: C,U,A,P,R break; -#ifdef UNIMPLEMENTED case 0x30: - // cnvsw + // cnvsw: convert single floating to word + m_fp_pc = m_pc; + + m_r[m_info.macro & 0xf] = float32_to_int32(m_f[(m_info.macro >> 4) & 0xf].s); + // TRAPS: F_IX + float_exception_flags &= (float_flag_invalid | float_flag_inexact); + break; case 0x31: - // cnvrsw + // cnvrsw: convert rounding single floating to word (non-IEEE +0.5/-0.5 rounding) + m_fp_pc = m_pc; + + if (float32_lt(m_f[(m_info.macro >> 4) & 0xf].s, 0)) + m_r[m_info.macro & 0xf] = float32_to_int32_round_to_zero(float32_sub(m_f[(m_info.macro >> 4) & 0xf].s, + float32_div(int32_to_float32(1), int32_to_float32(2)))); + else + m_r[m_info.macro & 0xf] = float32_to_int32_round_to_zero(float32_add(m_f[(m_info.macro >> 4) & 0xf].s, + float32_div(int32_to_float32(1), int32_to_float32(2)))); // TRAPS: F_IX + float_exception_flags &= (float_flag_invalid | float_flag_inexact); + break; case 0x32: - // cnvtsw + // cnvtsw: convert truncating single floating to word + m_fp_pc = m_pc; + + m_r[m_info.macro & 0xf] = float32_to_int32_round_to_zero(m_f[(m_info.macro >> 4) & 0xf].s); // TRAPS: F_IX + float_exception_flags &= (float_flag_invalid | float_flag_inexact); + break; case 0x33: - // cnvws + // cnvws: convert word to single floating + m_f[m_info.macro & 0xf].s = int32_to_float32(m_r[(m_info.macro >> 4) & 0xf]); + m_ssw |= SSW_FRD; // TRAPS: F_X + float_exception_flags &= (float_flag_inexact); + break; case 0x34: - // cnvdw + // cnvdw: convert double floating to word + m_fp_pc = m_pc; + + m_r[m_info.macro & 0xf] = float64_to_int32(m_f[(m_info.macro >> 4) & 0xf].d); // TRAPS: F_IX + float_exception_flags &= (float_flag_invalid | float_flag_inexact); + break; case 0x35: - // cnvrdw + // cnvrdw: convert rounding double floating to word (non-IEEE +0.5/-0.5 rounding) + m_fp_pc = m_pc; + + if (float64_lt(m_f[(m_info.macro >> 4) & 0xf].d, 0)) + m_r[m_info.macro & 0xf] = float64_to_int32_round_to_zero(float64_sub(m_f[(m_info.macro >> 4) & 0xf].d, + float64_div(int32_to_float64(1), int32_to_float64(2)))); + else + m_r[m_info.macro & 0xf] = float64_to_int32_round_to_zero(float64_add(m_f[(m_info.macro >> 4) & 0xf].d, + float64_div(int32_to_float64(1), int32_to_float64(2)))); // TRAPS: F_IX + float_exception_flags &= (float_flag_invalid | float_flag_inexact); break; -#endif - case 0x36: // cnvtdw - m_r[m_info.macro & 0xf] = (s32)m_f[(m_info.macro >> 4) & 0xf]; + case 0x36: + // cnvtdw: convert truncating double floating to word + m_fp_pc = m_pc; + + m_r[m_info.macro & 0xf] = float64_to_int32_round_to_zero(m_f[(m_info.macro >> 4) & 0xf].d); // TRAPS: F_IX + float_exception_flags &= (float_flag_invalid | float_flag_inexact); break; - case 0x37: // cnvwd - m_f[m_info.macro & 0xf] = (double)m_r[(m_info.macro >> 4) & 0xf]; + case 0x37: + // cnvwd: convert word to double floating + m_f[m_info.macro & 0xf].d = int32_to_float64(m_r[(m_info.macro >> 4) & 0xf]); + m_ssw |= SSW_FRD; + float_exception_flags &= (0); break; -#ifdef UNIMPLEMENTED case 0x38: - // cnvsd + // cnvsd: convert single to double floating + m_f[m_info.macro & 0xf].d = float32_to_float64(m_f[(m_info.macro >> 4) & 0xf].s); + m_ssw |= SSW_FRD; // TRAPS: F_I + float_exception_flags &= (float_flag_invalid); + break; case 0x39: - // cnvds + // cnvds: convert double to single floating + m_fp_pc = m_pc; + m_fp_dst = m_f[m_info.macro & 0xf].s; + + m_f[m_info.macro & 0xf].s = float64_to_float32(m_f[(m_info.macro >> 4) & 0xf].d); + m_ssw |= SSW_FRD; // TRAPS: F_IVUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); + break; case 0x3a: - // negs + // negs: negate single floating + m_f[m_info.macro & 0xf].s = float32_mul(m_f[(m_info.macro >> 4) & 0xf].s, int32_to_float32(-1)); + m_ssw |= SSW_FRD; + float_exception_flags &= (0); + break; case 0x3b: - // negds + // negd: negate double floating + m_f[m_info.macro & 0xf].d = float64_mul(m_f[(m_info.macro >> 4) & 0xf].d, int32_to_float64(-1)); + m_ssw |= SSW_FRD; + float_exception_flags &= (0); + break; case 0x3c: - // scalbs + /* + * This implementation for scalbd and scalbs is a bit opaque, but + * essentially we check if the integer value is within range, and + * directly create a floating constant representing 2^n or NaN + * respectively, which is used as an input to a multiply, producing + * the desired result. While doing an actual multiply is both + * inefficient and unnecessary, it's a tidy way to ensure the + * correct exception flags are set. + */ + // scalbs: scale by, single floating + m_fp_pc = m_pc; + m_fp_dst = m_f[m_info.macro & 0xf].s; + + m_f[m_info.macro & 0xf].s = float32_mul(m_f[m_info.macro & 0xf].s, + (((s32)m_r[(m_info.macro >> 4) & 0xf] > -127 && (s32)m_r[(m_info.macro >> 4) & 0xf] < 128) + ? (float32)(((s32)m_r[(m_info.macro >> 4) & 0xf] + 127) << 23) + : (float32)~u32(0))); + m_ssw |= SSW_FRD; // TRAPS: F_IVUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); + break; case 0x3d: - // scalbd - // FLAGS: N + // scalbd: scale by, double floating + m_fp_pc = m_pc; + m_fp_dst = m_f[m_info.macro & 0xf].d; + + m_f[m_info.macro & 0xf].d = float64_mul(m_f[m_info.macro & 0xf].d, + ((s32)m_r[(m_info.macro >> 4) & 0xf] > -1023 && (s32)m_r[(m_info.macro >> 4) & 0xf] < 1024) + ? (float64)((u64)((s32)m_r[(m_info.macro >> 4) & 0xf] + 1023) << 52) + : (float64)~u64(0)); + m_ssw |= SSW_FRD; // TRAPS: F_IVUX + float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); + break; case 0x3e: - // trapfn + // trapfn: trap floating unordered + if (PSW(Z) && PSW(N)) + next_pc = intrap(EXCEPTION_ILLEGAL_OPERATION, next_pc, CTS_ILLEGAL_OPERATION); // TRAPS: I case 0x3f: - // loadfs + // loadfs: load floating status + m_r[(m_info.macro >> 4) & 0xf] = m_fp_pc; + m_f[m_info.macro & 0xf].d = m_fp_dst; + m_ssw |= SSW_FRD; break; -#endif + default: LOG("illegal unprivileged macro opcode at 0x%08x\n", m_pc); next_pc = intrap(EXCEPTION_ILLEGAL_OPERATION, next_pc, CTS_ILLEGAL_OPERATION); machine().debug_break(); break; } - break; case 0xb6: @@ -1246,14 +1405,14 @@ int clipper_device::execute_instruction () case 0x00: // movus: move user to supervisor m_rs[m_info.macro & 0xf] = m_ru[(m_info.macro >> 4) & 0xf]; - FLAGS(0, 0, m_rs[m_info.macro & 0xf] == 0, m_rs[m_info.macro & 0xf] < 0) + FLAGS(0, 0, m_rs[m_info.macro & 0xf] == 0, (s32)m_rs[m_info.macro & 0xf] < 0) // FLAGS: 00ZN // TRAPS: S break; case 0x01: // movsu: move supervisor to user m_ru[m_info.macro & 0xf] = m_rs[(m_info.macro >> 4) & 0xf]; - FLAGS(0, 0, m_ru[m_info.macro & 0xf] == 0, m_ru[m_info.macro & 0xf] < 0) + FLAGS(0, 0, m_ru[m_info.macro & 0xf] == 0, (s32)m_ru[m_info.macro & 0xf] < 0) // FLAGS: 00ZN // TRAPS: S break; @@ -1285,6 +1444,9 @@ int clipper_device::execute_instruction () m_rs[(m_info.macro >> 4) & 0xf] += 12; m_r = SSW(U) ? m_ru : m_rs; + + fp_rounding(); + // TRAPS: S break; case 0x05: @@ -1330,15 +1492,17 @@ int clipper_device::execute_instruction () } /* -* Common entry point for transferring control in the event of an interrupt or exception. -*/ -u32 clipper_device::intrap(u32 vector, u32 pc, u32 cts, u32 mts) + * Common entry point for transferring control in the event of an interrupt or + * exception. Reading between the lines, it appears this logic was implemented + * using the macro instruction ROM and a special macro instruction (intrap). + */ +u32 clipper_device::intrap(u16 vector, u32 pc, u32 cts, u32 mts) { // fetch pc and ssw from interrupt vector u32 next_pc = m_data->read_dword(vector + 0); u32 next_ssw = m_data->read_dword(vector + 4); - LOGMASKED(LOG_INTERRUPT, "intrap vector 0x%08x pc 0x%08x next_pc 0x%08x ssp 0x%08x\n", vector, pc, next_pc, m_rs[15]); + LOGMASKED(LOG_INTERRUPT, "intrap vector 0x%04x pc 0x%08x next_pc 0x%08x ssp 0x%08x\n", vector, pc, next_pc, m_rs[15]); // set cts and mts to indicate source of exception m_psw = (m_psw & ~(PSW_CTS | PSW_MTS)) | mts | cts; @@ -1356,6 +1520,7 @@ u32 clipper_device::intrap(u32 vector, u32 pc, u32 cts, u32 mts) // clear psw m_psw = 0; + float_rounding_mode = float_round_nearest_even; m_r = SSW(U) ? m_ru : m_rs; @@ -1363,13 +1528,13 @@ u32 clipper_device::intrap(u32 vector, u32 pc, u32 cts, u32 mts) return next_pc; } -u32 clipper_c400_device::intrap(u32 vector, u32 pc, u32 cts, u32 mts) +u32 clipper_c400_device::intrap(u16 vector, u32 pc, u32 cts, u32 mts) { // C400 reverses order of pc and ssw in interrupt vector u32 next_pc = m_data->read_dword(vector + 4); u32 next_ssw = m_data->read_dword(vector + 0); - LOGMASKED(LOG_INTERRUPT, "intrap vector 0x%08x pc 0x%08x next_pc 0x%08x ssp 0x%08x\n", vector, pc, next_pc, m_rs[15]); + LOGMASKED(LOG_INTERRUPT, "intrap vector 0x%04x pc 0x%08x next_pc 0x%08x ssp 0x%08x\n", vector, pc, next_pc, m_rs[15]); // set cts and mts to indicate source of exception m_psw = (m_psw & ~(PSW_CTS | PSW_MTS)) | mts | cts; @@ -1393,6 +1558,7 @@ u32 clipper_c400_device::intrap(u32 vector, u32 pc, u32 cts, u32 mts) // clear psw m_psw = 0; + float_rounding_mode = float_round_nearest_even; m_r = SSW(U) ? m_ru : m_rs; @@ -1460,6 +1626,64 @@ bool clipper_device::evaluate_branch() const return false; } +void clipper_device::fp_rounding() +{ + // set the softfloat rounding mode based on the psw rounding mode + switch (PSW(FR)) + { + case FR_0: float_rounding_mode = float_round_nearest_even; break; + case FR_1: float_rounding_mode = float_round_up; break; + case FR_2: float_rounding_mode = float_round_down; break; + case FR_3: float_rounding_mode = float_round_to_zero; break; + } +} + +void clipper_device::fp_exception() +{ + u16 vector = 0; + + /* + * Set the psw floating exception flags, and identify any enabled + * exceptions. The order here is important, but since the documentation + * doesn't explicitly specify, this is a guess. Simply put, exceptions + * are considered in sequence with an increasing order of priority. + */ + if (float_exception_flags & float_flag_inexact) + { + m_psw |= PSW_FX; + if (PSW(EFX)) + vector = EXCEPTION_FLOATING_INEXACT; + } + if (float_exception_flags & float_flag_underflow) + { + m_psw |= PSW_FU; + if (PSW(EFU)) + vector = EXCEPTION_FLOATING_UNDERFLOW; + } + if (float_exception_flags & float_flag_overflow) + { + m_psw |= PSW_FV; + if (PSW(EFV)) + vector = EXCEPTION_FLOATING_OVERFLOW; + } + if (float_exception_flags & float_flag_divbyzero) + { + m_psw |= PSW_FD; + if (PSW(EFD)) + vector = EXCEPTION_FLOATING_DIVIDE_BY_ZERO; + } + if (float_exception_flags & float_flag_invalid) + { + m_psw |= PSW_FI; + if (PSW(EFI)) + vector = EXCEPTION_FLOATING_INVALID_OPERATION; + } + + // trigger a floating point exception + if (PSW(EFT) && vector) + m_pc = intrap(vector, m_pc); +} + offs_t clipper_device::disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) { return CPU_DISASSEMBLE_NAME(clipper)(this, stream, pc, oprom, opram, options); diff --git a/src/devices/cpu/clipper/clipper.h b/src/devices/cpu/clipper/clipper.h index 27624b4e05a..4ecb3926d25 100644 --- a/src/devices/cpu/clipper/clipper.h +++ b/src/devices/cpu/clipper/clipper.h @@ -7,6 +7,8 @@ #pragma once #include +#include "softfloat/milieu.h" +#include "softfloat/softfloat.h" // convenience macros for dealing with the psw and ssw #define PSW(mask) (m_psw & PSW_##mask) @@ -91,13 +93,21 @@ protected: PSW_MTS = 0xf0000000, // memory trap status (4 bits) }; - enum clipper_ssw + enum psw_fr + { + FR_0 = 0x00000000, // round to nearest + FR_1 = 0x00008000, // round toward + infinity + FR_2 = 0x00010000, // round toward - infinity + FR_3 = 0x00018000 // round toward zero + }; + + enum ssw { SSW_IN = 0x0000000f, // interrupt number (4 bits) SSW_IL = 0x000000f0, // interrupt level (4 bits) SSW_EI = 0x00000100, // enable interrupts SSW_ID = 0x0001fe00, // cpu rev # and type (8 bits) - // unused (5 bits) + // unused (5 bits) SSW_FRD = 0x00400000, // floating registers dirty SSW_TP = 0x00800000, // trace trap pending SSW_ECM = 0x01000000, // enabled corrected memory error @@ -110,7 +120,7 @@ protected: SSW_P = 0x80000000, // previous mode }; - enum clipper_ssw_id + enum ssw_id { SSW_ID_C400R0 = 0x00000, SSW_ID_C400R1 = 0x04000, @@ -211,8 +221,8 @@ protected: virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; // device_disasm_interface overrides - virtual uint32_t disasm_min_opcode_bytes() const override { return 2; } // smallest instruction - virtual uint32_t disasm_max_opcode_bytes() const override { return 8; } // largest instruction + virtual u32 disasm_min_opcode_bytes() const override { return 2; } // smallest instruction + virtual u32 disasm_max_opcode_bytes() const override { return 8; } // largest instruction virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) override; void set_ssw(u32 data) { m_ssw = (m_ssw & SSW(ID)) | (data & ~SSW(ID)); } @@ -223,12 +233,20 @@ protected: u32 m_ssw; // integer registers - s32 *m_r; // active registers - s32 m_ru[16]; // user registers - s32 m_rs[16]; // supervisor registers + u32 *m_r; // active registers + u32 m_ru[16]; // user registers + u32 m_rs[16]; // supervisor registers // floating registers - double m_f[16]; + union fpregs + { + float64 d; // double precision floating point + float32 s; // single precision floating point + } + m_f[16]; + + u32 m_fp_pc; // address of floating point instruction causing exception + u64 m_fp_dst; // original value of destination register during fp exception address_space_config m_insn_config; address_space_config m_data_config; @@ -244,12 +262,12 @@ private: u8 m_ivec; // decoded instruction information - struct + struct decode { + // various decoded instruction fields u8 opcode, subopcode; u8 r1, r2; - - s32 imm; + u32 imm; u16 macro; // total size of instruction in bytes @@ -257,14 +275,18 @@ private: // computed effective address u32 address; - } m_info; + } + m_info; void decode_instruction(u16 insn); int execute_instruction(); bool evaluate_branch() const; + void fp_rounding(); + void fp_exception(); + protected: - virtual uint32_t intrap(u32 vector, u32 pc, u32 cts = CTS_NO_CPU_TRAP, u32 mts = MTS_NO_MEMORY_TRAP); + virtual u32 intrap(u16 vector, u32 pc, u32 cts = CTS_NO_CPU_TRAP, u32 mts = MTS_NO_MEMORY_TRAP); }; class clipper_c100_device : public clipper_device @@ -285,7 +307,7 @@ public: clipper_c400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); protected: - virtual uint32_t intrap(u32 vector, u32 pc, u32 cts = CTS_NO_CPU_TRAP, u32 mts = MTS_NO_MEMORY_TRAP) override; + virtual u32 intrap(u16 vector, u32 pc, u32 cts = CTS_NO_CPU_TRAP, u32 mts = MTS_NO_MEMORY_TRAP) override; }; DECLARE_DEVICE_TYPE(CLIPPER_C100, clipper_c100_device) -- cgit v1.2.3 From f12b3fb4b76197387ab0ab9810b1c1ca6c2eda72 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 17 Nov 2017 15:20:07 +0700 Subject: interpro: use new 28f010 device (nw) Sapphire systems can now re-flash themselves from floppy. --- src/mame/drivers/interpro.cpp | 54 +++++++++++++++++++++++++------------------ src/mame/includes/interpro.h | 30 +++++------------------- 2 files changed, 38 insertions(+), 46 deletions(-) diff --git a/src/mame/drivers/interpro.cpp b/src/mame/drivers/interpro.cpp index 44bf7846b25..2445c9285b2 100644 --- a/src/mame/drivers/interpro.cpp +++ b/src/mame/drivers/interpro.cpp @@ -104,8 +104,10 @@ * U35 128 kB EPROM (MPRGW510B) Boot ROM * U43? (MPRGM610P) Bitstream for XC3020? * U44 Intel 82596SX Ethernet controller (20MHz) + * U67 Intel N28F010-200 128Kx8 flash memory (200ns) * U68 CYID21603 TC150G89AF * U71 LSI L1A6104 CICD 95801 Intergraph I/O gate array + * U76 Intel N28F010-200 128Kx8 flash memory (200ns) * U81 NCR 53C94 SCSI controller * U86 24.0 MHz crystal Clock source for 53C94? * U87 4.9152 MHz crystal Clock source for 8530s? @@ -129,7 +131,9 @@ * U43? (MPRGM610P) Bitstream for XC3020? * U44 Intel 82596SX? Ethernet controller * U68 CYID21603 TC150G89AF + * U67 Intel N28F010 128Kx8 flash memory * U71 LSI L1A7374 CIDC094A3 Intergraph I/O gate array + * U76 Intel N28F010 128Kx8 flash memory * U81 NCR 53C94 SCSI controller * U86 24.0 MHz crystal Clock source for 53C94? * U87 4.9152 MHz crystal Clock source for 8530s? @@ -155,14 +159,6 @@ #define VERBOSE 0 #include "logmacro.h" -// FIXME: eeprom/flash device embedded here until real device is known -DEFINE_DEVICE_TYPE(INTERPRO_EEPROM, interpro_eeprom_device, "interpro_eeprom", "InterPro Flash EEPROM"); - -interpro_eeprom_device::interpro_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : eeprom_base_device(mconfig, INTERPRO_EEPROM, tag, owner) -{ -} - void interpro_state::machine_start() { // FIXME: disabled for now to avoid cold start diagnostic errors @@ -242,7 +238,9 @@ WRITE16_MEMBER(sapphire_state::sreg_ctrl2_w) { interpro_state::sreg_ctrl2_w(space, offset, data, mem_mask); - m_eeprom->write_enable(data & CTRL2_FLASHEN ? ASSERT_LINE : CLEAR_LINE); + // enable/disable programming power on both flash devices + m_flash_lo->vpp(data & CTRL2_FLASHEN ? ASSERT_LINE : CLEAR_LINE); + m_flash_hi->vpp(data & CTRL2_FLASHEN ? ASSERT_LINE : CLEAR_LINE); } READ16_MEMBER(interpro_state::sreg_error_r) @@ -376,7 +374,8 @@ ADDRESS_MAP_END static ADDRESS_MAP_START(sapphire_main_map, 0, 32, sapphire_state) AM_RANGE(0x00000000, 0x00ffffff) AM_RAM AM_SHARE(RAM_TAG) AM_RANGE(0x7f100000, 0x7f11ffff) AM_ROM AM_REGION(INTERPRO_EPROM_TAG, 0) - AM_RANGE(0x7f180000, 0x7f1bffff) AM_DEVREADWRITE16(INTERPRO_EEPROM_TAG, interpro_eeprom_device, eeprom_r, eeprom_w, 0xffffffff) + AM_RANGE(0x7f180000, 0x7f1fffff) AM_DEVREADWRITE8(INTERPRO_FLASH_TAG "_lo", intel_28f010_device, read, write, 0x00ff00ff) AM_MASK(0x3ffff) + AM_RANGE(0x7f180000, 0x7f1fffff) AM_DEVREADWRITE8(INTERPRO_FLASH_TAG "_hi", intel_28f010_device, read, write, 0xff00ff00) AM_MASK(0x3ffff) AM_IMPORT_FROM(sapphire_base_map) ADDRESS_MAP_END @@ -635,10 +634,9 @@ static MACHINE_CONFIG_DERIVED(sapphire, interpro) MCFG_DEVICE_ADD(INTERPRO_IOGA_TAG, SAPPHIRE_IOGA, 0) MCFG_FRAGMENT_ADD(ioga) - // eeprom - MCFG_DEVICE_ADD(INTERPRO_EEPROM_TAG, INTERPRO_EEPROM, 0) - MCFG_EEPROM_SIZE(0x20000, 16) - MCFG_EEPROM_WRITE_TIME(attotime::from_usec(1000)) + // flash memory + MCFG_DEVICE_ADD(INTERPRO_FLASH_TAG "_lo", INTEL_28F010, 0) + MCFG_DEVICE_ADD(INTERPRO_FLASH_TAG "_hi", INTEL_28F010, 0) MACHINE_CONFIG_END MACHINE_CONFIG_DERIVED(ip2000, turquoise) @@ -684,8 +682,11 @@ ROM_START(ip2400) ROM_SYSTEM_BIOS(0, "ip2400", "InterPro 2400 EPROM") ROMX_LOAD("mprgw510b__05_16_92.u35", 0x00000, 0x20000, CRC(3b2c4545) SHA1(4e4c98d1cd1035a04be8527223f44d0b687ec3ef), ROM_BIOS(1)) - ROM_REGION16_LE(0x0040000, INTERPRO_EEPROM_TAG, 0) - ROM_LOAD_OPTIONAL("c4saph.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) + ROM_REGION(0x20000, INTERPRO_FLASH_TAG "_lo", 0) + ROM_LOAD_OPTIONAL("y225.u76", 0x00000, 0x20000, CRC(46c0b105) SHA1(7c4a104e4fb3d0e5e8db7c911cdfb3f5c4fb0218)) + + ROM_REGION(0x20000, INTERPRO_FLASH_TAG "_hi", 0) + ROM_LOAD_OPTIONAL("y226.u67", 0x00000, 0x20000, CRC(54d95730) SHA1(a4e114dee1567d8aa31eed770f7cc366588f395c)) ROM_END ROM_START(ip2500) @@ -696,8 +697,11 @@ ROM_START(ip2500) ROM_SYSTEM_BIOS(0, "ip2500", "InterPro 2500 EPROM") ROMX_LOAD("ip2500_eprom.bin", 0x00000, 0x20000, NO_DUMP, ROM_BIOS(1)) - ROM_REGION16_LE(0x0040000, INTERPRO_EEPROM_TAG, 0) - ROM_LOAD_OPTIONAL("c4saph.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) + ROM_REGION(0x20000, INTERPRO_FLASH_TAG "_lo", 0) + ROM_LOAD_OPTIONAL("y225.u76", 0x00000, 0x20000, CRC(46c0b105) SHA1(7c4a104e4fb3d0e5e8db7c911cdfb3f5c4fb0218)) + + ROM_REGION(0x20000, INTERPRO_FLASH_TAG "_hi", 0) + ROM_LOAD_OPTIONAL("y226.u67", 0x00000, 0x20000, CRC(54d95730) SHA1(a4e114dee1567d8aa31eed770f7cc366588f395c)) ROM_END ROM_START(ip2700) @@ -708,8 +712,11 @@ ROM_START(ip2700) ROM_SYSTEM_BIOS(0, "ip2700", "InterPro 2700 EPROM") ROMX_LOAD("mprgz530a__9405181.u35", 0x00000, 0x20000, CRC(467ce7bd) SHA1(53faee40d5df311f53b24c930e434cbf94a5c4aa), ROM_BIOS(1)) - ROM_REGION16_LE(0x0040000, INTERPRO_EEPROM_TAG, 0) - ROM_LOAD_OPTIONAL("c4saph.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) + ROM_REGION(0x20000, INTERPRO_FLASH_TAG "_lo", 0) + ROM_LOAD_OPTIONAL("y225.u76", 0x00000, 0x20000, CRC(46c0b105) SHA1(7c4a104e4fb3d0e5e8db7c911cdfb3f5c4fb0218)) + + ROM_REGION(0x20000, INTERPRO_FLASH_TAG "_hi", 0) + ROM_LOAD_OPTIONAL("y226.u67", 0x00000, 0x20000, CRC(54d95730) SHA1(a4e114dee1567d8aa31eed770f7cc366588f395c)) ROM_END ROM_START(ip2800) @@ -720,8 +727,11 @@ ROM_START(ip2800) ROM_SYSTEM_BIOS(0, "ip2800", "InterPro 2800 EPROM") ROMX_LOAD("ip2800_eprom.bin", 0x00000, 0x20000, CRC(467ce7bd) SHA1(53faee40d5df311f53b24c930e434cbf94a5c4aa), ROM_BIOS(1)) - ROM_REGION16_LE(0x0040000, INTERPRO_EEPROM_TAG, 0) - ROM_LOAD_OPTIONAL("c4saph.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) + ROM_REGION(0x20000, INTERPRO_FLASH_TAG "_lo", 0) + ROM_LOAD_OPTIONAL("y225.u76", 0x00000, 0x20000, CRC(46c0b105) SHA1(7c4a104e4fb3d0e5e8db7c911cdfb3f5c4fb0218)) + + ROM_REGION(0x20000, INTERPRO_FLASH_TAG "_hi", 0) + ROM_LOAD_OPTIONAL("y226.u67", 0x00000, 0x20000, CRC(54d95730) SHA1(a4e114dee1567d8aa31eed770f7cc366588f395c)) ROM_END /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ diff --git a/src/mame/includes/interpro.h b/src/mame/includes/interpro.h index d64884fe77d..f65bcbb0c1f 100644 --- a/src/mame/includes/interpro.h +++ b/src/mame/includes/interpro.h @@ -15,7 +15,7 @@ #include "machine/interpro_arbga.h" #include "machine/ram.h" -#include "machine/eeprom.h" +#include "machine/28fxxx.h" #include "machine/mc146818.h" #include "machine/z80scc.h" #include "machine/upd765.h" @@ -55,30 +55,10 @@ #define INTERPRO_IDPROM_TAG "idprom" #define INTERPRO_EPROM_TAG "eprom" -#define INTERPRO_EEPROM_TAG "eeprom" +#define INTERPRO_FLASH_TAG "flash" #define INTERPRO_SRBUS_TAG "sr" -class interpro_eeprom_device : public eeprom_base_device -{ -public: - interpro_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - DECLARE_READ16_MEMBER(eeprom_r) { return read(offset); } - DECLARE_WRITE16_MEMBER(eeprom_w) { if (m_write_enable) write(offset, data); } - - DECLARE_WRITE_LINE_MEMBER(write_enable) { m_write_enable = state; } - -protected: - virtual void device_start() override { eeprom_base_device::device_start(); } - virtual void device_reset() override { eeprom_base_device::device_reset(); } - -private: - int m_write_enable; -}; - -DECLARE_DEVICE_TYPE(INTERPRO_EEPROM, interpro_eeprom_device) - class interpro_state : public driver_device { public: @@ -210,10 +190,12 @@ class sapphire_state : public interpro_state public: sapphire_state(const machine_config &mconfig, device_type type, const char *tag) : interpro_state(mconfig, type, tag) - , m_eeprom(*this, INTERPRO_EEPROM_TAG) + , m_flash_lo(*this, INTERPRO_FLASH_TAG "_lo") + , m_flash_hi(*this, INTERPRO_FLASH_TAG "_hi") {} - required_device m_eeprom; + required_device m_flash_lo; + required_device m_flash_hi; virtual DECLARE_WRITE16_MEMBER(sreg_ctrl2_w) override; }; -- cgit v1.2.3 From 3873ba65ad3728038115de7ddd476fc971644035 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 17 Nov 2017 17:11:57 +0700 Subject: clipper: no unions (nw) --- src/devices/cpu/clipper/clipper.cpp | 206 +++++++++++++++--------------------- src/devices/cpu/clipper/clipper.h | 14 +-- 2 files changed, 94 insertions(+), 126 deletions(-) diff --git a/src/devices/cpu/clipper/clipper.cpp b/src/devices/cpu/clipper/clipper.cpp index 9b7a4721aab..d7498beb6f2 100644 --- a/src/devices/cpu/clipper/clipper.cpp +++ b/src/devices/cpu/clipper/clipper.cpp @@ -55,8 +55,6 @@ DEFINE_DEVICE_TYPE(CLIPPER_C100, clipper_c100_device, "clipper_c100", "C100 CLIP DEFINE_DEVICE_TYPE(CLIPPER_C300, clipper_c300_device, "clipper_c300", "C300 CLIPPER") DEFINE_DEVICE_TYPE(CLIPPER_C400, clipper_c400_device, "clipper_c400", "C400 CLIPPER") -ALLOW_SAVE_TYPE(clipper_device::fpregs); - clipper_c100_device::clipper_c100_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : clipper_device(mconfig, CLIPPER_C100, tag, owner, clock, 0) { } @@ -153,26 +151,26 @@ void clipper_device::device_start() state_add(CLIPPER_R14, "r14", m_r[14]); state_add(CLIPPER_R15, "r15", m_r[15]); - state_add(CLIPPER_F0, "f0", m_f[0].d); - state_add(CLIPPER_F1, "f1", m_f[1].d); - state_add(CLIPPER_F2, "f2", m_f[2].d); - state_add(CLIPPER_F3, "f3", m_f[3].d); - state_add(CLIPPER_F4, "f4", m_f[4].d); - state_add(CLIPPER_F5, "f5", m_f[5].d); - state_add(CLIPPER_F6, "f6", m_f[6].d); - state_add(CLIPPER_F7, "f7", m_f[7].d); + state_add(CLIPPER_F0, "f0", m_f[0]); + state_add(CLIPPER_F1, "f1", m_f[1]); + state_add(CLIPPER_F2, "f2", m_f[2]); + state_add(CLIPPER_F3, "f3", m_f[3]); + state_add(CLIPPER_F4, "f4", m_f[4]); + state_add(CLIPPER_F5, "f5", m_f[5]); + state_add(CLIPPER_F6, "f6", m_f[6]); + state_add(CLIPPER_F7, "f7", m_f[7]); // C400 has 8 additional floating point registers if (type() == CLIPPER_C400) { - state_add(CLIPPER_F8, "f8", m_f[8].d); - state_add(CLIPPER_F9, "f9", m_f[9].d); - state_add(CLIPPER_F10, "f10", m_f[10].d); - state_add(CLIPPER_F11, "f11", m_f[11].d); - state_add(CLIPPER_F12, "f12", m_f[12].d); - state_add(CLIPPER_F13, "f13", m_f[13].d); - state_add(CLIPPER_F14, "f14", m_f[14].d); - state_add(CLIPPER_F15, "f15", m_f[15].d); + state_add(CLIPPER_F8, "f8", m_f[8]); + state_add(CLIPPER_F9, "f9", m_f[9]); + state_add(CLIPPER_F10, "f10", m_f[10]); + state_add(CLIPPER_F11, "f11", m_f[11]); + state_add(CLIPPER_F12, "f12", m_f[12]); + state_add(CLIPPER_F13, "f13", m_f[13]); + state_add(CLIPPER_F14, "f14", m_f[14]); + state_add(CLIPPER_F15, "f15", m_f[15]); } } @@ -484,125 +482,89 @@ int clipper_device::execute_instruction () case 0x20: // adds: add single floating - m_fp_pc = m_pc; - m_fp_dst = m_f[R2].s; - - m_f[R2].s = float32_add(m_f[R2].s, m_f[R1].s); - m_ssw |= SSW_FRD; + set_fp32(R2, float32_add(get_fp32(R2), get_fp32(R1))); // TRAPS: F_IVUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x21: - // subs: subtract single floating (exception state not documented) - m_fp_pc = m_pc; - m_fp_dst = m_f[R2].s; - - m_f[R2].s = float32_sub(m_f[R2].s, m_f[R1].s); - m_ssw |= SSW_FRD; + // subs: subtract single floating + set_fp32(R2, float32_sub(get_fp32(R2), get_fp32(R1))); // TRAPS: F_IVUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x22: // addd: add double floating - m_fp_pc = m_pc; - m_fp_dst = m_f[R2].d; - - m_f[R2].d = float64_add(m_f[R2].d, m_f[R1].d); - m_ssw |= SSW_FRD; + set_fp64(R2, float64_add(get_fp64(R2), get_fp64(R1))); // TRAPS: F_IVUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x23: - // subd: subtract double floating (exception state not documented) - m_fp_pc = m_pc; - m_fp_dst = m_f[R2].d; - - m_f[R2].d = float64_sub(m_f[R2].d, m_f[R1].d); - m_ssw |= SSW_FRD; + // subd: subtract double floating + set_fp64(R2, float64_sub(get_fp64(R2), get_fp64(R1))); // TRAPS: F_IVUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x24: // movs: move single floating - m_f[R2].s = m_f[R1].s; - m_ssw |= SSW_FRD; + set_fp32(R2, get_fp32(R1)); break; case 0x25: // cmps: compare single floating - FLAGS(0, 0, float32_eq(m_f[R2].s, m_f[R1].s), float32_lt(m_f[R2].s, m_f[R1].s)) + FLAGS(0, 0, float32_eq(get_fp32(R2), get_fp32(R1)), float32_lt(get_fp32(R2), get_fp32(R1))) if (float_exception_flags & float_flag_invalid) m_psw |= PSW_Z | PSW_N; float_exception_flags &= (0); break; case 0x26: // movd: move double floating - m_f[R2].d = m_f[R1].d; - m_ssw |= SSW_FRD; + set_fp64(R2, get_fp64(R1)); break; case 0x27: // cmpd: compare double floating - FLAGS(0, 0, float64_eq(m_f[R2].d, m_f[R1].d), float64_lt(m_f[R2].d, m_f[R1].d)) + FLAGS(0, 0, float64_eq(get_fp64(R2), get_fp64(R1)), float64_lt(get_fp64(R2), get_fp64(R1))) if (float_exception_flags & float_flag_invalid) m_psw |= PSW_Z | PSW_N; float_exception_flags &= (0); break; case 0x28: // muls: multiply single floating - m_fp_pc = m_pc; - m_fp_dst = m_f[R2].s; - - m_f[R2].s = float32_mul(m_f[R2].s, m_f[R1].s); - m_ssw |= SSW_FRD; + set_fp32(R2, float32_mul(get_fp32(R2), get_fp32(R1))); // TRAPS: F_IVUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x29: // divs: divide single floating - m_fp_pc = m_pc; - m_fp_dst = m_f[R2].s; - - m_f[R2].s = float32_div(m_f[R2].s, m_f[R1].s); - m_ssw |= SSW_FRD; + set_fp32(R2, float32_div(get_fp32(R2), get_fp32(R1))); // TRAPS: F_IVDUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_divbyzero | float_flag_underflow | float_flag_inexact); break; case 0x2a: // muld: multiply double floating - m_fp_pc = m_pc; - m_fp_dst = m_f[R2].d; - - m_f[R2].d = float64_mul(m_f[R2].d, m_f[R1].d); - m_ssw |= SSW_FRD; + set_fp64(R2, float64_mul(get_fp64(R2), get_fp64(R1))); // TRAPS: F_IVUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x2b: // divd: divide double floating - m_fp_pc = m_pc; - m_fp_dst = m_f[R2].d; - - m_f[R2].d = float64_div(m_f[R2].d, m_f[R1].d); - m_ssw |= SSW_FRD; + set_fp64(R2, float64_div(get_fp64(R2), get_fp64(R1))); // TRAPS: F_IVDUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_divbyzero | float_flag_underflow | float_flag_inexact); break; case 0x2c: // movsw: move single floating to word - m_r[R2] = m_f[R1].s; + m_r[R2] = get_fp32(R1); break; case 0x2d: // movws: move word to single floating - m_f[R2].s = m_r[R1]; - m_ssw |= SSW_FRD; + set_fp32(R2, m_r[R1]); break; case 0x2e: // movdl: move double floating to longword - ((u64 *)m_r)[R2 >> 1] = m_f[R1].d; + ((u64 *)m_r)[R2 >> 1] = get_fp64(R1); break; case 0x2f: // movld: move longword to double floating - m_f[R2].d = ((u64 *)m_r)[R1 >> 1]; - m_ssw |= SSW_FRD; + set_fp64(R2, ((u64 *)m_r)[R1 >> 1]); break; case 0x30: // shaw: shift arithmetic word @@ -821,15 +783,13 @@ int clipper_device::execute_instruction () case 0x64: case 0x65: // loads: load single floating - m_f[R2].s = m_data->read_dword(m_info.address); - m_ssw |= SSW_FRD; + set_fp32(R2, m_data->read_dword(m_info.address)); // TRAPS: C,U,A,P,R,I break; case 0x66: case 0x67: // loadd: load double floating - m_f[R2].d = m_data->read_qword(m_info.address); - m_ssw |= SSW_FRD; + set_fp64(R2, m_data->read_qword(m_info.address)); // TRAPS: C,U,A,P,R,I break; case 0x68: @@ -872,13 +832,13 @@ int clipper_device::execute_instruction () case 0x74: case 0x75: // stors: store single floating - m_data->write_dword(m_info.address, m_f[R2].s); + m_data->write_dword(m_info.address, get_fp32(R2)); // TRAPS: A,P,W,I break; case 0x76: case 0x77: // stord: store double floating - m_data->write_qword(m_info.address, m_f[R2].d); + m_data->write_qword(m_info.address, get_fp64(R2)); // TRAPS: A,P,W,I break; case 0x78: @@ -1222,7 +1182,7 @@ int clipper_device::execute_instruction () // store fi at sp - 8 * (8 - i) for (int i = R2; i < 8; i++) - m_data->write_qword(m_r[15] - 8 * (8 - i), m_f[i].d); + m_data->write_qword(m_r[15] - 8 * (8 - i), get_fp64(i)); // decrement sp after push to allow restart on exceptions m_r[15] -= 8 * (8 - R2); @@ -1234,8 +1194,7 @@ int clipper_device::execute_instruction () // load fi from sp + 8 * (i - N) for (int i = R2; i < 8; i++) - m_f[i].d = m_data->read_qword(m_r[15] + 8 * (i - R2)); - m_ssw |= SSW_FRD; + set_fp64(i, m_data->read_qword(m_r[15] + 8 * (i - R2))); // increment sp after pop to allow restart on exceptions m_r[15] += 8 * (8 - R2); @@ -1245,7 +1204,7 @@ int clipper_device::execute_instruction () // cnvsw: convert single floating to word m_fp_pc = m_pc; - m_r[m_info.macro & 0xf] = float32_to_int32(m_f[(m_info.macro >> 4) & 0xf].s); + m_r[m_info.macro & 0xf] = float32_to_int32(get_fp32((m_info.macro >> 4) & 0xf)); // TRAPS: F_IX float_exception_flags &= (float_flag_invalid | float_flag_inexact); break; @@ -1253,11 +1212,11 @@ int clipper_device::execute_instruction () // cnvrsw: convert rounding single floating to word (non-IEEE +0.5/-0.5 rounding) m_fp_pc = m_pc; - if (float32_lt(m_f[(m_info.macro >> 4) & 0xf].s, 0)) - m_r[m_info.macro & 0xf] = float32_to_int32_round_to_zero(float32_sub(m_f[(m_info.macro >> 4) & 0xf].s, + if (float32_lt(get_fp32((m_info.macro >> 4) & 0xf), 0)) + m_r[m_info.macro & 0xf] = float32_to_int32_round_to_zero(float32_sub(get_fp32((m_info.macro >> 4) & 0xf), float32_div(int32_to_float32(1), int32_to_float32(2)))); else - m_r[m_info.macro & 0xf] = float32_to_int32_round_to_zero(float32_add(m_f[(m_info.macro >> 4) & 0xf].s, + m_r[m_info.macro & 0xf] = float32_to_int32_round_to_zero(float32_add(get_fp32((m_info.macro >> 4) & 0xf), float32_div(int32_to_float32(1), int32_to_float32(2)))); // TRAPS: F_IX float_exception_flags &= (float_flag_invalid | float_flag_inexact); @@ -1266,14 +1225,13 @@ int clipper_device::execute_instruction () // cnvtsw: convert truncating single floating to word m_fp_pc = m_pc; - m_r[m_info.macro & 0xf] = float32_to_int32_round_to_zero(m_f[(m_info.macro >> 4) & 0xf].s); + m_r[m_info.macro & 0xf] = float32_to_int32_round_to_zero(get_fp32((m_info.macro >> 4) & 0xf)); // TRAPS: F_IX float_exception_flags &= (float_flag_invalid | float_flag_inexact); break; case 0x33: // cnvws: convert word to single floating - m_f[m_info.macro & 0xf].s = int32_to_float32(m_r[(m_info.macro >> 4) & 0xf]); - m_ssw |= SSW_FRD; + set_fp32(m_info.macro & 0xf, int32_to_float32(m_r[(m_info.macro >> 4) & 0xf])); // TRAPS: F_X float_exception_flags &= (float_flag_inexact); break; @@ -1281,7 +1239,7 @@ int clipper_device::execute_instruction () // cnvdw: convert double floating to word m_fp_pc = m_pc; - m_r[m_info.macro & 0xf] = float64_to_int32(m_f[(m_info.macro >> 4) & 0xf].d); + m_r[m_info.macro & 0xf] = float64_to_int32(get_fp64((m_info.macro >> 4) & 0xf)); // TRAPS: F_IX float_exception_flags &= (float_flag_invalid | float_flag_inexact); break; @@ -1289,11 +1247,11 @@ int clipper_device::execute_instruction () // cnvrdw: convert rounding double floating to word (non-IEEE +0.5/-0.5 rounding) m_fp_pc = m_pc; - if (float64_lt(m_f[(m_info.macro >> 4) & 0xf].d, 0)) - m_r[m_info.macro & 0xf] = float64_to_int32_round_to_zero(float64_sub(m_f[(m_info.macro >> 4) & 0xf].d, + if (float64_lt(get_fp64((m_info.macro >> 4) & 0xf), 0)) + m_r[m_info.macro & 0xf] = float64_to_int32_round_to_zero(float64_sub(get_fp64((m_info.macro >> 4) & 0xf), float64_div(int32_to_float64(1), int32_to_float64(2)))); else - m_r[m_info.macro & 0xf] = float64_to_int32_round_to_zero(float64_add(m_f[(m_info.macro >> 4) & 0xf].d, + m_r[m_info.macro & 0xf] = float64_to_int32_round_to_zero(float64_add(get_fp64((m_info.macro >> 4) & 0xf), float64_div(int32_to_float64(1), int32_to_float64(2)))); // TRAPS: F_IX float_exception_flags &= (float_flag_invalid | float_flag_inexact); @@ -1302,43 +1260,35 @@ int clipper_device::execute_instruction () // cnvtdw: convert truncating double floating to word m_fp_pc = m_pc; - m_r[m_info.macro & 0xf] = float64_to_int32_round_to_zero(m_f[(m_info.macro >> 4) & 0xf].d); + m_r[m_info.macro & 0xf] = float64_to_int32_round_to_zero(get_fp64((m_info.macro >> 4) & 0xf)); // TRAPS: F_IX float_exception_flags &= (float_flag_invalid | float_flag_inexact); break; case 0x37: // cnvwd: convert word to double floating - m_f[m_info.macro & 0xf].d = int32_to_float64(m_r[(m_info.macro >> 4) & 0xf]); - m_ssw |= SSW_FRD; + set_fp64(m_info.macro & 0xf, int32_to_float64(m_r[(m_info.macro >> 4) & 0xf])); float_exception_flags &= (0); break; case 0x38: // cnvsd: convert single to double floating - m_f[m_info.macro & 0xf].d = float32_to_float64(m_f[(m_info.macro >> 4) & 0xf].s); - m_ssw |= SSW_FRD; + set_fp64(m_info.macro & 0xf, float32_to_float64(get_fp32((m_info.macro >> 4) & 0xf))); // TRAPS: F_I float_exception_flags &= (float_flag_invalid); break; case 0x39: // cnvds: convert double to single floating - m_fp_pc = m_pc; - m_fp_dst = m_f[m_info.macro & 0xf].s; - - m_f[m_info.macro & 0xf].s = float64_to_float32(m_f[(m_info.macro >> 4) & 0xf].d); - m_ssw |= SSW_FRD; + set_fp32(m_info.macro & 0xf, float64_to_float32(get_fp64((m_info.macro >> 4) & 0xf))); // TRAPS: F_IVUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x3a: // negs: negate single floating - m_f[m_info.macro & 0xf].s = float32_mul(m_f[(m_info.macro >> 4) & 0xf].s, int32_to_float32(-1)); - m_ssw |= SSW_FRD; + set_fp32(m_info.macro & 0xf, float32_mul(get_fp32((m_info.macro >> 4) & 0xf), int32_to_float32(-1))); float_exception_flags &= (0); break; case 0x3b: // negd: negate double floating - m_f[m_info.macro & 0xf].d = float64_mul(m_f[(m_info.macro >> 4) & 0xf].d, int32_to_float64(-1)); - m_ssw |= SSW_FRD; + set_fp64(m_info.macro & 0xf, float64_mul(get_fp64((m_info.macro >> 4) & 0xf), int32_to_float64(-1))); float_exception_flags &= (0); break; case 0x3c: @@ -1352,27 +1302,19 @@ int clipper_device::execute_instruction () * correct exception flags are set. */ // scalbs: scale by, single floating - m_fp_pc = m_pc; - m_fp_dst = m_f[m_info.macro & 0xf].s; - - m_f[m_info.macro & 0xf].s = float32_mul(m_f[m_info.macro & 0xf].s, + set_fp32(m_info.macro & 0xf, float32_mul(get_fp32(m_info.macro & 0xf), (((s32)m_r[(m_info.macro >> 4) & 0xf] > -127 && (s32)m_r[(m_info.macro >> 4) & 0xf] < 128) ? (float32)(((s32)m_r[(m_info.macro >> 4) & 0xf] + 127) << 23) - : (float32)~u32(0))); - m_ssw |= SSW_FRD; + : (float32)~u32(0)))); // TRAPS: F_IVUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; case 0x3d: // scalbd: scale by, double floating - m_fp_pc = m_pc; - m_fp_dst = m_f[m_info.macro & 0xf].d; - - m_f[m_info.macro & 0xf].d = float64_mul(m_f[m_info.macro & 0xf].d, + set_fp64(m_info.macro & 0xf, float64_mul(get_fp64(m_info.macro & 0xf), ((s32)m_r[(m_info.macro >> 4) & 0xf] > -1023 && (s32)m_r[(m_info.macro >> 4) & 0xf] < 1024) ? (float64)((u64)((s32)m_r[(m_info.macro >> 4) & 0xf] + 1023) << 52) - : (float64)~u64(0)); - m_ssw |= SSW_FRD; + : (float64)~u64(0))); // TRAPS: F_IVUX float_exception_flags &= (float_flag_invalid | float_flag_overflow | float_flag_underflow | float_flag_inexact); break; @@ -1384,7 +1326,7 @@ int clipper_device::execute_instruction () case 0x3f: // loadfs: load floating status m_r[(m_info.macro >> 4) & 0xf] = m_fp_pc; - m_f[m_info.macro & 0xf].d = m_fp_dst; + m_f[m_info.macro & 0xf] = m_fp_dst; m_ssw |= SSW_FRD; break; @@ -1684,6 +1626,32 @@ void clipper_device::fp_exception() m_pc = intrap(vector, m_pc); } +inline void clipper_device::set_fp32(const u8 reg, const float32 data) +{ + // save floating exception state + m_fp_pc = m_pc; + m_fp_dst = m_f[reg & 0xf]; + + // assign data + m_f[reg & 0xf] = data; + + // set floating dirty flag + m_ssw |= SSW_FRD; +} + +inline void clipper_device::set_fp64(const u8 reg, const float64 data) +{ + // save floating exception state + m_fp_pc = m_pc; + m_fp_dst = m_f[reg & 0xf]; + + // assign data + m_f[reg & 0xf] = data; + + // set floating dirty flag + m_ssw |= SSW_FRD; +} + offs_t clipper_device::disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) { return CPU_DISASSEMBLE_NAME(clipper)(this, stream, pc, oprom, opram, options); diff --git a/src/devices/cpu/clipper/clipper.h b/src/devices/cpu/clipper/clipper.h index 4ecb3926d25..6a1d5dc0ba2 100644 --- a/src/devices/cpu/clipper/clipper.h +++ b/src/devices/cpu/clipper/clipper.h @@ -227,6 +227,11 @@ protected: void set_ssw(u32 data) { m_ssw = (m_ssw & SSW(ID)) | (data & ~SSW(ID)); } + inline float32 get_fp32(const u8 reg) const { return m_f[reg & 0xf]; }; + inline float64 get_fp64(const u8 reg) const { return m_f[reg & 0xf]; }; + inline void set_fp32(const u8 reg, const float32 data); + inline void set_fp64(const u8 reg, const float64 data); + // core registers u32 m_pc; u32 m_psw; @@ -237,13 +242,8 @@ protected: u32 m_ru[16]; // user registers u32 m_rs[16]; // supervisor registers - // floating registers - union fpregs - { - float64 d; // double precision floating point - float32 s; // single precision floating point - } - m_f[16]; + // floating point registers + u64 m_f[16]; u32 m_fp_pc; // address of floating point instruction causing exception u64 m_fp_dst; // original value of destination register during fp exception -- cgit v1.2.3