1 // license:BSD-3-Clause
2 // copyright-holders:Mariusz Wojcieszek
3 /***************************************************************************
4 
5     Akiko
6 
7     ASIC used in the Amiga CD32. Commodore Part number 391563-01.
8 
9     - CD-ROM controller
10     - Builtin 1KB NVRAM
11     - Chunky to planar converter
12     - 2x CIA chips
13 
14 ***************************************************************************/
15 
16 #include "emu.h"
17 #include "akiko.h"
18 #include "coreutil.h"
19 #include "romload.h"
20 
21 
22 //**************************************************************************
23 //  CONSTANTS / MACROS
24 //**************************************************************************
25 
26 #define LOG_AKIKO       0
27 #define LOG_AKIKO_CD    0
28 
29 
30 //**************************************************************************
31 //  DEVICE DEFINITIONS
32 //**************************************************************************
33 
34 DEFINE_DEVICE_TYPE(AKIKO, akiko_device, "akiko", "CBM AKIKO")
35 
36 //-------------------------------------------------
37 //  device_add_mconfig - add device configuration
38 //-------------------------------------------------
39 
device_add_mconfig(machine_config & config)40 void akiko_device::device_add_mconfig(machine_config &config)
41 {
42 }
43 
44 
45 //**************************************************************************
46 //  LIVE DEVICE
47 //**************************************************************************
48 
49 //-------------------------------------------------
50 //  akiko_device - constructor
51 //-------------------------------------------------
52 
akiko_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)53 akiko_device::akiko_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
54 	: device_t(mconfig, AKIKO, tag, owner, clock),
55 	m_c2p_input_index(0),
56 	m_c2p_output_index(0),
57 	m_i2c_scl_out(0),
58 	m_i2c_scl_dir(0),
59 	m_i2c_sda_out(0),
60 	m_i2c_sda_dir(0),
61 	m_cdrom_track_index(0),
62 	m_cdrom_lba_start(0),
63 	m_cdrom_lba_end(0),
64 	m_cdrom_lba_cur(0),
65 	m_cdrom_readmask(0),
66 	m_cdrom_readreqmask(0),
67 	m_cdrom_dmacontrol(0),
68 	m_cdrom_numtracks(0),
69 	m_cdrom_speed(0),
70 	m_cdrom_cmd_start(0),
71 	m_cdrom_cmd_end(0),
72 	m_cdrom_cmd_resp(0),
73 	m_cdda(*this, "^cdda"),
74 	m_cddevice(*this, "^cdrom"),
75 	m_cdrom(nullptr),
76 	m_cdrom_toc(nullptr),
77 	m_dma_timer(nullptr),
78 	m_frame_timer(nullptr),
79 	m_mem_r(*this), m_mem_w(*this), m_int_w(*this),
80 	m_scl_w(*this), m_sda_r(*this), m_sda_w(*this)
81 {
82 	for (int i = 0; i < 8; i++)
83 	{
84 		m_c2p_input_buffer[i] = 0;
85 		m_c2p_output_buffer[i] = 0;
86 	}
87 
88 	for (int i = 0; i < 2; i++)
89 	{
90 		m_cdrom_status[i] = 0;
91 		m_cdrom_address[i] = 0;
92 	}
93 }
94 
95 //-------------------------------------------------
96 //  device_start - device-specific startup
97 //-------------------------------------------------
98 
device_start()99 void akiko_device::device_start()
100 {
101 	// resolve callbacks
102 	m_mem_r.resolve_safe(0xffff);
103 	m_mem_w.resolve_safe();
104 	m_int_w.resolve_safe();
105 	m_scl_w.resolve_safe();
106 	m_sda_r.resolve_safe(1);
107 	m_sda_w.resolve_safe();
108 
109 	m_c2p_input_index = 0;
110 	m_c2p_output_index = 0;
111 
112 	m_i2c_scl_out = 0;
113 	m_i2c_scl_dir = 0;
114 	m_i2c_sda_out = 0;
115 	m_i2c_sda_dir = 0;
116 
117 	m_cdrom_status[0] = m_cdrom_status[1] = 0;
118 	m_cdrom_address[0] = m_cdrom_address[1] = 0;
119 	m_cdrom_track_index = 0;
120 	m_cdrom_lba_start = 0;
121 	m_cdrom_lba_end = 0;
122 	m_cdrom_lba_cur = 0;
123 	m_cdrom_readmask = 0;
124 	m_cdrom_readreqmask = 0;
125 	m_cdrom_dmacontrol = 0;
126 	m_cdrom_numtracks = 0;
127 	m_cdrom_speed = 0;
128 	m_cdrom_cmd_start = 0;
129 	m_cdrom_cmd_end = 0;
130 	m_cdrom_cmd_resp = 0;
131 
132 	m_cdrom_toc = nullptr;
133 	m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(akiko_device::dma_proc), this));
134 	m_frame_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(akiko_device::frame_proc), this));
135 }
136 
137 //-------------------------------------------------
138 //  device_reset - device-specific reset
139 //-------------------------------------------------
140 
device_reset()141 void akiko_device::device_reset()
142 {
143 	if (m_cddevice.found())
144 	{
145 		// MESS case
146 		m_cdrom = m_cddevice->get_cdrom_file();
147 	}
148 	else
149 	{
150 		// MAME case
151 		m_cdrom = cdrom_open(machine().rom_load().get_disk_handle(":cdrom"));
152 	}
153 
154 	/* create the TOC table */
155 	if ( m_cdrom != nullptr && cdrom_get_last_track(m_cdrom) )
156 	{
157 		uint8_t *p;
158 		int     i, addrctrl = cdrom_get_adr_control( m_cdrom, 0 );
159 		uint32_t  discend;
160 
161 		discend = cdrom_get_track_start(m_cdrom,cdrom_get_last_track(m_cdrom)-1);
162 		discend += cdrom_get_toc(m_cdrom)->tracks[cdrom_get_last_track(m_cdrom)-1].frames;
163 		discend = lba_to_msf(discend);
164 
165 		m_cdrom_numtracks = cdrom_get_last_track(m_cdrom)+3;
166 
167 		m_cdrom_toc = std::make_unique<uint8_t[]>(13*m_cdrom_numtracks);
168 		memset( m_cdrom_toc.get(), 0, 13*m_cdrom_numtracks);
169 
170 		p = m_cdrom_toc.get();
171 		p[1] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4);
172 		p[3] = 0xa0; /* first track */
173 		p[8] = 1;
174 		p += 13;
175 		p[1] = 0x01;
176 		p[3] = 0xa1; /* last track */
177 		p[8] = cdrom_get_last_track(m_cdrom);
178 		p += 13;
179 		p[1] = 0x01;
180 		p[3] = 0xa2; /* disc end */
181 		p[8] = (discend >> 16 ) & 0xff;
182 		p[9] = (discend >> 8 ) & 0xff;
183 		p[10] = discend & 0xff;
184 		p += 13;
185 
186 		for( i = 0; i < cdrom_get_last_track(m_cdrom); i++ )
187 		{
188 			uint32_t  trackpos = cdrom_get_track_start(m_cdrom,i);
189 
190 			trackpos = lba_to_msf(trackpos);
191 			addrctrl = cdrom_get_adr_control( m_cdrom, i );
192 
193 			p[1] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4);
194 			p[3] = dec_2_bcd( i+1 );
195 			p[8] = (trackpos >> 16 ) & 0xff;
196 			p[9] = (trackpos >> 8 ) & 0xff;
197 			p[10] = trackpos & 0xff;
198 
199 			p += 13;
200 		}
201 	}
202 
203 }
204 
205 //-------------------------------------------------
206 //  device_stop - device-specific stop
207 //-------------------------------------------------
208 
device_stop()209 void akiko_device::device_stop()
210 {
211 	if (!m_cddevice.found())
212 	{
213 		if( m_cdrom )
214 		{
215 			cdrom_close(m_cdrom);
216 			m_cdrom = (cdrom_file *)nullptr;
217 		}
218 	}
219 }
220 
nvram_write(uint32_t data)221 void akiko_device::nvram_write(uint32_t data)
222 {
223 	m_i2c_scl_out = BIT(data, 31);
224 	m_i2c_sda_out = BIT(data, 30);
225 	m_i2c_scl_dir = BIT(data, 15);
226 	m_i2c_sda_dir = BIT(data, 14);
227 
228 	m_scl_w(m_i2c_scl_out);
229 	m_sda_w(m_i2c_sda_out);
230 }
231 
nvram_read()232 uint32_t akiko_device::nvram_read()
233 {
234 	uint32_t v = 0;
235 
236 	if (m_i2c_scl_dir)
237 		v |= m_i2c_scl_out << 31;
238 
239 	if (m_i2c_sda_dir)
240 		v |= m_i2c_sda_out << 30;
241 	else
242 		v |= m_sda_r() << 30;
243 
244 	v |= m_i2c_scl_dir << 15;
245 	v |= m_i2c_sda_dir << 14;
246 
247 	return v;
248 }
249 
mem_r8(offs_t offset)250 uint8_t akiko_device::mem_r8(offs_t offset)
251 {
252 	int shift = (offset & 1) ? 0 : 8;
253 	return m_mem_r(offset, 0xff << shift) >> shift;
254 }
255 
mem_w8(offs_t offset,uint8_t data)256 void akiko_device::mem_w8(offs_t offset, uint8_t data)
257 {
258 	int shift = (offset & 1) ? 0 : 8;
259 	m_mem_w(offset, data << shift, 0xff << shift);
260 }
261 
262 
263 /*************************************
264  *
265  * Akiko Chunky to Planar converter
266  *
267  ************************************/
268 
c2p_write(uint32_t data)269 void akiko_device::c2p_write(uint32_t data)
270 {
271 	m_c2p_input_buffer[m_c2p_input_index] = data;
272 	m_c2p_input_index++;
273 	m_c2p_input_index &= 7;
274 	m_c2p_output_index = 0;
275 }
276 
c2p_read()277 uint32_t akiko_device::c2p_read()
278 {
279 	uint32_t val;
280 
281 	if ( m_c2p_output_index == 0 )
282 	{
283 		int i;
284 
285 		for ( i = 0; i < 8; i++ )
286 			m_c2p_output_buffer[i] = 0;
287 
288 		for (i = 0; i < 8 * 32; i++)
289 		{
290 			if (m_c2p_input_buffer[7 - (i >> 5)] & (1 << (i & 31)))
291 				m_c2p_output_buffer[i & 7] |= 1 << (i >> 3);
292 		}
293 	}
294 	m_c2p_input_index = 0;
295 	val = m_c2p_output_buffer[m_c2p_output_index];
296 	m_c2p_output_index++;
297 	m_c2p_output_index &= 7;
298 	return val;
299 }
300 
301 static const char *const akiko_reg_names[] =
302 {
303 	/*0*/   "ID",
304 	/*1*/   "CDROM STATUS 1",
305 	/*2*/   "CDROM_STATUS 2",
306 	/*3*/   "???",
307 	/*4*/   "CDROM ADDRESS 1",
308 	/*5*/   "CDROM ADDRESS 2",
309 	/*6*/   "CDROM COMMAND 1",
310 	/*7*/   "CDROM COMMAND 2",
311 	/*8*/   "CDROM READMASK",
312 	/*9*/   "CDROM DMACONTROL",
313 	/*A*/   "???",
314 	/*B*/   "???",
315 	/*C*/   "NVRAM",
316 	/*D*/   "???",
317 	/*E*/   "C2P"
318 };
319 
get_akiko_reg_name(int reg)320 static const char* get_akiko_reg_name(int reg)
321 {
322 	if (reg < 0xf )
323 	{
324 		return akiko_reg_names[reg];
325 	}
326 	else
327 	{
328 		return "???";
329 	}
330 }
331 
332 /*************************************
333  *
334  * Akiko CDROM Controller
335  *
336  ************************************/
337 
cdda_stop()338 void akiko_device::cdda_stop()
339 {
340 	if (m_cdda != nullptr)
341 	{
342 		m_cdda->stop_audio();
343 		m_frame_timer->reset(  );
344 	}
345 }
346 
cdda_play(uint32_t lba,uint32_t num_blocks)347 void akiko_device::cdda_play(uint32_t lba, uint32_t num_blocks)
348 {
349 	if (m_cdda != nullptr)
350 	{
351 		m_cdda->start_audio(lba, num_blocks);
352 		m_frame_timer->adjust( attotime::from_hz( 75 ) );
353 	}
354 }
355 
cdda_pause(int pause)356 void akiko_device::cdda_pause(int pause)
357 {
358 	if (m_cdda != nullptr)
359 	{
360 		if (m_cdda->audio_active() && m_cdda->audio_paused() != pause )
361 		{
362 			m_cdda->pause_audio(pause);
363 
364 			if ( pause )
365 			{
366 				m_frame_timer->reset(  );
367 			}
368 			else
369 			{
370 				m_frame_timer->adjust( attotime::from_hz( 75 ) );
371 			}
372 		}
373 	}
374 }
375 
cdda_getstatus(uint32_t * lba)376 uint8_t akiko_device::cdda_getstatus(uint32_t *lba)
377 {
378 	if ( lba ) *lba = 0;
379 
380 	if (m_cdda != nullptr)
381 	{
382 		if (m_cdda->audio_active())
383 		{
384 			if ( lba ) *lba = m_cdda->get_audio_lba();
385 
386 			if (m_cdda->audio_paused())
387 			{
388 				return 0x12;    /* audio paused */
389 			}
390 			else
391 			{
392 				return 0x11;    /* audio in progress */
393 			}
394 		}
395 		else if (m_cdda->audio_ended())
396 		{
397 			return 0x13;    /* audio ended */
398 		}
399 	}
400 
401 	return 0x15;    /* no audio status */
402 }
403 
set_cd_status(uint32_t status)404 void akiko_device::set_cd_status(uint32_t status)
405 {
406 	m_cdrom_status[0] |= status;
407 
408 	if ( m_cdrom_status[0] & m_cdrom_status[1] )
409 	{
410 		if (LOG_AKIKO_CD)
411 			logerror("Akiko CD IRQ\n");
412 
413 		m_int_w(1);
414 	}
415 }
416 
TIMER_CALLBACK_MEMBER(akiko_device::frame_proc)417 TIMER_CALLBACK_MEMBER(akiko_device::frame_proc)
418 {
419 	(void)param;
420 
421 	if (m_cdda != nullptr)
422 	{
423 		uint8_t   s = cdda_getstatus(nullptr);
424 
425 		if ( s == 0x11 )
426 		{
427 			set_cd_status(0x80000000); /* subcode ready */
428 		}
429 
430 		m_frame_timer->adjust( attotime::from_hz( 75 ) );
431 	}
432 }
433 
lba_from_triplet(uint8_t * triplet)434 static uint32_t lba_from_triplet( uint8_t *triplet )
435 {
436 	uint32_t  r;
437 
438 	r = bcd_2_dec(triplet[0]) * (60*75);
439 	r += bcd_2_dec(triplet[1]) * 75;
440 	r += bcd_2_dec(triplet[2]);
441 
442 	return r;
443 }
444 
TIMER_CALLBACK_MEMBER(akiko_device::dma_proc)445 TIMER_CALLBACK_MEMBER(akiko_device::dma_proc)
446 {
447 	uint8_t   buf[2352];
448 	int     index;
449 
450 	if ( (m_cdrom_dmacontrol & 0x04000000) == 0 )
451 		return;
452 
453 	if ( m_cdrom_readreqmask == 0 )
454 		return;
455 
456 	index = (m_cdrom_lba_cur - m_cdrom_lba_start) & 0x0f;
457 
458 	if ( m_cdrom_readreqmask & ( 1 << index ) )
459 	{
460 		uint32_t  track = cdrom_get_track( m_cdrom, m_cdrom_lba_cur );
461 		uint32_t  datasize;// = cdrom_get_toc(m_cdrom)->tracks[track].datasize;
462 		uint32_t  subsize = cdrom_get_toc( m_cdrom )->tracks[track].subsize;
463 
464 		uint32_t  curmsf = lba_to_msf( m_cdrom_lba_cur );
465 		memset( buf, 0, 16 );
466 
467 		buf[3] = m_cdrom_lba_cur - m_cdrom_lba_start;
468 		memset( &buf[4], 0xff, 8 );
469 
470 		buf[12] = (curmsf >> 16) & 0xff;
471 		buf[13] = (curmsf >> 8) & 0xff;
472 		buf[14] = curmsf & 0xff;
473 		buf[15] = 0x01; /* mode1 */
474 
475 		datasize = 2048;
476 		if ( !cdrom_read_data( m_cdrom, m_cdrom_lba_cur, &buf[16], CD_TRACK_MODE1 ) )
477 		{
478 			logerror( "AKIKO: Read error trying to read sector %08x!\n", m_cdrom_lba_cur );
479 			return;
480 		}
481 
482 		if ( subsize )
483 		{
484 			if ( !cdrom_read_subcode( m_cdrom, m_cdrom_lba_cur, &buf[16+datasize] ) )
485 			{
486 				logerror( "AKIKO: Read error trying to read subcode for sector %08x!\n", m_cdrom_lba_cur );
487 				return;
488 			}
489 		}
490 
491 		if (LOG_AKIKO_CD) logerror( "DMA: sector %d - address %08x\n", m_cdrom_lba_cur, m_cdrom_address[0] + (index*4096) );
492 
493 		// write sector data to host memory
494 		for (int i = 0; i < 2352; i++)
495 			mem_w8(m_cdrom_address[0] + (index*4096) + i, buf[i]);
496 
497 		m_cdrom_readmask |= ( 1 << index );
498 		m_cdrom_readreqmask &= ~( 1 << index );
499 		m_cdrom_lba_cur++;
500 	}
501 
502 	if ( m_cdrom_readreqmask == 0 )
503 		set_cd_status(0x04000000);
504 	else
505 		m_dma_timer->adjust( attotime::from_usec( CD_SECTOR_TIME / m_cdrom_speed ) );
506 }
507 
start_dma()508 void akiko_device::start_dma()
509 {
510 	if ( m_cdrom_readreqmask == 0 )
511 		return;
512 
513 	if ( m_cdrom_lba_start > m_cdrom_lba_end )
514 		return;
515 
516 	if ( m_cdrom_speed == 0 )
517 		return;
518 
519 	m_cdrom_lba_cur = m_cdrom_lba_start;
520 
521 	m_dma_timer->adjust( attotime::from_usec( CD_SECTOR_TIME / m_cdrom_speed ) );
522 }
523 
setup_response(int len,uint8_t * r1)524 void akiko_device::setup_response( int len, uint8_t *r1 )
525 {
526 	int     resp_addr = m_cdrom_address[1];
527 	uint8_t   resp_csum = 0xff;
528 	uint8_t   resp_buffer[32];
529 	int     i;
530 
531 	memset( resp_buffer, 0, sizeof( resp_buffer ) );
532 
533 	for( i = 0; i < len; i++ )
534 	{
535 		resp_buffer[i] = r1[i];
536 		resp_csum -= resp_buffer[i];
537 	}
538 
539 	resp_buffer[len++] = resp_csum;
540 
541 	for( i = 0; i < len; i++ )
542 	{
543 		offs_t addr = resp_addr + ((m_cdrom_cmd_resp + i) & 0xff);
544 		mem_w8(addr, resp_buffer[i]);
545 	}
546 
547 	m_cdrom_cmd_resp = (m_cdrom_cmd_resp+len) & 0xff;
548 
549 	set_cd_status(0x10000000); /* new data available */
550 }
551 
TIMER_CALLBACK_MEMBER(akiko_device::cd_delayed_cmd)552 TIMER_CALLBACK_MEMBER( akiko_device::cd_delayed_cmd )
553 {
554 	uint8_t   resp[32];
555 	uint8_t   cddastatus;
556 
557 	if ( m_cdrom_status[0] & 0x10000000 )
558 		return;
559 
560 	cddastatus = cdda_getstatus(nullptr);
561 
562 	if ( cddastatus == 0x11 || cddastatus == 0x12 )
563 		return;
564 
565 	memset( resp, 0, sizeof( resp ) );
566 	resp[0] = param;
567 
568 	param &= 0x0f;
569 
570 	if ( param == 0x05 )
571 	{
572 		if (LOG_AKIKO_CD) logerror( "AKIKO: Completing Command %d\n", param );
573 
574 		resp[0] = 0x06;
575 
576 		if ( m_cdrom == nullptr || m_cdrom_numtracks == 0 )
577 		{
578 			resp[1] = 0x80;
579 			setup_response( 15, resp );
580 		}
581 		else
582 		{
583 			resp[1] = 0x00;
584 			memcpy( &resp[2], &m_cdrom_toc[13*m_cdrom_track_index], 13 );
585 
586 			m_cdrom_track_index = ( m_cdrom_track_index + 1 ) % m_cdrom_numtracks;
587 
588 			setup_response( 15, resp );
589 		}
590 	}
591 }
592 
update_cdrom()593 void akiko_device::update_cdrom()
594 {
595 	uint8_t   resp[32], cmdbuf[32];
596 
597 	if ( m_cdrom_status[0] & 0x10000000 )
598 		return;
599 
600 	while ( m_cdrom_cmd_start != m_cdrom_cmd_end )
601 	{
602 		uint32_t  cmd_addr = m_cdrom_address[1] + 0x200 + m_cdrom_cmd_start;
603 		uint8_t cmd = mem_r8(cmd_addr);
604 
605 		memset( resp, 0, sizeof( resp ) );
606 		resp[0] = cmd;
607 
608 		cmd &= 0x0f;
609 
610 		if (LOG_AKIKO_CD) logerror( "CDROM command: %02X\n", cmd );
611 
612 		if ( cmd == 0x02 ) /* pause audio */
613 		{
614 			resp[1] = 0x00;
615 
616 			if ( cdda_getstatus(nullptr) == 0x11 )
617 				resp[1] = 0x08;
618 
619 			cdda_pause(1);
620 
621 			m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff;
622 
623 			setup_response( 2, resp );
624 		}
625 		else if ( cmd == 0x03 ) /* unpause audio (and check audiocd playing status) */
626 		{
627 			resp[1] = 0x00;
628 
629 			if ( cdda_getstatus(nullptr) == 0x11 )
630 				resp[1] = 0x08;
631 
632 			cdda_pause(0);
633 
634 			m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff;
635 
636 			setup_response( 2, resp );
637 		}
638 		else if ( cmd == 0x04 ) /* seek/read/play cd multi command */
639 		{
640 			int i;
641 			uint32_t  startpos, endpos;
642 
643 			for( i = 0; i < 13; i++ )
644 			{
645 				cmdbuf[i] = mem_r8(cmd_addr);
646 				cmd_addr &= 0xffffff00;
647 				cmd_addr += ( m_cdrom_cmd_start + i + 1 ) & 0xff;
648 			}
649 
650 			m_cdrom_cmd_start = (m_cdrom_cmd_start+13) & 0xff;
651 
652 			if ( m_cdrom == nullptr || m_cdrom_numtracks == 0 )
653 			{
654 				resp[1] = 0x80;
655 				setup_response( 2, resp );
656 			}
657 			else
658 			{
659 				startpos = lba_from_triplet( &cmdbuf[1] );
660 				endpos = lba_from_triplet( &cmdbuf[4] );
661 
662 				cdda_stop();
663 
664 				resp[1] = 0x00;
665 
666 				if ( cmdbuf[7] == 0x80 )
667 				{
668 					if (LOG_AKIKO_CD) logerror( "%s:AKIKO CD: Data read - start lba: %08x - end lba: %08x\n", machine().describe_context(), startpos, endpos );
669 					m_cdrom_speed = (cmdbuf[8] & 0x40) ? 2 : 1;
670 					m_cdrom_lba_start = startpos;
671 					m_cdrom_lba_end = endpos;
672 
673 					resp[1] = 0x02;
674 				}
675 				else if ( cmdbuf[10] & 0x04 )
676 				{
677 					logerror( "AKIKO CD: Audio Play - start lba: %08x - end lba: %08x\n", startpos, endpos );
678 					cdda_play(startpos, endpos - startpos);
679 					resp[1] = 0x08;
680 				}
681 				else
682 				{
683 					if (LOG_AKIKO_CD) logerror( "AKIKO CD: Seek - start lba: %08x - end lba: %08x\n", startpos, endpos );
684 					m_cdrom_track_index = 0;
685 
686 					for( i = 0; i < cdrom_get_last_track(m_cdrom); i++ )
687 					{
688 						if ( startpos <= cdrom_get_track_start( m_cdrom, i ) )
689 						{
690 							/* reset to 0 */
691 							m_cdrom_track_index = i + 2;
692 							m_cdrom_track_index %= m_cdrom_numtracks;
693 							break;
694 						}
695 					}
696 				}
697 
698 				setup_response( 2, resp );
699 			}
700 		}
701 		else if ( cmd == 0x05 ) /* read toc */
702 		{
703 			m_cdrom_cmd_start = (m_cdrom_cmd_start+3) & 0xff;
704 
705 			machine().scheduler().timer_set( attotime::from_msec(1), timer_expired_delegate(FUNC(akiko_device::cd_delayed_cmd ), this), resp[0]);
706 
707 			break;
708 		}
709 		else if ( cmd == 0x06 ) /* read subq */
710 		{
711 			uint32_t  lba;
712 
713 			resp[1] = 0x00;
714 
715 			(void)cdda_getstatus(&lba);
716 
717 			if ( lba > 0 )
718 			{
719 				uint32_t  disk_pos;
720 				uint32_t  track_pos;
721 				uint32_t  track;
722 				int     addrctrl;
723 
724 				track = cdrom_get_track(m_cdrom, lba);
725 				addrctrl = cdrom_get_adr_control(m_cdrom, track);
726 
727 				resp[2] = 0x00;
728 				resp[3] = ((addrctrl & 0x0f) << 4) | ((addrctrl & 0xf0) >> 4);
729 				resp[4] = dec_2_bcd(track+1);
730 				resp[5] = 0; /* index */
731 
732 				disk_pos = lba_to_msf(lba);
733 				track_pos = lba_to_msf(lba - cdrom_get_track_start(m_cdrom, track));
734 
735 				/* track position */
736 				resp[6] = (track_pos >> 16) & 0xff;
737 				resp[7] = (track_pos >> 8) & 0xff;
738 				resp[8] = track_pos & 0xff;
739 
740 				/* disk position */
741 				resp[9] = (disk_pos >> 24) & 0xff;
742 				resp[10] = (disk_pos >> 16) & 0xff;
743 				resp[11] = (disk_pos >> 8) & 0xff;
744 				resp[12] = disk_pos & 0xff;
745 			}
746 			else
747 			{
748 				resp[1] = 0x80;
749 			}
750 
751 			setup_response( 15, resp );
752 		}
753 		else if ( cmd == 0x07 ) /* check door status */
754 		{
755 			resp[1] = 0x01;
756 
757 			m_cdrom_cmd_start = (m_cdrom_cmd_start+2) & 0xff;
758 
759 			if ( m_cdrom == nullptr || m_cdrom_numtracks == 0 )
760 				resp[1] = 0x80;
761 
762 			setup_response( 20, resp );
763 			break;
764 		}
765 		else
766 		{
767 			break;
768 		}
769 	}
770 }
771 
read(offs_t offset)772 uint32_t akiko_device::read(offs_t offset)
773 {
774 	uint32_t      retval;
775 
776 	if ( LOG_AKIKO && offset < (0x30/4) )
777 	{
778 		logerror( "Reading AKIKO reg %0x [%s] at %s\n", offset, get_akiko_reg_name(offset), machine().describe_context());
779 	}
780 
781 	switch( offset )
782 	{
783 		case 0x00/4:    /* ID */
784 			if ( m_cdrom != nullptr ) m_cdda->set_cdrom(m_cdrom);
785 			return 0x0000cafe;
786 
787 		case 0x04/4:    /* CDROM STATUS 1 */
788 			return m_cdrom_status[0];
789 
790 		case 0x08/4:    /* CDROM STATUS 2 */
791 			return m_cdrom_status[1];
792 
793 		case 0x10/4:    /* CDROM ADDRESS 1 */
794 			return m_cdrom_address[0];
795 
796 		case 0x14/4:    /* CDROM ADDRESS 2 */
797 			return m_cdrom_address[1];
798 
799 		case 0x18/4:    /* CDROM COMMAND 1 */
800 			update_cdrom();
801 			retval = m_cdrom_cmd_start;
802 			retval <<= 8;
803 			retval |= m_cdrom_cmd_resp;
804 			retval <<= 8;
805 			return retval;
806 
807 		case 0x1C/4:    /* CDROM COMMAND 2 */
808 			update_cdrom();
809 			retval = m_cdrom_cmd_end;
810 			retval <<= 16;
811 			return retval;
812 
813 		case 0x20/4:    /* CDROM DMA SECTOR READ MASK */
814 			retval = m_cdrom_readmask << 16;
815 			return retval;
816 
817 		case 0x24/4:    /* CDROM DMA ENABLE? */
818 			retval = m_cdrom_dmacontrol;
819 			return retval;
820 
821 		case 0x30/4:    /* NVRAM */
822 			return nvram_read();
823 
824 		case 0x38/4:    /* C2P */
825 			return c2p_read();
826 
827 		default:
828 			break;
829 	}
830 
831 	return 0;
832 }
833 
write(offs_t offset,uint32_t data,uint32_t mem_mask)834 void akiko_device::write(offs_t offset, uint32_t data, uint32_t mem_mask)
835 {
836 	if ( LOG_AKIKO && offset < (0x30/4) )
837 	{
838 		logerror( "Writing AKIKO reg %0x [%s] with %08x at %s\n", offset, get_akiko_reg_name(offset), data, machine().describe_context());
839 	}
840 
841 	switch( offset )
842 	{
843 		case 0x04/4:    /* CDROM STATUS 1 */
844 			m_cdrom_status[0] = data;
845 			break;
846 
847 		case 0x08/4:    /* CDROM STATUS 2 */
848 			m_cdrom_status[1] = data;
849 			m_cdrom_status[0] &= data;
850 			break;
851 
852 		case 0x10/4:    /* CDROM ADDRESS 1 */
853 			m_cdrom_address[0] = data;
854 			break;
855 
856 		case 0x14/4:    /* CDROM ADDRESS 2 */
857 			m_cdrom_address[1] = data;
858 			break;
859 
860 		case 0x18/4:    /* CDROM COMMAND 1 */
861 			if ( ACCESSING_BITS_16_23 )
862 				m_cdrom_cmd_start = ( data >> 16 ) & 0xff;
863 
864 			if ( ACCESSING_BITS_8_15 )
865 				m_cdrom_cmd_resp = ( data >> 8 ) & 0xff;
866 
867 			update_cdrom();
868 			break;
869 
870 		case 0x1C/4:    /* CDROM COMMAND 2 */
871 			if ( ACCESSING_BITS_16_23 )
872 				m_cdrom_cmd_end = ( data >> 16 ) & 0xff;
873 
874 			update_cdrom();
875 			break;
876 
877 		case 0x20/4:    /* CDROM DMA SECTOR READ REQUEST WRITE */
878 			if (LOG_AKIKO_CD) logerror( "Read Req mask W: data %08x - mem mask %08x\n", data, mem_mask );
879 			if ( ACCESSING_BITS_16_31 )
880 			{
881 				m_cdrom_readreqmask = (data >> 16);
882 				m_cdrom_readmask = 0;
883 			}
884 			break;
885 
886 		case 0x24/4:    /* CDROM DMA ENABLE? */
887 			if (LOG_AKIKO_CD) logerror( "DMA enable W: data %08x - mem mask %08x\n", data, mem_mask );
888 			if ( ( m_cdrom_dmacontrol ^ data ) & 0x04000000 )
889 			{
890 				if ( data & 0x04000000 )
891 					start_dma();
892 			}
893 			m_cdrom_dmacontrol = data;
894 			break;
895 
896 		case 0x30/4:
897 			nvram_write(data);
898 			break;
899 
900 		case 0x38/4:
901 			c2p_write(data);
902 			break;
903 
904 		default:
905 			break;
906 	}
907 }
908