diff options
-rw-r--r-- | scripts/src/machine.lua | 12 | ||||
-rw-r--r-- | scripts/target/mame/mess.lua | 1 | ||||
-rw-r--r-- | src/devices/machine/i82357.cpp | 307 | ||||
-rw-r--r-- | src/devices/machine/i82357.h | 91 | ||||
-rw-r--r-- | src/mame/drivers/jazz.cpp | 259 | ||||
-rw-r--r-- | src/mame/includes/jazz.h | 37 | ||||
-rw-r--r-- | src/mame/machine/jazz_mct_adr.cpp | 261 | ||||
-rw-r--r-- | src/mame/machine/jazz_mct_adr.h | 125 |
8 files changed, 1025 insertions, 68 deletions
diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index a68236ab223..6d1c8a96ba9 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -3857,3 +3857,15 @@ if (MACHINES["DC7085"]~=null) then MAME_DIR .. "src/devices/machine/dc7085.h", } end + +--------------------------------------------------- +-- +--@src/devices/machine/i82357.h,MACHINES["I82357"] = true +--------------------------------------------------- + +if (MACHINES["I82357"]~=null) then + files { + MAME_DIR .. "src/devices/machine/i82357.cpp", + MAME_DIR .. "src/devices/machine/i82357.h", + } +end diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 359e714b7aa..3b9fbab4243 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -682,6 +682,7 @@ MACHINES["IOPTIMER"] = true MACHINES["Z8038"] = true MACHINES["AIC6250"] = true MACHINES["DC7085"] = true +MACHINES["I82357"] = true -------------------------------------------------- -- specify available bus cores diff --git a/src/devices/machine/i82357.cpp b/src/devices/machine/i82357.cpp new file mode 100644 index 00000000000..9b3be9c0905 --- /dev/null +++ b/src/devices/machine/i82357.cpp @@ -0,0 +1,307 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * An implementation of the Intel 82357 Integrated System Peripheral. + * + * This device was one part of the 3-chip Intel 82350 EISA bus chipset. + * + * Sources: + * + * http://bitsavers.org/components/intel/_dataBooks/1996_Intel_Peripheral_Components.pdf + * + * TODO + * - expose everything to an actual EISA bus + * - 32-bit dma functionality + * + */ + +#include "emu.h" +#include "i82357.h" + +#define LOG_GENERAL (1U << 0) + +//#define VERBOSE (LOG_GENERAL) + +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(I82357, i82357_device, "i82357", "Intel 82357 Integrated System Peripheral") + +i82357_device::i82357_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, I82357, tag, owner, clock) + , m_pic(*this, "pic%u", 0) + , m_pit(*this, "pit%u", 0) + , m_dma(*this, "dma%u", 0) + , m_out_rtc(*this) + , m_out_nmi(*this) + , m_out_spkr(*this) +{ +} + +void i82357_device::device_add_mconfig(machine_config &config) +{ + PIC8259(config, m_pic[0], 0); + m_pic[0]->in_sp_callback().set_constant(1); + m_pic[0]->read_slave_ack_callback().set( + [this](offs_t offset) + { + if (offset == 2) + return m_pic[1]->acknowledge(); + + return u32(0); + }); + + PIC8259(config, m_pic[1], 0); + m_pic[1]->out_int_callback().set(m_pic[0], FUNC(pic8259_device::ir2_w)); + m_pic[1]->in_sp_callback().set_constant(0); + + PIT8254(config, m_pit[0], 0); + PIT8254(config, m_pit[1], 0); + + // timer 1 counter 0: system timer + m_pit[0]->set_clk<0>(clock() / 12); + m_pit[0]->out_handler<0>().set(m_pic[0], FUNC(pic8259_device::ir0_w)); + + // timer 1 counter 1: refresh request + m_pit[0]->set_clk<1>(clock() / 12); + m_pit[0]->out_handler<1>().set( + [this](int state) + { + // FIXME: not accurate, but good enough to pass diagnostic + if (state) + m_nmi_reg ^= NMI_REFRESH; + + m_pit[1]->write_gate2(state); + }); + + // timer 1 counter 2: speaker + m_pit[0]->set_clk<2>(clock() / 12); + m_pit[0]->out_handler<2>().set( + [this](int state) + { + if (state) + m_nmi_reg |= NMI_T1C2_STATE; + else + m_nmi_reg &= ~NMI_T1C2_STATE; + + m_out_spkr((m_nmi_reg & NMI_T1C2_STATE) && (m_nmi_reg & NMI_SPEAKER_DATA)); + }); + + // timer 2 counter 0: fail-safe timer + m_pit[1]->set_clk<0>(clock() / 48); + m_pit[1]->out_handler<0>().set( + [this](int state) + { + if (state && (m_nmi_ext & NMI_EXT_EN_FAILSAFE)) + { + m_nmi_ext |= NMI_EXT_FAILSAFE; + + m_nmi_check->adjust(attotime::zero); + } + }); + + // timer 2 counter 1: does not exist + + // timer 2 counter 2: cpu speed control + m_pit[1]->set_clk<2>(8_MHz_XTAL); + //m_pit[1]->out_handler<2>().set(); + + EISA_DMA(config, m_dma[0], clock() / 3); + EISA_DMA(config, m_dma[1], clock() / 3); + m_dma[1]->out_dack_callback<0>().set(m_dma[0], FUNC(eisa_dma_device::hack_w)).invert(); +} + +void i82357_device::map(address_map &map) +{ + map(0x000, 0x00f).rw(m_dma[0], FUNC(eisa_dma_device::read), FUNC(eisa_dma_device::write)); + map(0x020, 0x021).rw(m_pic[0], FUNC(pic8259_device::read), FUNC(pic8259_device::write)); + map(0x040, 0x043).rw(m_pit[0], FUNC(pit8254_device::read), FUNC(pit8254_device::write)); + map(0x048, 0x04b).rw(m_pit[1], FUNC(pit8254_device::read), FUNC(pit8254_device::write)); + + // FIXME: also 0x065 - "NMI Status" + map(0x061, 0x061).rw(FUNC(i82357_device::nmi_reg_r), FUNC(i82357_device::nmi_reg_w)); + + // NMI Enable Register (0x70, 72, 74, 76) + map(0x070, 0x077).lw8("nmi_rtc", + [this](address_space &space, offs_t offset, u8 data) + { + m_nmi_enabled = !BIT(data, 7); + + m_out_rtc(space, 0, data & 0x7f); + + m_nmi_check->adjust(attotime::zero); + }).umask64(0xff); + + map(0x081, 0x081).rw(m_dma[0], FUNC(eisa_dma_device::get_address_page<2>), FUNC(eisa_dma_device::set_address_page<2>)); + map(0x082, 0x082).rw(m_dma[0], FUNC(eisa_dma_device::get_address_page<3>), FUNC(eisa_dma_device::set_address_page<3>)); + map(0x083, 0x083).rw(m_dma[0], FUNC(eisa_dma_device::get_address_page<1>), FUNC(eisa_dma_device::set_address_page<1>)); + map(0x087, 0x087).rw(m_dma[0], FUNC(eisa_dma_device::get_address_page<0>), FUNC(eisa_dma_device::set_address_page<0>)); + map(0x089, 0x089).rw(m_dma[1], FUNC(eisa_dma_device::get_address_page<2>), FUNC(eisa_dma_device::set_address_page<2>)); + map(0x08a, 0x08a).rw(m_dma[1], FUNC(eisa_dma_device::get_address_page<3>), FUNC(eisa_dma_device::set_address_page<3>)); + map(0x08b, 0x08b).rw(m_dma[1], FUNC(eisa_dma_device::get_address_page<1>), FUNC(eisa_dma_device::set_address_page<1>)); + map(0x08f, 0x08f).rw(m_dma[1], FUNC(eisa_dma_device::get_address_page<0>), FUNC(eisa_dma_device::set_address_page<0>)); + + // TODO: also 0xa4, a8, ac, b0, b4, b8, bc + map(0x0a0, 0x0a1).rw(m_pic[1], FUNC(pic8259_device::read), FUNC(pic8259_device::write)); + map(0x0c0, 0x0df).rw(m_dma[1], FUNC(eisa_dma_device::read), FUNC(eisa_dma_device::write)).umask16(0x00ff); + + map(0x401, 0x401).rw(m_dma[0], FUNC(eisa_dma_device::get_count_high<0>), FUNC(eisa_dma_device::set_count_high<0>)); + map(0x403, 0x403).rw(m_dma[0], FUNC(eisa_dma_device::get_count_high<1>), FUNC(eisa_dma_device::set_count_high<1>)); + map(0x405, 0x405).rw(m_dma[0], FUNC(eisa_dma_device::get_count_high<2>), FUNC(eisa_dma_device::set_count_high<2>)); + map(0x407, 0x407).rw(m_dma[0], FUNC(eisa_dma_device::get_count_high<3>), FUNC(eisa_dma_device::set_count_high<3>)); + + //map(0x40a, 0x40a); // DMA1 Set Chaining Mode (w)/Interrupt Status (r) + //map(0x40b, 0x40b); // DMA1 Ext Write Mode (w) + //map(0x40c, 0x40c); // Chain Buffer Control + //map(0x40d, 0x40d); // Stepping Level Register (ro) + //map(0x40e, 0x40e); // ISP Test Register + //map(0x40f, 0x40f); // ISP Test Register + + map(0x461, 0x461).rw(FUNC(i82357_device::nmi_ext_r), FUNC(i82357_device::nmi_ext_w)); + map(0x462, 0x462).lw8("nmi_ioport", + [this](u8 data) + { + if (m_nmi_ext & NMI_EXT_EN_IOPORT) + { + m_nmi_ext |= NMI_EXT_IOPORT; + + m_nmi_check->adjust(attotime::zero); + } + }); + //map(0x464, 0x464); // Last 32-bit bus master granted (L) + + map(0x481, 0x481).rw(m_dma[0], FUNC(eisa_dma_device::get_address_page_high<2>), FUNC(eisa_dma_device::set_address_page_high<2>)); + map(0x482, 0x482).rw(m_dma[0], FUNC(eisa_dma_device::get_address_page_high<3>), FUNC(eisa_dma_device::set_address_page_high<3>)); + map(0x483, 0x483).rw(m_dma[0], FUNC(eisa_dma_device::get_address_page_high<1>), FUNC(eisa_dma_device::set_address_page_high<1>)); + map(0x487, 0x487).rw(m_dma[0], FUNC(eisa_dma_device::get_address_page_high<0>), FUNC(eisa_dma_device::set_address_page_high<0>)); + map(0x489, 0x489).rw(m_dma[1], FUNC(eisa_dma_device::get_address_page_high<2>), FUNC(eisa_dma_device::set_address_page_high<2>)); + map(0x48a, 0x48a).rw(m_dma[1], FUNC(eisa_dma_device::get_address_page_high<3>), FUNC(eisa_dma_device::set_address_page_high<3>)); + map(0x48b, 0x48b).rw(m_dma[1], FUNC(eisa_dma_device::get_address_page_high<1>), FUNC(eisa_dma_device::set_address_page_high<1>)); + map(0x48f, 0x48f).rw(m_dma[1], FUNC(eisa_dma_device::get_address_page_high<0>), FUNC(eisa_dma_device::set_address_page_high<0>)); + + map(0x4c2, 0x4c2).rw(m_dma[1], FUNC(eisa_dma_device::get_count_high<0>), FUNC(eisa_dma_device::set_count_high<0>)); + map(0x4c6, 0x4c6).rw(m_dma[1], FUNC(eisa_dma_device::get_count_high<1>), FUNC(eisa_dma_device::set_count_high<1>)); + map(0x4ca, 0x4ca).rw(m_dma[1], FUNC(eisa_dma_device::get_count_high<2>), FUNC(eisa_dma_device::set_count_high<2>)); + map(0x4ce, 0x4ce).rw(m_dma[1], FUNC(eisa_dma_device::get_count_high<3>), FUNC(eisa_dma_device::set_count_high<3>)); + map(0x4d0, 0x4d1).lrw8("elcr", + [this](offs_t offset) { return m_elcr[offset]; }, + [this](offs_t offset, u8 data) { m_elcr[offset] = data; }); + + //map(0x4d4, 0x4d4); // DMA2 Set Chaining Mode + //map(0x4d6, 0x4d6); // DMA2 Ext Write Mode Register + + map(0x4e0, 0x4e3).rw(m_dma[0], FUNC(eisa_dma_device::get_stop<0>), FUNC(eisa_dma_device::set_stop<0>)); + map(0x4e4, 0x4e7).rw(m_dma[0], FUNC(eisa_dma_device::get_stop<1>), FUNC(eisa_dma_device::set_stop<1>)); + map(0x4e8, 0x4eb).rw(m_dma[0], FUNC(eisa_dma_device::get_stop<2>), FUNC(eisa_dma_device::set_stop<2>)); + map(0x4ec, 0x4ef).rw(m_dma[0], FUNC(eisa_dma_device::get_stop<3>), FUNC(eisa_dma_device::set_stop<3>)); + + map(0x4f0, 0x4f3).rw(m_dma[1], FUNC(eisa_dma_device::get_stop<0>), FUNC(eisa_dma_device::set_stop<0>)); // reserved + map(0x4f4, 0x4f7).rw(m_dma[1], FUNC(eisa_dma_device::get_stop<1>), FUNC(eisa_dma_device::set_stop<1>)); + map(0x4f8, 0x4fb).rw(m_dma[1], FUNC(eisa_dma_device::get_stop<2>), FUNC(eisa_dma_device::set_stop<2>)); + map(0x4fc, 0x4ff).rw(m_dma[1], FUNC(eisa_dma_device::get_stop<3>), FUNC(eisa_dma_device::set_stop<3>)); +} + +void i82357_device::device_start() +{ + m_out_rtc.resolve_safe(); + m_out_nmi.resolve_safe(); + m_out_spkr.resolve_safe(); + + m_nmi_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(i82357_device::nmi_check), this)); +} + +void i82357_device::device_reset() +{ + m_elcr[0] = 0; + m_elcr[1] = 0; + + m_nmi_enabled = true; + m_nmi_reg = 0; + m_nmi_ext = 0; + + m_nmi_check->adjust(attotime::zero); +} + +void i82357_device::nmi_reg_w(u8 data) +{ + m_pit[0]->write_gate2(!!(data & NMI_T1C2_GATE)); + + // clear parity nmi + if (data & NMI_PARITY_DISABLE) + m_nmi_reg &= ~NMI_PARITY; + + // clear iochk nmi + if (data & NMI_IOCHK_DISABLE) + m_nmi_reg &= ~NMI_IOCHK; + + m_nmi_reg = (m_nmi_reg & ~NMI_WMASK) | (data & NMI_WMASK); + + // update speaker state + m_out_spkr((m_nmi_reg & NMI_T1C2_STATE) && (m_nmi_reg & NMI_SPEAKER_DATA)); + + m_nmi_check->adjust(attotime::zero); +} + +void i82357_device::nmi_ext_w(u8 data) +{ + if (!(data & NMI_EXT_EN_IOPORT)) + m_nmi_ext &= ~NMI_EXT_IOPORT; + + if (!(data & NMI_EXT_EN_TIMEOUT)) + m_nmi_ext &= ~NMI_EXT_TIMEOUT; + + if (!(data & NMI_EXT_EN_FAILSAFE)) + m_nmi_ext &= ~NMI_EXT_FAILSAFE; + + m_nmi_ext = (m_nmi_ext & ~NMI_EXT_WMASK) | (data & NMI_EXT_WMASK); + + m_nmi_check->adjust(attotime::zero); +} + +WRITE_LINE_MEMBER(i82357_device::in_iochk) +{ + if (!state && !(m_nmi_reg & NMI_PARITY_DISABLE)) + { + m_nmi_reg |= NMI_IOCHK; + + m_nmi_check->adjust(attotime::zero); + } + else + m_nmi_reg &= ~NMI_IOCHK; +} + +WRITE_LINE_MEMBER(i82357_device::in_parity) +{ + if (!state && !(m_nmi_reg & NMI_IOCHK_DISABLE)) + { + m_nmi_reg |= NMI_PARITY; + + m_nmi_check->adjust(attotime::zero); + } + else + m_nmi_reg &= ~NMI_PARITY; +} + +TIMER_CALLBACK_MEMBER(i82357_device::nmi_check) +{ + if (m_nmi_enabled) + { + if ((m_nmi_reg & NMI_NMI) || (m_nmi_ext & NMI_EXT_NMI)) + { + if (!m_out_nmi_asserted) + { + m_out_nmi_asserted = true; + m_out_nmi(1); + } + + return; + } + } + + // disabled or no source + if (m_out_nmi_asserted) + { + m_out_nmi_asserted = false; + m_out_nmi(0); + } +} diff --git a/src/devices/machine/i82357.h b/src/devices/machine/i82357.h new file mode 100644 index 00000000000..3c5a7756061 --- /dev/null +++ b/src/devices/machine/i82357.h @@ -0,0 +1,91 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_MACHINE_I82357_H +#define MAME_MACHINE_I82357_H + +#pragma once + +#include "machine/pic8259.h" +#include "machine/pit8253.h" +#include "machine/am9517a.h" + +class i82357_device : public device_t +{ +public: + i82357_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + auto out_rtc_cb() { return m_out_rtc.bind(); } + auto out_int_cb() { return subdevice<pic8259_device>("pic0")->out_int_callback(); } + auto out_nmi_cb() { return m_out_nmi.bind(); } + auto out_spkr_cb() { return m_out_spkr.bind(); } + + u32 eisa_irq_ack() { return m_pic[0]->acknowledge(); } + + DECLARE_WRITE_LINE_MEMBER(in_iochk); + DECLARE_WRITE_LINE_MEMBER(in_parity); + + void map(address_map &map); + +protected: + // standard device_t overrides + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + + void nmi_reg_w(u8 data); + void nmi_ext_w(u8 data); + u8 nmi_reg_r() { return m_nmi_reg; } + u8 nmi_ext_r() { return m_nmi_ext; } + + TIMER_CALLBACK_MEMBER(nmi_check); + +private: + required_device_array<pic8259_device, 2> m_pic; + required_device_array<pit8254_device, 2> m_pit; + required_device_array<eisa_dma_device, 2> m_dma; + + devcb_write8 m_out_rtc; + devcb_write_line m_out_nmi; + devcb_write_line m_out_spkr; + + enum nmi_reg_mask : u8 + { + NMI_T1C2_GATE = 0x01, + NMI_SPEAKER_DATA = 0x02, + NMI_PARITY_DISABLE = 0x04, + NMI_IOCHK_DISABLE = 0x08, + NMI_REFRESH = 0x10, + NMI_T1C2_STATE = 0x20, + NMI_IOCHK = 0x40, + NMI_PARITY = 0x80, + + NMI_WMASK = 0x0f, + NMI_NMI = 0xc0, + }; + enum nmi_ext_mask : u8 + { + NMI_EXT_BUS_RESET = 0x01, // bus reset (read/write) + NMI_EXT_EN_IOPORT = 0x02, + NMI_EXT_EN_FAILSAFE = 0x04, + NMI_EXT_EN_TIMEOUT = 0x08, + NMI_EXT_8US_TIMEOUT = 0x10, // 8us EISA bus master timeout occurred + NMI_EXT_IOPORT = 0x20, // NMI I/O port interrupt pending + NMI_EXT_TIMEOUT = 0x40, // EISA bus master timeout occurred, NMI requested + NMI_EXT_FAILSAFE = 0x80, // Fail-safe timer is active, NMI requested + + NMI_EXT_WMASK = 0x0f, + NMI_EXT_NMI = 0xe0, + }; + u8 m_elcr[2]; + + emu_timer *m_nmi_check; + bool m_out_nmi_asserted; + bool m_nmi_enabled; + u8 m_nmi_reg; + u8 m_nmi_ext; +}; + +DECLARE_DEVICE_TYPE(I82357, i82357_device) + +#endif // MAME_MACHINE_I82357_H diff --git a/src/mame/drivers/jazz.cpp b/src/mame/drivers/jazz.cpp index 4a8d5a52d84..a0b78f504b7 100644 --- a/src/mame/drivers/jazz.cpp +++ b/src/mame/drivers/jazz.cpp @@ -13,7 +13,10 @@ * http://www.sensi.org/~alec/mips/mips-history.html * * TODO - * - everything (skeleton only) + * - make it boot Windows NT + * - big-endian support for RISC/os + * - EISA bus and slots + * - slotify and improve graphics board * * Unconfirmed parts lists from ARCSystem reference design (which appears to * be very similar or identical to the Jazz system) taken from: @@ -69,35 +72,110 @@ void jazz_state::machine_reset() void jazz_state::init_common() { - // map the configured ram - m_maincpu->space(AS_PROGRAM).install_ram(0, m_ram->mask(), m_ram->pointer()); + // map the configured ram and vram + m_cpu->space(0).install_ram(0x00000000, 0x00000000 | m_ram->mask(), m_ram->pointer()); + m_cpu->space(0).install_ram(0x40000000, 0x40000000 | m_vram->mask(), m_vram->pointer()); } void jazz_state::jazz_common_map(address_map &map) { map(0x1fc00000, 0x1fc3ffff).r(m_flash, FUNC(amd_28f020_device::read)); - // FIXME: lots of guesswork and assumptions here for now + map(0x40000000, 0x407fffff).ram().share("vram"); // local video memory + map(0x60000000, 0x6000013f).lr8("video_rom", + [](offs_t offset) + { + /* + * Board_Identifier, PROM_Stride, PROM_Width, PROM_Size + * 0=JazzVideoG300, 1=JazzVideoG364, 2=JazzVideoVxl, 0x10=MipsVideoG364, 0x11=MaximumJazzVideo (jazzvideog364 osc period == 123077, MipsVideoG364 = 200000) + * Test_Byte_0 - Test_Byte_3 + * VideoMemorySize, VideoControlSize + * CodeOffset, CodeSize + * ID string + */ + /* + static u8 const jazz_g364[] = + { + 0x01, 0x08, 0x01, 0x20, 'J', 'a', 'z', 'z', + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 'J', 'a', 'z', 'z', ' ', 'G', '3', '6', + '4', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + static u8 const mips_g364[] = + { + 0x10, 0x08, 0x01, 0x20, 'J', 'a', 'z', 'z', + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 'M', 'i', 'p', 's', ' ', 'G', '3', '6', + '4', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + */ + + static u8 const bogus_g364[] = + { + 0x10, 0x00, 0x00, 0x00, 'J', 'a', 'z', 'z', + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 'M', 'i', 'p', 's', ' ', 'G', '3', '6', + '4', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + return bogus_g364[offset]; + }).umask64(0xff); + + map(0x60080000, 0x60081fff).m(m_ramdac, FUNC(g364_device::map)); // local video control + map(0x60180000, 0x60180007).lw32("g364_reset", [this](u32 data) { m_ramdac->reset(); }); + map(0x80000000, 0x80000fff).m(m_mct_adr, FUNC(jazz_mct_adr_device::map)); - map(0x80001000, 0x80001fff).m(m_network, FUNC(dp83932c_device::map)); - //map(0x80002000, 0x80002fff).m(m_scsi, FUNC(ncr5390_device::map)).umask32(0x000000ff); - map(0x80003000, 0x80003fff).m(m_fdc, FUNC(n82077aa_device::map)); - //map(0x80004000, 0x80004fff).rw(m_rtc, FUNC(mc146818_device::read), FUNC(mc146818_device::write)); - //map(0x80005000, 0x80005fff).m() // keyboard/mouse - //map(0x80006000, 0x80006fff).m() // serial1 - //map(0x80007000, 0x80007fff).m() // serial2 - //map(0x80008000, 0x80008fff).m() // parallel - map(0x80009000, 0x80009fff).ram().share("nvram"); // unprotected? - map(0x8000a000, 0x8000afff).ram().share("nvram"); // protected? - map(0x8000b000, 0x8000bfff).ram().share("nvram"); // read-only? also sonic IO access? + + map(0x80001000, 0x800010ff).m(m_network, FUNC(dp83932c_device::map)).umask32(0x0000ffff); + map(0x80002000, 0x8000200f).m(m_scsi, FUNC(ncr53c94_device::map)); + map(0x80003000, 0x8000300f).m(m_fdc, FUNC(n82077aa_device::map)); + map(0x80004000, 0x80004007).lrw8("rtc", + [this](address_space &space, offs_t offset) { return m_rtc->read(space, 1); }, + [this](address_space &space, offs_t offset, u8 data) { m_rtc->write(space, 1, data); }).umask64(0xff); + map(0x80005000, 0x80005007).rw(m_kbdc, FUNC(at_keyboard_controller_device::data_r), FUNC(at_keyboard_controller_device::data_w)).umask64(0x00ff); + map(0x80005000, 0x80005007).rw(m_kbdc, FUNC(at_keyboard_controller_device::status_r), FUNC(at_keyboard_controller_device::command_w)).umask64(0xff00); + map(0x80006000, 0x80006007).rw(m_ace[0], FUNC(ns16550_device::ins8250_r), FUNC(ns16550_device::ins8250_w)); + map(0x80007000, 0x80007007).rw(m_ace[1], FUNC(ns16550_device::ins8250_r), FUNC(ns16550_device::ins8250_w)); + map(0x80008000, 0x80008007).rw(m_lpt, FUNC(pc_lpt_device::read), FUNC(pc_lpt_device::write)).umask64(0xffffffff); + map(0x80009000, 0x8000afff).ram().share("nvram"); // 9000-9fff unprotected/a000-afff protected? + map(0x8000b000, 0x8000b007).lr8("mac", [this](offs_t offset) + { + // mac address and checksum + static u8 const mac[] = { 0x00, 0x00, 0x6b, 0x12, 0x34, 0x56, 0x00, 0xf7 }; + + return mac[offset]; + }); + // 3 4k pages of nvram: read/write, protected, read-only + // last page holds ethernet mac and checksum in bytes 0-7 + //map(0x8000c000, 0x8000cfff) // sound - map(0x8000d000, 0x8000dfff).noprw(); // dummy dma device? + //map(0x8000d000, 0x8000dfff).noprw(); // dummy dma device? + map(0x8000d600, 0x8000d607).nopw(); + + map(0x8000f000, 0x8000f007).lrw8( + "led", + [this]() { return m_led; }, + [this](u8 data) + { + logerror("led 0x%02x (%s)\n", data, machine().describe_context()); + m_led = data; + }).umask64(0xff); - map(0x8000f000, 0x8000f001).rw(FUNC(jazz_state::led_r), FUNC(jazz_state::led_w)); + // lots of byte data written to 800 + //map(0x800e0000, 0x800fffff).m() // dram config - //map(0x800e0000, 0x800e0000).rw(FUNC(jazz_state::dram_config_r), FUNC(jazz_state::dram_config_w)); + map(0x90000000, 0x90ffffff).m(m_isp, FUNC(i82357_device::map)); - map(0xe0800000, 0xe0bfffff).ram().share("vram"); // framebuffer? + //map(0x91000000, 0x91ffffff).m(); + //map(0x92000000, 0x92ffffff).m(); // EISA I/O ports? + //map(0x93000000, 0x93ffffff).m(); // EISA memory + + map(0xf0000000, 0xf0000007).r(m_mct_adr, FUNC(jazz_mct_adr_device::isr_r)).umask64(0xffff); + map(0xf0000000, 0xf0000007).rw(m_mct_adr, FUNC(jazz_mct_adr_device::imr_r), FUNC(jazz_mct_adr_device::imr_w)).umask64(0xffff0000); map(0xfff00000, 0xfff3ffff).r(m_flash, FUNC(amd_28f020_device::read)); // mirror? } @@ -108,46 +186,62 @@ static void jazz_scsi_devices(device_slot_interface &device) device.option_add("cdrom", NSCSI_CDROM); } +FLOPPY_FORMATS_MEMBER(jazz_state::floppy_formats) + FLOPPY_PC_FORMAT +FLOPPY_FORMATS_END + void jazz_state::jazz(machine_config &config) { - m_maincpu->set_addrmap(AS_PROGRAM, &jazz_state::jazz_common_map); + R4000(config, m_cpu, 50_MHz_XTAL); + m_cpu->set_addrmap(0, &jazz_state::jazz_common_map); - RAM(config, m_ram, 0); - m_ram->set_default_size("8M"); - m_ram->set_extra_options("16M,32M,64M,128M,256M"); + RAM(config, m_ram); + m_ram->set_default_size("16M"); + m_ram->set_extra_options("32M,64M,128M,256M"); m_ram->set_default_value(0); RAM(config, m_vram); m_vram->set_default_size("2M"); m_vram->set_default_value(0); - // FIXME: may require big and little endian variants + // local bus dma, timer and interrupt controller JAZZ_MCT_ADR(config, m_mct_adr, 0); + m_mct_adr->set_bus(m_cpu, 0); + m_mct_adr->out_int_dma_cb().set_inputline(m_cpu, INPUT_LINE_IRQ0); + m_mct_adr->out_int_device_cb().set_inputline(m_cpu, INPUT_LINE_IRQ1); + m_mct_adr->out_int_timer_cb().set_inputline(m_cpu, INPUT_LINE_IRQ4); + m_mct_adr->eisa_iack_cb().set(m_isp, FUNC(i82357_device::eisa_irq_ack)); // scsi bus and devices - NSCSI_BUS(config, m_scsibus, 0); - - nscsi_connector &harddisk(NSCSI_CONNECTOR(config, "scsi:0", 0)); - jazz_scsi_devices(harddisk); - harddisk.set_default_option("harddisk"); + NSCSI_BUS(config, m_scsibus); + NSCSI_CONNECTOR(config, "scsi:0", jazz_scsi_devices, "harddisk"); + NSCSI_CONNECTOR(config, "scsi:1", jazz_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:2", jazz_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:3", jazz_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:4", jazz_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:5", jazz_scsi_devices, nullptr); + NSCSI_CONNECTOR(config, "scsi:6", jazz_scsi_devices, "cdrom"); - nscsi_connector &cdrom(NSCSI_CONNECTOR(config, "scsi:6", 0)); - jazz_scsi_devices(cdrom); - cdrom.set_default_option("cdrom"); + // scsi host adapter + NSCSI_CONNECTOR(config, "scsi:7").option_set("ncr53c94", NCR53C94).clock(24_MHz_XTAL).machine_config( + [this](device_t *device) + { + ncr53c94_device &adapter = downcast<ncr53c94_device &>(*device); - jazz_scsi_devices(NSCSI_CONNECTOR(config, "scsi:1", 0)); - jazz_scsi_devices(NSCSI_CONNECTOR(config, "scsi:2", 0)); - jazz_scsi_devices(NSCSI_CONNECTOR(config, "scsi:3", 0)); - jazz_scsi_devices(NSCSI_CONNECTOR(config, "scsi:4", 0)); - jazz_scsi_devices(NSCSI_CONNECTOR(config, "scsi:5", 0)); + adapter.irq_handler_cb().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<5>));; + adapter.drq_handler_cb().set(m_mct_adr, FUNC(jazz_mct_adr_device::drq<0>)); - // scsi host adapter - nscsi_connector &adapter(NSCSI_CONNECTOR(config, "scsi:7", 0)); - adapter.option_add_internal("host", NCR53C90A); - adapter.set_default_option("host"); - adapter.set_fixed(true); + subdevice<jazz_mct_adr_device>(":mct_adr")->dma_r_cb<0>().set(adapter, FUNC(ncr53c94_device::dma_r)); + subdevice<jazz_mct_adr_device>(":mct_adr")->dma_w_cb<0>().set(adapter, FUNC(ncr53c94_device::dma_w)); + }); + // floppy controller and drive N82077AA(config, m_fdc, 24_MHz_XTAL); + m_fdc->intrq_wr_callback().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<1>)); + m_fdc->drq_wr_callback().set(m_mct_adr, FUNC(jazz_mct_adr_device::drq<1>)); + FLOPPY_CONNECTOR(config, "fdc:0", "35hd", FLOPPY_35_HD, true, jazz_state::floppy_formats).enable_sound(false); + m_mct_adr->dma_r_cb<1>().set(m_fdc, FUNC(n82077aa_device::dma_r)); + m_mct_adr->dma_w_cb<1>().set(m_fdc, FUNC(n82077aa_device::dma_w)); MC146818(config, m_rtc, 32.768_kHz_XTAL); @@ -155,57 +249,112 @@ void jazz_state::jazz(machine_config &config) AMD_28F020(config, m_flash); - // pc keyboard controller? + // pc keyboard connector pc_kbdc_device &kbdc(PC_KBDC(config, "pc_kbdc", 0)); - kbdc.out_clock_cb().set(m_kbdc, FUNC(at_keyboard_controller_device::kbd_clk_w)); - kbdc.out_data_cb().set(m_kbdc, FUNC(at_keyboard_controller_device::kbd_data_w)); + kbdc.out_clock_cb().set(m_kbdc, FUNC(ps2_keyboard_controller_device::kbd_clk_w)); + kbdc.out_data_cb().set(m_kbdc, FUNC(ps2_keyboard_controller_device::kbd_data_w)); // keyboard port pc_kbdc_slot_device &kbd(PC_KBDC_SLOT(config, "kbd", 0)); pc_at_keyboards(kbd); - kbd.set_default_option(STR_KBD_IBM_PC_AT_84); + kbd.set_default_option(STR_KBD_MICROSOFT_NATURAL); kbd.set_pc_kbdc_slot(&kbdc); - // at keyboard controller - AT_KEYBOARD_CONTROLLER(config, m_kbdc, 12_MHz_XTAL); - m_kbdc->hot_res().set_inputline(m_maincpu, INPUT_LINE_RESET); + // keyboard controller + PS2_KEYBOARD_CONTROLLER(config, m_kbdc, 12_MHz_XTAL); + //m_kbdc->hot_res().set_inputline(m_cpu, INPUT_LINE_RESET); + m_kbdc->hot_res().set([this](int state) { if (!state) m_cpu->reset(); }); m_kbdc->kbd_clk().set(kbdc, FUNC(pc_kbdc_device::clock_write_from_mb)); m_kbdc->kbd_data().set(kbdc, FUNC(pc_kbdc_device::data_write_from_mb)); + m_kbdc->kbd_irq().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<6>));; + + //m_kbdc->mouse_clk().set(); + //m_kbdc->mouse_data().set(); + m_kbdc->mouse_irq().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<7>)); SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_raw(78643200, 1280, 0, 1280, 1024, 0, 1024); m_screen->set_screen_update("g364", FUNC(g364_device::screen_update)); + m_screen->screen_vblank().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<3>)); // maybe? G364(config, m_ramdac, 5_MHz_XTAL); // FIXME: guessed clock m_ramdac->set_screen(m_screen); m_ramdac->set_vram(m_vram); + // WD16C552 (two 16550 + pc_lpt) + NS16550(config, m_ace[0], 4233600); + rs232_port_device &serial0(RS232_PORT(config, "serial0", default_rs232_devices, nullptr)); + + m_ace[0]->out_dtr_callback().set(serial0, FUNC(rs232_port_device::write_dtr)); + m_ace[0]->out_rts_callback().set(serial0, FUNC(rs232_port_device::write_rts)); + m_ace[0]->out_tx_callback().set(serial0, FUNC(rs232_port_device::write_txd)); + m_ace[0]->out_int_callback().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<8>)); + + serial0.cts_handler().set(m_ace[0], FUNC(ns16550_device::cts_w)); + serial0.dcd_handler().set(m_ace[0], FUNC(ns16550_device::dcd_w)); + serial0.dsr_handler().set(m_ace[0], FUNC(ns16550_device::dsr_w)); + serial0.ri_handler().set(m_ace[0], FUNC(ns16550_device::ri_w)); + serial0.rxd_handler().set(m_ace[0], FUNC(ns16550_device::rx_w)); + + NS16550(config, m_ace[1], 8_MHz_XTAL); + rs232_port_device &serial1(RS232_PORT(config, "serial1", default_rs232_devices, nullptr)); + + m_ace[1]->out_dtr_callback().set(serial1, FUNC(rs232_port_device::write_dtr)); + m_ace[1]->out_rts_callback().set(serial1, FUNC(rs232_port_device::write_rts)); + m_ace[1]->out_tx_callback().set(serial1, FUNC(rs232_port_device::write_txd)); + m_ace[1]->out_int_callback().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<9>)); + + serial1.cts_handler().set(m_ace[1], FUNC(ns16550_device::cts_w)); + serial1.dcd_handler().set(m_ace[1], FUNC(ns16550_device::dcd_w)); + serial1.dsr_handler().set(m_ace[1], FUNC(ns16550_device::dsr_w)); + serial1.ri_handler().set(m_ace[1], FUNC(ns16550_device::ri_w)); + serial1.rxd_handler().set(m_ace[1], FUNC(ns16550_device::rx_w)); + + PC_LPT(config, m_lpt, 0); + m_lpt->irq_handler().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<0>)); + + // TODO: sound, interrupt 2, drq 2(l) & 3(r) + + // buzzer + SPEAKER(config, "mono").front_center(); + SPEAKER_SOUND(config, m_buzzer); + m_buzzer->add_route(ALL_OUTPUTS, "mono", 0.50); + DP83932C(config, m_network, 20_MHz_XTAL); + m_network->out_int_cb().set(m_mct_adr, FUNC(jazz_mct_adr_device::irq<4>)); m_network->set_ram(RAM_TAG); + + I82357(config, m_isp, 14.318181_MHz_XTAL); + m_isp->out_rtc_cb().set(m_rtc, FUNC(mc146818_device::write)); + m_isp->out_int_cb().set_inputline(m_cpu, INPUT_LINE_IRQ2); + m_isp->out_nmi_cb().set_inputline(m_cpu, INPUT_LINE_IRQ3); + m_isp->out_spkr_cb().set(m_buzzer, FUNC(speaker_sound_device::level_w)); + + // TODO: 4 EISA slots } void jazz_state::mmr4000be(machine_config &config) { - R4000BE(config, m_maincpu, 50_MHz_XTAL); - jazz(config); + + m_cpu->set_config(r4000_device::CONFIG_BE, r4000_device::CONFIG_BE); } void jazz_state::mmr4000le(machine_config &config) { - R4000LE(config, m_maincpu, 50_MHz_XTAL); - jazz(config); + + m_cpu->set_config(0, r4000_device::CONFIG_BE); } ROM_START(mmr4000be) - ROM_REGION32_BE(0x40000, "flash", 0) + ROM_REGION64_BE(0x40000, "flash", 0) ROM_SYSTEM_BIOS(0, "riscos", "R4000 RISC/os PROM") ROMX_LOAD("riscos.bin", 0x00000, 0x40000, CRC(cea6bc8f) SHA1(3e47b4ad5d1a0c7aac649e6aef3df1bf86fc938b), ROM_BIOS(0)) ROM_END ROM_START(mmr4000le) - ROM_REGION32_LE(0x40000, "flash", 0) + ROM_REGION64_LE(0x40000, "flash", 0) ROM_SYSTEM_BIOS(0, "ntprom", "R4000 Windows NT PROM") ROMX_LOAD("ntprom.bin", 0x00000, 0x40000, CRC(d91018d7) SHA1(316de17820192c89b8ee6d9936ab8364a739ca53), ROM_BIOS(0)) ROM_END diff --git a/src/mame/includes/jazz.h b/src/mame/includes/jazz.h index 3bf5e801908..a3274d07526 100644 --- a/src/mame/includes/jazz.h +++ b/src/mame/includes/jazz.h @@ -6,7 +6,7 @@ #pragma once -#include "cpu/mips/mips3.h" +#include "cpu/mips/r4000.h" // memory #include "machine/ram.h" @@ -17,14 +17,21 @@ #include "machine/jazz_mct_adr.h" #include "machine/dp83932c.h" #include "machine/mc146818.h" +#include "machine/ins8250.h" #include "machine/ncr5390.h" #include "machine/upd765.h" #include "machine/at_keybc.h" +#include "machine/pc_lpt.h" +#include "machine/i82357.h" // video #include "screen.h" #include "video/ims_cvc.h" +// audio +#include "sound/spkrdev.h" +#include "speaker.h" + // busses and connectors #include "machine/nscsi_bus.h" #include "machine/nscsi_cd.h" @@ -33,17 +40,20 @@ #include "bus/pc_kbd/pc_kbdc.h" #include "bus/pc_kbd/keyboards.h" +#include "imagedev/floppy.h" +#include "formats/pc_dsk.h" + class jazz_state : public driver_device { public: jazz_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) - , m_maincpu(*this, "cpu") + , m_cpu(*this, "cpu") , m_ram(*this, "ram") , m_vram(*this, "vram") , m_mct_adr(*this, "mct_adr") , m_scsibus(*this, "scsi") - , m_scsi(*this, "scsi:7:host") + , m_scsi(*this, "scsi:7:ncr53c94") , m_fdc(*this, "fdc") , m_rtc(*this, "rtc") , m_nvram(*this, "nvram") @@ -52,6 +62,10 @@ public: , m_network(*this, "net") , m_screen(*this, "screen") , m_ramdac(*this, "g364") + , m_ace(*this, "ace%u", 0) + , m_lpt(*this, "lpt") + , m_isp(*this, "isp") + , m_buzzer(*this, "buzzer") { } @@ -65,32 +79,35 @@ protected: // machine config void jazz(machine_config &config); + public: void mmr4000be(machine_config &config); void mmr4000le(machine_config &config); void init_common(); + DECLARE_FLOPPY_FORMATS(floppy_formats); + protected: // devices - required_device<mips3_device> m_maincpu; + required_device<r4000_device> m_cpu; required_device<ram_device> m_ram; required_device<ram_device> m_vram; required_device<jazz_mct_adr_device> m_mct_adr; required_device<nscsi_bus_device> m_scsibus; - required_device<ncr5390_device> m_scsi; + required_device<ncr53c94_device> m_scsi; required_device<n82077aa_device> m_fdc; required_device<mc146818_device> m_rtc; required_device<nvram_device> m_nvram; required_device<amd_28f020_device> m_flash; - required_device<at_keyboard_controller_device> m_kbdc; + required_device<ps2_keyboard_controller_device> m_kbdc; required_device<dp83932c_device> m_network; required_device<screen_device> m_screen; required_device<g364_device> m_ramdac; - - // helpers - u8 led_r() { return m_led; } - void led_w(const u8 data) { logerror("led 0x%02x\n", data); m_led = data; } + required_device_array<ns16550_device, 2> m_ace; + required_device<pc_lpt_device> m_lpt; + required_device<i82357_device> m_isp; + required_device<speaker_sound_device> m_buzzer; private: // machine state diff --git a/src/mame/machine/jazz_mct_adr.cpp b/src/mame/machine/jazz_mct_adr.cpp index e14075f3f3f..1ae2c109d2b 100644 --- a/src/mame/machine/jazz_mct_adr.cpp +++ b/src/mame/machine/jazz_mct_adr.cpp @@ -20,7 +20,10 @@ * http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/arch/arc/jazz/ * * TODO - * - everything (skeleton only) + * - proper width dma + * - dma address translation errors + * - I/O cache + * - revision 2 device */ #include "emu.h" @@ -33,19 +36,271 @@ DEFINE_DEVICE_TYPE(JAZZ_MCT_ADR, jazz_mct_adr_device, "jazz_mct_adr", "Jazz MCT- jazz_mct_adr_device::jazz_mct_adr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, JAZZ_MCT_ADR, tag, owner, clock) + , m_bus(*this, finder_base::DUMMY_TAG, -1, 64) + , m_out_int_dma(*this) + , m_out_int_device(*this) + , m_out_int_timer(*this) + , m_eisa_iack(*this) + , m_dma_r{ *this, *this, *this, *this } + , m_dma_w{ *this, *this, *this, *this } { } void jazz_mct_adr_device::map(address_map &map) { - map(0x000, 0x003).lr32("config", [](){ return 0x00000000; }); - map(0x008, 0x00b).lr32("revision", [](){ return 0xf0000000; }); + map(0x000, 0x007).lrw32("configuration", [this](){ return m_config; }, [this](u32 data) { m_config = data; }); + map(0x008, 0x00f).lr32("revision_level", [](){ return 1; }); + map(0x010, 0x017).lr32("invalid_address", []() { return 0; }); + map(0x018, 0x01f).lrw32("translation_base", [this]() { return m_trans_tbl_base; }, [this](u32 data) { LOG("tbl base 0x%08x\n", data); m_trans_tbl_base = data; }); + map(0x020, 0x027).lrw32("translation_limit", [this]() { return m_trans_tbl_limit; }, [this](u32 data) { m_trans_tbl_limit = data; }); + map(0x028, 0x02f).lrw32("translation_invalidate", []() { return 0; }, [](u32 data) { }); + map(0x030, 0x037).lw32("cache_maintenance", [this](u32 data) { m_ioc_maint = data; }); + map(0x038, 0x03f).lr32("remote_failed_address", []() { return 0; }); + map(0x040, 0x047).lr32("memory_failed_address", []() { return 0; }); + map(0x048, 0x04f).lw32("io_cache_physical_tag", [this](u32 data) { m_ioc_physical_tag = data; }); + map(0x050, 0x057).lw32("io_cache_logical_tag", [this](u32 data) { m_ioc_logical_tag = data; }); + map(0x058, 0x05f).lrw32("io_cache_byte_mask", + // FIXME: hack to pass diagnostics + [this]() + { + u32 const data = m_ioc_byte_mask; + + if (data == 0xffffffff) + m_ioc_byte_mask = 0; + return data; + }, + [this](u32 data) { m_ioc_byte_mask |= data; }); + map(0x060, 0x067).lw32("io_cache_buffer_window_lo", [this](u32 data) + { + // FIXME: hack to pass diagnostics + if (m_ioc_logical_tag == 0x80000001 && m_ioc_byte_mask == 0x0f0f0f0f) + { + u32 const address = (m_ioc_physical_tag & ~0x1) + ((m_ioc_maint & 0x3) << 3); + + m_bus->write_dword(address, data); + } + }); + // io_cache_buffer_window_hi + map(0x070, 0x0ef).lrw32("remote_speed", + [this](offs_t offset) { return m_remote_speed[offset >> 1]; }, + [this](offs_t offset, u32 data) { m_remote_speed[offset >> 1] = data; }); + // parity_diagnostic_lo + // parity_diagnostic_hi + map(0x100, 0x1ff).lrw32("dma_reg", + [this](offs_t offset) { return m_dma_reg[offset >> 1]; }, + [this](offs_t offset, u32 data) + { + unsigned const reg = offset >> 1; + + LOG("dma_reg %d data 0x%08x (%s)\n", offset, data, machine().describe_context()); + + m_dma_reg[reg] = data; + + if ((reg == REG_ENABLE) && (data & DMA_ENABLE)) + LOG("dma started address 0x%08x count %d\n", translate_address(m_dma_reg[(0 << 2) + REG_ADDRESS]), m_dma_reg[(0 << 2) + REG_COUNT]); + }); + map(0x200, 0x207).lr32("interrupt_source", []() { return 0; }); + map(0x208, 0x20f).lr32("error_type", []() { return 0; }); + map(0x210, 0x217).lrw32("refresh_rate", [this]() { return m_memory_refresh_rate; }, [this](u32 data) { m_memory_refresh_rate = data; }); + // refresh_counter + map(0x220, 0x227).lrw32("system_security", [this]() { return m_nvram_protect; }, [this](u32 data) { LOG("nvram_protect 0x%08x (%s)\n", data, machine().describe_context()); m_nvram_protect = data; }); + map(0x228, 0x22f).lw32("interrupt_interval", [this](u32 data) + { + LOG("timer_w 0x%08x\n", data); + + attotime interval = attotime::from_ticks((data + 1) & 0x1ff, 1000); + + m_interval_timer->adjust(interval, 0, interval); + }); + map(0x230, 0x237).lr32("interval_timer", [this]() { if (m_out_int_timer_asserted) { m_out_int_timer_asserted = false; m_out_int_timer(0); } return 0; }); + map(0x238, 0x23b).lr32("interrupt_acknowledge", [this]() { return m_eisa_iack(); }); } void jazz_mct_adr_device::device_start() { + m_out_int_dma.resolve(); + m_out_int_device.resolve(); + m_out_int_timer.resolve(); + m_eisa_iack.resolve(); + + for (int i = 0; i < 4; i++) + { + m_dma_r[i].resolve_safe(0xff); + m_dma_w[i].resolve_safe(); + } + + m_config = 0x104; // REV1, REV2 is 0x410 + + m_ioc_maint = 0; + m_ioc_physical_tag = 0; + m_ioc_logical_tag = 0; + m_trans_tbl_base = 0; + m_trans_tbl_limit = 0; + m_ioc_byte_mask = 0; + + for (u32 &val : m_remote_speed) + val = 0x7; + + for (u32 &val : m_dma_reg) + val = 0; + + m_memory_refresh_rate = 0x18186; + m_nvram_protect = 0x7; + + m_irq_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(jazz_mct_adr_device::irq_check), this)); + m_dma_check = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(jazz_mct_adr_device::dma_check), this)); + m_interval_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(jazz_mct_adr_device::interval_timer), this)); + + m_out_int_timer_asserted = false; + m_out_int_device_asserted = false; } void jazz_mct_adr_device::device_reset() { + m_isr = 0; + m_imr = 0; // 0x10; + + m_interval_timer->adjust(attotime::from_usec(1), 0, attotime::from_usec(1)); +} + +void jazz_mct_adr_device::set_irq_line(int irq, int state) +{ + if ((irq != 3) && (m_isr & (1 << irq)) ^ (state << irq)) + LOG("set_irq_line %d state %d m_imr 0x%04x\n", irq, state, m_imr); + + if (state) + m_isr |= (1 << irq); + else + m_isr &= ~(1 << irq); + + m_irq_check->adjust(attotime::zero); +} + +TIMER_CALLBACK_MEMBER(jazz_mct_adr_device::irq_check) +{ + if (bool(m_isr & m_imr) != m_out_int_device_asserted) + { + m_out_int_device_asserted = bool(m_isr & m_imr); + + m_out_int_device(m_out_int_device_asserted ? 1 : 0); + } +} + +u16 jazz_mct_adr_device::isr_r() +{ + u16 const pending = m_isr & m_imr; + + // FIXME: really? + //m_out_int_device(CLEAR_LINE); + + for (u16 irq = 0; irq < 16; irq++) + if (BIT(pending, irq)) + return (irq + 1) << 2; + + return 0; +} + +void jazz_mct_adr_device::imr_w(u16 data) +{ + LOG("imr_w 0x%04x (%s)\n", data, machine().describe_context()); + + m_imr = data; + + m_irq_check->adjust(attotime::zero); +} + +TIMER_CALLBACK_MEMBER(jazz_mct_adr_device::interval_timer) +{ + //m_out_int_timer(CLEAR_LINE); + if (!m_out_int_timer_asserted) + { + m_out_int_timer_asserted = true; + m_out_int_timer(1); + } +} + +void jazz_mct_adr_device::set_drq_line(int channel, int state) +{ + m_drq_active[channel] = state == ASSERT_LINE; + + if (state) + m_dma_check->adjust(attotime::zero); +} + +TIMER_CALLBACK_MEMBER(jazz_mct_adr_device::dma_check) +{ + bool active = false; + + for (int channel = 0; channel < 4; channel++) + { + if (!m_drq_active[channel]) + continue; + + // reg 0x00: 0x00000011 - mode (ch0) (WIDTH16 | ATIME_80) + // reg 0x20: 0x0000000a - mode (ch1) (WIDTH8 | ATIME_120) + // reg 0x18: 0x00000f20 - address + // reg 0x10: 0x00000024 - count + // reg 0x08: 0x00000001 - enable (ENABLE | !WRITE) + + // check channel enabled + if (!(m_dma_reg[(channel << 2) + REG_ENABLE] & DMA_ENABLE)) + return; + + // check transfer count + if (!m_dma_reg[(channel << 2) + REG_COUNT]) + return; + + u32 const address = translate_address(m_dma_reg[(channel << 2) + REG_ADDRESS]); + + // perform dma transfer + if (m_dma_reg[(channel << 2) + REG_ENABLE] & DMA_DIRECTION) + { + u8 const data = m_bus->read_byte(address); + + //LOG("dma_w data 0x%02x address 0x%08x\n", data, m_dma_reg[(number << 2) + 3]); + + m_dma_w[channel](data); + } + else + { + u8 const data = m_dma_r[channel](); + + //LOG("dma_r data 0x%02x address 0x%08x\n", data, m_dma_reg[(number << 2) + 3]); + + m_bus->write_byte(address, data); + } + + // increment address, decrement count + m_dma_reg[(channel << 2) + REG_ADDRESS]++; + m_dma_reg[(channel << 2) + REG_COUNT]--; + + // set terminal count flag + if (!m_dma_reg[(channel << 2) + REG_COUNT]) + { + m_dma_reg[(channel << 2) + REG_ENABLE] |= DMA_TERMINAL_COUNT; + + // TODO: dma interrupts + if (m_dma_reg[(channel << 2) + REG_ENABLE] & DMA_INTERRUPT_ENABLE) + logerror("dma interrupt enable - interrupt expected\n"); + } + + if (m_drq_active[channel]) + active = true; + } + + if (active) + m_dma_check->adjust(attotime::zero); +} + +u32 jazz_mct_adr_device::translate_address(u32 logical_address) +{ + u32 page = logical_address >> 12; + if (page < (m_trans_tbl_limit) >> 3) + { + u32 entry_address = (m_trans_tbl_base & 0x7fffffff) + page * 8; + + return m_bus->read_dword(entry_address) | (logical_address & 0xfff); + } + else + return 0; // FIXME: address error } diff --git a/src/mame/machine/jazz_mct_adr.h b/src/mame/machine/jazz_mct_adr.h index dd2b651d25c..ff51813c7dc 100644 --- a/src/mame/machine/jazz_mct_adr.h +++ b/src/mame/machine/jazz_mct_adr.h @@ -11,12 +11,137 @@ class jazz_mct_adr_device : public device_t public: jazz_mct_adr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + // configuration + template <typename T> void set_bus(T &&tag, int spacenum) { m_bus.set_tag(std::forward<T>(tag), spacenum); } + + auto out_int_dma_cb() { return m_out_int_dma.bind(); } + auto out_int_device_cb() { return m_out_int_device.bind(); } + auto out_int_timer_cb() { return m_out_int_timer.bind(); } + auto eisa_iack_cb() { return m_eisa_iack.bind(); } + + template <unsigned DMA> auto dma_r_cb() { return m_dma_r[DMA].bind(); } + template <unsigned DMA> auto dma_w_cb() { return m_dma_w[DMA].bind(); } + + template <unsigned IRQ> DECLARE_WRITE_LINE_MEMBER(irq) { set_irq_line(IRQ, state); } + template <unsigned DRQ> DECLARE_WRITE_LINE_MEMBER(drq) { set_drq_line(DRQ, state); } + virtual void map(address_map &map); + u16 isr_r(); + u16 imr_r() { return m_imr; } + void imr_w(u16 data); + protected: // device_t overrides virtual void device_start() override; virtual void device_reset() override; + +private: + void set_irq_line(int number, int state); + void set_drq_line(int channel, int state); + + TIMER_CALLBACK_MEMBER(irq_check); + TIMER_CALLBACK_MEMBER(dma_check); + TIMER_CALLBACK_MEMBER(interval_timer); + + u32 translate_address(u32 logical_address); + + required_address_space m_bus; + + devcb_write_line m_out_int_dma; + devcb_write_line m_out_int_device; + devcb_write_line m_out_int_timer; + devcb_read32 m_eisa_iack; + + devcb_read8 m_dma_r[4]; + devcb_write8 m_dma_w[4]; + bool m_drq_active[4]; + + emu_timer *m_irq_check; + emu_timer *m_dma_check; + emu_timer *m_interval_timer; + + enum isr_mask : u16 + { + ISR_PRINTER = 0x0001, + ISR_FLOPPY = 0x0002, + ISR_SOUND = 0x0004, + ISR_VIDEO = 0x0008, + ISR_NETWORK = 0x0010, + ISR_SCSI = 0x0020, + ISR_KEYBOARD = 0x0040, + ISR_MOUSE = 0x0080, + ISR_SERIAL0 = 0x0100, + ISR_SERIAL1 = 0x0200, + }; + u16 m_isr; // local bus interrupt source + u16 m_imr; // local bus interrupt mask + + u32 m_config; + + enum dma_register : unsigned + { + REG_MODE = 0, + REG_ENABLE = 1, + REG_COUNT = 2, + REG_ADDRESS = 3, + }; + enum dma_mode_mask : u32 + { + DMA_ACCESS_TIME = 0x00000007, + DMA_TRANSFER_WIDTH = 0x00000018, + DMA_INTERRUPT_ENABLE = 0x00000020, + DMA_BURST_MODE = 0x00000040, + DMA_FAST_DMA_CYCLE = 0x00000080, + }; + enum dma_access_time : u32 + { + ACCESS_40NS = 0x00, + ACCESS_80NS = 0x01, + ACCESS_120NS = 0x02, + ACCESS_160NS = 0x03, + ACCESS_200NS = 0x04, + ACCESS_240NS = 0x05, + ACCESS_280NS = 0x06, + ACCESS_320NS = 0x07, + }; + enum dma_transfer_width : u32 + { + WIDTH_8BITS = 0x08, + WIDTH_16BITS = 0x10, + WIDTH_32BITS = 0x18, + }; + enum dma_enable_mask : u32 + { + DMA_ENABLE = 0x00000001, + DMA_DIRECTION = 0x00000002, // 1 == write to device + DMA_TERMINAL_COUNT = 0x00000100, + DMA_MEMORY_ERROR = 0x00000200, + DMA_TRANSLATION_ERROR = 0x00000400, + }; + enum dma_interrupt_source : u32 + { + DMA_INTERRUPT_PENDING = 0x000000ff, + DMA_PARITY_ERROR = 0x00000100, + DMA_ADDRESS_ERROR = 0000000200, + DMA_CACHE_FLUSH_ERROR = 0x00000400, + }; + + u32 m_trans_tbl_base; + u32 m_trans_tbl_limit; + u32 m_ioc_maint; + u32 m_ioc_physical_tag; + u32 m_ioc_logical_tag; + u32 m_ioc_byte_mask; + u32 m_remote_speed[16]; + u32 m_dma_reg[32]; + u32 m_memory_refresh_rate; + u32 m_nvram_protect; + + u32 m_dma_address[4]; + + bool m_out_int_timer_asserted; + bool m_out_int_device_asserted; }; // device type definition |