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