From 89b519f58ed45d3373509f6945bed3fa25da642b Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Fri, 8 Jan 2021 15:10:31 +0700 Subject: New machines marked as NOT_WORKING --- IBM RT PC [Bitsavers] --- scripts/target/mame/mess.lua | 12 + src/mame/drivers/rtpc.cpp | 768 +++++++++++++++++++++++++ src/mame/layout/rtpc.lay | 69 +++ src/mame/machine/rosetta.cpp | 1202 ++++++++++++++++++++++++++++++++++++++++ src/mame/machine/rosetta.h | 181 ++++++ src/mame/machine/rtpc_iocc.cpp | 349 ++++++++++++ src/mame/machine/rtpc_iocc.h | 170 ++++++ src/mame/mame.lst | 7 + src/mame/mess.flt | 1 + 9 files changed, 2759 insertions(+) create mode 100644 src/mame/drivers/rtpc.cpp create mode 100644 src/mame/layout/rtpc.lay create mode 100644 src/mame/machine/rosetta.cpp create mode 100644 src/mame/machine/rosetta.h create mode 100644 src/mame/machine/rtpc_iocc.cpp create mode 100644 src/mame/machine/rtpc_iocc.h diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 9c965137bec..d4693d037c6 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -165,6 +165,7 @@ CPUS["GTRON"] = true CPUS["M88000"] = true CPUS["XAVIX2"] = true CPUS["UPD78K"] = true +CPUS["ROMP"] = true -------------------------------------------------- -- specify available sound cores; some of these are @@ -920,6 +921,7 @@ BUSES["PSX_PARALLEL"] = true BUSES["QL"] = true BUSES["QBUS"] = true BUSES["RS232"] = true +BUSES["RTPC_KBD"] = true BUSES["S100"] = true BUSES["SAMCOUPE_DRIVE_PORT"] = true BUSES["SAMCOUPE_EXPANSION"] = true @@ -1334,6 +1336,7 @@ function linkProjects_mame_mess(_target, _subtarget) "rockwell", "roland", "rolm", + "rtpc", "sage", "saitek", "samcoupe", @@ -3432,6 +3435,15 @@ files { MAME_DIR .. "src/mame/drivers/aim65_40.cpp", } +createMESSProjects(_target, _subtarget, "rtpc") +files { + MAME_DIR .. "src/mame/drivers/rtpc.cpp", + MAME_DIR .. "src/mame/machine/rosetta.cpp", + MAME_DIR .. "src/mame/machine/rosetta.h", + MAME_DIR .. "src/mame/machine/rtpc_iocc.cpp", + MAME_DIR .. "src/mame/machine/rtpc_iocc.h", +} + createMESSProjects(_target, _subtarget, "sage") files { MAME_DIR .. "src/mame/drivers/sage2.cpp", diff --git a/src/mame/drivers/rtpc.cpp b/src/mame/drivers/rtpc.cpp new file mode 100644 index 00000000000..70f6046f7b4 --- /dev/null +++ b/src/mame/drivers/rtpc.cpp @@ -0,0 +1,768 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * IBM RT PC. + * + * Sources: + * - http://bitsavers.org/pdf/ibm/pc/rt/75X0232_RT_PC_Technical_Reference_Volume_1_Jun87.pdf + * - http://www.cs.cmu.edu/afs/andrew.cmu.edu/usr/shadow/www/ibmrt.html + * - http://ps-2.kev009.com/ohlandl/6152/rt_index.html + * + * TODO: + * - finish refactoring iocc + * - additional machine variants + * - configurable RAM size + */ +/* + * https://www-01.ibm.com/common/ssi/ShowDoc.wss?docURL=/common/ssi/rep_ca/6/897/ENUS186-006/index.html + * https://www-01.ibm.com/common/ssi/ShowDoc.wss?docURL=/common/ssi/rep_ca/1/897/ENUS187-021/index.html + * https://www-01.ibm.com/common/ssi/ShowDoc.wss?docURL=/common/ssi/rep_ca/0/897/ENUS188-120/index.html + * + * Model Chassis CPU RAM HDD Release Price Notes + * 010 6151 032 1M/4M 40M Jan 1986 $11,700 + * 015 6151 032 2M/4M 70M Nov 1986 $10,050 + * 020 6150 032 1M/4M 40M Jan 1986 $14,945 + * 025 6150 032 2M/4M 70M Jan 1986 $17,940 + * A25 6150 032 2M/4M 70M Jan 1986 $19,510 5080 attachment/no keyboard + * 115 6151 Adv 4M/16M 70M Feb 1987 $10,600 AFPA + * 125 6150 Adv 4M/16M 70M Feb 1987 $16,100 AFPA + * B25 6150 Adv 4M/16M 70M Feb 1987 $17,670 AFPA, 5080 attachment/no keyboard + * 130 6151 Enh 16M 114M Jul 1988 $23,220 EAFPA + * 135 6150 Enh 16M 114M Jul 1988 $30,595 EAFPA + * B35 6150 Enh 16M 114M Jul 1988 $32,165 EAFPA, 5080 attachment/no keyboard + * + * 032 (aka SGP), 170ns (23.5294 MHz crystal / 4 == 5.882350 MHz == 170ns), 1MB/2MB/4MB memory boards + * Advanced, 100ns 4MB (6151) external (6150) (presume ~40MHz crystal/4), 4MB/8MB memory boards + * Enhanced, 80ns, 16MB soldered, EAFPA standard, CMOS (49.400 MHz crystal/4 == 12.350MHz == 80.971ns) + * + * AFPA is M68881 @ 20MHz + * EAFPA is AD90221-2 ADSP-3210 (multiplier) + AD90222-2 ADSP-3221 (fp alu) + AD90220-2 ADSP-1401 (program sequencer) + * + * system processor real memory address map + * 0000'0000-00ff'ffff 16MB memory management unit + * 0100'0000-efff'ffff -- not defined + * + * system board I/O addresses (all in segment F) + * f000'0000-f0ff'ffff 16MB i/o channel i/o map + * f100'0000-f3ff'ffff 48MB reserved + * f400'0000-f4ff'ffff 16MB i/o channel memory map + * f500'0000-f7ff'ffff reserved? + * f800'0000-fbff'ffff reserved + * fc00'0000-fdff'ffff mc68881 + * fe00'0000-feff'ffff fpa2 + * ff00'0000-ffff'ffff 16MB floating point accelerator + * + * system processor i/o address map + * 00'0000-7f'ffff 8MB not defined + * 80'0000-80'ffff 64KB processor channel device initialization + * 81'0000-81'ffff 64KB memory management unit + * 82'0000-ff'ffff 8064KB not defined + * + * advanced processor + * 80'0400 i/o interface 1 i/o base + * 80'0100 i/o interface 2 i/o base + * + */ + /* + * WIP + * - diagnostic disk 1 fails with code 67 + * - aix vrm disk 1 fails with alternating code a6/13 + */ + +#include "emu.h" + +// cpu and memory +#include "cpu/romp/romp.h" +#include "cpu/mcs51/mcs51.h" + +// various hardware +#include "machine/rosetta.h" +#include "machine/rtpc_iocc.h" +#include "machine/am9517a.h" +#include "machine/pic8259.h" +#include "machine/i8255.h" +#include "machine/mc146818.h" +#include "machine/z80scc.h" +#include "machine/timer.h" + +// isa bus +#include "bus/isa/isa.h" +#include "bus/isa/isa_cards.h" +#include "bus/isa/mda.h" +#include "bus/isa/fdc.h" +#include "bus/isa/ide.h" + +// busses and connectors +#include "bus/rs232/rs232.h" +#include "bus/rtpc/kbd_con.h" +#include "bus/rtpc/kbd.h" + +#include "sound/spkrdev.h" +#include "machine/input_merger.h" + +#include "imagedev/floppy.h" +#include "formats/pc_dsk.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_KLS (1U << 1) + +//#define VERBOSE (LOG_GENERAL) +#include "logmacro.h" + +#include "debugger.h" + +#include "rtpc.lh" + +namespace { + +class rtpc_state : public driver_device +{ +public: + rtpc_state(machine_config const &mconfig, device_type type, char const *tag) + : driver_device(mconfig, type, tag) + , m_cpu(*this, "cpu") + , m_mcu(*this, "mcu") + , m_mmu(*this, "mmu") + , m_iocc(*this, "iocc") + , m_dma(*this, "dma%u", 0U) + , m_pic(*this, "pic%u", 0U) + , m_ppi(*this, "ppi") + , m_rtc(*this, "rtc") + , m_scc(*this, "scc") + , m_isa(*this, "isa") + , m_kbd_con(*this, "kbd_con") + , m_speaker(*this, "kbd_con:kbd:speaker") + , m_ipl(*this, "ipl") + { + } + + void ibm6150(machine_config &config); + void ibm6151(machine_config &config); + + void init_common(); + +protected: + // driver_device overrides + virtual void machine_start() override; + virtual void machine_reset() override; + + template void iocc_pio_map(address_map &map); + + void common(machine_config &config); + + DECLARE_FLOPPY_FORMATS(floppy_formats); + + void mcu_port1_w(u8 data); + void mcu_port2_w(u8 data); + void mcu_port3_w(u8 data); + void ppi_portc_w(u8 data); + + void kls_cmd_w(offs_t offset, u16 data, u16 mem_mask); + void crra_w(u8 data); + void crrb_w(u8 data); + void dia_w(u8 data); + + void mcu_timer(timer_device &timer, void *ptr, s32 param) + { + m_mcu_p3 ^= 0x10; + m_mcu->set_input_line(MCS51_T0_LINE, BIT(m_mcu_p3, 4)); + } + + void speaker() + { + if (m_speaker) + m_speaker->level_w(!BIT(m_mcu_p2, 7) ? m_mcu_p1 >> 6 : 0); + } + + // devices + required_device m_cpu; + required_device m_mcu; + required_device m_mmu; + required_device m_iocc; + + required_device_array m_dma; + required_device_array m_pic; + required_device m_ppi; + required_device m_rtc; + optional_device m_scc; + + required_device m_isa; + required_device m_kbd_con; + optional_device m_speaker; + + required_region_ptr m_ipl; + + u8 m_mcu_p0; + u8 m_mcu_p1; + u8 m_mcu_p2; + u8 m_mcu_p3; + + u8 m_ppi_pb; + u8 m_mcu_uart; + + u8 m_ch8er; // dma channel 8 enable register + u8 m_crra; // component reset register a + u8 m_crrb; // component reset register b + + u8 m_ext[2]; // external serial registers +}; + +static double const speaker_levels[4] = { 0.0, 1.0 / 3.0, 2.0 / 3.0, 1.0 }; + +void rtpc_state::machine_start() +{ + m_mcu_p0 = 0; + m_mcu_p1 = 0; + m_mcu_p2 = 0; + m_mcu_p3 = 0; + + m_ppi_pb = 0; + + m_crra = 0xff; + m_crrb = 0xff; +} + +void rtpc_state::machine_reset() +{ +} + +void rtpc_state::init_common() +{ + if (m_speaker) + m_speaker->set_levels(4, speaker_levels); +} + +template void rtpc_state::iocc_pio_map(address_map &map) +{ + if (SCC) + { + map(0x00'8000, 0x00'8003).rw(m_scc, FUNC(z80scc_device::dc_ab_r), FUNC(z80scc_device::dc_ab_w)); + map(0x00'8020, 0x00'8020).lrw8([this]() { return m_ext[0]; }, "ext_a_r", [this](u8 data) { m_ext[0] = data; }, "ext_a_w"); + map(0x00'8040, 0x00'8040).lrw8([this]() { return m_ext[1]; }, "ext_b_r", [this](u8 data) { m_ext[1] = data; }, "ext_b_w"); + map(0x00'8060, 0x00'8060).lr8([this]() { return u8(m_scc->m1_r()); }, "intack"); + } + + // delay 1µs per byte written + map(0x00'80e0, 0x00'80e3).lw8([this](u8 data) { m_cpu->eat_cycles(m_cpu->clock() / 1000000 + 1); }, "io_delay"); + + map(0x00'8400, 0x00'8403).mirror(0x7c).rw(m_ppi, FUNC(i8255_device::read), FUNC(i8255_device::write)); + map(0x00'8400, 0x00'8401).mirror(0x78).w(FUNC(rtpc_state::kls_cmd_w)); + + map(0x00'8800, 0x00'883f).rw(m_rtc, FUNC(mc146818_device::read_direct), FUNC(mc146818_device::write_direct)); + map(0x00'8840, 0x00'884f).mirror(0x10).rw(m_dma[0], FUNC(am9517a_device::read), FUNC(am9517a_device::write)); + map(0x00'8860, 0x00'887f).umask16(0xff00).rw(m_dma[1], FUNC(am9517a_device::read), FUNC(am9517a_device::write)); + map(0x00'8880, 0x00'8881).mirror(0x1e).rw(m_pic[0], FUNC(pic8259_device::read), FUNC(pic8259_device::write)); + map(0x00'88a0, 0x00'88a1).mirror(0x1e).rw(m_pic[1], FUNC(pic8259_device::read), FUNC(pic8259_device::write)); + map(0x00'88c0, 0x00'88c0).mirror(0x1f).rw(m_iocc, FUNC(rtpc_iocc_device::dbr_r), FUNC(rtpc_iocc_device::dbr_w)); + map(0x00'88e0, 0x00'88e0).mirror(0x1f).rw(m_iocc, FUNC(rtpc_iocc_device::dmr_r), FUNC(rtpc_iocc_device::dmr_w)); + + map(0x00'8c00, 0x00'8c00).mirror(0x03).lrw8([this]() { return m_ch8er; }, "ch8er_r", [this](u8 data) { m_ch8er = data; }, "ch8er_w"); + map(0x00'8c20, 0x00'8c20).mirror(0x03).rw(m_iocc, FUNC(rtpc_iocc_device::ccr_r), FUNC(rtpc_iocc_device::ccr_w)); + map(0x00'8c40, 0x00'8c40).mirror(0x03).lr8([this]() { return m_crra; }, "crra_r"); + map(0x00'8c40, 0x00'8c40).mirror(0x03).w(FUNC(rtpc_state::crra_w)); + map(0x00'8c60, 0x00'8c60).mirror(0x03).lr8([this]() { return m_crrb; }, "crrb_r"); + map(0x00'8c60, 0x00'8c60).mirror(0x03).w(FUNC(rtpc_state::crrb_w)); + + // memory config reg (cc=2x8M, dd=2x2M, 88=2x4M) + map(0x00'8c80, 0x00'8c80).mirror(0x03).lr8([this]() { return 0xf8; }, "mcr"); + map(0x00'8ca0, 0x00'8ca0).mirror(0x03).w(FUNC(rtpc_state::dia_w)); + + map(0x01'0000, 0x01'07ff).rw(m_iocc, FUNC(rtpc_iocc_device::tcw_r), FUNC(rtpc_iocc_device::tcw_w)); + map(0x01'0800, 0x01'0801).mirror(0x7fc).rw(m_iocc, FUNC(rtpc_iocc_device::csr_r<1>), FUNC(rtpc_iocc_device::csr_w)); + map(0x01'0802, 0x01'0803).mirror(0x7fc).rw(m_iocc, FUNC(rtpc_iocc_device::csr_r<0>), FUNC(rtpc_iocc_device::csr_w)); +} + +FLOPPY_FORMATS_MEMBER(rtpc_state::floppy_formats) + FLOPPY_PC_FORMAT +FLOPPY_FORMATS_END + +void rtpc_state::mcu_port1_w(u8 data) +{ + // bit function + // 6 speaker volume 0 + // 7 speaker volume 1 + LOGMASKED(LOG_KLS, "mcu_port1_w volume %d\n", data >> 6); + m_mcu_p1 = (m_mcu_p1 & 0x3f) | (data & 0xc0); + + // speaker volume wraps to ppi port b.6 and b.5 + m_ppi_pb &= ~0x60; + m_ppi_pb |= (data >> 1) & 0x60; + + speaker(); +} + +void rtpc_state::mcu_port2_w(u8 data) +{ + // bit dst + // 0 ppi port c.0 (iid0) + // 1 ppi port c.1 (iid1) + // 2 ppi port c.2 (iid2) + // 3 i/o channel system reset (active low) + // 4 ppi port c.4 + // 5 (input) + // 6 ppi port c.6 (-ack) + // 7 speaker frequency + + // interrupts + // 0 informational + // 1 received byte from keyboard + // 2 received byte from uart + // 3 returning byte requested by system + // 4 block transfer ready + // 5 unassigned + // 6 self-test performed + // 7 error condition + + if ((data ^ m_mcu_p2) & 7) + LOGMASKED(LOG_KLS, "mcu_port2_w interrupt %d\n", data & 7); + + if ((data ^ m_mcu_p2) & 8) + LOGMASKED(LOG_KLS, "mcu_port2_w system reset %d\n", data & 8); + + m_ppi->pc4_w(BIT(data, 4)); + m_ppi->pc6_w(BIT(data, 6)); + + m_mcu_p2 &= ~0xdf; + m_mcu_p2 |= data & 0xdf; + + // speaker frequency wraps to ppi port b.7 + m_ppi_pb &= ~0x80; + m_ppi_pb |= ~data & 0x80; + + speaker(); +} + +void rtpc_state::mcu_port3_w(u8 data) +{ + // bit i/o function + // 0 i uart rx + // 1 o uart tx + // 2 i kbd clock in + // 3 i obf/int1 + // 4 i 32 kHz + // 5 i kbd data in + // 6 o kbd data out + // 7 o kbd clock out + + LOGMASKED(LOG_KLS, "mcu_port3_w 0x%02x\n", data); + + m_kbd_con->data_write_from_mb(BIT(data, 6)); + m_kbd_con->clock_write_from_mb(BIT(data, 7)); + + m_mcu_p3 = (m_mcu_p3 & ~0xc2) | (data & 0xc2); +} + +void rtpc_state::ppi_portc_w(u8 data) +{ + LOGMASKED(LOG_KLS, "ppi_portc_w 0x%02x\n", data); + + // bit 3 -> i/o channel (irq) + m_pic[0]->ir5_w(BIT(data, 3)); + + // bit 5 -> mcu p2.5 (ibf) + if (BIT(data, 5)) + m_mcu_p2 |= 0x20; + else + m_mcu_p2 &= ~0x20; + + // bit 7 -> mcu p3.3(-int1) (-obf) + if (BIT(data, 7)) + m_mcu_p3 |= 0x08; + else + m_mcu_p3 &= ~0x08; + m_mcu->set_input_line(MCS51_INT1_LINE, !BIT(data, 7)); +} + +void rtpc_state::kls_cmd_w(offs_t offset, u16 data, u16 mem_mask) +{ + LOGMASKED(LOG_KLS, "kls_cmd_w command 0x%02x data 0x%02x mask 0x%04x\n", u8(data), data >> 8, mem_mask); + + // 00cc cccc dddd dddd + switch (mem_mask) + { + case 0xff00: + m_ppi->write(0, data); + break; + case 0x00ff: + m_ppi->write(1, data); + break; + case 0xffff: + m_mcu_p1 = (m_mcu_p1 & ~0x3f) | (data & 0x3f); + m_ppi->write(0, data >> 8); + break; + } +} + +void rtpc_state::crra_w(u8 data) +{ + LOG("crra_w 0x%02x\n", data); + + // bit function + // 0 i/o slot 1 + // 1 i/o slot 2 + // 2 i/o slot 3 + // 3 i/o slot 4 + // 4 i/o slot 5 + // 5 i/o slot 6 + // 6 i/o slot 7 + // 7 i/o slot 8 + + m_crra = data; +} + +void rtpc_state::crrb_w(u8 data) +{ + LOG("crrb_w 0x%02x\n", data); + + // bit function + // 0 8530 + // 1 rs232 interface + // 2 8051 + // 3 dmac1 + // 4 dmac2 + // 5 arbitor + // 6 reserved + // 7 reserved + + if (BIT(data, 0)) + m_scc->reset(); + // TODO: rs232 if + m_mcu->set_input_line(INPUT_LINE_RESET, !BIT(data, 2)); + // TODO: dmac !ready + // TODO: arbitor + + m_crrb = data; +} + +void rtpc_state::dia_w(u8 data) +{ + bool const state = BIT(data, 0); + + LOG("dia_w 0x%02x (%s)\n", data, machine().describe_context()); + + m_pic[0]->ir0_w(state); + m_pic[0]->ir1_w(state); + m_pic[0]->ir2_w(state); + m_pic[0]->ir3_w(state); + m_pic[0]->ir4_w(state); + m_pic[0]->ir5_w(state); + m_pic[0]->ir6_w(state); + m_pic[0]->ir7_w(state); + + m_pic[1]->ir0_w(state); + m_pic[1]->ir1_w(state); + m_pic[1]->ir2_w(state); + m_pic[1]->ir3_w(state); + m_pic[1]->ir4_w(state); + m_pic[1]->ir5_w(state); + m_pic[1]->ir6_w(state); + m_pic[1]->ir7_w(state); +} + +void rtpc_state::common(machine_config &config) +{ + ROMP(config, m_cpu, 23'529'400 / 4); + m_cpu->set_mmu(m_mmu); + m_cpu->set_iou(m_iocc); + + input_merger_device &reqi2(INPUT_MERGER_ANY_LOW(config, "reqi2")); + reqi2.output_handler().set_inputline(m_cpu, INPUT_LINE_IRQ2).invert(); + + // TODO: hole for 1M/4M memory boards + // 2/2 rams 4M + // 2/1 rams 4M + // 1/1 rams 4M hole 1M + // 4/0 rams 4M + // 4/4 rams 16M hole 4M + ROSETTA(config, m_mmu, m_cpu->clock(), rosetta_device::RAM_4M); + m_mmu->set_mem(m_cpu, AS_PROGRAM); + m_mmu->set_rom("ipl"); + m_mmu->out_pchk().set(reqi2, FUNC(input_merger_device::in_w<0>)); + m_mmu->out_mchk().set_inputline(m_cpu, INPUT_LINE_NMI); + + // keyboard, locator, speaker adapter + // P8051AH 2075 + // 61X6310 8811 + // (c)IBM 1986 + // (c)INTEL '80 + I8051(config, m_mcu, 9.216_MHz_XTAL); + m_mcu->port_in_cb<0>().set([this]() { return m_ppi->pa_r(); }); + m_mcu->port_out_cb<0>().set([this](u8 data) { m_mcu_p0 = data; }); + m_mcu->port_in_cb<1>().set([this]() { return m_mcu_p1 & 0x1f; }); + m_mcu->port_out_cb<1>().set(FUNC(rtpc_state::mcu_port1_w)); + m_mcu->port_in_cb<2>().set([this]() { return m_mcu_p2; }); + m_mcu->port_out_cb<2>().set(FUNC(rtpc_state::mcu_port2_w)); + m_mcu->port_out_cb<3>().set(FUNC(rtpc_state::mcu_port3_w)); + m_mcu->port_in_cb<3>().set([this]() { return m_mcu_p3 & 0x3d; }); + m_mcu->serial_tx_cb().set( + [this](u8 data) + { + if (BIT(m_mcu_p1, 5)) + { + m_mcu_uart = data; + m_mcu->set_input_line(MCS51_RX_LINE, 1); + } + else + logerror("uart tx 0x%02x\n", data); + }); + m_mcu->serial_rx_cb().set([this]() { return m_mcu_uart; }); + //m_mcu->out_?().set_inputline(m_cpu, INPUT_LINE_IRQ0); + + TIMER(config, "mcu_timer").configure_periodic(FUNC(rtpc_state::mcu_timer), attotime::from_hz(32768)); + + RTPC_IOCC(config, m_iocc, 0); + m_iocc->out_int().set(reqi2, FUNC(input_merger_device::in_w<1>)); + m_iocc->out_rst().set_inputline(m_dma[0], INPUT_LINE_RESET); + m_iocc->out_rst().append_inputline(m_dma[1], INPUT_LINE_RESET); + + // ISA bus + ISA16(config, m_isa, 14'318'180 / 3); + m_isa->set_memspace(m_iocc, AS_PROGRAM); + m_isa->set_iospace(m_iocc, AS_IO); + //m_isa->iochck_callback().set(FUNC(at_mb_device::iochck_w)); + + // NEC + // D8237AC-5 + // 8903HV101 + AM9517A(config, m_dma[0], m_isa->clock()); + // chan usage + // 0 serial port A + // 1 serial port B + // 2 diskette drive, serial port A + // 3 pc network, serial port B + m_isa->drq0_callback().set(m_dma[0], FUNC(am9517a_device::dreq_w<0>)); + m_isa->drq1_callback().set(m_dma[0], FUNC(am9517a_device::dreq_w<1>)); + m_isa->drq2_callback().set(m_dma[0], FUNC(am9517a_device::dreq_w<2>)); + m_isa->drq3_callback().set(m_dma[0], FUNC(am9517a_device::dreq_w<3>)); + m_dma[0]->out_hreq_callback().set(m_dma[0], FUNC(am9517a_device::hack_w)); + m_dma[0]->out_dack_callback<0>().set(m_iocc, FUNC(rtpc_iocc_device::dack_w<2>)); + m_dma[0]->out_dack_callback<1>().set(m_iocc, FUNC(rtpc_iocc_device::dack_w<1>)); + m_dma[0]->out_dack_callback<2>().set(m_iocc, FUNC(rtpc_iocc_device::dack_w<0>)); + m_dma[0]->out_dack_callback<3>().set(m_iocc, FUNC(rtpc_iocc_device::dack_w<3>)); + m_dma[0]->in_memr_callback().set(m_iocc, FUNC(rtpc_iocc_device::dma_b_r)); + m_dma[0]->out_memw_callback().set(m_iocc, FUNC(rtpc_iocc_device::dma_b_w)); + + // NEC + // D8237AC-5 + // 8903HV101 + AM9517A(config, m_dma[1], m_isa->clock()); + // chan usage + // 5 reserved + // 6 reserved + // 7 reserved + // 8 286 coprocessor + m_isa->drq5_callback().set(m_dma[1], FUNC(am9517a_device::dreq_w<1>)); + m_isa->drq6_callback().set(m_dma[1], FUNC(am9517a_device::dreq_w<2>)); + m_isa->drq7_callback().set(m_dma[1], FUNC(am9517a_device::dreq_w<3>)); + m_dma[1]->out_hreq_callback().set(m_dma[1], FUNC(am9517a_device::hack_w)); + m_dma[1]->out_dack_callback<0>().set(m_iocc, FUNC(rtpc_iocc_device::dack_w<4>)); + m_dma[1]->out_dack_callback<1>().set(m_iocc, FUNC(rtpc_iocc_device::dack_w<5>)); + m_dma[1]->out_dack_callback<2>().set(m_iocc, FUNC(rtpc_iocc_device::dack_w<6>)); + m_dma[1]->out_dack_callback<3>().set(m_iocc, FUNC(rtpc_iocc_device::dack_w<7>)); + m_dma[1]->in_memr_callback().set(m_iocc, FUNC(rtpc_iocc_device::dma_w_r)); + m_dma[1]->out_memw_callback().set(m_iocc, FUNC(rtpc_iocc_device::dma_w_w)); + + // NEC + // D8259AC + PIC8259(config, m_pic[0]); + m_pic[0]->out_int_callback().set_inputline(m_cpu, INPUT_LINE_IRQ3).invert(); + // irq source + // 0 iocc irq 0: dma tc + // 1 iocc irq 10: (multiport async) + // 2 iocc irq 9: pc network, (multiport async), enhanced color graphics adapter, 3278/79 emulation adapter + // 3 iocc irq 3: serial port 2, pc network + // 4 iocc irq 4: serial port 1 + // 5 iocc irq 1: kbd + // 6 iocc irq 2: 8530 + // 7 iocc irq 7: parallel port 1, monochrome/printer + m_isa->irq10_callback().set(m_pic[0], FUNC(pic8259_device::ir1_w)); + m_isa->irq2_callback().set(m_pic[0], FUNC(pic8259_device::ir2_w)); + m_isa->irq3_callback().set(m_pic[0], FUNC(pic8259_device::ir3_w)); + m_isa->irq4_callback().set(m_pic[0], FUNC(pic8259_device::ir4_w)); + m_isa->irq7_callback().set(m_pic[0], FUNC(pic8259_device::ir7_w)); + + // NEC + // D8259AC + PIC8259(config, m_pic[1]); + m_pic[1]->out_int_callback().set_inputline(m_cpu, INPUT_LINE_IRQ4).invert(); + // irq source + // 0 iocc irq 8: reserved + // 1 iocc irq 11: (advanced monochrome graphics display) (multiport async) + // 2 iocc irq 14: fixed disk + // 3 iocc irq 12: (ibm rt pc streaming tape drive adapter) + // 4 iocc irq 6: diskette drive + // 5 iocc irq 5: parallel port 2 + // 6 iocc irq 15: (286 coprocessor) + // 7 iocc irq 13: serial port ex ct1 irpt + m_isa->irq11_callback().set(m_pic[1], FUNC(pic8259_device::ir1_w)); + m_isa->irq14_callback().set(m_pic[1], FUNC(pic8259_device::ir2_w)); + m_isa->irq12_callback().set(m_pic[1], FUNC(pic8259_device::ir3_w)); + m_isa->irq6_callback().set(m_pic[1], FUNC(pic8259_device::ir4_w)); + m_isa->irq5_callback().set(m_pic[1], FUNC(pic8259_device::ir5_w)); + m_isa->irq15_callback().set(m_pic[1], FUNC(pic8259_device::ir6_w)); + + // P8255A-5 + // L6430434 + // (C)INTEL '81 + I8255A(config, m_ppi); + // port A: read/write 8051 + // port B: input + // port C lower: input + // port C upper: 8051 handshake + // port C & 0x20 -> irq + m_ppi->in_pa_callback().set([this]() { return m_mcu_p0; }); + + // TODO: bits 4-1 "non-adapter system board signals" + // TODO: bit 0 "uart rxd signal" + m_ppi->in_pb_callback().set([this]() { return m_ppi_pb; }); + + m_ppi->out_pc_callback().set(FUNC(rtpc_state::ppi_portc_w)); + m_ppi->in_pc_callback().set([this]() { return m_mcu_p2 & 0x57; }); + + RTPC_KBD_CON(config, m_kbd_con); + m_kbd_con->option_add("kbd", RTPC_KBD); + m_kbd_con->set_default_option("kbd"); + m_kbd_con->out_data_cb().set([this](int state) { if (state) m_mcu_p3 |= 0x20; else m_mcu_p3 &= ~0x20; }); + m_kbd_con->out_clock_cb().set( + [this](int state) + { + if (state) + m_mcu_p3 |= 0x04; + else + m_mcu_p3 &= ~0x04; + m_mcu->set_input_line(MCS51_INT0_LINE, !state); + }); + + // MC146818AP + // IL 0A46D8729 + MC146818(config, m_rtc, 32.768_kHz_XTAL); + m_rtc->sqw().set(m_cpu, FUNC(romp_device::clk_w)); + m_rtc->sqw().append( + [this](int state) + { + if (state) + m_ppi_pb |= 0x08; + else + m_ppi_pb &= ~0x08; + }); + m_rtc->irq().set_inputline(m_cpu, INPUT_LINE_IRQ1).invert(); + m_rtc->irq().append( + [this](int state) + { + if (!state) + m_ppi_pb |= 0x10; + else + m_ppi_pb &= ~0x10; + }); + + config.set_default_layout(layout_rtpc); +} + +void rtpc_isa8_cards(device_slot_interface &device) +{ + device.option_add("mda", ISA8_MDA); +} + +void rtpc_isa16_cards(device_slot_interface &device) +{ + // FIXME: need 16-bit combined hdc/fdc card + device.option_add("hdc", ISA16_IDE); + device.option_add("fdc", ISA8_FDC_AT); +} + +void rtpc_state::ibm6150(machine_config &config) +{ + common(config); + m_iocc->set_addrmap(2, &rtpc_state::iocc_pio_map); + + SCC8530N(config, m_scc, 3'580'000); + m_scc->configure_channels(3'072'000, 3'072'000, 3'072'000, 3'072'000); + m_scc->out_int_callback().set(m_pic[0], FUNC(pic8259_device::ir6_w)); + + // port: TXD, DTR, RTS, RI, RXD, DSR, CTS, DCD + // external registers: DTR, DSR, RI + // scc: TXD, RTS, RXD, CTS, DCD + // scc: DTR/REQ, SYNC not connected + + rs232_port_device &port0(RS232_PORT(config, "serial0", default_rs232_devices, nullptr)); + port0.cts_handler().set(m_scc, FUNC(z80scc_device::ctsa_w)); + port0.dcd_handler().set(m_scc, FUNC(z80scc_device::dcda_w)); + port0.rxd_handler().set(m_scc, FUNC(z80scc_device::rxa_w)); + m_scc->out_rtsa_callback().set(port0, FUNC(rs232_port_device::write_rts)); + m_scc->out_txda_callback().set(port0, FUNC(rs232_port_device::write_txd)); + + rs232_port_device &port1(RS232_PORT(config, "serial1", default_rs232_devices, nullptr)); + // TXD, DTR, RTS, RI, RXD, DSR, CTS, DCD + port1.cts_handler().set(m_scc, FUNC(z80scc_device::ctsb_w)); + port1.dcd_handler().set(m_scc, FUNC(z80scc_device::dcdb_w)); + port1.rxd_handler().set(m_scc, FUNC(z80scc_device::rxb_w)); + m_scc->out_rtsb_callback().set(port1, FUNC(rs232_port_device::write_rts)); + m_scc->out_txdb_callback().set(port1, FUNC(rs232_port_device::write_txd)); + + // ISA slots + ISA16_SLOT(config, "isa1", 0, m_isa, rtpc_isa16_cards, "fdc", false); // slot 1: disk/diskette adapter + ISA16_SLOT(config, "isa2", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 2: option + ISA8_SLOT(config, "isa3", 0, m_isa, rtpc_isa8_cards, "mda", false); // slot 3: option + ISA16_SLOT(config, "isa4", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 4: option + ISA16_SLOT(config, "isa5", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 5: option + ISA8_SLOT(config, "isa6", 0, m_isa, rtpc_isa8_cards, nullptr, false); // slot 6: option + ISA16_SLOT(config, "isa7", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 7: option + ISA16_SLOT(config, "isa8", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 8: coprocessor/option +} + +void rtpc_state::ibm6151(machine_config &config) +{ + common(config); + m_iocc->set_addrmap(2, &rtpc_state::iocc_pio_map); + + // ISA slots + ISA8_SLOT(config, "isa1", 0, m_isa, rtpc_isa8_cards, "mda", false); // slot 1: option + ISA16_SLOT(config, "isa2", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 2: option + ISA16_SLOT(config, "isa3", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 2: option + ISA16_SLOT(config, "isa4", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 4: option + ISA16_SLOT(config, "isa5", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 5: coprocessor/option + ISA16_SLOT(config, "isa6", 0, m_isa, rtpc_isa16_cards, nullptr, false); // slot 6: disk/diskette adapter +} + +ROM_START(ibm6150) + ROM_REGION32_BE(0x10000, "ipl", 0) + ROM_SYSTEM_BIOS(0, "ipl", "IPL") + ROMX_LOAD("79x3456.bin", 0x00000, 0x4000, CRC(0a45a9ba) SHA1(02ca637c6a871c180dbfebf2ec68d8ec5a998c76), ROM_BIOS(0) | ROM_SKIP(3)) + ROMX_LOAD("79x3458.bin", 0x00001, 0x4000, CRC(7bd08ab6) SHA1(aabcfbb8fa1a5f8a08fb5cfd90ca6fe05258fde9), ROM_BIOS(0) | ROM_SKIP(3)) + ROMX_LOAD("79x3460.bin", 0x00002, 0x4000, CRC(897586e0) SHA1(528772635903f27235ebba2622b03386b84e4e17), ROM_BIOS(0) | ROM_SKIP(3)) + ROMX_LOAD("79x3462.bin", 0x00003, 0x4000, CRC(12aca906) SHA1(58f95b95768ef131d8d9d552506a9fe9c9c6077d), ROM_BIOS(0) | ROM_SKIP(3)) + + ROM_REGION(0x1000, "mcu", 0) + ROM_LOAD("61x6310_8051.bin", 0x0000, 0x1000, CRC(296c16c1) SHA1(83858109c39d5be37e49f24d1db4e2b15f38843e)) +ROM_END + +ROM_START(ibm6151) + ROM_REGION32_BE(0x10000, "ipl", 0) + ROM_SYSTEM_BIOS(0, "ipl", "IPL") + ROMX_LOAD("79x3456.bin", 0x00000, 0x4000, CRC(0a45a9ba) SHA1(02ca637c6a871c180dbfebf2ec68d8ec5a998c76), ROM_BIOS(0) | ROM_SKIP(3)) + ROMX_LOAD("79x3458.bin", 0x00001, 0x4000, CRC(7bd08ab6) SHA1(aabcfbb8fa1a5f8a08fb5cfd90ca6fe05258fde9), ROM_BIOS(0) | ROM_SKIP(3)) + ROMX_LOAD("79x3460.bin", 0x00002, 0x4000, CRC(897586e0) SHA1(528772635903f27235ebba2622b03386b84e4e17), ROM_BIOS(0) | ROM_SKIP(3)) + ROMX_LOAD("79x3462.bin", 0x00003, 0x4000, CRC(12aca906) SHA1(58f95b95768ef131d8d9d552506a9fe9c9c6077d), ROM_BIOS(0) | ROM_SKIP(3)) + + // Version: 073 + // Date: 85 289 (16 Oct 1985) + // Checksum: 0xc8 0xe8 + ROM_REGION(0x1000, "mcu", 0) + ROM_LOAD("61x6310_8051.bin", 0x0000, 0x1000, CRC(296c16c1) SHA1(83858109c39d5be37e49f24d1db4e2b15f38843e)) +ROM_END + +#define rom_rtpc010 rom_ibm6151 +#define rom_rtpc015 rom_ibm6151 +#define rom_rtpc020 rom_ibm6150 +#define rom_rtpc025 rom_ibm6150 +#define rom_rtpca25 rom_ibm6150 + +} // anonymous namespace + +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP(1986, rtpc010, 0, 0, ibm6151, 0, rtpc_state, init_common, "International Business Machines", "IBM RT PC Model 010", MACHINE_NOT_WORKING) +COMP(1986, rtpc015, 0, 0, ibm6151, 0, rtpc_state, init_common, "International Business Machines", "IBM RT PC Model 015", MACHINE_NOT_WORKING) +COMP(1986, rtpc020, 0, 0, ibm6150, 0, rtpc_state, init_common, "International Business Machines", "IBM RT PC Model 020", MACHINE_NOT_WORKING) +COMP(1986, rtpc025, 0, 0, ibm6150, 0, rtpc_state, init_common, "International Business Machines", "IBM RT PC Model 025", MACHINE_NOT_WORKING) +COMP(1986, rtpca25, 0, 0, ibm6150, 0, rtpc_state, init_common, "International Business Machines", "IBM RT PC Model A25", MACHINE_NOT_WORKING) diff --git a/src/mame/layout/rtpc.lay b/src/mame/layout/rtpc.lay new file mode 100644 index 00000000000..e99ca37c05c --- /dev/null +++ b/src/mame/layout/rtpc.lay @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/machine/rosetta.cpp b/src/mame/machine/rosetta.cpp new file mode 100644 index 00000000000..12b6d5ec036 --- /dev/null +++ b/src/mame/machine/rosetta.cpp @@ -0,0 +1,1202 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * IBM Rosetta MMU. + * + * Sources: + * - http://bitsavers.org/pdf/ibm/pc/rt/75X0232_RT_PC_Technical_Reference_Volume_1_Jun87.pdf + * + * TODO: + * - tighten error detection/reporting + * - external device and multiple errors + * - ras diagnostic modes + * - advanced/enhanced variants + * - ram holes + */ + +#include "emu.h" +#include "rosetta.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_TLB (1U << 1) +#define LOG_RELOAD (1U << 2) +#define LOG_ECC (1U << 3) +#define LOG_INVALID (1U << 4) + +//#define VERBOSE (LOG_GENERAL|LOG_TLB|LOG_RELOAD|LOG_ECC|LOG_INVALID) +#include "logmacro.h" + +enum roms_mask : u32 +{ + ROMS_SIZE = 0x0000'000f, // rom size + ROMS_START = 0x0000'0ff0, // rom address + ROMS_P = 0x0000'1000, // parity enable +}; + +enum segment_mask : u32 +{ + SEGMENT_K = 0x0000'0001, // key + SEGMENT_S = 0x0000'0002, // special + SEGMENT_ID = 0x0000'3ffc, // identifier + SEGMENT_I = 0x0000'4000, // i/o access protect + SEGMENT_R = 0x0000'8000, // system processor access protect + SEGMENT_P = 0x0001'0000, // present +}; + +enum rams_mask : u32 +{ + RAMS_SIZE = 0x0000'000f, // ram size + RAMS_START = 0x0000'0ff0, // ram address +}; + +enum tcr_mask : u32 +{ + TCR_HIB = 0x0000'00ff, // hat/ipt base address + TCR_S = 0x0000'0100, // page size (1=4k pages) + TCR_P = 0x0000'0200, // r/c array parity enable (advanced/enhanced only?) + TCR_R = 0x0000'0400, // enable interrupt on successful tlb reload + TCR_C = 0x0000'0800, // enable interrupt on correctable ecc error + TCR_I = 0x0000'1000, // terminate long ipt search + TCR_D = 0x0000'2000, // enable ras diagnostic mode + TCR_E = 0x0000'4000, // interrupt on successful parity error retry + TCR_V = 0x0000'8000, // segment register zero virtual equal to real +}; + +enum mer_mask : u32 +{ + MER_D = 0x0000'0001, // data + MER_P = 0x0000'0002, // protection + MER_S = 0x0000'0004, // tlb specification + MER_F = 0x0000'0008, // page fault + MER_M = 0x0000'0010, // multiple exception + MER_E = 0x0000'0020, // external device exception + MER_I = 0x0000'0040, // ipt specification error + MER_W = 0x0000'0080, // write to rom + MER_R = 0x0000'0100, // r/c array parity error (advanced/enhanced only?) + MER_T = 0x0000'0200, // successful tlb reload + MER_C = 0x0000'0400, // correctable ecc error + MER_U = 0x0000'0800, // uncorrectable memory error + MER_L = 0x0000'1000, // access type (1=load) + MER_O = 0x0000'2000, // invalid i/o address + MER_B = 0x0000'4000, // invalid memory address + MER_N = 0x0000'8000, // processor channel nakd + MER_A = 0x0001'0000, // processor channel ackd + MER_V = 0x0002'0000, // segment protection violation +}; + +enum trar_mask : u32 +{ + TRAR_A = 0x00ff'ffff, // real memory address + TRAR_I = 0x8000'0000, // invalid +}; + +enum rmdr_mask : u32 +{ + RMDR_CHECK = 0x0000'ff00, // array check bits + RMDR_ALT = 0x0000'00ff, // alternate check bits +}; + +enum tlb_mask : u32 +{ + // field 0 + TLB_SEG = 0x1ffe'0000, // segment identifier + TLB_AT2K = 0x1fff'fff0, // address tag (2k page) + TLB_AT4K = 0x1fff'ffe0, // address tag (4k page) + + // field 1 + TLB_KEY = 0x0000'0003, // key bits + TLB_V = 0x0000'0004, // valid bit + TLB_RPN2K = 0x0000'fff8, // real page number (2k page) + TLB_RPN4K = 0x0000'fff0, // real page number (4k page) + + // field 2 + TLB_LB = 0x0000'ffff, // lock bits + TLB_TID = 0x00ff'0000, // transaction identifier + TLB_W = 0x0100'0000, // write bit + +}; + +enum hat_mask : u32 +{ + HAT_AT2K = 0x1fff'ffff, // address tag (2k page) + HAT_AT4K = 0x1fff'fffe, // address tag (4k page) + HAT_KEY = 0xc000'0000, // key + + HAT_IPTP = 0x0000'1fff, // ipt pointer + HAT_L = 0x0000'8000, // last + HAT_HATP = 0x1fff'0000, // hat pointer + HAT_E = 0x8000'0000, // empty + + HAT_LB = 0x0000'ffff, // lock bits + HAT_TID = 0x00ff'0000, // transaction identifier + HAT_W = 0x0100'0000, // write protect +}; + +enum rca_mask : u8 +{ + RCA_C = 0x01, // change + RCA_R = 0x02, // reference +}; + +enum reg : unsigned +{ + IOBA = 0, // i/o base address + MER = 1, // memory exception + MEAR = 2, // memory exception address + TRAR = 3, // translated real address + TID = 4, // transaction identifier + TCR = 5, // translation control + RAMS = 6, // ram specification + ROMS = 7, // rom specification + RMDR = 8, // ras mode diagnostic +}; + +static char const *const control_names[] = { "IOBA", "MER", "MEAR", "TRAR", "TID", "TCR", "RAMS", "ROMS", "RMDR" }; + +static u8 const ecc_bits[] = +{ + 0xa8, 0x68, 0xa4, 0x64, 0xa2, 0x62, 0xa1, 0x61, + 0x98, 0x58, 0x94, 0x54, 0x92, 0x52, 0x91, 0x51, + 0x8a, 0x89, 0x4a, 0x49, 0x2a, 0x29, 0x1a, 0x19, + 0x86, 0x85, 0x46, 0x45, 0x26, 0x25, 0x16, 0x15, +}; + +// 7-segment diagnostic led +static u8 const led_pattern[16] = +{ + 0x3f, 0x06, 0x5b, 0x4f, + 0x66, 0x6d, 0x7d, 0x07, + 0x7f, 0x6f, 0x77, 0x7c, + 0x39, 0x5e, 0x79, 0x00, +}; + +DEFINE_DEVICE_TYPE(ROSETTA, rosetta_device, "rosetta", "IBM Rosetta") + +ALLOW_SAVE_TYPE(rosetta_device::mear_state) + +rosetta_device::rosetta_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, ram_size ram) + : device_t(mconfig, ROSETTA, tag, owner, clock) + , rsc_cpu_interface(mconfig, *this) + , m_mem_space(*this, finder_base::DUMMY_TAG, -1, 32) + , m_rom(*this, finder_base::DUMMY_TAG) + , m_leds(*this, "led%u", 0U) + , m_out_pchk(*this) + , m_out_mchk(*this) + , m_segment{} + , m_control{} + , m_mear_lock(UNLOCKED) + , m_rmdr_lock(false) + , m_led_lock(true) + , m_pchk_state(false) + , m_tlb{ {}, {} } + , m_tlb_lru(0) + , m_ram_size(ram) +{ +} + +void rosetta_device::device_validity_check(validity_checker &valid) const +{ + if (!m_ram_size) + osd_printf_error("invalid ram size\n"); +} + +void rosetta_device::device_start() +{ + m_out_pchk.resolve_safe(); + m_out_mchk.resolve_safe(); + m_leds.resolve(); + + save_item(NAME(m_segment)); + save_item(NAME(m_control)); + save_item(NAME(m_mear_lock)); + save_item(NAME(m_rmdr_lock)); + save_item(NAME(m_led_lock)); + save_item(NAME(m_pchk_state)); + + save_item(STRUCT_MEMBER(m_tlb, field0)); + save_item(STRUCT_MEMBER(m_tlb, field1)); + save_item(STRUCT_MEMBER(m_tlb, field2)); + save_item(NAME(m_tlb_lru)); + + save_pointer(NAME(m_ram), m_ram_size); + save_pointer(NAME(m_ecc), m_ram_size); + save_pointer(NAME(m_rca), 2048); + + config_tlb(); + + m_ram = std::make_unique(m_ram_size); + m_ecc = std::make_unique(m_ram_size); + m_rca = std::make_unique(2048); + + offs_t const mask = m_rom.bytes() - 1; + m_mem_space->install_rom(0, mask, 0xffffff & ~mask, m_rom); + m_mem_space->cache(m_mem); +} + +void rosetta_device::device_reset() +{ + m_mear_lock = UNLOCKED; + m_rmdr_lock = false; + m_led_lock = true; + + set_pchk(false); + set_mchk(false); +} + +void rosetta_device::device_post_load() +{ + config_tlb(); +} + +bool rosetta_device::ior(u32 address, u32 &data) +{ + if ((address >> 16) == u8(m_control[IOBA])) + { + u16 const offset = u16(address); + + switch (offset) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + data = segment_r(offset & 0xf); + return true; + + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: + data = control_r(offset & 0xf); + return true; + + default: + if (offset - 0x20U < 0x60U) + { + data = tlb_r(offset - 0x20U); + return true; + } + else if (offset - 0x1000U < 0x2000U) + { + data = rca_r(offset - 0x1000U); + return true; + } + break; + } + } + else if (address == 0x80'8000U) + { + data = m_control[IOBA]; + return true; + } + + LOGMASKED(LOG_INVALID, "ior invalid address 0x%06x (%s)\n", address, machine().describe_context()); + m_control[MER] |= MER_O; + set_mear(address, MEMORY); + + return bool(m_control[TCR] & TCR_D); +} + +bool rosetta_device::iow(u32 address, u32 data) +{ + if ((address >> 16) == u8(m_control[IOBA])) + { + u16 const offset = u16(address); + + switch (offset) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + segment_w(offset & 0xf, data); + return true; + + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: + control_w(offset & 0xf, data); + return true; + + case 0x80: tlb_inv_all(data); return true; + case 0x81: tlb_inv_segment(data); return true; + case 0x82: tlb_inv_address(data); return true; + case 0x83: compute_address(data); return true; + + default: + if (offset - 0x20U < 0x60U) + { + tlb_w(offset - 0x20U, data); + return true; + } + else if (offset - 0x1000U < 0x2000U) + { + rca_w(offset - 0x1000U, data); + return true; + } + break; + } + } + else if (address == 0x80'8000U) + { + m_control[IOBA] = data; + return true; + } + + LOGMASKED(LOG_INVALID, "iow invalid address 0x%06x data 0x%08x (%s)\n", address, data, machine().describe_context()); + m_control[MER] |= MER_O; + set_mear(address, MEMORY); + set_pchk(true); + + return true; +} + +bool rosetta_device::translate(u32 &address, bool system_processor, bool store) +{ + unsigned const segment = address >> 28; + + // segment present + if (!(m_segment[segment] & SEGMENT_P)) + fatalerror("rosetta_device::translate() segment %d absent (%s)\n", segment, machine().describe_context()); + + // segment access protection + if (system_processor && (m_segment[segment] & SEGMENT_R)) + { + m_control[MER] |= MER_V; + + return false; + } + else if (!system_processor && (m_segment[segment] & SEGMENT_I)) + return false; + + // segment zero virtual equal to real + if ((m_control[TCR] & TCR_V) && !segment) + { + address &= 0x00ff'ffffU; + + return true; + } + + u64 const virtual_address = (u64(m_segment[segment] & SEGMENT_ID) << 26) | (address & 0x0fff'ffffU); + + tlb_entry const te = tlb_search(virtual_address, m_segment[segment] & SEGMENT_S); + if (!(te.field1 & TLB_V)) + return false; + + u32 const real_page = (te.field1 << 8) & m_page_mask; + + // special segment lockbit processing + if (m_segment[segment] & SEGMENT_S) + { + // check transaction identifier + if ((m_control[TID] & 0xff) != ((te.field2 & TLB_TID) >> 16)) + { + if (system_processor) + m_control[MER] |= MER_D; + + return false; + } + + // check write bit, lock bit and operation + bool const lockbit = BIT(te.field2, 15 - ((address >> (m_page_shift - 4)) & 15)); + if (te.field2 & TLB_W) + { + if (!lockbit && store) + { + if (system_processor) + m_control[MER] |= MER_D; + + return false; + } + } + else + { + if (!lockbit || store) + { + if (system_processor) + m_control[MER] |= MER_D; + + return false; + } + } + } + else + { + // non-special segment memory protection processing + switch (te.field1 & TLB_KEY) + { + case 0: + // key 0 fetch-protected + if (m_segment[segment] & SEGMENT_K) + { + if (system_processor) + m_control[MER] |= MER_P; + + return false; + } + break; + case 1: + // key 0 read/write + if ((m_segment[segment] & SEGMENT_K) && store) + { + if (system_processor) + m_control[MER] |= MER_P; + + return false; + } + break; + case 2: + // public read/write + break; + case 3: + // public read-only + if (store) + { + if (system_processor) + m_control[MER] |= MER_P; + + return false; + } + break; + } + } + + address = real_page | (address & ~m_page_mask); + + return true; +} + +rosetta_device::tlb_entry rosetta_device::tlb_search(u64 const virtual_address, bool const special) +{ + unsigned const tlb_index = (virtual_address >> m_page_shift) & 15; + tlb_entry te = { 0U, 0U, 0U }; + + // check first set + if ((m_tlb[tlb_index][0].field1 & TLB_V) && !((m_tlb[tlb_index][0].field0 ^ (virtual_address >> 11)) & m_atag_mask)) + { + te = m_tlb[tlb_index][0]; + + // tlb set 1 is least-recently used + m_tlb_lru |= (1U << tlb_index); + } + + // check second set + if ((m_tlb[tlb_index][1].field1 & TLB_V) && !((m_tlb[tlb_index][1].field0 ^ (virtual_address >> 11)) & m_atag_mask)) + { + if (!(te.field1 & TLB_V)) + { + te = m_tlb[tlb_index][1]; + + // tlb set 0 is least-recently used + m_tlb_lru &= ~(1U << tlb_index); + } + else + { + // double tlb set hit + m_control[MER] |= MER_S; + + fatalerror("rosetta_device::tlb_search() double tlb hit 0x%010x (%s)\n", + virtual_address, machine().describe_context()); + + if (!(m_control[TCR] & TCR_D)) + { + set_mchk(true); + + return tlb_entry{ 0U, 0U, 0U }; + } + else + // if store, address is logical OR of both real page numbers + // TODO: what about load? + te.field1 |= m_tlb[tlb_index][1].field1; + } + } + + // handle tlb miss + if (!(te.field1 & TLB_V)) + { + unsigned const lru = BIT(m_tlb_lru, tlb_index); + + u32 const mer = tlb_reload(te, virtual_address, special); + if (mer & (MER_T | MER_I | MER_F)) + { + // FIXME: set I&F only for system processor + m_control[MER] |= mer; + + return te; + } + else + m_tlb[tlb_index][lru] = te; + } + + return te; +} + +u32 rosetta_device::tlb_reload(rosetta_device::tlb_entry &tlb_entry, u64 const virtual_address, bool special) +{ + // compute hat index + u16 hat_offset = (((virtual_address >> 26) & SEGMENT_ID) ^ (virtual_address >> (m_page_shift - 2))) & m_hat_mask; + + // fetch hat entry + u32 hat_entry = m_ram[m_hat_base + hat_offset + 1]; + + if (!machine().side_effects_disabled()) + LOGMASKED(LOG_RELOAD, "reload 0x%010x hat base 0x%x index 0x%x entry 0x%08x\n", + virtual_address, m_hat_base, hat_offset, hat_entry); + + // set reference bit + m_rca[(m_hat_base + hat_offset) >> 11] |= (RCA_R << (((m_hat_base + hat_offset) >> 8) & 6)); + + if (hat_entry & HAT_E) + return MER_F; + + // compute ipt entry pointer + hat_offset = ((hat_entry & HAT_HATP) >> 14); + u32 const address = (virtual_address >> 11) & m_atag_mask; + + // ipt search + for (unsigned count = 0; count < 1024; count++) + { + // fetch ipt entry + u32 const ipt_entry = m_ram[m_hat_base + hat_offset + 0]; + + // set reference bit + m_rca[(m_hat_base + hat_offset) >> 11] |= (RCA_R << (((m_hat_base + hat_offset) >> 8) & 6)); + + if ((ipt_entry & m_atag_mask) == address) + { + // reload tlb + tlb_entry.field0 = ipt_entry & m_atag_mask; + tlb_entry.field1 = (hat_offset << 1) | TLB_V | (ipt_entry >> 30); + + if (special) + tlb_entry.field2 = m_ram[m_hat_base + hat_offset + 2]; + + if (!machine().side_effects_disabled()) + LOGMASKED(LOG_RELOAD, "reload complete count %d f0 0x%08x f1 0x%08x f2 0x%08x\n", + count, tlb_entry.field0, tlb_entry.field1, tlb_entry.field2); + + if (m_control[TCR] & TCR_R) + return MER_T; + + return 0; + } + + // terminate long ipt search + if ((m_control[TCR] & TCR_I) && (count == 127)) + { + LOGMASKED(LOG_RELOAD, "reload long search abort\n"); + + return MER_I; + } + + // fetch next hat entry + hat_entry = m_ram[m_hat_base + hat_offset + 1]; + if (hat_entry & HAT_L) + { + LOGMASKED(LOG_RELOAD, "reload fault\n"); + + return MER_F; + } + + // select next ipt entry + hat_offset = (hat_entry & HAT_IPTP) << 2; + } + + fatalerror("rosetta_device::reload() endless loop detected\n"); +} + +void rosetta_device::set_mear(u32 const address, mear_state lock) +{ + if (m_mear_lock == LOCKED) + return; + + if (m_mear_lock == MEMORY && lock == MEMORY) + return; + + m_control[MEAR] = address; + m_mear_lock = lock; +} + +void rosetta_device::set_rmdr(u8 const ecc, bool lock) +{ + if (m_rmdr_lock) + return; + + m_control[RMDR] = (m_control[RMDR] & ~RMDR_CHECK) | (ecc << 8); + m_rmdr_lock = lock; +} + +u32 rosetta_device::segment_r(offs_t offset) +{ + return m_segment[offset]; +} + +void rosetta_device::segment_w(offs_t offset, u32 data) +{ + LOG("segment_w 0x%x data 0x%x (%s)\n", offset, data, machine().describe_context()); + + m_segment[offset] = data; +} + +u32 rosetta_device::control_r(offs_t offset) +{ + u32 data = 0; + + switch (offset) + { + case MER: + data = m_control[offset]; + set_pchk(false); + break; + + case MEAR: + m_mear_lock = UNLOCKED; + data = m_control[offset]; + break; + + case RMDR: + m_mear_lock = UNLOCKED; + m_rmdr_lock = false; + data = m_control[offset]; + break; + + default: + data = m_control[offset]; + break; + } + + LOG("control_r %s data 0x%08x (%s)\n", control_names[offset], data, machine().describe_context()); + + return data; +} + +void rosetta_device::control_w(offs_t offset, u32 data) +{ + bool reconfig_tlb = false; + bool reconfig_map = false; + + LOG("control_w %s data 0x%08x (%s)\n", control_names[offset], data, machine().describe_context()); + + switch (offset) + { + case MEAR: + m_mear_lock = UNLOCKED; + m_control[offset] = data; + break; + + case TCR: + reconfig_tlb = (m_control[offset] ^ data) & (TCR_S | TCR_HIB); + m_control[offset] = data; + break; + + case RAMS: + reconfig_tlb = m_control[offset] ^ data; + reconfig_map = m_control[offset] ^ data; + m_control[offset] = data; + break; + + case ROMS: + reconfig_map = m_control[offset] ^ data; + m_control[offset] = data; + break; + + case RMDR: + // only alternate check bits are writeable + m_control[offset] = (m_control[offset] & ~RMDR_ALT) | (data & RMDR_ALT); + break; + + default: + m_control[offset] = data; + break; + } + + if (reconfig_map) + config_map(); + + if (reconfig_tlb) + config_tlb(); +} + +u32 rosetta_device::tlb_r(offs_t offset) +{ + unsigned const tlb_set = BIT(offset, 4); + u32 data = 0; + + switch (offset & 0x60) + { + case 0x00: data = m_tlb[offset & 0xf][tlb_set].field0; break; + case 0x20: data = m_tlb[offset & 0xf][tlb_set].field1; break; + case 0x40: data = m_tlb[offset & 0xf][tlb_set].field2; break; + } + + LOG("tlb_r offset %x data %x\n", offset, data); + + return data; +} + +void rosetta_device::tlb_w(offs_t offset, u32 data) +{ + unsigned const tlb_set = BIT(offset, 4); + + switch (offset & 0x60) + { + case 0x00: m_tlb[offset & 0xf][tlb_set].field0 = data; break; + case 0x20: m_tlb[offset & 0xf][tlb_set].field1 = data; break; + case 0x40: m_tlb[offset & 0xf][tlb_set].field2 = data; break; + } + + LOG("tlb_w offset %x data %x\n", offset, data); +} + +u32 rosetta_device::rca_r(offs_t offset) +{ + unsigned const shift = (offset & 3) * 2; + + if (!m_led_lock) + { + LOG("led 0x%02x (%s)\n", u8(offset), machine().describe_context()); + + m_leds[0] = led_pattern[(offset >> 0) & 15]; + m_leds[1] = led_pattern[(offset >> 4) & 15]; + } + + return (m_rca[offset >> 2] >> shift) & 3; +} + +void rosetta_device::rca_w(offs_t offset, u32 data) +{ + unsigned const shift = (offset & 3) * 2; + + m_rca[offset >> 2] &= ~(3 << shift); + m_rca[offset >> 2] |= (data & 3) << shift; + + m_led_lock = true; +} + +u32 rosetta_device::rom_r(offs_t offset, u32 mem_mask) +{ + if (!machine().side_effects_disabled()) + m_led_lock = false; + + return m_rom[offset]; +} + +void rosetta_device::rom_w(offs_t offset, u32 data, u32 mem_mask) +{ + LOGMASKED(LOG_INVALID, "rom_w invalid 0x%06x data 0x%08x mask 0x%08x (%s)\n", + offset << 2, data, mem_mask, machine().describe_context()); + + if (!machine().side_effects_disabled()) + m_control[MER] |= MER_W; +} + +void rosetta_device::ram_w(offs_t offset, u32 data, u32 mem_mask) +{ + if (offset < m_ram_size) + { + m_ram[offset] = (m_ram[offset] & ~mem_mask) | (data & mem_mask); + + // set reference and change bits + if (!machine().side_effects_disabled()) + m_rca[offset >> 11] |= ((RCA_R | RCA_C) << ((offset >> 8) & 6)); + + m_ecc[offset] = (m_control[TCR] & TCR_D) ? (m_control[RMDR] & RMDR_ALT) : compute_ecc(m_ram[offset]); + } + else + { + LOGMASKED(LOG_INVALID, "ram_w invalid 0x%06x data 0x%08x mask 0x%08x (%s)\n", + offset << 2, data, mem_mask, machine().describe_context()); + + m_control[MER] |= MER_B; + } +} + +u32 rosetta_device::ram_r(offs_t offset, u32 mem_mask) +{ + if (offset < m_ram_size) + { + u32 data = m_ram[offset]; + + if (!machine().side_effects_disabled()) + { + // set reference bit + m_rca[offset >> 11] |= (RCA_R << ((offset >> 8) & 6)); + + u8 const ecc = m_ecc[offset]; + + switch (check_ecc(data, ecc)) + { + case 1: + // correctable error + if ((m_control[TCR] & TCR_C) || (m_control[TCR] & TCR_D)) + { + if (!(m_control[MER] & MER_U)) + m_control[MER] |= MER_C; + set_rmdr(ecc, true); + } + break; + case 2: + // uncorrectable error + m_control[MER] |= MER_U; + set_rmdr(ecc, true); + break; + } + } + + return data; + } + else + { + LOGMASKED(LOG_INVALID, "ram_r invalid 0x%06x mask 0x%08x (%s)\n", + offset << 2, mem_mask, machine().describe_context()); + + m_control[MER] |= MER_B; + + return 0; + } +} + +u8 rosetta_device::compute_ecc(u32 const data) const +{ + u8 result = 0; + + for (unsigned i = 0; i < ARRAY_LENGTH(ecc_bits); i++) + result ^= BIT(data, 31 - i) ? ecc_bits[i] : 0; + + return result; +} + +unsigned rosetta_device::check_ecc(u32 &data, u8 const ecc) const +{ + u8 const error = compute_ecc(data) ^ ecc; + + if (error) + { + for (unsigned i = 0; i < ARRAY_LENGTH(ecc_bits); i++) + { + if (error == ecc_bits[i]) + { + LOGMASKED(LOG_ECC, "check_ecc single-bit error 0x%08x ecc 0x%02x error 0x%02x\n", data, ecc, error); + + // correct error + data ^= (0x8000'0000U >> i); + + return 1; + } + } + + // multiple-bit error + LOGMASKED(LOG_ECC, "check_ecc multiple-bit error 0x%08x ecc 0x%02x error 0x%02x\n", data, ecc, error); + return 2; + } + else + return 0; +} + +void rosetta_device::config_map() +{ + // unmap everything + m_mem_space->unmap_readwrite(0x000000, 0xffffff); + + // map rom + if (m_control[ROMS] & ROMS_SIZE) + { + unsigned const shift = (m_control[ROMS] & ROMS_SIZE) > 7 ? (m_control[ROMS] & ROMS_SIZE) - 7 : 0; + size_t const size = 0x10000ULL << shift; + unsigned const factor = (m_control[ROMS] & ROMS_START) >> (4 + shift); + + LOG("config rom size %dk map 0x%06x-0x%06x\n", size >> 10, size * factor, size * factor + size - 1); + + /* + * IPL code assumes ROM is mirrored within the configured range, making it + * difficult to identify under what circumstances an invalid memory access to + * the configured ROM address range would be reported. + */ + size_t const available = std::min(size, m_rom.bytes()); + m_mem_space->install_readwrite_handler(size * factor, size * factor + available - 1, available - 1, (size - 1) & ~(available - 1), 0, + read32s_delegate(*this, FUNC(rosetta_device::rom_r)), + write32s_delegate(*this, FUNC(rosetta_device::rom_w))); + } + + // map ram + if (m_control[RAMS] & RAMS_SIZE) + { + unsigned const shift = (m_control[RAMS] & RAMS_SIZE) > 7 ? (m_control[RAMS] & RAMS_SIZE) - 7 : 0; + unsigned const size = 0x10000U << shift; + unsigned const factor = (m_control[RAMS] & RAMS_START) >> (4 + shift); + + LOG("config ram size %dk map 0x%06x-0x%06x\n", size >> 10, size * factor, size * factor + size - 1); + + m_mem_space->install_readwrite_handler(size * factor, size * factor + size - 1, + read32s_delegate(*this, FUNC(rosetta_device::ram_r)), + write32s_delegate(*this, FUNC(rosetta_device::ram_w))); + } +} + +void rosetta_device::config_tlb() +{ + unsigned const ram_size = std::max(m_control[RAMS] & RAMS_SIZE, 7U); + + if (m_control[TCR] & TCR_S) + { + m_atag_mask = TLB_AT4K; + m_page_mask = 0xffff'f000U; + m_page_shift = 12; + + m_hat_base = (m_control[TCR] & TCR_HIB) << (ram_size - 1); + m_hat_mask = (1U << (ram_size - 1)) - 4; + } + else + { + m_atag_mask = TLB_AT2K; + m_page_mask = 0xffff'f800U; + m_page_shift = 11; + + m_hat_base = (m_control[TCR] & TCR_HIB) << ram_size; + m_hat_mask = (1U << ram_size) - 4; + } + + LOG("config page size %d hat base 0x%08x mask 0x%04x\n", 1 << m_page_shift, m_hat_base, m_hat_mask); +} + +void rosetta_device::tlb_inv_all(u32 data) +{ + LOGMASKED(LOG_TLB, "tlb_inv_all (%s)\n", machine().describe_context()); + + for (unsigned i = 0; i < 16; i++) + { + m_tlb[i][0].field1 &= ~TLB_V; + m_tlb[i][1].field1 &= ~TLB_V; + } +} + +void rosetta_device::tlb_inv_segment(u32 data) +{ + LOGMASKED(LOG_TLB, "tlb_inv_segment %x (%s)\n", data & 15, machine().describe_context()); + + unsigned const identifier = (m_segment[data & 15] & SEGMENT_ID) >> 2; + + for (unsigned i = 0; i < 16; i++) + { + if (((m_tlb[i][0].field0 & TLB_SEG) >> 17) == identifier) + m_tlb[i][0].field1 &= ~TLB_V; + + if (((m_tlb[i][1].field0 & TLB_SEG) >> 17) == identifier) + m_tlb[i][1].field1 &= ~TLB_V; + } +} + +void rosetta_device::tlb_inv_address(u32 data) +{ + u64 const virtual_address = (u64(m_segment[data >> 28] & SEGMENT_ID) << 26) | (data & 0x0fff'ffffU); + unsigned const tlb_index = (data >> m_page_shift) & 15; + + if ((m_tlb[tlb_index][0].field1 & TLB_V) && !((m_tlb[tlb_index][0].field0 ^ (virtual_address >> 11)) & m_atag_mask)) + { + LOGMASKED(LOG_TLB, "tlb_inv_address 0x%08x set 0 (%s)\n", data, machine().describe_context()); + + m_tlb[tlb_index][0].field1 &= ~TLB_V; + m_tlb_lru &= ~(1U << tlb_index); + } + + if ((m_tlb[tlb_index][1].field1 & TLB_V) && !((m_tlb[tlb_index][1].field0 ^ (virtual_address >> 11)) & m_atag_mask)) + { + LOGMASKED(LOG_TLB, "tlb_inv_address 0x%08x set 1 (%s)\n", data, machine().describe_context()); + + m_tlb[tlb_index][1].field1 &= ~TLB_V; + m_tlb_lru |= (1U << tlb_index); + } +} + +void rosetta_device::compute_address(u32 data) +{ + unsigned const segment = data >> 28; + tlb_entry t; + + m_control[TRAR] = TRAR_I; + + if ((m_control[TCR] & TCR_V) && !segment) + m_control[TRAR] = data & 0x00ff'ffffU; + else if (!tlb_reload(t, (u64(m_segment[segment] & SEGMENT_ID) << 26) | (data & 0x0fff'ffffU))) + m_control[TRAR] = (m_control[TCR] & TCR_S) + ? ((t.field1 & TLB_RPN4K) << 8) | (data & 0x0fffU) + : ((t.field1 & TLB_RPN2K) << 8) | (data & 0x07ffU); +} + +bool rosetta_device::fetch(u32 address, u16 &data, rsc_mode const mode) +{ + if (mode & rsc_mode::RSC_T) + { + // FIXME: differences between fetch and load + if (!translate(address, true, false)) + return false; + + // FIXME: unconditionally access RAM + } + + // access memory and handle errors + u32 const mer = m_control[MER] & (MER_B | MER_U | MER_C); + data = m_mem.read_word(address); + + switch ((mer ^ m_control[MER]) & (MER_B | MER_U | MER_C)) + { + case MER_U: + set_mear(address, MEMORY); + if (!(m_control[TCR] & TCR_D)) + { + set_mchk(true); + return false; + } + break; + + case MER_C: + set_mear(address, MEMORY); + if (!(m_control[TCR] & TCR_D)) + set_mchk(true); + break; + + case MER_B: + set_mear(address, MEMORY); + return false; + } + + return true; +} + +template bool rosetta_device::load(u32 address, T &data, rsc_mode const mode, bool sp) +{ + if (mode & rsc_mode::RSC_T) + { + if (!translate(address, sp, false)) + { + m_control[MER] |= MER_L; + if ((sp && (m_control[MER] & (MER_V | MER_I | MER_F | MER_S | MER_P | MER_D))) || (m_control[MER] & (MER_S))) + set_mear(address, LOCKED); + + return false; + } + + // FIXME: unconditionally access RAM + } + + // access memory and handle errors + u32 const mer = m_control[MER] & (MER_B | MER_U | MER_C); + switch (sizeof(T)) + { + case 1: data = m_mem.read_byte(address); break; + case 2: data = m_mem.read_word(address); break; + case 4: data = m_mem.read_dword(address); break; + } + + switch ((mer ^ m_control[MER]) & (MER_B | MER_U | MER_C)) + { + case MER_U: + set_mear(address, MEMORY); + if (!(m_control[TCR] & TCR_D)) + { + set_mchk(true); + return false; + } + break; + + case MER_C: + set_mear(address, MEMORY); + if (!(m_control[TCR] & TCR_D)) + set_mchk(true); + break; + + case MER_B: + set_mear(address, MEMORY); + return false; + } + + return true; +} + +template bool rosetta_device::store(u32 address, T data, rsc_mode const mode, bool sp) +{ + if (mode & rsc_mode::RSC_T) + { + if (!translate(address, sp, true)) + { + m_control[MER] &= ~MER_L; + if ((sp && (m_control[MER] & (MER_V | MER_I | MER_F | MER_S | MER_P | MER_D))) || (m_control[MER] & (MER_S))) + set_mear(address, LOCKED); + + return false; + } + + // FIXME: unconditionally access RAM + } + + // access memory and handle errors + u32 const mer = m_control[MER] & (MER_B | MER_W); + switch (sizeof(T)) + { + case 1: m_mem.write_byte(address, data); break; + case 2: m_mem.write_word(address, data); break; + case 4: m_mem.write_dword(address, data); break; + } + + switch ((mer ^ m_control[MER]) & (MER_B | MER_W)) + { + case MER_W: + set_mear(address, MEMORY); + set_pchk(true); + break; + + case MER_B: + set_mear(address, MEMORY); + if (mode & RSC_T) + return false; + else + set_pchk(true); + break; + } + + return true; +} + +template bool rosetta_device::modify(u32 address, std::function f, rsc_mode const mode) +{ + if (mode & rsc_mode::RSC_T) + { + if (!translate(address, true, true)) + { + m_control[MER] &= ~MER_L; + if (m_control[MER] & (MER_V | MER_I | MER_F | MER_S | MER_P | MER_D)) + set_mear(address, LOCKED); + + return false; + } + + // FIXME: unconditionally access RAM + } + + // access memory and handle errors + u32 const mer = m_control[MER] & (MER_B | MER_W); + switch (sizeof(T)) + { + case 1: m_mem.write_byte(address, f(m_mem.read_byte(address))); break; + case 2: m_mem.write_word(address, f(m_mem.read_word(address))); break; + case 4: m_mem.write_dword(address, f(m_mem.read_dword(address))); break; + } + + switch ((mer ^ m_control[MER]) & (MER_B | MER_W)) + { + case MER_W: + set_mear(address, MEMORY); + set_pchk(true); + break; + + case MER_B: + set_mear(address, MEMORY); + if (mode & RSC_T) + return false; + else + set_pchk(true); + break; + } + + return true; +} diff --git a/src/mame/machine/rosetta.h b/src/mame/machine/rosetta.h new file mode 100644 index 00000000000..a97036a01fc --- /dev/null +++ b/src/mame/machine/rosetta.h @@ -0,0 +1,181 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_MACHINE_ROSETTA_H +#define MAME_MACHINE_ROSETTA_H + +#pragma once + +#include "cpu/romp/rsc.h" + +class rosetta_device + : public device_t + , public rsc_cpu_interface +{ +public: + // ram size in doublewords + enum ram_size : unsigned + { + RAM_NONE = 0, + RAM_1M = 0x0004'0000, + RAM_2M = 0x0008'0000, + RAM_4M = 0x0010'0000, + RAM_8M = 0x0020'0000, + RAM_16M = 0x0040'0000, + }; + + rosetta_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, ram_size ram = RAM_NONE); + + template void set_mem(T &&tag, int spacenum) { m_mem_space.set_tag(std::forward(tag), spacenum); } + template void set_rom(T &&tag) { m_rom.set_tag(std::forward(tag)); } + + auto out_pchk() { return m_out_pchk.bind(); } + auto out_mchk() { return m_out_mchk.bind(); } + + using rsc_mode = rsc_bus_interface::rsc_mode; + + // rsc_cpu_interface overrides + virtual bool fetch(u32 address, u16 &data, rsc_mode const mode) override; + virtual bool ior(u32 address, u32 &data) override; + virtual bool iow(u32 address, u32 data) override; + + // rsc_bus_interface overrides + virtual bool load(u32 address, u8 &data, rsc_mode const mode, bool sp) override { return load(address, data, mode, sp); } + virtual bool load(u32 address, u16 &data, rsc_mode const mode, bool sp) override { return load(address, data, mode, sp); } + virtual bool load(u32 address, u32 &data, rsc_mode const mode, bool sp) override { return load(address, data, mode, sp); } + virtual bool store(u32 address, u8 data, rsc_mode const mode, bool sp) override { return store(address, data, mode, sp); } + virtual bool store(u32 address, u16 data, rsc_mode const mode, bool sp) override { return store(address, data, mode, sp); } + virtual bool store(u32 address, u32 data, rsc_mode const mode, bool sp) override { return store(address, data, mode, sp); } + virtual bool modify(u32 address, std::function f, rsc_mode const mode) override { return modify(address, f, mode); } + virtual bool modify(u32 address, std::function f, rsc_mode const mode) override { return modify(address, f, mode); } + virtual bool modify(u32 address, std::function f, rsc_mode const mode) override { return modify(address, f, mode); } + +protected: + // device_t overrides + virtual void device_validity_check(validity_checker &valid) const override; + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_post_load() override; + + // virtual address translation + bool translate(u32 &address, bool system_processor, bool store); + + // rsc_bus_interface implementation + template bool load(u32 address, T &data, rsc_mode const mode, bool sp); + template bool store(u32 address, T data, rsc_mode const mode, bool sp); + template bool modify(u32 address, std::function f, rsc_mode const mode); + + // register read handlers + u32 segment_r(offs_t offset); + u32 control_r(offs_t offset); + u32 tlb_r(offs_t offset); + + // register write handlers + void segment_w(offs_t offset, u32 data); + void control_w(offs_t offset, u32 data); + void tlb_w(offs_t offset, u32 data); + + // memory read handlers + u32 rom_r(offs_t offset, u32 mem_mask); + u32 ram_r(offs_t offset, u32 mem_mask); + u32 rca_r(offs_t offset); + + // memory write handlers + void rom_w(offs_t offset, u32 data, u32 mem_mask); + void ram_w(offs_t offset, u32 data, u32 mem_mask); + void rca_w(offs_t offset, u32 data); + + u8 compute_ecc(u32 const data) const; + unsigned check_ecc(u32 &data, u8 const ecc) const; + + struct tlb_entry + { + u32 field0 = 0; // address tag + u32 field1 = 0; // real page, valid, key + u32 field2 = 0; // write, transaction identifier, lockbits + }; + tlb_entry tlb_search(u64 const virtual_address, bool const special); + u32 tlb_reload(tlb_entry &tlb_entry, u64 const virtual_address, bool special = false); + + void tlb_inv_all(u32 data); + void tlb_inv_segment(u32 data); + void tlb_inv_address(u32 data); + void compute_address(u32 data); + + void config_map(); + void config_tlb(); + + enum mear_state : u32 + { + UNLOCKED, + LOCKED, + MEMORY, + }; + void set_mear(u32 const address, mear_state lock); + void set_rmdr(u8 const ecc, bool lock); + + void set_pchk(bool state) + { + if (state != m_pchk_state) + { + m_pchk_state = state; + + // program check line is active low + m_out_pchk(!m_pchk_state); + } + } + + void set_mchk(bool state) + { + // assume edge-triggered, active low + if (state) + { + m_out_mchk(0); + m_out_mchk(1); + } + else + m_out_mchk(1); + } + +private: + required_address_space m_mem_space; + required_region_ptr m_rom; + output_finder<2> m_leds; + + devcb_write_line m_out_pchk; + devcb_write_line m_out_mchk; + + memory_access<24, 2, 0, ENDIANNESS_BIG>::cache m_mem; + + // registers + u32 m_segment[16]; + u32 m_control[9]; + + // lock and line state + mear_state m_mear_lock; + bool m_rmdr_lock; + bool m_led_lock; + bool m_pchk_state; + + // tlb state + tlb_entry m_tlb[16][2]; + u16 m_tlb_lru; + + // storage + std::unique_ptr m_ram; + std::unique_ptr m_ecc; + std::unique_ptr m_rca; + + // address translation constants + u32 m_atag_mask; + u32 m_page_mask; + unsigned m_page_shift; + u32 m_hat_base; + u16 m_hat_mask; + + ram_size const m_ram_size; +}; + +DECLARE_DEVICE_TYPE(ROSETTA, rosetta_device) + +#endif // MAME_MACHINE_ROSETTA_H diff --git a/src/mame/machine/rtpc_iocc.cpp b/src/mame/machine/rtpc_iocc.cpp new file mode 100644 index 00000000000..b06cb3f5147 --- /dev/null +++ b/src/mame/machine/rtpc_iocc.cpp @@ -0,0 +1,349 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * IBM RT PC I/O Channel Converter/Controller + * + * Sources: + * - http://bitsavers.org/pdf/ibm/pc/rt/75X0232_RT_PC_Technical_Reference_Volume_1_Jun87.pdf + * + * TODO: + * - bus spaces should be little endian + * - alternate controllers, region mode dma + * - improve rsc interface + * - state saving + * - refactoring and cleanup + */ + +#include "emu.h" +#include "rtpc_iocc.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_DMA (1U << 1) +#define LOG_WIDEPIO (1U << 2) + +//#define VERBOSE (LOG_GENERAL|LOG_DMA) +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(RTPC_IOCC, rtpc_iocc_device, "rtpc_iocc", "RT PC I/O Channel Converter/Controller") + +rtpc_iocc_device::rtpc_iocc_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, RTPC_IOCC, tag, owner, clock) + , device_memory_interface(mconfig, *this) + , rsc_bus_interface(mconfig, *this) + , m_mem_config("mem", ENDIANNESS_BIG, 16, 24, 0) + , m_pio_config("pio", ENDIANNESS_BIG, 16, 24, 0) + , m_out_int(*this) + , m_out_rst(*this) + , m_rsc(*this, "^mmu") + , m_csr(0) + , m_ccr(0) + , m_dbr(0) + , m_dmr(0) + , m_tcw{} + , m_adc(0) + , m_out_int_state(false) +{ +} + +device_memory_interface::space_config_vector rtpc_iocc_device::memory_space_config() const +{ + return space_config_vector{ + std::make_pair(AS_PROGRAM, &m_mem_config), + std::make_pair(AS_IO, &m_pio_config) + }; +} + +void rtpc_iocc_device::device_start() +{ + m_out_int.resolve_safe(); + m_out_rst.resolve_safe(); + + save_item(NAME(m_csr)); + save_item(NAME(m_ccr)); + save_item(NAME(m_dbr)); + save_item(NAME(m_dmr)); + save_item(NAME(m_tcw)); + save_item(NAME(m_adc)); + save_item(NAME(m_out_int_state)); +} + +void rtpc_iocc_device::device_reset() +{ + m_csr = 0; + + set_int(false); +} + +u8 rtpc_iocc_device::dma_b_r(offs_t offset) +{ + u8 data = 0; + + if (!BIT(m_dmr, 7 - m_adc)) + { + u16 const tcw = m_tcw[(m_adc << 6) | (offset >> 11)]; + u32 const real = ((tcw & TCW_PFX) << 11) | (offset & 0x7ff); + + LOGMASKED(LOG_DMA, "dma0 tcw 0x%04x real 0x%08x\n", tcw, real); + if (tcw & TCW_IOC) + data = space(AS_PROGRAM).read_byte(real); + else + { + if (!m_rsc->load(real, data, RSC_N)) + { + // on dma exception + // - assert interrupt (level 2) + // - csr | DE | ~PER | INTP + + m_csr &= ~CSR_PER; + m_csr |= (CSR_DE0 >> m_adc) | CSR_DEXK; + m_out_rst(1); + set_int(true); + } + } + } + else + fatalerror("rtpc_iocc_device::dma_b_r() invalid dma operation\n"); + + return data; +} + +void rtpc_iocc_device::dma_b_w(offs_t offset, u8 data) +{ + LOGMASKED(LOG_DMA, "dma0 offset 0x%04x data 0x%02x\n", offset, data); + + if (!BIT(m_dmr, 7 - m_adc)) + { + u16 const tcw = m_tcw[(m_adc << 6) | (offset >> 11)]; + u32 const real = ((tcw & TCW_PFX) << 11) | (offset & 0x7ff); + + LOGMASKED(LOG_DMA, "dma0 tcw 0x%04x real 0x%08x\n", tcw, real); + if (tcw & TCW_IOC) + space(AS_PROGRAM).write_byte(real, data); + else + m_rsc->store(real, data, RSC_N); + } + else + fatalerror("rtpc_iocc_device::dma_b_w() invalid dma operation\n"); +} + +u8 rtpc_iocc_device::dma_w_r(offs_t offset) +{ + u16 data = 0; + + if (!BIT(m_dmr, 7 - m_adc)) + { + u16 const tcw = m_tcw[(m_adc << 6) | (offset >> 10)]; + u32 const real = ((tcw & TCW_PFX) << 11) | (offset & 0x7ff); + + LOGMASKED(LOG_DMA, "dma1 tcw 0x%04x real 0x%08x\n", tcw, real); + if (tcw & TCW_IOC) + data = space(AS_PROGRAM).read_word(real); + else + m_rsc->load(real, data, RSC_N); + } + else + fatalerror("rtpc_iocc_device::dma_w_r() invalid dma operation\n"); + + return data; +} + +void rtpc_iocc_device::dma_w_w(offs_t offset, u8 data) +{ + LOGMASKED(LOG_DMA, "dma1 offset 0x%04x data 0x%02x\n", offset, data); + + if (!BIT(m_dmr, 7 - m_adc)) + { + u16 const tcw = m_tcw[(m_adc << 6) | (offset >> 10)]; + u32 const real = ((tcw & TCW_PFX) << 11) | ((offset & 0x7ff) << 1); + + LOGMASKED(LOG_DMA, "dma1 tcw 0x%04x real 0x%08x\n", tcw, real); + // FIXME: upper data bits + if (tcw & TCW_IOC) + space(AS_PROGRAM).write_word(real, data); + else + m_rsc->store(real, u16(data), RSC_N); + } + else + fatalerror("rtpc_iocc_device::dma_w_w() invalid dma operation\n"); +} + +template bool rtpc_iocc_device::load(u32 address, T &data, rsc_mode const mode) +{ + unsigned const s = (address >> 24) & 15 ? AS_PROGRAM : AS_IO; + + if (s == AS_PROGRAM && (mode & RSC_U) && !(m_ccr & CCR_MMP)) + { + LOG("load mem protection violation (%s)\n", machine().describe_context()); + m_csr |= CSR_EXR | CSR_PER | CSR_PD | CSR_PVIO; + + return false; + } + + if (s == AS_IO) + { + if ((mode & RSC_U) && (address == 0xf001'0800U || !(m_ccr & CCR_IMP))) + { + LOG("load pio protection violation (%s)\n", machine().describe_context()); + m_csr |= CSR_EXR | CSR_PER | CSR_PD | CSR_PVIO; + + return false; + } + } + + switch (sizeof(T)) + { + case 1: data = space(s).read_byte(address); break; + case 2: + if (s == 2 && target_size(address) < sizeof(T)) + { + LOGMASKED(LOG_WIDEPIO, "load pio w<-b 0x%08x (%s)\n", address, machine().describe_context()); + data = u16(space(s).read_byte(address)) << 8; + data |= space(s).read_byte(address); + } + else + data = space(s).read_word(address); + break; + case 4: + if (s == 2 && target_size(address) < sizeof(T)) + { + if (target_size(address) == 1) + { + LOGMASKED(LOG_WIDEPIO, "load pio d<-b 0x%08x (%s)\n", address, machine().describe_context()); + data = u32(space(s).read_byte(address)) << 24; + data |= u32(space(s).read_byte(address)) << 16; + data |= u32(space(s).read_byte(address)) << 8; + data |= space(s).read_byte(address); + } + else + { + LOGMASKED(LOG_WIDEPIO, "load pio d<-w 0x%08x (%s)\n", address, machine().describe_context()); + data = u32(space(s).read_word(address)) << 16; + data |= space(s).read_word(address); + } + } + else + data = space(s).read_dword(address); + break; + } + + return true; +} + +#ifdef _MSC_VER +// avoid incorrect MSVC warnings about excessive shift sizes below +#pragma warning(disable:4333) +#endif + +template bool rtpc_iocc_device::store(u32 address, T data, rsc_mode const mode) +{ + unsigned const spacenum = (address >> 24) & 15 ? AS_PROGRAM : AS_IO; + + if (spacenum == AS_PROGRAM && (mode & RSC_U) && !(m_ccr & CCR_MMP)) + { + LOG("store mem protection violation (%s)\n", machine().describe_context()); + m_csr |= CSR_PER | CSR_PD | CSR_PVIO; + if (mode & RSC_T) + { + m_csr |= CSR_EXR; + return false; + } + else + set_int(true); + + return true; + } + + if (spacenum == AS_IO && (mode & RSC_U)) + { + if (address == 0xf001'0800U || !(m_ccr & CCR_IMP)) + { + LOG("store pio protection violation (%s)\n", machine().describe_context()); + m_csr |= CSR_PER | CSR_PD | CSR_PVIO; + if (mode & RSC_T) + { + m_csr |= CSR_EXR; + return false; + } + else + set_int(true); + + return true; + } + } + + switch (sizeof(T)) + { + case 1: space(spacenum).write_byte(address, data); break; + case 2: + if (spacenum == AS_IO && target_size(address) < sizeof(T)) + { + LOGMASKED(LOG_WIDEPIO, "store pio w->b 0x%08x data 0x%04x (%s)\n", address, data, machine().describe_context()); + space(spacenum).write_byte(address, u8(data >> 8)); + space(spacenum).write_byte(address, u8(data >> 0)); + } + else + space(spacenum).write_word(address, data); + break; + case 4: + if (spacenum == AS_IO && target_size(address) < sizeof(T)) + { + if (target_size(address) == 1) + { + LOGMASKED(LOG_WIDEPIO, "store pio d->b 0x%08x data 0x%08x (%s)\n", address, data, machine().describe_context()); + space(spacenum).write_byte(address, u8(data >> 24)); + space(spacenum).write_byte(address, u8(data >> 16)); + space(spacenum).write_byte(address, u8(data >> 8)); + space(spacenum).write_byte(address, u8(data >> 0)); + } + else + { + LOGMASKED(LOG_WIDEPIO, "store pio d->w 0x%08x data 0x%08x (%s)\n", address, data, machine().describe_context()); + space(spacenum).write_word(address, u16(data >> 16)); + space(spacenum).write_word(address, u16(data >> 0)); + } + } + else + space(spacenum).write_dword(address, data); + break; + } + + return true; +} + +template bool rtpc_iocc_device::modify(u32 address, std::function f, rsc_mode const mode) +{ + unsigned const spacenum = (address >> 24) & 15 ? AS_PROGRAM : AS_IO; + + if (spacenum == AS_PROGRAM && (mode & RSC_U) && !(m_ccr & CCR_MMP)) + { + LOG("modify mem protection violation (%s)\n", machine().describe_context()); + m_csr |= CSR_PER | CSR_PD | CSR_PVIO; + if (mode & RSC_T) + { + m_csr |= CSR_EXR; + return false; + } + else + set_int(true); + + return true; + } + + if (spacenum == AS_IO) + { + LOG("modify pio space invalid operation (%s)\n", machine().describe_context()); + m_csr |= CSR_EXR | CSR_PER | CSR_PD | CSR_INVOP; + + return false; + } + + switch (sizeof(T)) + { + case 1: space(spacenum).write_byte(address, f(space(spacenum).read_byte(address))); break; + case 2: space(spacenum).write_word(address, f(space(spacenum).read_word(address))); break; + case 4: space(spacenum).write_dword(address, f(space(spacenum).read_dword(address))); break; + } + + return true; +} diff --git a/src/mame/machine/rtpc_iocc.h b/src/mame/machine/rtpc_iocc.h new file mode 100644 index 00000000000..cf7a2052ec7 --- /dev/null +++ b/src/mame/machine/rtpc_iocc.h @@ -0,0 +1,170 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_MACHINE_RTPC_IOCC_H +#define MAME_MACHINE_RTPC_IOCC_H + +#pragma once + +#include "cpu/romp/rsc.h" + +class rtpc_iocc_device + : public device_t + , public device_memory_interface + , public rsc_bus_interface +{ +public: + rtpc_iocc_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + + auto out_int() { return m_out_int.bind(); } + auto out_rst() { return m_out_rst.bind(); } + + enum ccr_mask : u8 + { + CCR_RFE = 0x02, // refresh enable + CCR_RFT = 0x04, // refresh period (0=14.9µs, 1=6.4µs) + CCR_MMP = 0x08, // memory map privilege + CCR_IMP = 0x10, // i/o map privilege + CCR_DKA = 0x20, // dma keyboard access + CCR_DSA = 0x40, // dma i/o subsystem access + CCR_DCA = 0x80, // dma control register access + }; + + enum csr_mask : u32 + { + CSR_EXR = 0x80000000, // exception reported + CSR_INTP = 0x40000000, // interrupt pending + CSR_EPOW = 0x10000000, // early power off warning + CSR_SRST = 0x08000000, // soft reset + CSR_SAT = 0x04000000, // system attention + CSR_PER = 0x01000000, // pio error + CSR_DE0 = 0x00800000, // dma error channel 0 + CSR_DE1 = 0x00400000, // dma error channel 1 + CSR_DE2 = 0x00200000, // dma error channel 2 + CSR_DE3 = 0x00100000, // dma error channel 3 + CSR_DE5 = 0x00080000, // dma error channel 5 + CSR_DE6 = 0x00040000, // dma error channel 6 + CSR_DE7 = 0x00020000, // dma error channel 7 + CSR_DE8 = 0x00010000, // dma error channel 8 + CSR_PD = 0x00008000, // pio/dma + CSR_PVIO = 0x00004000, // protection violation + CSR_INVOP = 0x00002000, // invalid operation + CSR_IOCK = 0x00001000, // i/o channel check + CSR_DEXK = 0x00000800, // dma exception + CSR_CRC = 0x00000400, // channel reset captured + CSR_SBB = 0x00000200, // system board busy + CSR_PRP = 0x00000100, // pio request pending + + CSR_RSV = 0x220000ff, // reserved + }; + + enum tcw_mask : u16 + { + TCW_PFX = 0x1fff, // translation prefix + TCW_IOC = 0x4000, // i/o channel destination + TCW_VIR = 0x8000, // virtual access + }; + + using rsc_mode = rsc_bus_interface::rsc_mode; + + // rsc_pio_interface overrides + virtual bool load(u32 address, u8 &data, rsc_mode const mode, bool sp) override { return load(address, data, mode); } + virtual bool load(u32 address, u16 &data, rsc_mode const mode, bool sp) override { return load(address, data, mode); } + virtual bool load(u32 address, u32 &data, rsc_mode const mode, bool sp) override { return load(address, data, mode); } + virtual bool store(u32 address, u8 data, rsc_mode const mode, bool sp) override { return store(address, data, mode); } + virtual bool store(u32 address, u16 data, rsc_mode const mode, bool sp) override { return store(address, data, mode); } + virtual bool store(u32 address, u32 data, rsc_mode const mode, bool sp) override { return store(address, data, mode); } + virtual bool modify(u32 address, std::function f, rsc_mode const mode) override { return modify(address, f, mode); } + virtual bool modify(u32 address, std::function f, rsc_mode const mode) override { return modify(address, f, mode); } + virtual bool modify(u32 address, std::function f, rsc_mode const mode) override { return modify(address, f, mode); } + + u8 ccr_r() { return m_ccr; } + void ccr_w(u8 data) { m_ccr = data; } + + template u16 csr_r() { return u16((m_csr | CSR_RSV) >> (16 * Word)); } + void csr_w(u16 data) { set_int(false); m_csr = 0; } + + u8 dma_b_r(offs_t offset); + u8 dma_w_r(offs_t offset); + void dma_b_w(offs_t offset, u8 data); + void dma_w_w(offs_t offset, u8 data); + + u8 dmr_r() { return m_dmr; } + u8 dbr_r() { return m_dbr; } + void dmr_w(u8 data) { m_dmr = data; } + void dbr_w(u8 data) { m_dbr = data; } + + u16 tcw_r(offs_t offset) { return m_tcw[offset]; } + void tcw_w(offs_t offset, u16 data, u16 mem_mask) { COMBINE_DATA(&m_tcw[offset]); } + + template void dack_w(int state) { if (!state) m_adc = Channel; } + +protected: + // device_t overrides + 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; + + template bool load(u32 address, T &data, rsc_mode const mode); + template bool store(u32 address, T data, rsc_mode const mode); + template bool modify(u32 address, std::function f, rsc_mode const mode); + + void set_int(bool state) + { + if (state != m_out_int_state) + { + if (state) + m_csr |= CSR_INTP; + m_out_int_state = state; + m_out_int(!m_out_int_state); + } + } + + unsigned target_size(u32 const address) const + { + if (address < 0xf000'8000U) + { + if (address == 0xf000'0110U || address == 0xf000'0112U) + return 2; + else + // FIXME: get size from isa bus + return 1; + } + else if (address == 0xf000'8400U) + // exception for kls + return 2; + else if (address < 0xf001'0000U) + return 1; + else if (address < 0xf001'0800U) + return 2; + else + return 4; + } + +private: + address_space_config m_mem_config; + address_space_config m_pio_config; + + devcb_write_line m_out_int; + devcb_write_line m_out_rst; + + required_device m_rsc; + + u32 m_csr; // channel status register + u8 m_ccr; // channel control register + + u8 m_dbr; // dma buffer register + u8 m_dmr; // dma mode register + u16 m_tcw[1024]; // dma translation control words + + unsigned m_adc; // active dma channel + + bool m_out_int_state; +}; + +DECLARE_DEVICE_TYPE(RTPC_IOCC, rtpc_iocc_device) + +#endif // MAME_MACHINE_RTPC_IOCC_H diff --git a/src/mame/mame.lst b/src/mame/mame.lst index f5cea93339e..c5868c83ede 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -35828,6 +35828,13 @@ rt1715 // rt1715lc // (latin/cyrillic) rt1715w // +@source:rtpc.cpp +rtpc010 // IBM RT PC Model 010 +rtpc015 // IBM RT PC Model 015 +rtpc020 // IBM RT PC Model 020 +rtpc025 // IBM RT PC Model 025 +rtpc025 // IBM RT PC Model A25 + @source:runaway.cpp qwak // (proto) (c) 1982 runaway // (proto) (c) 1982 diff --git a/src/mame/mess.flt b/src/mame/mess.flt index c724869402c..553e4000cc0 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -850,6 +850,7 @@ roland_tr707.cpp roland_tr909.cpp roland_u20.cpp rt1715.cpp +rtpc.cpp rvoice.cpp rx78.cpp rz1.cpp -- cgit v1.2.3