// license:BSD-3-Clause
// copyright-holders:Mariusz Wojcieszek
/***************************************************************************
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 "emu.h"
#include "akiko.h"
#include "imagedev/chd_cd.h"
#include "coreutil.h"
#include "romload.h"
//**************************************************************************
// CONSTANTS / MACROS
//**************************************************************************
#define LOG_AKIKO 0
#define LOG_AKIKO_CD 0
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(AKIKO, akiko_device, "akiko", "CBM AKIKO")
//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------
void akiko_device::device_add_mconfig(machine_config &config)
{
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// akiko_device - constructor
//-------------------------------------------------
akiko_device::akiko_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, AKIKO, tag, owner, clock),
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(nullptr),
m_cdrom(nullptr),
m_cdrom_toc(nullptr),
m_dma_timer(nullptr),
m_frame_timer(nullptr),
m_cdrom_is_device(0),
m_mem_r(*this), m_mem_w(*this), m_int_w(*this),
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;
}
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void akiko_device::device_start()
{
// resolve callbacks
m_mem_r.resolve_safe(0xffff);
m_mem_w.resolve_safe();
m_int_w.resolve_safe();
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;
m_cdrom_toc = nullptr;
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 != nullptr)
{
// MESS case
m_cdrom = cddevice->get_cdrom_file();
m_cdrom_is_device = 1;
}
else
{
// MAME case
m_cdrom = cdrom_open(machine().rom_load().get_disk_handle(":cdrom"));
m_cdrom_is_device = 0;
}
/* create the TOC table */
if ( m_cdrom != nullptr && cdrom_get_last_track(m_cdrom) )
{
uint8_t *p;
int i, addrctrl = cdrom_get_adr_control( m_cdrom, 0 );
uint32_t 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 = std::make_unique<uint8_t[]>(13*m_cdrom_numtracks);
memset( m_cdrom_toc.get(), 0, 13*m_cdrom_numtracks);
p = m_cdrom_toc.get();
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_t 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 *)nullptr;
}
}
}
void akiko_device::nvram_write(uint32_t 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_t akiko_device::nvram_read()
{
uint32_t 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;
}
uint8_t akiko_device::mem_r8(offs_t offset)
{
int shift = (offset & 1) ? 0 : 8;
return m_mem_r(offset, 0xff << shift) >> shift;
}
void akiko_device::mem_w8(offs_t offset, uint8_t data)
{
int shift = (offset & 1) ? 0 : 8;
m_mem_w(offset, data << shift, 0xff << shift);
}
/*************************************
*
* Akiko Chunky to Planar converter
*
************************************/
void akiko_device::c2p_write(uint32_t 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_t akiko_device::c2p_read()
{
uint32_t 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 != nullptr)
{
m_cdda->stop_audio();
m_frame_timer->reset( );
}
}
void akiko_device::cdda_play(uint32_t lba, uint32_t num_blocks)
{
if (m_cdda != nullptr)
{
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 != nullptr)
{
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_t akiko_device::cdda_getstatus(uint32_t *lba)
{
if ( lba ) *lba = 0;
if (m_cdda != nullptr)
{
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_t status)
{
m_cdrom_status[0] |= status;
if ( m_cdrom_status[0] & m_cdrom_status[1] )
{
if (LOG_AKIKO_CD)
logerror("Akiko CD IRQ\n");
m_int_w(1);
}
}
TIMER_CALLBACK_MEMBER(akiko_device::frame_proc)
{
(void)param;
if (m_cdda != nullptr)
{
uint8_t s = cdda_getstatus(nullptr);
if ( s == 0x11 )
{
set_cd_status(0x80000000); /* subcode ready */
}
m_frame_timer->adjust( attotime::from_hz( 75 ) );
}
}
static uint32_t lba_from_triplet( uint8_t *triplet )
{
uint32_t 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_t 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 ) )
{
uint32_t track = cdrom_get_track( m_cdrom, m_cdrom_lba_cur );
uint32_t datasize;// = cdrom_get_toc(m_cdrom)->tracks[track].datasize;
uint32_t subsize = cdrom_get_toc( m_cdrom )->tracks[track].subsize;
uint32_t 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) );
// write sector data to host memory
for (int i = 0; i < 2352; i++)
mem_w8(m_cdrom_address[0] + (index*4096) + i, buf[i]);
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_t *r1 )
{
int resp_addr = m_cdrom_address[1];
uint8_t resp_csum = 0xff;
uint8_t 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++ )
{
offs_t addr = resp_addr + ((m_cdrom_cmd_resp + i) & 0xff);
mem_w8(addr, 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_t resp[32];
uint8_t cddastatus;
if ( m_cdrom_status[0] & 0x10000000 )
return;
cddastatus = cdda_getstatus(nullptr);
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 == nullptr || 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_t resp[32], cmdbuf[32];
if ( m_cdrom_status[0] & 0x10000000 )
return;
while ( m_cdrom_cmd_start != m_cdrom_cmd_end )
{
uint32_t cmd_addr = m_cdrom_address[1] + 0x200 + m_cdrom_cmd_start;
uint8_t cmd = mem_r8(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(nullptr) == 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(nullptr) == 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_t startpos, endpos;
for( i = 0; i < 13; i++ )
{
cmdbuf[i] = mem_r8(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 == nullptr || 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_t lba;
resp[1] = 0x00;
(void)cdda_getstatus(&lba);
if ( lba > 0 )
{
uint32_t disk_pos;
uint32_t track_pos;
uint32_t 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 == nullptr || m_cdrom_numtracks == 0 )
resp[1] = 0x80;
setup_response( 20, resp );
break;
}
else
{
break;
}
}
}
READ32_MEMBER( akiko_device::read )
{
uint32_t retval;
if ( LOG_AKIKO && offset < (0x30/4) )
{
logerror( "Reading AKIKO reg %0x [%s] at %s\n", offset, get_akiko_reg_name(offset), machine().describe_context());
}
switch( offset )
{
case 0x00/4: /* ID */
if ( m_cdrom != nullptr ) 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 %s\n", offset, get_akiko_reg_name(offset), data, machine().describe_context());
}
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;
}
}