summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author Dirk Best <mail@dirk-best.de>2014-05-13 11:46:02 +0000
committer Dirk Best <mail@dirk-best.de>2014-05-13 11:46:02 +0000
commit640354ad9efa2b8c0027c0bce444e652cb593333 (patch)
tree9b96640848e9599d569e8c9a683acf3417406d60 /src/emu
parent4997e59478dc1d5c0b60c4125e609c3c271a85f7 (diff)
Big Amiga cleanup and reorganizaton. CDTV temporarily broken. Lots of
work still to do. All basic Amiga models are now supported to varying degrees.
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
#-------------------------------------------------