1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * CDTV-CR emulation
5 * (4510 microcontroller only simulated)
6 *
7 * Copyright 2014 Toni Wilen
8 *
9 *
10 */
11 
12 #define CDTVCR_4510_EMULATION 0
13 
14 #define CDTVCR_DEBUG 0
15 
16 #include "sysconfig.h"
17 #include "sysdeps.h"
18 
19 #include "options.h"
20 #include "memory.h"
21 #include "newcpu.h"
22 #include "debug.h"
23 #include "zfile.h"
24 #include "gui.h"
25 #include "cdtvcr.h"
26 #include "blkdev.h"
27 #include "threaddep/thread.h"
28 #include "uae.h"
29 #include "custom.h"
30 
31 #define CDTVCR_MASK 0xffff
32 
33 #define CDTVCR_RAM_OFFSET 0x1000
34 #define CDTVCR_RAM_SIZE 4096
35 #define CDTVCR_RAM_MASK (CDTVCR_RAM_SIZE - 1)
36 
37 #define CDTVCR_CLOCK 0xc10
38 #define CDTVCR_ID 0x9dc
39 
40 #define CDTVCR_RESET 0xc00
41 
42 #define CDTVCR_CD_CMD 0xc40
43 #define CDTVCR_CD_CMD_DO 0xc52
44 #define CDTVCR_CD_CMD_STATUS 0xc4e
45 #define CDTVCR_CD_CMD_STATUS2 0xc4f
46 
47 #define CDTVCR_CD_STATE 0xc53
48 #define CDTVCR_SYS_STATE 0xc54
49 #define CDTVCR_CD_SPEED 0xc59
50 #define CDTVCR_CD_PLAYING 0xc5b
51 #define CDTVCR_CD_SUBCODES 0xc60
52 #define CDTVCR_CD_ALLOC 0xc61
53 
54 #define CDTVCR_INTDISABLE 0xc04
55 #define CDTVCR_INTACK 0xc05
56 #define CDTVCR_INTENA 0xc55
57 #define CDTVCR_INTREQ 0xc56
58 #define CDTVCR_4510_TRIGGER 0x4000
59 
60 #define CDTVCR_KEYCMD 0xc80
61 
62 #define CDTVCR_SUBQ 0x906
63 #define CDTVCR_SUBBANK 0x917
64 #define CDTVCR_SUBC 0x918
65 #define CDTVCR_TOC 0xa00
66 
67 #define CDTVCR_PLAYLIST_TRACK 0xc2f
68 #define CDTVCR_PLAYLIST_TIME_MINS 0xc35
69 #define CDTVCR_PLAYLIST_TIME_SECS 0xc36
70 #define CDTVCR_PLAYLIST_TIME_MODE 0xc22
71 #define CDTVCR_PLAYLIST_TIME_MODE2 0xc84
72 #define CDTVCR_PLAYLIST_STATE 0xc86
73 #define CDTVCR_PLAYLIST_CURRENT 0xc8a
74 #define CDTVCR_PLAYLIST_ENTRIES 0xc8b
75 #define CDTVCR_PLAYLIST_DATA 0xc8c
76 
77 
78 static uae_u8 cdtvcr_4510_ram[CDTVCR_RAM_OFFSET];
79 static uae_u8 cdtvcr_ram[CDTVCR_RAM_SIZE];
80 static uae_u8 cdtvcr_clock[2];
81 
82 static smp_comm_pipe requests;
83 static uae_sem_t sub_sem;
84 static volatile int thread_alive;
85 static int unitnum = -1;
86 static struct cd_toc_head toc;
87 static int datatrack;
88 static int cdtvcr_media;
89 static int subqcnt;
90 static int cd_audio_status;
91 static int cdtvcr_wait_sectors;
92 static int cd_led;
93 
94 #define MAX_SUBCODEBUFFER 36
95 static volatile int subcodebufferoffset, subcodebufferoffsetw;
96 static uae_u8 subcodebufferinuse[MAX_SUBCODEBUFFER];
97 static uae_u8 subcodebuffer[MAX_SUBCODEBUFFER * SUB_CHANNEL_SIZE];
98 
cdtvcr_battram_reset(void)99 static void cdtvcr_battram_reset (void)
100 {
101 	struct zfile *f;
102 	int v;
103 
104 	memset (cdtvcr_ram, 0, CDTVCR_RAM_SIZE);
105 	f = zfile_fopen (currprefs.flashfile, _T("rb+"), ZFD_NORMAL);
106 	if (!f) {
107 		f = zfile_fopen (currprefs.flashfile, _T("wb"), 0);
108 		if (f) {
109 			zfile_fwrite (cdtvcr_ram, CDTVCR_RAM_SIZE, 1, f);
110 			zfile_fclose (f);
111 		}
112 		return;
113 	}
114 	v = zfile_fread (cdtvcr_ram, 1, CDTVCR_RAM_SIZE, f);
115 	if (v < CDTVCR_RAM_SIZE)
116 		zfile_fwrite (cdtvcr_ram + v, 1, CDTVCR_RAM_SIZE - v, f);
117 	zfile_fclose (f);
118 }
119 
cdtvcr_battram_write(int addr,int v)120 static void cdtvcr_battram_write (int addr, int v)
121 {
122 	struct zfile *f;
123 	int offset = addr & CDTVCR_RAM_MASK;
124 
125 	if (offset >= CDTVCR_RAM_SIZE)
126 		return;
127 	gui_flicker_led (LED_MD, 0, 2);
128 	if (cdtvcr_ram[offset] == v)
129 		return;
130 	cdtvcr_ram[offset] = v;
131 	f = zfile_fopen (currprefs.flashfile, _T("rb+"), ZFD_NORMAL);
132 	if (!f)
133 		return;
134 	zfile_fseek (f, offset, SEEK_SET);
135 	zfile_fwrite (cdtvcr_ram + offset, 1, 1, f);
136 	zfile_fclose (f);
137 }
138 
cdtvcr_battram_read(int addr)139 static uae_u8 cdtvcr_battram_read (int addr)
140 {
141 	uae_u8 v;
142 	int offset;
143 	offset = addr & CDTVCR_RAM_MASK;
144 	if (offset >= CDTVCR_RAM_SIZE)
145 		return 0;
146 	gui_flicker_led (LED_MD, 0, 1);
147 	v = cdtvcr_ram[offset];
148 	return v;
149 }
150 
ismedia(void)151 static int ismedia (void)
152 {
153 	cdtvcr_4510_ram[CDTVCR_SYS_STATE] &= ~8;
154 	if (unitnum < 0)
155 		return 0;
156 	if (sys_command_ismedia (unitnum, 0)) {
157 		cdtvcr_4510_ram[CDTVCR_SYS_STATE] |= 8;
158 		return 1;
159 	}
160 	return 0;
161 }
162 
get_qcode(void)163 static int get_qcode (void)
164 {
165 #if 0
166 	if (!sys_command_cd_qcode (unitnum, cdrom_qcode))
167 		return 0;
168 	cdrom_qcode[1] = cd_audio_status;
169 #endif
170 	return 1;
171 }
172 
get_toc(void)173 static int get_toc (void)
174 {
175 	uae_u32 msf;
176 	uae_u8 *p, *pl;
177 
178 	cdtvcr_4510_ram[CDTVCR_SYS_STATE] &= ~4;
179 	datatrack = 0;
180 	if (!sys_command_cd_toc (unitnum, &toc))
181 		return 0;
182 	cdtvcr_4510_ram[CDTVCR_SYS_STATE] |= 4 | 8;
183 	if (toc.first_track == 1 && (toc.toc[toc.first_track_offset].control & 0x0c) == 0x04)
184 		datatrack = 1;
185 	p = &cdtvcr_4510_ram[CDTVCR_TOC];
186 	cdtvcr_4510_ram[CDTVCR_PLAYLIST_CURRENT] = 0;
187 	cdtvcr_4510_ram[CDTVCR_PLAYLIST_ENTRIES] = 0;
188 	pl = &cdtvcr_4510_ram[CDTVCR_PLAYLIST_DATA];
189 	p[0] = toc.first_track;
190 	p[1] = toc.last_track;
191 	msf = lsn2msf(toc.lastaddress);
192 	p[2] = msf >> 16;
193 	p[3] = msf >>  8;
194 	p[4] = msf >>  0;
195 	p += 5;
196 	for (int j = toc.first_track_offset; j <= toc.last_track_offset; j++) {
197 		struct cd_toc *s = &toc.toc[j];
198 		p[0] = (s->adr << 0) | (s->control << 4);
199 		p[1] = s->track;
200 		msf = lsn2msf(s->address);
201 		p[2] = msf >> 16;
202 		p[3] = msf >>  8;
203 		p[4] = msf >>  0;
204 		p += 5;
205 		*pl++ = s->track | 0x80;
206 		cdtvcr_4510_ram[CDTVCR_PLAYLIST_ENTRIES]++;
207 	}
208 	return 1;
209 }
210 
cdtvcr_4510_reset(uae_u8 v)211 static void cdtvcr_4510_reset(uae_u8 v)
212 {
213 	cdtvcr_4510_ram[CDTVCR_ID + 0] = 'C';
214 	cdtvcr_4510_ram[CDTVCR_ID + 1] = 'D';
215 	cdtvcr_4510_ram[CDTVCR_ID + 2] = 'T';
216 	cdtvcr_4510_ram[CDTVCR_ID + 3] = 'V';
217 
218 	write_log(_T("4510 reset %d\n"), v);
219 	if (v == 3) {
220 		sys_command_cd_pause (unitnum, 0);
221 		sys_command_cd_stop (unitnum);
222 		cdtvcr_4510_ram[CDTVCR_CD_PLAYING] = 0;
223 		cdtvcr_4510_ram[CDTVCR_CD_STATE] = 0;
224 		return;
225 	} else if (v == 2 || v == 1) {
226 		cdtvcr_4510_ram[CDTVCR_INTENA] = 0;
227 		cdtvcr_4510_ram[CDTVCR_INTREQ] = 0;
228 		if (v == 1) {
229 			memset(cdtvcr_4510_ram, 0, 4096);
230 		}
231 		cdtvcr_4510_ram[CDTVCR_INTDISABLE] = 1;
232 		cdtvcr_4510_ram[CDTVCR_CD_STATE] = 1;
233 	}
234 	cdtvcr_4510_ram[CDTVCR_PLAYLIST_TIME_MODE] = 2;
235 	uae_sem_wait (&sub_sem);
236 	memset (subcodebufferinuse, 0, sizeof subcodebufferinuse);
237 	subcodebufferoffsetw = subcodebufferoffset = 0;
238 	uae_sem_post (&sub_sem);
239 
240 	if (ismedia())
241 		get_toc();
242 }
243 
rethink_cdtvcr(void)244 void rethink_cdtvcr(void)
245 {
246 	if ((cdtvcr_4510_ram[CDTVCR_INTREQ] & cdtvcr_4510_ram[CDTVCR_INTENA]) && !cdtvcr_4510_ram[CDTVCR_INTDISABLE]) {
247 		INTREQ_0 (0x8000 | 0x0008);
248 		cd_led ^= LED_CD_ACTIVE2;
249 	}
250 }
251 
cdtvcr_cmd_done(void)252 static void cdtvcr_cmd_done(void)
253 {
254 	cdtvcr_4510_ram[CDTVCR_SYS_STATE] &= ~3;
255 	cdtvcr_4510_ram[CDTVCR_CD_CMD_DO] = 0;
256 	cdtvcr_4510_ram[CDTVCR_INTREQ] |= 0x40;
257 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS] = 0;
258 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS2] = 0;
259 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS + 2] = 0;
260 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS2 + 2] = 0;
261 }
262 
cdtvcr_play_done(void)263 static void cdtvcr_play_done(void)
264 {
265 	cdtvcr_4510_ram[CDTVCR_SYS_STATE] &= ~3;
266 	cdtvcr_4510_ram[CDTVCR_CD_CMD_DO] = 0;
267 	cdtvcr_4510_ram[CDTVCR_INTREQ] |= 0x80;
268 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS] = 0;
269 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS2] = 0;
270 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS + 2] = 0;
271 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS2 + 2] = 0;
272 }
273 
cdtvcr_state_stopped(void)274 static void cdtvcr_state_stopped(void)
275 {
276 	cdtvcr_4510_ram[CDTVCR_CD_PLAYING] = 0;
277 	cdtvcr_4510_ram[CDTVCR_CD_STATE] = 1;
278 }
279 
cdtvcr_state_play(void)280 static void cdtvcr_state_play(void)
281 {
282 	cdtvcr_4510_ram[CDTVCR_CD_PLAYING] = 1;
283 	cdtvcr_4510_ram[CDTVCR_CD_STATE] = 3;
284 }
285 
cdtvcr_cmd_play_started(void)286 static void cdtvcr_cmd_play_started(void)
287 {
288 	cdtvcr_cmd_done();
289 	cdtvcr_state_play();
290 }
291 
cdtvcr_start(void)292 static void cdtvcr_start (void)
293 {
294 	if (unitnum < 0)
295 		return;
296 	cdtvcr_4510_ram[CDTVCR_CD_STATE] = 0;
297 }
298 
cdtvcr_stop(void)299 static void cdtvcr_stop (void)
300 {
301 	if (unitnum < 0)
302 		return;
303 	sys_command_cd_pause (unitnum, 0);
304 	sys_command_cd_stop (unitnum);
305 	if (cdtvcr_4510_ram[CDTVCR_CD_PLAYING]) {
306 		cdtvcr_4510_ram[CDTVCR_INTREQ] |= 0x80;
307 	}
308 	cdtvcr_state_stopped();
309 }
310 
cdtvcr_state_pause(bool pause)311 static void cdtvcr_state_pause(bool pause)
312 {
313 	cdtvcr_4510_ram[CDTVCR_CD_STATE] = 3;
314 	if (pause)
315 		cdtvcr_4510_ram[CDTVCR_CD_STATE] = 2;
316 }
317 
cdtvcr_pause(bool pause)318 static void cdtvcr_pause(bool pause)
319 {
320 	sys_command_cd_pause (unitnum, pause ? 1 : 0);
321 	cdtvcr_state_pause(pause);
322 	cdtvcr_cmd_done();
323 }
324 
setsubchannel(uae_u8 * s)325 static void setsubchannel(uae_u8 *s)
326 {
327 	uae_u8 *d;
328 
329 	// q-channel
330 	d = &cdtvcr_4510_ram[CDTVCR_SUBQ];
331 	s += SUB_ENTRY_SIZE;
332 	int track = frombcd(s[1]);
333 	/* CtlAdr */
334 	d[0] = s[0];
335 	/* Track */
336 	d[1] = s[1];
337 	cdtvcr_4510_ram[CDTVCR_PLAYLIST_TRACK] = track;
338 	/* Index */
339 	d[2] = s[2];
340 	/* TrackPos */
341 	d[3] = s[3];
342 	d[4] = s[4];
343 	d[5] = s[5];
344 	/* DiskPos */
345 	d[6] = s[6];
346 	d[7] = s[7];
347 	d[8] = s[8];
348 	d[9] = s[9];
349 
350 	uae_u8 mins = 0, secs = 0;
351 	uae_s32 trackpos = msf2lsn(fromlongbcd(s + 3));
352 	if (trackpos < 0)
353 		trackpos = 0;
354 	uae_s32 diskpos = msf2lsn(fromlongbcd(s + 7));
355 	if (diskpos < 0)
356 		diskpos = 0;
357 	switch (cdtvcr_4510_ram[CDTVCR_PLAYLIST_TIME_MODE2])
358 	{
359 		case 0:
360 		secs = (trackpos / 75) % 60;
361 		mins = trackpos / (75 * 60);
362 		break;
363 		case 1:
364 		trackpos = toc.toc[toc.first_track_offset + track].paddress - diskpos;
365 		secs = (trackpos / 75) % 60;
366 		mins = trackpos / (75 * 60);
367 		break;
368 		case 2:
369 		secs = (diskpos / 75) % 60;
370 		mins = diskpos / (75 * 60);
371 		break;
372 		case 3:
373 		diskpos = toc.lastaddress - diskpos;
374 		secs = (diskpos / 75) % 60;
375 		mins = diskpos / (75 * 60);
376 		break;
377 	}
378 	cdtvcr_4510_ram[CDTVCR_PLAYLIST_TIME_MINS] = mins;
379 	cdtvcr_4510_ram[CDTVCR_PLAYLIST_TIME_SECS] = secs;
380 
381 	cdtvcr_4510_ram[CDTVCR_SUBQ - 2] = 1; // qcode valid
382 	cdtvcr_4510_ram[CDTVCR_SUBQ - 1] = 0;
383 
384 	if (cdtvcr_4510_ram[CDTVCR_CD_SUBCODES])
385 		cdtvcr_4510_ram[CDTVCR_INTREQ] |= 4;
386 }
387 
subfunc(uae_u8 * data,int cnt)388 static void subfunc(uae_u8 *data, int cnt)
389 {
390 	uae_u8 out[SUB_CHANNEL_SIZE];
391 	sub_to_deinterleaved(data, out);
392 	setsubchannel(out);
393 
394 	uae_sem_wait(&sub_sem);
395 	if (subcodebufferinuse[subcodebufferoffsetw]) {
396 		memset (subcodebufferinuse, 0,sizeof (subcodebufferinuse));
397 		subcodebufferoffsetw = subcodebufferoffset = 0;
398 	} else {
399 		int offset = subcodebufferoffsetw;
400 		while (cnt > 0) {
401 			if (subcodebufferinuse[offset]) {
402 				write_log (_T("CD32: subcode buffer overflow 2\n"));
403 				break;
404 			}
405 			subcodebufferinuse[offset] = 1;
406 			memcpy (&subcodebuffer[offset * SUB_CHANNEL_SIZE], data, SUB_CHANNEL_SIZE);
407 			data += SUB_CHANNEL_SIZE;
408 			offset++;
409 			if (offset >= MAX_SUBCODEBUFFER)
410 				offset = 0;
411 			cnt--;
412 		}
413 		subcodebufferoffsetw = offset;
414 	}
415 	uae_sem_post(&sub_sem);
416 }
417 
statusfunc(int status)418 static int statusfunc(int status)
419 {
420 	if (status == -1)
421 		return 75;
422 	if (status == -2)
423 		return 75;
424 	if (cd_audio_status != status) {
425 		if (status == AUDIO_STATUS_PLAY_COMPLETE || status == AUDIO_STATUS_PLAY_ERROR) {
426 			cdtvcr_play_done();
427 		} else if (status == AUDIO_STATUS_IN_PROGRESS) {
428 			cdtvcr_cmd_play_started();
429 		}
430 	}
431 	cd_audio_status = status;
432 	return 0;
433 }
434 
cdtvcr_play(uae_u32 start,uae_u32 end)435 static void cdtvcr_play(uae_u32 start, uae_u32 end)
436 {
437 	sys_command_cd_pause(unitnum, 0);
438 	if (!sys_command_cd_play(unitnum, start, end, 0, statusfunc, subfunc))
439 		cdtvcr_play_done();
440 }
441 
cdtvcr_play_track(uae_u32 track_start,uae_u32 track_end)442 static void cdtvcr_play_track(uae_u32 track_start, uae_u32 track_end)
443 {
444 	int start_found, end_found;
445 	uae_u32 start, end;
446 
447 	start_found = end_found = 0;
448 	for (int j = toc.first_track_offset; j <= toc.last_track_offset; j++) {
449 		struct cd_toc *s = &toc.toc[j];
450 		if (track_start == s->track) {
451 			start_found++;
452 			start = s->paddress;
453 		}
454 		if (track_end == s->track) {
455 			end = s->paddress;
456 			end_found++;
457 		}
458 	}
459 	if (start_found == 0) {
460 		write_log (_T("PLAY CD AUDIO: illegal start track %d\n"), track_start);
461 		cdtvcr_stop();
462 		cdtvcr_cmd_done();
463 		return;
464 	}
465 	cdtvcr_play(start, end);
466 }
467 
cdtvcr_read_data(uae_u32 start,uae_u32 addr,uae_u32 len)468 static void cdtvcr_read_data(uae_u32 start, uae_u32 addr, uae_u32 len)
469 {
470 	uae_u8 buffer[2048];
471 	int didread;
472 
473 	cdtvcr_wait_sectors = 0;
474 	while (len) {
475 		didread = sys_command_cd_read (unitnum, buffer, start, 1);
476 		if (!didread)
477 			break;
478 		for (int i = 0; i < 2048 && len > 0; i++) {
479 			put_byte(addr + i, buffer[i]);
480 			len--;
481 		}
482 		addr += 2048;
483 		start++;
484 		cdtvcr_wait_sectors++;
485 	}
486 }
487 
cdtvcr_player_state_change(void)488 static void cdtvcr_player_state_change(void)
489 {
490 	cdtvcr_4510_ram[CDTVCR_INTREQ] |= 0x10;
491 }
492 
cdtvcr_player_pause(void)493 static void cdtvcr_player_pause(void)
494 {
495 	if (cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] == 4)
496 		cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] = 3;
497 	else if (cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] == 3)
498 		cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] = 4;
499 	else
500 		return;
501 	cdtvcr_pause(cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] == 4);
502 	cdtvcr_state_pause(cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] == 4);
503 	cdtvcr_player_state_change();
504 }
505 
cdtvcr_player_stop(void)506 static void cdtvcr_player_stop(void)
507 {
508 	cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] = 1;
509 	cdtvcr_stop();
510 	cdtvcr_state_stopped();
511 	cdtvcr_player_state_change();
512 }
513 
cdtvcr_player_play(void)514 static void cdtvcr_player_play(void)
515 {
516 	int start_found, end_found;
517 	uae_u32 start, end;
518 
519 	int entry = cdtvcr_4510_ram[CDTVCR_PLAYLIST_CURRENT];
520 	int track = cdtvcr_4510_ram[CDTVCR_PLAYLIST_DATA + entry] & 0x7f;
521 	start_found = end_found = 0;
522 	for (int j = toc.first_track_offset; j <= toc.last_track_offset; j++) {
523 		struct cd_toc *s = &toc.toc[j];
524 		if (track == s->track) {
525 			start_found++;
526 			start = s->paddress;
527 			end = s[1].paddress;
528 		}
529 	}
530 	if (start_found == 0) {
531 		cdtvcr_player_stop();
532 		return;
533 	}
534 	cdtvcr_play(start, end);
535 	cdtvcr_state_play();
536 	cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] = 3;
537 	cdtvcr_player_state_change();
538 }
539 
cdtvcr_do_cmd(void)540 static void cdtvcr_do_cmd(void)
541 {
542 	uae_u32 addr, len, start, end, datalen;
543 	uae_u32 startlsn, endlsn;
544 	uae_u8 starttrack, endtrack;
545 	uae_u8 *p = &cdtvcr_4510_ram[CDTVCR_CD_CMD];
546 
547 	cdtvcr_4510_ram[CDTVCR_SYS_STATE] |= 2;
548 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS] = 2;
549 	cdtvcr_4510_ram[CDTVCR_CD_CMD_STATUS2] = 0;
550 	write_log(_T("CDTVCR CD command %02x\n"), p[0]);
551 	for(int i = 0; i < 14; i++)
552 		write_log(_T(".%02x"), p[i]);
553 	write_log(_T("\n"));
554 
555 	start = (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
556 	startlsn = msf2lsn(start);
557 	end = (p[4] << 16) | (p[5] << 8) | (p[6] << 0);
558 	endlsn = msf2lsn(end);
559 	addr = (p[7] << 24) | (p[8] << 16) | (p[9] << 8) | (p[10] << 0);
560 	len = (p[4] << 16) | (p[5] << 8) | (p[6] << 0);
561 	datalen = (p[11] << 16) | (p[12] << 8) | (p[13] << 0);
562 	starttrack = p[1];
563 	endtrack = p[3];
564 
565 	switch(p[0])
566 	{
567 		case 2: // start
568 		cdtvcr_start();
569 		cdtvcr_cmd_done();
570 		break;
571 		case 3: // stop
572 		cdtvcr_stop();
573 		cdtvcr_cmd_done();
574 		break;
575 		case 4: // toc
576 		cdtvcr_stop();
577 		get_toc();
578 		cdtvcr_cmd_done();
579 		break;
580 		case 6: // play
581 		cdtvcr_stop();
582 		cdtvcr_play(startlsn, endlsn);
583 		break;
584 		case 7: // play track
585 		cdtvcr_stop();
586 		cdtvcr_play_track(starttrack, endtrack);
587 		break;
588 		case 8: // read
589 		cdtvcr_stop();
590 		cdtvcr_read_data(start, addr, datalen);
591 		break;
592 		case 9:
593 		cdtvcr_pause(true);
594 		break;
595 		case 10:
596 		cdtvcr_pause(false);
597 		break;
598 		case 11: // stop play
599 		cdtvcr_stop();
600 		cdtvcr_cmd_done();
601 		break;
602 		default:
603 		write_log(_T("unsupported command!\n"));
604 		break;
605 	}
606 }
607 
cdtvcr_4510_do_something(void)608 static void cdtvcr_4510_do_something(void)
609 {
610 	if (cdtvcr_4510_ram[CDTVCR_INTACK]) {
611 		cdtvcr_4510_ram[CDTVCR_INTACK] = 0;
612 		rethink_cdtvcr();
613 	}
614 	if (cdtvcr_4510_ram[CDTVCR_CD_CMD_DO]) {
615 		cdtvcr_4510_ram[CDTVCR_CD_CMD_DO] = 0;
616 		cdtvcr_4510_ram[CDTVCR_SYS_STATE] |= 2;
617 		write_comm_pipe_u32 (&requests, 0x0100, 1);
618 	}
619 }
620 
cdtvcr_debug(uaecptr addr)621 static bool cdtvcr_debug(uaecptr addr)
622 {
623 	addr &= CDTVCR_MASK;
624 	return !(addr >= CDTVCR_RAM_OFFSET && addr < CDTVCR_RAM_OFFSET + CDTVCR_RAM_SIZE);
625 }
626 
cdtvcr_bput2(uaecptr addr,uae_u8 v)627 static void cdtvcr_bput2 (uaecptr addr, uae_u8 v)
628 {
629 	addr &= CDTVCR_MASK;
630 	if (addr == CDTVCR_4510_TRIGGER) {
631 		if (v & 0x80)
632 			cdtvcr_4510_do_something();
633 	} else if (addr >= CDTVCR_RAM_OFFSET && addr < CDTVCR_RAM_OFFSET + CDTVCR_RAM_SIZE) {
634 		cdtvcr_battram_write(addr - CDTVCR_RAM_OFFSET, v);
635 	} else if (addr >= CDTVCR_CLOCK && addr < CDTVCR_CLOCK + 0x20) {
636 		int reg = addr - CDTVCR_CLOCK;
637 		switch (reg)
638 		{
639 			case 0:
640 			cdtvcr_clock[0] = v;
641 			case 1:
642 			cdtvcr_clock[1] = v;
643 			break;
644 		}
645 	} else {
646 		switch(addr)
647 		{
648 			case CDTVCR_RESET:
649 			cdtvcr_4510_reset(v);
650 			break;
651 		}
652 	}
653 	if (addr >= 0xc00 && addr < CDTVCR_RAM_OFFSET) {
654 		switch (addr)
655 		{
656 			case CDTVCR_KEYCMD:
657 			{
658 				uae_u8 keycode = cdtvcr_4510_ram[CDTVCR_KEYCMD + 1];
659 				write_log(_T("Got keycode %x\n"), keycode);
660 				cdtvcr_4510_ram[CDTVCR_KEYCMD + 1] = 0;
661 				switch(keycode)
662 				{
663 					case 0x73: // PLAY
664 					if (cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] >= 3) {
665 						cdtvcr_player_pause();
666 					} else {
667 						cdtvcr_player_play();
668 					}
669 					break;
670 					case 0x72: // STOP
671 					cdtvcr_player_stop();
672 					break;
673 					case 0x74: // <-
674 					if (cdtvcr_4510_ram[CDTVCR_PLAYLIST_CURRENT] > 0) {
675 						cdtvcr_4510_ram[CDTVCR_PLAYLIST_CURRENT]--;
676 						if (cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] >= 3) {
677 							cdtvcr_player_play();
678 						}
679 					}
680 					break;
681 					case 0x75: // ->
682 					if (cdtvcr_4510_ram[CDTVCR_PLAYLIST_CURRENT] < cdtvcr_4510_ram[CDTVCR_PLAYLIST_ENTRIES] - 1) {
683 						cdtvcr_4510_ram[CDTVCR_PLAYLIST_CURRENT]++;
684 						if (cdtvcr_4510_ram[CDTVCR_PLAYLIST_STATE] >= 3) {
685 							cdtvcr_player_play();
686 						}
687 					}
688 					break;
689 				}
690 				v = 0;
691 				break;
692 			}
693 		}
694 		cdtvcr_4510_ram[addr] = v;
695 
696 		if (addr >= 0xc80)
697 			write_log(_T("%04x %02x\n"), addr, v);
698 
699 	}
700 }
701 
cdtvcr_bget2(uaecptr addr)702 static uae_u8 cdtvcr_bget2 (uaecptr addr)
703 {
704 	uae_u8 v = 0;
705 	addr &= CDTVCR_MASK;
706 	if (addr < CDTVCR_RAM_OFFSET) {
707 		v = cdtvcr_4510_ram[addr];
708 	}
709 	if (addr >= CDTVCR_RAM_OFFSET && addr < CDTVCR_RAM_OFFSET + CDTVCR_RAM_SIZE) {
710 		v = cdtvcr_battram_read(addr - CDTVCR_RAM_OFFSET);
711 	} else if (addr >= CDTVCR_CLOCK && addr < CDTVCR_CLOCK + 0x20) {
712 		int reg = addr - CDTVCR_CLOCK;
713 		int days, mins, ticks;
714 		int tickcount = currprefs.ntscmode ? 60 : 50;
715 		struct timeval tv;
716 		struct mytimeval mtv;
717 		gettimeofday (&tv, NULL);
718 		tv.tv_sec -= _timezone;
719 		mtv.tv_sec = tv.tv_sec;
720 		mtv.tv_usec = tv.tv_usec;
721 		timeval_to_amiga(&mtv, &days, &mins, &ticks, tickcount);
722 		switch (reg)
723 		{
724 			case 0:
725 			case 1:
726 			v = cdtvcr_clock[reg];
727 			break;
728 			case 2:
729 			v = days >> 8;
730 			break;
731 			case 3:
732 			v = days;
733 			break;
734 			case 4:
735 			v = mins / 60;
736 			break;
737 			case 5:
738 			v = mins % 60;
739 			break;
740 			case 6:
741 			v = ticks / tickcount;
742 			break;
743 			case 7:
744 			v = ticks % tickcount;
745 			break;
746 			case 8:
747 			v = tickcount;
748 			break;
749 
750 		}
751 	} else {
752 		switch(addr)
753 		{
754 			case CDTVCR_RESET:
755 			v = 0;
756 			break;
757 		}
758 	}
759 	return v;
760 }
761 
cdtvcr_lget(uaecptr addr)762 static uae_u32 REGPARAM2 cdtvcr_lget (uaecptr addr)
763 {
764 	uae_u32 v;
765 	v = (cdtvcr_bget2 (addr) << 24) | (cdtvcr_bget2 (addr + 1) << 16) |
766 		(cdtvcr_bget2 (addr + 2) << 8) | (cdtvcr_bget2 (addr + 3));
767 #if CDTVCR_DEBUG
768 	if (cdtvcr_debug(addr))
769 		write_log (_T("cdtvcr_lget %08X=%08X PC=%08X\n"), addr, v, M68K_GETPC);
770 #endif
771 	return v;
772 }
773 
cdtvcr_wgeti(uaecptr addr)774 static uae_u32 REGPARAM2 cdtvcr_wgeti (uaecptr addr)
775 {
776 	uae_u32 v = 0xffff;
777 	return v;
778 }
cdtvcr_lgeti(uaecptr addr)779 static uae_u32 REGPARAM2 cdtvcr_lgeti (uaecptr addr)
780 {
781 	uae_u32 v = 0xffff;
782 	return v;
783 }
784 
cdtvcr_wget(uaecptr addr)785 static uae_u32 REGPARAM2 cdtvcr_wget (uaecptr addr)
786 {
787 	uae_u32 v;
788 	v = (cdtvcr_bget2 (addr) << 8) | cdtvcr_bget2 (addr + 1);
789 #if CDTVCR_DEBUG
790 	if (cdtvcr_debug(addr))
791 		write_log (_T("cdtvcr_wget %08X=%04X PC=%08X\n"), addr, v, M68K_GETPC);
792 #endif
793 	return v;
794 }
795 
cdtvcr_bget(uaecptr addr)796 static uae_u32 REGPARAM2 cdtvcr_bget (uaecptr addr)
797 {
798 	uae_u32 v;
799 	v = cdtvcr_bget2 (addr);
800 #if CDTVCR_DEBUG
801 	if (cdtvcr_debug(addr))
802 		write_log (_T("cdtvcr_bget %08X=%02X PC=%08X\n"), addr, v, M68K_GETPC);
803 #endif
804 	return v;
805 }
806 
cdtvcr_lput(uaecptr addr,uae_u32 l)807 static void REGPARAM2 cdtvcr_lput (uaecptr addr, uae_u32 l)
808 {
809 #if CDTVCR_DEBUG
810 	if (cdtvcr_debug(addr))
811 		write_log (_T("cdtvcr_lput %08X=%08X PC=%08X\n"), addr, l, M68K_GETPC);
812 #endif
813 	cdtvcr_bput2 (addr, l >> 24);
814 	cdtvcr_bput2 (addr + 1, l >> 16);
815 	cdtvcr_bput2 (addr + 2, l >> 8);
816 	cdtvcr_bput2 (addr + 3, l);
817 }
818 
cdtvcr_wput(uaecptr addr,uae_u32 w)819 static void REGPARAM2 cdtvcr_wput (uaecptr addr, uae_u32 w)
820 {
821 #if CDTVCR_DEBUG
822 	if (cdtvcr_debug(addr))
823 		write_log (_T("cdtvcr_wput %08X=%04X PC=%08X\n"), addr, w & 65535, M68K_GETPC);
824 #endif
825 	cdtvcr_bput2 (addr, w >> 8);
826 	cdtvcr_bput2 (addr + 1, w);
827 }
828 
cdtvcr_bput(uaecptr addr,uae_u32 b)829 static void REGPARAM2 cdtvcr_bput (uaecptr addr, uae_u32 b)
830 {
831 #if CDTVCR_DEBUG
832 	if (cdtvcr_debug(addr))
833 		write_log (_T("cdtvcr_bput %08X=%02X PC=%08X\n"), addr, b & 255, M68K_GETPC);
834 #endif
835 	cdtvcr_bput2 (addr, b);
836 }
837 
838 
839 addrbank cdtvcr_bank = {
840 	cdtvcr_lget, cdtvcr_wget, cdtvcr_bget,
841 	cdtvcr_lput, cdtvcr_wput, cdtvcr_bput,
842 	default_xlate, default_check, NULL, NULL, _T("CDTV-CR"),
843 	cdtvcr_lgeti, cdtvcr_wgeti,
844 	ABFLAG_IO | ABFLAG_SAFE, S_READ, S_WRITE
845 };
846 
dev_thread(void * p)847 static void *dev_thread (void *p)
848 {
849 	write_log (_T("CDTV-CR: CD thread started\n"));
850 	thread_alive = 1;
851 	for (;;) {
852 
853 		uae_u32 b = read_comm_pipe_u32_blocking (&requests);
854 		if (b == 0xffff) {
855 			thread_alive = -1;
856 			return NULL;
857 		}
858 		if (unitnum < 0)
859 			continue;
860 		switch (b)
861 		{
862 			case 0x0100:
863 				cdtvcr_do_cmd();
864 			break;
865 			case 0x0101:
866 			{
867 				int m = ismedia ();
868 				if (m < 0) {
869 					write_log (_T("CDTV: device %d lost\n"), unitnum);
870 					cdtvcr_4510_ram[CDTVCR_SYS_STATE] &= ~(4 | 8);
871 					cdtvcr_4510_ram[CDTVCR_INTREQ] |= 0x10 | 8;
872 					cdtvcr_4510_ram[CDTVCR_CD_STATE] = 0;
873 				} else if (m != cdtvcr_media) {
874 					cdtvcr_media = m;
875 					get_toc ();
876 					cdtvcr_4510_ram[CDTVCR_INTREQ] |= 0x10 | 8;
877 					if (cdtvcr_media) {
878 						cdtvcr_4510_ram[CDTVCR_CD_STATE] = 2;
879 					} else {
880 						cdtvcr_4510_ram[CDTVCR_CD_STATE] = 1;
881 						cdtvcr_4510_ram[CDTVCR_SYS_STATE] &= ~(4 | 8);
882 					}
883 				}
884 				if (cdtvcr_media)
885 					get_qcode ();
886 			}
887 			break;
888 		}
889 	}
890 }
891 
CDTVCR_hsync_handler(void)892 void CDTVCR_hsync_handler (void)
893 {
894 	static int subqcnt, readcnt;
895 
896 	if (!currprefs.cs_cdtvcr)
897 		return;
898 
899 	if (cdtvcr_wait_sectors > 0 && currprefs.cd_speed == 0) {
900 		cdtvcr_wait_sectors = 0;
901 		cdtvcr_cmd_done();
902 	}
903 	readcnt--;
904 	if (readcnt <= 0) {
905 		int cdspeed = cdtvcr_4510_ram[CDTVCR_CD_SPEED] ? 150 : 75;
906 		readcnt = (int)(maxvpos * vblank_hz / cdspeed);
907 		if (cdtvcr_wait_sectors > 0) {
908 			cdtvcr_wait_sectors--;
909 			if (cdtvcr_wait_sectors == 0)
910 				cdtvcr_cmd_done();
911 		}
912 	}
913 	subqcnt--;
914 	if (subqcnt <= 0) {
915 		write_comm_pipe_u32 (&requests, 0x0101, 1);
916 		subqcnt = (int)(maxvpos * vblank_hz / 75 - 1);
917 		if (subcodebufferoffset != subcodebufferoffsetw) {
918 			uae_sem_wait (&sub_sem);
919 			cdtvcr_4510_ram[CDTVCR_SUBBANK] = cdtvcr_4510_ram[CDTVCR_SUBBANK] ? 0 : SUB_CHANNEL_SIZE + 2;
920 			uae_u8 *d = &cdtvcr_4510_ram[CDTVCR_SUBC];
921 			d[cdtvcr_4510_ram[CDTVCR_SUBBANK] + SUB_CHANNEL_SIZE + 0] = 0x1f;
922 			d[cdtvcr_4510_ram[CDTVCR_SUBBANK] + SUB_CHANNEL_SIZE + 1] = 0x3d;
923 			for (int i = 0; i < SUB_CHANNEL_SIZE; i++) {
924 				d[cdtvcr_4510_ram[CDTVCR_SUBBANK] + i] = subcodebuffer[subcodebufferoffset * SUB_CHANNEL_SIZE + i] & 0x3f;
925 			}
926 			subcodebufferinuse[subcodebufferoffset] = 0;
927 			subcodebufferoffset++;
928 			if (subcodebufferoffset >= MAX_SUBCODEBUFFER)
929 				subcodebufferoffset -= MAX_SUBCODEBUFFER;
930 			uae_sem_post (&sub_sem);
931 			if (cdtvcr_4510_ram[CDTVCR_CD_SUBCODES])
932 				cdtvcr_4510_ram[CDTVCR_INTREQ] |= 2;
933 		} else if (cdtvcr_4510_ram[CDTVCR_CD_SUBCODES] && !cdtvcr_4510_ram[CDTVCR_CD_PLAYING]) {
934 			// want subcodes but not playing?
935 			// just return fake stuff, for some reason cdtv-cr driver requires something
936 			// that looks valid, even when not playing or it gets stuck in infinite loop
937 			uae_u8 dst[SUB_CHANNEL_SIZE];
938 			// regenerate Q-subchannel
939 			uae_u8 *s = dst + 12;
940 			struct cd_toc *cdtoc = &toc.toc[toc.first_track];
941 			int sector = 150;
942 			memset (dst, 0, SUB_CHANNEL_SIZE);
943 			s[0] = (cdtoc->control << 4) | (cdtoc->adr << 0);
944 			s[1] = tobcd (cdtoc->track);
945 			s[2] = tobcd (1);
946 			int msf = lsn2msf (sector);
947 			tolongbcd (s + 7, msf);
948 			msf = lsn2msf (sector - cdtoc->address - 150);
949 			tolongbcd (s + 3, msf);
950 			setsubchannel(dst);
951 		}
952 	}
953 
954 	if (cdtvcr_wait_sectors)
955 		cd_led |= LED_CD_ACTIVE;
956 	else
957 		cd_led &= ~LED_CD_ACTIVE;
958 	if ((cd_led & ~LED_CD_ACTIVE2) && !cdtvcr_4510_ram[CDTVCR_CD_PLAYING])
959 		gui_flicker_led(LED_CD, 0, cd_led);
960 
961 	rethink_cdtvcr();
962 }
963 
open_unit(void)964 static void open_unit (void)
965 {
966 	struct device_info di;
967 	unitnum = get_standard_cd_unit (CD_STANDARD_UNIT_CDTV);
968 	sys_command_info (unitnum, &di, 0);
969 	write_log (_T("using drive %s (unit %d, media %d)\n"), di.label, unitnum, di.media_inserted);
970 }
971 
close_unit(void)972 static void close_unit (void)
973 {
974 	if (unitnum >= 0)
975 		sys_command_close (unitnum);
976 	unitnum = -1;
977 }
978 
cdtvcr_reset(void)979 void cdtvcr_reset(void)
980 {
981 	if (!currprefs.cs_cdtvcr)
982 		return;
983 	close_unit ();
984 	if (!thread_alive) {
985 		init_comm_pipe (&requests, 100, 1);
986 		uae_start_thread (_T("cdtv-cr"), dev_thread, NULL, NULL);
987 		while (!thread_alive)
988 			sleep_millis (10);
989 		uae_sem_init (&sub_sem, 0, 1);
990 	}
991 	open_unit ();
992 	gui_flicker_led (LED_CD, 0, -1);
993 
994 	cdtvcr_4510_reset(0);
995 	cdtvcr_battram_reset();
996 	cdtvcr_clock[0] = 0xe3;
997 	cdtvcr_clock[1] = 0x1b;
998 }
999 
cdtvcr_free(void)1000 void cdtvcr_free(void)
1001 {
1002 	if (thread_alive > 0) {
1003 		write_comm_pipe_u32 (&requests, 0xffff, 1);
1004 		while (thread_alive > 0)
1005 			sleep_millis (10);
1006 		uae_sem_destroy (&sub_sem);
1007 	}
1008 	thread_alive = 0;
1009 	close_unit ();
1010 }
1011 
1012 #if CDTVCR_4510_EMULATION
1013 
1014 // VICE 65C02 emulator, waiting for future full CDTV-CR 4510 emulation.
1015 
1016 typedef unsigned char BYTE;
1017 typedef unsigned short WORD;
1018 typedef unsigned int CLOCK;
1019 
cpu65c02_reset(void)1020 static void cpu65c02_reset(void)
1021 {
1022 }
1023 
1024 #define CLOCK_MAX (~((CLOCK)0))
1025 #define TRAP_OPCODE 0x02
1026 #define STATIC_ASSERT(_x)
1027 
1028 #define NUM_MEMSPACES e_invalid_space
1029 
1030 enum mon_int {
1031 	MI_NONE = 0,
1032 	MI_BREAK = 1 << 0,
1033 	MI_WATCH = 1 << 1,
1034 	MI_STEP = 1 << 2
1035 };
1036 
1037 enum t_memspace {
1038 	e_default_space = 0,
1039 	e_comp_space,
1040 	e_disk8_space,
1041 	e_disk9_space,
1042 	e_disk10_space,
1043 	e_disk11_space,
1044 	e_invalid_space
1045 };
1046 typedef enum t_memspace MEMSPACE;
1047 static unsigned monitor_mask[NUM_MEMSPACES];
monitor_check_icount_interrupt(void)1048 static void monitor_check_icount_interrupt(void)
1049 {
1050 }
monitor_check_icount(WORD a)1051 static void monitor_check_icount(WORD a)
1052 {
1053 }
monitor_force_import(int mem)1054 static int monitor_force_import(int mem)
1055 {
1056 	return 0;
1057 }
monitor_check_breakpoints(int mem,WORD addr)1058 static int monitor_check_breakpoints(int mem, WORD addr)
1059 {
1060 	return 0;
1061 }
monitor_check_watchpoints(unsigned int lastpc,unsigned int pc)1062 static void monitor_check_watchpoints(unsigned int lastpc, unsigned int pc)
1063 {
1064 }
monitor_startup(int mem)1065 static void monitor_startup(int mem)
1066 {
1067 }
1068 
1069 #define INTERRUPT_DELAY 2
1070 
1071 #define INTRRUPT_MAX_DMA_PER_OPCODE (7+10000)
1072 
1073 enum cpu_int {
1074 	IK_NONE = 0,
1075 	IK_NMI = 1 << 0,
1076 	IK_IRQ = 1 << 1,
1077 	IK_RESET = 1 << 2,
1078 	IK_TRAP = 1 << 3,
1079 	IK_MONITOR = 1 << 4,
1080 	IK_DMA = 1 << 5,
1081 	IK_IRQPEND = 1 << 6
1082 };
1083 
1084 struct interrupt_cpu_status_s {
1085 	/* Number of interrupt lines.  */
1086 	unsigned int num_ints;
1087 
1088 	/* Define, for each interrupt source, whether it has a pending interrupt
1089 	(IK_IRQ, IK_NMI, IK_RESET and IK_TRAP) or not (IK_NONE).  */
1090 	unsigned int *pending_int;
1091 
1092 	/* Name for each interrupt source */
1093 	char **int_name;
1094 
1095 	/* Number of active IRQ lines.  */
1096 	int nirq;
1097 
1098 	/* Tick when the IRQ was triggered.  */
1099 	CLOCK irq_clk;
1100 
1101 	/* Number of active NMI lines.  */
1102 	int nnmi;
1103 
1104 	/* Tick when the NMI was triggered.  */
1105 	CLOCK nmi_clk;
1106 
1107 	/* If an opcode is intercepted by a DMA, save the number of cycles
1108 	left at the start of this particular DMA (needed by *_set_irq() to
1109 	calculate irq_clk).  */
1110 	unsigned int num_dma_per_opcode;
1111 	unsigned int num_cycles_left[INTRRUPT_MAX_DMA_PER_OPCODE];
1112 	CLOCK dma_start_clk[INTRRUPT_MAX_DMA_PER_OPCODE];
1113 
1114 	/* counters for delay between interrupt request and handler */
1115 	unsigned int irq_delay_cycles;
1116 	unsigned int nmi_delay_cycles;
1117 
1118 	/* If 1, do a RESET.  */
1119 	int reset;
1120 
1121 	/* If 1, call the trapping function.  */
1122 	int trap;
1123 
1124 	/* Debugging function.  */
1125 	void(*trap_func)(WORD, void *data);
1126 
1127 	/* Data to pass to the debugging function when called.  */
1128 	void *trap_data;
1129 
1130 	/* Pointer to the last executed opcode information.  */
1131 	unsigned int *last_opcode_info_ptr;
1132 
1133 	/* Number of cycles we have stolen to the processor last time.  */
1134 	int num_last_stolen_cycles;
1135 
1136 	/* Clock tick at which these cycles have been stolen.  */
1137 	CLOCK last_stolen_cycles_clk;
1138 
1139 	/* Clock tick where just ACK'd IRQs may still trigger an interrupt.
1140 	Set to CLOCK_MAX when irrelevant.  */
1141 	CLOCK irq_pending_clk;
1142 
1143 	unsigned int global_pending_int;
1144 
1145 	void(*nmi_trap_func)(void);
1146 
1147 	void(*reset_trap_func)(void);
1148 };
1149 typedef struct interrupt_cpu_status_s interrupt_cpu_status_t;
1150 
1151 /* Masks to extract information. */
1152 #define OPINFO_DELAYS_INTERRUPT_MSK     (1 << 8)
1153 #define OPINFO_DISABLES_IRQ_MSK         (1 << 9)
1154 #define OPINFO_ENABLES_IRQ_MSK          (1 << 10)
1155 
1156 /* Return nonzero if `opinfo' causes a 1-cycle interrupt delay.  */
1157 #define OPINFO_DELAYS_INTERRUPT(opinfo)         \
1158     ((opinfo) & OPINFO_DELAYS_INTERRUPT_MSK)
1159 
1160 /* Return nonzero if `opinfo' has changed the I flag from 0 to 1, so that an
1161 IRQ that happened 2 or more cycles before the end of the opcode should be
1162 allowed.  */
1163 #define OPINFO_DISABLES_IRQ(opinfo)             \
1164     ((opinfo) & OPINFO_DISABLES_IRQ_MSK)
1165 
1166 /* Return nonzero if `opinfo' has changed the I flag from 1 to 0, so that an
1167 IRQ that happened 2 or more cycles before the end of the opcode should not
1168 be allowed.  */
1169 #define OPINFO_ENABLES_IRQ(opinfo)              \
1170     ((opinfo) & OPINFO_ENABLES_IRQ_MSK)
1171 
1172 /* Set the information for `opinfo'.  `number' is the opcode number,
1173 `delays_interrupt' must be non-zero if it causes a 1-cycle interrupt
1174 delay, `disables_interrupts' must be non-zero if it disabled IRQs.  */
1175 #define OPINFO_SET(opinfo,                                                \
1176                    number, delays_interrupt, disables_irq, enables_irq)   \
1177     ((opinfo) = ((number)                                                 \
1178                  | ((delays_interrupt) ? OPINFO_DELAYS_INTERRUPT_MSK : 0) \
1179                  | ((disables_irq) ? OPINFO_DISABLES_IRQ_MSK : 0)         \
1180                  | ((enables_irq) ? OPINFO_ENABLES_IRQ_MSK : 0)))
1181 
1182 /* Set whether the opcode causes the 1-cycle interrupt delay according to
1183 `delay'.  */
1184 #define OPINFO_SET_DELAYS_INTERRUPT(opinfo, delay)   \
1185     do {                                             \
1186         if ((delay))                                 \
1187             (opinfo) |= OPINFO_DELAYS_INTERRUPT_MSK; \
1188     } while (0)
1189 
1190 /* Set whether the opcode disables previously enabled IRQs according to
1191 `disable'.  */
1192 #define OPINFO_SET_DISABLES_IRQ(opinfo, disable) \
1193     do {                                         \
1194         if ((disable))                           \
1195             (opinfo) |= OPINFO_DISABLES_IRQ_MSK; \
1196     } while (0)
1197 
1198 /* Set whether the opcode enables previously disabled IRQs according to
1199 `enable'.  */
1200 #define OPINFO_SET_ENABLES_IRQ(opinfo, enable)  \
1201     do {                                        \
1202         if ((enable))                           \
1203             (opinfo) |= OPINFO_ENABLES_IRQ_MSK; \
1204     } while (0)
1205 
1206 
1207 
1208 typedef struct mos6510_regs_s {
1209 	unsigned int pc;        /* `unsigned int' required by the drive code. */
1210 	BYTE a;
1211 	BYTE x;
1212 	BYTE y;
1213 	BYTE sp;
1214 	BYTE p;
1215 	BYTE n;
1216 	BYTE z;
1217 } mos6510_regs_t;
1218 
1219 typedef struct R65C02_regs_s
1220 {
1221 	unsigned int pc;
1222 	BYTE a;
1223 	BYTE x;
1224 	BYTE y;
1225 	BYTE sp;
1226 	BYTE p;
1227 	BYTE n;
1228 	BYTE z;
1229 } R65C02_regs_t;
1230 
1231 #define DRIVE_RAM_SIZE 32768
1232 
1233 typedef BYTE drive_read_func_t(struct drive_context_s *, WORD);
1234 typedef void drive_store_func_t(struct drive_context_s *, WORD,
1235 	BYTE);
1236 
1237 typedef struct drivecpud_context_s {
1238 	/* Drive RAM */
1239 	BYTE drive_ram[DRIVE_RAM_SIZE];
1240 
1241 	/* functions */
1242 	drive_read_func_t  *read_func[0x101];
1243 	drive_store_func_t *store_func[0x101];
1244 //	drive_read_func_t  *read_func_watch[0x101];
1245 //	drive_store_func_t *store_func_watch[0x101];
1246 //	drive_read_func_t  *read_func_nowatch[0x101];
1247 //	drive_store_func_t *store_func_nowatch[0x101];
1248 
1249 	int sync_factor;
1250 } drivecpud_context_t;
1251 
1252 typedef struct drive_context_s {
1253 	int mynumber;         /* init to [0123] */
1254 	CLOCK *clk_ptr;       /* shortcut to drive_clk[mynumber] */
1255 
1256 	struct drivecpu_context_s *cpu;
1257 	struct drivecpud_context_s *cpud;
1258 	struct drivefunc_context_s *func;
1259 } drive_context_t;
1260 
drive_trap_handler(drive_context_t * d)1261 static int drive_trap_handler(drive_context_t *d)
1262 {
1263 	return -1;
1264 }
1265 
1266 typedef struct drivecpu_context_s
1267 {
1268 	int traceflg;
1269 	/* This is non-zero each time a Read-Modify-Write instructions that accesses
1270 	memory is executed.  We can emulate the RMW bug of the 6502 this way.  */
1271 	int rmw_flag; /* init to 0 */
1272 
1273 				  /* Interrupt/alarm status.  */
1274 	struct interrupt_cpu_status_s *int_status;
1275 
1276 	struct alarm_context_s *alarm_context;
1277 
1278 	/* Clk guard.  */
1279 	struct clk_guard_s *clk_guard;
1280 
1281 	struct monitor_interface_s *monitor_interface;
1282 
1283 	/* Value of clk for the last time mydrive_cpu_execute() was called.  */
1284 	CLOCK last_clk;
1285 
1286 	/* Number of cycles in excess we executed last time mydrive_cpu_execute()
1287 	was called.  */
1288 	CLOCK last_exc_cycles;
1289 
1290 	CLOCK stop_clk;
1291 
1292 	CLOCK cycle_accum;
1293 	BYTE *d_bank_base;
1294 	unsigned int d_bank_start;
1295 	unsigned int d_bank_limit;
1296 
1297 	/* Information about the last executed opcode.  */
1298 	unsigned int last_opcode_info;
1299 
1300 	/* Address of the last executed opcode. This is used by watchpoints. */
1301 	unsigned int last_opcode_addr;
1302 
1303 	/* Public copy of the registers.  */
1304 	mos6510_regs_t cpu_regs;
1305 //	R65C02_regs_t cpu_R65C02_regs;
1306 
1307 	BYTE *pageone;        /* init to NULL */
1308 
1309 	int monspace;         /* init to e_disk[89]_space */
1310 
1311 	char *snap_module_name;
1312 
1313 	char *identification_string;
1314 } drivecpu_context_t;
1315 
1316 #define LOAD(a)           (drv->cpud->read_func[(a) >> 8](drv, (WORD)(a)))
1317 #define LOAD_ZERO(a)      (drv->cpud->read_func[0](drv, (WORD)(a)))
1318 #define LOAD_ADDR(a)      (LOAD(a) | (LOAD((a) + 1) << 8))
1319 #define LOAD_ZERO_ADDR(a) (LOAD_ZERO(a) | (LOAD_ZERO((a) + 1) << 8))
1320 #define STORE(a, b)       (drv->cpud->store_func[(a) >> 8](drv, (WORD)(a), \
1321                           (BYTE)(b)))
1322 #define STORE_ZERO(a, b)  (drv->cpud->store_func[0](drv, (WORD)(a), \
1323                           (BYTE)(b)))
1324 
1325 #define JUMP(addr)                                       \
1326 
1327 #define P_SIGN          0x80
1328 #define P_OVERFLOW      0x40
1329 #define P_UNUSED        0x20
1330 #define P_BREAK         0x10
1331 #define P_DECIMAL       0x08
1332 #define P_INTERRUPT     0x04
1333 #define P_ZERO          0x02
1334 #define P_CARRY         0x01
1335 
1336 #define CPU_WDC65C02   0
1337 #define CPU_R65C02     1
1338 #define CPU_65SC02     2
1339 
1340 #define CLK (*(drv->clk_ptr))
1341 #define RMW_FLAG (cpu->rmw_flag)
1342 #define PAGE_ONE (cpu->pageone)
1343 #define LAST_OPCODE_INFO (cpu->last_opcode_info)
1344 #define LAST_OPCODE_ADDR (cpu->last_opcode_addr)
1345 #define TRACEFLG (debug.drivecpu_traceflg[drv->mynumber])
1346 
1347 #define CPU_INT_STATUS (cpu->int_status)
1348 
1349 #define ALARM_CONTEXT (cpu->alarm_context)
1350 
1351 #define ROM_TRAP_ALLOWED() 1
1352 
1353 #define ROM_TRAP_HANDLER() drive_trap_handler(drv)
1354 
1355 #define CALLER (cpu->monspace)
1356 
1357 #define DMA_FUNC drive_generic_dma()
1358 
1359 #define DMA_ON_RESET
1360 
1361 #define cpu_reset() (cpu_reset)(drv)
1362 #define bank_limit (cpu->d_bank_limit)
1363 #define bank_start (cpu->d_bank_start)
1364 #define bank_base (cpu->d_bank_base)
1365 
1366 /* WDC_STP() and WDC_WAI() are not used on the R65C02. */
1367 #define WDC_STP()
1368 #define WDC_WAI()
1369 
1370 #define GLOBAL_REGS cpu->cpu_R65C02_regs
1371 
1372 #define DRIVE_CPU
1373 
drive_generic_dma(void)1374 static void drive_generic_dma(void)
1375 {
1376 }
interrupt_trigger_dma(interrupt_cpu_status_t * cs,CLOCK cpu_clk)1377 static void interrupt_trigger_dma(interrupt_cpu_status_t *cs, CLOCK cpu_clk)
1378 {
1379 	cs->global_pending_int = (enum cpu_int)
1380 		(cs->global_pending_int | IK_DMA);
1381 }
interrupt_ack_dma(interrupt_cpu_status_t * cs)1382 static void interrupt_ack_dma(interrupt_cpu_status_t *cs)
1383 {
1384 	cs->global_pending_int = (enum cpu_int)
1385 		(cs->global_pending_int & ~IK_DMA);
1386 }
interrupt_do_trap(interrupt_cpu_status_t * cs,WORD address)1387 static void interrupt_do_trap(interrupt_cpu_status_t *cs, WORD address)
1388 {
1389 	cs->global_pending_int &= ~IK_TRAP;
1390 	cs->trap_func(address, cs->trap_data);
1391 }
interrupt_ack_reset(interrupt_cpu_status_t * cs)1392 static void interrupt_ack_reset(interrupt_cpu_status_t *cs)
1393 {
1394 	cs->global_pending_int &= ~IK_RESET;
1395 
1396 	if (cs->reset_trap_func)
1397 		cs->reset_trap_func();
1398 }
interrupt_ack_nmi(interrupt_cpu_status_t * cs)1399 static void interrupt_ack_nmi(interrupt_cpu_status_t *cs)
1400 {
1401 	cs->global_pending_int =
1402 		(cs->global_pending_int & ~IK_NMI);
1403 
1404 	if (cs->nmi_trap_func) {
1405 		cs->nmi_trap_func();
1406 	}
1407 }
interrupt_ack_irq(interrupt_cpu_status_t * cs)1408 static void interrupt_ack_irq(interrupt_cpu_status_t *cs)
1409 {
1410 	cs->global_pending_int =
1411 		(cs->global_pending_int & ~IK_IRQPEND);
1412 	cs->irq_pending_clk = CLOCK_MAX;
1413 }
interrupt_check_nmi_delay(interrupt_cpu_status_t * cs,CLOCK cpu_clk)1414 static int interrupt_check_nmi_delay(interrupt_cpu_status_t *cs,
1415 	CLOCK cpu_clk)
1416 {
1417 	CLOCK nmi_clk = cs->nmi_clk + INTERRUPT_DELAY;
1418 
1419 	/* Branch instructions delay IRQs and NMI by one cycle if branch
1420 	is taken with no page boundary crossing.  */
1421 	if (OPINFO_DELAYS_INTERRUPT(*cs->last_opcode_info_ptr))
1422 		nmi_clk++;
1423 
1424 	if (cpu_clk >= nmi_clk)
1425 		return 1;
1426 
1427 	return 0;
1428 }
interrupt_check_irq_delay(interrupt_cpu_status_t * cs,CLOCK cpu_clk)1429 static int interrupt_check_irq_delay(interrupt_cpu_status_t *cs,
1430 	CLOCK cpu_clk)
1431 {
1432 	CLOCK irq_clk = cs->irq_clk + INTERRUPT_DELAY;
1433 
1434 	/* Branch instructions delay IRQs and NMI by one cycle if branch
1435 	is taken with no page boundary crossing.  */
1436 	if (OPINFO_DELAYS_INTERRUPT(*cs->last_opcode_info_ptr))
1437 		irq_clk++;
1438 
1439 	/* If an opcode changes the I flag from 1 to 0, the 6510 needs
1440 	one more opcode before it triggers the IRQ routine.  */
1441 	if (cpu_clk >= irq_clk) {
1442 		if (!OPINFO_ENABLES_IRQ(*cs->last_opcode_info_ptr)) {
1443 			return 1;
1444 		} else {
1445 			cs->global_pending_int |= IK_IRQPEND;
1446 		}
1447 	}
1448 	return 0;
1449 }
1450 
1451 struct alarm_context_s {
1452 	CLOCK next_pending_alarm_clk;
1453 };
1454 typedef struct alarm_context_s alarm_context_t;
1455 
alarm_context_dispatch(alarm_context_t * context,CLOCK cpu_clk)1456 static void alarm_context_dispatch(alarm_context_t *context, CLOCK cpu_clk)
1457 {
1458 }
alarm_context_next_pending_clk(alarm_context_t * context)1459 static CLOCK alarm_context_next_pending_clk(alarm_context_t *context)
1460 {
1461 	return context->next_pending_alarm_clk;
1462 }
1463 
cpu_4510(void)1464 static void cpu_4510(void)
1465 {
1466 	int cpu_type = CPU_R65C02;
1467 	drivecpu_context_t *cpu = NULL;
1468 	drive_context_t *drv = NULL;
1469 
1470 #define reg_a   (cpu->cpu_regs.a)
1471 #define reg_x   (cpu->cpu_regs.x)
1472 #define reg_y   (cpu->cpu_regs.y)
1473 #define reg_pc  (cpu->cpu_regs.pc)
1474 #define reg_sp  (cpu->cpu_regs.sp)
1475 #define reg_p   (cpu->cpu_regs.p)
1476 #define flag_z  (cpu->cpu_regs.z)
1477 #define flag_n  (cpu->cpu_regs.n)
1478 
1479 #include "65c02core.cpp"
1480 }
1481 
init_65c02(struct drive_context_s * drv)1482 static void init_65c02(struct drive_context_s *drv)
1483 {
1484 	drivecpu_context_t *cpu = drv->cpu;
1485 
1486 	cpu->rmw_flag = 0;
1487 	cpu->d_bank_limit = 0;
1488 	cpu->d_bank_start = 0;
1489 	cpu->pageone = NULL;
1490 }
1491 
1492 #endif
1493