diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index c388c2bc450..a24d60051b8 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -3367,6 +3367,7 @@ if (CPUS["ROMP"]~=null) then files { MAME_DIR .. "src/devices/cpu/romp/romp.cpp", MAME_DIR .. "src/devices/cpu/romp/romp.h", + MAME_DIR .. "src/devices/cpu/romp/rsc.h", } end diff --git a/src/devices/cpu/romp/romp.cpp b/src/devices/cpu/romp/romp.cpp index d95404c1a89..7f987b81e96 100644 --- a/src/devices/cpu/romp/romp.cpp +++ b/src/devices/cpu/romp/romp.cpp @@ -5,12 +5,13 @@ * IBM Research and Office Products Division Microprocessor (ROMP). * * Sources: - * - http://bitsavers.org/pdf/ibm/pc/rt/6489893_RT_PC_Technical_Reference_Volume_1_Nov85.pdf + * - http://bitsavers.org/pdf/ibm/pc/rt/75X0232_RT_PC_Technical_Reference_Volume_1_Jun87.pdf * * TODO: - * - instruction fetch and rmw cycles + * - configurable storage channel * - multiple exceptions * - check stop mask + * - advanced/enhanced variants */ #include "emu.h" @@ -35,7 +36,8 @@ ALLOW_SAVE_TYPE(romp_device::branch_state); romp_device::romp_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) : cpu_device(mconfig, ROMP, tag, owner, clock) , m_mem_config("memory", ENDIANNESS_BIG, 32, 32) - , m_io_config("io", ENDIANNESS_BIG, 32, 24, -2) + , m_mmu(*this, finder_base::DUMMY_TAG) + , m_iou(*this, finder_base::DUMMY_TAG) , m_icount(0) , m_reqi(0) { @@ -70,7 +72,6 @@ void romp_device::device_start() save_item(NAME(m_reqi)); save_item(NAME(m_trap)); - save_item(NAME(m_error)); save_item(NAME(m_branch_state)); save_item(NAME(m_branch_source)); @@ -95,23 +96,18 @@ void romp_device::state_string_export(device_state_entry const &entry, std::stri void romp_device::device_reset() { - // TODO: assumed for (u32 &scr : m_scr) scr = 0; - // TODO: assumed for (u32 &gpr : m_gpr) gpr = 0; // initialize the state - set_space(m_scr[ICS]); - m_trap = false; - m_error = false; m_branch_state = DEFAULT; // fetch initial iar - m_scr[IAR] = m_mem.read_dword(0); + load(0, [this](u32 data) { m_scr[IAR] = data; }); } void romp_device::execute_run() @@ -119,8 +115,6 @@ void romp_device::execute_run() // core execution loop while (m_icount-- > 0) { - m_error = false; - if (m_branch_state != BRANCH) interrupt_check(); @@ -133,10 +127,10 @@ void romp_device::execute_run() debugger_instruction_hook(m_scr[IAR]); // fetch instruction - u16 const op = m_mem.read_word(m_scr[IAR]); - u32 updated_iar = m_scr[IAR] + 2; - if (m_error) - program_check(PCS_PCK | PCS_IAE); + u32 updated_iar = m_scr[IAR]; + fetch(m_scr[IAR], [this, &updated_iar](u16 op) + { + updated_iar += 2; switch (op >> 12) { @@ -154,70 +148,41 @@ void romp_device::execute_run() program_check(PCS_PCK | PCS_IOC, m_branch_source); break; case 0x1: // stcs: store character short - m_mem.write_byte(r3_0(R3) + ((op >> 8) & 15), m_gpr[R2]); - if (m_error) - program_check(PCS_PCK | PCS_DAE); + store(r3_0(R3) + ((op >> 8) & 15), m_gpr[R2]); m_icount -= 4; break; case 0x2: // sths: store half short - m_mem.write_word(r3_0(R3) + ((op >> 7) & 30), m_gpr[R2]); - if (m_error) - program_check(PCS_PCK | PCS_DAE); + store(r3_0(R3) + ((op >> 7) & 30), m_gpr[R2]); m_icount -= 4; break; case 0x3: // sts: store short - m_mem.write_dword(r3_0(R3) + ((op >> 6) & 60), m_gpr[R2]); - if (m_error) - program_check(PCS_PCK | PCS_DAE); + store(r3_0(R3) + ((op >> 6) & 60), m_gpr[R2]); m_icount -= 4; break; case 0x4: // lcs: load character short - { - u8 const data = m_mem.read_byte(r3_0(R3) + ((op >> 8) & 15)); - if (!m_error) - m_gpr[R2] = data; - else - program_check(PCS_PCK | PCS_DAE); - m_icount -= 4; - } + load(r3_0(R3) + ((op >> 8) & 15), [this, op](u8 data) { m_gpr[R2] = data; }); + m_icount -= 4; break; case 0x5: // lhas: load half algebraic short - { - s32 const data = s32(s16(m_mem.read_word(r3_0(R3) + ((op >> 7) & 30)))); - if (!m_error) - m_gpr[R2] = data; - else - program_check(PCS_PCK | PCS_DAE); - m_icount -= 4; - } + load(r3_0(R3) + ((op >> 7) & 30), [this, op](u16 data) { m_gpr[R2] = s32(s16(data)); }); + m_icount -= 4; break; case 0x6: // cas: compute address short m_gpr[(op >> 8) & 15] = m_gpr[R2] + r3_0(R3); break; case 0x7: // ls: load short - { - u32 const data = m_mem.read_dword(r3_0(R3) + ((op >> 6) & 60)); - if (!m_error) - m_gpr[R2] = data; - else - program_check(PCS_PCK | PCS_DAE); - m_icount -= 4; - } + load(r3_0(R3) + ((op >> 6) & 60), [this, op](u32 data) { m_gpr[R2] = data; }); + m_icount -= 4; break; case 0x8: // BI, BA format + fetch(updated_iar, [this, &updated_iar, op](u16 b) { - u16 const b = m_mem.read_word(updated_iar); updated_iar += 2; - if (m_error) - { - program_check(PCS_PCK | PCS_IAE); - break; - } if (m_branch_state == BRANCH) { program_check(PCS_PCK | PCS_IOC, m_branch_source); - break; + return; } switch (op >> 8) @@ -287,19 +252,14 @@ void romp_device::execute_run() program_check(PCS_PCK | PCS_IOC); break; } - } + }); break; case 0xc: case 0xd: // D format + fetch(updated_iar, [this, &updated_iar, op](u16 i) { - u16 const i = m_mem.read_word(updated_iar); updated_iar += 2; - if (m_error) - { - program_check(PCS_PCK | PCS_IAE); - break; - } u32 const r3 = R3 ? m_gpr[R3] : 0; @@ -349,29 +309,18 @@ void romp_device::execute_run() case 0xc9: // lm: load multiple for (unsigned reg = R2, offset = r3 + s16(i); reg < 16; reg++, offset += 4) { - u32 const data = m_mem.read_dword(offset); - if (!m_error) - m_gpr[reg] = data; + // FIXME: multiple exceptions + load(offset, [this, reg](u32 data) { m_gpr[reg] = data; }); m_icount -= 2; } - if (m_error) - program_check(PCS_PCK | PCS_DAE); m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 1; break; case 0xca: // lha: load half algebraic - { - s32 const data = s32(s16(m_mem.read_word(r3 + s16(i)))); - if (!m_error) - m_gpr[R2] = data; - else - program_check(PCS_PCK | PCS_DAE); - m_icount -= 4; - } + load(r3 + s16(i), [this, op](u16 data) { m_gpr[R2] = s32(s16(data)); }); + m_icount -= 4; break; case 0xcb: // ior: input/output read - if (!((r3 + i) & 0xff00'0000U)) - m_gpr[R2] = space(AS_IO).read_dword(r3 + i); - else + if (((r3 + i) & 0xff00'0000U) || !m_mmu->ior(r3 + i, m_gpr[R2])) program_check(PCS_PCK | PCS_DAE); break; case 0xcc: // ti: trap on condition immediate @@ -386,40 +335,21 @@ void romp_device::execute_run() program_check(PCS_PCK | PCS_IOC, m_branch_source); break; case 0xcd: // l: load - { - u32 const data = m_mem.read_dword(r3 + s16(i)); - if (!m_error) - m_gpr[R2] = data; - else - program_check(PCS_PCK | PCS_DAE); - m_icount -= 4; - } + load(r3 + s16(i), [this, op](u32 data) { m_gpr[R2] = data; }); + m_icount -= 4; break; case 0xce: // lc: load character - { - u8 const data = m_mem.read_byte(r3 + s16(i)); - if (!m_error) - m_gpr[R2] = data; - else - program_check(PCS_PCK | PCS_DAE); - m_icount -= 4; - } + load(r3 + s16(i), [this, op](u8 data) { m_gpr[R2] = data; }); + m_icount -= 4; break; case 0xcf: // tsh: test and set half - { - u16 const data = m_mem.read_word(r3 + s16(i)); - if (!m_error) + modify(r3 + s16(i), [this, op](u16 data) { m_gpr[R2] = data; - m_mem.write_word(r3 + s16(i), 0xff00, 0xff00); - if (m_error) - program_check(PCS_PCK | PCS_DAE); - } - else - program_check(PCS_PCK | PCS_DAE); - m_icount -= 4; - } + return 0xff00 | data; + }); + m_icount -= 4; break; case 0xd0: // lps: load program status @@ -427,18 +357,16 @@ void romp_device::execute_run() { if (m_branch_state != BRANCH) { - m_branch_target = m_mem.read_dword(r3 + s16(i) + 0); + load(r3 + s16(i) + 0, [this](u32 data) { m_branch_target = data; }); m_branch_state = BRANCH; - m_scr[ICS] = m_mem.read_word(r3 + s16(i) + 4); - m_scr[CS] = m_mem.read_word(r3 + s16(i) + 6); + load(r3 + s16(i) + 6, [this](u16 data) { m_scr[CS] = data; }); + load(r3 + s16(i) + 4, [this](u16 data) { m_scr[ICS] = data; }); if (m_scr[MPCS] & MCS_ALL) m_scr[MPCS] &= ~MCS_ALL; else m_scr[MPCS] &= ~PCS_ALL; // TODO: defer interrupt enable - set_space(m_scr[ICS]); - m_icount -= 15; } else @@ -491,46 +419,31 @@ void romp_device::execute_run() case 0xd9: // stm: store multiple for (unsigned reg = R2, offset = r3 + s16(i); reg < 16; reg++, offset += 4) { - m_mem.write_dword(offset, m_gpr[reg]); + // FIXME: multiple exceptions + store(offset, m_gpr[reg]); m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 2; } - if (m_error) - program_check(PCS_PCK | PCS_DAE); m_icount -= (m_scr[ICS] & ICS_TM) ? 3 : 2; break; case 0xda: // lh: load half - { - u16 const data = m_mem.read_word(r3 + s16(i)); - if (!m_error) - m_gpr[R2] = data; - else - program_check(PCS_PCK | PCS_DAE); - m_icount -= 4; - } + load(r3 + s16(i), [this, op](u16 data) { m_gpr[R2] = data; }); + m_icount -= 4; break; case 0xdb: // iow: input/output write - if (!((r3 + i) & 0xff00'0000U)) - space(AS_IO).write_dword(r3 + i, m_gpr[R2]); - else + if (((r3 + i) & 0xff00'0000U) || !m_mmu->iow(r3 + i, m_gpr[R2])) program_check(PCS_PCK | PCS_DAE); m_icount--; break; case 0xdc: // sth: store half - m_mem.write_word(r3 + s16(i), m_gpr[R2]); - if (m_error) - program_check(PCS_PCK | PCS_DAE); + store(r3 + s16(i), m_gpr[R2]); m_icount -= 4; break; case 0xdd: // st: store - m_mem.write_dword(r3 + s16(i), m_gpr[R2]); - if (m_error) - program_check(PCS_PCK | PCS_DAE); + store(r3 + s16(i), m_gpr[R2]); m_icount -= 4; break; case 0xde: // stc: store character - m_mem.write_byte(r3 + s16(i), m_gpr[R2]); - if (m_error) - program_check(PCS_PCK | PCS_DAE); + store(r3 + s16(i), m_gpr[R2]); m_icount -= 4; break; @@ -538,7 +451,7 @@ void romp_device::execute_run() program_check(PCS_PCK | PCS_IOC); break; } - } + }); break; case 0x9: @@ -893,14 +806,8 @@ void romp_device::execute_run() break; case 0xeb: // lhs: load half short - { - u16 const data = m_mem.read_word(m_gpr[R3]); - if (!m_error) - m_gpr[R2] = data; - else - program_check(PCS_PCK | PCS_DAE); - m_icount -= 4; - } + load(m_gpr[R3], [this, op](u16 data) { m_gpr[R2] = data; }); + m_icount -= 4; break; case 0xec: // balr: branch and link if (m_branch_state != BRANCH) @@ -1012,6 +919,7 @@ void romp_device::execute_run() break; } + }); // update iar and branch state switch (m_branch_state) { @@ -1047,21 +955,18 @@ void romp_device::set_scr(unsigned scr, u32 data) static char const *const scr_names[16] = { "scr0", "scr1", "scr2", "scr3", "scr4", "scr5", "cous", "cou", - "ts", "scr9", "mq", "mpcs", "irb", "iar", "ics", "cs", + "ts", "ecr", "mq", "mpcs", "irb", "iar", "ics", "cs", }; LOG("set_scr %s data 0x%08x (%s)\n", scr_names[scr], data, machine().describe_context()); if (!(m_scr[ICS] & ICS_US) || scr == MQ || scr == CS) { - switch (scr) - { - case ICS: - set_space(data); - break; - } - - m_scr[scr] = data; + if (scr == ICS) + // TODO: only SGP is emulated + m_scr[scr] = data & 0x1ff7U; + else + m_scr[scr] = data; } else program_check(PCS_PCK | PCS_PIE); @@ -1093,13 +998,7 @@ void romp_device::execute_set_input(int irqline, int state) device_memory_interface::space_config_vector romp_device::memory_space_config() const { - return space_config_vector { - std::make_pair(0, &m_mem_config), // privileged, untranslated - std::make_pair(1, &m_mem_config), // privileged, translated - std::make_pair(2, &m_io_config), - std::make_pair(4, &m_mem_config), // unprivileged, untranslated - std::make_pair(5, &m_mem_config), // unprivileged, translated - }; + return space_config_vector { std::make_pair(AS_PROGRAM, &m_mem_config) }; } bool romp_device::memory_translate(int spacenum, int intention, offs_t &address) @@ -1229,22 +1128,21 @@ void romp_device::program_check(u32 pcs, u32 iar) void romp_device::interrupt_enter(unsigned vector, u32 iar, u16 svc) { // take interrupt - offs_t const address = 0x100 + vector * 16; + u32 const address = 0x100 + vector * 16; // save old program status - space(0).write_dword(address + 0, iar); - space(0).write_word(address + 4, u16(m_scr[ICS])); - space(0).write_word(address + 6, u16(m_scr[CS])); + // TODO: error handling + store(address + 0, iar, false); + store(address + 4, u16(m_scr[ICS]), false); + store(address + 6, u16(m_scr[CS]), false); if (vector == 9) - space(0).write_word(address + 14, svc); + store(address + 14, svc, false); // load new program status - m_scr[IAR] = space(0).read_dword(address + 8); - m_scr[ICS] = space(0).read_word(address + 12); + load(address + 8, [this](u32 data) { m_scr[IAR] = data; }, false); + load(address + 12, [this](u16 data) { m_scr[ICS] = data; }, false); if (vector < 7) - m_scr[CS] = space(0).read_word(address + 14); - - set_space(m_scr[ICS]); + load(address + 14, [this](u16 data) { m_scr[CS] = data; }, false); m_branch_state = DEFAULT; } diff --git a/src/devices/cpu/romp/romp.h b/src/devices/cpu/romp/romp.h index dd121069b6d..3ff1a55be0e 100644 --- a/src/devices/cpu/romp/romp.h +++ b/src/devices/cpu/romp/romp.h @@ -6,12 +6,16 @@ #pragma once +#include "rsc.h" + class romp_device : public cpu_device { public: romp_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); - void err_w(int state) { m_error = state; } + template void set_mmu(T &&tag) { m_mmu.set_tag(std::forward(tag)); } + template void set_iou(T &&tag) { m_iou.set_tag(std::forward(tag)); } + void clk_w(int state); protected: @@ -26,6 +30,7 @@ protected: COUS = 6, // counter source COU = 7, // counter TS = 8, // timer status + ECR = 9, // exception control (advanced/enhanced only) MQ = 10, // multiplier quotient MPCS = 11, // machine/program check status IRB = 12, // interrupt request buffer @@ -88,6 +93,7 @@ protected: ICS_US = 0x0000'0400, // unprivileged state ICS_MP = 0x0000'0800, // memory protect ICS_PE = 0x0000'1000, // parity error retry interrupt enable + ICS_UA = 0x0000'2000, // unaligned access interrupt enable (advanced/enhanced only) }; enum cs_mask : u32 { @@ -132,7 +138,6 @@ private: void flags_add(u32 const op1, u32 const op2); void flags_sub(u32 const op1, u32 const op2); - void set_space(u32 const ics) { space(((ics & ICS_US) ? 4 : 0) + ((ics & ICS_TM) ? 1 : 0)).cache(m_mem); } void set_scr(unsigned scr, u32 data); void interrupt_check(); @@ -141,11 +146,83 @@ private: void program_check(u32 pcs) { program_check(pcs, m_scr[IAR]); } void interrupt_enter(unsigned vector, u32 iar, u16 svc = 0); + using rsc_mode = rsc_bus_interface::rsc_mode; + + void fetch(u32 address, std::function f) + { + u16 data = 0; + + if (m_mmu->fetch(address, data, rsc_mode((m_scr[ICS] >> 9) & 7))) + f(data); + else + program_check(PCS_PCK | PCS_IAE); + } + + template void load(u32 address, std::function f, bool mask = true) + { + rsc_mode const mode = mask ? rsc_mode((m_scr[ICS] >> 9) & 7) : rsc_mode::RSC_N; + + T data = 0; + + switch (address >> 28) + { + default: + if (m_mmu->load(address, data, mode)) + f(data); + else + program_check(PCS_PCK | PCS_DAE); + break; + + case 15: + if (m_iou->load(address, data, mode)) + f(data); + else + program_check(PCS_PCK | PCS_DAE); + break; + } + } + + template void store(u32 address, T data, bool mask = true) + { + rsc_mode const mode = mask ? rsc_mode((m_scr[ICS] >> 9) & 7) : rsc_mode::RSC_N; + + switch (address >> 28) + { + default: + if (!m_mmu->store(address, data, mode)) + program_check(PCS_PCK | PCS_DAE); + break; + + case 15: + if (!m_iou->store(address, data, mode)) + program_check(PCS_PCK | PCS_DAE); + break; + } + } + + template void modify(u32 address, std::function f, bool mask = true) + { + rsc_mode const mode = mask ? rsc_mode((m_scr[ICS] >> 9) & 7) : rsc_mode::RSC_N; + + switch (address >> 28) + { + default: + if (!m_mmu->modify(address, f, mode)) + program_check(PCS_PCK | PCS_DAE); + break; + + case 15: + if (!m_iou->modify(address, f, mode)) + program_check(PCS_PCK | PCS_DAE); + break; + } + } + // address spaces address_space_config const m_mem_config; - address_space_config const m_io_config; - memory_access<32, 2, 0, ENDIANNESS_BIG>::cache m_mem; + required_device m_mmu; + required_device m_iou; // mame state int m_icount; @@ -157,7 +234,6 @@ private: // input line state u8 m_reqi; bool m_trap; - bool m_error; // internal state enum branch_state : unsigned diff --git a/src/devices/cpu/romp/rompdasm.cpp b/src/devices/cpu/romp/rompdasm.cpp index 148630e312e..213c2f3aacb 100644 --- a/src/devices/cpu/romp/rompdasm.cpp +++ b/src/devices/cpu/romp/rompdasm.cpp @@ -20,7 +20,7 @@ static char const *const gpr[16] = static char const *const scr[16] = { "scr0", "scr1", "scr2", "scr3", "scr4", "scr5", "cous", "cou", - "ts", "scr9", "mq", "mpcs", "irb", "iar", "ics", "cs", + "ts", "ecr", "mq", "mpcs", "irb", "iar", "ics", "cs", }; static char const *const cc[16] = diff --git a/src/devices/cpu/romp/rsc.h b/src/devices/cpu/romp/rsc.h new file mode 100644 index 00000000000..6810a7cefcb --- /dev/null +++ b/src/devices/cpu/romp/rsc.h @@ -0,0 +1,85 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_CPU_ROMP_RSC_H +#define MAME_CPU_ROMP_RSC_H + +#pragma once + +/* + * ROMP Storage Channel (the 32-bit, packet-switched, synchronous, pipelined + * interface between ROMP CPU, MMU and I/O Channel Converter/Controller). + * + * TODO: + * - improve registration/decoding + * - advanced/enhanced variations + */ + +class rsc_bus_interface + : public device_interface +{ +public: + rsc_bus_interface(machine_config const &mconfig, device_t &device) + : rsc_bus_interface(mconfig, device, "rsc_bus_interface") + { + } + virtual ~rsc_bus_interface() = default; + + enum rsc_mode : unsigned + { + RSC_N = 0, + RSC_T = 1, // translate mode + RSC_U = 2, // unprivileged state + RSC_UT = 3, + RSC_P = 4, // memory protect + RSC_PT = 5, + RSC_PU = 6, + RSC_PUT = 7, + }; + + virtual bool load(u32 address, u8 &data, rsc_mode const mode = RSC_N, bool sp = false) = 0; + virtual bool load(u32 address, u16 &data, rsc_mode const mode = RSC_N, bool sp = false) = 0; + virtual bool load(u32 address, u32 &data, rsc_mode const mode = RSC_N, bool sp = false) = 0; + + virtual bool store(u32 address, u8 data, rsc_mode const mode = RSC_N, bool sp = false) = 0; + virtual bool store(u32 address, u16 data, rsc_mode const mode = RSC_N, bool sp = false) = 0; + virtual bool store(u32 address, u32 data, rsc_mode const mode = RSC_N, bool sp = false) = 0; + + virtual bool modify(u32 address, std::function f, rsc_mode const mode = RSC_N) = 0; + virtual bool modify(u32 address, std::function f, rsc_mode const mode = RSC_N) = 0; + virtual bool modify(u32 address, std::function f, rsc_mode const mode = RSC_N) = 0; + +protected: + rsc_bus_interface(machine_config const &mconfig, device_t &device, char const *type) + : device_interface(device, type) + { + } +}; + +class rsc_cpu_interface + : public rsc_bus_interface +{ +public: + rsc_cpu_interface(machine_config const &mconfig, device_t &device) + : rsc_bus_interface(mconfig, device, "rsc_cpu_interface") + { + } + virtual ~rsc_cpu_interface() = default; + + // cpu interface + virtual bool fetch(u32 address, u16 &data, rsc_mode const mode = RSC_N) = 0; + + virtual bool ior(u32 address, u32 &data) = 0; + virtual bool iow(u32 address, u32 data) = 0; + + // rsc_bus_interface overrides + virtual bool load(u32 address, u8 &data, rsc_mode const mode = RSC_N, bool sp = true) override = 0; + virtual bool load(u32 address, u16 &data, rsc_mode const mode = RSC_N, bool sp = true) override = 0; + virtual bool load(u32 address, u32 &data, rsc_mode const mode = RSC_N, bool sp = true) override = 0; + + virtual bool store(u32 address, u8 data, rsc_mode const mode = RSC_N, bool sp = true) override = 0; + virtual bool store(u32 address, u16 data, rsc_mode const mode = RSC_N, bool sp = true) override = 0; + virtual bool store(u32 address, u32 data, rsc_mode const mode = RSC_N, bool sp = true) override = 0; +}; + +#endif // MAME_CPU_ROMP_RSC_H