diff options
Diffstat (limited to 'src/emu/machine')
-rw-r--r-- | src/emu/machine/6525tpi.c | 6 | ||||
-rw-r--r-- | src/emu/machine/6525tpi.h | 12 | ||||
-rw-r--r-- | src/emu/machine/akiko.c | 925 | ||||
-rw-r--r-- | src/emu/machine/akiko.h | 153 | ||||
-rw-r--r-- | src/emu/machine/amigafdc.c | 7 | ||||
-rw-r--r-- | src/emu/machine/autoconfig.c | 167 | ||||
-rw-r--r-- | src/emu/machine/autoconfig.h | 72 | ||||
-rw-r--r-- | src/emu/machine/cr511b.c | 123 | ||||
-rw-r--r-- | src/emu/machine/cr511b.h | 152 | ||||
-rw-r--r-- | src/emu/machine/dmac.c | 467 | ||||
-rw-r--r-- | src/emu/machine/dmac.h | 173 | ||||
-rw-r--r-- | src/emu/machine/machine.mak | 40 |
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 #------------------------------------------------- |