summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/machine
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/machine')
-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
12 files changed, 2293 insertions, 4 deletions
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
#-------------------------------------------------