summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author R. Belmont <rb6502@users.noreply.github.com>2017-11-17 09:15:00 -0500
committer GitHub <noreply@github.com>2017-11-17 09:15:00 -0500
commite8e9cbe6c2b5a73053bb327405c41cb42717e289 (patch)
treebd8da767b74229330de606620e19c078e2f5da9c
parentc5028af1e5e1784e5b892c9042a2d2daa84fc243 (diff)
parent3873ba65ad3728038115de7ddd476fc971644035 (diff)
Merge pull request #2815 from pmackinlay/interpro
interpro: clipper floating point improvements and use new 28f010 flash memory
-rw-r--r--src/devices/cpu/clipper/clipper.cpp454
-rw-r--r--src/devices/cpu/clipper/clipper.h54
-rw-r--r--src/mame/drivers/interpro.cpp54
-rw-r--r--src/mame/includes/interpro.h30
4 files changed, 399 insertions, 193 deletions
diff --git a/src/devices/cpu/clipper/clipper.cpp b/src/devices/cpu/clipper/clipper.cpp
index c2d057d8d35..d7498beb6f2 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
@@ -119,6 +118,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));
@@ -181,14 +182,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 +249,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 +329,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 +345,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 +356,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 +437,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 +482,242 @@ int clipper_device::execute_instruction ()
case 0x20:
// adds: add single floating
- *((float *)&m_f[R2]) += *((float *)&m_f[R1]);
+ 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
- *((float *)&m_f[R2]) -= *((float *)&m_f[R1]);
+ 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_f[R2] += m_f[R1];
+ 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
- m_f[R2] -= m_f[R1];
+ 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
- *((float *)&m_f[R2]) = *((float *)&m_f[R1]);
+ set_fp32(R2, get_fp32(R1));
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(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] = m_f[R1];
+ set_fp64(R2, get_fp64(R1));
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(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
- *((float *)&m_f[R2]) *= *((float *)&m_f[R1]);
+ 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
- *((float *)&m_f[R2]) /= *((float *)&m_f[R1]);
+ 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_f[R2] *= m_f[R1];
+ 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_f[R2] /= m_f[R1];
+ 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] = *((s32 *)&m_f[R1]);
+ m_r[R2] = get_fp32(R1);
break;
case 0x2d:
// movws: move word to single floating
- *((s32 *)&m_f[R2]) = m_r[R1];
+ set_fp32(R2, m_r[R1]);
break;
case 0x2e:
// movdl: move double floating to longword
- ((double *)m_r)[R2 >> 1] = m_f[R1];
+ ((u64 *)m_r)[R2 >> 1] = get_fp64(R1);
break;
case 0x2f:
// movld: move longword to double floating
- m_f[R2] = ((double *)m_r)[R1 >> 1];
+ set_fp64(R2, ((u64 *)m_r)[R1 >> 1]);
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 +783,13 @@ int clipper_device::execute_instruction ()
case 0x64:
case 0x65:
// loads: load single floating
- ((u64 *)&m_f)[R2] = m_data->read_dword(m_info.address);
+ 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
- ((u64 *)&m_f)[R2] = m_data->read_qword(m_info.address);
+ set_fp64(R2, m_data->read_qword(m_info.address));
// TRAPS: C,U,A,P,R,I
break;
case 0x68:
@@ -808,13 +832,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, get_fp32(R2));
// 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, get_fp64(R2));
// TRAPS: A,P,W,I
break;
case 0x78:
@@ -835,7 +859,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 +867,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 +894,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 +930,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 +945,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 +961,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 +974,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 +986,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 +995,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 +1005,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 +1017,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 +1025,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 +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]);
+ 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);
@@ -1170,71 +1194,148 @@ 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));
+ 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);
// 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(get_fp32((m_info.macro >> 4) & 0xf));
+ // 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(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(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);
+ 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(get_fp32((m_info.macro >> 4) & 0xf));
// TRAPS: F_IX
+ float_exception_flags &= (float_flag_invalid | float_flag_inexact);
+ break;
case 0x33:
- // cnvws
+ // cnvws: convert word to single floating
+ 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;
case 0x34:
- // cnvdw
+ // cnvdw: convert double floating to word
+ m_fp_pc = m_pc;
+
+ 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;
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(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(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);
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(get_fp64((m_info.macro >> 4) & 0xf));
// 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
+ set_fp64(m_info.macro & 0xf, int32_to_float64(m_r[(m_info.macro >> 4) & 0xf]));
+ float_exception_flags &= (0);
break;
-#ifdef UNIMPLEMENTED
case 0x38:
- // cnvsd
+ // cnvsd: convert single to double floating
+ 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
+ // cnvds: convert double to single floating
+ 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
+ // negs: negate single floating
+ 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:
- // negds
+ // negd: negate double floating
+ 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:
- // 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
+ 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))));
// 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
+ 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)));
// 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] = 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 +1347,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 +1386,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 +1434,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 +1462,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 +1470,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 +1500,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 +1568,90 @@ 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);
+}
+
+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 27624b4e05a..6a1d5dc0ba2 100644
--- a/src/devices/cpu/clipper/clipper.h
+++ b/src/devices/cpu/clipper/clipper.h
@@ -7,6 +7,8 @@
#pragma once
#include <limits.h>
+#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,24 +221,32 @@ 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)); }
+ 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;
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];
+ // 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
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)
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<interpro_eeprom_device> m_eeprom;
+ required_device<intel_28f010_device> m_flash_lo;
+ required_device<intel_28f010_device> m_flash_hi;
virtual DECLARE_WRITE16_MEMBER(sreg_ctrl2_w) override;
};