mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
905 lines
19 KiB
C
905 lines
19 KiB
C
#include "driver.h"
|
|
#include "includes/amiga.h"
|
|
#include "cdrom.h"
|
|
#include "coreutil.h"
|
|
#include "sound/cdda.h"
|
|
#include "machine/i2cmem.h"
|
|
#include "includes/cubocd32.h"
|
|
|
|
|
|
|
|
/*********************************************************************************
|
|
|
|
Akiko custom chip emulation
|
|
|
|
The Akiko chip has:
|
|
- built in 1KB NVRAM
|
|
- chunky to planar converter
|
|
- custom CDROM controller
|
|
|
|
TODO: Add CDDA support
|
|
|
|
*********************************************************************************/
|
|
|
|
#define LOG_AKIKO 0
|
|
#define LOG_AKIKO_CD 0
|
|
|
|
#define CD_SECTOR_TIME (1000/((150*1024)/2048)) /* 1X CDROM sector time in msec (300KBps) */
|
|
|
|
|
|
#define NVRAM_SIZE 1024
|
|
#define NVRAM_PAGE_SIZE 16 /* max size of one write request */
|
|
|
|
static struct akiko_def
|
|
{
|
|
/* chunky to planar converter */
|
|
UINT32 c2p_input_buffer[8];
|
|
UINT32 c2p_output_buffer[8];
|
|
UINT32 c2p_input_index;
|
|
UINT32 c2p_output_index;
|
|
|
|
/* i2c bus */
|
|
int i2c_scl_out;
|
|
int i2c_scl_dir;
|
|
int i2c_sda_out;
|
|
int i2c_sda_dir;
|
|
|
|
/* cdrom */
|
|
UINT32 cdrom_status[2];
|
|
UINT32 cdrom_address[2];
|
|
UINT32 cdrom_track_index;
|
|
UINT32 cdrom_lba_start;
|
|
UINT32 cdrom_lba_end;
|
|
UINT32 cdrom_lba_cur;
|
|
UINT16 cdrom_readmask;
|
|
UINT16 cdrom_readreqmask;
|
|
UINT32 cdrom_dmacontrol;
|
|
UINT32 cdrom_numtracks;
|
|
UINT8 cdrom_speed;
|
|
UINT8 cdrom_cmd_start;
|
|
UINT8 cdrom_cmd_end;
|
|
UINT8 cdrom_cmd_resp;
|
|
cdrom_file *cdrom;
|
|
UINT8 * cdrom_toc;
|
|
emu_timer *dma_timer;
|
|
emu_timer *frame_timer;
|
|
} akiko;
|
|
|
|
static TIMER_CALLBACK(akiko_dma_proc);
|
|
static TIMER_CALLBACK(akiko_frame_proc);
|
|
|
|
static void amiga_akiko_exit(running_machine* machine)
|
|
{
|
|
if( akiko.cdrom ) {
|
|
cdrom_close(akiko.cdrom);
|
|
akiko.cdrom = (cdrom_file *)NULL;
|
|
}
|
|
}
|
|
|
|
void amiga_akiko_init(running_machine* machine)
|
|
{
|
|
i2cmem_init( 0, I2CMEM_SLAVE_ADDRESS, NVRAM_PAGE_SIZE, NVRAM_SIZE, NULL );
|
|
|
|
akiko.c2p_input_index = 0;
|
|
akiko.c2p_output_index = 0;
|
|
|
|
akiko.i2c_scl_out = 0;
|
|
akiko.i2c_scl_dir = 0;
|
|
akiko.i2c_sda_out = 0;
|
|
akiko.i2c_sda_dir = 0;
|
|
|
|
akiko.cdrom_status[0] = akiko.cdrom_status[1] = 0;
|
|
akiko.cdrom_address[0] = akiko.cdrom_address[1] = 0;
|
|
akiko.cdrom_track_index = 0;
|
|
akiko.cdrom_lba_start = 0;
|
|
akiko.cdrom_lba_end = 0;
|
|
akiko.cdrom_lba_cur = 0;
|
|
akiko.cdrom_readmask = 0;
|
|
akiko.cdrom_readreqmask = 0;
|
|
akiko.cdrom_dmacontrol = 0;
|
|
akiko.cdrom_numtracks = 0;
|
|
akiko.cdrom_speed = 0;
|
|
akiko.cdrom_cmd_start = 0;
|
|
akiko.cdrom_cmd_end = 0;
|
|
akiko.cdrom_cmd_resp = 0;
|
|
akiko.cdrom = cdrom_open(get_disk_handle(0));
|
|
akiko.cdrom_toc = NULL;
|
|
akiko.dma_timer = timer_alloc(akiko_dma_proc, NULL);
|
|
akiko.frame_timer = timer_alloc(akiko_frame_proc, NULL);
|
|
|
|
add_exit_callback(machine, amiga_akiko_exit);
|
|
|
|
/* create the TOC table */
|
|
if ( akiko.cdrom != NULL && cdrom_get_last_track(akiko.cdrom) )
|
|
{
|
|
UINT8 *p;
|
|
int i, addrctrl = cdrom_get_adr_control( akiko.cdrom, 0 );
|
|
UINT32 discend;
|
|
|
|
discend = cdrom_get_track_start(akiko.cdrom,cdrom_get_last_track(akiko.cdrom)-1);
|
|
discend += cdrom_get_toc(akiko.cdrom)->tracks[cdrom_get_last_track(akiko.cdrom)-1].frames;
|
|
discend = lba_to_msf(discend);
|
|
|
|
akiko.cdrom_numtracks = cdrom_get_last_track(akiko.cdrom)+3;
|
|
|
|
akiko.cdrom_toc = (UINT8*)auto_malloc(13*akiko.cdrom_numtracks);
|
|
memset( akiko.cdrom_toc, 0, 13*akiko.cdrom_numtracks);
|
|
|
|
p = akiko.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(akiko.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(akiko.cdrom); i++ )
|
|
{
|
|
UINT32 trackpos = cdrom_get_track_start(akiko.cdrom,i);
|
|
|
|
trackpos = lba_to_msf(trackpos);
|
|
addrctrl = cdrom_get_adr_control( akiko.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;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void akiko_nvram_write(UINT32 data)
|
|
{
|
|
akiko.i2c_scl_out = BIT(data,31);
|
|
akiko.i2c_sda_out = BIT(data,30);
|
|
akiko.i2c_scl_dir = BIT(data,15);
|
|
akiko.i2c_sda_dir = BIT(data,14);
|
|
|
|
i2cmem_write( 0, I2CMEM_SCL, akiko.i2c_scl_out );
|
|
i2cmem_write( 0, I2CMEM_SDA, akiko.i2c_sda_out );
|
|
}
|
|
|
|
static UINT32 akiko_nvram_read(void)
|
|
{
|
|
UINT32 v = 0;
|
|
|
|
if ( akiko.i2c_scl_dir )
|
|
{
|
|
v |= akiko.i2c_scl_out << 31;
|
|
}
|
|
else
|
|
{
|
|
v |= 0 << 31;
|
|
}
|
|
|
|
if ( akiko.i2c_sda_dir )
|
|
{
|
|
v |= akiko.i2c_sda_out << 30;
|
|
}
|
|
else
|
|
{
|
|
v |= i2cmem_read( 0, I2CMEM_SDA ) << 30;
|
|
}
|
|
|
|
v |= akiko.i2c_scl_dir << 15;
|
|
v |= akiko.i2c_sda_dir << 14;
|
|
|
|
return v;
|
|
}
|
|
|
|
NVRAM_HANDLER( cd32 )
|
|
{
|
|
nvram_handler_i2cmem_0( machine, file, read_or_write );
|
|
}
|
|
|
|
/*************************************
|
|
*
|
|
* Akiko Chunky to Planar converter
|
|
*
|
|
************************************/
|
|
|
|
static void akiko_c2p_write(UINT32 data)
|
|
{
|
|
akiko.c2p_input_buffer[akiko.c2p_input_index] = data;
|
|
akiko.c2p_input_index++;
|
|
akiko.c2p_input_index &= 7;
|
|
akiko.c2p_output_index = 0;
|
|
}
|
|
|
|
static UINT32 akiko_c2p_read(void)
|
|
{
|
|
UINT32 val;
|
|
|
|
if ( akiko.c2p_output_index == 0 )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; i < 8; i++ )
|
|
akiko.c2p_output_buffer[i] = 0;
|
|
|
|
for (i = 0; i < 8 * 32; i++) {
|
|
if (akiko.c2p_input_buffer[7 - (i >> 5)] & (1 << (i & 31)))
|
|
akiko.c2p_output_buffer[i & 7] |= 1 << (i >> 3);
|
|
}
|
|
}
|
|
akiko.c2p_input_index = 0;
|
|
val = akiko.c2p_output_buffer[akiko.c2p_output_index];
|
|
akiko.c2p_output_index++;
|
|
akiko.c2p_output_index &= 7;
|
|
return val;
|
|
}
|
|
|
|
#if LOG_AKIKO
|
|
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"
|
|
};
|
|
|
|
const char* get_akiko_reg_name(int reg)
|
|
{
|
|
if (reg < 0xf )
|
|
{
|
|
return akiko_reg_names[reg];
|
|
}
|
|
else
|
|
{
|
|
return "???";
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*************************************
|
|
*
|
|
* Akiko CDROM Controller
|
|
*
|
|
************************************/
|
|
|
|
static void akiko_cdda_stop( void )
|
|
{
|
|
int cddanum = cdda_num_from_cdrom(akiko.cdrom);
|
|
|
|
if (cddanum != -1)
|
|
{
|
|
cdda_stop_audio(cddanum);
|
|
timer_reset( akiko.frame_timer, attotime_never );
|
|
}
|
|
}
|
|
|
|
static void akiko_cdda_play( UINT32 lba, UINT32 num_blocks )
|
|
{
|
|
int cddanum = cdda_num_from_cdrom(akiko.cdrom);
|
|
if (cddanum != -1)
|
|
{
|
|
cdda_start_audio(cddanum, lba, num_blocks);
|
|
timer_adjust( akiko.frame_timer, ATTOTIME_IN_HZ( 75 ), 0, attotime_zero );
|
|
}
|
|
}
|
|
|
|
static void akiko_cdda_pause( int pause )
|
|
{
|
|
int cddanum = cdda_num_from_cdrom(akiko.cdrom);
|
|
if (cddanum != -1)
|
|
{
|
|
if (cdda_audio_active(cddanum) && cdda_audio_paused(cddanum) != pause )
|
|
{
|
|
cdda_pause_audio(cddanum, pause);
|
|
|
|
if ( pause )
|
|
{
|
|
timer_reset( akiko.frame_timer, attotime_never );
|
|
}
|
|
else
|
|
{
|
|
timer_adjust( akiko.frame_timer, ATTOTIME_IN_HZ( 75 ), 0, attotime_zero );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static UINT8 akiko_cdda_getstatus( UINT32 *lba )
|
|
{
|
|
int cddanum = cdda_num_from_cdrom(akiko.cdrom);
|
|
|
|
if ( lba ) *lba = 0;
|
|
|
|
if (cddanum != -1)
|
|
{
|
|
if (cdda_audio_active(cddanum))
|
|
{
|
|
if ( lba ) *lba = cdda_get_audio_lba(cddanum);
|
|
|
|
if (cdda_audio_paused(cddanum))
|
|
{
|
|
return 0x12; /* audio paused */
|
|
}
|
|
else
|
|
{
|
|
return 0x11; /* audio in progress */
|
|
}
|
|
}
|
|
else if (cdda_audio_ended(cddanum))
|
|
{
|
|
return 0x13; /* audio ended */
|
|
}
|
|
}
|
|
|
|
return 0x15; /* no audio status */
|
|
}
|
|
|
|
static void akiko_set_cd_status( UINT32 status )
|
|
{
|
|
akiko.cdrom_status[0] |= status;
|
|
|
|
if ( akiko.cdrom_status[0] & akiko.cdrom_status[1] )
|
|
{
|
|
#if LOG_AKIKO_CD
|
|
logerror( "Akiko CD IRQ\n" );
|
|
#endif
|
|
amiga_custom_w(REG_INTREQ, 0x8000 | INTENA_PORTS, 0);
|
|
}
|
|
}
|
|
|
|
static TIMER_CALLBACK(akiko_frame_proc)
|
|
{
|
|
int cddanum = cdda_num_from_cdrom(akiko.cdrom);
|
|
|
|
(void)param;
|
|
|
|
if (cddanum != -1)
|
|
{
|
|
UINT8 s = akiko_cdda_getstatus(NULL);
|
|
|
|
if ( s == 0x11 )
|
|
{
|
|
akiko_set_cd_status( 0x80000000 ); /* subcode ready */
|
|
}
|
|
|
|
timer_adjust( akiko.frame_timer, ATTOTIME_IN_HZ( 75 ), 0, attotime_zero );
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static TIMER_CALLBACK(akiko_dma_proc)
|
|
{
|
|
UINT8 buf[2352];
|
|
int index;
|
|
|
|
if ( (akiko.cdrom_dmacontrol & 0x04000000) == 0 )
|
|
return;
|
|
|
|
if ( akiko.cdrom_readreqmask == 0 )
|
|
return;
|
|
|
|
index = (akiko.cdrom_lba_cur - akiko.cdrom_lba_start) & 0x0f;
|
|
|
|
if ( akiko.cdrom_readreqmask & ( 1 << index ) )
|
|
{
|
|
UINT32 track = cdrom_get_track( akiko.cdrom, akiko.cdrom_lba_cur );
|
|
UINT32 datasize = cdrom_get_toc( akiko.cdrom )->tracks[track].datasize;
|
|
UINT32 subsize = cdrom_get_toc( akiko.cdrom )->tracks[track].subsize;
|
|
UINT32 secsize = datasize + subsize;
|
|
int i;
|
|
|
|
if ( secsize <= (2352-16) )
|
|
{
|
|
UINT32 curmsf = lba_to_msf( akiko.cdrom_lba_cur );
|
|
memset( buf, 0, 16 );
|
|
|
|
buf[3] = akiko.cdrom_lba_cur - akiko.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 */
|
|
|
|
if ( !cdrom_read_data( akiko.cdrom, akiko.cdrom_lba_cur, &buf[16], CD_TRACK_RAW_DONTCARE ) )
|
|
{
|
|
logerror( "AKIKO: Read error trying to read sector %08x!\n", akiko.cdrom_lba_cur );
|
|
return;
|
|
}
|
|
|
|
if ( subsize )
|
|
{
|
|
if ( !cdrom_read_subcode( akiko.cdrom, akiko.cdrom_lba_cur, &buf[16+datasize] ) )
|
|
{
|
|
logerror( "AKIKO: Read error trying to read subcode for sector %08x!\n", akiko.cdrom_lba_cur );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !cdrom_read_data( akiko.cdrom, akiko.cdrom_lba_cur, buf, CD_TRACK_RAW_DONTCARE) )
|
|
{
|
|
logerror( "AKIKO: Read error trying to read sector %08x!\n", akiko.cdrom_lba_cur );
|
|
return;
|
|
}
|
|
|
|
if ( subsize )
|
|
{
|
|
if ( !cdrom_read_subcode( akiko.cdrom, akiko.cdrom_lba_cur, &buf[datasize] ) )
|
|
{
|
|
logerror( "AKIKO: Read error trying to read subcode for sector %08x!\n", akiko.cdrom_lba_cur );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if LOG_AKIKO_CD
|
|
logerror( "DMA: sector %d - address %08x\n", akiko.cdrom_lba_cur, akiko.cdrom_address[0] + (index*4096) );
|
|
#endif
|
|
|
|
for( i = 0; i < 2352; i += 2 )
|
|
{
|
|
UINT16 data;
|
|
|
|
data = buf[i];
|
|
data <<= 8;
|
|
data |= buf[i+1];
|
|
|
|
amiga_chip_ram_w( akiko.cdrom_address[0] + (index*4096) + i, data );
|
|
}
|
|
|
|
akiko.cdrom_readmask |= ( 1 << index );
|
|
akiko.cdrom_readreqmask &= ~( 1 << index );
|
|
akiko.cdrom_lba_cur++;
|
|
}
|
|
|
|
if ( akiko.cdrom_readreqmask == 0 )
|
|
akiko_set_cd_status(0x04000000);
|
|
else
|
|
timer_adjust( akiko.dma_timer, ATTOTIME_IN_USEC( CD_SECTOR_TIME / akiko.cdrom_speed ), 0, attotime_zero );
|
|
}
|
|
|
|
static void akiko_start_dma( void )
|
|
{
|
|
if ( akiko.cdrom_readreqmask == 0 )
|
|
return;
|
|
|
|
if ( akiko.cdrom_lba_start > akiko.cdrom_lba_end )
|
|
return;
|
|
|
|
if ( akiko.cdrom_speed == 0 )
|
|
return;
|
|
|
|
akiko.cdrom_lba_cur = akiko.cdrom_lba_start;
|
|
|
|
timer_adjust( akiko.dma_timer, ATTOTIME_IN_USEC( CD_SECTOR_TIME / akiko.cdrom_speed ), 0, attotime_zero );
|
|
}
|
|
|
|
static void akiko_setup_response( int len, UINT8 *r1 )
|
|
{
|
|
int resp_addr = akiko.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++ )
|
|
{
|
|
program_write_byte( resp_addr + ((akiko.cdrom_cmd_resp + i) & 0xff), resp_buffer[i] );
|
|
}
|
|
|
|
akiko.cdrom_cmd_resp = (akiko.cdrom_cmd_resp+len) & 0xff;
|
|
|
|
akiko_set_cd_status( 0x10000000 ); /* new data available */
|
|
}
|
|
|
|
static TIMER_CALLBACK( akiko_cd_delayed_cmd )
|
|
{
|
|
UINT8 resp[32];
|
|
UINT8 cddastatus;
|
|
|
|
if ( akiko.cdrom_status[0] & 0x10000000 )
|
|
return;
|
|
|
|
cddastatus = akiko_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 );
|
|
#endif
|
|
|
|
resp[0] = 0x06;
|
|
|
|
if ( akiko.cdrom == NULL || akiko.cdrom_numtracks == 0 )
|
|
{
|
|
resp[1] = 0x80;
|
|
akiko_setup_response( 15, resp );
|
|
}
|
|
else
|
|
{
|
|
resp[1] = 0x00;
|
|
memcpy( &resp[2], &akiko.cdrom_toc[13*akiko.cdrom_track_index], 13 );
|
|
|
|
akiko.cdrom_track_index = ( akiko.cdrom_track_index + 1 ) % akiko.cdrom_numtracks;
|
|
|
|
akiko_setup_response( 15, resp );
|
|
}
|
|
}
|
|
}
|
|
|
|
static void akiko_update_cdrom( void )
|
|
{
|
|
UINT8 resp[32], cmdbuf[32];
|
|
|
|
if ( akiko.cdrom_status[0] & 0x10000000 )
|
|
return;
|
|
|
|
while ( akiko.cdrom_cmd_start != akiko.cdrom_cmd_end )
|
|
{
|
|
UINT32 cmd_addr = akiko.cdrom_address[1] + 0x200 + akiko.cdrom_cmd_start;
|
|
int cmd = program_read_byte( cmd_addr );
|
|
|
|
memset( resp, 0, sizeof( resp ) );
|
|
resp[0] = cmd;
|
|
|
|
cmd &= 0x0f;
|
|
|
|
#if LOG_AKIKO_CD
|
|
logerror( "CDROM command: %02X\n", cmd );
|
|
#endif
|
|
|
|
if ( cmd == 0x02 ) /* pause audio */
|
|
{
|
|
resp[1] = 0x00;
|
|
|
|
if ( akiko_cdda_getstatus(NULL) == 0x11 )
|
|
resp[1] = 0x08;
|
|
|
|
akiko_cdda_pause( 1 );
|
|
|
|
akiko.cdrom_cmd_start = (akiko.cdrom_cmd_start+2) & 0xff;
|
|
|
|
akiko_setup_response( 2, resp );
|
|
}
|
|
else if ( cmd == 0x03 ) /* unpause audio (and check audiocd playing status) */
|
|
{
|
|
resp[1] = 0x00;
|
|
|
|
if ( akiko_cdda_getstatus(NULL) == 0x11 )
|
|
resp[1] = 0x08;
|
|
|
|
akiko_cdda_pause( 0 );
|
|
|
|
akiko.cdrom_cmd_start = (akiko.cdrom_cmd_start+2) & 0xff;
|
|
|
|
akiko_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] = program_read_byte( cmd_addr );
|
|
cmd_addr &= 0xffffff00;
|
|
cmd_addr += ( akiko.cdrom_cmd_start + i + 1 ) & 0xff;
|
|
}
|
|
|
|
akiko.cdrom_cmd_start = (akiko.cdrom_cmd_start+13) & 0xff;
|
|
|
|
if ( akiko.cdrom == NULL || akiko.cdrom_numtracks == 0 )
|
|
{
|
|
resp[1] = 0x80;
|
|
akiko_setup_response( 2, resp );
|
|
}
|
|
else
|
|
{
|
|
startpos = lba_from_triplet( &cmdbuf[1] );
|
|
endpos = lba_from_triplet( &cmdbuf[4] );
|
|
|
|
akiko_cdda_stop();
|
|
|
|
resp[1] = 0x00;
|
|
|
|
if ( cmdbuf[7] == 0x80 )
|
|
{
|
|
#if LOG_AKIKO_CD
|
|
logerror( "AKIKO CD: PC:%06x Data read - start lba: %08x - end lba: %08x\n", safe_activecpu_get_pc(), startpos, endpos );
|
|
#endif
|
|
akiko.cdrom_speed = (cmdbuf[8] & 0x40) ? 2 : 1;
|
|
akiko.cdrom_lba_start = startpos;
|
|
akiko.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 );
|
|
akiko_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 );
|
|
#endif
|
|
akiko.cdrom_track_index = 0;
|
|
|
|
for( i = 0; i < cdrom_get_last_track(akiko.cdrom); i++ )
|
|
{
|
|
if ( startpos <= cdrom_get_track_start( akiko.cdrom, i ) )
|
|
{
|
|
/* reset to 0 */
|
|
akiko.cdrom_track_index = i + 2;
|
|
akiko.cdrom_track_index %= akiko.cdrom_numtracks;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
akiko_setup_response( 2, resp );
|
|
}
|
|
}
|
|
else if ( cmd == 0x05 ) /* read toc */
|
|
{
|
|
akiko.cdrom_cmd_start = (akiko.cdrom_cmd_start+3) & 0xff;
|
|
|
|
timer_set( ATTOTIME_IN_MSEC(1), NULL, resp[0], akiko_cd_delayed_cmd );
|
|
|
|
break;
|
|
}
|
|
else if ( cmd == 0x06 ) /* read subq */
|
|
{
|
|
UINT32 lba;
|
|
|
|
resp[1] = 0x00;
|
|
|
|
(void)akiko_cdda_getstatus( &lba );
|
|
|
|
if ( lba > 0 )
|
|
{
|
|
UINT32 disk_pos;
|
|
UINT32 track_pos;
|
|
UINT32 track;
|
|
int addrctrl;
|
|
|
|
track = cdrom_get_track(akiko.cdrom, lba);
|
|
addrctrl = cdrom_get_adr_control(akiko.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(akiko.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;
|
|
}
|
|
|
|
akiko_setup_response( 15, resp );
|
|
}
|
|
else if ( cmd == 0x07 ) /* check door status */
|
|
{
|
|
resp[1] = 0x01;
|
|
|
|
akiko.cdrom_cmd_start = (akiko.cdrom_cmd_start+2) & 0xff;
|
|
|
|
if ( akiko.cdrom == NULL || akiko.cdrom_numtracks == 0 )
|
|
resp[1] = 0x80;
|
|
|
|
akiko_setup_response( 20, resp );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
READ32_HANDLER(amiga_akiko32_r)
|
|
{
|
|
UINT32 retval;
|
|
|
|
#if LOG_AKIKO
|
|
if ( offset < (0x30/4) )
|
|
{
|
|
logerror( "Reading AKIKO reg %0x [%s] at PC=%06x\n", offset, get_akiko_reg_name(offset), activecpu_get_pc() );
|
|
}
|
|
#endif
|
|
|
|
switch( offset )
|
|
{
|
|
case 0x00/4: /* ID */
|
|
if ( akiko.cdrom != NULL ) cdda_set_cdrom(0, akiko.cdrom);
|
|
return 0x0000cafe;
|
|
|
|
case 0x04/4: /* CDROM STATUS 1 */
|
|
return akiko.cdrom_status[0];
|
|
|
|
case 0x08/4: /* CDROM STATUS 2 */
|
|
return akiko.cdrom_status[1];
|
|
|
|
case 0x10/4: /* CDROM ADDRESS 1 */
|
|
return akiko.cdrom_address[0];
|
|
|
|
case 0x14/4: /* CDROM ADDRESS 2 */
|
|
return akiko.cdrom_address[1];
|
|
|
|
case 0x18/4: /* CDROM COMMAND 1 */
|
|
akiko_update_cdrom();
|
|
retval = akiko.cdrom_cmd_start;
|
|
retval <<= 8;
|
|
retval |= akiko.cdrom_cmd_resp;
|
|
retval <<= 8;
|
|
return retval;
|
|
|
|
case 0x1C/4: /* CDROM COMMAND 2 */
|
|
akiko_update_cdrom();
|
|
retval = akiko.cdrom_cmd_end;
|
|
retval <<= 16;
|
|
return retval;
|
|
|
|
case 0x20/4: /* CDROM DMA SECTOR READ MASK */
|
|
retval = akiko.cdrom_readmask << 16;
|
|
return retval;
|
|
|
|
case 0x24/4: /* CDROM DMA ENABLE? */
|
|
retval = akiko.cdrom_dmacontrol;
|
|
return retval;
|
|
|
|
case 0x30/4: /* NVRAM */
|
|
return akiko_nvram_read();
|
|
|
|
case 0x38/4: /* C2P */
|
|
return akiko_c2p_read();
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
WRITE32_HANDLER(amiga_akiko32_w)
|
|
{
|
|
#if LOG_AKIKO
|
|
if ( offset < (0x30/4) )
|
|
{
|
|
logerror( "Writing AKIKO reg %0x [%s] with %08x at PC=%06x\n", offset, get_akiko_reg_name(offset), data, activecpu_get_pc() );
|
|
}
|
|
#endif
|
|
|
|
switch( offset )
|
|
{
|
|
case 0x04/4: /* CDROM STATUS 1 */
|
|
akiko.cdrom_status[0] = data;
|
|
break;
|
|
|
|
case 0x08/4: /* CDROM STATUS 2 */
|
|
akiko.cdrom_status[1] = data;
|
|
akiko.cdrom_status[0] &= data;
|
|
break;
|
|
|
|
case 0x10/4: /* CDROM ADDRESS 1 */
|
|
akiko.cdrom_address[0] = data;
|
|
break;
|
|
|
|
case 0x14/4: /* CDROM ADDRESS 2 */
|
|
akiko.cdrom_address[1] = data;
|
|
break;
|
|
|
|
case 0x18/4: /* CDROM COMMAND 1 */
|
|
if ( ( mem_mask & 0x00ff0000 ) == 0 )
|
|
akiko.cdrom_cmd_start = ( data >> 16 ) & 0xff;
|
|
|
|
if ( ( mem_mask & 0x0000ff00 ) == 0 )
|
|
akiko.cdrom_cmd_resp = ( data >> 8 ) & 0xff;
|
|
|
|
akiko_update_cdrom();
|
|
break;
|
|
|
|
case 0x1C/4: /* CDROM COMMAND 2 */
|
|
if ( ( mem_mask & 0x00ff0000 ) == 0 )
|
|
akiko.cdrom_cmd_end = ( data >> 16 ) & 0xff;
|
|
|
|
akiko_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 );
|
|
#endif
|
|
if ( ( mem_mask & 0xffff0000 ) == 0 )
|
|
{
|
|
akiko.cdrom_readreqmask = (data >> 16);
|
|
akiko.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 );
|
|
#endif
|
|
if ( ( akiko.cdrom_dmacontrol ^ data ) & 0x04000000 )
|
|
{
|
|
if ( data & 0x04000000 )
|
|
akiko_start_dma();
|
|
}
|
|
akiko.cdrom_dmacontrol = data;
|
|
break;
|
|
|
|
case 0x30/4:
|
|
akiko_nvram_write(data);
|
|
break;
|
|
|
|
case 0x38/4:
|
|
akiko_c2p_write(data);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|