summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author Dirk Best <mail@dirk-best.de>2014-05-13 11:46:43 +0000
committer Dirk Best <mail@dirk-best.de>2014-05-13 11:46:43 +0000
commit39e6b343ed946a62e0442bc479f66f6a0497967a (patch)
treefd8071af73eaca4bf6b56149342738491670dbf1 /src/emu
parent8882453f5a3236d20f75227b784e4a1edacd4496 (diff)
parent640354ad9efa2b8c0027c0bce444e652cb593333 (diff)
Merge branch 'master' of ssh://mess.org/mame
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/bus/bus.mak12
-rw-r--r--src/emu/bus/zorro/a590.c346
-rw-r--r--src/emu/bus/zorro/a590.h135
-rw-r--r--src/emu/bus/zorro/action_replay.c150
-rw-r--r--src/emu/bus/zorro/action_replay.h83
-rw-r--r--src/emu/bus/zorro/cards.c31
-rw-r--r--src/emu/bus/zorro/cards.h38
-rw-r--r--src/emu/bus/zorro/zorro.c358
-rw-r--r--src/emu/bus/zorro/zorro.h443
-rw-r--r--src/emu/machine/6525tpi.c6
-rw-r--r--src/emu/machine/6525tpi.h12
-rw-r--r--src/emu/machine/akiko.c925
-rw-r--r--src/emu/machine/akiko.h153
-rw-r--r--src/emu/machine/amigafdc.c7
-rw-r--r--src/emu/machine/autoconfig.c167
-rw-r--r--src/emu/machine/autoconfig.h72
-rw-r--r--src/emu/machine/cr511b.c123
-rw-r--r--src/emu/machine/cr511b.h152
-rw-r--r--src/emu/machine/dmac.c467
-rw-r--r--src/emu/machine/dmac.h173
-rw-r--r--src/emu/machine/machine.mak40
-rw-r--r--src/emu/sound/amiga.c240
-rw-r--r--src/emu/sound/amiga.h63
-rw-r--r--src/emu/sound/sound.mak11
24 files changed, 4203 insertions, 4 deletions
diff --git a/src/emu/bus/bus.mak b/src/emu/bus/bus.mak
index e47605433d8..9067f5bca1d 100644
--- a/src/emu/bus/bus.mak
+++ b/src/emu/bus/bus.mak
@@ -1082,3 +1082,15 @@ BUSOBJS += $(BUSOBJ)/a1bus/a1cassette.o
BUSOBJS += $(BUSOBJ)/a1bus/a1cffa.o
endif
+#-------------------------------------------------
+#
+#@src/emu/bus/zorro/zorro.h,BUSES += ZORRO
+#-------------------------------------------------
+
+ifneq ($(filter ZORRO,$(BUSES)),)
+OBJDIRS += $(BUSOBJ)/zorro
+BUSOBJS += $(BUSOBJ)/zorro/zorro.o
+BUSOBJS += $(BUSOBJ)/zorro/cards.o
+BUSOBJS += $(BUSOBJ)/zorro/a590.o
+BUSOBJS += $(BUSOBJ)/zorro/action_replay.o
+endif
diff --git a/src/emu/bus/zorro/a590.c b/src/emu/bus/zorro/a590.c
new file mode 100644
index 00000000000..d6ca7d12b6b
--- /dev/null
+++ b/src/emu/bus/zorro/a590.c
@@ -0,0 +1,346 @@
+/***************************************************************************
+
+ Commodore A590 / A2091
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ DMAC based HD controller for the Amiga 500 and Zorro-II
+
+***************************************************************************/
+
+#include "a590.h"
+#include "bus/scsi/scsi.h"
+#include "bus/scsi/scsihd.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type A590 = &device_creator<a590_device>;
+const device_type A2091 = &device_creator<a2091_device>;
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+static INPUT_PORTS_START( a590_pcb )
+ PORT_START("dips")
+ PORT_DIPNAME(0x01, 0x01, "A590 Auto-Boot")
+ PORT_DIPLOCATION("DIP:1")
+ PORT_DIPSETTING(0x00, "Enabled")
+ PORT_DIPSETTING(0x01, "Disabled")
+ PORT_DIPNAME(0x02, 0x00, "A590 LUN")
+ PORT_DIPLOCATION("DIP:2")
+ PORT_DIPSETTING(0x00, "Disabled")
+ PORT_DIPSETTING(0x02, "Enabled")
+ PORT_DIPNAME(0x04, 0x04, "A590 Wait period")
+ PORT_DIPLOCATION("DIP:3")
+ PORT_DIPSETTING(0x00, "Short")
+ PORT_DIPSETTING(0x04, "Long")
+ PORT_DIPNAME(0x08, 0x00, "A590 Reserved")
+ PORT_DIPLOCATION("DIP:4")
+ PORT_DIPSETTING(0x00, "Enabled")
+ PORT_DIPSETTING(0x08, "Disabled")
+ PORT_START("jp1")
+ PORT_DIPNAME(0x0f, 0x01, "A590 Memory size")
+ PORT_DIPLOCATION("JP1:1,2,3,4")
+ PORT_DIPSETTING(0x01, "Amnesia")
+ PORT_DIPSETTING(0x02, "512K")
+ PORT_DIPSETTING(0x04, "1MB")
+ PORT_DIPSETTING(0x08, "2MB")
+ PORT_START("jp2")
+ PORT_DIPNAME(0x01, 0x00, "A590 Drive LED")
+ PORT_DIPLOCATION("JP2:1")
+ PORT_DIPSETTING(0x00, "XT Drive")
+ PORT_DIPSETTING(0x01, "SCSI Drive")
+ PORT_START("jp4")
+ PORT_DIPNAME(0x01, 0x00, "A590 Interrupt")
+ PORT_DIPLOCATION("JP4:1")
+ PORT_DIPSETTING(0x00, "INT 2")
+ PORT_DIPSETTING(0x01, "INT 6")
+INPUT_PORTS_END
+
+ioport_constructor a590_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( a590_pcb );
+}
+
+static INPUT_PORTS_START( a2091_pcb )
+ PORT_START("jp1")
+ PORT_DIPNAME(0x0f, 0x01, "A2091 Memory size")
+ PORT_DIPLOCATION("JP1:1,2,3,4")
+ PORT_DIPSETTING(0x01, "0K")
+ PORT_DIPSETTING(0x02, "512K")
+ PORT_DIPSETTING(0x04, "1MB")
+ PORT_DIPSETTING(0x08, "2MB")
+ PORT_START("jp2")
+ PORT_DIPNAME(0x01, 0x00, "A2091 Auto-Boot")
+ PORT_DIPLOCATION("JP2:1")
+ PORT_DIPSETTING(0x00, "Enabled")
+ PORT_DIPSETTING(0x01, "Disabled")
+ PORT_START("jp3")
+ PORT_DIPNAME(0x01, 0x00, "A2091 Interrupt")
+ PORT_DIPLOCATION("JP3:1")
+ PORT_DIPSETTING(0x00, "INT 2")
+ PORT_DIPSETTING(0x01, "INT 6")
+ PORT_START("jp5")
+ PORT_DIPNAME(0x01, 0x00, "A2091 LUN")
+ PORT_DIPLOCATION("JP5:1")
+ PORT_DIPSETTING(0x00, "Disabled")
+ PORT_DIPSETTING(0x01, "Enabled")
+ PORT_DIPNAME(0x02, 0x00, "A2091 Time-Out")
+ PORT_DIPLOCATION("JP5:2")
+ PORT_DIPSETTING(0x00, "Short")
+ PORT_DIPSETTING(0x02, "Long")
+ PORT_DIPNAME(0x04, 0x00, "A2091 Reserved")
+ PORT_DIPLOCATION("JP5:3")
+ PORT_DIPSETTING(0x00, "Disabled")
+ PORT_DIPSETTING(0x02, "Enabled")
+ PORT_START("jp201")
+ PORT_DIPNAME(0x01, 0x00, "A2091 WD33C93 Clock")
+ PORT_DIPLOCATION("JP201:1")
+ PORT_DIPSETTING(0x00, "7 MHz")
+ PORT_DIPSETTING(0x01, "14 MHz")
+INPUT_PORTS_END
+
+ioport_constructor a2091_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( a2091_pcb );
+}
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( dmac_hdc )
+ MCFG_DMAC_ADD("dmac", 0)
+ MCFG_DMAC_SCSI_READ_HANDLER(READ8(dmac_hdc_device, dmac_scsi_r))
+ MCFG_DMAC_SCSI_WRITE_HANDLER(WRITE8(dmac_hdc_device, dmac_scsi_w))
+ MCFG_DMAC_INT_HANDLER(WRITELINE(dmac_hdc_device, dmac_int_w))
+ MCFG_DMAC_CFGOUT_HANDLER(WRITELINE(dmac_hdc_device, dmac_cfgout_w))
+ MCFG_DEVICE_ADD("scsi", SCSI_PORT, 0)
+ MCFG_SCSIDEV_ADD("scsi:" SCSI_PORT_DEVICE1, "harddisk", SCSIHD, SCSI_ID_1)
+ MCFG_DEVICE_ADD("scsi:wd33c93", WD33C93, 0)
+ MCFG_LEGACY_SCSI_PORT("scsi")
+ MCFG_WD33C93_IRQ_CB(DEVWRITELINE("^^", dmac_hdc_device, scsi_irq_w))
+MACHINE_CONFIG_END
+
+machine_config_constructor dmac_hdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( dmac_hdc );
+}
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( dmac_hdc )
+ ROM_REGION16_BE(0x8000, "bootrom", 0)
+ ROM_DEFAULT_BIOS("v70")
+
+ ROM_SYSTEM_BIOS(0, "v60", "Version 6.0")
+ ROMX_LOAD("390388-03.u13", 0x0000, 0x2000, CRC(2e77bbff) SHA1(8a098845068f32cfa4d34a278cd290f61d35a52c), ROM_SKIP(1) | ROM_BIOS(1))
+ ROMX_LOAD("390389-03.u12", 0x0001, 0x2000, CRC(b0b8cf24) SHA1(fcf4017505f4d441814b45d559c19eab43816b30), ROM_SKIP(1) | ROM_BIOS(1))
+ ROMX_LOAD("390388-03.u13", 0x4000, 0x2000, CRC(2e77bbff) SHA1(8a098845068f32cfa4d34a278cd290f61d35a52c), ROM_SKIP(1) | ROM_BIOS(1))
+ ROMX_LOAD("390389-03.u12", 0x4001, 0x2000, CRC(b0b8cf24) SHA1(fcf4017505f4d441814b45d559c19eab43816b30), ROM_SKIP(1) | ROM_BIOS(1))
+
+ // changelog v6.1: prevent accesses to location 0 by application programs
+ ROM_SYSTEM_BIOS(1, "v61", "Version 6.1")
+ ROMX_LOAD("390721-01.u13", 0x0000, 0x2000, NO_DUMP, ROM_SKIP(1) | ROM_BIOS(2))
+ ROMX_LOAD("390722-01.u12", 0x0001, 0x2000, NO_DUMP, ROM_SKIP(1) | ROM_BIOS(2))
+ ROMX_LOAD("390721-01.u13", 0x4000, 0x2000, NO_DUMP, ROM_SKIP(1) | ROM_BIOS(2))
+ ROMX_LOAD("390722-01.u12", 0x4001, 0x2000, NO_DUMP, ROM_SKIP(1) | ROM_BIOS(2))
+
+ // changelog v6.6: fixes dual scsi problems with the wd33c93a controller
+ ROM_SYSTEM_BIOS(2, "v66", "Version 6.6")
+ ROMX_LOAD("390721-02.u13", 0x0000, 0x2000, CRC(c0871d25) SHA1(e155f18abb90cf820589c15e70559d3b6b391af8), ROM_SKIP(1) | ROM_BIOS(3))
+ ROMX_LOAD("390722-02.u12", 0x0001, 0x2000, CRC(e536bbb2) SHA1(fd7f8a6da18c1b02d07eb990c2467a24183ede12), ROM_SKIP(1) | ROM_BIOS(3))
+ ROMX_LOAD("390721-02.u13", 0x4000, 0x2000, CRC(c0871d25) SHA1(e155f18abb90cf820589c15e70559d3b6b391af8), ROM_SKIP(1) | ROM_BIOS(3))
+ ROMX_LOAD("390722-02.u12", 0x4001, 0x2000, CRC(e536bbb2) SHA1(fd7f8a6da18c1b02d07eb990c2467a24183ede12), ROM_SKIP(1) | ROM_BIOS(3))
+
+ // final commodore released version
+ ROM_SYSTEM_BIOS(3, "v70", "Version 7.0")
+ ROMX_LOAD("390721-03.u13", 0x0000, 0x2000, CRC(2942747a) SHA1(dbd7648e79c753337ff3e4f491de224bf05e6bb6), ROM_SKIP(1) | ROM_BIOS(4))
+ ROMX_LOAD("390722-03.u12", 0x0001, 0x2000, CRC(a9ccffed) SHA1(149f5bd52e2d29904e3de483b9ad772448e9278e), ROM_SKIP(1) | ROM_BIOS(4))
+ ROMX_LOAD("390721-03.u13", 0x4000, 0x2000, CRC(2942747a) SHA1(dbd7648e79c753337ff3e4f491de224bf05e6bb6), ROM_SKIP(1) | ROM_BIOS(4))
+ ROMX_LOAD("390722-03.u12", 0x4001, 0x2000, CRC(a9ccffed) SHA1(149f5bd52e2d29904e3de483b9ad772448e9278e), ROM_SKIP(1) | ROM_BIOS(4))
+
+ // third-party upgrade rom, requires a small rom adapter pcb
+ ROM_SYSTEM_BIOS(4, "g614", "Guru-ROM 6.14")
+ ROMX_LOAD("gururom_v614.bin", 0x0000, 0x8000, CRC(04e52f93) SHA1(6da21b6f5e8f8837d64507cd8a4d5cdcac4f426b), ROM_GROUPWORD | ROM_BIOS(5))
+ROM_END
+
+const rom_entry *dmac_hdc_device::device_rom_region() const
+{
+ return ROM_NAME( dmac_hdc );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// dmac_hdc_device - constructor
+//-------------------------------------------------
+
+dmac_hdc_device::dmac_hdc_device(const machine_config &mconfig, device_type type, const char *tag,
+ device_t *owner, UINT32 clock, const char *name, const char *shortname) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__),
+ m_int6(false),
+ m_dmac(*this, "dmac"),
+ m_wdc(*this, "scsi:wd33c93")
+{
+}
+
+a590_device::a590_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ dmac_hdc_device(mconfig, A590, tag, owner, clock, "CBM A590 HD Controller", "a590"),
+ device_exp_card_interface(mconfig, *this),
+ m_dips(*this, "dips"),
+ m_jp1(*this, "jp1"),
+ m_jp2(*this, "jp2"),
+ m_jp4(*this, "jp4")
+{
+}
+
+a2091_device::a2091_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ dmac_hdc_device(mconfig, A2091, tag, owner, clock, "CBM A2091 HD Controller", "a2091"),
+ device_zorro2_card_interface(mconfig, *this),
+ m_jp1(*this, "jp1"),
+ m_jp2(*this, "jp2"),
+ m_jp3(*this, "jp3"),
+ m_jp5(*this, "jp5"),
+ m_jp201(*this, "jp201")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void dmac_hdc_device::device_start()
+{
+}
+
+void a590_device::device_start()
+{
+ set_zorro_device();
+
+ // setup dmac
+ m_dmac->set_address_space(m_slot->m_space);
+ m_dmac->set_rom(memregion("bootrom")->base());
+}
+
+void a2091_device::device_start()
+{
+ set_zorro_device();
+
+ // setup dmac
+ m_dmac->set_address_space(m_slot->m_space);
+ m_dmac->set_rom(memregion("bootrom")->base());
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void dmac_hdc_device::device_reset()
+{
+}
+
+void dmac_hdc_device::resize_ram(int config)
+{
+ // allocate space for ram
+ switch (config & 0x0f)
+ {
+ case 0x01:
+ m_ram.resize(0);
+ m_dmac->ramsz_w(0);
+ break;
+ case 0x02:
+ m_ram.resize(0x080000);
+ m_dmac->ramsz_w(1);
+ break;
+ case 0x04:
+ m_ram.resize(0x100000);
+ m_dmac->ramsz_w(2);
+ break;
+ case 0x08:
+ m_ram.resize(0x200000);
+ m_dmac->ramsz_w(3);
+ break;
+ }
+
+ m_dmac->set_ram(m_ram);
+}
+
+void a590_device::device_reset()
+{
+}
+
+void a2091_device::device_reset()
+{
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+WRITE_LINE_MEMBER( a590_device::cfgin_w )
+{
+ // make sure we configure ourselves first
+ m_int6 = m_jp4->read() & 0x01;
+ resize_ram(m_dips->read() & 0x0f);
+
+ // then tell the dmac to start configuring
+ m_dmac->configin_w(state);
+}
+
+WRITE_LINE_MEMBER( a2091_device::cfgin_w )
+{
+ // make sure we configure ourselves first
+ m_int6 = m_jp3->read() & 0x01;
+ resize_ram(m_jp1->read() & 0x0f);
+
+ // then tell the dmac to start configuring
+ m_dmac->configin_w(state);
+}
+
+READ8_MEMBER( dmac_hdc_device::dmac_scsi_r )
+{
+ switch (offset)
+ {
+ case 0x48: return m_wdc->read(space, 0);
+ case 0x49: return m_wdc->read(space, 1);
+ }
+
+ return 0xff;
+}
+
+WRITE8_MEMBER( dmac_hdc_device::dmac_scsi_w )
+{
+ switch (offset)
+ {
+ case 0x48: m_wdc->write(space, 0, data); break;
+ case 0x49: m_wdc->write(space, 1, data); break;
+ }
+}
+
+WRITE_LINE_MEMBER( dmac_hdc_device::dmac_int_w )
+{
+ if (m_int6)
+ int6_w(state);
+ else
+ int2_w(state);
+}
+
+WRITE_LINE_MEMBER( dmac_hdc_device::scsi_irq_w )
+{
+ // should be or'ed with xt-ide irq
+ m_dmac->intx_w(state);
+}
diff --git a/src/emu/bus/zorro/a590.h b/src/emu/bus/zorro/a590.h
new file mode 100644
index 00000000000..4682c72903f
--- /dev/null
+++ b/src/emu/bus/zorro/a590.h
@@ -0,0 +1,135 @@
+/***************************************************************************
+
+ Commodore A590 / A2091
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ DMAC based SCSI controller for the Amiga 500 and Zorro-II
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __A590_H__
+#define __A590_H__
+
+#include "emu.h"
+#include "zorro.h"
+#include "machine/dmac.h"
+#include "machine/wd33c93.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> dmac_hdc_device
+
+class dmac_hdc_device : public device_t
+{
+public:
+ // construction/destruction
+ dmac_hdc_device(const machine_config &mconfig, device_type type, const char *tag,
+ device_t *owner, UINT32 clock, const char *name, const char *shortname);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER( dmac_scsi_r );
+ DECLARE_WRITE8_MEMBER( dmac_scsi_w );
+ DECLARE_WRITE_LINE_MEMBER( dmac_int_w );
+ DECLARE_WRITE_LINE_MEMBER( dmac_cfgout_w ) { cfgout_w(state); }
+ DECLARE_WRITE_LINE_MEMBER( scsi_irq_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // to slot
+ virtual void cfgout_w(int state) = 0;
+ virtual void int2_w(int state) = 0;
+ virtual void int6_w(int state) = 0;
+
+ // should be called when the ram size changes
+ void resize_ram(int config);
+
+ // amiga interrupt target, int 2 or 6
+ bool m_int6;
+
+ // sub-devices
+ required_device<dmac_device> m_dmac;
+ required_device<wd33c93_device> m_wdc;
+
+ dynamic_buffer m_ram;
+};
+
+// ======================> a590_device
+
+class a590_device : public dmac_hdc_device, public device_exp_card_interface
+{
+public:
+ // construction/destruction
+ a590_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+
+ // output to slot
+ virtual void cfgout_w(int state) { m_slot->cfgout_w(state); }
+ virtual void int2_w(int state) { m_slot->int2_w(state); }
+ virtual void int6_w(int state) { m_slot->int6_w(state); }
+
+ // input from slot
+ virtual DECLARE_WRITE_LINE_MEMBER( cfgin_w );
+
+private:
+ required_ioport m_dips;
+ required_ioport m_jp1;
+ required_ioport m_jp2;
+ required_ioport m_jp4;
+};
+
+// ======================> a2091_device
+
+class a2091_device : public dmac_hdc_device, public device_zorro2_card_interface
+{
+public:
+ // construction/destruction
+ a2091_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+
+ // output to slot
+ virtual void cfgout_w(int state) { m_slot->cfgout_w(state); }
+ virtual void int2_w(int state) { m_slot->int2_w(state); }
+ virtual void int6_w(int state) { m_slot->int6_w(state); }
+
+ // input from slot
+ virtual DECLARE_WRITE_LINE_MEMBER( cfgin_w );
+
+private:
+ required_ioport m_jp1;
+ required_ioport m_jp2;
+ required_ioport m_jp3;
+ required_ioport m_jp5;
+ required_ioport m_jp201;
+};
+
+// device type definition
+extern const device_type A590;
+extern const device_type A2091;
+
+#endif
diff --git a/src/emu/bus/zorro/action_replay.c b/src/emu/bus/zorro/action_replay.c
new file mode 100644
index 00000000000..890e0081373
--- /dev/null
+++ b/src/emu/bus/zorro/action_replay.c
@@ -0,0 +1,150 @@
+/***************************************************************************
+
+ Datel Action Replay
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ Freezer cartridge for Amiga 500 and Amiga 2000
+
+ Skeleton device, just loads the ROMs and generates the NMI
+ for now.
+
+ Hardware notes:
+ - http://www.mways.co.uk/amiga/howtocode/text/actionreplay.php
+
+***************************************************************************/
+
+#include "action_replay.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ACTION_REPLAY_MK1 = &device_creator<action_replay_mk1_device>;
+const device_type ACTION_REPLAY_MK2 = &device_creator<action_replay_mk2_device>;
+const device_type ACTION_REPLAY_MK3 = &device_creator<action_replay_mk3_device>;
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+static INPUT_PORTS_START( ar_button )
+ PORT_START("freeze")
+ PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Freeze") PORT_CODE(KEYCODE_F12) PORT_CHANGED_MEMBER(DEVICE_SELF, action_replay_device, freeze, 0)
+INPUT_PORTS_END
+
+ioport_constructor action_replay_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( ar_button );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( ar_mk1 )
+ ROM_REGION(0x10000, "firmware", 0)
+ ROM_DEFAULT_BIOS("v150")
+ ROM_SYSTEM_BIOS(0, "v100", "Version 1.00")
+ ROMX_LOAD("ar1_v100.bin", 0x0000, 0x10000, BAD_DUMP CRC(2d921771) SHA1(1ead9dda2dad29146441f5ef7218375022e01248), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(1, "v150", "Version 1.50")
+ ROMX_LOAD("ar1_v150.bin", 0x0000, 0x10000, BAD_DUMP CRC(f82c4258) SHA1(843b433b2c56640e045d5fdc854dc6b1a4964e7c), ROM_BIOS(2))
+ROM_END
+
+const rom_entry *action_replay_mk1_device::device_rom_region() const
+{
+ return ROM_NAME( ar_mk1 );
+}
+
+ROM_START( ar_mk2 )
+ ROM_REGION(0x20000, "firmware", 0)
+ ROM_DEFAULT_BIOS("v214")
+ ROM_SYSTEM_BIOS(0, "v205", "Version 2.05")
+ ROMX_LOAD("ar2_v205.bin", 0x0000, 0x20000, BAD_DUMP CRC(4051eef8) SHA1(9df22b1d3285b522c223697c83d144d04e961a4a), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(1, "v212", "Version 2.12")
+ ROMX_LOAD("ar2_v212.bin", 0x0000, 0x20000, BAD_DUMP CRC(d29bdd86) SHA1(76c2900457badf22b742f0af48b78937e8b67694), ROM_BIOS(2))
+ ROM_SYSTEM_BIOS(2, "v214", "Version 2.14")
+ ROMX_LOAD("ar2_v214.bin", 0x0000, 0x20000, BAD_DUMP CRC(1bb3d0a8) SHA1(14b1f5a69efb6f4e2331970e6ca0f33c0f04ac91), ROM_BIOS(3))
+ROM_END
+
+const rom_entry *action_replay_mk2_device::device_rom_region() const
+{
+ return ROM_NAME( ar_mk2 );
+}
+
+ROM_START( ar_mk3 )
+ ROM_REGION(0x40000, "firmware", 0)
+ ROM_DEFAULT_BIOS("v309")
+ ROM_SYSTEM_BIOS(0, "v309", "Version 3.09")
+ ROMX_LOAD("ar3_v309.evn", 0x00000, 0x20000, CRC(2b84519f) SHA1(7841873bf009d8341dfa2794b3751bacf86adcc8), ROM_SKIP(1) | ROM_BIOS(1))
+ ROMX_LOAD("ar3_v309.odd", 0x00001, 0x20000, CRC(1d35bd56) SHA1(6464be1626b519499e76e4e3409e8016515d48b6), ROM_SKIP(1) | ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(1, "v317", "Version 3.17")
+ ROMX_LOAD("ar3_v314.bin", 0x0000, 0x40000, BAD_DUMP CRC(009f7768) SHA1(0439d6ccc2a0e5c2e83fcf2389dc4d4a440a4c62), ROM_BIOS(2))
+ROM_END
+
+const rom_entry *action_replay_mk3_device::device_rom_region() const
+{
+ return ROM_NAME( ar_mk3 );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// action_replay_device - constructor
+//-------------------------------------------------
+
+action_replay_device::action_replay_device(const machine_config &mconfig, device_type type, const char *tag,
+ device_t *owner, UINT32 clock, const char *name, const char *shortname) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__),
+ device_exp_card_interface(mconfig, *this),
+ m_button(*this, "freeze")
+{
+}
+
+action_replay_mk1_device::action_replay_mk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ action_replay_device(mconfig, ACTION_REPLAY_MK1, tag, owner, clock, "Datel Action Replay MK-I", "amiga_ar1")
+{
+}
+
+action_replay_mk2_device::action_replay_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ action_replay_device(mconfig, ACTION_REPLAY_MK1, tag, owner, clock, "Datel Action Replay MK-II", "amiga_ar2")
+{
+}
+
+action_replay_mk3_device::action_replay_mk3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ action_replay_device(mconfig, ACTION_REPLAY_MK1, tag, owner, clock, "Datel Action Replay MK-III", "amiga_ar3")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void action_replay_device::device_start()
+{
+ set_zorro_device();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void action_replay_device::device_reset()
+{
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+INPUT_CHANGED_MEMBER( action_replay_device::freeze )
+{
+ // pushing the freeze button generates an nmi
+ m_slot->ipl_w(newval == 1 ? 7 : 0);
+}
diff --git a/src/emu/bus/zorro/action_replay.h b/src/emu/bus/zorro/action_replay.h
new file mode 100644
index 00000000000..f2520575fb7
--- /dev/null
+++ b/src/emu/bus/zorro/action_replay.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+
+ Datel Action Replay
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ Freezer cartridge for Amiga 500 and Amiga 2000
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __ACTION_REPLAY_H__
+#define __ACTION_REPLAY_H__
+
+#include "emu.h"
+#include "zorro.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> action_replay_device
+
+class action_replay_device : public device_t, public device_exp_card_interface
+{
+public:
+ // construction/destruction
+ action_replay_device(const machine_config &mconfig, device_type type, const char *tag,
+ device_t *owner, UINT32 clock, const char *name, const char *shortname);
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+
+ DECLARE_INPUT_CHANGED_MEMBER( freeze );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ required_ioport m_button;
+};
+
+class action_replay_mk1_device : public action_replay_device
+{
+public:
+ // construction/destruction
+ action_replay_mk1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+};
+
+class action_replay_mk2_device : public action_replay_device
+{
+public:
+ // construction/destruction
+ action_replay_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+};
+
+class action_replay_mk3_device : public action_replay_device
+{
+public:
+ // construction/destruction
+ action_replay_mk3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+};
+
+// device type definition
+extern const device_type ACTION_REPLAY_MK1;
+extern const device_type ACTION_REPLAY_MK2;
+extern const device_type ACTION_REPLAY_MK3;
+
+#endif
diff --git a/src/emu/bus/zorro/cards.c b/src/emu/bus/zorro/cards.c
new file mode 100644
index 00000000000..68af08c60a5
--- /dev/null
+++ b/src/emu/bus/zorro/cards.c
@@ -0,0 +1,31 @@
+/***************************************************************************
+
+ Amiga Zorro Cards
+
+***************************************************************************/
+
+#include "cards.h"
+
+SLOT_INTERFACE_START( a1000_expansion_cards )
+SLOT_INTERFACE_END
+
+SLOT_INTERFACE_START( a500_expansion_cards )
+ SLOT_INTERFACE("ar1", ACTION_REPLAY_MK1)
+ SLOT_INTERFACE("ar2", ACTION_REPLAY_MK2)
+ SLOT_INTERFACE("ar3", ACTION_REPLAY_MK3)
+ SLOT_INTERFACE("a590", A590)
+SLOT_INTERFACE_END
+
+SLOT_INTERFACE_START( a2000_expansion_cards )
+ SLOT_INTERFACE("ar1", ACTION_REPLAY_MK1)
+ SLOT_INTERFACE("ar2", ACTION_REPLAY_MK2)
+ SLOT_INTERFACE("ar3", ACTION_REPLAY_MK3)
+SLOT_INTERFACE_END
+
+SLOT_INTERFACE_START( zorro2_cards )
+ SLOT_INTERFACE("a2091", A2091)
+SLOT_INTERFACE_END
+
+SLOT_INTERFACE_START( zorro3_cards )
+ SLOT_INTERFACE("a2091", A2091)
+SLOT_INTERFACE_END
diff --git a/src/emu/bus/zorro/cards.h b/src/emu/bus/zorro/cards.h
new file mode 100644
index 00000000000..6c34f9394fb
--- /dev/null
+++ b/src/emu/bus/zorro/cards.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+
+ Amiga Zorro Cards
+
+ There are different card types and layouts:
+
+ * 86-pin expansion slot
+ - A1000
+ - A500 (rotated slot)
+ - A2000/B2000 (internal slot)
+ * Zorro-II
+ - A2000
+ - B2000
+ * Zorro-III
+ - A3000, A4000
+
+ For details see zorro.h. Zorro-II cards can be inserted into
+ Zorro-III slots.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CARDS_H__
+#define __CARDS_H__
+
+#include "emu.h"
+#include "a590.h"
+#include "action_replay.h"
+
+SLOT_INTERFACE_EXTERN( a1000_expansion_cards );
+SLOT_INTERFACE_EXTERN( a500_expansion_cards );
+SLOT_INTERFACE_EXTERN( a2000_expansion_cards );
+
+SLOT_INTERFACE_EXTERN( zorro2_cards );
+SLOT_INTERFACE_EXTERN( zorro3_cards );
+
+#endif // __CARDS_H__
diff --git a/src/emu/bus/zorro/zorro.c b/src/emu/bus/zorro/zorro.c
new file mode 100644
index 00000000000..91918c2ffea
--- /dev/null
+++ b/src/emu/bus/zorro/zorro.c
@@ -0,0 +1,358 @@
+/***************************************************************************
+
+ Amiga Zorro Slots
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ 86-pin Expansion Slot (Zorro-I), Zorro-II, Zorro-III
+
+***************************************************************************/
+
+#include "zorro.h"
+
+
+//**************************************************************************
+// ZORRO SLOT DEVICE
+//**************************************************************************
+
+const device_type ZORRO_SLOT = &device_creator<zorro_slot_device>;
+
+//-------------------------------------------------
+// zorro_slot_device - constructor
+//-------------------------------------------------
+
+zorro_slot_device::zorro_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ZORRO_SLOT, "Zorro slot", tag, owner, clock, "zorro_slot", __FILE__),
+ device_slot_interface(mconfig, *this),
+ m_zorro_tag(NULL)
+{
+}
+
+zorro_slot_device::zorro_slot_device(const machine_config &mconfig, device_type type, const char *name,
+ const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_slot_interface(mconfig, *this),
+ m_zorro_tag(NULL)
+{
+}
+
+void zorro_slot_device::set_zorro_slot(device_t &device, device_t *owner, const char *zorro_tag)
+{
+ zorro_slot_device &zorro_card = dynamic_cast<zorro_slot_device &>(device);
+ zorro_card.m_owner = owner;
+ zorro_card.m_zorro_tag = zorro_tag;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void zorro_slot_device::device_start()
+{
+ device_zorro_card_interface *dev = dynamic_cast<device_zorro_card_interface *>(get_card_device());
+
+ if (dev)
+ {
+ zorro_device *m_zorro_bus = downcast<zorro_device *>(m_owner->subdevice(m_zorro_tag));
+ m_zorro_bus->add_card(dev);
+ }
+}
+
+
+//**************************************************************************
+// BASE ZORRO BUS DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// exp_slot_device - constructor
+//-------------------------------------------------
+
+zorro_device::zorro_device(const machine_config &mconfig, device_type type, const char *name,
+ const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_space(NULL),
+ m_cputag(NULL),
+ m_ovr_handler(*this),
+ m_int2_handler(*this),
+ m_int6_handler(*this)
+{
+}
+
+//-------------------------------------------------
+// set_cputag - set cpu we are attached to
+//-------------------------------------------------
+
+void zorro_device::set_cputag(device_t &device, const char *tag)
+{
+ zorro_device &zorro = downcast<zorro_device &>(device);
+ zorro.m_cputag = tag;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void zorro_device::device_start()
+{
+ // get address space
+ device_t *cpu = machine().device(m_cputag);
+ m_space = &cpu->memory().space(AS_PROGRAM);
+
+ // resolve callbacks
+ m_ovr_handler.resolve_safe();
+ m_int2_handler.resolve_safe();
+ m_int6_handler.resolve_safe();
+}
+
+// from slot device
+WRITE_LINE_MEMBER( zorro_device::ovr_w ) { m_ovr_handler(state); }
+WRITE_LINE_MEMBER( zorro_device::int2_w ) { m_int2_handler(state); }
+WRITE_LINE_MEMBER( zorro_device::int6_w ) { m_int6_handler(state); }
+
+
+//**************************************************************************
+// EXPANSION SLOT DEVICE
+//**************************************************************************
+
+const device_type EXP_SLOT = &device_creator<exp_slot_device>;
+
+//-------------------------------------------------
+// exp_slot_device - constructor
+//-------------------------------------------------
+
+exp_slot_device::exp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ zorro_device(mconfig, EXP_SLOT, "86-pin expansion slot", tag, owner, clock, "exp_slot", __FILE__),
+ m_ipl_handler(*this),
+ m_dev(NULL)
+{
+}
+
+exp_slot_device::exp_slot_device(const machine_config &mconfig, device_type type, const char *name,
+ const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ zorro_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_ipl_handler(*this),
+ m_dev(NULL)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void exp_slot_device::device_start()
+{
+ // resolve callbacks
+ m_ipl_handler.resolve_safe();
+
+ // call base device start
+ zorro_device::device_start();
+}
+
+//-------------------------------------------------
+// add_card - add new card to our bus
+//-------------------------------------------------
+
+void exp_slot_device::add_card(device_zorro_card_interface *card)
+{
+ m_dev = downcast<device_exp_card_interface *>(card);
+}
+
+// from slot device
+void exp_slot_device::ipl_w(int interrupt) { m_ipl_handler(0, interrupt, 0xff); }
+
+// from host
+void exp_slot_device::fc_w(int code) { if (m_dev) m_dev->fc_w(code); }
+
+
+//**************************************************************************
+// ZORRO2 DEVICE
+//**************************************************************************
+
+const device_type ZORRO2 = &device_creator<zorro2_device>;
+
+//-------------------------------------------------
+// zorro2_device - constructor
+//-------------------------------------------------
+
+zorro2_device::zorro2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ zorro_device(mconfig, ZORRO2, "Zorro-II bus", tag, owner, clock, "zorro2", __FILE__),
+ m_eint1_handler(*this),
+ m_eint4_handler(*this),
+ m_eint5_handler(*this),
+ m_eint7_handler(*this),
+ m_autoconfig_device(NULL)
+{
+}
+
+zorro2_device::zorro2_device(const machine_config &mconfig, device_type type, const char *name,
+ const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ zorro_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_eint1_handler(*this),
+ m_eint4_handler(*this),
+ m_eint5_handler(*this),
+ m_eint7_handler(*this),
+ m_autoconfig_device(NULL)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void zorro2_device::device_start()
+{
+ // resolve callbacks
+ m_eint1_handler.resolve_safe();
+ m_eint4_handler.resolve_safe();
+ m_eint5_handler.resolve_safe();
+ m_eint7_handler.resolve_safe();
+
+ // call base device start
+ zorro_device::device_start();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void zorro2_device::device_reset()
+{
+ // initiate autoconfig
+ m_autoconfig_device = m_dev.first();
+
+ // if we have a device, start the autoconfig chain
+ if (m_autoconfig_device)
+ m_autoconfig_device->cfgin_w(0);
+}
+
+//-------------------------------------------------
+// add_card - add new card to our bus
+//-------------------------------------------------
+
+void zorro2_device::add_card(device_zorro_card_interface *card)
+{
+ device_zorro2_card_interface *zorro2_card = downcast<device_zorro2_card_interface *>(card);
+ card->set_zorro_bus(this);
+ m_dev.append(*zorro2_card);
+}
+
+// from slot device
+WRITE_LINE_MEMBER( zorro2_device::eint1_w ) { m_eint1_handler(state); }
+WRITE_LINE_MEMBER( zorro2_device::eint4_w ) { m_eint4_handler(state); }
+WRITE_LINE_MEMBER( zorro2_device::eint5_w ) { m_eint5_handler(state); }
+WRITE_LINE_MEMBER( zorro2_device::eint7_w ) { m_eint7_handler(state); }
+
+WRITE_LINE_MEMBER( zorro2_device::cfgout_w )
+{
+ m_autoconfig_device = m_autoconfig_device->next();
+
+ // if there is still a device in the chain, tell it to configure itself
+ if (m_autoconfig_device)
+ m_autoconfig_device->cfgin_w(0);
+}
+
+// from host
+void zorro2_device::fc_w(int code)
+{
+ device_zorro2_card_interface *entry = m_dev.first();
+
+ while (entry)
+ {
+ entry->fc_w(code);
+ entry = entry->next();
+ }
+}
+
+
+//**************************************************************************
+// ZORRO INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_zorro_card_interface - constructor
+//-------------------------------------------------
+
+device_zorro_card_interface::device_zorro_card_interface(const machine_config &mconfig, device_t &device) :
+ device_slot_card_interface(mconfig, device),
+ m_zorro(NULL)
+{
+}
+
+//-------------------------------------------------
+// ~device_zorro_card_interface - destructor
+//-------------------------------------------------
+
+device_zorro_card_interface::~device_zorro_card_interface()
+{
+}
+
+void device_zorro_card_interface::set_zorro_bus(zorro_device *device)
+{
+ m_zorro = device;
+}
+
+void device_zorro_card_interface::fc_w(int code)
+{
+}
+
+WRITE_LINE_MEMBER( device_zorro_card_interface::cfgin_w )
+{
+}
+
+
+//**************************************************************************
+// EXPANSION CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_exp_card_interface - constructor
+//-------------------------------------------------
+
+device_exp_card_interface::device_exp_card_interface(const machine_config &mconfig, device_t &device) :
+ device_zorro_card_interface(mconfig, device),
+ m_slot(NULL)
+{
+}
+
+//-------------------------------------------------
+// ~device_exp_card_interface - destructor
+//-------------------------------------------------
+
+device_exp_card_interface::~device_exp_card_interface()
+{
+}
+
+void device_exp_card_interface::set_zorro_device()
+{
+ m_slot = dynamic_cast<exp_slot_device *>(m_zorro);
+}
+
+
+//**************************************************************************
+// ZORRO-II CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_zorro2_interface - constructor
+//-------------------------------------------------
+
+device_zorro2_card_interface::device_zorro2_card_interface(const machine_config &mconfig, device_t &device) :
+ device_zorro_card_interface(mconfig, device),
+ m_next(NULL),
+ m_slot(NULL)
+{
+}
+
+//-------------------------------------------------
+// ~device_zorro2_interface - destructor
+//-------------------------------------------------
+
+device_zorro2_card_interface::~device_zorro2_card_interface()
+{
+}
+
+void device_zorro2_card_interface::set_zorro_device()
+{
+ m_slot = dynamic_cast<zorro2_device *>(m_zorro);
+}
diff --git a/src/emu/bus/zorro/zorro.h b/src/emu/bus/zorro/zorro.h
new file mode 100644
index 00000000000..d018b217374
--- /dev/null
+++ b/src/emu/bus/zorro/zorro.h
@@ -0,0 +1,443 @@
+/***************************************************************************
+
+ Amiga Zorro Slots
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ 86-pin Expansion Slot (Zorro-I), Zorro-II, Zorro-III
+
+ 86-pin Expansion Slot
+
+ 2 Ground 1 Ground
+ 4 Ground 3 Ground
+ 6 +5VDC 5 +5VDC
+ 8 -5VDC 7 N/C
+ 10 +12VDC 9 N/C *1
+ 12 CFGIN 11 N/C *2
+ 14 /C3 Clock 13 Ground
+ 16 /C1 Clock 15 CDAC
+ 18 XRDY 17 /OVR
+ 20 N/C *3 19 /INT2
+ 22 /INT6 21 A5
+ 24 A4 23 A6
+ 26 A3 25 Ground
+ 28 A7 27 A2
+ 30 A8 29 A1
+ 32 A9 31 FC0
+ 34 A10 33 FC1
+ 36 A11 35 FC2
+ 38 A12 37 Ground
+ 40 /IPL0 39 A13
+ 42 /IPL1 41 A14
+ 44 /IPL2 43 A15
+ 46 /BEER 45 A16
+ 48 /VPA 47 A17
+ 50 E Clock 49 Ground
+ 52 A18 51 /VMA
+ 54 A19 53 /RST
+ 56 A20 55 /HLT
+ 58 A21 57 A22
+ 60 /BR *4 59 A23
+ 62 /BGACK 61 Ground
+ 64 /BG *5 63 D15
+ 66 /DTACK 65 D14
+ 68 R/W 67 D13
+ 70 /LDS 69 D12
+ 72 /UDS 71 D11
+ 74 /AS 73 Ground
+ 76 D10 75 D0
+ 78 D9 77 D1
+ 80 D8 79 D2
+ 82 D7 81 D3
+ 84 D6 83 D4
+ 86 D5 85 Ground
+
+ *1 28 MHz Clock on A2000 and B2000
+ *2 /COPCFG on B2000
+ *3 /PALOPE on A1000, /BOSS on B2000
+ *4 /CBR on B2000
+ *5 /CBG on B2000
+
+ Zorro-II (differences only)
+
+ 7 /OWN
+ 9 /SLAVEn
+ 11 /CFGOUTn
+ 12 /CFGINn
+ 20 -12VDC
+ 40 /EINT7
+ 42 /EINT5
+ 44 /EINT4
+ 60 /BRn
+ 64 /BGn
+
+ 88 Ground 87 Ground
+ 90 Ground 89 Ground
+ 92 7 MHz 91 Ground
+ 94 /BURST 93 DOE
+ 96 /EINT1 95 /BG *5
+ 98 N/C 97 N/C
+ 100 Ground 99 Ground
+
+ *6 /GBG on B2000
+
+ Zorro-III
+
+ The Zorro-III is a multiplexed Zorro-II bus with address- and
+ data phases. Signals changes as follows:
+
+ 17 /CINH
+ 18 /MTCR
+ 29 /LOCK
+ 30 AD8 (D0)
+ 32 AD9 (D1)
+ 34 AD10 (D2)
+ 36 AD11 (D3)
+ 38 AD12 (D4)
+ 39 AD13 (D5)
+ 40 Reserved
+ 41 AD14 (D6)
+ 42 Reserved
+ 43 AD15 (D7)
+ 44 Reserved
+ 45 AD16 (D8)
+ 47 AD17 (D9)
+ 48 /MTACK
+ 51 /DS0
+ 52 AD18 (D10)
+ 54 AD19 (D11)
+ 56 AD20 (D12)
+ 57 AD22 (D14)
+ 58 AD21 (D13)
+ 59 AD23 (D15)
+ 63 AD31
+ 65 AD30
+ 67 AD29
+ 69 AD28
+ 70 /DS2
+ 71 AD27
+ 72 /DS3
+ 74 /CCS
+ 75 SD0 (D16)
+ 76 AD26
+ 77 SD1 (D17)
+ 78 AD25
+ 79 SD2 (D18)
+ 80 AD24
+ 81 SD3 (D19)
+ 82 SD7 (D23)
+ 83 SD4 (D20)
+ 84 SD6 (D22)
+ 86 SD5 (D21)
+ 91 Sense Z3
+ 94 /IORST
+ 95 /BCLR
+ 97 /FCS
+ 98 /DS1
+
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __ZORRO_H__
+#define __ZORRO_H__
+
+#include "emu.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_ZORRO_SLOT_ADD(_zorrotag, _tag, _slot_intf, _def_slot) \
+ MCFG_DEVICE_ADD(_tag, ZORRO_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \
+ zorro_slot_device::set_zorro_slot(*device, owner, _zorrotag);
+
+// ======================> expansion slot
+
+#define MCFG_EXPANSION_SLOT_ADD(_cputag, _slot_intf, _def_slot) \
+ MCFG_DEVICE_ADD("exp", EXP_SLOT, 0) \
+ zorro_device::set_cputag(*device, _cputag); \
+ MCFG_ZORRO_SLOT_ADD("exp", "slot", _slot_intf, _def_slot)
+
+// callbacks
+#define MCFG_EXPANSION_SLOT_OVR_HANDLER(_devcb) \
+ devcb = &zorro_device::set_ovr_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_EXPANSION_SLOT_INT2_HANDLER(_devcb) \
+ devcb = &zorro_device::set_int2_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_EXPANSION_SLOT_INT6_HANDLER(_devcb) \
+ devcb = &zorro_device::set_int6_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_EXPANSION_SLOT_IPL_HANDLER(_devcb) \
+ devcb = &exp_slot_device::set_ipl_handler(*device, DEVCB2_##_devcb);
+
+// ======================> zorro 2 bus
+
+#define MCFG_ZORRO2_ADD(_cputag) \
+ MCFG_DEVICE_ADD("zorrobus", ZORRO2, 0) \
+ zorro_device::set_cputag(*device, _cputag);
+
+#define MCFG_ZORRO2_SLOT_ADD(_tag, _slot_intf, _def_slot) \
+ MCFG_ZORRO_SLOT_ADD("zorrobus", _tag, _slot_intf, _def_slot)
+
+#define MCFG_ZORRO2_OVR_HANDLER(_devcb) \
+ devcb = &zorro_device::set_ovr_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_ZORRO2_INT2_HANDLER(_devcb) \
+ devcb = &zorro_device::set_int2_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_ZORRO2_INT6_HANDLER(_devcb) \
+ devcb = &zorro_device::set_int6_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_ZORRO2_EINT1_HANDLER(_devcb) \
+ devcb = &zorro2_device::set_eint1_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_ZORRO2_EINT4_HANDLER(_devcb) \
+ devcb = &zorro2_device::set_eint4_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_ZORRO2_EINT5_HANDLER(_devcb) \
+ devcb = &zorro2_device::set_eint5_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_ZORRO2_EINT7_HANDLER(_devcb) \
+ devcb = &zorro2_device::set_eint7_handler(*device, DEVCB2_##_devcb);
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// forward declaration of card interfaces
+class device_zorro_card_interface;
+class device_exp_card_interface;
+class device_zorro2_card_interface;
+
+// ======================> zorro slot device
+
+class zorro_slot_device : public device_t, public device_slot_interface
+{
+public:
+ // construction/destruction
+ zorro_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ zorro_slot_device(const machine_config &mconfig, device_type type, const char *name,
+ const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // inline configuration
+ static void set_zorro_slot(device_t &device, device_t *owner, const char *zorro_tag);
+
+protected:
+ // configuration
+ const char *m_zorro_tag;
+};
+
+// device type definition
+extern const device_type ZORRO_SLOT;
+
+// ======================> base zorro bus device
+
+class zorro_device : public device_t
+{
+public:
+ // construction/destruction
+ zorro_device(const machine_config &mconfig, device_type type, const char *name,
+ const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // static configuration helpers
+ static void set_cputag(device_t &device, const char *tag);
+
+ template<class _Object> static devcb2_base &set_int2_handler(device_t &device, _Object object)
+ { return downcast<zorro_device &>(device).m_int2_handler.set_callback(object); }
+ template<class _Object> static devcb2_base &set_int6_handler(device_t &device, _Object object)
+ { return downcast<zorro_device &>(device).m_int6_handler.set_callback(object); }
+ template<class _Object> static devcb2_base &set_ovr_handler(device_t &device, _Object object)
+ { return downcast<zorro_device &>(device).m_ovr_handler.set_callback(object); }
+
+ virtual void add_card(device_zorro_card_interface *card) = 0;
+
+ // interface (from slot device)
+ virtual DECLARE_WRITE_LINE_MEMBER( cfgout_w ) {};
+
+ DECLARE_WRITE_LINE_MEMBER( int2_w );
+ DECLARE_WRITE_LINE_MEMBER( int6_w );
+ DECLARE_WRITE_LINE_MEMBER( ovr_w );
+
+ // interface (from host)
+ virtual void fc_w(int code) = 0;
+
+ // access to the host space
+ address_space *m_space;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+private:
+ const char *m_cputag;
+
+ devcb2_write_line m_ovr_handler;
+ devcb2_write_line m_int2_handler;
+ devcb2_write_line m_int6_handler;
+};
+
+// ======================> expansion slot device
+
+class exp_slot_device : public zorro_device
+{
+public:
+ // construction/destruction
+ exp_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ exp_slot_device(const machine_config &mconfig, device_type type, const char *name,
+ const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ template<class _Object> static devcb2_base &set_ipl_handler(device_t &device, _Object object)
+ { return downcast<exp_slot_device &>(device).m_ipl_handler.set_callback(object); }
+
+ // the expansion slot can only have a single card
+ virtual void add_card(device_zorro_card_interface *card);
+
+ // interface (from slot device)
+ void ipl_w(int interrupt);
+
+ // interface (from host)
+ virtual void fc_w(int code);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+private:
+ devcb2_write8 m_ipl_handler;
+
+ device_exp_card_interface *m_dev;
+};
+
+// device type definition
+extern const device_type EXP_SLOT;
+
+// ======================> zorro2 slot device
+
+class zorro2_device : public zorro_device
+{
+public:
+ // construction/destruction
+ zorro2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ zorro2_device(const machine_config &mconfig, device_type type, const char *name,
+ const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ template<class _Object> static devcb2_base &set_eint1_handler(device_t &device, _Object object)
+ { return downcast<zorro2_device &>(device).m_eint1_handler.set_callback(object); }
+ template<class _Object> static devcb2_base &set_eint4_handler(device_t &device, _Object object)
+ { return downcast<zorro2_device &>(device).m_eint4_handler.set_callback(object); }
+ template<class _Object> static devcb2_base &set_eint5_handler(device_t &device, _Object object)
+ { return downcast<zorro2_device &>(device).m_eint5_handler.set_callback(object); }
+ template<class _Object> static devcb2_base &set_eint7_handler(device_t &device, _Object object)
+ { return downcast<zorro2_device &>(device).m_eint7_handler.set_callback(object); }
+
+ // device-level overrides
+ virtual void device_reset();
+
+ // the zorro2 bus supports multiple cards
+ virtual void add_card(device_zorro_card_interface *card);
+
+ // interface (from slot device)
+ virtual DECLARE_WRITE_LINE_MEMBER( cfgout_w );
+
+ DECLARE_WRITE_LINE_MEMBER( eint1_w );
+ DECLARE_WRITE_LINE_MEMBER( eint4_w );
+ DECLARE_WRITE_LINE_MEMBER( eint5_w );
+ DECLARE_WRITE_LINE_MEMBER( eint7_w );
+
+ // interface (from host)
+ virtual void fc_w(int code);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+private:
+ devcb2_write_line m_eint1_handler;
+ devcb2_write_line m_eint4_handler;
+ devcb2_write_line m_eint5_handler;
+ devcb2_write_line m_eint7_handler;
+
+ simple_list<device_zorro2_card_interface> m_dev;
+
+ // the device which is currently configuring
+ device_zorro2_card_interface *m_autoconfig_device;
+};
+
+// device type definition
+extern const device_type ZORRO2;
+
+
+// ======================> base zorro card interface
+
+class device_zorro_card_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ device_zorro_card_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_zorro_card_interface();
+
+ virtual void set_zorro_device() = 0;
+
+ void set_zorro_bus(zorro_device *device);
+
+ // interface (from device)
+ void cfgout_w(int state) { m_zorro->cfgout_w(state); }
+
+ // interface (from host)
+ virtual void fc_w(int code);
+ virtual DECLARE_WRITE_LINE_MEMBER( cfgin_w );
+
+protected:
+ zorro_device *m_zorro;
+};
+
+// ======================> expansion slot card interface
+
+class device_exp_card_interface : public device_zorro_card_interface
+{
+public:
+ // construction/destruction
+ device_exp_card_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_exp_card_interface();
+
+ virtual void set_zorro_device();
+
+protected:
+ exp_slot_device *m_slot;
+};
+
+// ======================> zorro2 card interface
+
+class device_zorro2_card_interface : public device_zorro_card_interface
+{
+public:
+ // construction/destruction
+ device_zorro2_card_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_zorro2_card_interface();
+
+ virtual void set_zorro_device();
+
+ device_zorro2_card_interface *next() const { return m_next; }
+ device_zorro2_card_interface *m_next;
+
+protected:
+ zorro2_device *m_slot;
+};
+
+
+// include this here so that you don't need to include it into every
+// driver that uses zorro slots
+#include "cards.h"
+
+
+#endif // __ZORRO_H__
diff --git a/src/emu/machine/6525tpi.c b/src/emu/machine/6525tpi.c
index 2d83a49527b..4589ff23ea7 100644
--- a/src/emu/machine/6525tpi.c
+++ b/src/emu/machine/6525tpi.c
@@ -535,6 +535,12 @@ WRITE8_MEMBER( tpi6525_device::write )
}
}
+void tpi6525_device::port_line_w(UINT8 &port, int line, int state)
+{
+ port &= ~(1 << line);
+ port |= state << line;
+}
+
/* this should probably be done better, needed for amigacd.c */
UINT8 tpi6525_device::get_ddr_a()
diff --git a/src/emu/machine/6525tpi.h b/src/emu/machine/6525tpi.h
index 6132fa45c18..a6bcea1f3c1 100644
--- a/src/emu/machine/6525tpi.h
+++ b/src/emu/machine/6525tpi.h
@@ -66,6 +66,15 @@ public:
DECLARE_WRITE8_MEMBER( pb_w );
DECLARE_WRITE8_MEMBER( pc_w );
+ WRITE_LINE_MEMBER( pb0_w ) { port_line_w(m_in_b, 0, state); }
+ WRITE_LINE_MEMBER( pb1_w ) { port_line_w(m_in_b, 1, state); }
+ WRITE_LINE_MEMBER( pb2_w ) { port_line_w(m_in_b, 2, state); }
+ WRITE_LINE_MEMBER( pb3_w ) { port_line_w(m_in_b, 3, state); }
+ WRITE_LINE_MEMBER( pb4_w ) { port_line_w(m_in_b, 4, state); }
+ WRITE_LINE_MEMBER( pb5_w ) { port_line_w(m_in_b, 5, state); }
+ WRITE_LINE_MEMBER( pb6_w ) { port_line_w(m_in_b, 6, state); }
+ WRITE_LINE_MEMBER( pb7_w ) { port_line_w(m_in_b, 7, state); }
+
UINT8 get_ddr_a();
UINT8 get_ddr_b();
UINT8 get_ddr_c();
@@ -104,6 +113,9 @@ private:
void set_interrupt();
void clear_interrupt();
+
+ // helper function to write a single line
+ static void port_line_w(UINT8 &port, int line, int state);
};
extern const device_type TPI6525;
diff --git a/src/emu/machine/akiko.c b/src/emu/machine/akiko.c
new file mode 100644
index 00000000000..c9eb0a30114
--- /dev/null
+++ b/src/emu/machine/akiko.c
@@ -0,0 +1,925 @@
+/***************************************************************************
+
+ Akiko
+
+ ASIC used in the Amiga CD32. Commodore Part number 391563-01.
+
+ - CD-ROM controller
+ - Builtin 1KB NVRAM
+ - Chunky to planar converter
+ - 2x CIA chips
+
+***************************************************************************/
+
+#include "akiko.h"
+#include "includes/amiga.h"
+#include "imagedev/chd_cd.h"
+#include "coreutil.h"
+
+
+//**************************************************************************
+// CONSTANTS / MACROS
+//**************************************************************************
+
+#define LOG_AKIKO 0
+#define LOG_AKIKO_CD 0
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type AKIKO = &device_creator<akiko_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( akiko )
+MACHINE_CONFIG_END
+
+machine_config_constructor akiko_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( akiko );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// akiko_device - constructor
+//-------------------------------------------------
+
+akiko_device::akiko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, AKIKO, "CBM AKIKO", tag, owner, clock, "akiko", __FILE__),
+ m_c2p_input_index(0),
+ m_c2p_output_index(0),
+ m_i2c_scl_out(0),
+ m_i2c_scl_dir(0),
+ m_i2c_sda_out(0),
+ m_i2c_sda_dir(0),
+ m_cdrom_track_index(0),
+ m_cdrom_lba_start(0),
+ m_cdrom_lba_end(0),
+ m_cdrom_lba_cur(0),
+ m_cdrom_readmask(0),
+ m_cdrom_readreqmask(0),
+ m_cdrom_dmacontrol(0),
+ m_cdrom_numtracks(0),
+ m_cdrom_speed(0),
+ m_cdrom_cmd_start(0),
+ m_cdrom_cmd_end(0),
+ m_cdrom_cmd_resp(0),
+ m_cdda(NULL),
+ m_cdrom(NULL),
+ m_cdrom_toc(NULL),
+ m_dma_timer(NULL),
+ m_frame_timer(NULL),
+ m_cdrom_is_device(0),
+ m_scl_w(*this),
+ m_sda_r(*this),
+ m_sda_w(*this)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ m_c2p_input_buffer[i] = 0;
+ m_c2p_output_buffer[i] = 0;
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ m_cdrom_status[i] = 0;
+ m_cdrom_address[i] = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// set_cputag - set cpu tag for cpu we working on
+//-------------------------------------------------
+
+void akiko_device::set_cputag(device_t &device, const char *tag)
+{
+ akiko_device &akiko = downcast<akiko_device &>(device);
+ akiko.m_cputag = tag;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void akiko_device::device_start()
+{
+ // resolve callbacks
+ m_scl_w.resolve_safe();
+ m_sda_r.resolve_safe(1);
+ m_sda_w.resolve_safe();
+
+ m_c2p_input_index = 0;
+ m_c2p_output_index = 0;
+
+ m_i2c_scl_out = 0;
+ m_i2c_scl_dir = 0;
+ m_i2c_sda_out = 0;
+ m_i2c_sda_dir = 0;
+
+ m_cdrom_status[0] = m_cdrom_status[1] = 0;
+ m_cdrom_address[0] = m_cdrom_address[1] = 0;
+ m_cdrom_track_index = 0;
+ m_cdrom_lba_start = 0;
+ m_cdrom_lba_end = 0;
+ m_cdrom_lba_cur = 0;
+ m_cdrom_readmask = 0;
+ m_cdrom_readreqmask = 0;
+ m_cdrom_dmacontrol = 0;
+ m_cdrom_numtracks = 0;
+ m_cdrom_speed = 0;
+ m_cdrom_cmd_start = 0;
+ m_cdrom_cmd_end = 0;
+ m_cdrom_cmd_resp = 0;
+
+ device_t *cpu = machine().device(m_cputag);
+ m_space = &cpu->memory().space(AS_PROGRAM);
+
+ m_cdrom_toc = NULL;
+ m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(akiko_device::dma_proc), this));
+ m_frame_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(akiko_device::frame_proc), this));
+ m_cdda = machine().device<cdda_device>("cdda");
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void akiko_device::device_reset()
+{
+ cdrom_image_device *cddevice = machine().device<cdrom_image_device>("cdrom");
+
+ if (cddevice != NULL)
+ {
+ // MESS case
+ m_cdrom = cddevice->get_cdrom_file();
+ m_cdrom_is_device = 1;
+ }
+ else
+ {
+ // MAME case
+ m_cdrom = cdrom_open(get_disk_handle(machine(), ":cdrom"));
+ m_cdrom_is_device = 0;
+ }
+
+ /* create the TOC table */
+ if ( m_cdrom != NULL && cdrom_get_last_track(m_cdrom) )
+ {
+ UINT8 *p;
+ int i, addrctrl = cdrom_get_adr_control( m_cdrom, 0 );
+ UINT32 discend;
+
+ discend = cdrom_get_track_start(m_cdrom,cdrom_get_last_track(m_cdrom)-1);
+ discend += cdrom_get_toc(m_cdrom)->tracks[cdrom_get_last_track(m_cdrom)-1].frames;
+ discend = lba_to_msf(discend);
+
+ m_cdrom_numtracks = cdrom_get_last_track(m_cdrom)+3;
+
+ m_cdrom_toc = auto_alloc_array(machine(), UINT8, 13*m_cdrom_numtracks);
+ memset( m_cdrom_toc, 0, 13*m_cdrom_numtracks);
+
+ p = m_cdrom_toc;
+ p[1] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4);
+ p[3] = 0xa0; /* first track */
+ p[8] = 1;
+ p += 13;
+ p[1] = 0x01;
+ p[3] = 0xa1; /* last track */
+ p[8] = cdrom_get_last_track(m_cdrom);
+ p += 13;
+ p[1] = 0x01;
+ p[3] = 0xa2; /* disc end */
+ p[8] = (discend >> 16 ) & 0xff;
+ p[9] = (discend >> 8 ) & 0xff;
+ p[10] = discend & 0xff;
+ p += 13;
+
+ for( i = 0; i < cdrom_get_last_track(m_cdrom); i++ )
+ {
+ UINT32 trackpos = cdrom_get_track_start(m_cdrom,i);
+
+ trackpos = lba_to_msf(trackpos);
+ addrctrl = cdrom_get_adr_control( m_cdrom, i );
+
+ p[1] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4);
+ p[3] = dec_2_bcd( i+1 );
+ p[8] = (trackpos >> 16 ) & 0xff;
+ p[9] = (trackpos >> 8 ) & 0xff;
+ p[10] = trackpos & 0xff;
+
+ p += 13;
+ }
+ }
+
+}
+
+//-------------------------------------------------
+// device_stop - device-specific stop
+//-------------------------------------------------
+
+void akiko_device::device_stop()
+{
+ if (!m_cdrom_is_device)
+ {
+ if( m_cdrom )
+ {
+ cdrom_close(m_cdrom);
+ m_cdrom = (cdrom_file *)NULL;
+ }
+ }
+}
+
+void akiko_device::nvram_write(UINT32 data)
+{
+ m_i2c_scl_out = BIT(data, 31);
+ m_i2c_sda_out = BIT(data, 30);
+ m_i2c_scl_dir = BIT(data, 15);
+ m_i2c_sda_dir = BIT(data, 14);
+
+ m_scl_w(m_i2c_scl_out);
+ m_sda_w(m_i2c_sda_out);
+}
+
+UINT32 akiko_device::nvram_read()
+{
+ UINT32 v = 0;
+
+ if (m_i2c_scl_dir)
+ v |= m_i2c_scl_out << 31;
+
+ if (m_i2c_sda_dir)
+ v |= m_i2c_sda_out << 30;
+ else
+ v |= m_sda_r() << 30;
+
+ v |= m_i2c_scl_dir << 15;
+ v |= m_i2c_sda_dir << 14;
+
+ return v;
+}
+
+/*************************************
+ *
+ * Akiko Chunky to Planar converter
+ *
+ ************************************/
+
+void akiko_device::c2p_write(UINT32 data)
+{
+ m_c2p_input_buffer[m_c2p_input_index] = data;
+ m_c2p_input_index++;
+ m_c2p_input_index &= 7;
+ m_c2p_output_index = 0;
+}
+
+UINT32 akiko_device::c2p_read()
+{
+ UINT32 val;
+
+ if ( m_c2p_output_index == 0 )
+ {
+ int i;
+
+ for ( i = 0; i < 8; i++ )
+ m_c2p_output_buffer[i] = 0;
+
+ for (i = 0; i < 8 * 32; i++)
+ {
+ if (m_c2p_input_buffer[7 - (i >> 5)] & (1 << (i & 31)))
+ m_c2p_output_buffer[i & 7] |= 1 << (i >> 3);
+ }
+ }
+ m_c2p_input_index = 0;
+ val = m_c2p_output_buffer[m_c2p_output_index];
+ m_c2p_output_index++;
+ m_c2p_output_index &= 7;
+ return val;
+}
+
+static const char *const akiko_reg_names[] =
+{
+ /*0*/ "ID",
+ /*1*/ "CDROM STATUS 1",
+ /*2*/ "CDROM_STATUS 2",
+ /*3*/ "???",
+ /*4*/ "CDROM ADDRESS 1",
+ /*5*/ "CDROM ADDRESS 2",
+ /*6*/ "CDROM COMMAND 1",
+ /*7*/ "CDROM COMMAND 2",
+ /*8*/ "CDROM READMASK",
+ /*9*/ "CDROM DMACONTROL",
+ /*A*/ "???",
+ /*B*/ "???",
+ /*C*/ "NVRAM",
+ /*D*/ "???",
+ /*E*/ "C2P"
+};
+
+static const char* get_akiko_reg_name(int reg)
+{
+ if (reg < 0xf )
+ {
+ return akiko_reg_names[reg];
+ }
+ else
+ {
+ return "???";
+ }
+}
+
+/*************************************
+ *
+ * Akiko CDROM Controller
+ *
+ ************************************/
+
+void akiko_device::cdda_stop()
+{
+ if (m_cdda != NULL)
+ {
+ m_cdda->stop_audio();
+ m_frame_timer->reset( );
+ }
+}
+
+void akiko_device::cdda_play(UINT32 lba, UINT32 num_blocks)
+{
+ if (m_cdda != NULL)
+ {
+ m_cdda->start_audio(lba, num_blocks);
+ m_frame_timer->adjust( attotime::from_hz( 75 ) );
+ }
+}
+
+void akiko_device::cdda_pause(int pause)
+{
+ if (m_cdda != NULL)
+ {
+ if (m_cdda->audio_active() && m_cdda->audio_paused() != pause )
+ {
+ m_cdda->pause_audio(pause);
+
+ if ( pause )
+ {
+ m_frame_timer->reset( );
+ }
+ else
+ {
+ m_frame_timer->adjust( attotime::from_hz( 75 ) );
+ }
+ }
+ }
+}
+
+UINT8 akiko_device::cdda_getstatus(UINT32 *lba)
+{
+ if ( lba ) *lba = 0;
+
+ if (m_cdda != NULL)
+ {
+ if (m_cdda->audio_active())
+ {
+ if ( lba ) *lba = m_cdda->get_audio_lba();
+
+ if (m_cdda->audio_paused())
+ {
+ return 0x12; /* audio paused */
+ }
+ else
+ {
+ return 0x11; /* audio in progress */
+ }
+ }
+ else if (m_cdda->audio_ended())
+ {
+ return 0x13; /* audio ended */
+ }
+ }
+
+ return 0x15; /* no audio status */
+}
+
+void akiko_device::set_cd_status(UINT32 status)
+{
+ amiga_state *amiga = machine().driver_data<amiga_state>();
+
+ m_cdrom_status[0] |= status;
+
+ if ( m_cdrom_status[0] & m_cdrom_status[1] )
+ {
+ if (LOG_AKIKO_CD)
+ logerror("Akiko CD IRQ\n");
+
+ amiga->custom_chip_w(REG_INTREQ, INTENA_SETCLR | INTENA_PORTS);
+ }
+}
+
+TIMER_CALLBACK_MEMBER(akiko_device::frame_proc)
+{
+ (void)param;
+
+ if (m_cdda != NULL)
+ {
+ UINT8 s = cdda_getstatus(NULL);
+
+ if ( s == 0x11 )
+ {
+ set_cd_status(0x80000000); /* subcode ready */
+ }
+
+ m_frame_timer->adjust( attotime::from_hz( 75 ) );
+ }
+}
+
+static UINT32 lba_from_triplet( UINT8 *triplet )
+{
+ UINT32 r;
+
+ r = bcd_2_dec(triplet[0]) * (60*75);
+ r += bcd_2_dec(triplet[1]) * 75;
+ r += bcd_2_dec(triplet[2]);
+
+ return r;
+}
+
+TIMER_CALLBACK_MEMBER(akiko_device::dma_proc)
+{
+ UINT8 buf[2352];
+ int index;
+
+ if ( (m_cdrom_dmacontrol & 0x04000000) == 0 )
+ return;
+
+ if ( m_cdrom_readreqmask == 0 )
+ return;
+
+ index = (m_cdrom_lba_cur - m_cdrom_lba_start) & 0x0f;
+
+ if ( m_cdrom_readreqmask & ( 1 << index ) )
+ {
+ amiga_state *amiga = machine().driver_data<amiga_state>();
+ UINT32 track = cdrom_get_track( m_cdrom, m_cdrom_lba_cur );
+ UINT32 datasize = cdrom_get_toc( m_cdrom )->tracks[track].datasize;
+ UINT32 subsize = cdrom_get_toc( m_cdrom )->tracks[track].subsize;
+ int i;
+
+ UINT32 curmsf = lba_to_msf( m_cdrom_lba_cur );
+ memset( buf, 0, 16 );
+
+ buf[3] = m_cdrom_lba_cur - m_cdrom_lba_start;
+ memset( &buf[4], 0xff, 8 );
+
+ buf[12] = (curmsf >> 16) & 0xff;
+ buf[13] = (curmsf >> 8) & 0xff;
+ buf[14] = curmsf & 0xff;
+ buf[15] = 0x01; /* mode1 */
+
+ datasize = 2048;
+ if ( !cdrom_read_data( m_cdrom, m_cdrom_lba_cur, &buf[16], CD_TRACK_MODE1 ) )
+ {
+ logerror( "AKIKO: Read error trying to read sector %08x!\n", m_cdrom_lba_cur );
+ return;
+ }
+
+ if ( subsize )
+ {
+ if ( !cdrom_read_subcode( m_cdrom, m_cdrom_lba_cur, &buf[16+datasize] ) )
+ {
+ logerror( "AKIKO: Read error trying to read subcode for sector %08x!\n", m_cdrom_lba_cur );
+ return;
+ }
+ }
+
+ if (LOG_AKIKO_CD) logerror( "DMA: sector %d - address %08x\n", m_cdrom_lba_cur, m_cdrom_address[0] + (index*4096) );
+
+ for( i = 0; i < 2352; i += 2 )
+ {
+ UINT16 data;
+
+ data = buf[i];
+ data <<= 8;
+ data |= buf[i+1];
+
+ (*amiga->m_chip_ram_w)( amiga, m_cdrom_address[0] + (index*4096) + i, data );
+ }
+
+ m_cdrom_readmask |= ( 1 << index );
+ m_cdrom_readreqmask &= ~( 1 << index );
+ m_cdrom_lba_cur++;
+ }
+
+ if ( m_cdrom_readreqmask == 0 )
+ set_cd_status(0x04000000);
+ else
+ m_dma_timer->adjust( attotime::from_usec( CD_SECTOR_TIME / m_cdrom_speed ) );
+}
+
+void akiko_device::start_dma()
+{
+ if ( m_cdrom_readreqmask == 0 )
+ return;
+
+ if ( m_cdrom_lba_start > m_cdrom_lba_end )
+ return;
+
+ if ( m_cdrom_speed == 0 )
+ return;
+
+ m_cdrom_lba_cur = m_cdrom_lba_start;
+
+ m_dma_timer->adjust( attotime::from_usec( CD_SECTOR_TIME / m_cdrom_speed ) );
+}
+
+void akiko_device::setup_response( int len, UINT8 *r1 )
+{
+ int resp_addr = m_cdrom_address[1];
+ UINT8 resp_csum = 0xff;
+ UINT8 resp_buffer[32];
+ int i;
+
+ memset( resp_buffer, 0, sizeof( resp_buffer ) );
+
+ for( i = 0; i < len; i++ )
+ {
+ resp_buffer[i] = r1[i];
+ resp_csum -= resp_buffer[i];
+ }
+
+ resp_buffer[len++] = resp_csum;
+
+ for( i = 0; i < len; i++ )
+ {
+ m_space->write_byte( resp_addr + ((m_cdrom_cmd_resp + i) & 0xff), resp_buffer[i] );
+ }
+
+ m_cdrom_cmd_resp = (m_cdrom_cmd_resp+len) & 0xff;
+
+ set_cd_status(0x10000000); /* new data available */
+}
+
+TIMER_CALLBACK_MEMBER( akiko_device::cd_delayed_cmd )
+{
+ UINT8 resp[32];
+ UINT8 cddastatus;
+
+ if ( m_cdrom_status[0] & 0x10000000 )
+ return;
+
+ cddastatus = cdda_getstatus(NULL);
+
+ if ( cddastatus == 0x11 || cddastatus == 0x12 )
+ return;
+
+ memset( resp, 0, sizeof( resp ) );
+ resp[0] = param;
+
+ param &= 0x0f;
+
+ if ( param == 0x05 )
+ {
+ if (LOG_AKIKO_CD) logerror( "AKIKO: Completing Command %d\n", param );
+
+ resp[0] = 0x06;
+
+ if ( m_cdrom == NULL || m_cdrom_numtracks == 0 )
+ {
+ resp[1] = 0x80;
+ setup_response( 15, resp );
+ }
+ else
+ {
+ resp[1] = 0x00;
+ memcpy( &resp[2], &m_cdrom_toc[13*m_cdrom_track_index], 13 );
+
+ m_cdrom_track_index = ( m_cdrom_track_index + 1 ) % m_cdrom_numtracks;
+
+ setup_response( 15, resp );
+ }
+ }
+}
+
+void akiko_device::update_cdrom()
+{
+ UINT8 resp[32], cmdbuf[32];
+
+ if ( m_cdrom_status[0] & 0x10000000 )
+ return;
+
+ while ( m_cdrom_cmd_start != m_cdrom_cmd_end )
+ {
+ UINT32 cmd_addr = m_cdrom_address[1] + 0x200 + m_cdrom_cmd_start;
+ int cmd = m_space->read_byte( cmd_addr );
+
+ memset( resp, 0, sizeof( resp ) );
+ resp[0] = cmd;
+
+ cmd &= 0x0f;
+
+ if (LOG_AKIKO_CD) logerror( "CDROM command: %02X\n", cmd );
+
+ if ( cmd == 0x02 ) /* pause audio */
+ {
+ resp[1] = 0x00;
+
+ if ( cdda_getstatus(NULL) == 0x11 )
+ resp[1] = 0x08;
+
+ cdda_pause(1);
+
+ m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff;
+
+ setup_response( 2, resp );
+ }
+ else if ( cmd == 0x03 ) /* unpause audio (and check audiocd playing status) */
+ {
+ resp[1] = 0x00;
+
+ if ( cdda_getstatus(NULL) == 0x11 )
+ resp[1] = 0x08;
+
+ cdda_pause(0);
+
+ m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff;
+
+ setup_response( 2, resp );
+ }
+ else if ( cmd == 0x04 ) /* seek/read/play cd multi command */
+ {
+ int i;
+ UINT32 startpos, endpos;
+
+ for( i = 0; i < 13; i++ )
+ {
+ cmdbuf[i] = m_space->read_byte( cmd_addr );
+ cmd_addr &= 0xffffff00;
+ cmd_addr += ( m_cdrom_cmd_start + i + 1 ) & 0xff;
+ }
+
+ m_cdrom_cmd_start = (m_cdrom_cmd_start+13) & 0xff;
+
+ if ( m_cdrom == NULL || m_cdrom_numtracks == 0 )
+ {
+ resp[1] = 0x80;
+ setup_response( 2, resp );
+ }
+ else
+ {
+ startpos = lba_from_triplet( &cmdbuf[1] );
+ endpos = lba_from_triplet( &cmdbuf[4] );
+
+ cdda_stop();
+
+ resp[1] = 0x00;
+
+ if ( cmdbuf[7] == 0x80 )
+ {
+ if (LOG_AKIKO_CD) logerror( "%s:AKIKO CD: Data read - start lba: %08x - end lba: %08x\n", machine().describe_context(), startpos, endpos );
+ m_cdrom_speed = (cmdbuf[8] & 0x40) ? 2 : 1;
+ m_cdrom_lba_start = startpos;
+ m_cdrom_lba_end = endpos;
+
+ resp[1] = 0x02;
+ }
+ else if ( cmdbuf[10] & 0x04 )
+ {
+ logerror( "AKIKO CD: Audio Play - start lba: %08x - end lba: %08x\n", startpos, endpos );
+ cdda_play(startpos, endpos - startpos);
+ resp[1] = 0x08;
+ }
+ else
+ {
+ if (LOG_AKIKO_CD) logerror( "AKIKO CD: Seek - start lba: %08x - end lba: %08x\n", startpos, endpos );
+ m_cdrom_track_index = 0;
+
+ for( i = 0; i < cdrom_get_last_track(m_cdrom); i++ )
+ {
+ if ( startpos <= cdrom_get_track_start( m_cdrom, i ) )
+ {
+ /* reset to 0 */
+ m_cdrom_track_index = i + 2;
+ m_cdrom_track_index %= m_cdrom_numtracks;
+ break;
+ }
+ }
+ }
+
+ setup_response( 2, resp );
+ }
+ }
+ else if ( cmd == 0x05 ) /* read toc */
+ {
+ m_cdrom_cmd_start = (m_cdrom_cmd_start+3) & 0xff;
+
+ machine().scheduler().timer_set( attotime::from_msec(1), timer_expired_delegate(FUNC(akiko_device::cd_delayed_cmd ), this), resp[0]);
+
+ break;
+ }
+ else if ( cmd == 0x06 ) /* read subq */
+ {
+ UINT32 lba;
+
+ resp[1] = 0x00;
+
+ (void)cdda_getstatus(&lba);
+
+ if ( lba > 0 )
+ {
+ UINT32 disk_pos;
+ UINT32 track_pos;
+ UINT32 track;
+ int addrctrl;
+
+ track = cdrom_get_track(m_cdrom, lba);
+ addrctrl = cdrom_get_adr_control(m_cdrom, track);
+
+ resp[2] = 0x00;
+ resp[3] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4);
+ resp[4] = dec_2_bcd(track+1);
+ resp[5] = 0; /* index */
+
+ disk_pos = lba_to_msf(lba);
+ track_pos = lba_to_msf(lba - cdrom_get_track_start(m_cdrom, track));
+
+ /* track position */
+ resp[6] = (track_pos >> 16) & 0xff;
+ resp[7] = (track_pos >> 8) & 0xff;
+ resp[8] = track_pos & 0xff;
+
+ /* disk position */
+ resp[9] = (disk_pos >> 24) & 0xff;
+ resp[10] = (disk_pos >> 16) & 0xff;
+ resp[11] = (disk_pos >> 8) & 0xff;
+ resp[12] = disk_pos & 0xff;
+ }
+ else
+ {
+ resp[1] = 0x80;
+ }
+
+ setup_response( 15, resp );
+ }
+ else if ( cmd == 0x07 ) /* check door status */
+ {
+ resp[1] = 0x01;
+
+ m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff;
+
+ if ( m_cdrom == NULL || m_cdrom_numtracks == 0 )
+ resp[1] = 0x80;
+
+ setup_response( 20, resp );
+ break;
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+READ32_MEMBER( akiko_device::read )
+{
+ UINT32 retval;
+
+ if ( LOG_AKIKO && offset < (0x30/4) )
+ {
+ logerror( "Reading AKIKO reg %0x [%s] at PC=%06x\n", offset, get_akiko_reg_name(offset), m_space->device().safe_pc() );
+ }
+
+ switch( offset )
+ {
+ case 0x00/4: /* ID */
+ if ( m_cdrom != NULL ) m_cdda->set_cdrom(m_cdrom);
+ return 0x0000cafe;
+
+ case 0x04/4: /* CDROM STATUS 1 */
+ return m_cdrom_status[0];
+
+ case 0x08/4: /* CDROM STATUS 2 */
+ return m_cdrom_status[1];
+
+ case 0x10/4: /* CDROM ADDRESS 1 */
+ return m_cdrom_address[0];
+
+ case 0x14/4: /* CDROM ADDRESS 2 */
+ return m_cdrom_address[1];
+
+ case 0x18/4: /* CDROM COMMAND 1 */
+ update_cdrom();
+ retval = m_cdrom_cmd_start;
+ retval <<= 8;
+ retval |= m_cdrom_cmd_resp;
+ retval <<= 8;
+ return retval;
+
+ case 0x1C/4: /* CDROM COMMAND 2 */
+ update_cdrom();
+ retval = m_cdrom_cmd_end;
+ retval <<= 16;
+ return retval;
+
+ case 0x20/4: /* CDROM DMA SECTOR READ MASK */
+ retval = m_cdrom_readmask << 16;
+ return retval;
+
+ case 0x24/4: /* CDROM DMA ENABLE? */
+ retval = m_cdrom_dmacontrol;
+ return retval;
+
+ case 0x30/4: /* NVRAM */
+ return nvram_read();
+
+ case 0x38/4: /* C2P */
+ return c2p_read();
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER( akiko_device::write )
+{
+ if ( LOG_AKIKO && offset < (0x30/4) )
+ {
+ logerror( "Writing AKIKO reg %0x [%s] with %08x at PC=%06x\n", offset, get_akiko_reg_name(offset), data, m_space->device().safe_pc() );
+ }
+
+ switch( offset )
+ {
+ case 0x04/4: /* CDROM STATUS 1 */
+ m_cdrom_status[0] = data;
+ break;
+
+ case 0x08/4: /* CDROM STATUS 2 */
+ m_cdrom_status[1] = data;
+ m_cdrom_status[0] &= data;
+ break;
+
+ case 0x10/4: /* CDROM ADDRESS 1 */
+ m_cdrom_address[0] = data;
+ break;
+
+ case 0x14/4: /* CDROM ADDRESS 2 */
+ m_cdrom_address[1] = data;
+ break;
+
+ case 0x18/4: /* CDROM COMMAND 1 */
+ if ( ACCESSING_BITS_16_23 )
+ m_cdrom_cmd_start = ( data >> 16 ) & 0xff;
+
+ if ( ACCESSING_BITS_8_15 )
+ m_cdrom_cmd_resp = ( data >> 8 ) & 0xff;
+
+ update_cdrom();
+ break;
+
+ case 0x1C/4: /* CDROM COMMAND 2 */
+ if ( ACCESSING_BITS_16_23 )
+ m_cdrom_cmd_end = ( data >> 16 ) & 0xff;
+
+ update_cdrom();
+ break;
+
+ case 0x20/4: /* CDROM DMA SECTOR READ REQUEST WRITE */
+ if (LOG_AKIKO_CD) logerror( "Read Req mask W: data %08x - mem mask %08x\n", data, mem_mask );
+ if ( ACCESSING_BITS_16_31 )
+ {
+ m_cdrom_readreqmask = (data >> 16);
+ m_cdrom_readmask = 0;
+ }
+ break;
+
+ case 0x24/4: /* CDROM DMA ENABLE? */
+ if (LOG_AKIKO_CD) logerror( "DMA enable W: data %08x - mem mask %08x\n", data, mem_mask );
+ if ( ( m_cdrom_dmacontrol ^ data ) & 0x04000000 )
+ {
+ if ( data & 0x04000000 )
+ start_dma();
+ }
+ m_cdrom_dmacontrol = data;
+ break;
+
+ case 0x30/4:
+ nvram_write(data);
+ break;
+
+ case 0x38/4:
+ c2p_write(data);
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/src/emu/machine/akiko.h b/src/emu/machine/akiko.h
new file mode 100644
index 00000000000..47fa22fee19
--- /dev/null
+++ b/src/emu/machine/akiko.h
@@ -0,0 +1,153 @@
+/***************************************************************************
+
+ Akiko
+
+ Used in the Amiga CD32
+
+ - CD-ROM controller
+ - Builtin 1KB NVRAM
+ - Chunky to planar converter
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __AKIKO_H__
+#define __AKIKO_H__
+
+#include "emu.h"
+#include "cdrom.h"
+#include "sound/cdda.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_AKIKO_ADD(_tag, _cputag) \
+ MCFG_DEVICE_ADD(_tag, AKIKO, 0) \
+ akiko_device::set_cputag(*device, _cputag);
+
+#define MCFG_AKIKO_SCL_HANDLER(_devcb) \
+ devcb = &akiko_device::set_scl_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_AKIKO_SDA_READ_HANDLER(_devcb) \
+ devcb = &akiko_device::set_sda_read_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_AKIKO_SDA_WRITE_HANDLER(_devcb) \
+ devcb = &akiko_device::set_sda_write_handler(*device, DEVCB2_##_devcb);
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> akiko_device
+
+class akiko_device : public device_t
+{
+public:
+ akiko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~akiko_device() {}
+
+ // callbacks
+ template<class _Object> static devcb2_base &set_scl_handler(device_t &device, _Object object)
+ { return downcast<akiko_device &>(device).m_scl_w.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_sda_read_handler(device_t &device, _Object object)
+ { return downcast<akiko_device &>(device).m_sda_r.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_sda_write_handler(device_t &device, _Object object)
+ { return downcast<akiko_device &>(device).m_sda_w.set_callback(object); }
+
+ DECLARE_READ32_MEMBER( read );
+ DECLARE_WRITE32_MEMBER( write );
+
+ // inline configuration
+ static void set_cputag(device_t &device, const char *tag);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_stop();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+ // 1X CDROM sector time in msec (300KBps)
+ static const int CD_SECTOR_TIME = (1000/((150*1024)/2048));
+
+ // internal state
+ address_space *m_space;
+
+ // chunky to planar converter
+ UINT32 m_c2p_input_buffer[8];
+ UINT32 m_c2p_output_buffer[8];
+ UINT32 m_c2p_input_index;
+ UINT32 m_c2p_output_index;
+
+ // i2c bus
+ int m_i2c_scl_out;
+ int m_i2c_scl_dir;
+ int m_i2c_sda_out;
+ int m_i2c_sda_dir;
+
+ // cdrom
+ UINT32 m_cdrom_status[2];
+ UINT32 m_cdrom_address[2];
+ UINT32 m_cdrom_track_index;
+ UINT32 m_cdrom_lba_start;
+ UINT32 m_cdrom_lba_end;
+ UINT32 m_cdrom_lba_cur;
+ UINT16 m_cdrom_readmask;
+ UINT16 m_cdrom_readreqmask;
+ UINT32 m_cdrom_dmacontrol;
+ UINT32 m_cdrom_numtracks;
+ UINT8 m_cdrom_speed;
+ UINT8 m_cdrom_cmd_start;
+ UINT8 m_cdrom_cmd_end;
+ UINT8 m_cdrom_cmd_resp;
+
+ cdda_device *m_cdda;
+ cdrom_file *m_cdrom;
+
+ UINT8 *m_cdrom_toc;
+
+ emu_timer *m_dma_timer;
+ emu_timer *m_frame_timer;
+
+ int m_cdrom_is_device;
+
+ void nvram_write(UINT32 data);
+ UINT32 nvram_read();
+
+ void c2p_write(UINT32 data);
+ UINT32 c2p_read();
+
+ void cdda_stop();
+ void cdda_play(UINT32 lba, UINT32 num_blocks);
+ void cdda_pause(int pause);
+ UINT8 cdda_getstatus(UINT32 *lba);
+ void set_cd_status(UINT32 status);
+
+ TIMER_CALLBACK_MEMBER( frame_proc );
+ TIMER_CALLBACK_MEMBER( dma_proc );
+
+ void start_dma();
+ void setup_response( int len, UINT8 *r1 );
+
+ TIMER_CALLBACK_MEMBER( cd_delayed_cmd );
+ void update_cdrom();
+
+ // i2c interface
+ devcb2_write_line m_scl_w;
+ devcb2_read_line m_sda_r;
+ devcb2_write_line m_sda_w;
+
+ const char *m_cputag;
+};
+
+// device type definition
+extern const device_type AKIKO;
+
+#endif
diff --git a/src/emu/machine/amigafdc.c b/src/emu/machine/amigafdc.c
index 2349a3b7ce0..334c2032a11 100644
--- a/src/emu/machine/amigafdc.c
+++ b/src/emu/machine/amigafdc.c
@@ -63,8 +63,7 @@ void amiga_fdc::dma_done()
{
amiga_state *state = machine().driver_data<amiga_state>();
dma_state = DMA_IDLE;
- address_space &space = *state->m_maincpu_program_space;
- state->amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKBLK, 0xffff);
+ state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | INTENA_DSKBLK);
}
void amiga_fdc::dma_write(UINT16 value)
@@ -202,8 +201,7 @@ void amiga_fdc::live_run(attotime limit)
cur_live.bit_counter = 0;
}
dskbyt |= 0x1000;
- address_space &space = *state->m_maincpu_program_space;
- state->amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKSYN, 0xffff);
+ state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | INTENA_DSKSYN);
} else
dskbyt &= ~0x1000;
@@ -412,6 +410,7 @@ UINT8 amiga_fdc::ciaapra_r()
if(!floppy->dskchg_r())
ret &= ~0x04;
}
+
return ret;
}
diff --git a/src/emu/machine/autoconfig.c b/src/emu/machine/autoconfig.c
new file mode 100644
index 00000000000..3c93efa6cff
--- /dev/null
+++ b/src/emu/machine/autoconfig.c
@@ -0,0 +1,167 @@
+/***************************************************************************
+
+ Amiga Autoconfig
+
+***************************************************************************/
+
+#include "autoconfig.h"
+
+
+//**************************************************************************
+// CONSTANTS & MACROS
+//**************************************************************************
+
+#define VERBOSE 1
+
+
+//**************************************************************************
+// CONSTRUCTOR
+//**************************************************************************
+
+amiga_autoconfig::amiga_autoconfig()
+{
+ memset(m_cfg, 0xff, sizeof(m_cfg));
+
+ // interrupt status register, not inverted
+ m_cfg[0x20] = 0;
+ m_cfg[0x21] = 0;
+}
+
+amiga_autoconfig::~amiga_autoconfig()
+{
+}
+
+
+//**************************************************************************
+// AUTOCONFIG INFO SETTERS
+//**************************************************************************
+
+void amiga_autoconfig::autoconfig_board_type(board_type type)
+{
+ m_cfg[0x00] &= 0x3000;
+ m_cfg[0x00] |= (type << 2) << 12;
+}
+
+void amiga_autoconfig::autoconfig_board_size(board_size size)
+{
+ m_cfg[0x01] &= 0x8000;
+ m_cfg[0x01] |= (size << 0) << 12;
+}
+
+void amiga_autoconfig::autoconfig_rom_vector_valid(bool state)
+{
+ m_cfg[0x00] &= 0xe000;
+ m_cfg[0x00] |= (state ? 0x01 : 0x00) << 12;
+}
+
+void amiga_autoconfig::autoconfig_link_into_memory(bool state)
+{
+ m_cfg[0x00] &= 0xd000;
+ m_cfg[0x00] |= (state ? 0x02 : 0x00) << 12;
+}
+
+void amiga_autoconfig::autoconfig_multi_device(bool state)
+{
+ m_cfg[0x01] &= 0x7000;
+ m_cfg[0x01] |= (state ? 0x08 : 0x00) << 12;
+}
+
+void amiga_autoconfig::autoconfig_8meg_preferred(bool state)
+{
+ m_cfg[0x04] &= 0x7000;
+ m_cfg[0x04] |= (state ? 0x08 : 0x00) << 12;
+}
+
+void amiga_autoconfig::autoconfig_can_shutup(bool state)
+{
+ m_cfg[0x04] &= 0xb000;
+ m_cfg[0x04] |= (state ? 0x04 : 0x00) << 12;
+}
+
+void amiga_autoconfig::autoconfig_product(UINT8 data)
+{
+ m_cfg[0x02] = ~((data & 0xf0) >> 4) << 12;
+ m_cfg[0x03] = ~((data & 0x0f) >> 0) << 12;
+}
+
+void amiga_autoconfig::autoconfig_manufacturer(UINT16 data)
+{
+ m_cfg[0x08] = ~((data & 0xf000) >> 12) << 12;
+ m_cfg[0x09] = ~((data & 0x0f00) >> 8) << 12;
+ m_cfg[0x0a] = ~((data & 0x00f0) >> 4) << 12;
+ m_cfg[0x0b] = ~((data & 0x000f) >> 0) << 12;
+}
+
+void amiga_autoconfig::autoconfig_serial(UINT32 data)
+{
+ m_cfg[0x0c] = ~((data & 0xf0000000) >> 28) << 12;
+ m_cfg[0x0d] = ~((data & 0x0f000000) >> 24) << 12;
+ m_cfg[0x0e] = ~((data & 0x00f00000) >> 20) << 12;
+ m_cfg[0x0f] = ~((data & 0x000f0000) >> 16) << 12;
+ m_cfg[0x10] = ~((data & 0x0000f000) >> 12) << 12;
+ m_cfg[0x11] = ~((data & 0x00000f00) >> 8) << 12;
+ m_cfg[0x12] = ~((data & 0x000000f0) >> 4) << 12;
+ m_cfg[0x13] = ~((data & 0x0000000f) >> 0) << 12;
+}
+
+void amiga_autoconfig::autoconfig_rom_vector(UINT16 data)
+{
+ m_cfg[0x14] = ~((data & 0xf000) >> 12) << 12;
+ m_cfg[0x15] = ~((data & 0x0f00) >> 8) << 12;
+ m_cfg[0x16] = ~((data & 0x00f0) >> 4) << 12;
+ m_cfg[0x17] = ~((data & 0x000f) >> 0) << 12;
+}
+
+
+//**************************************************************************
+// MEMORY INTERFACE
+//**************************************************************************
+
+READ16_MEMBER( amiga_autoconfig::autoconfig_read )
+{
+ UINT16 data = m_cfg[offset] | 0x0fff;
+
+ if (VERBOSE && !space.debugger_access())
+ logerror("autoconfig_read %04x @ %02x [mask = %04x]\n", data, offset, mem_mask);
+
+ return data;
+}
+
+WRITE16_MEMBER( amiga_autoconfig::autoconfig_write )
+{
+ if (VERBOSE && !space.debugger_access())
+ logerror("autoconfig_write %04x @ %02x [mask = %04x]\n", data, offset, mem_mask);
+
+ switch (offset)
+ {
+ case 0x20:
+ // user-definable
+ break;
+
+ case 0x21:
+ // bit 0 = interrupt enable
+ // bit 1 = user-definable
+ // bit 2 = local reset
+ // bit 3 = user-definable
+ break;
+
+ case 0x24:
+ // base address register
+ m_cfg[0x24] = data & 0xf000;
+ autoconfig_base_address((m_cfg[0x24] << 8) | (m_cfg[0x25] << 4));
+ break;
+
+ case 0x25:
+ // latch low-nibble
+ m_cfg[0x25] = data & 0xf000;
+ break;
+
+ case 0x26:
+ // shut-up register
+ autoconfig_base_address(0);
+ break;
+
+ case 0x27:
+ break;
+ }
+}
diff --git a/src/emu/machine/autoconfig.h b/src/emu/machine/autoconfig.h
new file mode 100644
index 00000000000..5183f474af9
--- /dev/null
+++ b/src/emu/machine/autoconfig.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+
+ Amiga Autoconfig
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __AUTOCONFIG_H__
+#define __AUTOCONFIG_H__
+
+#include "emu.h"
+
+class amiga_autoconfig
+{
+public:
+ amiga_autoconfig();
+ virtual ~amiga_autoconfig();
+
+ // read from autoconfig space
+ DECLARE_READ16_MEMBER( autoconfig_read );
+
+ // write to autoconfig space
+ DECLARE_WRITE16_MEMBER( autoconfig_write );
+
+protected:
+ enum board_type
+ {
+ BOARD_TYPE_ZORRO3 = 2,
+ BOARD_TYPE_ZORRO2 = 3
+ };
+
+ enum board_size
+ {
+ BOARD_SIZE_8M = 0,
+ BOARD_SIZE_64K = 1,
+ BOARD_SIZE_128K = 2,
+ BOARD_SIZE_256K = 3,
+ BOARD_SIZE_512K = 4,
+ BOARD_SIZE_1M = 5,
+ BOARD_SIZE_2M = 6,
+ BOARD_SIZE_4M = 7
+ };
+
+ // board type & size
+ void autoconfig_board_type(board_type type);
+ void autoconfig_board_size(board_size size);
+
+ // various flags
+ void autoconfig_rom_vector_valid(bool state);
+ void autoconfig_link_into_memory(bool state);
+ void autoconfig_multi_device(bool state);
+ void autoconfig_8meg_preferred(bool state);
+ void autoconfig_can_shutup(bool state);
+
+ // product number, manufacturer number, serial number
+ void autoconfig_product(UINT8 data);
+ void autoconfig_manufacturer(UINT16 data);
+ void autoconfig_serial(UINT32 data);
+
+ // rom vector
+ void autoconfig_rom_vector(UINT16 data);
+
+ // called once we have received a valid base address from the host system
+ virtual void autoconfig_base_address(offs_t address) = 0;
+
+private:
+ // configuration information about our autoconfig board, 256 nibbles
+ UINT16 m_cfg[0x40];
+};
+
+#endif // __AUTOCONFIG_H__
diff --git a/src/emu/machine/cr511b.c b/src/emu/machine/cr511b.c
new file mode 100644
index 00000000000..0a4ee90bf80
--- /dev/null
+++ b/src/emu/machine/cr511b.c
@@ -0,0 +1,123 @@
+/***************************************************************************
+
+ CR-511-B CD-ROM drive
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ CD-ROM drive with a custom MKE/Panasonic interface as used in the
+ Commodore CDTV and early SoundBlaster cards.
+
+***************************************************************************/
+
+#include "cr511b.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type CR511B = &device_creator<cr511b_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( cr511b )
+ MCFG_CDROM_ADD("cdrom")
+ MCFG_CDROM_INTERFACE("cdrom")
+ MCFG_SOUND_ADD("cdda", CDDA, 0)
+ MCFG_SOUND_ROUTE(0, ":lspeaker", 1.0)
+ MCFG_SOUND_ROUTE(1, ":rspeaker", 1.0)
+MACHINE_CONFIG_END
+
+machine_config_constructor cr511b_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( cr511b );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// cr511b_device - constructor
+//-------------------------------------------------
+
+cr511b_device::cr511b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, CR511B, "CR-511-B CD-ROM drive", tag, owner, clock, "cr511b", __FILE__),
+ m_cdrom(*this, "cdrom"),
+ m_cdda(*this, "cdda"),
+ m_stch_handler(*this),
+ m_sten_handler(*this),
+ m_drq_handler(*this),
+ m_dten_handler(*this),
+ m_scor_handler(*this),
+ m_xaen_handler(*this),
+ m_frame_timer(NULL),
+ m_motor(false),
+ m_enabled(-1),
+ m_cmd(-1)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void cr511b_device::device_start()
+{
+ // resolve callbacks
+ m_stch_handler.resolve_safe();
+ m_sten_handler.resolve_safe();
+ m_drq_handler.resolve_safe();
+ m_dten_handler.resolve_safe();
+ m_scor_handler.resolve_safe();
+ m_xaen_handler.resolve_safe();
+
+ m_frame_timer = timer_alloc(0, NULL);
+ m_frame_timer->adjust(attotime::never);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void cr511b_device::device_reset()
+{
+}
+
+//-------------------------------------------------
+// device_timer - device-specific timer events
+//-------------------------------------------------
+
+void cr511b_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+READ8_MEMBER( cr511b_device::read )
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER ( cr511b_device::write )
+{
+
+}
+
+WRITE_LINE_MEMBER( cr511b_device::enable_w )
+{
+ m_enabled = state;
+}
+
+WRITE_LINE_MEMBER( cr511b_device::cmd_w )
+{
+ m_cmd = state;
+}
diff --git a/src/emu/machine/cr511b.h b/src/emu/machine/cr511b.h
new file mode 100644
index 00000000000..5def8947fc9
--- /dev/null
+++ b/src/emu/machine/cr511b.h
@@ -0,0 +1,152 @@
+/***************************************************************************
+
+ CR-511-B CD-ROM drive
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ CD-ROM drive with a custom MKE/Panasonic interface as used in the
+ Commodore CDTV and early SoundBlaster cards.
+
+ 1 _RESET 2 GND
+ 3 EFFK 4 SCCK
+ 5 SBCP 6 SCOR
+ 7 GND 8 GND
+ 9 C16M 10 GND
+ 11 _XAEN 12 GND
+ 13 EMPASIS 14 D0
+ 15 LRCK 16 DSCK
+ 17 _MUTE 18 GND
+ 19 _BUSY 20 _STCH
+ 21 _ENABLE 22 DRQ
+ 23 _HWR 24 GND
+ 25 _DTEN 26 _HRD
+ 27 _STEN 28 _CMD
+ 29 _EOP 30 GND
+ 31 DB7 32 GND
+ 33 DB6 34 DB5
+ 35 DB4 36 GND
+ 37 DB3 38 DB2
+ 39 DB1 40 DB0
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CR511B_H__
+#define __CR511B_H__
+
+#include "emu.h"
+#include "imagedev/chd_cd.h"
+#include "sound/cdda.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_CR511B_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, CR511B, 0) \
+
+#define MCFG_CR511B_STCH_HANDLER(_devcb) \
+ devcb = &cr511b_device::set_stch_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_CR511B_STEN_HANDLER(_devcb) \
+ devcb = &cr511b_device::set_sten_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_CR511B_DRQ_HANDLER(_devcb) \
+ devcb = &cr511b_device::set_drq_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_CR511B_DTEN_HANDLER(_devcb) \
+ devcb = &cr511b_device::set_dten_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_CR511B_SCOR_HANDLER(_devcb) \
+ devcb = &cr511b_device::set_scor_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_CR511B_XAEN_HANDLER(_devcb) \
+ devcb = &cr511b_device::set_xaen_handler(*device, DEVCB2_##_devcb);
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> cr511b_device
+
+class cr511b_device : public device_t
+{
+public:
+ // construction/destruction
+ cr511b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // callbacks
+ template<class _Object> static devcb2_base &set_stch_handler(device_t &device, _Object object)
+ { return downcast<cr511b_device &>(device).m_stch_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_sten_handler(device_t &device, _Object object)
+ { return downcast<cr511b_device &>(device).m_sten_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_drq_handler(device_t &device, _Object object)
+ { return downcast<cr511b_device &>(device).m_drq_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_dten_handler(device_t &device, _Object object)
+ { return downcast<cr511b_device &>(device).m_dten_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_scor_handler(device_t &device, _Object object)
+ { return downcast<cr511b_device &>(device).m_scor_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_xaen_handler(device_t &device, _Object object)
+ { return downcast<cr511b_device &>(device).m_xaen_handler.set_callback(object); }
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER ( write );
+
+ DECLARE_WRITE_LINE_MEMBER( enable_w );
+ DECLARE_WRITE_LINE_MEMBER( cmd_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ enum
+ {
+ STATUS_DOOR_CLOSED = 0x80,
+ STATUS_MEDIA = 0x40,
+ STATUS_MOTOR = 0x20,
+ STATUS_ERROR = 0x10,
+ STATUS_SUCCESS = 0x08,
+ STATUS_PLAYING = 0x04,
+ STATUS_DOOR_LOCKED = 0x02,
+ STATUS_READY = 0x01
+ };
+
+ required_device<cdrom_image_device> m_cdrom;
+ required_device<cdda_device> m_cdda;
+
+ devcb2_write_line m_stch_handler;
+ devcb2_write_line m_sten_handler;
+ devcb2_write_line m_drq_handler;
+ devcb2_write_line m_dten_handler;
+ devcb2_write_line m_scor_handler;
+ devcb2_write_line m_xaen_handler;
+
+ emu_timer *m_frame_timer;
+
+ bool m_motor;
+
+ // state of lines
+ int m_enabled;
+ int m_cmd;
+
+ // data transfer
+ UINT8 m_sector_buffer[CD_MAX_SECTOR_DATA];
+};
+
+// device type definition
+extern const device_type CR511B;
+
+#endif
diff --git a/src/emu/machine/dmac.c b/src/emu/machine/dmac.c
new file mode 100644
index 00000000000..7f2f674a793
--- /dev/null
+++ b/src/emu/machine/dmac.c
@@ -0,0 +1,467 @@
+/***************************************************************************
+
+ DMAC
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ DMA controller used in Amiga systems
+
+BOARDS:
+ CBM A590/A2091 HD controller: Prod=514/3($202/$3) (@$e90000 64K)
+ CBM A2052/58. RAM I 590/2091.RAM Prod=514/10($202/$a) (@$200000 2meg mem)
+
+***************************************************************************/
+
+#include "dmac.h"
+
+
+//**************************************************************************
+// CONSTANTS / MACROS
+//**************************************************************************
+
+#define VERBOSE 1
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type DMAC = &device_creator<dmac_device>;
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// dmac_device - constructor
+//-------------------------------------------------
+
+dmac_device::dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, DMAC, "DMAC DMA Controller", tag, owner, clock, "dmac", __FILE__),
+ amiga_autoconfig(),
+ m_cfgout_handler(*this),
+ m_int_handler(*this),
+ m_xdack_handler(*this),
+ m_scsi_read_handler(*this),
+ m_scsi_write_handler(*this),
+ m_io_read_handler(*this),
+ m_io_write_handler(*this),
+ m_space(NULL),
+ m_rom(NULL),
+ m_ram(NULL),
+ m_ram_size(-1),
+ m_configured(false),
+ m_rst(-1),
+ m_cntr(0),
+ m_istr(0),
+ m_wtc(0),
+ m_acr(0),
+ m_dma_active(false)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void dmac_device::device_start()
+{
+ // resolve callbacks
+ m_cfgout_handler.resolve_safe();
+ m_int_handler.resolve_safe();
+ m_xdack_handler.resolve_safe();
+ m_scsi_read_handler.resolve_safe(0);
+ m_scsi_write_handler.resolve_safe();
+ m_io_read_handler.resolve_safe(0);
+ m_io_write_handler.resolve_safe();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void dmac_device::device_reset()
+{
+ // fifo empty
+ m_istr |= ISTR_FE_FLG;
+}
+
+void dmac_device::autoconfig_base_address(offs_t address)
+{
+ if (VERBOSE)
+ logerror("%s('%s'): autoconfig_base_address received: 0x%06x\n", shortname(), basetag(), address);
+
+ if (!m_configured && m_ram_size > 0)
+ {
+ if (VERBOSE)
+ logerror("-> installing ram (%d bytes)\n", m_ram_size);
+
+ // install access to the ram space
+ if (address)
+ m_space->install_ram(address, address + (m_ram_size - 1), m_ram);
+
+ // prepare autoconfig for main device
+ autoconfig_board_size(BOARD_SIZE_64K);
+ autoconfig_product(0x03); // or 0x02 for rev 1
+ autoconfig_rom_vector(0x2000);
+ autoconfig_rom_vector_valid(true);
+ autoconfig_link_into_memory(false);
+ autoconfig_multi_device(false);
+
+ // first device configured
+ m_configured = true;
+ }
+ else
+ {
+ if (VERBOSE)
+ logerror("-> installing dmac\n");
+
+ // internal dmac registers
+ m_space->install_readwrite_handler(address, address + 0xff,
+ read16_delegate(FUNC(dmac_device::register_read), this),
+ write16_delegate(FUNC(dmac_device::register_write), this), 0xffff);
+
+ // install access to the rom space
+ if (m_rom)
+ {
+ m_space->install_rom(address + 0x2000, address + 0x7fff, m_rom + 0x2000);
+ m_space->install_rom(address + 0x8000, address + 0xffff, m_rom);
+ }
+
+ // stop responding to autoconfig
+ m_space->unmap_readwrite(0xe80000, 0xe8007f);
+
+ // we're done
+ m_cfgout_handler(0);
+ }
+}
+
+void dmac_device::check_interrupts()
+{
+ // interrupts enabled?
+ if (m_cntr & CNTR_INTEN)
+ {
+ // any interrupts pending?
+ if (m_istr & ISTR_INT_MASK)
+ m_istr |= ISTR_INT_P;
+ }
+ else
+ m_istr &= ~ISTR_INT_P;
+
+ // finally update interrupt line
+ m_int_handler((m_istr & ISTR_INT_P) ? 1 : 0);
+}
+
+void dmac_device::stop_dma()
+{
+ m_dma_active = false;
+ m_istr &= ~ISTR_E_INT;
+ check_interrupts();
+}
+
+void dmac_device::start_dma()
+{
+ m_dma_active = true;
+}
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+READ16_MEMBER( dmac_device::register_read )
+{
+ UINT16 data = 0xffff;
+
+ // autoconfig handles this
+ if (offset < 0x20)
+ return autoconfig_read(space, offset, mem_mask);
+
+ switch (offset)
+ {
+ case 0x20:
+ data = m_istr;
+
+ // reading clears fifo status (?)
+ m_istr &= ~0x0f;
+ check_interrupts();
+
+ if (VERBOSE)
+ logerror("%s('%s'): read istr %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ break;
+
+ case 0x21:
+ data = m_cntr;
+
+ if (VERBOSE)
+ logerror("%s('%s'): read cntr %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ break;
+
+ case 0x48:
+ case 0x49:
+ case 0x50:
+ case 0x58:
+ case 0x59:
+ case 0x5a:
+ case 0x5b:
+ case 0x5c:
+ case 0x5e:
+ case 0x5f:
+ data = m_scsi_read_handler(offset);
+
+ if (VERBOSE)
+ logerror("%s('%s'): read scsi data @ %02x %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask);
+
+ break;
+
+ case 0x70:
+ if (VERBOSE)
+ logerror("%s('%s'): read dma start strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ start_dma();
+ break;
+
+ case 0x71:
+ if (VERBOSE)
+ logerror("%s('%s'): read dma stop strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ stop_dma();
+ break;
+
+ case 0x72:
+ if (VERBOSE)
+ logerror("%s('%s'): read clear irq strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ // clear all interrupts
+ m_istr &= ~ISTR_INT_MASK;
+ check_interrupts();
+ break;
+
+ case 0x74:
+ if (VERBOSE)
+ logerror("%s('%s'): read flush fifo strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ m_istr |= ISTR_FE_FLG;
+ break;
+
+ default:
+ if (VERBOSE)
+ logerror("%s('%s'): register_read %04x @ %02x [mask = %04x]\n", shortname(), basetag(), data, offset, mem_mask);
+ }
+
+ return data;
+}
+
+WRITE16_MEMBER( dmac_device::register_write )
+{
+ switch (offset)
+ {
+ case 0x21:
+ if (VERBOSE)
+ logerror("%s('%s'): write cntr %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ m_cntr = data;
+ check_interrupts();
+ break;
+
+ case 0x40:
+ if (VERBOSE)
+ logerror("%s('%s'): write wtc hi %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ m_wtc &= 0x0000ffff;
+ m_wtc |= ((UINT32) data) << 16;
+ break;
+
+ case 0x41:
+ if (VERBOSE)
+ logerror("%s('%s'): write wtc lo %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ m_wtc &= 0xffff0000;
+ m_wtc |= data;
+ break;
+
+ case 0x42:
+ if (VERBOSE)
+ logerror("%s('%s'): write acr hi %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ m_acr &= 0x0000ffff;
+ m_acr |= ((UINT32) data) << 16;
+ break;
+
+ case 0x43:
+ if (VERBOSE)
+ logerror("%s('%s'): write acr lo %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ m_acr &= 0xffff0000;
+ m_acr |= data;
+ break;
+
+ case 0x47:
+ if (VERBOSE)
+ logerror("%s('%s'): write dawr %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+ break;
+
+ case 0x48:
+ case 0x49:
+ case 0x50:
+ case 0x58:
+ case 0x59:
+ case 0x5a:
+ case 0x5b:
+ case 0x5c:
+ case 0x5e:
+ case 0x5f:
+ if (VERBOSE)
+ logerror("%s('%s'): write scsi data @ %02x %04x [mask = %04x]\n", shortname(), basetag(), offset, data, mem_mask);
+
+ m_scsi_write_handler(offset, data, 0xff);
+ break;
+
+ case 0x70:
+ if (VERBOSE)
+ logerror("%s('%s'): write dma start strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ start_dma();
+ break;
+
+ case 0x71:
+ if (VERBOSE)
+ logerror("%s('%s'): write dma stop strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ stop_dma();
+ break;
+
+ case 0x72:
+ if (VERBOSE)
+ logerror("%s('%s'): write clear irq strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ // clear all interrupts
+ m_istr &= ~ISTR_INT_MASK;
+ check_interrupts();
+ break;
+
+ case 0x74:
+ if (VERBOSE)
+ logerror("%s('%s'): write flush fifo strobe %04x [mask = %04x]\n", shortname(), basetag(), data, mem_mask);
+
+ m_istr |= ISTR_FE_FLG;
+ break;
+
+ default:
+ if (VERBOSE)
+ logerror("%s('%s'): write %04x @ %02x [mask = %04x]\n", shortname(), basetag(), data, offset, mem_mask);
+ }
+}
+
+// this signal tells us to expose our autoconfig values
+WRITE_LINE_MEMBER( dmac_device::configin_w )
+{
+ if (VERBOSE)
+ logerror("%s('%s'): configin_w (%d)\n", shortname(), basetag(), state);
+
+ if (state == 0 && !m_configured)
+ {
+ // common autoconfig values
+ autoconfig_board_type(BOARD_TYPE_ZORRO2);
+ autoconfig_manufacturer(0x0202);
+ autoconfig_serial(0x00000000);
+ autoconfig_8meg_preferred(false);
+ autoconfig_can_shutup(true);
+
+ // if we have ram, configure it first
+ if (m_ram_size > 0)
+ {
+ // product id 10
+ autoconfig_product(0x0a);
+
+ // board size
+ switch (m_ram_size)
+ {
+ case 0x080000: autoconfig_board_size(BOARD_SIZE_512K); break;
+ case 0x100000: autoconfig_board_size(BOARD_SIZE_1M); break;
+ case 0x200000: autoconfig_board_size(BOARD_SIZE_2M); break;
+ }
+
+ // no rom and link into free memory
+ autoconfig_rom_vector_valid(false);
+ autoconfig_link_into_memory(true);
+
+ // the main device follows
+ autoconfig_multi_device(true);
+ }
+ else
+ {
+ // just setup autoconfig for the main device
+ autoconfig_board_size(BOARD_SIZE_64K);
+ autoconfig_product(0x03); // or 0x02 for rev 1
+ autoconfig_rom_vector(0x2000);
+ autoconfig_rom_vector_valid(true);
+ autoconfig_link_into_memory(false);
+
+ // no more devices after this
+ autoconfig_multi_device(false);
+ }
+
+ // install autoconfig handler
+ m_space->install_readwrite_handler(0xe80000, 0xe8007f,
+ read16_delegate(FUNC(amiga_autoconfig::autoconfig_read), static_cast<amiga_autoconfig *>(this)),
+ write16_delegate(FUNC(amiga_autoconfig::autoconfig_write), static_cast<amiga_autoconfig *>(this)), 0xffff);
+ }
+}
+
+// this sets the ram size depending on the line voltage
+WRITE_LINE_MEMBER( dmac_device::ramsz_w )
+{
+ if (VERBOSE)
+ logerror("%s('%s'): ramsz_w (%d)\n", shortname(), basetag(), state);
+
+ switch (state)
+ {
+ case 0: m_ram_size = 0x000000; break;
+ case 1: m_ram_size = 0x080000; break;
+ case 2: m_ram_size = 0x100000; break;
+ case 3: m_ram_size = 0x200000; break;
+ }
+}
+
+// reset the device
+WRITE_LINE_MEMBER( dmac_device::rst_w )
+{
+ if (VERBOSE)
+ logerror("%s('%s'): rst_w (%d)\n", shortname(), basetag(), state);
+
+ if (m_rst == 1 && state == 0)
+ device_reset();
+
+ m_rst = state;
+}
+
+// external interrupt
+WRITE_LINE_MEMBER( dmac_device::intx_w )
+{
+ if (VERBOSE)
+ logerror("%s('%s'): intx_w (%d)\n", shortname(), basetag(), state);
+
+ if (state)
+ m_istr |= ISTR_INTS;
+ else
+ m_istr &= ~ISTR_INTS;
+
+ check_interrupts();
+}
+
+// data request
+WRITE_LINE_MEMBER( dmac_device::xdreq_w )
+{
+ if (VERBOSE)
+ logerror("%s('%s'): xdreq_w (%d)\n", shortname(), basetag(), state);
+
+ if (m_dma_active)
+ {
+
+ }
+}
diff --git a/src/emu/machine/dmac.h b/src/emu/machine/dmac.h
new file mode 100644
index 00000000000..ce3849d9ea5
--- /dev/null
+++ b/src/emu/machine/dmac.h
@@ -0,0 +1,173 @@
+/***************************************************************************
+
+ DMAC
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ DMA controller used in Amiga systems
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __DMAC_H__
+#define __DMAC_H__
+
+#include "emu.h"
+#include "autoconfig.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_DMAC_ADD(_tag, _clock) \
+ MCFG_DEVICE_ADD(_tag, DMAC, _clock) \
+
+#define MCFG_DMAC_CFGOUT_HANDLER(_devcb) \
+ devcb = &dmac_device::set_cfgout_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_DMAC_INT_HANDLER(_devcb) \
+ devcb = &dmac_device::set_int_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_DMAC_XDACK_HANDLER(_devcb) \
+ devcb = &dmac_device::set_xdack_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_DMAC_SCSI_READ_HANDLER(_devcb) \
+ devcb = &dmac_device::set_scsi_read_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_DMAC_SCSI_WRITE_HANDLER(_devcb) \
+ devcb = &dmac_device::set_scsi_write_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_DMAC_IO_READ_HANDLER(_devcb) \
+ devcb = &dmac_device::set_io_read_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_DMAC_IO_WRITE_HANDLER(_devcb) \
+ devcb = &dmac_device::set_io_write_handler(*device, DEVCB2_##_devcb);
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> dmac_device
+
+class dmac_device : public device_t, public amiga_autoconfig
+{
+public:
+ // construction/destruction
+ dmac_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // callbacks
+ template<class _Object> static devcb2_base &set_cfgout_handler(device_t &device, _Object object)
+ { return downcast<dmac_device &>(device).m_cfgout_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_int_handler(device_t &device, _Object object)
+ { return downcast<dmac_device &>(device).m_int_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_xdack_handler(device_t &device, _Object object)
+ { return downcast<dmac_device &>(device).m_xdack_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_scsi_read_handler(device_t &device, _Object object)
+ { return downcast<dmac_device &>(device).m_scsi_read_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_scsi_write_handler(device_t &device, _Object object)
+ { return downcast<dmac_device &>(device).m_scsi_write_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_io_read_handler(device_t &device, _Object object)
+ { return downcast<dmac_device &>(device).m_io_read_handler.set_callback(object); }
+
+ template<class _Object> static devcb2_base &set_io_write_handler(device_t &device, _Object object)
+ { return downcast<dmac_device &>(device).m_io_write_handler.set_callback(object); }
+
+ void set_address_space(address_space *space) { m_space = space; };
+ void set_rom(UINT8 *rom) { m_rom = rom; };
+ void set_ram(UINT8 *ram) { m_ram = ram; };
+
+ // input lines
+ DECLARE_WRITE_LINE_MEMBER( configin_w );
+ DECLARE_WRITE_LINE_MEMBER( ramsz_w );
+ DECLARE_WRITE_LINE_MEMBER( rst_w );
+ DECLARE_WRITE_LINE_MEMBER( intx_w );
+ DECLARE_WRITE_LINE_MEMBER( xdreq_w );
+
+ // dmac register access
+ DECLARE_READ16_MEMBER( register_read );
+ DECLARE_WRITE16_MEMBER( register_write );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // amiga_autoconfig overrides
+ virtual void autoconfig_base_address(offs_t address);
+
+private:
+
+ // control register flags
+ enum
+ {
+ CNTR_TCEN = 0x80, // terminal count enable
+ CNTR_PREST = 0x40, // peripheral reset
+ CNTR_PDMD = 0x20, // peripheral device mode select (1=scsi, 0=xt)
+ CNTR_INTEN = 0x10, // interrupt enable
+ CNTR_DDIR = 0x08 // device direction (1=rd host, wr to peripheral)
+ };
+
+ // interrupt status register
+ enum
+ {
+ ISTR_INTX = 0x100, // xt interrupt pending
+ ISTR_INT_F = 0x080, // interrupt follow
+ ISTR_INTS = 0x040, // scsi peripheral interrupt
+ ISTR_E_INT = 0x020, // end-of-process interrupt
+ ISTR_INT_P = 0x010, // interrupt pending
+ ISTR_UE_INT = 0x008, // under-run fifo error interrupt
+ ISTR_OE_INT = 0x004, // over-run fifo error interrupt
+ ISTR_FF_FLG = 0x002, // fifo-full flag
+ ISTR_FE_FLG = 0x001 // fifo-empty flag
+ };
+
+ static const int ISTR_INT_MASK = 0x1fc;
+
+ // callbacks
+ devcb2_write_line m_cfgout_handler;
+ devcb2_write_line m_int_handler;
+ devcb2_write_line m_xdack_handler;
+ devcb2_read8 m_scsi_read_handler;
+ devcb2_write8 m_scsi_write_handler;
+ devcb2_read8 m_io_read_handler;
+ devcb2_write8 m_io_write_handler;
+
+ address_space *m_space;
+ UINT8 *m_rom;
+ UINT8 *m_ram;
+ int m_ram_size;
+
+ // autoconfig state
+ bool m_configured;
+
+ // state of lines
+ int m_rst;
+
+ // register
+ UINT16 m_cntr; // control register
+ UINT16 m_istr; // interrupt status register
+ UINT32 m_wtc; // word transfer count
+ UINT32 m_acr; // address control register
+
+ bool m_dma_active;
+
+ void check_interrupts();
+ void start_dma();
+ void stop_dma();
+};
+
+
+// device type definition
+extern const device_type DMAC;
+
+
+#endif /* __DMAC_H__ */
diff --git a/src/emu/machine/machine.mak b/src/emu/machine/machine.mak
index 18897309000..de303b9dfa7 100644
--- a/src/emu/machine/machine.mak
+++ b/src/emu/machine/machine.mak
@@ -16,6 +16,46 @@ MACHINEOBJ = $(EMUOBJ)/machine
#-------------------------------------------------
#
+#@src/emu/machine/akiko.h,MACHINES += AKIKO
+#-------------------------------------------------
+
+ifneq ($(filter AKIKO,$(MACHINES)),)
+MACHINEOBJS += $(MACHINEOBJ)/akiko.o
+endif
+
+
+#-------------------------------------------------
+#
+#@src/emu/machine/autoconfig.h,MACHINES += AUTOCONFIG
+#-------------------------------------------------
+
+ifneq ($(filter AUTOCONFIG,$(MACHINES)),)
+MACHINEOBJS += $(MACHINEOBJ)/autoconfig.o
+endif
+
+
+#-------------------------------------------------
+#
+#@src/emu/machine/cr511b.h,MACHINES += CR511B
+#-------------------------------------------------
+
+ifneq ($(filter CR511B,$(MACHINES)),)
+MACHINEOBJS += $(MACHINEOBJ)/cr511b.o
+endif
+
+
+#-------------------------------------------------
+#
+#@src/emu/machine/dmac.h,MACHINES += DMAC
+#-------------------------------------------------
+
+ifneq ($(filter DMAC,$(MACHINES)),)
+MACHINEOBJS += $(MACHINEOBJ)/dmac.o
+endif
+
+
+#-------------------------------------------------
+#
#@src/emu/machine/40105.h,MACHINES += CMOS40105
#-------------------------------------------------
diff --git a/src/emu/sound/amiga.c b/src/emu/sound/amiga.c
new file mode 100644
index 00000000000..c4c9f045352
--- /dev/null
+++ b/src/emu/sound/amiga.c
@@ -0,0 +1,240 @@
+/***************************************************************************
+
+ Amiga audio hardware
+
+***************************************************************************/
+
+#include "amiga.h"
+#include "includes/amiga.h"
+
+
+//**************************************************************************
+// CONSTANTS / MACROS
+//**************************************************************************
+
+#define VERBOSE 0
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type AMIGA = &device_creator<amiga_sound_device>;
+
+
+//*************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// amiga_sound_device - constructor
+//-------------------------------------------------
+
+amiga_sound_device::amiga_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, AMIGA, "Amiga Paula", tag, owner, clock, "amiga_paula", __FILE__),
+ device_sound_interface(mconfig, *this),
+ m_stream(NULL)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void amiga_sound_device::device_start()
+{
+ // initialize channels
+ for (int i = 0; i < 4; i++)
+ {
+ m_channel[i].index = i;
+ m_channel[i].irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(amiga_sound_device::signal_irq), this));
+ }
+
+ // create the stream
+ m_stream = machine().sound().stream_alloc(*this, 0, 4, clock() / CLOCK_DIVIDER);
+}
+
+
+//*************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+//-------------------------------------------------
+// signal_irq - irq signaling
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER( amiga_sound_device::signal_irq )
+{
+ amiga_state *state = machine().driver_data<amiga_state>();
+
+ state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | (0x80 << param));
+}
+
+//-------------------------------------------------
+// dma_reload
+//-------------------------------------------------
+
+void amiga_sound_device::dma_reload(audio_channel *chan)
+{
+ amiga_state *state = machine().driver_data<amiga_state>();
+
+ chan->curlocation = CUSTOM_REG_LONG(REG_AUD0LCH + chan->index * 8);
+ chan->curlength = CUSTOM_REG(REG_AUD0LEN + chan->index * 8);
+ chan->irq_timer->adjust(attotime::from_hz(15750), chan->index);
+
+ LOG(("dma_reload(%d): offs=%05X len=%04X\n", chan->index, chan->curlocation, chan->curlength));
+}
+
+//-------------------------------------------------
+// data_w - manual mode data writer
+//-------------------------------------------------
+
+void amiga_sound_device::data_w(int which, UINT16 data)
+{
+ m_channel[which].manualmode = true;
+}
+
+//-------------------------------------------------
+// update - stream updater
+//-------------------------------------------------
+
+void amiga_sound_device::update()
+{
+ m_stream->update();
+}
+
+//-------------------------------------------------
+// sound_stream_update - handle a stream update
+//-------------------------------------------------
+
+void amiga_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ amiga_state *state = machine().driver_data<amiga_state>();
+ int channum, sampoffs = 0;
+
+ // if all DMA off, disable all channels
+ if (!(CUSTOM_REG(REG_DMACON) & 0x0200))
+ {
+ m_channel[0].dma_enabled =
+ m_channel[1].dma_enabled =
+ m_channel[2].dma_enabled =
+ m_channel[3].dma_enabled = false;
+
+ // clear the sample data to 0
+ for (channum = 0; channum < 4; channum++)
+ memset(outputs[channum], 0, sizeof(stream_sample_t) * samples);
+ return;
+ }
+
+ samples *= CLOCK_DIVIDER;
+
+ // update the DMA states on each channel and reload if fresh
+ for (channum = 0; channum < 4; channum++)
+ {
+ audio_channel *chan = &m_channel[channum];
+ if (!chan->dma_enabled && ((CUSTOM_REG(REG_DMACON) >> channum) & 1))
+ dma_reload(chan);
+ chan->dma_enabled = (CUSTOM_REG(REG_DMACON) >> channum) & 1;
+ }
+
+ // loop until done
+ while (samples > 0)
+ {
+ int nextper, nextvol;
+ int ticks = samples;
+
+ // determine the number of ticks we can do in this chunk
+ if (ticks > m_channel[0].curticks)
+ ticks = m_channel[0].curticks;
+ if (ticks > m_channel[1].curticks)
+ ticks = m_channel[1].curticks;
+ if (ticks > m_channel[2].curticks)
+ ticks = m_channel[2].curticks;
+ if (ticks > m_channel[3].curticks)
+ ticks = m_channel[3].curticks;
+
+ // loop over channels
+ nextper = nextvol = -1;
+ for (channum = 0; channum < 4; channum++)
+ {
+ int volume = (nextvol == -1) ? CUSTOM_REG(REG_AUD0VOL + channum * 8) : nextvol;
+ int period = (nextper == -1) ? CUSTOM_REG(REG_AUD0PER + channum * 8) : nextper;
+ audio_channel *chan = &m_channel[channum];
+ stream_sample_t sample;
+ int i;
+
+ // normalize the volume value
+ volume = (volume & 0x40) ? 64 : (volume & 0x3f);
+ volume *= 4;
+
+ // are we modulating the period of the next channel?
+ if ((CUSTOM_REG(REG_ADKCON) >> channum) & 0x10)
+ {
+ nextper = CUSTOM_REG(REG_AUD0DAT + channum * 8);
+ nextvol = -1;
+ sample = 0;
+ }
+
+ // are we modulating the volume of the next channel?
+ else if ((CUSTOM_REG(REG_ADKCON) >> channum) & 0x01)
+ {
+ nextper = -1;
+ nextvol = CUSTOM_REG(REG_AUD0DAT + channum * 8);
+ sample = 0;
+ }
+
+ // otherwise, we are generating data
+ else
+ {
+ nextper = nextvol = -1;
+ sample = chan->latched * volume;
+ }
+
+ // fill the buffer with the sample
+ for (i = 0; i < ticks; i += CLOCK_DIVIDER)
+ outputs[channum][(sampoffs + i) / CLOCK_DIVIDER] = sample;
+
+ // account for the ticks; if we hit 0, advance
+ chan->curticks -= ticks;
+ if (chan->curticks == 0)
+ {
+ // reset the clock and ensure we're above the minimum ticks
+ chan->curticks = period;
+ if (chan->curticks < 124)
+ chan->curticks = 124;
+
+ // move forward one byte; if we move to an even byte, fetch new
+ if (chan->dma_enabled || chan->manualmode)
+ chan->curlocation++;
+ if (chan->dma_enabled && !(chan->curlocation & 1))
+ {
+ CUSTOM_REG(REG_AUD0DAT + channum * 8) = (*state->m_chip_ram_r)(state, chan->curlocation);
+ if (chan->curlength != 0)
+ chan->curlength--;
+
+ // if we run out of data, reload the dma
+ if (chan->curlength == 0)
+ dma_reload(chan);
+ }
+
+ // latch the next byte of the sample
+ if (!(chan->curlocation & 1))
+ chan->latched = CUSTOM_REG(REG_AUD0DAT + channum * 8) >> 8;
+ else
+ chan->latched = CUSTOM_REG(REG_AUD0DAT + channum * 8) >> 0;
+
+ // if we're in manual mode, signal an interrupt once we latch the low byte
+ if (!chan->dma_enabled && chan->manualmode && (chan->curlocation & 1))
+ {
+ signal_irq(NULL, channum);
+ chan->manualmode = false;
+ }
+ }
+ }
+
+ // bump ourselves forward by the number of ticks
+ sampoffs += ticks;
+ samples -= ticks;
+ }
+}
diff --git a/src/emu/sound/amiga.h b/src/emu/sound/amiga.h
new file mode 100644
index 00000000000..56e092b248f
--- /dev/null
+++ b/src/emu/sound/amiga.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+
+ Amiga audio hardware
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __SOUND_AMIGA_H__
+#define __SOUND_AMIGA_H__
+
+#include "emu.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> amiga_sound_device
+
+class amiga_sound_device : public device_t, public device_sound_interface
+{
+public:
+ amiga_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~amiga_sound_device() {}
+
+ void update();
+ void data_w(int which, UINT16 data);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+ // sound stream update overrides
+ virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
+
+private:
+ static const int CLOCK_DIVIDER = 16;
+
+ struct audio_channel
+ {
+ emu_timer *irq_timer;
+ UINT32 curlocation;
+ UINT16 curlength;
+ UINT16 curticks;
+ UINT8 index;
+ bool dma_enabled;
+ bool manualmode;
+ INT8 latched;
+ };
+
+ void dma_reload(audio_channel *chan);
+
+ // internal state
+ audio_channel m_channel[4];
+ sound_stream *m_stream;
+
+ TIMER_CALLBACK_MEMBER( signal_irq );
+};
+
+extern const device_type AMIGA;
+
+#endif // __SOUND_AMIGA_H__
diff --git a/src/emu/sound/sound.mak b/src/emu/sound/sound.mak
index 070534c8e09..6a6a0cf0d0d 100644
--- a/src/emu/sound/sound.mak
+++ b/src/emu/sound/sound.mak
@@ -101,6 +101,17 @@ endif
#-------------------------------------------------
+# Amiga audio hardware
+#@src/emu/sound/amiga.h,SOUNDS += AMIGA
+#-------------------------------------------------
+
+ifneq ($(filter AMIGA,$(SOUNDS)),)
+SOUNDOBJS += $(SOUNDOBJ)/amiga.o
+endif
+
+
+
+#-------------------------------------------------
# Bally Astrocade sound system
#@src/emu/sound/astrocde.h,SOUNDS += ASTROCADE
#-------------------------------------------------