diff --git a/hash/interpro.xml b/hash/interpro.xml new file mode 100644 index 00000000000..08a12d721a1 --- /dev/null +++ b/hash/interpro.xml @@ -0,0 +1,248 @@ + + + + + + + + Intergraph System Software + 1999 + Intergraph + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Rebuild Floppies + 1998 + Intergraph + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Diagnostic Floppies + 1994 + Intergraph + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/devices/cpu/clipper/clipper.cpp b/src/devices/cpu/clipper/clipper.cpp index d9812b4a987..33418a764df 100644 --- a/src/devices/cpu/clipper/clipper.cpp +++ b/src/devices/cpu/clipper/clipper.cpp @@ -8,7 +8,7 @@ * * TODO: * - save/restore state - * - unimplemented C400 instructions + * - unimplemented C400 instructions (cdb, cnvx[ds]w, loadts, waitd) * - correct boot logic * - condition codes for multiply instructions * - instruction timing @@ -57,25 +57,29 @@ DEFINE_DEVICE_TYPE(CLIPPER_C400, clipper_c400_device, "clipper_c400", "C400 CLIP 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, ENDIANNESS_LITTLE, 0) + , m_icammu(*this, "^cammu_i") + , m_dcammu(*this, "^cammu_d") { } clipper_c300_device::clipper_c300_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : clipper_device(mconfig, CLIPPER_C300, tag, owner, clock, ENDIANNESS_LITTLE, 0) + , m_icammu(*this, "^cammu_i") + , m_dcammu(*this, "^cammu_d") { } clipper_c400_device::clipper_c400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : clipper_device(mconfig, CLIPPER_C400, tag, owner, clock, ENDIANNESS_LITTLE, SSW_ID_C400R4) + , m_cammu(*this, "^cammu") { } clipper_device::clipper_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, const endianness_t endianness, const u32 cpuid) : cpu_device(mconfig, type, tag, owner, clock) - , m_insn_config("insn", endianness, 32, 32, 0) - , m_data_config("data", endianness, 32, 32, 0) - , m_insn(nullptr) - , m_data(nullptr) + , m_main_config("main", endianness, 32, 32, 0) + , m_io_config("io", endianness, 32, 32, 0) + , m_boot_config("boot", endianness, 32, 32, 0) , m_icount(0) , m_psw(endianness == ENDIANNESS_BIG ? PSW_BIG : 0) , m_ssw(cpuid) @@ -110,9 +114,12 @@ inline u64 rotr64(u64 x, u8 shift) void clipper_device::device_start() { - // get our address spaces - m_insn = &space(AS_PROGRAM); - m_data = &space(AS_DATA); + // map spaces to system tags + std::vector spaces = { &space(0), &space(0), &space(0), &space(0), &space(1), &space(2), nullptr, nullptr }; + + // configure the cammu address spaces + get_icammu().set_spaces(spaces); + get_dcammu().set_spaces(spaces); // set our instruction counter m_icountptr = &m_icount; @@ -156,6 +163,8 @@ void clipper_device::device_reset() * ssw: EI, TP, M, U, K, KU, UU, P cleared, ID set from hardware, others undefined */ + m_wait = false; + // clear the psw and ssw set_psw(0); set_ssw(0); @@ -205,11 +214,15 @@ void clipper_device::execute_run() // acknowledge interrupt standard_irq_callback(INPUT_LINE_IRQ0); - LOGMASKED(LOG_EXCEPTION, "transferring control to ivec 0x%02x\n", m_ivec); m_ip = intrap(EXCEPTION_INTERRUPT_BASE + m_ivec * 8, m_ip); + + LOGMASKED(LOG_EXCEPTION, "transferring control to ivec 0x%02x address 0x%08x\n", m_ivec, m_ip); } } + if (m_wait) + m_icount = 0; + while (m_icount > 0) { debugger_instruction_hook(this, m_ip); @@ -282,6 +295,9 @@ void clipper_device::execute_run() void clipper_device::execute_set_input(int inputnum, int state) { + if (state) + m_wait = false; + switch (inputnum) { case INPUT_LINE_IRQ0: @@ -294,15 +310,12 @@ void clipper_device::execute_set_input(int inputnum, int state) } } -/* - * The CLIPPER has a true Harvard architecture. In the InterPro, these are tied back together - * again by the MMU, which then directs the access to one of 3 address spaces: main, i/o or boot. - */ device_memory_interface::space_config_vector clipper_device::memory_space_config() const { return space_config_vector { - std::make_pair(AS_PROGRAM, &m_insn_config), - std::make_pair(AS_DATA, &m_data_config) + std::make_pair(0, &m_main_config), + std::make_pair(1, &m_io_config), + std::make_pair(2, &m_boot_config) }; } @@ -324,17 +337,15 @@ WRITE16_MEMBER(clipper_device::set_exception) */ bool clipper_device::decode_instruction() { - // fetch instruction word - u16 insn = m_insn->read_word(m_ip + 0); - if (m_exception) + // fetch and decode the primary parcel + if (!get_icammu().fetch(m_ssw, m_ip + 0, [this](u16 insn) { + m_info.opcode = insn >> 8; + m_info.subopcode = insn & 0xff; + m_info.r1 = (insn & 0x00f0) >> 4; + m_info.r2 = insn & 0x000f; + })) return false; - // decode the primary parcel - m_info.opcode = insn >> 8; - m_info.subopcode = insn & 0xff; - m_info.r1 = (insn & 0x00f0) >> 4; - m_info.r2 = insn & 0x000f; - // initialise the other fields m_info.imm = 0; m_info.macro = 0; @@ -343,112 +354,93 @@ bool clipper_device::decode_instruction() // default instruction size is 2 bytes int size = 2; - if ((insn & 0xf800) == 0x3800) + if ((m_info.opcode & 0xf8) == 0x38) { - // instruction has a 16 bit immediate operand - // fetch 16 bit immediate and sign extend - m_info.imm = (s16)m_insn->read_word(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](s32 v) { m_info.imm = v; })) return false; size = 4; } - else if ((insn & 0xd300) == 0x8300) + else if ((m_info.opcode & 0xd3) == 0x83) { // instruction has an immediate operand, either 16 or 32 bit - if (insn & 0x0080) + if (m_info.subopcode & 0x80) { // fetch 16 bit immediate and sign extend - m_info.imm = (s16)m_insn->read_word(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](s32 v) { m_info.imm = v; })) return false; size = 4; } else { // fetch 32 bit immediate - m_info.imm = m_insn->read_dword_unaligned(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](u32 v) { m_info.imm = v; })) return false; size = 6; } } - else if ((insn & 0xc000) == 0x4000) + else if ((m_info.opcode & 0xc0) == 0x40) { // instructions with addresses - if (insn & 0x0100) + if (m_info.opcode & 0x01) { // instructions with complex modes - u16 temp; - - switch (insn & 0x00f0) + switch (m_info.subopcode & 0xf0) { case ADDR_MODE_PC32: - m_info.address = m_ip + m_insn->read_dword_unaligned(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](u32 v) { m_info.address = m_ip + v; })) return false; size = 6; break; case ADDR_MODE_ABS32: - m_info.address = m_insn->read_dword_unaligned(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](u32 v) { m_info.address = v; })) return false; size = 6; break; case ADDR_MODE_REL32: - m_info.r2 = m_insn->read_word(m_ip + 2) & 0xf; - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](u16 v) { m_info.r2 = v & 0xf; })) return false; - m_info.address = m_r[insn & 0xf] + m_insn->read_dword_unaligned(m_ip + 4); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 4, [this](u32 v) { m_info.address = m_r[m_info.subopcode & 0xf] + v; })) return false; size = 8; break; case ADDR_MODE_PC16: - m_info.address = m_ip + (s16)m_insn->read_word(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](s16 v) { m_info.address = m_ip + v; })) return false; size = 4; break; case ADDR_MODE_REL12: - temp = m_insn->read_word(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](s16 v) { + m_info.r2 = v & 0xf; + m_info.address = m_r[m_info.subopcode & 0xf] + (v >> 4); })) return false; - - m_info.r2 = temp & 0xf; - m_info.address = m_r[insn & 0xf] + ((s16)temp >> 4); size = 4; break; case ADDR_MODE_ABS16: - m_info.address = (s16)m_insn->read_word(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](s32 v) { m_info.address = v; })) return false; size = 4; break; case ADDR_MODE_PCX: - temp = m_insn->read_word(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](u16 v) { + m_info.r2 = v & 0xf; + m_info.address = m_ip + m_r[(v >> 4) & 0xf]; })) return false; - - m_info.r2 = temp & 0xf; - m_info.address = m_ip + m_r[(temp >> 4) & 0xf]; size = 4; break; case ADDR_MODE_RELX: - temp = m_insn->read_word(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](u16 v) { + m_info.r2 = v & 0xf; + m_info.address = m_r[m_info.subopcode & 0xf] + m_r[(v >> 4) & 0xf]; })) return false; - - m_info.r2 = temp & 0xf; - m_info.address = m_r[insn & 0xf] + m_r[(temp >> 4) & 0xf]; size = 4; break; @@ -461,11 +453,10 @@ bool clipper_device::decode_instruction() // relative addressing mode m_info.address = m_r[m_info.r1]; } - else if ((insn & 0xfd00) == 0xb400) + else if ((m_info.opcode & 0xfd) == 0xb4) { // macro instructions - m_info.macro = m_insn->read_word(m_ip + 2); - if (m_exception) + if (!get_icammu().fetch(m_ssw, m_ip + 2, [this](u16 v) { m_info.macro = v; })) return false; size = 4; } @@ -479,9 +470,6 @@ bool clipper_device::decode_instruction() void clipper_device::execute_instruction() { - // memory fetch temporary - u64 temp; - switch (m_info.opcode) { case 0x00: // noop @@ -511,27 +499,25 @@ void clipper_device::execute_instruction() break; case 0x13: // ret: return from subroutine - temp = m_data->read_dword(m_r[R2]); - if (!m_exception) - { - m_ip = temp; + get_dcammu().load(m_ssw, m_r[R2], [this](u32 v) { + m_ip = v; m_r[R2] += 4; - } + }); // TRAPS: C,U,A,P,R break; case 0x14: // pushw: push word - m_data->write_dword(m_r[R1] - 4, m_r[R2]); - m_r[R1] -= 4; + if (get_dcammu().store(m_ssw, m_r[R1] - 4, m_r[R2])) + m_r[R1] -= 4; // TRAPS: A,P,W break; case 0x16: // popw: pop word - m_r[R1] += 4; - temp = m_data->read_dword(m_r[R1] - 4); - if (!m_exception) - m_r[R2] = temp; + get_dcammu().load(m_ssw, m_r[R1], [this](u32 v) { + m_r[R1] += 4; + m_r[R2] = v; + }); // TRAPS: C,U,A,P,R break; @@ -774,8 +760,7 @@ void clipper_device::execute_instruction() case 0x44: case 0x45: // call: call subroutine - m_data->write_dword(m_r[R2] - 4, m_ip); - if (!m_exception) + if (get_dcammu().store(m_ssw, m_r[R2] - 4, m_ip)) { m_ip = m_info.address; m_r[R2] -= 4; @@ -818,9 +803,7 @@ void clipper_device::execute_instruction() case 0x60: case 0x61: // loadw: load word - temp = m_data->read_dword(m_info.address); - if (!m_exception) - m_r[R2] = temp; + get_dcammu().load(m_ssw, m_info.address, [this](u32 v) { m_r[R2] = v; }); // TRAPS: C,U,A,P,R,I break; case 0x62: @@ -832,92 +815,77 @@ void clipper_device::execute_instruction() case 0x64: case 0x65: // loads: load single floating - temp = m_data->read_dword(m_info.address); - if (!m_exception) - set_fp(R2, (float32)temp, F_NONE); + get_dcammu().load(m_ssw, m_info.address, [this](float32 v) { set_fp(R2, v, F_NONE); }); // TRAPS: C,U,A,P,R,I break; case 0x66: case 0x67: // loadd: load double floating - temp = m_data->read_qword(m_info.address); - if (!m_exception) - set_fp(R2, (float64)temp, F_NONE); + get_dcammu().load(m_ssw, m_info.address, [this](float64 v) { set_fp(R2, float64(v), F_NONE); }); // TRAPS: C,U,A,P,R,I break; case 0x68: case 0x69: // loadb: load byte - temp = s64(s8(m_data->read_byte(m_info.address))); - if (!m_exception) - m_r[R2] = temp; + get_dcammu().load(m_ssw, m_info.address, [this](s32 v) { m_r[R2] = v; }); // TRAPS: C,U,A,P,R,I break; case 0x6a: case 0x6b: // loadbu: load byte unsigned - temp = m_data->read_byte(m_info.address); - if (!m_exception) - m_r[R2] = temp; + get_dcammu().load(m_ssw, m_info.address, [this](u32 v) { m_r[R2] = v; }); // TRAPS: C,U,A,P,R,I break; case 0x6c: case 0x6d: // loadh: load halfword - temp = s64(s16(m_data->read_word(m_info.address))); - if (!m_exception) - m_r[R2] = temp; + get_dcammu().load(m_ssw, m_info.address, [this](s32 v) { m_r[R2] = v; }); // TRAPS: C,U,A,P,R,I break; case 0x6e: case 0x6f: // loadhu: load halfword unsigned - temp = m_data->read_word(m_info.address); - if (!m_exception) - m_r[R2] = temp; + get_dcammu().load(m_ssw, m_info.address, [this](u32 v) { m_r[R2] = v; }); // TRAPS: C,U,A,P,R,I break; case 0x70: case 0x71: // storw: store word - m_data->write_dword(m_info.address, m_r[R2]); + get_dcammu().store(m_ssw, m_info.address, m_r[R2]); // TRAPS: A,P,W,I break; case 0x72: case 0x73: // tsts: test and set - temp = m_data->read_dword(m_info.address); - if (!m_exception) - { - m_data->write_dword(m_info.address, temp | 0x80000000U); - if (!m_exception) - m_r[R2] = temp; - } + get_dcammu().modify(m_ssw, m_info.address, [this](u32 v) { + m_r[R2] = v; + return v | 0x80000000U; + }); // TRAPS: C,U,A,P,R,W,I break; case 0x74: case 0x75: // stors: store single floating - m_data->write_dword(m_info.address, get_fp32(R2)); + get_dcammu().store(m_ssw, 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, get_fp64(R2)); + get_dcammu().store(m_ssw, m_info.address, get_fp64(R2)); // TRAPS: A,P,W,I break; case 0x78: case 0x79: // storb: store byte - m_data->write_byte(m_info.address, m_r[R2]); + get_dcammu().store(m_ssw, m_info.address, m_r[R2]); // TRAPS: A,P,W,I break; case 0x7c: case 0x7d: // storh: store halfword - m_data->write_word(m_info.address, m_r[R2]); + get_dcammu().store(m_ssw, m_info.address, m_r[R2]); // TRAPS: A,P,W,I break; @@ -1163,7 +1131,7 @@ void clipper_device::execute_instruction() // store ri at sp - 4 * (15 - i) for (int i = R2; i < 15 && !m_exception; i++) - m_data->write_dword(m_r[15] - 4 * (15 - i), m_r[i]); + get_dcammu().store(m_ssw, m_r[15] - 4 * (15 - i), m_r[i]); // decrement sp after push to allow restart on exceptions if (!m_exception) @@ -1179,11 +1147,8 @@ void clipper_device::execute_instruction() while (m_r[0]) { - const u8 byte = m_data->read_byte(m_r[1]); - if (m_exception) - break; + get_dcammu().load(m_ssw, m_r[1], [this](u8 byte) { get_dcammu().store(m_ssw, m_r[2], byte); }); - m_data->write_byte(m_r[2], byte); if (m_exception) break; @@ -1197,8 +1162,7 @@ void clipper_device::execute_instruction() // initc: initialise r0 bytes at r1 with value in r2 while (m_r[0]) { - m_data->write_byte(m_r[1], m_r[2]); - if (m_exception) + if (!get_dcammu().store(m_ssw, m_r[1], m_r[2])) break; m_r[0]--; @@ -1215,18 +1179,15 @@ void clipper_device::execute_instruction() while (m_r[0]) { - // set condition codes and abort the loop if the current byte does not match - s32 byte1 = s8(m_data->read_byte(m_r[1])); - if (m_exception) + // read and compare bytes (as signed 32 bit integers) + get_dcammu().load(m_ssw, m_r[1], [this](s32 byte1) { + get_dcammu().load(m_ssw, m_r[2], [this, byte1](s32 byte2) { + if (byte1 != byte2) + FLAGS(C_SUB(byte2, byte1), V_SUB(byte2, byte1), byte2 == byte1, byte2 < byte1); }); }); + + // abort on exception or mismatch + if (m_exception || !PSW(Z)) break; - s32 byte2 = s8(m_data->read_byte(m_r[2])); - if (m_exception) - break; - if (byte1 != byte2) - { - FLAGS(C_SUB(byte2, byte1), V_SUB(byte2, byte1), byte2 == byte1, byte2 < byte1) - break; - } m_r[0]--; m_r[1]++; @@ -1241,13 +1202,8 @@ void clipper_device::execute_instruction() // restwN..restw12: pop registers rN:r14 // load ri from sp + 4 * (i - N) - for (int i = R2; i < 15; i++) - { - temp = m_data->read_dword(m_r[15] + 4 * (i - R2)); - if (m_exception) - break; - m_r[i] = temp; - } + for (int i = R2; i < 15 && !m_exception; i++) + get_dcammu().load(m_ssw, m_r[15] + 4 * (i - R2), [this, i](u32 v) { m_r[i] = v; }); // increment sp after pop to allow restart on exceptions if (!m_exception) @@ -1261,7 +1217,7 @@ void clipper_device::execute_instruction() // store fi at sp - 8 * (8 - i) for (int i = R2; i < 8 && !m_exception; i++) - m_data->write_qword(m_r[15] - 8 * (8 - i), get_fp64(i)); + get_dcammu().store(m_ssw, m_r[15] - 8 * (8 - i), get_fp64(i)); // decrement sp after push to allow restart on exceptions if (!m_exception) @@ -1273,13 +1229,8 @@ void clipper_device::execute_instruction() // restd0..restd7: pop registers fN:f7 // load fi from sp + 8 * (i - N) - for (int i = R2; i < 8; i++) - { - temp = m_data->read_qword(m_r[15] + 8 * (i - R2)); - if (m_exception) - break; - set_fp(i, (float64)temp, F_NONE); - } + for (int i = R2; i < 8 && !m_exception; i++) + get_dcammu().load(m_ssw, m_r[15] + 8 * (i - R2), [this, i](float64 v) { set_fp(i, v, F_NONE); }); // increment sp after pop to allow restart on exceptions if (!m_exception) @@ -1438,7 +1389,7 @@ void clipper_device::execute_instruction() case 0x02: // saveur: save user registers for (int i = 0; i < 16 && !m_exception; i++) - m_data->write_dword(m_rs[(m_info.macro >> 4) & 0xf] - 4 * (i + 1), m_ru[15 - i]); + get_dcammu().store(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] - 4 * (i + 1), m_ru[15 - i]); if (!m_exception) m_rs[(m_info.macro >> 4) & 0xf] -= 64; @@ -1446,13 +1397,8 @@ void clipper_device::execute_instruction() break; case 0x03: // restur: restore user registers - for (int i = 0; i < 16; i++) - { - temp = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 4 * i); - if (m_exception) - break; - m_ru[i] = temp; - } + for (int i = 0; i < 16 && !m_exception; i++) + get_dcammu().load(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] + 4 * i, [this, i](u32 v) { m_ru[i] = v; }); if (!m_exception) m_rs[(m_info.macro >> 4) & 0xf] += 64; @@ -1465,7 +1411,7 @@ void clipper_device::execute_instruction() break; case 0x05: // wait: wait for interrupt - m_ip = m_pc; + m_wait = true; // TRAPS: S break; @@ -1486,17 +1432,16 @@ void clipper_device::execute_instruction() u32 clipper_device::reti() { + u32 new_psw = 0, new_ssw = 0, new_pc = 0; + // fetch the psw, ssw and pc from the supervisor stack - const u32 new_psw = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 0); - if (m_exception) + if (!get_dcammu().load(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] + 0, [&new_psw](u32 v) { new_psw = v; })) fatalerror("reti unrecoverable fault 0x%04x read psw address 0x%08x pc 0x%08x\n", m_exception, m_rs[(m_info.macro >> 4) & 0xf] + 0, m_pc); - const u32 new_ssw = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 4); - if (m_exception) + if (!get_dcammu().load(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] + 4, [&new_ssw](u32 v) { new_ssw = v; })) fatalerror("reti unrecoverable fault 0x%04x read ssw address 0x%08x pc 0x%08x\n", m_exception, m_rs[(m_info.macro >> 4) & 0xf] + 4, m_pc); - const u32 new_pc = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 8); - if (m_exception) + if (!get_dcammu().load(m_ssw, m_rs[(m_info.macro >> 4) & 0xf] + 8, [&new_pc](u32 v) { new_pc = v; })) fatalerror("reti unrecoverable fault 0x%04x read pc address 0x%08x pc 0x%08x\n", m_exception, m_rs[(m_info.macro >> 4) & 0xf] + 8, m_pc); LOGMASKED(LOG_EXCEPTION, "reti r%d ssp 0x%08x pc 0x%08x ssw 0x%08x psw 0x%08x new_pc 0x%08x new_ssw 0x%08x new_psw 0x%08x\n", @@ -1522,6 +1467,7 @@ u32 clipper_device::intrap(const u16 vector, const u32 old_pc) { const u32 old_ssw = m_ssw; const u32 old_psw = m_psw; + u32 new_pc = 0, new_ssw = 0; // clear ssw bits to enable supervisor memory access m_ssw &= ~(SSW_U | SSW_K | SSW_UU | SSW_KU); @@ -1530,13 +1476,10 @@ u32 clipper_device::intrap(const u16 vector, const u32 old_pc) m_exception = 0; // fetch next pc and ssw from interrupt vector - const u32 new_pc = m_data->read_dword(vector + get_evpc_offset()); - if (m_exception) - fatalerror("intrap unrecoverable fault 0x%04x read pc address 0x%08x pc 0x%08x\n", m_exception, vector + get_evpc_offset(), old_pc); - - const u32 new_ssw = m_data->read_dword(vector + get_evssw_offset()); - if (m_exception) - fatalerror("intrap unrecoverable fault 0x%04x read ssw address 0x%08x pc 0x%08x\n", m_exception, vector + get_evssw_offset(), old_pc); + if (!get_dcammu().load(m_ssw, vector + 0, [&new_pc](u32 v) { new_pc = v; })) + fatalerror("intrap unrecoverable fault 0x%04x load pc address 0x%08x pc 0x%08x\n", m_exception, vector + 0, old_pc); + if (!get_dcammu().load(m_ssw, vector + 4, [&new_ssw](u32 v) { new_ssw = v; })) + fatalerror("intrap unrecoverable fault 0x%04x load ssw address 0x%08x pc 0x%08x\n", m_exception, vector + 4, old_pc); LOGMASKED(LOG_EXCEPTION, "intrap vector 0x%04x pc 0x%08x ssp 0x%08x new_pc 0x%08x new_ssw 0x%08x\n", vector, old_pc, m_rs[15], new_pc, new_ssw); @@ -1581,18 +1524,107 @@ u32 clipper_device::intrap(const u16 vector, const u32 old_pc) } // push pc, ssw and psw onto supervisor stack - m_data->write_dword(m_rs[15] - 0x4, old_pc); - if (m_exception) - fatalerror("intrap unrecoverable fault 0x%04x write pc address 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x4, old_pc); - m_data->write_dword(m_rs[15] - 0x8, old_ssw); - if (m_exception) - fatalerror("intrap unrecoverable fault 0x%04x write ssw address 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x8, old_pc); - m_data->write_dword(m_rs[15] - 0xc, (old_psw & ~(PSW_CTS | PSW_MTS)) | source); - if (m_exception) - fatalerror("intrap unrecoverable fault 0x%04x write psw address 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0xc, old_pc); + if (!get_dcammu().store(m_ssw, m_rs[15] - 0x4, old_pc)) + fatalerror("intrap unrecoverable fault 0x%04x push pc ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x4, old_pc); + + if (!get_dcammu().store(m_ssw, m_rs[15] - 0x8, old_ssw)) + fatalerror("intrap unrecoverable fault 0x%04x push ssw ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x8, old_pc); + + if (!get_dcammu().store(m_ssw, m_rs[15] - 0xc, (old_psw & ~(PSW_CTS | PSW_MTS)) | source)) + fatalerror("intrap unrecoverable fault 0x%04x push psw ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0xc, old_pc); // decrement supervisor stack pointer - m_rs[15] -= get_eframe_size(); + m_rs[15] -= 12; + + // set ssw from vector and previous mode + set_ssw((new_ssw & ~SSW_P) | (old_ssw & SSW_U) << 1); + + // clear psw + set_psw(0); + + // return new pc from trap vector + return new_pc; +} + +u32 clipper_c400_device::intrap(const u16 vector, const u32 old_pc) +{ + const u32 old_ssw = m_ssw; + const u32 old_psw = m_psw; + u32 new_pc = 0, new_ssw = 0; + + // clear ssw bits to enable supervisor memory access + m_ssw &= ~(SSW_U | SSW_K | SSW_UU | SSW_KU); + + // clear exception state + m_exception = 0; + + // fetch ssw and pc from interrupt vector (C400 reversed wrt C100/C300) + if (!get_dcammu().load(m_ssw, vector + 0, [&new_ssw](u32 v) { new_ssw = v; })) + fatalerror("intrap unrecoverable fault 0x%04x load ssw address 0x%08x pc 0x%08x\n", m_exception, vector + 0, old_pc); + if (!get_dcammu().load(m_ssw, vector + 4, [&new_pc](u32 v) { new_pc = v; })) + fatalerror("intrap unrecoverable fault 0x%04x load pc address 0x%08x pc 0x%08x\n", m_exception, vector + 4, old_pc); + + LOGMASKED(LOG_EXCEPTION, "intrap vector 0x%04x pc 0x%08x ssp 0x%08x new_pc 0x%08x new_ssw 0x%08x\n", vector, old_pc, m_rs[15], new_pc, new_ssw); + + // derive cts and mts from vector + u32 source = 0; + switch (vector) + { + // data memory trap group + case EXCEPTION_D_CORRECTED_MEMORY_ERROR: + case EXCEPTION_D_UNCORRECTABLE_MEMORY_ERROR: + case EXCEPTION_D_ALIGNMENT_FAULT: + case EXCEPTION_D_PAGE_FAULT: + case EXCEPTION_D_READ_PROTECT_FAULT: + case EXCEPTION_D_WRITE_PROTECT_FAULT: + + // instruction memory trap group + case EXCEPTION_I_CORRECTED_MEMORY_ERROR: + case EXCEPTION_I_UNCORRECTABLE_MEMORY_ERROR: + case EXCEPTION_I_ALIGNMENT_FAULT: + case EXCEPTION_I_PAGE_FAULT: + case EXCEPTION_I_EXECUTE_PROTECT_FAULT: + source = (vector & MTS_VMASK) << (MTS_SHIFT - MTS_VSHIFT); + break; + + // integer arithmetic trap group + case EXCEPTION_INTEGER_DIVIDE_BY_ZERO: + source = CTS_DIVIDE_BY_ZERO; + break; + + // illegal operation trap group + case EXCEPTION_ILLEGAL_OPERATION: + source = CTS_ILLEGAL_OPERATION; + break; + case EXCEPTION_PRIVILEGED_INSTRUCTION: + source = CTS_PRIVILEGED_INSTRUCTION; + break; + + // diagnostic trap group + case EXCEPTION_TRACE: + source = CTS_TRACE_TRAP; + break; + } + + // push pc, ssw and psw onto supervisor stack + if (!get_dcammu().store(m_ssw, m_rs[15] - 0x4, old_pc)) + fatalerror("intrap unrecoverable fault 0x%04x push pc ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x4, old_pc); + + if (!get_dcammu().store(m_ssw, m_rs[15] - 0x8, old_ssw)) + fatalerror("intrap unrecoverable fault 0x%04x push ssw ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x8, old_pc); + + if (!get_dcammu().store(m_ssw, m_rs[15] - 0xc, (old_psw & ~(PSW_CTS | PSW_MTS)) | source)) + fatalerror("intrap unrecoverable fault 0x%04x push psw ssp 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0xc, old_pc); + + // TODO: push pc1 + // TODO: push pc2 + + // push delayed branch pc onto supervisor stack + if (!get_dcammu().store(m_ssw, m_rs[15] - 0x18, m_db_pc)) + fatalerror("intrap unrecoverable fault 0x%04x push db_pc address 0x%08x pc 0x%08x\n", m_exception, m_rs[15] - 0x18, old_pc); + + // decrement supervisor stack pointer + m_rs[15] -= 24; // set ssw from vector and previous mode set_ssw((new_ssw & ~SSW_P) | (old_ssw & SSW_U) << 1); @@ -1736,37 +1768,119 @@ void clipper_device::fp_exception() void clipper_c400_device::execute_instruction() { + // update delay slot pointer + switch (PSW(DSP)) + { + case DSP_S1: + // take delayed branch + m_psw &= ~PSW_DSP; + m_ip = m_db_pc; + return; + + case DSP_SALL: + // one delay slot still active + m_psw &= ~PSW_DSP; + m_psw |= DSP_S1; + break; + + case DSP_SETUP: + // two delay slots active + m_psw &= ~PSW_DSP; + m_psw |= DSP_SALL; + break; + } + + // if executing a delay slot instruction, test for valid type + if (PSW(DSP)) + { + switch (m_info.opcode) + { + case 0x13: // ret + case 0x44: // call + case 0x45: + case 0x48: // b* + case 0x49: + case 0x4a: // cdb + case 0x4b: + case 0x4c: // cdbeq + case 0x4d: + case 0x4e: // cdbne + case 0x4f: + case 0x50: // db* + case 0x51: + // TODO: this should throw some kind of illegal instruction trap, not abort + fatalerror("instruction type 0x%02x invalid in branch delay slot pc 0x%08x\n", m_info.opcode, m_pc); + + default: + break; + } + } + switch (m_info.opcode) { -#ifdef UNIMPLEMENTED_C400 case 0x46: case 0x47: - // loadd2: + // loadd2: load double floating double + // TODO: 128-bit load + get_dcammu().load(m_ssw, m_info.address + 0, [this](float64 v) { set_fp(R2 + 0, v, F_NONE); }); + get_dcammu().load(m_ssw, m_info.address + 8, [this](float64 v) { set_fp(R2 + 1, v, F_NONE); }); + // TRAPS: C,U,A,P,R,I break; case 0x4a: case 0x4b: - // cdb: - break; + // cdb: call with delayed branch? + // emulate.h: "cdb is special because it does not support all addressing modes", 2-3 parcels + fatalerror("cdb pc 0x%08x\n", m_pc); case 0x4c: case 0x4d: - // cdbeq: - break; + // cdbeq: call with delayed branch if equal? + fatalerror("cdbeq pc 0x%08x\n", m_pc); case 0x4e: case 0x4f: - // cdbne: - break; + // cdbne: call with delayed branch if not equal? + fatalerror("cdbne pc 0x%08x\n", m_pc); case 0x50: case 0x51: - // db*: + // db*: delayed branch on condition + if (evaluate_branch()) + { + m_psw |= DSP_SETUP; + m_db_pc = m_info.address; + } break; case 0xb0: // abss: absolute value single floating? + if (float32_lt(get_fp32(R1), 0)) + set_fp(R2, float32_mul(get_fp32(R1), int32_to_float32(-1)), F_IVUX); + else + set_fp(R2, get_fp32(R1), F_IVUX); break; case 0xb2: // absd: absolute value double floating? + if (float64_lt(get_fp64(R1), 0)) + set_fp(R2, float64_mul(get_fp64(R1), int32_to_float64(-1)), F_IVUX); + else + set_fp(R2, get_fp64(R1), F_IVUX); + break; + + case 0xb4: + // unprivileged macro instructions + switch (m_info.subopcode) + { + case 0x44: + // cnvxsw: ?? + fatalerror("cnvxsw pc 0x%08x\n", m_pc); + case 0x46: + // cnvxdw: ?? + fatalerror("cnvxdw pc 0x%08x\n", m_pc); + + default: + clipper_device::execute_instruction(); + break; + } break; case 0xb6: @@ -1777,19 +1891,29 @@ void clipper_c400_device::execute_instruction() { case 0x07: // loadts: unknown? + fatalerror("loadts pc 0x%08x\n", m_pc); + + default: + clipper_device::execute_instruction(); break; } } + else + m_exception = EXCEPTION_PRIVILEGED_INSTRUCTION; break; case 0xbc: // waitd: + if (!SSW(U)) + ; // TODO: don't know what this instruction does + else + m_exception = EXCEPTION_PRIVILEGED_INSTRUCTION; break; case 0xc0: - // s*: + // s*: set register on condition + m_r[R1] = evaluate_branch() ? 1 : 0; break; -#endif default: clipper_device::execute_instruction(); diff --git a/src/devices/cpu/clipper/clipper.h b/src/devices/cpu/clipper/clipper.h index 1781401fece..c1324d8ae27 100644 --- a/src/devices/cpu/clipper/clipper.h +++ b/src/devices/cpu/clipper/clipper.h @@ -10,6 +10,9 @@ #include "softfloat/milieu.h" #include "softfloat/softfloat.h" +#include "cpu/clipper/common.h" +#include "machine/cammu.h" + // convenience macros for dealing with the psw and ssw #define PSW(mask) (m_psw & PSW_##mask) #define SSW(mask) (m_ssw & SSW_##mask) @@ -17,22 +20,9 @@ class clipper_device : public cpu_device { public: - DECLARE_READ32_MEMBER(get_ssw) const { return m_ssw; } DECLARE_WRITE8_MEMBER(set_ivec) { m_ivec = data; } DECLARE_WRITE16_MEMBER(set_exception); - enum addressing_modes : u8 - { - ADDR_MODE_PC32 = 0x10, // pc relative with 32 bit displacement - ADDR_MODE_ABS32 = 0x30, // 32 bit absolute - ADDR_MODE_REL32 = 0x60, // relative with 32 bit displacement - ADDR_MODE_PC16 = 0x90, // pc relative with 16 bit displacement - ADDR_MODE_REL12 = 0xa0, // relative with 12 bit displacement - ADDR_MODE_ABS16 = 0xb0, // 16 bit absolute - ADDR_MODE_PCX = 0xd0, // pc indexed - ADDR_MODE_RELX = 0xe0 // relative indexed - }; - // branch conditions (first description for comparison, second for move/logical) enum branch_conditions : u8 { @@ -94,73 +84,21 @@ public: FR_3 = 0x00018000 // round toward zero }; - enum ssw : u32 + enum psw_dsp : u32 { - 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) - SSW_FRD = 0x00400000, // floating registers dirty - SSW_TP = 0x00800000, // trace trap pending - SSW_ECM = 0x01000000, // enable corrected memory error - SSW_DF = 0x02000000, // fpu disabled - SSW_M = 0x04000000, // mapped mode - SSW_KU = 0x08000000, // user protect key - SSW_UU = 0x10000000, // user data mode - SSW_K = 0x20000000, // protect key - SSW_U = 0x40000000, // user mode - SSW_P = 0x80000000 // previous mode + DSP_NONE = 0x00000000, // no delayed branch active + DSP_S1 = 0x00100000, // delayed branch slot 1 active + DSP_SALL = 0x00200000, // delayed branch slots 0 and 1 active + DSP_SETUP = 0x00300000 // delayed branch taken }; enum ssw_id : u32 { - SSW_ID_C400R0 = 0x00000, - SSW_ID_C400R1 = 0x04000, - SSW_ID_C400R2 = 0x08000, - SSW_ID_C400R3 = 0x0c000, - SSW_ID_C400R4 = 0x10000 - }; - - enum exception_vectors : u16 - { - // data memory trap group - EXCEPTION_D_CORRECTED_MEMORY_ERROR = 0x108, - EXCEPTION_D_UNCORRECTABLE_MEMORY_ERROR = 0x110, - EXCEPTION_D_ALIGNMENT_FAULT = 0x120, - EXCEPTION_D_PAGE_FAULT = 0x128, - EXCEPTION_D_READ_PROTECT_FAULT = 0x130, - EXCEPTION_D_WRITE_PROTECT_FAULT = 0x138, - - // floating-point arithmetic trap group - EXCEPTION_FLOATING_INEXACT = 0x180, - EXCEPTION_FLOATING_UNDERFLOW = 0x188, - EXCEPTION_FLOATING_DIVIDE_BY_ZERO = 0x190, - EXCEPTION_FLOATING_OVERFLOW = 0x1a0, - EXCEPTION_FLOATING_INVALID_OPERATION = 0x1c0, - - // integer arithmetic trap group - EXCEPTION_INTEGER_DIVIDE_BY_ZERO = 0x208, - - // instruction memory trap group - EXCEPTION_I_CORRECTED_MEMORY_ERROR = 0x288, - EXCEPTION_I_UNCORRECTABLE_MEMORY_ERROR = 0x290, - EXCEPTION_I_ALIGNMENT_FAULT = 0x2a0, - EXCEPTION_I_PAGE_FAULT = 0x2a8, - EXCEPTION_I_EXECUTE_PROTECT_FAULT = 0x2b0, - - // illegal operation trap group - EXCEPTION_ILLEGAL_OPERATION = 0x300, - EXCEPTION_PRIVILEGED_INSTRUCTION = 0x308, - - // diagnostic trap group - EXCEPTION_TRACE = 0x380, - - // supervisor calls (0x400-0x7f8) - EXCEPTION_SUPERVISOR_CALL_BASE = 0x400, - - // prioritized interrupts (0x800-0xff8) - EXCEPTION_INTERRUPT_BASE = 0x800 + SSW_ID_C400R0 = 0x00800, + SSW_ID_C400R1 = 0x04800, + SSW_ID_C400R2 = 0x08800, + SSW_ID_C400R3 = 0x0c800, + SSW_ID_C400R4 = 0x10800 }; // trap source values are shifted into the correct field in the psw @@ -230,13 +168,17 @@ protected: // device_disasm_interface overrides virtual util::disasm_interface *create_disassembler() override; + // mmu helpers + virtual cammu_device &get_icammu() const = 0; + virtual cammu_device &get_dcammu() const = 0; + // cpu execution logic bool decode_instruction(); virtual void execute_instruction(); bool evaluate_branch() const; // exception entry and return helpers - u32 intrap(const u16 vector, const u32 old_pc); + virtual u32 intrap(const u16 vector, const u32 old_pc); u32 reti(); // cpu state helpers @@ -248,11 +190,6 @@ protected: virtual int get_ireg_count() const { return 16; } virtual int get_freg_count() const { return 8; } - // exception vector and frame helpers - virtual int get_eframe_size() const { return 12; } - virtual int get_evpc_offset() const { return 0; } - virtual int get_evssw_offset() const { return 4; } - // floating point helpers float32 get_fp32(const u8 reg) const { return m_f[reg & 0xf]; } float64 get_fp64(const u8 reg) const { return m_f[reg & 0xf]; } @@ -317,11 +254,9 @@ protected: }; // emulation state - address_space_config m_insn_config; - address_space_config m_data_config; - - address_space *m_insn; - address_space *m_data; + address_space_config m_main_config; + address_space_config m_io_config; + address_space_config m_boot_config; enum registers { @@ -333,6 +268,7 @@ protected: }; int m_icount; // instruction cycle count + bool m_wait; // program-visible cpu state u32 m_pc; // current instruction address @@ -372,12 +308,28 @@ class clipper_c100_device : public clipper_device { public: clipper_c100_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual cammu_device &get_icammu() const override { return *m_icammu; } + virtual cammu_device &get_dcammu() const override { return *m_dcammu; } + +private: + required_device m_icammu; + required_device m_dcammu; }; class clipper_c300_device : public clipper_device { public: clipper_c300_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual cammu_device &get_icammu() const override { return *m_icammu; } + virtual cammu_device &get_dcammu() const override { return *m_dcammu; } + +private: + required_device m_icammu; + required_device m_dcammu; }; class clipper_c400_device : public clipper_device @@ -386,19 +338,20 @@ public: clipper_c400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); protected: + virtual u32 intrap(const u16 vector, const u32 old_pc) override; + // C400 has additional 8 floating point registers virtual int get_freg_count() const override { return 16; } - // C400 creates a 24 byte exception frame (C100/C300 is 12 bytes), but the - // service routine must increment sp by 12 prior to executing reti - // exception frame size - virtual int get_eframe_size() const override { return 24; } - - // C400 pc and ssw are reversed in exception vector compared to C100/C300 - virtual int get_evpc_offset() const override { return 4; } - virtual int get_evssw_offset() const override { return 0; } - virtual void execute_instruction() override; + + virtual cammu_device &get_icammu() const override { return *m_cammu; } + virtual cammu_device &get_dcammu() const override { return *m_cammu; } + +private: + u32 m_db_pc; // delayed branch pc + + required_device m_cammu; }; DECLARE_DEVICE_TYPE(CLIPPER_C100, clipper_c100_device) diff --git a/src/devices/cpu/clipper/clipperd.cpp b/src/devices/cpu/clipper/clipperd.cpp index d328d3b4631..c11cf0a5ee8 100644 --- a/src/devices/cpu/clipper/clipperd.cpp +++ b/src/devices/cpu/clipper/clipperd.cpp @@ -2,6 +2,7 @@ // copyright-holders:Patrick Mackinlay #include "emu.h" +#include "cpu/clipper/common.h" #include "clipperd.h" /* @@ -297,6 +298,10 @@ offs_t clipper_disassembler::disassemble(std::ostream &stream, offs_t pc, const case 0x3e: util::stream_format(stream, "trapfn"); break; case 0x3f: util::stream_format(stream, "loadfs r%d,f%d", (opcodes.r16(pc+2) & 0xf0) >> 4, opcodes.r16(pc+2) & 0xf); break; +#if C400_INSTRUCTIONS + case 0x44: util::stream_format(stream, "cnvxsw f%d,f%d", (opcodes.r16(pc + 2) & 0xf0) >> 4, opcodes.r16(pc + 2) & 0xf); break; + case 0x46: util::stream_format(stream, "cnvxdw f%d,f%d", (opcodes.r16(pc + 2) & 0xf0) >> 4, opcodes.r16(pc + 2) & 0xf); break; +#endif default: util::stream_format(stream, "macro 0x%04x 0x%04x", opcodes.r16(pc), opcodes.r16(pc+2)); break; diff --git a/src/devices/cpu/clipper/clipperd.h b/src/devices/cpu/clipper/clipperd.h index 1dd757fde63..cac65afdf93 100644 --- a/src/devices/cpu/clipper/clipperd.h +++ b/src/devices/cpu/clipper/clipperd.h @@ -16,22 +16,8 @@ public: virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override; private: - enum addressing_modes : u8 - { - ADDR_MODE_PC32 = 0x10, // pc relative with 32 bit displacement - ADDR_MODE_ABS32 = 0x30, // 32 bit absolute - ADDR_MODE_REL32 = 0x60, // relative with 32 bit displacement - ADDR_MODE_PC16 = 0x90, // pc relative with 16 bit displacement - ADDR_MODE_REL12 = 0xa0, // relative with 12 bit displacement - ADDR_MODE_ABS16 = 0xb0, // 16 bit absolute - ADDR_MODE_PCX = 0xd0, // pc indexed - ADDR_MODE_RELX = 0xe0 // relative indexed - }; - static const char *const cc[]; std::string address (offs_t pc, const data_buffer &opcodes); - - }; #endif diff --git a/src/devices/cpu/clipper/common.h b/src/devices/cpu/clipper/common.h new file mode 100644 index 00000000000..343e18c4913 --- /dev/null +++ b/src/devices/cpu/clipper/common.h @@ -0,0 +1,83 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_CPU_CLIPPER_COMMON_H +#define MAME_CPU_CLIPPER_COMMON_H + +#pragma once + +enum addressing_modes : u8 +{ + ADDR_MODE_PC32 = 0x10, // pc relative with 32 bit displacement + ADDR_MODE_ABS32 = 0x30, // 32 bit absolute + ADDR_MODE_REL32 = 0x60, // relative with 32 bit displacement + ADDR_MODE_PC16 = 0x90, // pc relative with 16 bit displacement + ADDR_MODE_REL12 = 0xa0, // relative with 12 bit displacement + ADDR_MODE_ABS16 = 0xb0, // 16 bit absolute + ADDR_MODE_PCX = 0xd0, // pc indexed + ADDR_MODE_RELX = 0xe0 // relative indexed +}; + +enum ssw_mask : u32 +{ + 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) + SSW_FRD = 0x00400000, // floating registers dirty + SSW_TP = 0x00800000, // trace trap pending + SSW_ECM = 0x01000000, // enable corrected memory error + SSW_DF = 0x02000000, // fpu disabled + SSW_M = 0x04000000, // mapped mode + SSW_KU = 0x08000000, // user protect key + SSW_UU = 0x10000000, // user data mode + SSW_K = 0x20000000, // protect key + SSW_U = 0x40000000, // user mode + SSW_P = 0x80000000, // previous mode + + SSW_PL = 0x78000000 // protection level relevant bits +}; + +enum exception_vector : u16 +{ + // data memory trap group + EXCEPTION_D_CORRECTED_MEMORY_ERROR = 0x108, + EXCEPTION_D_UNCORRECTABLE_MEMORY_ERROR = 0x110, + EXCEPTION_D_ALIGNMENT_FAULT = 0x120, + EXCEPTION_D_PAGE_FAULT = 0x128, + EXCEPTION_D_READ_PROTECT_FAULT = 0x130, + EXCEPTION_D_WRITE_PROTECT_FAULT = 0x138, + + // floating-point arithmetic trap group + EXCEPTION_FLOATING_INEXACT = 0x180, + EXCEPTION_FLOATING_UNDERFLOW = 0x188, + EXCEPTION_FLOATING_DIVIDE_BY_ZERO = 0x190, + EXCEPTION_FLOATING_OVERFLOW = 0x1a0, + EXCEPTION_FLOATING_INVALID_OPERATION = 0x1c0, + + // integer arithmetic trap group + EXCEPTION_INTEGER_DIVIDE_BY_ZERO = 0x208, + + // instruction memory trap group + EXCEPTION_I_CORRECTED_MEMORY_ERROR = 0x288, + EXCEPTION_I_UNCORRECTABLE_MEMORY_ERROR = 0x290, + EXCEPTION_I_ALIGNMENT_FAULT = 0x2a0, + EXCEPTION_I_PAGE_FAULT = 0x2a8, + EXCEPTION_I_EXECUTE_PROTECT_FAULT = 0x2b0, + + // illegal operation trap group + EXCEPTION_ILLEGAL_OPERATION = 0x300, + EXCEPTION_PRIVILEGED_INSTRUCTION = 0x308, + + // diagnostic trap group + EXCEPTION_TRACE = 0x380, + + // supervisor calls (0x400-0x7f8) + EXCEPTION_SUPERVISOR_CALL_BASE = 0x400, + + // prioritized interrupts (0x800-0xff8) + EXCEPTION_INTERRUPT_BASE = 0x800 +}; + +#endif // MAME_CPU_CLIPPER_COMMON_H diff --git a/src/mame/drivers/interpro.cpp b/src/mame/drivers/interpro.cpp index ee65b1e6bb8..c6e455d0e89 100644 --- a/src/mame/drivers/interpro.cpp +++ b/src/mame/drivers/interpro.cpp @@ -7,7 +7,7 @@ * * The first systems were built using the original C100 CLIPPER CPU, and used * an additional Intel 80186 as an I/O processor, later moving to a C300 with - * 80386 IOP. Around 1989, the CLIPPER became fast enough to obviate the need + * 80386 IOP. Around 1990, the CLIPPER became fast enough to obviate the need * for the separate I/O processor, and systems from that point used the main * CPU for both compute and I/O, along with some custom ASICs. * @@ -17,66 +17,77 @@ * Year Family Models CPU * 1986 amethyst 32C/100/200 C100 (80186 IOP) * 1988 topaz 300/3000/4000/5000 C300/C300Plus (80386 IOP) - * 1989 turquoise 2000 C300 - * 1989 emerald 6000/6100/6200/6500/6600 C300/C300Plus (C4T in 6600?) - * 1991 sapphire 2400/6400 C4T - * 1992 sapphire 2500/2700/6700/6800/2800 C4I + * 1990 emerald 6000/6100/6200/6500 C300/C300Plus + * 1990 turquoise 2000 C300 + * 1991 emerald? 6600 C4? + * 1992 sapphire 2400/6400 C4T + * 1993 sapphire 2500/2700/6700/6800 C4I + * 1994 sapphire 2800 C4I * * Individual models and some of their specific attributes include: * - * Model Year CPU Clock Family - * 2000 1989 C300 turquoise - * 6000 1989 C300 emerald - * 2400 1991? C4T 40MHz? sapphire - * 6400 1991 C4T 40MHz sapphire - * 6600 C400 emerald (IOI, SRX bus?) - * 6700 1992 C400I 70MHz? sapphire - * 6800 1993 C400I 80MHz? sapphire - * 2500 1993? C400I 50MHz? sapphire - * 2700 1992 C400I 70MHz? sapphire - * 2800 1994 C400I 80MHz? sapphire + * Model Year CPU Performance Clock Family Bus + * 6000 1990 C300 10 MIPS 40MHz emerald SRX + * 6100 1990 14 MIPS emerald IOI?, 6105 has 5-slot chassis + * 6500 C300+ emerald IOI, QWIC bus? + * 6200 1990 C300+ 14 MIPS 60MHz emerald + * 1991 18 MIPS + * 2000 1990 C300 12.5 MIPS 50MHz? turquoise CBUS + * 6600 1991 C400 40 MIPS emerald? IOI, SRX bus? + * 2400 1992 C4T 36 MIPS/33 SPECmarks 40MHz? sapphire CBUS + * 6400 1992 C4T 36 MIPS/33 SPECmarks 40MHz sapphire SRX + * 2700 1993 C400I 40.1 SPECmark89 sapphire 2 CBUS + * 6700 1993 C400I 40.1 SPECmark89 sapphire 2 SRX + * 6800 1993 C400I 67.2 SPECmark89 sapphire 3 SRX + * 2500 1993 C400I 19.9 SPECint92 sapphire + * 2800 1994 C400I sapphire 3 CBUS? * - * 6100 emerald (IOI) - * 6200 1989 C300Plus 60MHz emerald - * 6500 C300Plus emerald (IOI, QWIC bus?) + * IOI == I/O Interface (another type of bus?) + * Sapphire 2 w/CBUS supports RETRY (maybe bus retry?) * - * With many exceptions, the general model numbering system is ABCD, where: + * With some exceptions, system models are numbered ABCD, where: * - * A: case type (2=desktop, 6=tower) + * A: case type (2=desktop, 6=minicase) * B: CPU type (0=C300, 4=C4T, 6=C400?, 7/8/5 = C400I) - * C: graphics type (0=none, 3/5=GT, 4/8 = EDGE) - * D: always 0? + * C: graphics type (0=none, 3/5=GT, 4=EDGE-1, 8 = EDGE-2) + * D: usually 0, 6xxx systems have 5, 7 and 9 options (backplane type?) * - * Both the desktop and tower units supported an expansion bus with a variety + * Graphics type 3 is for GT graphics fitted to a 2xxx system, and type 5 when + * fitted to a 6xxx system. The latter is possibly also known as GTDB. + * + * Both the desktop and minicase units supported expansion slots with a variety * of cards, although with different profiles and connectors between 2xxx and * 6xxx systems. The bus is referred to as SR, SRX, SR Bus, CBUS and some - * combinations of these in various places, but all appears to be compatible or + * combinations of these in various places, but all appear to be compatible or * identical, possibly with SRX being an enhanced version. The bus supported a * range of add-in cards, ranging from expanded SCSI and serial controllers, * to specialised scanning and plotting controllers, a VME bridge, and most * importantly various single and dual-headed graphics boards. * * The InterPro graphics options included the GT range, generally fitted to the - * desktop systems, and EDGE graphics for the towers. Systems with no graphics - * were operated through a serial console on serial port 2, and were branded as - * InterServe rather than InterPro systems. + * desktops, and EDGE graphics for the 6xxx systems. Systems with no graphics + * were operated through a serial terminal on serial port 2, and were branded + * InterServe rather than InterPro. * * Model Year Performance * GT 1990? 360k 2D vec/s (in a 2020) - * EDGE-1 - * EDGE-2 + * EDGE-1 8 planes + 1 highlight plane, double buffered (6040) + * EDGE-2 24 bit, 400k 2D vec/s, 350k 3D vec/s (6280) * GT+ 760k 2D vec/s, 530k 3D vec/s (in a 2730) * GTII 830k 2D vec/s, 640k 3D vec/s (in a 6750) * 900k 2D vec/s, 700k 3D vec/s (in a 6850) * EDGE II+ 50k Gouraud-shaded poly/s (in a 6780) * + * GT graphics are also referred to in various places as Memory Mapped Graphics + * or MMG. EDGE stands for Extensible Display Geometry Engine. + * * This emulation currently supports the Turquoise and Sapphire desktop systems (i.e. models * 2000/2400/2500/2700/2800). Base GT graphics can be used with any of these models, or the * graphics and keyboard removed and the systems used with a serial terminal instead. * * Key parts lists for the supported models are as follows. * - * 2000 Turquoise (C300 @ 40MHz?, main board PCB962) + * 2000 Turquoise (C300 @ 50MHz?, main board PCB962) * * Ref Part Function * U37 Intel 82072 Floppy drive controller @@ -103,16 +114,16 @@ * U34 Xilinix XC3020-50 Plotter control FPGA? * 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) + * U44 Intel 82596SX-20 Ethernet controller + * U67 Intel N28F010-200 128Kx8 flash memory (Y226 0B03 0592) * U68 CYID21603 TC150G89AF * U71 LSI L1A6104 CICD 95801 Intergraph I/O gate array - * U76 Intel N28F010-200 128Kx8 flash memory (200ns) + * U76 Intel N28F010-200 128Kx8 flash memory (Y225 0B?? 27??) * U81 NCR 53C94 SCSI controller * U86 24.0 MHz crystal Clock source for 53C94? * U87 4.9152 MHz crystal Clock source for 8530s? * U88 20.0 MHz crystal Clock source for 82596? - * U91 Intel N82077AA Floppy drive controller + * U91 Intel N82077AA-1 Floppy drive controller * U96 32.0 MHz crystal * U97 40.0 MHz crystal * U112? (MPRG4230A) node ID prom? @@ -129,23 +140,40 @@ * U34 Xilinix XC3020-70 Plotter control FPGA? * U35 128 kB EPROM (MPRGZ530A) Boot ROM * U43? (MPRGM610P) Bitstream for XC3020? - * U44 Intel 82596SX? Ethernet controller + * U44 Intel 82596SX-20 Ethernet controller * U68 CYID21603 TC150G89AF - * U67 Intel N28F010 128Kx8 flash memory + * U67 Intel N28F010 128Kx8 flash memory (Y226 0C30 4291) * U71 LSI L1A7374 CIDC094A3 Intergraph I/O gate array - * U76 Intel N28F010 128Kx8 flash memory + * U76 Intel N28F010 128Kx8 flash memory (Y225 0C30 4220) * U81 NCR 53C94 SCSI controller - * U86 24.0 MHz crystal Clock source for 53C94? + * U86 24.0 MHz crystal Clock source for 82077 * U87 4.9152 MHz crystal Clock source for 8530s? * U88 20.0 MHz crystal Clock source for 82596? - * U91 Intel N82077AA? Floppy drive controller - * U96 32.0 MHz crystal? + * U91 Intel N82077SL-1 Floppy drive controller + * U96 29.0 MHz crystal * U97 40.0 MHz crystal * U112? (MPRGZ260E) node ID prom? - * U113? Dallas DS12887 RTC and NVRAM + * U113 Dallas DS12887 RTC and NVRAM * U117? diagnostic 7-segment LED? * U118? () * U155 CYID212?4 TC140G54AF? + * + * CPU daughter-boards + * PCB824 Rev J - 2000 (also has label MPCBA5507) + * SMT082 (MSMT0820B, 36MHz?) - 6400 (SMT046 "6400 36-MHz Series System Board") + * SMT03? 2400/6400 - (MSMT03804 -> rev 2 cammu, goes with "6400 36-MHz Series System Board", MSMT0380A eco 3+ use rev 3 cammu) + * SMT019 (MSMT019 C4E CPU Assembly) + * SMT104 Rev A - 2700/6700 (aka MSMT1040A "C4I CPU", C4 CPU REV 3 + C4 FPU REV 3 + C4I CAMMU) + * + * PCB962 2000 System Board MPCB824 C300 + * SMT046 6400 36-MHz Series System Board MSMT03804 rev 2 CAMMU/30MHz Kryptonite Rev 3 CAMMU/32MHz Kryptonite Rev 3 CAMMU/MSMT0820B(36MHz) + * SMT047 2400 Series System Board MSMT03804 rev 2 CAMMU/MSMT0380A eco 3+ Rev 3 CAMMU + * SMT098A 6400 32-MHz Sapphire System Board + * SMT098B 6400 32-MHz Sapphire System Board + * SMT127 6700 Series System Board MSMT1040A C4I: C4 CPU Rev 3 + C4 FPU Rev 3 + C4I CAMMU + * SMT128 2700 Series System Board MSMT1040A C4I: C4 CPU Rev 3 + C4 FPU Rev 3 + C4I CAMMU + * SMT144 6800 Series System Board + * SMT145 2800 Series System Board */ #include "emu.h" @@ -184,12 +212,6 @@ void interpro_state::machine_reset() DRIVER_INIT_MEMBER(interpro_state, common) { -} - -DRIVER_INIT_MEMBER(turquoise_state, turquoise) -{ - interpro_state::init_common(); - // FIXME: not all memory sizes are reported properly using fdm "5 inqhw" and // "optimum_memory" commands @@ -200,25 +222,7 @@ DRIVER_INIT_MEMBER(turquoise_state, turquoise) // 256 = reports 256M, 32x8 // map the configured ram - m_d_cammu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer()); - m_i_cammu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer()); -} - -DRIVER_INIT_MEMBER(sapphire_state, sapphire) -{ - interpro_state::init_common(); - - // FIXME: not all memory sizes are reported properly using fdm "5 inqhw" and - // "optimum_memory" commands - - // 16 = reports 16M, banks empty? - // 32 = reports 16M, banks empty? - // 64 = reports 128M, 16x8 - // 128 = reports 128M, 16x8 - // 256 = reports 256M, 32x8 - - // map the configured ram - m_mmu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer()); + m_maincpu->space(0).install_ram(0, m_ram->mask(), m_ram->pointer()); } WRITE16_MEMBER(interpro_state::sreg_led_w) @@ -275,7 +279,7 @@ READ16_MEMBER(interpro_state::sreg_error_r) return result; } -READ32_MEMBER(interpro_state::unmapped_r) +READ32_MEMBER(sapphire_state::unmapped_r) { // check if non-existent memory errors are enabled if (!machine().side_effects_disabled()) @@ -291,7 +295,7 @@ READ32_MEMBER(interpro_state::unmapped_r) return space.unmap(); } -WRITE32_MEMBER(interpro_state::unmapped_w) +WRITE32_MEMBER(sapphire_state::unmapped_w) { // check if non-existent memory errors are enabled if (m_arbga->tctrl_r(space, offset, mem_mask) & interpro_arbga_device::TCTRL_ENNEM) @@ -319,23 +323,6 @@ READ8_MEMBER(interpro_state::nodeid_r) return space.unmap(); } -// these maps connect the cpu virtual addresses to the mmu -ADDRESS_MAP_START(interpro_state::c300_insn_map) - AM_RANGE(0x00000000, 0xffffffff) AM_DEVREAD(INTERPRO_MMU_TAG "_i", cammu_device, read) -ADDRESS_MAP_END - -ADDRESS_MAP_START(interpro_state::c300_data_map) - AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE(INTERPRO_MMU_TAG "_d", cammu_device, read, write) -ADDRESS_MAP_END - -ADDRESS_MAP_START(interpro_state::c400_insn_map) - AM_RANGE(0x00000000, 0xffffffff) AM_DEVREAD(INTERPRO_MMU_TAG, cammu_device, read) -ADDRESS_MAP_END - -ADDRESS_MAP_START(interpro_state::c400_data_map) - AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE(INTERPRO_MMU_TAG, cammu_device, read, write) -ADDRESS_MAP_END - ADDRESS_MAP_START(interpro_state::interpro_common_map) // FIXME: don't know what this range is for AM_RANGE(0x08000000, 0x08000fff) AM_NOP @@ -343,7 +330,6 @@ ADDRESS_MAP_START(interpro_state::interpro_common_map) AM_RANGE(0x4f007e00, 0x4f007eff) AM_DEVICE(INTERPRO_SGA_TAG, interpro_sga_device, map) AM_RANGE(0x7f000100, 0x7f00011f) AM_DEVICE8(INTERPRO_FDC_TAG, upd765_family_device, map, 0x000000ff) - AM_RANGE(0x7f000200, 0x7f0002ff) AM_DEVICE(INTERPRO_ARBGA_TAG, interpro_arbga_device, map) AM_RANGE(0x7f000300, 0x7f000303) AM_READ16(sreg_error_r, 0x0000ffff) AM_RANGE(0x7f000304, 0x7f000307) AM_READWRITE16(sreg_status_r, sreg_led_w, 0x0000ffff) AM_RANGE(0x7f000308, 0x7f00030b) AM_READWRITE16(sreg_ctrl1_r, sreg_ctrl1_w, 0x0000ffff) @@ -356,25 +342,10 @@ ADDRESS_MAP_START(interpro_state::interpro_common_map) ;map(0x7f000500, 0x7f000503).lrw8("rtc_rw", [this](address_space &space, offs_t offset, u8 mem_mask){ return m_rtc->read(space, offset^1, mem_mask); }, [this](address_space &space, offs_t offset, u8 data, u8 mem_mask){ m_rtc->write(space, offset^1, data, mem_mask); }).umask32(0x000000ff); AM_RANGE(0x7f000600, 0x7f000603) AM_DEVWRITE8(INTERPRO_RTC_TAG, mc146818_device, write, 0x000000ff) - AM_RANGE(0x7f000600, 0x7f00060f) AM_READ8(nodeid_r, 0xff) // the system board id prom AM_RANGE(0x7f000700, 0x7f00077f) AM_ROM AM_REGION(INTERPRO_IDPROM_TAG, 0) - // scsi registers have unusual address mapping - AM_RANGE(0x7f001000, 0x7f001003) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_lo_r, tcount_lo_w, 0x0000ff00) - AM_RANGE(0x7f001100, 0x7f001103) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_hi_r, tcount_hi_w, 0x0000ff00) - AM_RANGE(0x7f001200, 0x7f001203) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_r, fifo_w, 0x0000ff00) - AM_RANGE(0x7f001300, 0x7f001303) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, command_r, command_w, 0x0000ff00) - AM_RANGE(0x7f001400, 0x7f001403) AM_DEVREAD8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, status_r, 0xff00) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, bus_id_w, 0x0000ff00) - AM_RANGE(0x7f001500, 0x7f001503) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, istatus_r, timeout_w, 0x0000ff00) - AM_RANGE(0x7f001600, 0x7f001603) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, seq_step_r, sync_period_w, 0x0000ff00) - AM_RANGE(0x7f001700, 0x7f001703) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_flags_r, sync_offset_w, 0x0000ff00) - AM_RANGE(0x7f001800, 0x7f001803) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf_r, conf_w, 0x0000ff00) - AM_RANGE(0x7f001900, 0x7f001903) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, clock_w, 0x0000ff00) - AM_RANGE(0x7f001a00, 0x7f001a03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, test_w, 0x0000ff00) - AM_RANGE(0x7f001b00, 0x7f001b03) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf2_r, conf2_w, 0x0000ff00) - AM_RANGE(0x7f0fff00, 0x7f0fffff) AM_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, map) ADDRESS_MAP_END @@ -382,7 +353,24 @@ ADDRESS_MAP_START(turquoise_state::turquoise_base_map) AM_IMPORT_FROM(interpro_common_map) AM_RANGE(0x40000000, 0x4000003f) AM_DEVICE(INTERPRO_MCGA_TAG, interpro_mcga_device, map) + + // scsi registers have unusual address mapping + AM_RANGE(0x7f000200, 0x7f000203) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_lo_r, tcount_lo_w, 0x0000ff00) + AM_RANGE(0x7f000204, 0x7f000207) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_hi_r, tcount_hi_w, 0x0000ff00) + AM_RANGE(0x7f000208, 0x7f00020b) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_r, fifo_w, 0x0000ff00) + AM_RANGE(0x7f00020c, 0x7f00020f) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, command_r, command_w, 0x0000ff00) + AM_RANGE(0x7f000210, 0x7f000213) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, status_r, bus_id_w, 0x0000ff00) + AM_RANGE(0x7f000214, 0x7f000217) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, istatus_r, timeout_w, 0x0000ff00) + AM_RANGE(0x7f000218, 0x7f00021b) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, seq_step_r, sync_period_w, 0x0000ff00) + AM_RANGE(0x7f00021c, 0x7f00021f) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_flags_r, sync_offset_w, 0x0000ff00) + AM_RANGE(0x7f000220, 0x7f000223) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf_r, conf_w, 0x0000ff00) + AM_RANGE(0x7f000224, 0x7f000227) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, clock_w, 0x0000ff00) + AM_RANGE(0x7f000228, 0x7f00022b) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, test_w, 0x0000ff00) + AM_RANGE(0x7f00022c, 0x7f00022f) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf2_r, conf2_w, 0x0000ff00) + AM_RANGE(0x7f000300, 0x7f000303) AM_WRITE8(sreg_error_w, 0x000000ff) + + AM_RANGE(0x7f000600, 0x7f00067f) AM_ROM AM_REGION(INTERPRO_NODEID_TAG, 0) ADDRESS_MAP_END ADDRESS_MAP_START(turquoise_state::turquoise_main_map) @@ -396,6 +384,23 @@ ADDRESS_MAP_START(sapphire_state::sapphire_base_map) AM_IMPORT_FROM(interpro_common_map) AM_RANGE(0x40000000, 0x4000004f) AM_DEVICE(INTERPRO_MCGA_TAG, interpro_fmcc_device, map) + AM_RANGE(0x7f000200, 0x7f0002ff) AM_DEVICE(INTERPRO_ARBGA_TAG, interpro_arbga_device, map) + + AM_RANGE(0x7f000600, 0x7f00060f) AM_READ8(nodeid_r, 0xff) + + // scsi registers have unusual address mapping + AM_RANGE(0x7f001000, 0x7f001003) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, tcounter_lo_r, tcount_lo_w, 0x0000ff00) + AM_RANGE(0x7f001100, 0x7f001103) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, tcounter_hi_r, tcount_hi_w, 0x0000ff00) + AM_RANGE(0x7f001200, 0x7f001203) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, fifo_r, fifo_w, 0x0000ff00) + AM_RANGE(0x7f001300, 0x7f001303) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, command_r, command_w, 0x0000ff00) + AM_RANGE(0x7f001400, 0x7f001403) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, status_r, bus_id_w, 0x0000ff00) + AM_RANGE(0x7f001500, 0x7f001503) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, istatus_r, timeout_w, 0x0000ff00) + AM_RANGE(0x7f001600, 0x7f001603) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, seq_step_r, sync_period_w, 0x0000ff00) + AM_RANGE(0x7f001700, 0x7f001703) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, fifo_flags_r, sync_offset_w, 0x0000ff00) + AM_RANGE(0x7f001800, 0x7f001803) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, conf_r, conf_w, 0x0000ff00) + AM_RANGE(0x7f001900, 0x7f001903) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, clock_w, 0x0000ff00) + AM_RANGE(0x7f001a00, 0x7f001a03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, test_w, 0x0000ff00) + AM_RANGE(0x7f001b00, 0x7f001b03) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, conf2_r, conf2_w, 0x0000ff00) AM_RANGE(0x7f001c00, 0x7f001c03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, conf3_w, 0x0000ff00) AM_RANGE(0x7f001f00, 0x7f001f03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, fifo_align_w, 0x0000ff00) ADDRESS_MAP_END @@ -448,9 +453,8 @@ static SLOT_INTERFACE_START(interpro_floppies) SLOT_INTERFACE("35hd", FLOPPY_35_HD) SLOT_INTERFACE_END -MACHINE_CONFIG_START(interpro_state::interpro_serial1) - MCFG_SCC85C30_ADD(INTERPRO_SCC1_TAG, XTAL(4'915'200), 0, 0, 0, 0) - +MACHINE_CONFIG_START(interpro_state::interpro_scc1) + MCFG_DEVICE_MODIFY(INTERPRO_SCC1_TAG) MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(INTERPRO_SERIAL_PORT1_TAG, rs232_port_device, write_txd)) MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(INTERPRO_SERIAL_PORT2_TAG, rs232_port_device, write_txd)) MCFG_Z80SCC_OUT_INT_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir11_w)) @@ -468,8 +472,8 @@ MACHINE_CONFIG_START(interpro_state::interpro_serial1) MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, ctsb_w)) MACHINE_CONFIG_END -MACHINE_CONFIG_START(interpro_state::interpro_serial2) - MCFG_SCC85C30_ADD(INTERPRO_SCC2_TAG, XTAL(4'915'200), 0, 0, 0, 0) +MACHINE_CONFIG_START(interpro_state::interpro_scc2) + MCFG_DEVICE_MODIFY(INTERPRO_SCC2_TAG) MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(INTERPRO_KEYBOARD_PORT_TAG, interpro_keyboard_port_device, write_txd)) MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(INTERPRO_SERIAL_PORT0_TAG, rs232_port_device, write_txd)) MCFG_Z80SCC_OUT_INT_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir11_w)) @@ -542,9 +546,6 @@ MACHINE_CONFIG_START(interpro_state::interpro) // floppy - // srx arbiter gate array - MCFG_DEVICE_ADD(INTERPRO_ARBGA_TAG, INTERPRO_ARBGA, 0) - // serial // real-time clock/non-volatile memory @@ -557,8 +558,8 @@ MACHINE_CONFIG_START(interpro_state::interpro) MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":0", interpro_scsi_devices, "harddisk", false) MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":1", interpro_scsi_devices, nullptr, false) MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":2", interpro_scsi_devices, nullptr, false) - MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":3", interpro_scsi_devices, "cdrom", false) - MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":4", interpro_scsi_devices, nullptr, false) + MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":3", interpro_scsi_devices, nullptr, false) + MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":4", interpro_scsi_devices, "cdrom", false) MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":5", interpro_scsi_devices, nullptr, false) MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":6", interpro_scsi_devices, nullptr, false) @@ -568,32 +569,29 @@ MACHINE_CONFIG_START(interpro_state::interpro) // sr bus and slots MCFG_DEVICE_ADD(INTERPRO_SRBUS_TAG, SR, 0) + MCFG_SR_OUT_IRQ0_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir6_w)) MCFG_SR_SLOT_ADD(INTERPRO_SRBUS_TAG, INTERPRO_SRBUS_TAG ":0", sr_cards, "mpcb963", false) MCFG_SR_SLOT_ADD(INTERPRO_SRBUS_TAG, INTERPRO_SRBUS_TAG ":1", sr_cards, nullptr, false) // system layout MCFG_DEFAULT_LAYOUT(layout_interpro) + + // software lists + MCFG_SOFTWARE_LIST_ADD("softlist", "interpro") MACHINE_CONFIG_END MACHINE_CONFIG_START(turquoise_state::turquoise) interpro(config); MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER_C300, XTAL(12'500'000)) - MCFG_CPU_PROGRAM_MAP(c300_insn_map) - MCFG_CPU_DATA_MAP(c300_data_map) + MCFG_DEVICE_ADDRESS_MAP(0, turquoise_main_map) + MCFG_DEVICE_ADDRESS_MAP(1, turquoise_io_map) + MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map) MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, acknowledge_interrupt) MCFG_DEVICE_ADD(INTERPRO_MMU_TAG "_i", CAMMU_C3, 0) - MCFG_DEVICE_ADDRESS_MAP(0, turquoise_main_map) - MCFG_DEVICE_ADDRESS_MAP(1, turquoise_io_map) - MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map) - MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, get_ssw)) MCFG_CAMMU_EXCEPTION_CB(DEVWRITE16(INTERPRO_CPU_TAG, clipper_device, set_exception)) MCFG_DEVICE_ADD(INTERPRO_MMU_TAG "_d", CAMMU_C3, 0) - MCFG_DEVICE_ADDRESS_MAP(0, turquoise_main_map) - MCFG_DEVICE_ADDRESS_MAP(1, turquoise_io_map) - MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map) - MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, get_ssw)) MCFG_CAMMU_EXCEPTION_CB(DEVWRITE16(INTERPRO_CPU_TAG, clipper_device, set_exception)) MCFG_CAMMU_LINK(INTERPRO_MMU_TAG "_i") @@ -617,8 +615,10 @@ MACHINE_CONFIG_START(turquoise_state::turquoise) MCFG_FLOPPY_DRIVE_SOUND(false) // serial controllers and ports - interpro_serial1(config); - interpro_serial2(config); + MCFG_SCC85C30_ADD(INTERPRO_SCC1_TAG, XTAL(4'915'200), 0, 0, 0, 0) + interpro_scc1(config); + MCFG_SCC85C30_ADD(INTERPRO_SCC2_TAG, XTAL(4'915'200), 0, 0, 0, 0) + interpro_scc2(config); // scsi controller MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":7", turquoise_scsi_devices, INTERPRO_SCSI_ADAPTER_TAG, true) @@ -631,25 +631,23 @@ MACHINE_CONFIG_START(turquoise_state::turquoise) // i/o gate array MCFG_DEVICE_ADD(INTERPRO_IOGA_TAG, TURQUOISE_IOGA, 0) - MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_MMU_TAG "_d", 0) + MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_CPU_TAG, 0) ioga(config); MCFG_DEVICE_MODIFY(INTERPRO_SRBUS_TAG) - MCFG_SR_MEMORY(INTERPRO_MMU_TAG "_d", 0, 1) + MCFG_SR_MEMORY(INTERPRO_CPU_TAG, 0, 1) MACHINE_CONFIG_END MACHINE_CONFIG_START(sapphire_state::sapphire) interpro(config); MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER_C400, XTAL(12'500'000)) - MCFG_CPU_PROGRAM_MAP(c400_insn_map) - MCFG_CPU_DATA_MAP(c400_data_map) - MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, acknowledge_interrupt) - - MCFG_DEVICE_ADD(INTERPRO_MMU_TAG, CAMMU_C4T, 0) MCFG_DEVICE_ADDRESS_MAP(0, sapphire_main_map) MCFG_DEVICE_ADDRESS_MAP(1, sapphire_io_map) MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map) - MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, get_ssw)) + MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, acknowledge_interrupt) + + // FIXME: 2400/6400 should be C4T cammu? + MCFG_DEVICE_ADD(INTERPRO_MMU_TAG, CAMMU_C4I, 0) MCFG_CAMMU_EXCEPTION_CB(DEVWRITE16(INTERPRO_CPU_TAG, clipper_device, set_exception)) // memory control gate array @@ -665,22 +663,27 @@ MACHINE_CONFIG_START(sapphire_state::sapphire) MCFG_FLOPPY_DRIVE_ADD("fdc:1", interpro_floppies, "35hd", interpro_state::floppy_formats) MCFG_FLOPPY_DRIVE_SOUND(false) + // srx arbiter gate array + MCFG_DEVICE_ADD(INTERPRO_ARBGA_TAG, INTERPRO_ARBGA, 0) + // serial controllers and ports - interpro_serial1(config); - interpro_serial2(config); + MCFG_SCC85230_ADD(INTERPRO_SCC1_TAG, XTAL(4'915'200), 0, 0, 0, 0) + interpro_scc1(config); + MCFG_SCC85C30_ADD(INTERPRO_SCC2_TAG, XTAL(4'915'200), 0, 0, 0, 0) + interpro_scc2(config); // scsi controller MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":7", sapphire_scsi_devices, INTERPRO_SCSI_ADAPTER_TAG, true) MCFG_DEVICE_CARD_MACHINE_CONFIG(INTERPRO_SCSI_ADAPTER_TAG, interpro_scsi_adapter) // ethernet controller - MCFG_DEVICE_ADD(INTERPRO_ETH_TAG, I82596_LE32, XTAL(20'000'000)) + MCFG_DEVICE_ADD(INTERPRO_ETH_TAG, I82596_LE16, XTAL(20'000'000)) MCFG_I82586_IRQ_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir12_w)) MCFG_DEVICE_ADDRESS_MAP(0, interpro_82596_map) // i/o gate array MCFG_DEVICE_ADD(INTERPRO_IOGA_TAG, SAPPHIRE_IOGA, 0) - MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_MMU_TAG, 0) + MCFG_INTERPRO_IOGA_MEMORY(INTERPRO_CPU_TAG, 0) ioga(config); // flash memory @@ -689,42 +692,72 @@ MACHINE_CONFIG_START(sapphire_state::sapphire) // sr bus address spaces MCFG_DEVICE_MODIFY(INTERPRO_SRBUS_TAG) - MCFG_SR_MEMORY(INTERPRO_MMU_TAG, 0, 1) + MCFG_SR_MEMORY(INTERPRO_CPU_TAG, 0, 1) MACHINE_CONFIG_END MACHINE_CONFIG_START(turquoise_state::ip2000) turquoise(config); //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) //MCFG_DEVICE_CLOCK(XTAL(40'000'000)) + + MCFG_SOFTWARE_LIST_FILTER("softlist", "2000") MACHINE_CONFIG_END MACHINE_CONFIG_START(sapphire_state::ip2400) sapphire(config); //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) - //MCFG_DEVICE_CLOCK(XTAL(40'000'000)) + //MCFG_DEVICE_CLOCK(XTAL(50'000'000)) + + MCFG_DEVICE_MODIFY(INTERPRO_MMU_TAG) + MCFG_CAMMU_ID(cammu_c4i_device::CID_C4IR0) + + MCFG_DEVICE_MODIFY(INTERPRO_SRBUS_TAG ":0") + MCFG_SLOT_DEFAULT_OPTION("mpcb070") + + MCFG_SOFTWARE_LIST_FILTER("softlist", "2400") MACHINE_CONFIG_END MACHINE_CONFIG_START(sapphire_state::ip2500) sapphire(config); //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) - //MCFG_DEVICE_CLOCK(XTAL(50'000'000)) + //MCFG_DEVICE_CLOCK(XTAL(?) + + // FIXME: don't know which cammu revision + MCFG_DEVICE_MODIFY(INTERPRO_MMU_TAG) + MCFG_CAMMU_ID(cammu_c4i_device::CID_C4IR0) + + MCFG_SOFTWARE_LIST_FILTER("softlist", "2500") MACHINE_CONFIG_END MACHINE_CONFIG_START(sapphire_state::ip2700) sapphire(config); //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) - //MCFG_DEVICE_CLOCK(XTAL_70MHz) + //MCFG_DEVICE_CLOCK(?) + + MCFG_DEVICE_MODIFY(INTERPRO_MMU_TAG) + MCFG_CAMMU_ID(cammu_c4i_device::CID_C4IR2) + + MCFG_SOFTWARE_LIST_FILTER("softlist", "2700") MACHINE_CONFIG_END MACHINE_CONFIG_START(sapphire_state::ip2800) sapphire(config); //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) - //MCFG_DEVICE_CLOCK(XTAL_80MHz) + //MCFG_DEVICE_CLOCK(?) + + // FIXME: don't know which cammu revision + MCFG_DEVICE_MODIFY(INTERPRO_MMU_TAG) + MCFG_CAMMU_ID(cammu_c4i_device::CID_C4IR2) + + MCFG_SOFTWARE_LIST_FILTER("softlist", "2800") MACHINE_CONFIG_END ROM_START(ip2000) + ROM_REGION(0x80, INTERPRO_NODEID_TAG, 0) + ROM_LOAD32_BYTE("nodeid.bin", 0x0, 0x20, CRC(a38397a6) SHA1(9f45fb932bbe231c95b3d5470dcd1fa1c846486f)) + ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) - ROM_LOAD32_BYTE("mpcb962a.bin", 0x0, 0x20, CRC(712f5ba9) SHA1(93ccdcb68be4038bb35b02cee612927ad4451190)) + ROM_LOAD32_BYTE("mpcb962a.bin", 0x0, 0x20, CRC(e391342c) SHA1(02e03aad760b6651b8599c3a41c7c457983ee97d)) ROM_REGION(0x0040000, INTERPRO_EPROM_TAG, 0) ROM_SYSTEM_BIOS(0, "ip2000", "InterPro 2000 EPROM") @@ -734,7 +767,7 @@ ROM_END ROM_START(ip2400) ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) - ROM_LOAD32_BYTE("msmt047a.bin", 0x0, 0x20, CRC(3078d84d) SHA1(2876b8b8054bb7528680d259fea428db6f1712b4)) + ROM_LOAD32_BYTE("msmt0470.bin", 0x0, 0x20, CRC(498c80df) SHA1(18a49732ac9d04b20a77747c1b946c2e88abb087)) ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0) ROM_SYSTEM_BIOS(0, "ip2400", "InterPro 2400 EPROM") @@ -749,7 +782,7 @@ ROM_END ROM_START(ip2500) ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) - ROM_LOAD32_BYTE("msmt100a.bin", 0x0, 0x20, CRC(46647cdf) SHA1(581a3424a9b7028e619a7f03fa86ebdee3cf2494)) + ROM_LOAD32_BYTE("msmt1000.bin", 0x0, 0x20, CRC(548046c0) SHA1(ce7646e868f3aa35642d7f9348f6b9e91693918e)) ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0) ROM_SYSTEM_BIOS(0, "ip2500", "InterPro 2500 EPROM") @@ -764,7 +797,7 @@ ROM_END ROM_START(ip2700) ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) - ROM_LOAD32_BYTE("msmt128a.bin", 0x0, 0x20, CRC(6d8e68e8) SHA1(a649097df730c79b03bbf777b788f0721e072f03)) + ROM_LOAD32_BYTE("msmt1280.bin", 0x0, 0x20, CRC(32d833af) SHA1(7225c5f5670fe49d86556a2cb453ae6fe09e3e19)) ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0) ROM_SYSTEM_BIOS(0, "ip2700", "InterPro 2700 EPROM") @@ -779,7 +812,7 @@ ROM_END ROM_START(ip2800) ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) - ROM_LOAD32_BYTE("msmt145a.bin", 0x0, 0x20, CRC(e1c265e3) SHA1(105d646552d56c7af2f403aac1aa97b047b6a50e)) + ROM_LOAD32_BYTE("msmt1450.bin", 0x0, 0x20, CRC(61c7a305) SHA1(efcd045cbdfda8df44eaad761b0ba99367973cd7)) ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0) ROM_SYSTEM_BIOS(0, "ip2800", "InterPro 2800 EPROM") @@ -793,8 +826,8 @@ ROM_START(ip2800) ROM_END /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP( 1989, ip2000, 0, 0, ip2000, interpro, turquoise_state, turquoise, "Intergraph", "InterPro 2000", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) -COMP( 1991?, ip2400, 0, 0, ip2400, interpro, sapphire_state, sapphire, "Intergraph", "InterPro 2400", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) -COMP( 1993?, ip2500, 0, 0, ip2500, interpro, sapphire_state, sapphire, "Intergraph", "InterPro 2500", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) -COMP( 1992, ip2700, 0, 0, ip2700, interpro, sapphire_state, sapphire, "Intergraph", "InterPro 2700", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) -COMP( 1994, ip2800, 0, 0, ip2800, interpro, sapphire_state, sapphire, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1990, ip2000, 0, 0, ip2000, interpro, turquoise_state, common, "Intergraph", "InterPro 2000", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1992, ip2400, 0, 0, ip2400, interpro, sapphire_state, common, "Intergraph", "InterPro 2400", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1993, ip2500, 0, 0, ip2500, interpro, sapphire_state, common, "Intergraph", "InterPro 2500", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1993, ip2700, 0, 0, ip2700, interpro, sapphire_state, common, "Intergraph", "InterPro 2700", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1994, ip2800, 0, 0, ip2800, interpro, sapphire_state, common, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) diff --git a/src/mame/includes/interpro.h b/src/mame/includes/interpro.h index c340ff99f28..676affa2fb2 100644 --- a/src/mame/includes/interpro.h +++ b/src/mame/includes/interpro.h @@ -33,9 +33,10 @@ #include "bus/interpro/keyboard/keyboard.h" #include "formats/pc_dsk.h" +#include "softlist.h" #define INTERPRO_CPU_TAG "cpu" -#define INTERPRO_MMU_TAG "mmu" +#define INTERPRO_MMU_TAG "cammu" #define INTERPRO_MCGA_TAG "mcga" #define INTERPRO_SGA_TAG "sga" #define INTERPRO_FDC_TAG "fdc" @@ -53,6 +54,7 @@ #define INTERPRO_ETH_TAG "eth" #define INTERPRO_IOGA_TAG "ioga" +#define INTERPRO_NODEID_TAG "nodeid" #define INTERPRO_IDPROM_TAG "idprom" #define INTERPRO_EPROM_TAG "eprom" #define INTERPRO_FLASH_TAG "flash" @@ -69,12 +71,10 @@ public: , m_mcga(*this, INTERPRO_MCGA_TAG) , m_sga(*this, INTERPRO_SGA_TAG) , m_fdc(*this, INTERPRO_FDC_TAG) - , m_arbga(*this, INTERPRO_ARBGA_TAG) , m_scc1(*this, INTERPRO_SCC1_TAG) , m_scc2(*this, INTERPRO_SCC2_TAG) , m_rtc(*this, INTERPRO_RTC_TAG) , m_scsibus(*this, INTERPRO_SCSI_TAG) - , m_scsi(*this, INTERPRO_SCSI_DEVICE_TAG) , m_eth(*this, INTERPRO_ETH_TAG) , m_ioga(*this, INTERPRO_IOGA_TAG) { @@ -86,12 +86,10 @@ public: required_device m_mcga; required_device m_sga; required_device m_fdc; - required_device m_arbga; required_device m_scc1; required_device m_scc2; required_device m_rtc; required_device m_scsibus; - required_device m_scsi; required_device m_eth; required_device m_ioga; @@ -156,22 +154,16 @@ public: DECLARE_READ8_MEMBER(nodeid_r); - DECLARE_READ32_MEMBER(unmapped_r); - DECLARE_WRITE32_MEMBER(unmapped_w); - DECLARE_FLOPPY_FORMATS(floppy_formats); void ioga(machine_config &config); - void interpro_serial1(machine_config &config); - void interpro_serial2(machine_config &config); + void interpro_scc1(machine_config &config); + void interpro_scc2(machine_config &config); void interpro(machine_config &config); static void interpro_scsi_adapter(device_t *device); - void c300_data_map(address_map &map); - void c300_insn_map(address_map &map); - void c400_data_map(address_map &map); - void c400_insn_map(address_map &map); void interpro_boot_map(address_map &map); void interpro_common_map(address_map &map); + protected: virtual void machine_start() override; virtual void machine_reset() override; @@ -192,15 +184,16 @@ public: : interpro_state(mconfig, type, tag) , m_d_cammu(*this, INTERPRO_MMU_TAG "_d") , m_i_cammu(*this, INTERPRO_MMU_TAG "_i") + , m_scsi(*this, INTERPRO_SCSI_DEVICE_TAG) { } - DECLARE_DRIVER_INIT(turquoise); - DECLARE_WRITE8_MEMBER(sreg_error_w) { m_sreg_error = data; } required_device m_d_cammu; required_device m_i_cammu; + required_device m_scsi; + void turquoise(machine_config &config); void ip2000(machine_config &config); void interpro_82586_map(address_map &map); @@ -215,19 +208,23 @@ public: sapphire_state(const machine_config &mconfig, device_type type, const char *tag) : interpro_state(mconfig, type, tag) , m_mmu(*this, INTERPRO_MMU_TAG) + , m_scsi(*this, INTERPRO_SCSI_DEVICE_TAG) + , m_arbga(*this, INTERPRO_ARBGA_TAG) , m_flash_lo(*this, INTERPRO_FLASH_TAG "_lo") , m_flash_hi(*this, INTERPRO_FLASH_TAG "_hi") { } - DECLARE_DRIVER_INIT(sapphire); - virtual DECLARE_WRITE16_MEMBER(sreg_ctrl2_w) override; + DECLARE_READ32_MEMBER(unmapped_r); + DECLARE_WRITE32_MEMBER(unmapped_w); required_device m_mmu; - + required_device m_scsi; + required_device m_arbga; required_device m_flash_lo; required_device m_flash_hi; + void sapphire(machine_config &config); void ip2500(machine_config &config); void ip2400(machine_config &config); diff --git a/src/mame/machine/cammu.cpp b/src/mame/machine/cammu.cpp index 11dafe2bfbc..99f783f4128 100644 --- a/src/mame/machine/cammu.cpp +++ b/src/mame/machine/cammu.cpp @@ -23,7 +23,6 @@ * * TODO * - fault register values - * - alignment faults * - c3 protection faults * - hard-wired and dynamic tlb * - cache @@ -112,18 +111,17 @@ DEFINE_DEVICE_TYPE(CAMMU_C4I, cammu_c4i_device, "c4i", "C4I CAMMU") DEFINE_DEVICE_TYPE(CAMMU_C3, cammu_c3_device, "c3", "C1/C3 CAMMU") cammu_c4t_device::cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : cammu_c4_device(mconfig, CAMMU_C4T, tag, owner, clock, CID_C4T) + : cammu_c4_device(mconfig, CAMMU_C4T, tag, owner, clock) { } cammu_c4i_device::cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : cammu_c4_device(mconfig, CAMMU_C4I, tag, owner, clock, CID_C4I) + : cammu_c4_device(mconfig, CAMMU_C4I, tag, owner, clock) { } -cammu_c4_device::cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 cammu_id) +cammu_c4_device::cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : cammu_device(mconfig, type, tag, owner, clock) - , m_control(cammu_id) { } @@ -136,42 +134,13 @@ cammu_c3_device::cammu_c3_device(const machine_config &mconfig, const char *tag, cammu_device::cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, type, tag, owner, clock) - , device_memory_interface(mconfig, *this) - , m_main_space_config("main", ENDIANNESS_LITTLE, 32, 32, 0) - , m_io_space_config("io", ENDIANNESS_LITTLE, 32, 32, 0) - , m_boot_space_config("boot", ENDIANNESS_LITTLE, 32, 32, 0) - , m_main_space(nullptr) - , m_io_space(nullptr) - , m_boot_space(nullptr) - , m_ssw_func(*this) , m_exception_func(*this) { } -device_memory_interface::space_config_vector cammu_device::memory_space_config() const -{ - return space_config_vector { - std::make_pair(0, &m_main_space_config), - std::make_pair(1, &m_io_space_config), - std::make_pair(2, &m_boot_space_config) - }; -} - -void cammu_c3_device::static_add_linked(device_t &device, const char *const tag) -{ - cammu_c3_device &parent = downcast(device); - - parent.m_linked.push_back(downcast(parent.siblingdevice(tag))); -} - void cammu_device::device_start() { - m_ssw_func.resolve(); m_exception_func.resolve(); - - m_main_space = &space(0); - m_io_space = &space(1); - m_boot_space = &space(2); } void cammu_device::device_reset() @@ -246,238 +215,168 @@ void cammu_c3_device::device_reset() m_reset = 0; } -READ32_MEMBER(cammu_device::read) +void cammu_device::set_spaces(std::vector spaces) { - const u32 virtual_address = (offset << 2) | ( - (mem_mask & 0x00ffffff) == 0 ? 0x3 : - (mem_mask & 0x0000ffff) == 0 ? 0x2 : - (mem_mask & 0x000000ff) == 0 ? 0x1 : 0x0); - offs_t physical_address; + assert_always(spaces.size() == 8, "exactly 8 address space pointers are required"); - LOGMASKED(LOG_ACCESS, "%s read address 0x%08x mem_mask 0x%08x (%s)\n", - space.name(), virtual_address, mem_mask, machine().describe_context()); - - address_space *physical_space = translate_address(virtual_address, space.spacenum() == AS_PROGRAM ? ACCESS_X : ACCESS_R, &physical_address); - - if (physical_space != nullptr) - return physical_space->read_dword(physical_address, mem_mask); - else - return space.unmap(); + for (int i = 0; i < spaces.size(); i++) + m_space[i] = spaces[i]; } -WRITE32_MEMBER(cammu_device::write) +cammu_device::translated_t cammu_device::translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode) { - const u32 virtual_address = (offset << 2) | ( - (mem_mask & 0x00ffffff) == 0 ? 0x3 : - (mem_mask & 0x0000ffff) == 0 ? 0x2 : - (mem_mask & 0x000000ff) == 0 ? 0x1 : 0x0); - offs_t physical_address; + // get effective user/supervisor mode + const bool user = mode == EXECUTE ? ssw & SSW_U : ssw & (SSW_U | SSW_UU); - LOGMASKED(LOG_ACCESS, "%s write address 0x%08x data 0x%08x mem_mask 0x%08x (%s)\n", - space.name(), virtual_address, data, mem_mask, machine().describe_context()); + // check for alignment faults + if (get_alignment() && !machine().side_effects_disabled()) + { + if ((mode == EXECUTE && (virtual_address & 0x1)) || (mode != EXECUTE && virtual_address & (size - 1))) + { + set_fault_address(virtual_address); + m_exception_func(mode == EXECUTE ? EXCEPTION_I_ALIGNMENT_FAULT : EXCEPTION_D_ALIGNMENT_FAULT); - address_space *physical_space = translate_address(virtual_address, ACCESS_W, &physical_address); - - if (physical_space != nullptr) - physical_space->write_dword(physical_address, data, mem_mask); -} - -address_space *cammu_device::translate_address(const offs_t virtual_address, const access_t mode, offs_t *physical_address) -{ - // get ssw and user/supervisor mode - const u32 ssw = m_ssw_func(); - const bool user = mode == ACCESS_X ? ssw & SSW_U : ssw & (SSW_U | SSW_UU); - - // TODO: check for alignment faults + return { nullptr, 0 }; + } + } // in supervisor mode, the first 8 pages are always mapped via the hard-wired tlb if (!user && (virtual_address & ~0x7fff) == 0) { switch (virtual_address & 0x7000) { - case 0x0000: - case 0x1000: - case 0x2000: - case 0x3000: // pages 0-3: main space pages 0-3 - *physical_address = virtual_address & 0x3fff; - return m_main_space; + case 0x0000: return { m_space[ST1], virtual_address & 0x3fff }; + case 0x1000: return { m_space[ST2], virtual_address & 0x3fff }; + case 0x2000: return { m_space[ST3], virtual_address & 0x3fff }; + case 0x3000: return { m_space[ST3], virtual_address & 0x3fff }; - case 0x4000: - case 0x5000: // pages 4-5: i/o space pages 0-1 - *physical_address = virtual_address & 0x1fff; - return m_io_space; + case 0x4000: return { m_space[ST4], virtual_address & 0x1fff }; + case 0x5000: return { m_space[ST4], virtual_address & 0x1fff }; - case 0x6000: - case 0x7000: // pages 6-7: boot space pages 0-1 - *physical_address = virtual_address & 0x1fff; - return m_boot_space; + case 0x6000: return { m_space[ST5], virtual_address & 0x1fff }; + case 0x7000: return { m_space[ST5], virtual_address & 0x1fff }; } } // if not in mapped mode, use unmapped system tag if ((ssw & SSW_M) == 0) - { - *physical_address = virtual_address; - - return get_ust_space(); - } + return { m_space[get_ust_space()], virtual_address }; // get the page table entry - const u32 pte = get_pte(virtual_address, user); + pte_t pte = get_pte(virtual_address, user); // check for page faults - if (pte & PTE_F) + if (pte.entry & PTE_F) { if (!machine().side_effects_disabled()) { LOG("%s page fault address 0x%08x ssw 0x%08x pte 0x%08x (%s)\n", - mode == ACCESS_X ? "instruction" : "data", - virtual_address, ssw, pte, machine().describe_context()); + mode == EXECUTE ? "instruction" : "data", + virtual_address, ssw, pte.entry, machine().describe_context()); set_fault_address(virtual_address); - m_exception_func(mode == ACCESS_X ? EXCEPTION_I_PAGE_FAULT : EXCEPTION_D_PAGE_FAULT); + m_exception_func(mode == EXECUTE ? EXCEPTION_I_PAGE_FAULT : EXCEPTION_D_PAGE_FAULT); } - return nullptr; + return { nullptr, 0 }; } // check for protection level faults - if (!machine().side_effects_disabled() && !get_access(mode, pte, ssw)) + if (!machine().side_effects_disabled() && !get_access(mode, pte.entry, ssw)) { LOG("%s protection fault address 0x%08x ssw 0x%08x pte 0x%08x (%s)\n", - mode == ACCESS_X ? "execute" : mode == ACCESS_R ? "read" : "write", - virtual_address, ssw, pte, machine().describe_context()); + mode == EXECUTE ? "execute" : mode == READ ? "read" : "write", + virtual_address, ssw, pte.entry, machine().describe_context()); set_fault_address(virtual_address); m_exception_func( - mode == ACCESS_X ? EXCEPTION_I_EXECUTE_PROTECT_FAULT : - mode == ACCESS_R ? EXCEPTION_D_READ_PROTECT_FAULT : + mode == EXECUTE ? EXCEPTION_I_EXECUTE_PROTECT_FAULT : + mode == READ ? EXCEPTION_D_READ_PROTECT_FAULT : EXCEPTION_D_WRITE_PROTECT_FAULT); - return nullptr; + return { nullptr, 0 }; } + // set pte referenced and dirty flags + if (mode & WRITE && !(pte.entry & PTE_D)) + m_space[ST0]->write_dword(pte.address, pte.entry | PTE_D | PTE_R); + else if (!(pte.entry & PTE_R)) + m_space[ST0]->write_dword(pte.address, pte.entry | PTE_R); + // translate the address - *physical_address = (pte & ~CAMMU_PAGE_MASK) | (virtual_address & CAMMU_PAGE_MASK); - LOGMASKED(LOG_DTU, "%s address translated 0x%08x\n", mode == ACCESS_X ? "instruction" : "data", *physical_address); + LOGMASKED(LOG_DTU, "%s address translated 0x%08x\n", mode == EXECUTE ? "instruction" : "data", + (pte.entry & ~CAMMU_PAGE_MASK) | (virtual_address & CAMMU_PAGE_MASK)); - // return the physical space based on the system tag - switch (pte & PTE_ST) - { - case ST_0: - case ST_1: - case ST_2: - case ST_3: - // main memory space - return m_main_space; - - case ST_4: - // i/o space - return m_io_space; - - case ST_5: - // boot space - return m_boot_space; - - case ST_6: - // cache purge - case ST_7: - // main memory, slave mode - if (!machine().side_effects_disabled()) - fatalerror("%s page table entry system tag %d not supported\n", - mode == ACCESS_X ? "instruction" : "data", (pte & PTE_ST) >> 9); - break; - } - - return nullptr; + // return the system tag and translated address + return { m_space[system_tag_t((pte.entry & PTE_ST) >> PTE_ST_SHIFT)], (pte.entry & ~CAMMU_PAGE_MASK) | (virtual_address & CAMMU_PAGE_MASK) }; } // return the page table entry for a given virtual address -u32 cammu_device::get_pte(const u32 va, const bool user) +cammu_device::pte_t cammu_device::get_pte(const u32 va, const bool user) { - const u32 tlb_index = user ? 1 : 0; - if ((va & ~CAMMU_PAGE_MASK) != m_tlb[tlb_index].va) - { - // get page table directory origin from user or supervisor pdo register - const u32 pdo = get_pdo(user); + // get page table directory origin from user or supervisor pdo register + const u32 pdo = get_pdo(user); - // get page table directory index from top 12 bits of virtual address - const u32 ptdi = (va & VA_PTDI) >> 20; + // get page table directory index from top 12 bits of virtual address + const u32 ptdi = (va & VA_PTDI) >> 20; - // fetch page table directory entry - const u32 ptde = m_main_space->read_dword(pdo | ptdi); + // fetch page table directory entry + const u32 ptde = m_space[ST0]->read_dword(pdo | ptdi); - LOGMASKED(LOG_DTU, "get_pte pdo 0x%08x ptdi 0x%08x ptde 0x%08x\n", pdo, ptdi, ptde); + LOGMASKED(LOG_DTU, "get_pte pdo 0x%08x ptdi 0x%08x ptde 0x%08x\n", pdo, ptdi, ptde); - // check for page table directory entry fault - if (ptde & PTDE_F) - return PTE_F; + // check for page table directory entry fault + if (ptde & PTDE_F) + return { PTE_F, pdo | ptdi }; - // get the page table origin from the page table directory entry - const u32 pto = ptde & PTDE_PTO; + // get the page table origin from the page table directory entry + const u32 pto = ptde & PTDE_PTO; - // get the page table index from the middle 12 bits of the virtual address - const u32 pti = (va & VA_PTI) >> 10; + // get the page table index from the middle 12 bits of the virtual address + const u32 pti = (va & VA_PTI) >> 10; - // fetch page table entry - const u32 pte = m_main_space->read_dword(pto | pti); + // fetch page table entry + pte_t pte = { m_space[ST0]->read_dword(pto | pti), pto | pti }; - LOGMASKED(LOG_DTU, "get_pte pto 0x%08x pti 0x%08x pte 0x%08x\n", pto, pti, pte); + LOGMASKED(LOG_DTU, "get_pte pto 0x%08x pti 0x%08x pte 0x%08x\n", pto, pti, pte.entry); - // check for page table entry fault - if (pte & PTE_F) - return PTE_F; + // check for page table entry fault + if (!(pte.entry & PTE_F)) + LOGMASKED(LOG_DTU, "get_pte address 0x%08x pte 0x%08x (%s)\n", va, pte.entry, machine().describe_context()); - // add the pte to the tlb - m_tlb[tlb_index].va = va & ~CAMMU_PAGE_MASK; - m_tlb[tlb_index].pte = pte; - - LOGMASKED(LOG_DTU, "get_pte address 0x%08x pte 0x%08x (%s)\n", va, pte, machine().describe_context()); - } - - return m_tlb[tlb_index].pte; + return pte; } -address_space *cammu_c4i_device::get_ust_space() const -{ - switch (m_control & CNTL_UMM) - { - case UMM_MM: return m_main_space; - case UMM_MMRIO: return m_main_space; // FIXME: what determines main or i/o? - case UMM_IO: return m_io_space; - } - - return m_main_space; -} - -bool cammu_c4_device::get_access(const access_t mode, const u32 pte, const u32 ssw) const +bool cammu_c4_device::get_access(const access_type mode, const u32 pte, const u32 ssw) const { switch (mode) { - case ACCESS_R: return pte & 0x20; - case ACCESS_W: return pte & 0x10; - case ACCESS_X: return pte & 0x08; + case READ: return pte & 0x20; + case WRITE: return pte & 0x10; + case RMW: return (pte & 0x30) == 0x30; + case EXECUTE: return pte & 0x08; } return false; } -bool cammu_c3_device::get_access(const access_t mode, const u32 pte, const u32 ssw) const +bool cammu_c3_device::get_access(const access_type mode, const u32 pte, const u32 ssw) const { // FIXME: logic is not correct yet return true; - const u8 column = (mode == ACCESS_X ? i_cammu_column : d_cammu_column)[(ssw & SSW_PL) >> 9]; + const u8 column = (mode == EXECUTE ? i_cammu_column : d_cammu_column)[(ssw & SSW_PL) >> 9]; const u8 access = cammu_matrix[column][(pte & PTE_PL) >> 3]; switch (mode) { - case ACCESS_R: return access & R; - case ACCESS_W: return access & W; - case ACCESS_X: return access & E; + case READ: return access & R; + case WRITE: return access & W; + case RMW: return (access & (R | W)) == (R | W); + case EXECUTE: return access & E; } return false; @@ -494,5 +393,3 @@ const cammu_c3_device::c3_access_t cammu_c3_device::cammu_matrix[][16] = { N, N, RW, RW, RW, R, R, RWE, N, N, RE, RE, N, RE, N, N }, { N, N, N, RW, R, R, R, RWE, N, N, N, RE, RE, N, RE, N } }; - - diff --git a/src/mame/machine/cammu.h b/src/mame/machine/cammu.h index cb38c433aae..a8f6a1d9330 100644 --- a/src/mame/machine/cammu.h +++ b/src/mame/machine/cammu.h @@ -6,53 +6,25 @@ #pragma once -#define MCFG_CAMMU_SSW_CB(_sswcb) \ - devcb = &downcast(*device).set_ssw_callback(DEVCB_##_sswcb); +#include "cpu/clipper/common.h" + +#define MCFG_CAMMU_ID(_id) \ + downcast(*device).set_cammu_id(_id); #define MCFG_CAMMU_EXCEPTION_CB(_exceptioncb) \ devcb = &downcast(*device).set_exception_callback(DEVCB_##_exceptioncb); #define MCFG_CAMMU_LINK(_tag) \ - cammu_c3_device::static_add_linked(*device, _tag); + downcast(*device).add_linked(_tag); -class cammu_device : public device_t, public device_memory_interface +class cammu_device : public device_t { public: - template devcb_base &set_ssw_callback(Object &&cb) { return m_ssw_func.set_callback(std::forward(cb)); } template devcb_base &set_exception_callback(Object &&cb) { return m_exception_func.set_callback(std::forward(cb)); } static const u32 CAMMU_PAGE_SIZE = 0x1000; static const u32 CAMMU_PAGE_MASK = (CAMMU_PAGE_SIZE - 1); - enum ssw_mask : u32 - { - SSW_M = 0x04000000, // mapped mode - SSW_KU = 0x08000000, // user protect key - SSW_UU = 0x10000000, // user data mode - SSW_K = 0x20000000, // protect key - SSW_U = 0x40000000, // user mode - - SSW_PL = 0x78000000 // protection level relevant bits - }; - - enum exception_vectors : u16 - { - // data memory trap group - EXCEPTION_D_CORRECTED_MEMORY_ERROR = 0x108, - EXCEPTION_D_UNCORRECTABLE_MEMORY_ERROR = 0x110, - EXCEPTION_D_ALIGNMENT_FAULT = 0x120, - EXCEPTION_D_PAGE_FAULT = 0x128, - EXCEPTION_D_READ_PROTECT_FAULT = 0x130, - EXCEPTION_D_WRITE_PROTECT_FAULT = 0x138, - - // instruction memory trap group - EXCEPTION_I_CORRECTED_MEMORY_ERROR = 0x288, - EXCEPTION_I_UNCORRECTABLE_MEMORY_ERROR = 0x290, - EXCEPTION_I_ALIGNMENT_FAULT = 0x2a0, - EXCEPTION_I_PAGE_FAULT = 0x2a8, - EXCEPTION_I_EXECUTE_PROTECT_FAULT = 0x2b0, - }; - enum pdo_mask : u32 { PDO_MASK = 0xfffff000 @@ -79,17 +51,7 @@ public: PTE_LOCK = 0x00000100 // page lock (software) }; - enum pte_st_mask : u32 - { - ST_0 = 0x00000000, // private, write-through, main memory space - ST_1 = 0x00000200, // shared, write-through, main memory space - ST_2 = 0x00000400, // private, copy-back, main memory space - ST_3 = 0x00000600, // noncacheable, main memory space - ST_4 = 0x00000800, // noncacheable, i/o space - ST_5 = 0x00000a00, // noncacheable, boot space - ST_6 = 0x00000c00, // cache purge - ST_7 = 0x00000e00 // slave i/o - }; + static const int PTE_ST_SHIFT = 9; enum va_mask : u32 { @@ -98,10 +60,100 @@ public: VA_PTDI = 0xffc00000 // page table directory index }; + enum system_tag_t : u8 + { + ST0 = 0, // private, write-through, main memory space + ST1 = 1, // shared, write-through, main memory space + ST2 = 2, // private, copy-back, main memory space + ST3 = 3, // noncacheable, main memory space + ST4 = 4, // noncacheable, i/o space + ST5 = 5, // noncacheable, boot space + ST6 = 6, // cache purge + ST7 = 7 // slave i/o + }; + virtual void map(address_map &map) = 0; - DECLARE_READ32_MEMBER(read); - DECLARE_WRITE32_MEMBER(write); + void set_spaces(std::vector spaces); + + template std::enable_if_t>::value, bool> load(const u32 ssw, const u32 address, U &&apply) + { + translated_t t = translate_address(ssw, address, access_size(sizeof(T)), READ); + + if (t.space != nullptr) + { + switch (sizeof(T)) + { + case 1: apply(T(t.space->read_byte(t.address))); break; + case 2: apply(T(t.space->read_word(t.address))); break; + case 4: apply(T(t.space->read_dword(t.address))); break; + case 8: apply(T(t.space->read_qword(t.address))); break; + default: fatalerror("unhandled load size %d\n", access_size(sizeof(T))); + } + + return true; + } + else + return false; + } + + template std::enable_if_t::value, bool> store(const u32 ssw, const u32 address, U data) + { + translated_t t = translate_address(ssw, address, access_size(sizeof(T)), WRITE); + + if (t.space != nullptr) + { + switch (sizeof(T)) + { + case 1: t.space->write_byte(t.address, T(data)); break; + case 2: t.space->write_word(t.address, T(data)); break; + case 4: t.space->write_dword(t.address, T(data)); break; + case 8: t.space->write_qword(t.address, T(data)); break; + default: fatalerror("unhandled store size %d\n", access_size(sizeof(T))); + } + + return true; + } + else + return false; + } + + template std::enable_if_t>::value, bool> modify(const u32 ssw, const u32 address, U &&apply) + { + translated_t t = translate_address(ssw, address, access_size(sizeof(T)), RMW); + + if (t.space != nullptr) + { + switch (sizeof(T)) + { + case 4: t.space->write_dword(t.address, apply(T(t.space->read_dword(t.address)))); break; + default: fatalerror("unhandled modify size %d\n", access_size(sizeof(T))); + } + + return true; + } + else + return false; + } + + template std::enable_if_t>::value, bool> fetch(const u32 ssw, const u32 address, U &&apply) + { + translated_t t = translate_address(ssw, address, access_size(sizeof(T)), EXECUTE); + + if (t.space != nullptr) + { + switch (sizeof(T)) + { + case 2: apply(T(t.space->read_word(t.address))); break; + case 4: apply(T(t.space->read_dword_unaligned(t.address))); break; + default: fatalerror("unhandled fetch size %d\n", access_size(sizeof(T))); + } + + return true; + } + else + return false; + } protected: cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); @@ -110,52 +162,55 @@ protected: virtual void device_start() override; virtual void device_reset() override; - // device_memory_interface overrides - virtual space_config_vector memory_space_config() const override; - //virtual bool memory_translate(int spacenum, int intention, offs_t &address) override; - - enum access_t + enum access_size : u8 { - ACCESS_R = 1, - ACCESS_W = 2, - ACCESS_X = 3 + BYTE = 1, + WORD = 2, + DWORD = 4, + QWORD = 8 }; - address_space *translate_address(const offs_t virtual_address, const access_t mode, offs_t *physical_address); + enum access_type : u8 + { + READ = 1, + WRITE = 2, + RMW = 3, + EXECUTE = 4 + }; - u32 get_pte(const u32 va, const bool user); +private: + // address translation + struct translated_t + { + address_space *const space; + const u32 address; + }; + translated_t translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode); - virtual bool get_access(const access_t mode, const u32 pte, const u32 ssw) const = 0; + struct pte_t + { + const u32 entry; + const u32 address; + }; + pte_t get_pte(const u32 va, const bool user); + + // helpers + virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const = 0; virtual bool get_alignment() const = 0; virtual u32 get_pdo(const bool user) const = 0; - virtual address_space *get_ust_space() const = 0; + virtual system_tag_t get_ust_space() const = 0; virtual void set_fault_address(const u32 va) = 0; - address_space_config m_main_space_config; - address_space_config m_io_space_config; - address_space_config m_boot_space_config; - - address_space *m_main_space; - address_space *m_io_space; - address_space *m_boot_space; - - devcb_read32 m_ssw_func; devcb_write16 m_exception_func; - - struct - { - u32 va; - u32 pte; - } - m_tlb[2]; - -private: + address_space *m_space[8]; }; class cammu_c4_device : public cammu_device { public: + void set_cammu_id(const u32 cammu_id) { m_control = cammu_id; } + DECLARE_READ32_MEMBER(s_pdo_r) { return m_s_pdo; } DECLARE_WRITE32_MEMBER(s_pdo_w) { m_s_pdo = ((m_s_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; } DECLARE_READ32_MEMBER(u_pdo_r) { return m_u_pdo; } @@ -180,11 +235,11 @@ public: DECLARE_WRITE32_MEMBER(fault_data_2_hi_w) { m_fault_data_2_hi = data; } protected: - cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, u32 cammu_id); + cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); virtual void device_start() override; - virtual bool get_access(const access_t mode, const u32 pte, const u32 ssw) const override; + virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override; virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; } virtual void set_fault_address(const u32 va) override { m_fault_address_1 = va; } @@ -274,7 +329,7 @@ protected: virtual void device_start() override; virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; } - virtual address_space *get_ust_space() const override { return (m_control & CNTL_IOTS) ? m_io_space : m_main_space; } + virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & (CNTL_IOTS | CNTL_UST)) >> 4); } private: u32 m_ram_line; @@ -333,9 +388,11 @@ public: CRR_OFF = 0x00700000, // refresh off }; + // c4i cammu identification (rev 2 and rev 3 known to have existed) enum control_cid_mask : u32 { - CID_C4I = 0x02000000 // c4i cammu identification + CID_C4IR0 = 0x00000000, + CID_C4IR2 = 0x02000000 }; virtual DECLARE_READ32_MEMBER(control_r) override { return m_control; } @@ -374,7 +431,8 @@ protected: virtual void device_start() override; virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; } - virtual address_space *get_ust_space() const override; + // FIXME: don't really know how unmapped mode works on c4i + virtual system_tag_t get_ust_space() const override { return (m_control & UMM_IO) ? ST4 : ST3; } private: u32 m_reset; @@ -391,11 +449,11 @@ class cammu_c3_device : public cammu_device public: cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - static void static_add_linked(device_t &device, const char *const tag); - virtual void map(address_map &map) override; virtual void map_global(address_map &map); + void add_linked(const char *const tag) { m_linked.push_back(downcast(siblingdevice(tag))); } + enum control_mask : u32 { CNTL_EP = 0x00000001, // enable prefetch @@ -443,10 +501,10 @@ protected: virtual void device_reset() override; virtual void device_start() override; - virtual bool get_access(const access_t mode, const u32 pte, const u32 ssw) const override; + virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override; virtual bool get_alignment() const override { return m_control & CNTL_ATE; } virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; } - virtual address_space *get_ust_space() const override { return m_main_space; } + virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & CNTL_UST) >> 4); } virtual void set_fault_address(const u32 va) override { m_fault = va; } diff --git a/src/mame/machine/interpro_ioga.cpp b/src/mame/machine/interpro_ioga.cpp index 4a009aea1d8..8f3b7865f15 100644 --- a/src/mame/machine/interpro_ioga.cpp +++ b/src/mame/machine/interpro_ioga.cpp @@ -124,6 +124,7 @@ ADDRESS_MAP_START(interpro_ioga_device::map) AM_RANGE(0x94, 0x97) AM_READ(error_address_r) AM_RANGE(0x98, 0x9b) AM_READ(error_businfo_r) AM_RANGE(0x9c, 0x9f) AM_READWRITE16(arbctl_r, arbctl_w, 0x0000ffff) + //AM_RANGE(0x9c, 0x9f) AM_READWRITE16(?, ?, 0xffff0000) // ip2000 boot code writes 0x7f18 AM_RANGE(0xa0, 0xa3) AM_READWRITE(timer2_count_r, timer2_count_w) AM_RANGE(0xa4, 0xa7) AM_READWRITE(timer2_value_r, timer2_value_w) AM_RANGE(0xa8, 0xab) AM_READWRITE(timer3_r, timer3_w) @@ -507,48 +508,20 @@ WRITE16_MEMBER(interpro_ioga_device::icr_w) LOGIRQ(offset, "irq: interrupt vector %d = 0x%04x (%s)\n", offset, data, machine().describe_context()); - if (data & IRQ_PENDING) - { - // record interrupt pending forced - m_hwint_forced |= 1 << offset; + // store all bits except pending + m_hwicr[offset] = (m_hwicr[offset] & IRQ_PENDING) | (data & ~IRQ_PENDING); - // store all bits except pending - m_hwicr[offset] = (m_hwicr[offset] & IRQ_PENDING) | (data & ~IRQ_PENDING); - - // FIXME: is it possible trigger a pending interrupt by unmasking it here? - } - else if (m_hwint_forced & (1 << offset)) - { - // interrupt is being forced - m_hwicr[offset] = data; - - // clear forced flag - m_hwint_forced &= ~(1 << offset); - - // FIXME: in/ex - LOGIRQ(offset, "irq: forcing interrupt vector %d\n", offset); - set_int_line(INT_HARD_IN, offset, ASSERT_LINE); - } - else - // otherwise just store the value - m_hwicr[offset] = data; + // scan for pending interrupts + m_interrupt_timer->adjust(attotime::zero); } WRITE8_MEMBER(interpro_ioga_device::softint_w) { - // check for forced interrupts - const u8 forced = m_softint & ~data; - // store the written value - m_softint = data; + // FIXME: forced interrupt handling + COMBINE_DATA(&m_softint); - // force interrupts if needed - if (forced != 0) - { - for (int i = 0; i < 8; i++) - if (forced & (1 << i)) - set_int_line(INT_SOFT_LO, i, ASSERT_LINE); - } + m_interrupt_timer->adjust(attotime::zero); } WRITE8_MEMBER(interpro_ioga_device::nmictrl_w) @@ -569,15 +542,11 @@ WRITE8_MEMBER(interpro_ioga_device::nmictrl_w) WRITE16_MEMBER(interpro_ioga_device::softint_vector_w) { - // check for forced interrupt - const bool forced = (m_swicr[offset] & IRQ_PENDING) && !(data & IRQ_PENDING); - // store the written value - m_swicr[offset] = data; + COMBINE_DATA(&m_swicr[offset]); // force interrupt if needed - if (forced) - set_int_line(INT_SOFT_HI, offset, ASSERT_LINE); + m_interrupt_timer->adjust(attotime::zero); } /* @@ -599,43 +568,80 @@ TIMER_CALLBACK_MEMBER(interpro_ioga_device::dma) if ((m_arbctl & dma_channel.arb_mask) == 0) { // set bus wait flag and abort - dma_channel.control |= DMA_CTRL_WAIT; + //dma_channel.control |= DMA_CTRL_WAIT; continue; } - else - // clear bus wait flag - dma_channel.control &= ~DMA_CTRL_WAIT; + //else + // // clear bus wait flag + // dma_channel.control &= ~DMA_CTRL_WAIT; - //LOGMASKED(LOG_DMA, "dma: transfer %s device begun, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n", + // translate address when DMA_CTRL_VIRTUAL is set + // FIXME: what happens when we span a page? + if (dma_channel.control & DMA_CTRL_VIRTUAL) + { + const u32 ptde = m_memory_space->read_dword(dma_channel.virtual_address); + + if ((ptde & 0x1) == 0) + { + dma_channel.real_address = (ptde & ~0xfff) | (dma_channel.real_address & 0xfff); + dma_channel.control &= ~DMA_CTRL_VIRTUAL; + + LOGDMA(dma_channel.channel, "dma: translated virtual address 0x%08x\n", dma_channel.real_address); + + // FIXME: what about protection levels and system tags? + + // set referenced and dirty page table entry flags + m_memory_space->write_dword(dma_channel.virtual_address, ptde | ((dma_channel.control & DMA_CTRL_WRITE) ? 0x2 : 0x6)); + } + else + { + // page fault + // FIXME: error status + dma_channel.control |= DMA_CTRL_BERR | DMA_CTRL_ERR; + LOGDMA(dma_channel.channel, "dma: page fault translating virtual address 0x%08x ptde 0x%08x\n", dma_channel.virtual_address, ptde); + break; + } + } + + //LOGDMA(dma_channel.channel, "dma: transfer %s device begun, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n", // (dma_channel.control & DMA_CTRL_WRITE) ? "to" : "from", dma_channel.channel, dma_channel.control, dma_channel.real_address, dma_channel.virtual_address, dma_channel.transfer_count); // transfer from the memory to device or device to memory while (dma_channel.transfer_count && dma_channel.drq_state) { // transfer from the memory to device or device to memory - // TODO: implement virtual addressing when DMA_CTRL_VIRTUAL is set - if (dma_channel.control & DMA_CTRL_WRITE) dma_channel.device_w(m_memory_space->read_byte(dma_channel.real_address)); else m_memory_space->write_byte(dma_channel.real_address, dma_channel.device_r()); - // increment addresses and decrement count + // increment address and decrement count dma_channel.real_address++; - dma_channel.virtual_address++; dma_channel.transfer_count--; + + // check for page wrap + if (dma_channel.transfer_count && (dma_channel.real_address & 0xfff) == 0) + { + LOGDMA(dma_channel.channel, "dma: wrapped to next memory page\n"); + + dma_channel.virtual_address += 4; + dma_channel.control |= DMA_CTRL_VIRTUAL; + + m_dma_timer->adjust(attotime::zero); + break; + } } // check if the transfer is complete if (dma_channel.transfer_count == 0) { - LOGMASKED(LOG_DMA, "dma: transfer %s device ended, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n", + LOGDMA(dma_channel.channel, "dma: transfer %s device ended, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n", (dma_channel.control & DMA_CTRL_WRITE) ? "to" : "from", dma_channel.channel, dma_channel.control, dma_channel.real_address, dma_channel.virtual_address, dma_channel.transfer_count); if (dma_channel.channel == DMA_FLOPPY) { - LOGMASKED(LOG_DMA | LOG_FLOPPY, "dma: asserting fdc terminal count line\n"); + LOGDMA(dma_channel.channel, "dma: asserting fdc terminal count line\n"); m_fdc_tc_func(ASSERT_LINE); m_fdc_tc_func(CLEAR_LINE); @@ -725,9 +731,7 @@ void interpro_ioga_device::drq(int state, int channel) // log every 256 bytes if ((dma_channel.transfer_count & 0xff) == 0) - { - LOGMASKED(LOG_DMA, "dma: drq for channel %d %s transfer_count 0x%08x\n", channel, state ? "asserted" : "deasserted", dma_channel.transfer_count); - } + LOGDMA(channel, "dma: drq for channel %d %s transfer_count 0x%08x\n", channel, state ? "asserted" : "deasserted", dma_channel.transfer_count); if (state) m_dma_timer->adjust(attotime::zero); @@ -764,28 +768,33 @@ void interpro_ioga_device::dma_w(address_space &space, offs_t offset, u32 data, switch (offset) { case 0: - LOGMASKED(LOG_DMA, "dma: channel %d real address = 0x%08x (%s)\n", channel, data, machine().describe_context()); - dma_channel.real_address = data; + LOGDMA(channel, "dma: channel %d real address 0x%08x mem_mask 0x%08x (%s)\n", + channel, data, mem_mask, machine().describe_context()); + COMBINE_DATA(&dma_channel.real_address); break; case 1: - LOGMASKED(LOG_DMA, "dma: channel %d virtual address = 0x%08x (%s)\n", channel, data, machine().describe_context()); - dma_channel.virtual_address = data & ~0x3; + LOGDMA(channel, "dma: channel %d virtual address = 0x%08x mem_mask 0x%08x (%s)\n", + channel, data, mem_mask, machine().describe_context()); + COMBINE_DATA(&dma_channel.virtual_address); break; case 2: - LOGMASKED(LOG_DMA, "dma: channel %d transfer count = 0x%08x (%s)\n", channel, data, machine().describe_context()); - dma_channel.transfer_count = data; + LOGDMA(channel, "dma: channel %d transfer count = 0x%08x mem_mask 0x%08x (%s)\n", + channel, data, mem_mask, machine().describe_context()); + COMBINE_DATA(&dma_channel.transfer_count); break; case 3: - LOGMASKED(LOG_DMA, "dma: channel %d control = 0x%08x (%s)\n", channel, data, machine().describe_context()); + LOGDMA(channel, "dma: channel %d control = 0x%08x mem_mask 0x%08x (%s)\n", + channel, data, mem_mask, machine().describe_context()); + COMBINE_DATA(&dma_channel.control); // (7.0272) if bus error flag is set, clear existing bus error (otherwise retain existing state) - if (data & DMA_CTRL_BERR) - dma_channel.control = data & DMA_CTRL_WMASK; - else - dma_channel.control = (data & DMA_CTRL_WMASK) | (dma_channel.control & DMA_CTRL_BERR); + //if (data & DMA_CTRL_BERR) + // dma_channel.control = data & DMA_CTRL_WMASK; + //else + // dma_channel.control = (data & DMA_CTRL_WMASK) | (dma_channel.control & DMA_CTRL_BERR); dma_channel.state = COMMAND; break; @@ -1097,7 +1106,12 @@ READ32_MEMBER(interpro_ioga_device::mouse_status_r) // clear xpos and ypos fields if (!machine().side_effects_disabled()) - m_mouse_status &= ~(MOUSE_XPOS | MOUSE_YPOS); + { + if (mem_mask & MOUSE_XPOS) + m_mouse_status &= ~(MOUSE_XPOS); + if (mem_mask & MOUSE_YPOS) + m_mouse_status &= ~(MOUSE_YPOS); + } return result; } @@ -1120,6 +1134,10 @@ INPUT_CHANGED_MEMBER(interpro_ioga_device::mouse_button) else m_mouse_status &= ~(field.mask() << 16); + // FIXME: this isn't right, but the rebuild code only + // reads the button status if the x/y status is non-zero? + m_mouse_status |= MOUSE_COUNTER; + set_int_line(INT_HARD_IN, IRQ_MOUSE, ASSERT_LINE); } @@ -1148,7 +1166,7 @@ INPUT_CHANGED_MEMBER(interpro_ioga_device::mouse_y) else if (delta < -0x80) delta += 0x100; - // set new x delta + // set new y delta m_mouse_status &= ~MOUSE_YPOS; m_mouse_status |= ((delta << 0) & MOUSE_YPOS); @@ -1265,29 +1283,29 @@ WRITE32_MEMBER(sapphire_ioga_device::eth_control_w) } } -WRITE32_MEMBER(sapphire_ioga_device::eth_w) +WRITE16_MEMBER(sapphire_ioga_device::eth_w) { // top two bits give channel (0=A, 4=B, 8=C, f=?) - const int channel = offset >> 28; - u32 address = (offset << 2) & 0x3fffffff; + const int channel = offset >> 29; + u32 address = (offset << 1) & 0x3fffffff; if ((m_eth_control & ETH_MAPEN) && (address & ETH_MAPPG) == (m_eth_mappg & ETH_MAPPG)) { address &= ~(m_eth_mappg & ETH_MAPPG); address |= (m_eth_remap & ETH_REMAP_ADDR); - LOGMASKED(LOG_NETWORK, "eth_w address 0x%08x remapped 0x%08x\n", offset << 2, address); + LOGMASKED(LOG_NETWORK, "eth_w address 0x%08x remapped 0x%08x\n", offset << 1, address); } - LOGMASKED(LOG_NETWORK, "eth_w channel %c address 0x%08x mask 0x%08x data 0x%08x\n", channel + 'A', address, mem_mask, data); - m_memory_space->write_dword(address, data, mem_mask); + LOGMASKED(LOG_NETWORK, "eth_w channel %c address 0x%08x mask 0x%08x data 0x%04x\n", channel + 'A', address, mem_mask, data); + m_memory_space->write_word(address, data, mem_mask); } -READ32_MEMBER(sapphire_ioga_device::eth_r) +READ16_MEMBER(sapphire_ioga_device::eth_r) { // top two bits give channel (0=A, 4=B, 8=C, f=?) - const int channel = offset >> 28; - u32 address = (offset << 2) & 0x3fffffff; + const int channel = offset >> 29; + u32 address = (offset << 1) & 0x3fffffff; if ((m_eth_control & ETH_MAPEN) && (address & ETH_MAPPG) == (m_eth_mappg & ETH_MAPPG)) { @@ -1295,11 +1313,11 @@ READ32_MEMBER(sapphire_ioga_device::eth_r) address |= (m_eth_remap & ETH_REMAP_ADDR); address &= 0x3fffffff; - LOGMASKED(LOG_NETWORK, "eth_r address 0x%08x remapped 0x%08x\n", offset << 2, address); + LOGMASKED(LOG_NETWORK, "eth_r address 0x%08x remapped 0x%08x\n", offset << 1, address); } - u32 data = m_memory_space->read_dword(address, mem_mask); - LOGMASKED(LOG_NETWORK, "eth_r channel %c address 0x%08x mask 0x%08x data 0x%08x\n", channel + 'A', address, mem_mask, data); + u16 data = m_memory_space->read_word(address, mem_mask); + LOGMASKED(LOG_NETWORK, "eth_r channel %c address 0x%08x mask 0x%08x data 0x%04x\n", channel + 'A', address, mem_mask, data); return data; } diff --git a/src/mame/machine/interpro_ioga.h b/src/mame/machine/interpro_ioga.h index 2c9d9da7d6f..2b9cc685d07 100644 --- a/src/mame/machine/interpro_ioga.h +++ b/src/mame/machine/interpro_ioga.h @@ -196,10 +196,9 @@ public: DMA_CTRL_ERR = 0x00800000, // checked for in scsi isr DMA_CTRL_BGR = 0x01000000, // cleared when command complete (maybe bus grant required?) - DMA_CTRL_WAIT = 0x02000000, // waiting for bus grant + DMA_CTRL_VIRTUAL = 0x02000000, // virtual address translation required DMA_CTRL_DOUBLE = 0x04000000, // double transfer size (double or quad quad) - DMA_CTRL_VIRTUAL = 0x20000000, // use virtual addressing DMA_CTRL_WRITE = 0x40000000, // memory to device transfer DMA_CTRL_QUAD = 0x80000000, // select quad transfer size (quad quad when combined with double) @@ -513,8 +512,8 @@ public: virtual void map(address_map &map) override; - DECLARE_WRITE32_MEMBER(eth_w); - DECLARE_READ32_MEMBER(eth_r); + DECLARE_WRITE16_MEMBER(eth_w); + DECLARE_READ16_MEMBER(eth_r); protected: virtual TIMER_CALLBACK_MEMBER(eth_reset) override;