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