From 59baa6640b17b4baad328d5b9ec3401fac9ce122 Mon Sep 17 00:00:00 2001 From: arbee Date: Sat, 29 Apr 2023 21:21:49 -0400 Subject: [PATCH] machine/mpc106.cpp: properly endian-swap PPC/PCI transactions, support LE PPC, use logmacro. [R. Belmont] apple/bandit.cpp: properly endian-swap PPC/PCI transactions, use logmacro. [R. Belmont] apple/heathrow.cpp: interrupt controller filled out, audio CODEC interface defined, added audio DMA channels. [R. Belmont] apple/dbdma.cpp: New device, a single Descriptor Based DMA channel. [R. Belmont] apple/awacs_macrisc.cpp: New device, the AWACS and Screamer CODECs in their MacRISC compatible form. [R. Belmont] apple/burgundy.cpp: New device, MacRISC compatible CODEC used in the iMac G3 and "Blue & White" G3. apple/imacg3.cpp: Boot chime now plays. [R. Belmont] apple/powermacg3.cpp: Boot chime now plays. [R. Belmont] --- src/devices/machine/mpc106.cpp | 97 +++++++++-- src/devices/machine/mpc106.h | 6 +- src/mame/apple/awacs_macrisc.cpp | 210 ++++++++++++++++++++++++ src/mame/apple/awacs_macrisc.h | 76 +++++++++ src/mame/apple/bandit.cpp | 10 +- src/mame/apple/burgundy.cpp | 169 +++++++++++++++++++ src/mame/apple/burgundy.h | 62 +++++++ src/mame/apple/dbdma.cpp | 273 +++++++++++++++++++++++++++++++ src/mame/apple/dbdma.h | 69 ++++++++ src/mame/apple/heathrow.cpp | 255 +++++++++++++++++++++++------ src/mame/apple/heathrow.h | 98 ++++++----- src/mame/apple/imacg3.cpp | 19 +++ src/mame/apple/pippin.cpp | 56 +++++-- src/mame/apple/powermacg3.cpp | 19 +++ 14 files changed, 1285 insertions(+), 134 deletions(-) create mode 100644 src/mame/apple/awacs_macrisc.cpp create mode 100644 src/mame/apple/awacs_macrisc.h create mode 100644 src/mame/apple/burgundy.cpp create mode 100644 src/mame/apple/burgundy.h create mode 100644 src/mame/apple/dbdma.cpp create mode 100644 src/mame/apple/dbdma.h diff --git a/src/devices/machine/mpc106.cpp b/src/devices/machine/mpc106.cpp index c8e57c72912..15bdb9645ef 100755 --- a/src/devices/machine/mpc106.cpp +++ b/src/devices/machine/mpc106.cpp @@ -22,6 +22,8 @@ enum AS_PCI_IO = 2 }; +constexpr u32 PICR1_LE_MODE = 0x00000020; // Host CPU is little-endian if set, big-endian if clear + DEFINE_DEVICE_TYPE(MPC106, mpc106_host_device, "mpc106", "Motorola MPC106 PCI Bridge/Memory Controller") void mpc106_host_device::config_map(address_map &map) @@ -32,6 +34,7 @@ void mpc106_host_device::config_map(address_map &map) map(0x80, 0x8f).rw(FUNC(mpc106_host_device::memory_start_r), FUNC(mpc106_host_device::memory_start_w)); map(0x90, 0x9f).rw(FUNC(mpc106_host_device::memory_end_r), FUNC(mpc106_host_device::memory_end_w)); map(0xa0, 0xa0).rw(FUNC(mpc106_host_device::memory_enable_r), FUNC(mpc106_host_device::memory_enable_w)); + map(0xa8, 0xab).rw(FUNC(mpc106_host_device::picr1_r), FUNC(mpc106_host_device::picr1_w)); } mpc106_host_device::mpc106_host_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) @@ -42,6 +45,7 @@ mpc106_host_device::mpc106_host_device(const machine_config &mconfig, const char { set_ids_host(0x10570002, 0x40, 0x000006); m_memory_bank_enable = 0; + m_picr1 = 0; } void mpc106_host_device::set_ram_info(u8 *ram_ptr, int ram_size) @@ -108,7 +112,14 @@ void mpc106_host_device::device_start() m_cpu_space->install_read_handler (0xfe800000, 0xfebfffff, read32s_delegate(*this, FUNC(mpc106_host_device::pci_io_r<0x00800000>))); m_cpu_space->install_write_handler(0xfe800000, 0xfebfffff, write32s_delegate(*this, FUNC(mpc106_host_device::pci_io_w<0x00800000>))); - m_cpu_space->install_device(0xfec00000, 0xfeefffff, *static_cast(this), &mpc106_host_device::access_map); + if (m_picr1 & PICR1_LE_MODE) + { + m_cpu_space->install_device(0xfec00000, 0xfeefffff, *static_cast(this), &mpc106_host_device::access_map_le); + } + else + { + m_cpu_space->install_device(0xfec00000, 0xfeefffff, *static_cast(this), &mpc106_host_device::access_map_be); + } } save_item(NAME(m_pwrconfig1)); @@ -116,6 +127,7 @@ void mpc106_host_device::device_start() save_item(NAME(m_memory_starts)); save_item(NAME(m_memory_ends)); save_item(NAME(m_memory_bank_enable)); + save_item(NAME(m_picr1)); } device_memory_interface::space_config_vector mpc106_host_device::memory_space_config() const @@ -136,7 +148,13 @@ void mpc106_host_device::device_reset() pci_host_device::device_reset(); } -void mpc106_host_device::access_map(address_map &map) +void mpc106_host_device::access_map_le(address_map &map) +{ + map(0x00000000, 0x001fffff).rw(FUNC(mpc106_host_device::config_address_r), FUNC(mpc106_host_device::config_address_w)); + map(0x00200000, 0x002fffff).rw(FUNC(mpc106_host_device::config_data_r), FUNC(mpc106_host_device::config_data_w)); +} + +void mpc106_host_device::access_map_be(address_map &map) { map(0x00000000, 0x001fffff).rw(FUNC(mpc106_host_device::be_config_address_r), FUNC(mpc106_host_device::be_config_address_w)); map(0x00200000, 0x002fffff).rw(FUNC(mpc106_host_device::be_config_data_r), FUNC(mpc106_host_device::be_config_data_w)); @@ -149,32 +167,43 @@ u32 mpc106_host_device::be_config_address_r() void mpc106_host_device::be_config_address_w(offs_t offset, u32 data, u32 mem_mask) { - const u32 tempdata = swapendian_int32(data); - pci_host_device::config_address_w(offset, tempdata, mem_mask); + pci_host_device::config_address_w(offset, swapendian_int32(data), swapendian_int32(mem_mask)); } u32 mpc106_host_device::be_config_data_r(offs_t offset, u32 mem_mask) { - return swapendian_int32(pci_host_device::config_data_r(offset, mem_mask)); + return swapendian_int32(pci_host_device::config_data_r(offset, swapendian_int32(mem_mask))); } void mpc106_host_device::be_config_data_w(offs_t offset, u32 data, u32 mem_mask) { - const u32 tempdata = swapendian_int32(data); - pci_host_device::config_data_w(offset, tempdata, mem_mask); + pci_host_device::config_data_w(offset, swapendian_int32(data), swapendian_int32(mem_mask)); } template u32 mpc106_host_device::cpu_memory_r(offs_t offset, u32 mem_mask) { - const u32 result = m_cpu_space->read_dword(Base + (offset * 4), mem_mask); - return result; + if (m_picr1 & PICR1_LE_MODE) + { + return m_cpu_space->read_dword(Base + (offset * 4), mem_mask); + } + else + { + return swapendian_int32(m_cpu_space->read_dword(Base + (offset * 4), swapendian_int32(mem_mask))); + } } template void mpc106_host_device::cpu_memory_w(offs_t offset, u32 data, u32 mem_mask) { - m_cpu_space->write_dword(Base + (offset * 4), data, mem_mask); + if (m_picr1 & PICR1_LE_MODE) + { + m_cpu_space->write_dword(Base + (offset * 4), data, mem_mask); + } + else + { + m_cpu_space->write_dword(Base + (offset * 4), swapendian_int32(data), swapendian_int32(mem_mask)); + } } template u32 mpc106_host_device::cpu_memory_r<0>(offs_t offset, u32 mem_mask); @@ -186,14 +215,27 @@ template void mpc106_host_device::cpu_memory_w<0xff800000>(offs_t offset, u32 da template u32 mpc106_host_device::pci_memory_r(offs_t offset, u32 mem_mask) { - const u32 result = this->space(AS_PCI_MEM).read_dword(Base + (offset * 4), mem_mask); - return result; + if (m_picr1 & PICR1_LE_MODE) + { + return this->space(AS_PCI_MEM).read_dword(Base + (offset * 4), mem_mask); + } + else + { + return swapendian_int32(this->space(AS_PCI_MEM).read_dword(Base + (offset * 4), swapendian_int32(mem_mask))); + } } template void mpc106_host_device::pci_memory_w(offs_t offset, u32 data, u32 mem_mask) { - this->space(AS_PCI_MEM).write_dword(Base + (offset * 4), data, mem_mask); + if (m_picr1 & PICR1_LE_MODE) + { + this->space(AS_PCI_MEM).write_dword(Base + (offset * 4), data, mem_mask); + } + else + { + this->space(AS_PCI_MEM).write_dword(Base + (offset * 4), swapendian_int32(data), swapendian_int32((mem_mask))); + } } template u32 mpc106_host_device::pci_memory_r<0>(offs_t offset, u32 mem_mask); @@ -205,14 +247,27 @@ template void mpc106_host_device::pci_memory_w<0x80000000>(offs_t offset, u32 da template u32 mpc106_host_device::pci_io_r(offs_t offset, u32 mem_mask) { - u32 result = this->space(AS_PCI_IO).read_dword(Base + (offset * 4), mem_mask); - return result; + if (m_picr1 & PICR1_LE_MODE) + { + return this->space(AS_PCI_IO).read_dword(Base + (offset * 4), mem_mask); + } + else + { + return swapendian_int32(this->space(AS_PCI_IO).read_dword(Base + (offset * 4), swapendian_int32(mem_mask))); + } } template void mpc106_host_device::pci_io_w(offs_t offset, u32 data, u32 mem_mask) { - this->space(AS_PCI_IO).write_dword(Base + (offset * 4), data, mem_mask); + if (m_picr1 & PICR1_LE_MODE) + { + this->space(AS_PCI_IO).write_dword(Base + (offset * 4), data, mem_mask); + } + else + { + this->space(AS_PCI_IO).write_dword(Base + (offset * 4), swapendian_int32(data), swapendian_int32((mem_mask))); + } } template u32 mpc106_host_device::pci_io_r<0>(offs_t offset, u32 mem_mask); @@ -319,3 +374,13 @@ void mpc106_host_device::memory_enable_w(offs_t offset, u8 data) end2 >>= 8; } } + +u32 mpc106_host_device::picr1_r() +{ + return m_picr1; +} + +void mpc106_host_device::picr1_w(u32 data) +{ + m_picr1 = data; +} diff --git a/src/devices/machine/mpc106.h b/src/devices/machine/mpc106.h index 84d0a1780d6..da4ecca061f 100644 --- a/src/devices/machine/mpc106.h +++ b/src/devices/machine/mpc106.h @@ -51,7 +51,8 @@ protected: virtual space_config_vector memory_space_config() const override; private: - void access_map(address_map &map); + void access_map_le(address_map &map); + void access_map_be(address_map &map); u32 be_config_address_r(); void be_config_address_w(offs_t offset, u32 data, u32 mem_mask = ~0); u32 be_config_data_r(offs_t offset, u32 mem_mask = ~0); @@ -73,6 +74,8 @@ private: void memory_end_w(offs_t offset, u32 data, u32 mem_mask); u8 memory_enable_r(); void memory_enable_w(offs_t offset, u8 data); + u32 picr1_r(); + void picr1_w(u32 data); address_space_config m_mem_config, m_io_config; const char *m_rom_tag; @@ -87,6 +90,7 @@ private: u8 m_pwrconfig2; u32 m_memory_starts[4]; u32 m_memory_ends[4]; + u32 m_picr1; u8 m_memory_bank_enable; }; diff --git a/src/mame/apple/awacs_macrisc.cpp b/src/mame/apple/awacs_macrisc.cpp new file mode 100644 index 00000000000..6b18b3e835e --- /dev/null +++ b/src/mame/apple/awacs_macrisc.cpp @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + awacs_macrisc.cpp + + AWACS/Screamer 16-bit audio I/O for "MacRisc" architecture Macs (PCI-based) + + AWACS and Screamer are audio CODECs that comply with a specification. + Data transfer to and from them is done in terms of serial frames. + + Screamer is back-compatible with AWACS but supports more mixer inputs and + better power management. + +***************************************************************************/ + +#include "emu.h" +#include "awacs_macrisc.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_REGISTERS (1U << 0) + +#define VERBOSE (0) +#include "logmacro.h" + +constexpr u16 REGISTER_1_MUTE = 0x100; + +// device type definition +DEFINE_DEVICE_TYPE(AWACS_MACRISC, awacs_macrisc_device, "awacsmr", "AWACS MacRisc audio I/O") +DEFINE_DEVICE_TYPE(SCREAMER, screamer_device, "screamer", "Screamer audio I/O") + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// awacs_macrisc_device - constructor +//------------------------------------------------- + +awacs_macrisc_device::awacs_macrisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , m_output_cb(*this) + , m_input_cb(*this) + , m_stream(nullptr) +{ +} + +awacs_macrisc_device::awacs_macrisc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : awacs_macrisc_device(mconfig, AWACS_MACRISC, tag, owner, clock) + { + } + + screamer_device::screamer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : awacs_macrisc_device(mconfig, SCREAMER, tag, owner, clock) + { + } + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void awacs_macrisc_device::device_start() +{ + // create the stream + m_stream = stream_alloc(0, 2, clock()/1024, STREAM_SYNCHRONOUS); + + m_output_cb.resolve_safe(0); + m_input_cb.resolve_safe(); + + save_item(NAME(m_phase)); + save_item(NAME(m_active)); + save_item(NAME(m_registers)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void awacs_macrisc_device::device_reset() +{ + m_phase = 0; + m_active = ACTIVE_OUT; // AWACS is always running, Screamer has a real enable/disable bit + m_registers[1] = REGISTER_1_MUTE; + m_stream->set_sample_rate(clock() / 1024); +} + +void screamer_device::device_reset() +{ + awacs_macrisc_device::device_reset(); + m_active = 0; +} + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void awacs_macrisc_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) +{ + // if we're active and not muted + if ((m_active & ACTIVE_OUT) && !(m_registers[1] & REGISTER_1_MUTE)) + { + const s16 atten_L = 0xf - (m_registers[2] >> 6) & 0xf; + const s16 atten_R = 0xf - m_registers[2] & 0xf; + + const u32 data = swapendian_int32(m_output_cb(m_phase)); + const s16 l_raw = (s16)(data >> 16); + const s16 r_raw = (s16)(data & 0xffff); + + const s32 left = ((s32)l_raw * atten_L) >> 4; + const s32 right = ((s32)r_raw * atten_R) >> 4; + outputs[0].put_int(0, left, 32768); + outputs[1].put_int(0, right, 32768); + } + else + { + outputs[0].put_int(0, 0, 32768); + outputs[1].put_int(0, 0, 32768); + } + + m_phase = (m_phase + 1) & 0xfff; +} + +uint32_t awacs_macrisc_device::read_macrisc(offs_t offset) +{ + LOGMASKED(LOG_REGISTERS, "read AWACS @ %x\n", offset); + switch (offset) + { + case 0: // Audio Control + return 0; + + case 4: // Audio CODEC Control + return 0; + + case 8: // Audio CODEC Status + return 0x314000; // Screamer info + } + + return 0; +} + +void awacs_macrisc_device::write_macrisc(offs_t offset, uint32_t data) +{ + static const int rates[8] = { 512, 768, 1024, 1280, 1536, 2048, 2560, 3072 }; + + LOGMASKED(LOG_REGISTERS, "%s: %08x @ %x\n", tag(), data, offset*4); + switch (offset) + { + case 0: // Audio Control + m_stream->set_sample_rate(clock() / rates[(data >> 8) & 7]); + LOGMASKED(LOG_GENERAL, "%s: sample rate to %d Hz\n", tag(), clock() / rates[(data >> 8) & 7]); + break; + + case 4: // Audio CODEC Control + { + int subframe = (data >> 22) & 0x3; + int codec_addr = (data >> 12) & 0xfff; + int codec_data = (data & 0xfff); + + LOGMASKED(LOG_REGISTERS, "%s: CODEC control: %x to addr %x (subframe %d)\n", tag(), codec_data, codec_addr, subframe); + + m_registers[codec_addr] = codec_data; + } + break; + + case 8: // Audio CODEC Status + break; + + case 12: // Byte swap + printf("CODEC byte swap: %08x\n", data); + break; + } +} + +// Screamer +uint32_t screamer_device::read_macrisc(offs_t offset) +{ + switch (offset) + { + case 0: // Audio Control + return 0; + + case 4: // Audio CODEC Control + return 0; + + case 8: // Audio CODEC Status + return swapendian_int32((0x40 << 8) | // indicate CODEC is present + (1 << 16) | // manufacturer is Crystal Semiconductor + (3 << 20)); // CODEC version 3 (Screamer) + } + + return 0; +} + +void screamer_device::write_macrisc(offs_t offset, uint32_t data) +{ + awacs_macrisc_device::write_macrisc(offset, data); + + // if IDLE bit is off, we're active + if (!BIT(m_registers[6], 1)) + { + m_active |= ACTIVE_OUT; + } + else + { + m_active &= ~ACTIVE_OUT; + } + LOGMASKED(LOG_GENERAL, "%s: Playback %s reg 6 %x)\n", tag(), !BIT(m_registers[6], 1) ? "on" : "off", m_registers[6]); +} diff --git a/src/mame/apple/awacs_macrisc.h b/src/mame/apple/awacs_macrisc.h new file mode 100644 index 00000000000..3941fb29062 --- /dev/null +++ b/src/mame/apple/awacs_macrisc.h @@ -0,0 +1,76 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + awacs_macrisc.h + + AWACS/Screamer 16-bit audio I/O for "MacRisc" architecture Macs (PCI-based) + +***************************************************************************/ + +#ifndef MAME_APPLE_AWACS_MACRISC_H +#define MAME_APPLE_AWACS_MACRISC_H + +#pragma once + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> awacs_macrisc_device + +class awacs_macrisc_device : public device_t, public device_sound_interface +{ +public: + // construction/destruction + awacs_macrisc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto dma_output() { return m_output_cb.bind(); } + auto dma_input() { return m_input_cb.bind(); } + + virtual u32 read_macrisc(offs_t offset); + virtual void write_macrisc(offs_t offset, u32 data); + +protected: + awacs_macrisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); + + enum { + ACTIVE_OUT = 0x01, + ACTIVE_IN = 0x02 + }; + + static const u8 divider[4]; + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + + devcb_read32 m_output_cb; + devcb_write32 m_input_cb; + + sound_stream *m_stream; + + u32 m_registers[16]; + u8 m_active; + u16 m_phase; +}; + +class screamer_device : public awacs_macrisc_device +{ +public: + screamer_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + virtual u32 read_macrisc(offs_t offset) override; + virtual void write_macrisc(offs_t offset, u32 data) override; + +protected: + virtual void device_reset() override; +}; + +// device type definition +DECLARE_DEVICE_TYPE(AWACS_MACRISC, awacs_macrisc_device) +DECLARE_DEVICE_TYPE(SCREAMER, screamer_device) + +#endif // MAME_APPLE_AWACS_MACRISC_H diff --git a/src/mame/apple/bandit.cpp b/src/mame/apple/bandit.cpp index ee2008417b3..3bed4f837fd 100644 --- a/src/mame/apple/bandit.cpp +++ b/src/mame/apple/bandit.cpp @@ -156,14 +156,13 @@ void bandit_host_device::be_config_data_w(offs_t offset, u32 data, u32 mem_mask) template u32 bandit_host_device::pci_memory_r(offs_t offset, u32 mem_mask) { - u32 result = this->space(AS_PCI_MEM).read_dword(Base + (offset * 4), mem_mask); - return result; + return swapendian_int32(this->space(AS_PCI_MEM).read_dword(Base + (offset * 4), swapendian_int32(mem_mask))); } template void bandit_host_device::pci_memory_w(offs_t offset, u32 data, u32 mem_mask) { - this->space(AS_PCI_MEM).write_dword(Base + (offset * 4), data, mem_mask); + this->space(AS_PCI_MEM).write_dword(Base + (offset * 4), swapendian_int32(data), swapendian_int32((mem_mask))); } template u32 bandit_host_device::pci_memory_r<0x80000000>(offs_t offset, u32 mem_mask); @@ -180,14 +179,13 @@ template void bandit_host_device::pci_memory_w<0xf7000000>(offs_t offset, u32 da template u32 bandit_host_device::pci_io_r(offs_t offset, u32 mem_mask) { - u32 result = this->space(AS_PCI_IO).read_dword(Base + (offset * 4), mem_mask); - return result; + return swapendian_int32(this->space(AS_PCI_IO).read_dword(Base + (offset * 4), swapendian_int32(mem_mask))); } template void bandit_host_device::pci_io_w(offs_t offset, u32 data, u32 mem_mask) { - this->space(AS_PCI_IO).write_dword(Base + (offset * 4), data, mem_mask); + this->space(AS_PCI_IO).write_dword(Base + (offset * 4), swapendian_int32(data), swapendian_int32((mem_mask))); } // map PCI memory and I/O space stuff here diff --git a/src/mame/apple/burgundy.cpp b/src/mame/apple/burgundy.cpp new file mode 100644 index 00000000000..2f071929c00 --- /dev/null +++ b/src/mame/apple/burgundy.cpp @@ -0,0 +1,169 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + burgundy.cpp + + "Burgundy" stereo 16-bit audio CODEC (iMac, Blue & White G3) + +***************************************************************************/ + +#include "emu.h" +#include "burgundy.h" + +#define LOG_GENERAL (1U << 0) +#define LOG_REGISTERS (1U << 0) + +#define VERBOSE (0) +#include "logmacro.h" + +// device type definition +DEFINE_DEVICE_TYPE(BURGUNDY, burgundy_device, "burgundy", "Burgundy audio I/O") + +constexpr u32 CODEC_BUSY = (1 << 23); +constexpr u32 CODEC_PRESENT = (1 << 22); + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// burgundy_device - constructor +//------------------------------------------------- + +burgundy_device::burgundy_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, BURGUNDY, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , m_output_cb(*this) + , m_input_cb(*this) + , m_stream(nullptr) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void burgundy_device::device_start() +{ + // create the stream + m_stream = stream_alloc(0, 2, clock() / 512, STREAM_SYNCHRONOUS); + + m_output_cb.resolve_safe(0); + m_input_cb.resolve_safe(); + + save_item(NAME(m_phase)); + save_item(NAME(m_active)); + save_item(NAME(m_registers)); + save_item(NAME(m_codec_status)); + save_item(NAME(m_counter)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void burgundy_device::device_reset() +{ + m_phase = 0; + m_codec_status = 0; + m_counter = 0; + m_stream->set_sample_rate(clock() / 512); +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests for +// our sound stream +//------------------------------------------------- + +void burgundy_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) +{ + if (m_codec_status & CODEC_BUSY) + { + m_codec_status &= ~CODEC_BUSY; // clear busy + m_counter++; + m_counter &= 3; + } + + if (m_active & ACTIVE_OUT) + { + const u32 data = swapendian_int32(m_output_cb(m_phase)); + const s16 left = data >> 16; + const s16 right = data; + outputs[0].put_int(0, left, 32768); + outputs[1].put_int(0, right, 32768); + } + else + { + outputs[0].put_int(0, 0, 32768); + outputs[1].put_int(0, 0, 32768); + } + + m_phase = (m_phase + 1) & 0xfff; +} + +uint32_t burgundy_device::read_macrisc(offs_t offset) +{ + switch (offset) + { + case 0: // Audio Control + return 0; + + case 4: // Audio CODEC Control + return m_last_codec_control; + + case 8: // Audio CODEC Status + return m_codec_status; + } + + return 0; +} + +void burgundy_device::write_macrisc(offs_t offset, uint32_t data) +{ + switch (offset) + { + case 0: // Audio Control + break; + + case 4: // Audio CODEC Control + m_last_codec_control = data; + + m_reg_addr = (data >> 12) & 0xff; + m_cur_byte = (data >> 8) & 3; + m_last_byte = (data >> 10) & 3; + + if (BIT(data, 21)) + { + u32 reg_mask = 0xff << (m_cur_byte << 3); + m_registers[m_reg_addr] &= ~reg_mask; + m_registers[m_reg_addr] |= ((data & 0xff) << (m_cur_byte << 3)); + LOGMASKED(LOG_REGISTERS, "%s: reg %x is now %x\n", tag(), m_reg_addr, m_registers[m_reg_addr]); + + if (m_reg_addr == 0x60) + { + if ((m_registers[0x60] & 6) != 0) + { + LOGMASKED(LOG_GENERAL, "%s: Playback enabled\n", tag()); + m_active |= ACTIVE_OUT; + } + else + { + LOGMASKED(LOG_GENERAL, "%s: Playback disabled\n", tag()); + m_active &= ~ACTIVE_OUT; + } + } + } + else + { + u8 reg_data = (m_registers[m_reg_addr] >> (m_cur_byte << 3)) & 0xff; + m_codec_status = CODEC_BUSY | CODEC_PRESENT | (m_counter << 14) | (m_cur_byte << 12) | (reg_data << 4); + } + break; + + case 8: // Audio CODEC Status + break; + } +} diff --git a/src/mame/apple/burgundy.h b/src/mame/apple/burgundy.h new file mode 100644 index 00000000000..ca40ab29443 --- /dev/null +++ b/src/mame/apple/burgundy.h @@ -0,0 +1,62 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/*************************************************************************** + + burgundy.h + + "Burgundy" stereo 16-bit audio CODEC (iMac, Blue & White G3) + +***************************************************************************/ + +#ifndef MAME_APPLE_BURGUNDY_H +#define MAME_APPLE_BURGUNDY_H + +#pragma once + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> awacs_macrisc_device + +class burgundy_device : public device_t, public device_sound_interface +{ +public: + // construction/destruction + burgundy_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto dma_output() { return m_output_cb.bind(); } + auto dma_input() { return m_input_cb.bind(); } + + virtual u32 read_macrisc(offs_t offset); + virtual void write_macrisc(offs_t offset, u32 data); + +protected: + enum { + ACTIVE_OUT = 0x01, + ACTIVE_IN = 0x02 + }; + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + + virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + + devcb_read32 m_output_cb; + devcb_write32 m_input_cb; + + sound_stream *m_stream; + + u32 m_registers[256]; + u8 m_active; + u16 m_phase; + u16 m_reg_addr, m_cur_byte, m_last_byte; + u32 m_codec_status, m_last_codec_control; + u8 m_counter; +}; + +// device type definition +DECLARE_DEVICE_TYPE(BURGUNDY, burgundy_device) + +#endif // MAME_APPLE_BURGUNDY_H diff --git a/src/mame/apple/dbdma.cpp b/src/mame/apple/dbdma.cpp new file mode 100644 index 00000000000..cd10acc5561 --- /dev/null +++ b/src/mame/apple/dbdma.cpp @@ -0,0 +1,273 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont +/* + Apple "Descriptor-Based DMA" channel device + Emulation by R. Belmont +*/ + +#include "emu.h" +#include "dbdma.h" + +#define LOG_GENERAL (1U << 0) + +#define VERBOSE (0) +#include "logmacro.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(DBDMA_CHANNEL, dbdma_device, "appledbdma", "Apple descriptor-based DMA channel") + +static constexpr u16 STATUS_RUN = 0x8000; +static constexpr u16 STATUS_PAUSE = 0x4000; +static constexpr u16 STATUS_FLUSH = 0x2000; +static constexpr u16 STATUS_WAKE = 0x1000; +[[maybe_unused]] static constexpr u16 STATUS_DEAD = 0x0800; +static constexpr u16 STATUS_ACTIVE = 0x0400; + +//------------------------------------------------- +// dbdma_device - constructor +//------------------------------------------------- + +dbdma_device::dbdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, DBDMA_CHANNEL, tag, owner, clock), + write_irq(*this) +{ +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void dbdma_device::device_start() +{ + write_irq.resolve_safe(); + + save_item(NAME(m_status)); + save_item(NAME(m_command_pointer)); + save_item(NAME(m_intselect)); + save_item(NAME(m_branchselect)); + save_item(NAME(m_waitselect)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void dbdma_device::device_reset() +{ + m_status = 0; + m_command_pointer = 0; + m_intselect = m_branchselect = m_waitselect = 0; +} + +// 00 = control (write only) +// 04 = status (read only) +// 0c = command pointer (read/write) +// 10 = interrupt select +// 14 = branch select +// 18 = wait select + +void dbdma_device::map(address_map &map) +{ + map(0x00, 0x03).w(FUNC(dbdma_device::control_w)); + map(0x04, 0x07).r(FUNC(dbdma_device::status_r)); + map(0x0c, 0x0f).rw(FUNC(dbdma_device::cmdpointer_r), FUNC(dbdma_device::cmdpointer_w)); + map(0x10, 0x13).rw(FUNC(dbdma_device::intselect_r), FUNC(dbdma_device::intselect_w)); + map(0x14, 0x17).rw(FUNC(dbdma_device::branchselect_r), FUNC(dbdma_device::branchselect_w)); + map(0x18, 0x1b).rw(FUNC(dbdma_device::waitselect_r), FUNC(dbdma_device::waitselect_w)); +} + +void dbdma_device::control_w(u32 data) +{ + // the top 16 bits of data are a mask selecting which bits of + // the status are changed by the write. + const u16 mask = (data >> 16); + + m_status &= (mask ^ 0xffff); + m_status |= (data & mask); + LOGMASKED(LOG_GENERAL, "%s: channel status/control to %04x (raw %08x)\n", tag(), m_status, data); + + if (m_status & STATUS_RUN) + { + LOGMASKED(LOG_GENERAL, "%s: channel set to RUN, also setting ACTIVE\n", tag()); + m_status |= STATUS_ACTIVE; + } + else + { + m_status &= ~STATUS_ACTIVE; + } + + if (m_status & STATUS_PAUSE) + { + m_status &= ~STATUS_ACTIVE; + } + + if (m_status & STATUS_FLUSH) + { + // TODO + } + + if (m_status & STATUS_WAKE) + { + // TODO + } +} + +u32 dbdma_device::status_r() +{ + return m_status; +} + +u32 dbdma_device::cmdpointer_r() +{ + return m_command_pointer; +} + +void dbdma_device::cmdpointer_w(u32 data) +{ + if (!(m_status & STATUS_ACTIVE)) + { + LOGMASKED(LOG_GENERAL, "%s: %08x to command pointer\n", tag(), swapendian_int32(data)); + m_command_pointer = data; + + new_command(); + } +} + +u32 dbdma_device::intselect_r() +{ + return m_intselect; +} + +void dbdma_device::intselect_w(u32 data) +{ + m_intselect = data; +} + +u32 dbdma_device::branchselect_r() +{ + return m_branchselect; +} + +void dbdma_device::branchselect_w(u32 data) +{ + m_branchselect = data; +} + +u32 dbdma_device::waitselect_r() +{ + return m_waitselect; +} + +void dbdma_device::waitselect_w(u32 data) +{ + m_waitselect = data; +} + +u32 dbdma_device::dma_read(u32 offset) +{ + step_program(); + return m_xfer_word; +} + +void dbdma_device::dma_write(u32 offset, u32 data) +{ + m_xfer_word = data; + step_program(); +} + +void dbdma_device::step_program() +{ + if ((m_status & STATUS_PAUSE) || !(m_status & STATUS_ACTIVE)) + { + return; + } + + switch (m_opcode >> 28) + { + case 0: // OUTPUT MORE + case 1: // OUTPUT LAST + m_xfer_word = m_pci_memory->read_dword(m_address); + m_address += 4; + m_currentXfer += 4; + break; + + case 2: // INPUT MORE + case 3: // INPUT LAST + m_pci_memory->write_dword(m_address, m_xfer_word); + m_address += 4; + m_currentXfer += 4; + break; + + case 4: // STORE QUAD + switch (m_xferLimit & 7) + { + case 1: + m_pci_memory->write_byte(m_address, m_cmdDep); + break; + + case 2: + m_pci_memory->write_word(m_address, m_cmdDep); + break; + + case 4: + m_pci_memory->write_dword(m_address, m_cmdDep); + break; + } + m_currentXfer += m_opcode & 7; + break; + + case 5: // LOAD QUAD + switch (m_xferLimit & 7) + { + case 1: + m_xfer_word = m_pci_memory->read_byte(m_address); + m_pci_memory->write_byte(m_cmdDep, m_xfer_word); + break; + + case 2: + m_xfer_word = m_pci_memory->read_word(m_address); + m_pci_memory->write_word(m_cmdDep, m_xfer_word); + break; + + case 4: + m_xfer_word = m_pci_memory->read_dword(m_address); + m_pci_memory->write_dword(m_cmdDep, m_xfer_word); + break; + } + m_currentXfer += m_opcode & 7; + break; + + case 6: // NOP + break; + + case 7: // STOP + m_status &= ~STATUS_ACTIVE; + break; + } + + if (m_status & STATUS_ACTIVE) + { + if (m_currentXfer >= m_xferLimit) + { + m_command_pointer += 16; + LOGMASKED(LOG_GENERAL, "%s: Advancing command pointer to %08x\n", tag(), m_command_pointer); + new_command(); + } + } +} + +void dbdma_device::new_command() +{ + m_opcode = m_pci_memory->read_dword(m_command_pointer); + m_address = m_pci_memory->read_dword(m_command_pointer + 4); + m_cmdDep = m_pci_memory->read_dword(m_command_pointer + 8); + m_statusCount = m_pci_memory->read_dword(m_command_pointer + 12); + m_currentXfer = m_statusCount & 0xffff; + m_xferLimit = m_opcode & 0xffff; + + LOGMASKED(LOG_GENERAL, "%s: new command %08x %08x %08x %08x\n", tag(), m_opcode, m_address, m_cmdDep, m_statusCount); + LOGMASKED(LOG_GENERAL, "%s: opcode %d\n", tag(), m_opcode >> 28); +} diff --git a/src/mame/apple/dbdma.h b/src/mame/apple/dbdma.h new file mode 100644 index 00000000000..191109805d2 --- /dev/null +++ b/src/mame/apple/dbdma.h @@ -0,0 +1,69 @@ +// license:BSD-3-Clause +// copyright-holders:R. Belmont + +#ifndef MAME_APPLE_DBDMA_H +#define MAME_APPLE_DBDMA_H + +#pragma once + + +// ======================> dbdma_device + +class dbdma_device : public device_t +{ +public: + // construction/destruction + dbdma_device(const machine_config &mconfig, const char *tag, device_t *owner) + : dbdma_device(mconfig, tag, owner, (uint32_t)0) + { + } + + dbdma_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + u32 dma_read(u32 offset); + void dma_write(u32 offset, u32 data); + + auto irq_callback() { return write_irq.bind(); } + + void set_address_space(address_space *space) { m_pci_memory = space; } + + void map(address_map &map); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + +private: + devcb_write_line write_irq; + + address_space *m_pci_memory; + + u16 m_status; + u32 m_command_pointer; + u32 m_intselect; + u32 m_branchselect; + u32 m_waitselect; + u32 m_xfer_word; + u32 m_opcode, m_address, m_cmdDep, m_statusCount; + u16 m_currentXfer, m_xferLimit; + + void control_w(u32 data); + u32 status_r(); + u32 cmdpointer_r(); + void cmdpointer_w(u32 data); + u32 intselect_r(); + void intselect_w(u32 data); + u32 branchselect_r(); + void branchselect_w(u32 data); + u32 waitselect_r(); + void waitselect_w(u32 data); + + void step_program(); + void new_command(); +}; + +// device type definition +DECLARE_DEVICE_TYPE(DBDMA_CHANNEL, dbdma_device) + +#endif // MAME_APPLE_DBDMA_H diff --git a/src/mame/apple/heathrow.cpp b/src/mame/apple/heathrow.cpp index 83c06520d62..d69a096dc79 100644 --- a/src/mame/apple/heathrow.cpp +++ b/src/mame/apple/heathrow.cpp @@ -6,7 +6,7 @@ These ASICs sit on the PCI bus and provide what came to be known as "Mac I/O", including: - - A VIA to interface with Cuda + - A VIA to interface with Cuda / an enhanced VIA that can speak SPI to interface with PG&E (O'Hare and later) - Serial - SWIM3 floppy - MESH SCSI ("Macintosh Enhanced SCSI Handler"), a 5394/96 clone with some features Apple didn't use removed) @@ -22,6 +22,12 @@ #include "bus/rs232/rs232.h" #include "formats/ap_dsk35.h" +#define LOG_GENERAL (1U << 0) +#define LOG_IRQ (1U << 1) + +#define VERBOSE (0) +#include "logmacro.h" + static constexpr u32 C7M = 7833600; static constexpr u32 C15M = (C7M * 2); @@ -37,27 +43,51 @@ DEFINE_DEVICE_TYPE(GRAND_CENTRAL, grandcentral_device, "grndctrl", "Apple Grand //------------------------------------------------- // ADDRESS_MAP //------------------------------------------------- -/* - A "Kanga" G3 PowerBook says: - 16000 : VIA - 12000 : SCC Rd - 12000 : SCC Wr - 15000 : IWM/SWIM - 10000 : SCSI - - DMA is at 8xxx (audio DMA at 88xx) - ATA is at 20000 +/* Grand Central O'Hare Heathrow/Paddington +0x10000 SCSI0 SCSI0 SCSI +0x11000 MACE Ethernet (unused) "BigMac" Ethernet +0x12000 SCC "compatibility" SCC compat SCC compat +0x13000 SCC "MacRisc" SCC MacRisc SCC MacRisc +0x14000 Audio Audio Audio +0x15000 SWIM3 SWIM3 SWIM3 +0x16000 VIA VIA VIA +0x17000 VIA VIA VIA +0x18000 SCSI1 (unused) (unused) +0x19000 Ethernet MAC PROM (unused) ADB Master Cell +0x1a000 (external IOBus) (external IOBus) (external IOBus) +0x1b000 (external IOBus) (external IOBus) (external IOBus) +0x1c000 (external IOBus) (external IOBus) (external IOBus) +0x1d000 (external IOBus) (external IOBus) (external IOBus) +0x1e000 (external IOBus) (unused) +0x1f000 (external IOBus) (unused) +0x20000 (external IOBus) ATA bus 0 ATA bus 0 +0x21000 (external IOBus) ATA bus 1 ATA bus 1 +0x60000 (128K BAR, no) PRAM PRAM +0x70000 (128K BAR, no) PRAM PRAM */ +void grandcentral_device::map(address_map &map) +{ + map(0x00000, 0x00fff).rw(FUNC(grandcentral_device::macio_r), FUNC(grandcentral_device::macio_w)); + map(0x08800, 0x0881f).m(m_dma_audio_out, FUNC(dbdma_device::map)); + map(0x08900, 0x0891f).m(m_dma_audio_in, FUNC(dbdma_device::map)); + map(0x12000, 0x12fff).rw(FUNC(grandcentral_device::scc_r), FUNC(grandcentral_device::scc_w)); + map(0x13000, 0x13fff).rw(FUNC(grandcentral_device::scc_macrisc_r), FUNC(grandcentral_device::scc_macrisc_w)); + map(0x14000, 0x140ff).rw(FUNC(heathrow_device::codec_r), FUNC(heathrow_device::codec_w)); + map(0x15000, 0x15fff).rw(FUNC(grandcentral_device::fdc_r), FUNC(grandcentral_device::fdc_w)); + map(0x16000, 0x17fff).rw(FUNC(grandcentral_device::mac_via_r), FUNC(grandcentral_device::mac_via_w)); +} + void heathrow_device::map(address_map &map) { map(0x00000, 0x00fff).rw(FUNC(heathrow_device::macio_r), FUNC(heathrow_device::macio_w)); + map(0x08800, 0x0881f).m(m_dma_audio_out, FUNC(dbdma_device::map)); + map(0x08900, 0x0891f).m(m_dma_audio_in, FUNC(dbdma_device::map)); map(0x12000, 0x12fff).rw(FUNC(heathrow_device::scc_r), FUNC(heathrow_device::scc_w)); map(0x13000, 0x13fff).rw(FUNC(heathrow_device::scc_macrisc_r), FUNC(heathrow_device::scc_macrisc_w)); - map(0x14000, 0x1401f).rw(m_awacs, FUNC(awacs_device::read), FUNC(awacs_device::write)); - map(0x14020, 0x14023).r(FUNC(heathrow_device::unk_r)); + map(0x14000, 0x140ff).rw(FUNC(heathrow_device::codec_r), FUNC(heathrow_device::codec_w)); map(0x15000, 0x15fff).rw(FUNC(heathrow_device::fdc_r), FUNC(heathrow_device::fdc_w)); map(0x16000, 0x17fff).rw(FUNC(heathrow_device::mac_via_r), FUNC(heathrow_device::mac_via_w)); - map(0x60000, 0x7ffff).rw(FUNC(heathrow_device::nvram_r), FUNC(heathrow_device::nvram_w)); + map(0x60000, 0x7ffff).rw(FUNC(heathrow_device::nvram_r), FUNC(heathrow_device::nvram_w)).umask32(0x000000ff); } //------------------------------------------------- @@ -71,16 +101,13 @@ void heathrow_device::device_add_mconfig(machine_config &config) m_via1->writepa_handler().set(FUNC(heathrow_device::via_out_a)); m_via1->writepb_handler().set(FUNC(heathrow_device::via_out_b)); m_via1->cb2_handler().set(FUNC(heathrow_device::via_out_cb2)); - m_via1->irq_handler().set(FUNC(heathrow_device::via1_irq)); + m_via1->irq_handler().set(FUNC(heathrow_device::set_irq_line<18>)); - AWACS(config, m_awacs, 45.1584_MHz_XTAL / 2); - m_awacs->dma_output().set(FUNC(heathrow_device::sound_dma_output)); - m_awacs->dma_input().set(FUNC(heathrow_device::sound_dma_input)); + DBDMA_CHANNEL(config, m_dma_audio_out, 0); + m_dma_audio_out->irq_callback().set(FUNC(heathrow_device::set_irq_line<8>)); - SPEAKER(config, "lspeaker").front_left(); - SPEAKER(config, "rspeaker").front_right(); - m_awacs->add_route(0, "lspeaker", 1.0); - m_awacs->add_route(1, "rspeaker", 1.0); + DBDMA_CHANNEL(config, m_dma_audio_in, 0); + m_dma_audio_in->irq_callback().set(FUNC(heathrow_device::set_irq_line<9>)); SWIM3(config, m_fdc, C15M); m_fdc->devsel_cb().set(FUNC(heathrow_device::devsel_w)); @@ -116,16 +143,21 @@ void heathrow_device::config_map(address_map &map) heathrow_device::heathrow_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) : pci_device(mconfig, type, tag, owner, clock), + write_irq(*this), write_pb4(*this), write_pb5(*this), write_cb2(*this), read_pb3(*this), + read_codec(*this), + write_codec(*this), m_maincpu(*this, finder_base::DUMMY_TAG), m_via1(*this, "via1"), m_fdc(*this, "fdc"), m_floppy(*this, "fdc:%d", 0U), - m_awacs(*this, "awacs"), m_scc(*this, "scc"), + m_dma_audio_in(*this, "dma_audin"), + m_dma_audio_out(*this, "dma_audout"), + m_pci_memory(*this, ":pci:00.0", AS_DATA), m_cur_floppy(nullptr), m_hdsel(0) { @@ -158,41 +190,58 @@ ohare_device::ohare_device(const machine_config &mconfig, const char *tag, devic void heathrow_device::common_init() { + write_irq.resolve_safe(); write_pb4.resolve_safe(); write_pb5.resolve_safe(); write_cb2.resolve_safe(); read_pb3.resolve_safe(0); + read_codec.resolve_safe(0); + write_codec.resolve_safe(); - m_6015_timer = timer_alloc(FUNC(heathrow_device::mac_6015_tick), this); - m_6015_timer->adjust(attotime::never); - save_item(NAME(m_hdsel)); + m_dma_audio_out->set_address_space(m_pci_memory); - add_map(0x80000, M_MEM, FUNC(heathrow_device::map)); command = 2; // enable our memory range revision = 1; + + m_InterruptEvents = m_InterruptMask = m_InterruptLevels = 0; + m_InterruptEvents2 = m_InterruptMask2 = m_InterruptLevels2 = 0; + recalc_irqs(); + + save_item(NAME(m_hdsel)); + save_item(NAME(m_InterruptEvents)); + save_item(NAME(m_InterruptMask)); + save_item(NAME(m_InterruptLevels)); + save_item(NAME(m_InterruptEvents2)); + save_item(NAME(m_InterruptMask2)); + save_item(NAME(m_InterruptLevels2)); + save_item(NAME(m_nvram)); } void heathrow_device::device_start() { common_init(); + add_map(0x80000, M_MEM, FUNC(heathrow_device::map)); set_ids(0x106b0010, 0x01, 0xff000001, 0x000000); } void paddington_device::device_start() { common_init(); + add_map(0x80000, M_MEM, FUNC(heathrow_device::map)); set_ids(0x106b0017, 0x01, 0xff000001, 0x000000); } void grandcentral_device::device_start() { common_init(); + add_map(0x20000, M_MEM, FUNC(heathrow_device::map)); // Grand Central only has 128K of BAR space, the others have 512K set_ids(0x106b0002, 0x01, 0xff000001, 0x000000); } void ohare_device::device_start() { common_init(); + add_map(0x80000, M_MEM, FUNC(heathrow_device::map)); set_ids(0x106b0007, 0x01, 0xff000001, 0x000000); } @@ -202,18 +251,9 @@ void ohare_device::device_start() void heathrow_device::device_reset() { - // start 60.15 Hz timer - m_6015_timer->adjust(attotime::from_hz(60.15), 0, attotime::from_hz(60.15)); - m_hdsel = 0; } -TIMER_CALLBACK_MEMBER(heathrow_device::mac_6015_tick) -{ - m_via1->write_ca1(CLEAR_LINE); - m_via1->write_ca1(ASSERT_LINE); -} - u8 heathrow_device::via_in_a() { return 0x80; @@ -248,10 +288,6 @@ void heathrow_device::via_out_b(u8 data) write_pb5(BIT(data, 5)); } -WRITE_LINE_MEMBER(heathrow_device::via1_irq) -{ -} - WRITE_LINE_MEMBER(heathrow_device::cb1_w) { m_via1->write_cb1(state); @@ -353,13 +389,126 @@ void heathrow_device::devsel_w(u8 devsel) u32 heathrow_device::macio_r(offs_t offset) { + // InterruptLevels = live status of all interrupt lines + // InterruptMask = mask to determine which bits of InterruptLevels matter + // InterruptEvents = interrupts allowed to fire by InterruptMask // printf("macio_r: offset %x (%x)\n", offset, offset*4); + switch (offset << 2) + { + case 0x10: + return swapendian_int32(m_InterruptEvents2 & m_InterruptMask2); + case 0x14: + return swapendian_int32(m_InterruptMask2); + case 0x1c: + return swapendian_int32(m_InterruptLevels2); + case 0x20: + return swapendian_int32(m_InterruptEvents & m_InterruptMask); + case 0x24: + return swapendian_int32(m_InterruptMask); + case 0x2c: + return swapendian_int32(m_InterruptLevels); + } return 0; } void heathrow_device::macio_w(offs_t offset, u32 data, u32 mem_mask) { + data = swapendian_int32(data); + mem_mask = swapendian_int32(mem_mask); // printf("macio_w: offset %x (%x) data %08x mask %08x\n", offset, offset*4, data, mem_mask); + switch (offset << 2) + { + case 0x14: + m_InterruptMask2 = data; + recalc_irqs(); + break; + case 0x18: // InterruptClear + // which interrupt mode? + if (BIT(m_InterruptMask2, 31)) + { + // in Mode 1, "1" to bit 31 clears all active interrupts + if (BIT(data, 31)) + { + m_InterruptEvents2 = 0; + } + else + { + m_InterruptEvents2 &= (data ^ 0xffffffff); + } + } + else + { + m_InterruptEvents2 &= (data ^ 0xffffffff); + } + recalc_irqs(); + break; + case 0x24: + m_InterruptMask = data; + recalc_irqs(); + break; + case 0x28: // InterruptClear + // which interrupt mode? + if (BIT(m_InterruptMask, 31)) + { + // in Mode 1, "1" to bit 31 clears all active interrupts + if (BIT(data, 31)) + { + m_InterruptEvents = 0; + } + else + { + m_InterruptEvents &= (data ^ 0xffffffff); + } + } + else + { + m_InterruptEvents &= (data ^ 0xffffffff); + } + recalc_irqs(); + break; + } +} + +void heathrow_device::recalc_irqs() +{ + LOGMASKED(LOG_IRQ, "%s recalc_irqs: events %08x levels %08x mask %08x\n", tag(), m_InterruptEvents, m_InterruptLevels, m_InterruptMask); + m_InterruptEvents = m_InterruptLevels & m_InterruptMask; + m_InterruptEvents2 = m_InterruptLevels2 & m_InterruptMask2; + if (m_InterruptEvents || m_InterruptEvents2) + { + write_irq(ASSERT_LINE); + } + else + { + write_irq(CLEAR_LINE); + } +} + +template WRITE_LINE_MEMBER(heathrow_device::set_irq_line) +{ + if (bit < 32) + { + if (state == ASSERT_LINE) + { + m_InterruptLevels |= (1 << bit); + } + else + { + m_InterruptLevels &= ((1 << bit) ^ 0xffffffff); + } + } + else + { + if (state == ASSERT_LINE) + { + m_InterruptLevels2 |= (1 << (bit-32)); + } + else + { + m_InterruptLevels2 &= ((1 << (bit-32)) ^ 0xffffffff); + } + } + recalc_irqs(); } u8 heathrow_device::fdc_r(offs_t offset) @@ -374,12 +523,12 @@ void heathrow_device::fdc_w(offs_t offset, u8 data) u8 heathrow_device::nvram_r(offs_t offset) { - return m_nvram[offset >> 2]; + return m_nvram[offset>>2]; } void heathrow_device::nvram_w(offs_t offset, u8 data) { - m_nvram[offset >> 2] = data; + m_nvram[offset>>2] = data; } u16 heathrow_device::scc_r(offs_t offset) @@ -430,21 +579,23 @@ void heathrow_device::scc_macrisc_w(offs_t offset, u8 data) } } -u32 heathrow_device::unk_r(offs_t offset) +// Audio support +uint32_t heathrow_device::codec_r(offs_t offset) { - m_toggle ^= 0xffffffff; - return m_toggle; + return read_codec(offset); } -// ***************************************************** -// DMA -// ***************************************************** - -u32 heathrow_device::sound_dma_output(offs_t offset) +void heathrow_device::codec_w(offs_t offset, uint32_t data) { - return 0; + write_codec(offset, data); } -void heathrow_device::sound_dma_input(offs_t offset, u32 value) +u32 heathrow_device::codec_dma_read(u32 offset) { + return m_dma_audio_out->dma_read(offset); +} + +void heathrow_device::codec_dma_write(u32 offset, u32 data) +{ + m_dma_audio_in->dma_write(offset, data); } diff --git a/src/mame/apple/heathrow.h b/src/mame/apple/heathrow.h index 8ceecf19195..548db815697 100644 --- a/src/mame/apple/heathrow.h +++ b/src/mame/apple/heathrow.h @@ -6,13 +6,14 @@ #pragma once +#include "dbdma.h" + #include "machine/pci.h" #include "machine/6522via.h" #include "machine/applefdintf.h" #include "machine/swim3.h" #include "machine/z80scc.h" #include "speaker.h" -#include "sound/awacs.h" // ======================> heathrow_device @@ -24,19 +25,32 @@ public: heathrow_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); // interface routines + auto irq_callback() { return write_irq.bind(); } auto pb4_callback() { return write_pb4.bind(); } auto pb5_callback() { return write_pb5.bind(); } auto cb2_callback() { return write_cb2.bind(); } auto pb3_callback() { return read_pb3.bind(); } - void map(address_map &map); + auto codec_r_callback() { return read_codec.bind(); } + auto codec_w_callback() { return write_codec.bind(); } + + virtual void map(address_map &map); template void set_maincpu_tag(T &&... args) { m_maincpu.set_tag(std::forward(args)...); } + template void set_pci_root_tag(T &&... args) { m_pci_memory.set_tag(std::forward(args)...); } DECLARE_WRITE_LINE_MEMBER(cb1_w); DECLARE_WRITE_LINE_MEMBER(cb2_w); DECLARE_WRITE_LINE_MEMBER(scc_irq_w); + template DECLARE_WRITE_LINE_MEMBER(set_irq_line); + + u32 codec_dma_read(u32 offset); + void codec_dma_write(u32 offset, u32 data); + + u32 codec_r(offs_t offset); + void codec_w(offs_t offset, u32 data); + protected: // device-level overrides virtual void device_start() override; @@ -47,40 +61,6 @@ protected: void common_init(); -private: - emu_timer *m_6015_timer; - devcb_write_line write_pb4, write_pb5, write_cb2; - devcb_read_line read_pb3; - - required_device m_maincpu; - required_device m_via1; - required_device m_fdc; - required_device_array m_floppy; - required_device m_awacs; - required_device m_scc; - - floppy_image_device *m_cur_floppy = nullptr; - int m_hdsel; - - u8 m_nvram[0x20000/4]; - - u16 mac_via_r(offs_t offset); - void mac_via_w(offs_t offset, u16 data, u16 mem_mask); - - u8 via_in_a(); - u8 via_in_b(); - void via_out_a(u8 data); - void via_out_b(u8 data); - void via_sync(); - void field_interrupts(); - DECLARE_WRITE_LINE_MEMBER(via_out_cb2); - DECLARE_WRITE_LINE_MEMBER(via1_irq); - DECLARE_WRITE_LINE_MEMBER(via2_irq); - DECLARE_WRITE_LINE_MEMBER(asc_irq); - TIMER_CALLBACK_MEMBER(mac_6015_tick); - - void phases_w(u8 phases); - void devsel_w(u8 devsel); uint16_t swim_r(offs_t offset, u16 mem_mask); void swim_w(offs_t offset, u16 data, u16 mem_mask); @@ -98,12 +78,46 @@ private: u8 scc_macrisc_r(offs_t offset); void scc_macrisc_w(offs_t offset, u8 data); - u32 m_toggle; - u32 unk_r(offs_t offset); + u16 mac_via_r(offs_t offset); + void mac_via_w(offs_t offset, u16 data, u16 mem_mask); - // DMA - u32 sound_dma_output(offs_t offset); - void sound_dma_input(offs_t offset, u32 value); + devcb_write_line write_irq, write_pb4, write_pb5, write_cb2; + devcb_read_line read_pb3; + + devcb_read32 read_codec; + devcb_write32 write_codec; + + required_device m_maincpu; + required_device m_via1; + required_device m_fdc; + required_device_array m_floppy; + required_device m_scc; + required_device m_dma_audio_in, m_dma_audio_out; + required_address_space m_pci_memory; + +private: + floppy_image_device *m_cur_floppy = nullptr; + int m_hdsel; + + u8 m_nvram[0x20000]; + + u8 via_in_a(); + u8 via_in_b(); + void via_out_a(u8 data); + void via_out_b(u8 data); + void via_sync(); + void field_interrupts(); + DECLARE_WRITE_LINE_MEMBER(via_out_cb2); + + void phases_w(u8 phases); + void devsel_w(u8 devsel); + + u32 m_toggle; + + // Interrupts + void recalc_irqs(); + u32 m_InterruptEvents, m_InterruptMask, m_InterruptLevels; + u32 m_InterruptEvents2, m_InterruptMask2, m_InterruptLevels2; }; class paddington_device : public heathrow_device @@ -123,6 +137,8 @@ public: // construction/destruction grandcentral_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + void map(address_map &map) override; + protected: // device-level overrides virtual void device_start() override; diff --git a/src/mame/apple/imacg3.cpp b/src/mame/apple/imacg3.cpp index 19f793e330e..7bf0bbab2ed 100644 --- a/src/mame/apple/imacg3.cpp +++ b/src/mame/apple/imacg3.cpp @@ -25,6 +25,7 @@ #include "machine/pci.h" #include "machine/pci-ide.h" #include "machine/ram.h" +#include "burgundy.h" #include "cuda.h" #include "heathrow.h" #include "macadb.h" @@ -54,6 +55,11 @@ private: m_maincpu->set_input_line(INPUT_LINE_HALT, state); m_maincpu->set_input_line(INPUT_LINE_RESET, state); } + + WRITE_LINE_MEMBER(irq_w) + { + m_maincpu->set_input_line(PPC_IRQ, state); + } }; imac_state::imac_state(const machine_config &mconfig, device_type type, const char *tag) : @@ -116,6 +122,8 @@ void imac_state::imac(machine_config &config) paddington_device &paddington(PADDINGTON(config, "pci:10.0", 0)); paddington.set_maincpu_tag("maincpu"); + paddington.set_pci_root_tag(":pci:00.0", AS_DATA); + paddington.irq_callback().set(FUNC(imac_state::irq_w)); MACADB(config, m_macadb, 15.6672_MHz_XTAL); @@ -151,6 +159,17 @@ void imac_state::imac(machine_config &config) RAM(config, m_ram); m_ram->set_default_size("32M"); m_ram->set_extra_options("32M,64M,128M"); + + burgundy_device &burgundy(BURGUNDY(config, "codec", 45.1584_MHz_XTAL / 2)); + burgundy.dma_output().set(paddington, FUNC(heathrow_device::codec_dma_read)); + + paddington.codec_r_callback().set(burgundy, FUNC(burgundy_device::read_macrisc)); + paddington.codec_w_callback().set(burgundy, FUNC(burgundy_device::write_macrisc)); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + burgundy.add_route(0, "lspeaker", 1.0); + burgundy.add_route(1, "rspeaker", 1.0); } ROM_START(imac) diff --git a/src/mame/apple/pippin.cpp b/src/mame/apple/pippin.cpp index 488d2f3749d..db7f54026c9 100644 --- a/src/mame/apple/pippin.cpp +++ b/src/mame/apple/pippin.cpp @@ -52,6 +52,7 @@ #include "machine/ram.h" #include "sound/cdda.h" +#include "awacs_macrisc.h" #include "bandit.h" #include "cuda.h" #include "heathrow.h" @@ -59,15 +60,15 @@ #include "softlist.h" #include "speaker.h" -class macpci_state : public driver_device +class pippin_state : public driver_device { public: void pippin(machine_config &config); - macpci_state(const machine_config &mconfig, device_type type, const char *tag); + pippin_state(const machine_config &mconfig, device_type type, const char *tag); required_device m_maincpu; - required_device m_bandit; + required_device m_aspen; required_device m_cuda; required_device m_macadb; required_device m_ram; @@ -85,29 +86,34 @@ private: m_maincpu->set_input_line(INPUT_LINE_HALT, state); m_maincpu->set_input_line(INPUT_LINE_RESET, state); } + + WRITE_LINE_MEMBER(irq_w) + { + m_maincpu->set_input_line(PPC_IRQ, state); + } }; -macpci_state::macpci_state(const machine_config &mconfig, device_type type, const char *tag) : +pippin_state::pippin_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), - m_bandit(*this, "pci:00.0"), + m_aspen(*this, "pci:00.0"), m_cuda(*this, "cuda"), m_macadb(*this, "macadb"), m_ram(*this, RAM_TAG) { } -void macpci_state::machine_start() +void pippin_state::machine_start() { } -void macpci_state::machine_reset() +void pippin_state::machine_reset() { // the PPC can't run until Cuda's ready m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); } -void macpci_state::pippin_map(address_map &map) +void pippin_state::pippin_map(address_map &map) { map(0x00000000, 0x005fffff).ram(); @@ -118,19 +124,20 @@ void macpci_state::pippin_map(address_map &map) map(0x03c00000, 0x03c01007).ram(); map(0x40000000, 0x403fffff).rom().region("bootrom", 0).mirror(0x0fc00000); // mirror of ROM for 680x0 emulation + map(0x40000000, 0x40000000).lr8(NAME([]() { return 0x80; })); // hack to make flash ROM status check pass (causes 0xe1 to be written to VRAM, which is important later) map(0x5ffffffc, 0x5fffffff).lr32(NAME([](offs_t offset) { return 0xa55a7001; })); - map(0xf00dfff8, 0xf00dffff).lr64(NAME([](offs_t offset) { return (uint64_t)0xe1 << 32; })); // PC=0xfff04810 + map(0xf0000000, 0xf00fffff).ram(); // VRAM map(0xffc00000, 0xffffffff).rom().region("bootrom", 0); } -void macpci_state::cdmcu_mem(address_map &map) +void pippin_state::cdmcu_mem(address_map &map) { map(0x0000, 0xffff).rom().region("cdrom", 0); } -void macpci_state::cdmcu_data(address_map &map) +void pippin_state::cdmcu_data(address_map &map) { map(0x0000, 0x0001).noprw(); map(0x0003, 0x0003).noprw(); @@ -155,14 +162,14 @@ void macpci_state::cdmcu_data(address_map &map) static INPUT_PORTS_START( pippin ) INPUT_PORTS_END -void macpci_state::pippin(machine_config &config) +void pippin_state::pippin(machine_config &config) { /* basic machine hardware */ PPC603(config, m_maincpu, 66000000); - m_maincpu->set_addrmap(AS_PROGRAM, &macpci_state::pippin_map); + m_maincpu->set_addrmap(AS_PROGRAM, &pippin_state::pippin_map); PCI_ROOT(config, "pci", 0); - ASPEN(config, m_bandit, 66000000, "maincpu").set_dev_offset(1); + ASPEN(config, m_aspen, 66000000, "maincpu").set_dev_offset(1); cdrom_image_device &cdrom(CDROM(config, "cdrom", 0)); cdrom.set_interface("pippin_cdrom"); @@ -173,11 +180,24 @@ void macpci_state::pippin(machine_config &config) grandcentral_device &grandcentral(GRAND_CENTRAL(config, "pci:0d.0", 0)); grandcentral.set_maincpu_tag("maincpu"); + grandcentral.set_pci_root_tag(":pci:00.0", AS_DATA); + grandcentral.irq_callback().set(FUNC(pippin_state::irq_w)); + + awacs_macrisc_device &awacs(AWACS_MACRISC(config, "codec", 45.1584_MHz_XTAL / 2)); + awacs.dma_output().set(grandcentral, FUNC(heathrow_device::codec_dma_read)); + + grandcentral.codec_r_callback().set(awacs, FUNC(awacs_macrisc_device::read_macrisc)); + grandcentral.codec_w_callback().set(awacs, FUNC(awacs_macrisc_device::write_macrisc)); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + awacs.add_route(0, "lspeaker", 1.0); + awacs.add_route(1, "rspeaker", 1.0); MACADB(config, m_macadb, 15.6672_MHz_XTAL); CUDA(config, m_cuda, CUDA_341S0060); - m_cuda->reset_callback().set(FUNC(macpci_state::cuda_reset_w)); + m_cuda->reset_callback().set(FUNC(pippin_state::cuda_reset_w)); m_cuda->linechange_callback().set(m_macadb, FUNC(macadb_device::adb_linechange_w)); m_cuda->via_clock_callback().set(grandcentral, FUNC(heathrow_device::cb1_w)); m_cuda->via_data_callback().set(grandcentral, FUNC(heathrow_device::cb2_w)); @@ -190,8 +210,8 @@ void macpci_state::pippin(machine_config &config) grandcentral.cb2_callback().set(m_cuda, FUNC(cuda_device::set_via_data)); mn1880_device &cdmcu(MN1880(config, "cdmcu", 8388608)); // type and clock unknown - cdmcu.set_addrmap(AS_PROGRAM, &macpci_state::cdmcu_mem); - cdmcu.set_addrmap(AS_DATA, &macpci_state::cdmcu_data); + cdmcu.set_addrmap(AS_PROGRAM, &pippin_state::cdmcu_mem); + cdmcu.set_addrmap(AS_DATA, &pippin_state::cdmcu_data); cdmcu.set_disable(); } @@ -235,4 +255,4 @@ ROM_END /* Driver */ /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP( 1996, pippin, 0, 0, pippin, pippin, macpci_state, empty_init, "Apple / Bandai", "Pippin @mark", MACHINE_NOT_WORKING) +COMP( 1996, pippin, 0, 0, pippin, pippin, pippin_state, empty_init, "Apple / Bandai", "Pippin @mark", MACHINE_NOT_WORKING) diff --git a/src/mame/apple/powermacg3.cpp b/src/mame/apple/powermacg3.cpp index 318a59ee856..45564c81941 100644 --- a/src/mame/apple/powermacg3.cpp +++ b/src/mame/apple/powermacg3.cpp @@ -24,6 +24,7 @@ #include "machine/pci.h" #include "machine/pci-ide.h" #include "machine/ram.h" +#include "awacs_macrisc.h" #include "cuda.h" #include "heathrow.h" #include "macadb.h" @@ -53,6 +54,11 @@ private: m_maincpu->set_input_line(INPUT_LINE_HALT, state); m_maincpu->set_input_line(INPUT_LINE_RESET, state); } + + WRITE_LINE_MEMBER(irq_w) + { + m_maincpu->set_input_line(PPC_IRQ, state); + } }; pwrmacg3_state::pwrmacg3_state(const machine_config &mconfig, device_type type, const char *tag) : @@ -123,6 +129,7 @@ void pwrmacg3_state::pwrmacg3(machine_config &config) heathrow_device &heathrow(HEATHROW(config, "pci:10.0", 0)); heathrow.set_maincpu_tag("maincpu"); + heathrow.set_pci_root_tag(":pci:00.0", AS_DATA); MACADB(config, m_macadb, 15.6672_MHz_XTAL); @@ -134,6 +141,7 @@ void pwrmacg3_state::pwrmacg3(machine_config &config) m_macadb->adb_data_callback().set(m_cuda, FUNC(cuda_device::set_adb_line)); config.set_perfect_quantum(m_maincpu); + heathrow.irq_callback().set(FUNC(pwrmacg3_state::irq_w)); heathrow.pb3_callback().set(m_cuda, FUNC(cuda_device::get_treq)); heathrow.pb4_callback().set(m_cuda, FUNC(cuda_device::set_byteack)); heathrow.pb5_callback().set(m_cuda, FUNC(cuda_device::set_tip)); @@ -163,6 +171,17 @@ void pwrmacg3_state::pwrmacg3(machine_config &config) RAM(config, m_ram); m_ram->set_default_size("32M"); m_ram->set_extra_options("32M,64M,96M,128M,256M"); + + screamer_device &screamer(SCREAMER(config, "codec", 45.1584_MHz_XTAL / 2)); + screamer.dma_output().set(heathrow, FUNC(heathrow_device::codec_dma_read)); + + heathrow.codec_r_callback().set(screamer, FUNC(screamer_device::read_macrisc)); + heathrow.codec_w_callback().set(screamer, FUNC(screamer_device::write_macrisc)); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + screamer.add_route(0, "lspeaker", 1.0); + screamer.add_route(1, "rspeaker", 1.0); } /*