comparison segacd.c @ 2072:cc13c100b027

Merge Sega CD branch now that it sort of works
author Michael Pavone <pavone@retrodev.com>
date Sun, 30 Jan 2022 22:29:29 -0800
parents 8e51c0c3f2e3
children c69e42444f96
comparison
equal deleted inserted replaced
2052:3748a2a8a4b7 2072:cc13c100b027
1 #include <stdlib.h>
2 #include <string.h>
3 #include "cd_graphics.h"
4 #include "genesis.h"
5 #include "util.h"
6
7 #define SCD_MCLKS 50000000
8 #define SCD_PERIPH_RESET_CLKS (SCD_MCLKS / 10)
9 #define TIMER_TICK_CLKS 1536
10
11 enum {
12 GA_SUB_CPU_CTRL,
13 GA_MEM_MODE,
14 GA_CDC_CTRL,
15 GA_CDC_REG_DATA,
16 GA_CDC_HOST_DATA,
17 GA_CDC_DMA_ADDR,
18 GA_STOP_WATCH,
19 GA_COMM_FLAG,
20 GA_COMM_CMD0,
21 GA_COMM_CMD1,
22 GA_COMM_CMD2,
23 GA_COMM_CMD3,
24 GA_COMM_CMD4,
25 GA_COMM_CMD5,
26 GA_COMM_CMD6,
27 GA_COMM_CMD7,
28 GA_COMM_STATUS0,
29 GA_COMM_STATUS1,
30 GA_COMM_STATUS2,
31 GA_COMM_STATUS3,
32 GA_COMM_STATUS4,
33 GA_COMM_STATUS5,
34 GA_COMM_STATUS6,
35 GA_COMM_STATUS7,
36 GA_TIMER,
37 GA_INT_MASK,
38 GA_CDD_FADER,
39 GA_CDD_CTRL,
40 GA_CDD_STATUS0,
41 GA_CDD_STATUS1,
42 GA_CDD_STATUS2,
43 GA_CDD_STATUS3,
44 GA_CDD_STATUS4,
45 GA_CDD_CMD0,
46 GA_CDD_CMD1,
47 GA_CDD_CMD2,
48 GA_CDD_CMD3,
49 GA_CDD_CMD4,
50 GA_FONT_COLOR,
51 GA_FONT_BITS,
52 GA_FONT_DATA0,
53 GA_FONT_DATA1,
54 GA_FONT_DATA2,
55 GA_FONT_DATA3,
56
57 GA_HINT_VECTOR = GA_CDC_REG_DATA
58 };
59 //GA_SUB_CPU_CTRL
60 #define BIT_IEN2 0x8000
61 #define BIT_IFL2 0x0100
62 #define BIT_LEDG 0x0200
63 #define BIT_LEDR 0x0100
64 #define BIT_SBRQ 0x0002
65 #define BIT_SRES 0x0001
66 #define BIT_PRES 0x0001
67 //GA_MEM_MODE
68 #define MASK_PROG_BANK 0x00C0
69 #define BIT_OVERWRITE 0x0010
70 #define BIT_UNDERWRITE 0x0008
71 #define MASK_PRIORITY (BIT_OVERWRITE|BIT_UNDERWRITE)
72 #define BIT_MEM_MODE 0x0004
73 #define BIT_DMNA 0x0002
74 #define BIT_RET 0x0001
75
76 //GA_CDC_CTRL
77 #define BIT_EDT 0x8000
78 #define BIT_DSR 0x4000
79
80 enum {
81 DST_MAIN_CPU = 2,
82 DST_SUB_CPU,
83 DST_PCM_RAM,
84 DST_PROG_RAM,
85 DST_WORD_RAM = 7
86 };
87
88 //GA_INT_MASK
89 #define BIT_MASK_IEN1 0x0002
90 #define BIT_MASK_IEN2 0x0004
91 #define BIT_MASK_IEN3 0x0008
92 #define BIT_MASK_IEN4 0x0010
93 #define BIT_MASK_IEN5 0x0020
94 #define BIT_MASK_IEN6 0x0040
95
96 //GA_CDD_CTRL
97 #define BIT_HOCK 0x0004
98
99 static void *prog_ram_wp_write16(uint32_t address, void *vcontext, uint16_t value)
100 {
101 m68k_context *m68k = vcontext;
102 segacd_context *cd = m68k->system;
103 //if (!(cd->gate_array[GA_MEM_MODE] & (1 << ((address >> 9) + 8)))) {
104 if (address >= ((cd->gate_array[GA_MEM_MODE] & 0xFF00) << 1)) {
105 cd->prog_ram[address >> 1] = value;
106 m68k_invalidate_code_range(m68k, address, address + 2);
107 }
108 return vcontext;
109 }
110
111 static void *prog_ram_wp_write8(uint32_t address, void *vcontext, uint8_t value)
112 {
113 m68k_context *m68k = vcontext;
114 segacd_context *cd = m68k->system;
115 if (address >= ((cd->gate_array[GA_MEM_MODE] & 0xFF00) << 1)) {
116 ((uint8_t *)cd->prog_ram)[address ^ 1] = value;
117 m68k_invalidate_code_range(m68k, address, address + 1);
118 }
119 return vcontext;
120 }
121
122 static uint16_t word_ram_2M_read16(uint32_t address, void *vcontext)
123 {
124 m68k_context *m68k = vcontext;
125 //TODO: fixme for interleaving
126 uint16_t* bank = m68k->mem_pointers[1];
127 uint16_t raw = bank[address >> 2];
128 if (address & 2) {
129 return (raw & 0xF) | (raw << 4 & 0xF00);
130 } else {
131 return (raw >> 4 & 0xF00) | (raw >> 8 & 0xF);
132 }
133 }
134
135 static uint8_t word_ram_2M_read8(uint32_t address, void *vcontext)
136 {
137 uint16_t word = word_ram_2M_read16(address, vcontext);
138 if (address & 1) {
139 return word;
140 }
141 return word >> 8;
142 }
143
144 static void *word_ram_2M_write8(uint32_t address, void *vcontext, uint8_t value)
145 {
146 m68k_context *m68k = vcontext;
147 segacd_context *cd = m68k->system;
148 value &= 0xF;
149 uint16_t priority = cd->gate_array[GA_MEM_MODE] & MASK_PRIORITY;
150
151 if (priority == BIT_OVERWRITE && !value) {
152 return vcontext;
153 }
154 if (priority == BIT_UNDERWRITE) {
155 if (!value) {
156 return vcontext;
157 }
158 uint8_t old = word_ram_2M_read8(address, vcontext);
159 if (old) {
160 return vcontext;
161 }
162 }
163 uint16_t* bank = m68k->mem_pointers[1];
164 uint16_t raw = bank[address >> 2];
165 uint16_t shift = ((address & 3) * 4);
166 raw &= ~(0xF000 >> shift);
167 raw |= value << (12 - shift);
168 bank[address >> 2] = raw;
169 return vcontext;
170 }
171
172
173 static void *word_ram_2M_write16(uint32_t address, void *vcontext, uint16_t value)
174 {
175 word_ram_2M_write8(address, vcontext, value >> 8);
176 return word_ram_2M_write8(address + 1, vcontext, value);
177 }
178
179 static uint16_t word_ram_1M_read16(uint32_t address, void *vcontext)
180 {
181 return 0;
182 }
183
184 static uint8_t word_ram_1M_read8(uint32_t address, void *vcontext)
185 {
186 return 0;
187 }
188
189 static void *word_ram_1M_write16(uint32_t address, void *vcontext, uint16_t value)
190 {
191 return vcontext;
192 }
193
194 static void *word_ram_1M_write8(uint32_t address, void *vcontext, uint8_t value)
195 {
196 return vcontext;
197 }
198
199
200 static uint16_t unmapped_prog_read16(uint32_t address, void *vcontext)
201 {
202 return 0xFFFF;
203 }
204
205 static uint8_t unmapped_prog_read8(uint32_t address, void *vcontext)
206 {
207 return 0xFF;
208 }
209
210 static void *unmapped_prog_write16(uint32_t address, void *vcontext, uint16_t value)
211 {
212 return vcontext;
213 }
214
215 static void *unmapped_prog_write8(uint32_t address, void *vcontext, uint8_t value)
216 {
217 return vcontext;
218 }
219
220 static uint16_t unmapped_word_read16(uint32_t address, void *vcontext)
221 {
222 return 0xFFFF;
223 }
224
225 static uint8_t unmapped_word_read8(uint32_t address, void *vcontext)
226 {
227 return 0xFF;
228 }
229
230 static void *unmapped_word_write16(uint32_t address, void *vcontext, uint16_t value)
231 {
232 return vcontext;
233 }
234
235 static void *unmapped_word_write8(uint32_t address, void *vcontext, uint8_t value)
236 {
237 return vcontext;
238 }
239
240 static uint16_t cell_image_read16(uint32_t address, void *vcontext)
241 {
242 return 0xFFFF;
243 }
244
245 static uint8_t cell_image_read8(uint32_t address, void *vcontext)
246 {
247 return 0xFF;
248 }
249
250 static void *cell_image_write16(uint32_t address, void *vcontext, uint16_t value)
251 {
252 return vcontext;
253 }
254
255 static void *cell_image_write8(uint32_t address, void *vcontext, uint8_t value)
256 {
257 return vcontext;
258 }
259
260 static uint8_t pcm_read8(uint32_t address, void *vcontext)
261 {
262 return 0;
263 }
264
265 static uint16_t pcm_read16(uint32_t address, void *vcontext)
266 {
267 return 0xFF00 | pcm_read8(address+1, vcontext);
268 }
269
270 static void *pcm_write8(uint32_t address, void *vcontext, uint8_t value)
271 {
272 return vcontext;
273 }
274
275 static void *pcm_write16(uint32_t address, void *vcontext, uint16_t value)
276 {
277 return pcm_write8(address+1, vcontext, value);
278 }
279
280
281 static void timers_run(segacd_context *cd, uint32_t cycle)
282 {
283 if (cycle <= cd->stopwatch_cycle) {
284 return;
285 }
286 uint32_t ticks = (cycle - cd->stopwatch_cycle) / TIMER_TICK_CLKS;
287 cd->stopwatch_cycle += ticks * TIMER_TICK_CLKS;
288 cd->gate_array[GA_STOP_WATCH] += ticks;
289 cd->gate_array[GA_STOP_WATCH] &= 0xFFF;
290 if (ticks && !cd->timer_value) {
291 --ticks;
292 cd->timer_value = cd->gate_array[GA_TIMER];
293 }
294 if (ticks && cd->timer_value) {
295 while (ticks >= (cd->timer_value + 1)) {
296 ticks -= cd->timer_value + 1;
297 cd->timer_value = cd->gate_array[GA_TIMER];
298 cd->timer_pending = 1;
299 }
300 cd->timer_value -= ticks;
301 if (!cd->timer_value) {
302 cd->timer_pending = 1;
303 }
304 }
305 }
306
307 static void cdd_run(segacd_context *cd, uint32_t cycle)
308 {
309 cdd_mcu_run(&cd->cdd, cycle, cd->gate_array + GA_CDD_CTRL, &cd->cdc);
310 lc8951_run(&cd->cdc, cycle);
311 }
312
313 static uint32_t next_timer_int(segacd_context *cd)
314 {
315 if (cd->timer_pending) {
316 return cd->stopwatch_cycle;
317 }
318 if (cd->timer_value) {
319 return cd->stopwatch_cycle + TIMER_TICK_CLKS * cd->timer_value;
320 }
321 if (cd->gate_array[GA_TIMER]) {
322 return cd->stopwatch_cycle + TIMER_TICK_CLKS * (cd->gate_array[GA_TIMER] + 1);
323 }
324 return CYCLE_NEVER;
325 }
326
327 static void calculate_target_cycle(m68k_context * context)
328 {
329 segacd_context *cd = context->system;
330 context->int_cycle = CYCLE_NEVER;
331 uint8_t mask = context->status & 0x7;
332 if (mask < 5) {
333 if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN5) {
334 uint32_t cdc_cycle = lc8951_next_interrupt(&cd->cdc);
335 //CDC interrupts only generated on falling edge of !INT signal
336 if (cd->cdc_int_ack) {
337 if (cdc_cycle > cd->cdc.cycle) {
338 cd->cdc_int_ack = 0;
339 } else {
340 cdc_cycle = CYCLE_NEVER;
341 }
342 }
343 if (cdc_cycle < context->int_cycle) {
344 context->int_cycle = cdc_cycle;
345 context->int_num = 5;
346 }
347 }
348 if (mask < 4) {
349 if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN4) {
350 uint32_t cdd_cycle = cd->cdd.int_pending ? context->current_cycle : cd->cdd.next_int_cycle;
351 if (cdd_cycle < context->int_cycle) {
352 context->int_cycle = cdd_cycle;
353 context->int_num = 4;
354 }
355 }
356 if (mask < 3) {
357 uint32_t next_timer;
358 if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN3) {
359 uint32_t next_timer_cycle = next_timer_int(cd);
360 if (next_timer_cycle < context->int_cycle) {
361 context->int_cycle = next_timer_cycle;
362 context->int_num = 3;
363 }
364 }
365 if (mask < 2) {
366 if (cd->int2_cycle < context->int_cycle && (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN2)) {
367 context->int_cycle = cd->int2_cycle;
368 context->int_num = 2;
369 }
370 if (mask < 1) {
371 if (cd->graphics_int_cycle < context->int_cycle && (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN1)) {
372 context->int_cycle = cd->graphics_int_cycle;
373 context->int_num = 1;
374 }
375 }
376 }
377 }
378 }
379 }
380 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) {
381 context->int_pending = INT_PENDING_NONE;
382 }
383 if (context->current_cycle >= context->sync_cycle) {
384 context->should_return = 1;
385 context->target_cycle = context->current_cycle;
386 return;
387 }
388 if (context->status & M68K_STATUS_TRACE || context->trace_pending) {
389 context->target_cycle = context->current_cycle;
390 return;
391 }
392 context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle;
393 }
394
395 static uint16_t sub_gate_read16(uint32_t address, void *vcontext)
396 {
397 m68k_context *m68k = vcontext;
398 segacd_context *cd = m68k->system;
399 uint32_t reg = address >> 1;
400 switch (reg)
401 {
402 case GA_SUB_CPU_CTRL: {
403 uint16_t value = cd->gate_array[reg] & 0xFFFE;
404 if (cd->periph_reset_cycle == CYCLE_NEVER || (m68k->current_cycle - cd->periph_reset_cycle) > SCD_PERIPH_RESET_CLKS) {
405 value |= BIT_PRES;
406 }
407 return value;
408 }
409 case GA_MEM_MODE:
410 return cd->gate_array[reg] & 0xFF1F;
411 case GA_CDC_CTRL:
412 cdd_run(cd, m68k->current_cycle);
413 return cd->gate_array[reg] | cd->cdc.ar;
414 case GA_CDC_REG_DATA:
415 cdd_run(cd, m68k->current_cycle);
416 return lc8951_reg_read(&cd->cdc);
417 case GA_CDC_HOST_DATA: {
418 cdd_run(cd, m68k->current_cycle);
419 uint16_t dst = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7;
420 if (dst == DST_SUB_CPU) {
421 if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) {
422 cd->gate_array[GA_CDC_CTRL] &= ~BIT_DSR;
423 lc8951_resume_transfer(&cd->cdc, cd->cdc.cycle);
424 }
425 calculate_target_cycle(cd->m68k);
426
427 }
428 return cd->gate_array[reg];
429 }
430 case GA_STOP_WATCH:
431 case GA_TIMER:
432 timers_run(cd, m68k->current_cycle);
433 return cd->gate_array[reg];
434 case GA_CDD_STATUS0:
435 case GA_CDD_STATUS1:
436 case GA_CDD_STATUS2:
437 case GA_CDD_STATUS3:
438 case GA_CDD_STATUS4:
439 cdd_run(cd, m68k->current_cycle);
440 return cd->gate_array[reg];
441 break;
442 case GA_FONT_DATA0:
443 case GA_FONT_DATA1:
444 case GA_FONT_DATA2:
445 case GA_FONT_DATA3: {
446 uint16_t shift = 4 * (3 - (reg - GA_FONT_DATA0));
447 uint16_t value = 0;
448 uint16_t fg = cd->gate_array[GA_FONT_COLOR] >> 4;
449 uint16_t bg = cd->gate_array[GA_FONT_COLOR] & 0xF;
450 for (int i = 0; i < 4; i++) {
451 uint16_t pixel = 0;
452 if (cd->gate_array[GA_FONT_BITS] & 1 << (shift + i)) {
453 pixel = fg;
454 } else {
455 pixel = bg;
456 }
457 value |= pixel << (i * 4);
458 }
459 return value;
460 case GA_STAMP_SIZE:
461 case GA_IMAGE_BUFFER_LINES:
462 //these two have bits that change based on graphics operations
463 cd_graphics_run(cd, m68k->current_cycle);
464 return cd->gate_array[reg];
465 case GA_TRACE_VECTOR_BASE:
466 //write only
467 return 0xFFFF;
468 }
469 default:
470 return cd->gate_array[reg];
471 }
472 }
473
474 static uint8_t sub_gate_read8(uint32_t address, void *vcontext)
475 {
476 uint16_t val = sub_gate_read16(address, vcontext);
477 return address & 1 ? val : val >> 8;
478 }
479
480 static void *sub_gate_write16(uint32_t address, void *vcontext, uint16_t value)
481 {
482 m68k_context *m68k = vcontext;
483 segacd_context *cd = m68k->system;
484 uint32_t reg = address >> 1;
485 switch (reg)
486 {
487 case GA_SUB_CPU_CTRL:
488 cd->gate_array[reg] &= 0xF0;
489 cd->gate_array[reg] |= value & (BIT_LEDG|BIT_LEDR);
490 if (value & BIT_PRES) {
491 cd->periph_reset_cycle = m68k->current_cycle;
492 }
493 break;
494 case GA_MEM_MODE: {
495 uint16_t changed = value ^ cd->gate_array[reg];
496 genesis_context *gen = cd->genesis;
497 if (changed & BIT_MEM_MODE) {
498 //FIXME: ram banks are supposed to be interleaved when in 2M mode
499 cd->gate_array[reg] &= ~BIT_DMNA;
500 if (value & BIT_MEM_MODE) {
501 //switch to 1M mode
502 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = (value & BIT_RET) ? cd->word_ram + 0x10000 : cd->word_ram;
503 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL;
504 m68k->mem_pointers[0] = NULL;
505 m68k->mem_pointers[1] = (value & BIT_RET) ? cd->word_ram : cd->word_ram + 0x10000;
506 } else {
507 //switch to 2M mode
508 if (value & BIT_RET) {
509 //Main CPU will have word ram
510 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = cd->word_ram;
511 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = cd->word_ram + 0x10000;
512 m68k->mem_pointers[0] = NULL;
513 m68k->mem_pointers[1] = NULL;
514 } else {
515 //sub cpu will have word ram
516 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = NULL;
517 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL;
518 m68k->mem_pointers[0] = cd->word_ram;
519 m68k->mem_pointers[1] = NULL;
520 }
521 }
522 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000);
523 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000);
524 } else if (changed & BIT_RET) {
525 if (value & BIT_MEM_MODE) {
526 cd->gate_array[reg] &= ~BIT_DMNA;
527 //swapping banks in 1M mode
528 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = (value & BIT_RET) ? cd->word_ram + 0x10000 : cd->word_ram;
529 m68k->mem_pointers[1] = (value & BIT_RET) ? cd->word_ram : cd->word_ram + 0x10000;
530 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000);
531 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000);
532 } else if (value & BIT_RET) {
533 cd->gate_array[reg] &= ~BIT_DMNA;
534 //giving word ram to main CPU in 2M mode
535 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = cd->word_ram;
536 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = cd->word_ram + 0x10000;
537 m68k->mem_pointers[0] = NULL;
538 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000);
539 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000);
540 } else {
541 value |= BIT_RET;
542 }
543 }
544 cd->gate_array[reg] &= 0xFFC2;
545 cd->gate_array[reg] |= value & (BIT_RET|BIT_MEM_MODE|MASK_PRIORITY);
546 break;
547 }
548 case GA_CDC_CTRL:
549 cdd_run(cd, m68k->current_cycle);
550 lc8951_ar_write(&cd->cdc, value);
551 //cd->gate_array[reg] &= 0xC000;
552 //apparently this clears EDT, should it also clear DSR?
553 cd->gate_array[reg] = value & 0x0700;
554 cd->cdc_dst_low = 0;
555 break;
556 case GA_CDC_REG_DATA:
557 cdd_run(cd, m68k->current_cycle);
558 printf("CDC write %X: %X @ %u\n", cd->cdc.ar, value, m68k->current_cycle);
559 lc8951_reg_write(&cd->cdc, value);
560 calculate_target_cycle(m68k);
561 break;
562 case GA_CDC_DMA_ADDR:
563 cdd_run(cd, m68k->current_cycle);
564 cd->gate_array[reg] = value;
565 cd->cdc_dst_low = 0;
566 break;
567 case GA_STOP_WATCH:
568 //docs say you should only write zero to reset
569 //mcd-verificator comments suggest any value will reset
570 timers_run(cd, m68k->current_cycle);
571 cd->gate_array[reg] = 0;
572 break;
573 case GA_COMM_FLAG:
574 cd->gate_array[reg] &= 0xFF00;
575 cd->gate_array[reg] |= value & 0xFF;
576 break;
577 case GA_COMM_STATUS0:
578 case GA_COMM_STATUS1:
579 case GA_COMM_STATUS2:
580 case GA_COMM_STATUS3:
581 case GA_COMM_STATUS4:
582 case GA_COMM_STATUS5:
583 case GA_COMM_STATUS6:
584 case GA_COMM_STATUS7:
585 //no effects for these other than saving the value
586 cd->gate_array[reg] = value;
587 break;
588 case GA_TIMER:
589 timers_run(cd, m68k->current_cycle);
590 cd->gate_array[reg] = value & 0xFF;
591 calculate_target_cycle(m68k);
592 break;
593 case GA_INT_MASK:
594 cd->gate_array[reg] = value & (BIT_MASK_IEN6|BIT_MASK_IEN5|BIT_MASK_IEN4|BIT_MASK_IEN3|BIT_MASK_IEN2|BIT_MASK_IEN1);
595 calculate_target_cycle(m68k);
596 break;
597 case GA_CDD_CTRL: {
598 cdd_run(cd, m68k->current_cycle);
599 uint16_t changed = cd->gate_array[reg] ^ value;
600 cd->gate_array[reg] &= ~BIT_HOCK;
601 cd->gate_array[reg] |= value & BIT_HOCK;
602 if (changed & BIT_HOCK) {
603 if (value & BIT_HOCK) {
604 cdd_hock_enabled(&cd->cdd);
605 } else {
606 cdd_hock_disabled(&cd->cdd);
607 }
608 calculate_target_cycle(m68k);
609 }
610 break;
611 }
612 case GA_CDD_CMD0:
613 case GA_CDD_CMD1:
614 case GA_CDD_CMD2:
615 case GA_CDD_CMD3:
616 cdd_run(cd, m68k->current_cycle);
617 cd->gate_array[reg] = value & 0x0F0F;
618 break;
619 case GA_CDD_CMD4:
620 cdd_run(cd, m68k->current_cycle);
621 cd->gate_array[reg] = value & 0x0F0F;
622 cdd_mcu_start_cmd_recv(&cd->cdd, cd->gate_array + GA_CDD_CTRL);
623 break;
624 case GA_FONT_COLOR:
625 cd->gate_array[reg] = value & 0xFF;
626 break;
627 case GA_FONT_BITS:
628 cd->gate_array[reg] = value;
629 break;
630 case GA_STAMP_SIZE:
631 cd_graphics_run(cd, m68k->current_cycle);
632 cd->gate_array[reg] &= BIT_GRON;
633 cd->gate_array[reg] |= value & (BIT_SMS|BIT_STS|BIT_RPT);
634 break;
635 case GA_STAMP_MAP_BASE:
636 cd_graphics_run(cd, m68k->current_cycle);
637 cd->gate_array[reg] = value & 0xFFE0;
638 break;
639 case GA_IMAGE_BUFFER_VCELLS:
640 cd_graphics_run(cd, m68k->current_cycle);
641 cd->gate_array[reg] = value & 0x1F;
642 break;
643 case GA_IMAGE_BUFFER_START:
644 cd_graphics_run(cd, m68k->current_cycle);
645 cd->gate_array[reg] = value & 0xFFF8;
646 break;
647 case GA_IMAGE_BUFFER_OFFSET:
648 cd_graphics_run(cd, m68k->current_cycle);
649 cd->gate_array[reg] = value & 0x3F;
650 break;
651 case GA_IMAGE_BUFFER_HDOTS:
652 cd_graphics_run(cd, m68k->current_cycle);
653 cd->gate_array[reg] = value & 0x1FF;
654 break;
655 case GA_IMAGE_BUFFER_LINES:
656 cd_graphics_run(cd, m68k->current_cycle);
657 cd->gate_array[reg] = value & 0xFF;
658 break;
659 case GA_TRACE_VECTOR_BASE:
660 cd_graphics_run(cd, m68k->current_cycle);
661 cd->gate_array[reg] = value & 0xFFFE;
662 cd_graphics_start(cd);
663 break;
664 default:
665 printf("Unhandled gate array write %X:%X\n", address, value);
666 }
667 return vcontext;
668 }
669
670 static void *sub_gate_write8(uint32_t address, void *vcontext, uint8_t value)
671 {
672 m68k_context *m68k = vcontext;
673 segacd_context *cd = m68k->system;
674 uint32_t reg = (address & 0x1FF) >> 1;
675 uint16_t value16;
676 switch (address >> 1)
677 {
678 case GA_CDC_HOST_DATA:
679 case GA_CDC_DMA_ADDR:
680 case GA_STOP_WATCH:
681 case GA_COMM_FLAG:
682 case GA_TIMER:
683 case GA_CDD_FADER:
684 case GA_FONT_COLOR:
685 //these registers treat all writes as word-wide
686 value16 = value | (value << 8);
687 break;
688 case GA_CDC_CTRL:
689 if (address & 1) {
690 lc8951_ar_write(&cd->cdc, value);
691 return vcontext;
692 } else {
693 value16 = cd->cdc.ar | (value << 8);
694 }
695 break;
696 case GA_CDD_CMD4:
697 if (!address) {
698 //byte write to $FF804A should not trigger transfer
699 cdd_run(cd, m68k->current_cycle);
700 cd->gate_array[reg] &= 0x0F;
701 cd->gate_array[reg] |= (value << 8 & 0x0F00);
702 return vcontext;
703 }
704 //intentional fallthrough for $FF804B
705 default:
706 if (address & 1) {
707 value16 = cd->gate_array[reg] & 0xFF00 | value;
708 } else {
709 value16 = cd->gate_array[reg] & 0xFF | (value << 8);
710 }
711 }
712 return sub_gate_write16(address, vcontext, value16);
713 }
714
715 static uint8_t handle_cdc_byte(void *vsys, uint8_t value)
716 {
717 segacd_context *cd = vsys;
718 if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) {
719 //host reg is already full, pause transfer
720 return 0;
721 }
722 if (cd->cdc.cycle == cd->cdc.transfer_end) {
723 cd->gate_array[GA_CDC_CTRL] |= BIT_EDT;
724 printf("EDT set at %u\n", cd->cdc.cycle);
725 }
726 uint16_t dest = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7;
727 if (!(cd->cdc_dst_low & 1)) {
728 cd->gate_array[GA_CDC_HOST_DATA] &= 0xFF;
729 cd->gate_array[GA_CDC_HOST_DATA] |= value << 8;
730 cd->cdc_dst_low++;
731 if (dest != DST_PCM_RAM) {
732 //PCM RAM writes a byte at a time
733 return 1;
734 }
735 } else {
736 cd->gate_array[GA_CDC_HOST_DATA] &= 0xFF00;
737 cd->gate_array[GA_CDC_HOST_DATA] |= value;
738 }
739
740 uint32_t dma_addr = cd->gate_array[GA_CDC_DMA_ADDR] << 3;
741 dma_addr |= cd->cdc_dst_low;
742 switch (dest)
743 {
744 case DST_MAIN_CPU:
745 case DST_SUB_CPU:
746 cd->cdc_dst_low = 0;
747 cd->gate_array[GA_CDC_CTRL] |= BIT_DSR;
748 printf("DSR set at %u, (transfer_end %u, dbcl %X, dbch %X)\n", cd->cdc.cycle, cd->cdc.transfer_end, cd->cdc.regs[2], cd->cdc.regs[3]);
749 break;
750 case DST_PCM_RAM:
751 dma_addr &= (1 << 13) - 1;
752 //TODO: write to currently visible 8K bank of PCM RAM I guess?
753 dma_addr += 2;
754 cd->cdc_dst_low = dma_addr & 7;
755 cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3;
756 break;
757 case DST_PROG_RAM:
758 cd->prog_ram[dma_addr >> 1] = cd->gate_array[GA_CDC_HOST_DATA];
759 m68k_invalidate_code_range(cd->m68k, dma_addr - 1, dma_addr + 1);
760 dma_addr++;
761 cd->cdc_dst_low = dma_addr & 7;
762 cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3;
763 break;
764 case DST_WORD_RAM:
765 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) {
766 //1M mode, write to bank assigned to Sub CPU
767 dma_addr &= (1 << 17) - 1;
768 cd->m68k->mem_pointers[1][dma_addr >> 1] = cd->gate_array[GA_CDC_HOST_DATA];
769 m68k_invalidate_code_range(cd->m68k, 0x0C0000 + dma_addr - 1, 0x0C0000 + dma_addr + 1);
770 } else {
771 //2M mode, check if Sub CPU has access
772 if (!(cd->gate_array[GA_MEM_MODE] & BIT_RET)) {
773 dma_addr &= (1 << 18) - 1;
774 cd->word_ram[dma_addr >> 1] = cd->gate_array[GA_CDC_HOST_DATA];
775 m68k_invalidate_code_range(cd->m68k, 0x080000 + dma_addr, 0x080000 + dma_addr + 1);
776 }
777 }
778 dma_addr++;
779 cd->cdc_dst_low = dma_addr & 7;
780 cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3;
781 break;
782 default:
783 printf("Invalid CDC transfer destination %d\n", dest);
784 }
785 return 1;
786 }
787
788 static uint8_t can_main_access_prog(segacd_context *cd)
789 {
790 //TODO: use actual busack
791 return cd->busreq || !cd->reset;
792 }
793
794 static void scd_peripherals_run(segacd_context *cd, uint32_t cycle)
795 {
796 timers_run(cd, cycle);
797 cdd_run(cd, cycle);
798 cd_graphics_run(cd, cycle);
799 }
800
801 static m68k_context *sync_components(m68k_context * context, uint32_t address)
802 {
803 segacd_context *cd = context->system;
804 scd_peripherals_run(cd, context->current_cycle);
805 switch (context->int_ack)
806 {
807 case 1:
808 cd->graphics_int_cycle = CYCLE_NEVER;
809 break;
810 case 2:
811 cd->int2_cycle = CYCLE_NEVER;
812 break;
813 case 3:
814 cd->timer_pending = 0;
815 break;
816 case 4:
817 cd->cdd.int_pending = 0;
818 break;
819 case 5:
820 cd->cdc_int_ack = 1;
821 break;
822 }
823 context->int_ack = 0;
824 calculate_target_cycle(context);
825 return context;
826 }
827
828 void scd_run(segacd_context *cd, uint32_t cycle)
829 {
830 uint8_t m68k_run = !can_main_access_prog(cd);
831 if (cycle > cd->m68k->current_cycle) {
832 if (m68k_run) {
833 uint32_t start = cd->m68k->current_cycle;
834 cd->m68k->sync_cycle = cycle;
835 if (cd->need_reset) {
836 cd->need_reset = 0;
837 m68k_reset(cd->m68k);
838 } else {
839 calculate_target_cycle(cd->m68k);
840 resume_68k(cd->m68k);
841 }
842 } else {
843 cd->m68k->current_cycle = cycle;
844 }
845 }
846 scd_peripherals_run(cd, cycle);
847 }
848
849 uint32_t gen_cycle_to_scd(uint32_t cycle, genesis_context *gen)
850 {
851 return ((uint64_t)cycle) * ((uint64_t)SCD_MCLKS) / ((uint64_t)gen->normal_clock);
852 }
853
854 void scd_adjust_cycle(segacd_context *cd, uint32_t deduction)
855 {
856 deduction = gen_cycle_to_scd(deduction, cd->genesis);
857 cd->m68k->current_cycle -= deduction;
858 cd->stopwatch_cycle -= deduction;
859 if (deduction >= cd->int2_cycle) {
860 cd->int2_cycle = 0;
861 } else if (cd->int2_cycle != CYCLE_NEVER) {
862 cd->int2_cycle -= deduction;
863 }
864 if (deduction >= cd->periph_reset_cycle) {
865 cd->periph_reset_cycle = CYCLE_NEVER;
866 } else if (cd->periph_reset_cycle != CYCLE_NEVER) {
867 cd->periph_reset_cycle -= deduction;
868 }
869 cdd_mcu_adjust_cycle(&cd->cdd, deduction);
870 lc8951_adjust_cycles(&cd->cdc, deduction);
871 cd->graphics_cycle -= deduction;
872 if (cd->graphics_int_cycle != CYCLE_NEVER) {
873 if (cd->graphics_int_cycle > deduction) {
874 cd->graphics_int_cycle -= deduction;
875 } else {
876 cd->graphics_int_cycle = 0;
877 }
878 }
879 }
880
881 static uint16_t main_gate_read16(uint32_t address, void *vcontext)
882 {
883 m68k_context *m68k = vcontext;
884 genesis_context *gen = m68k->system;
885 segacd_context *cd = gen->expansion;
886 uint32_t scd_cycle = gen_cycle_to_scd(m68k->current_cycle, gen);
887 scd_run(cd, scd_cycle);
888 uint32_t offset = (address & 0x1FF) >> 1;
889 switch (offset)
890 {
891 case GA_SUB_CPU_CTRL: {
892 uint16_t value = 0;
893 if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN2) {
894 value |= BIT_IEN2;
895 }
896 if (cd->int2_cycle != CYCLE_NEVER) {
897 value |= BIT_IFL2;
898 }
899 if (can_main_access_prog(cd)) {
900 value |= BIT_SBRQ;
901 }
902 if (cd->reset) {
903 value |= BIT_SRES;
904 }
905 return value;
906 }
907 case GA_MEM_MODE:
908 //Main CPU can't read priority mode bits
909 return cd->gate_array[offset] & 0xFFE7;
910 case GA_HINT_VECTOR:
911 return cd->rom_mut[0x72/2];
912 case GA_CDC_HOST_DATA: {
913 uint16_t dst = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7;
914 if (dst == DST_MAIN_CPU) {
915 if (cd->gate_array[GA_CDC_CTRL] & BIT_DSR) {
916 printf("DSR cleared at %u (%u)\n", scd_cycle, cd->cdc.cycle);
917 cd->gate_array[GA_CDC_CTRL] &= ~BIT_DSR;
918 lc8951_resume_transfer(&cd->cdc, scd_cycle);
919 } else {
920 printf("Read of CDC host data with DSR clear at %u\n", scd_cycle);
921 }
922 calculate_target_cycle(cd->m68k);
923 }
924 return cd->gate_array[offset];
925 }
926 case GA_CDC_DMA_ADDR:
927 //TODO: open bus maybe?
928 return 0xFFFF;
929 default:
930 if (offset < GA_TIMER) {
931 if (offset == GA_CDC_CTRL) {
932 printf("CDC read(main): %X - %X @ %u (%u)\n", address, cd->gate_array[offset], m68k->current_cycle, scd_cycle);
933 } else if (offset >= GA_COMM_FLAG && offset <= GA_COMM_STATUS7) {
934 printf("COMM read(main): %X - %X @ %u (%u)\n", address, cd->gate_array[offset], m68k->current_cycle, scd_cycle);
935 }
936 return cd->gate_array[offset];
937 }
938 //TODO: open bus maybe?
939 return 0xFFFF;
940 }
941 }
942
943 static uint8_t main_gate_read8(uint32_t address, void *vcontext)
944 {
945 uint16_t val = main_gate_read16(address & 0xFE, vcontext);
946 return address & 1 ? val : val >> 8;
947 }
948
949 static void dump_prog_ram(segacd_context *cd)
950 {
951 static int dump_count;
952 char fname[256];
953 sprintf(fname, "prog_ram_%d.bin", dump_count++);
954 FILE *f = fopen(fname, "wb");
955 if (f) {
956 uint32_t last = 256*1024-1;
957 for(; last > 0; --last)
958 {
959 if (cd->prog_ram[last]) {
960 break;
961 }
962 }
963 for (uint32_t i = 0; i <= last; i++)
964 {
965 uint8_t pair[2];
966 pair[0] = cd->prog_ram[i] >> 8;
967 pair[1] = cd->prog_ram[i];
968 fwrite(pair, 1, sizeof(pair), f);
969 }
970
971 fclose(f);
972 }
973 }
974
975 static void *main_gate_write16(uint32_t address, void *vcontext, uint16_t value)
976 {
977 m68k_context *m68k = vcontext;
978 genesis_context *gen = m68k->system;
979 segacd_context *cd = gen->expansion;
980 uint32_t scd_cycle = gen_cycle_to_scd(m68k->current_cycle, gen);
981 scd_run(cd, scd_cycle);
982 uint32_t reg = (address & 0x1FF) >> 1;
983 switch (reg)
984 {
985 case GA_SUB_CPU_CTRL: {
986 uint8_t old_access = can_main_access_prog(cd);
987 cd->busreq = value & BIT_SBRQ;
988 uint8_t old_reset = cd->reset;
989 cd->reset = value & BIT_SRES;
990 if (cd->reset && !old_reset) {
991 cd->need_reset = 1;
992 }
993 if (value & BIT_IFL2) {
994 cd->int2_cycle = scd_cycle;
995 }
996 /*cd->gate_array[reg] &= 0x7FFF;
997 cd->gate_array[reg] |= value & 0x8000;*/
998 uint8_t new_access = can_main_access_prog(cd);
999 uint32_t bank = cd->gate_array[GA_MEM_MODE] >> 6 & 0x3;
1000 if (new_access) {
1001 if (!old_access) {
1002 m68k->mem_pointers[cd->memptr_start_index] = cd->prog_ram + bank * 0x10000;
1003 m68k_invalidate_code_range(m68k, cd->base + 0x220000, cd->base + 0x240000);
1004 }
1005 } else if (old_access) {
1006 m68k->mem_pointers[cd->memptr_start_index] = NULL;
1007 m68k_invalidate_code_range(m68k, cd->base + 0x220000, cd->base + 0x240000);
1008 m68k_invalidate_code_range(cd->m68k, bank * 0x20000, (bank + 1) * 0x20000);
1009 if (!new_access) {
1010 dump_prog_ram(cd);
1011 }
1012 }
1013 break;
1014 }
1015 case GA_MEM_MODE: {
1016 uint16_t changed = cd->gate_array[reg] ^ value;
1017 //Main CPU can't write priority mode bits, MODE or RET
1018 cd->gate_array[reg] &= 0x001F;
1019 cd->gate_array[reg] |= value & 0xFFC0;
1020 if ((cd->gate_array[reg] & BIT_MEM_MODE)) {
1021 //1M mode
1022 if (!(value & BIT_DMNA)) {
1023 cd->gate_array[reg] |= BIT_DMNA;
1024 }
1025 } else {
1026 //2M mode
1027 if (changed & value & BIT_DMNA) {
1028 cd->gate_array[reg] |= BIT_DMNA;
1029 m68k->mem_pointers[cd->memptr_start_index + 1] = NULL;
1030 m68k->mem_pointers[cd->memptr_start_index + 2] = NULL;
1031 cd->m68k->mem_pointers[0] = cd->word_ram;
1032 cd->gate_array[reg] &= ~BIT_RET;
1033
1034 m68k_invalidate_code_range(m68k, cd->base + 0x200000, cd->base + 0x240000);
1035 m68k_invalidate_code_range(cd->m68k, 0x080000, 0x0C0000);
1036 }
1037 }
1038 if (changed & MASK_PROG_BANK && can_main_access_prog(cd)) {
1039 uint32_t bank = cd->gate_array[GA_MEM_MODE] >> 6 & 0x3;
1040 m68k->mem_pointers[cd->memptr_start_index] = cd->prog_ram + bank * 0x10000;
1041 m68k_invalidate_code_range(m68k, cd->base + 0x220000, cd->base + 0x240000);
1042 }
1043 break;
1044 }
1045 case GA_HINT_VECTOR:
1046 cd->rom_mut[0x72/2] = value;
1047 break;
1048 case GA_COMM_FLAG:
1049 //Main CPU can only write the upper byte;
1050 cd->gate_array[reg] &= 0xFF;
1051 cd->gate_array[reg] |= value & 0xFF00;
1052 printf("COMM write(main): %X - %X @ %u (%u)\n", address, value, m68k->current_cycle, scd_cycle);
1053 break;
1054 case GA_COMM_CMD0:
1055 case GA_COMM_CMD1:
1056 case GA_COMM_CMD2:
1057 case GA_COMM_CMD3:
1058 case GA_COMM_CMD4:
1059 case GA_COMM_CMD5:
1060 case GA_COMM_CMD6:
1061 case GA_COMM_CMD7:
1062 //no effects for these other than saving the value
1063 printf("COMM write(main): %X - %X @ %u (%u)\n", address, value, m68k->current_cycle, scd_cycle);
1064 cd->gate_array[reg] = value;
1065 break;
1066 default:
1067 printf("Unhandled gate array write %X:%X\n", address, value);
1068 }
1069 return vcontext;
1070 }
1071
1072 static void *main_gate_write8(uint32_t address, void *vcontext, uint8_t value)
1073 {
1074 m68k_context *m68k = vcontext;
1075 genesis_context *gen = m68k->system;
1076 segacd_context *cd = gen->expansion;
1077 uint32_t reg = (address & 0x1FF) >> 1;
1078 uint16_t value16;
1079 switch (reg >> 1)
1080 {
1081 case GA_SUB_CPU_CTRL:
1082 if (address & 1) {
1083 value16 = value;
1084 } else {
1085 value16 = value << 8;
1086 if (cd->reset) {
1087 value16 |= BIT_SRES;
1088 }
1089 if (cd->busreq) {
1090 value16 |= BIT_SBRQ;
1091 }
1092 }
1093 break;
1094 case GA_HINT_VECTOR:
1095 case GA_COMM_FLAG:
1096 //writes to these regs are always treated as word wide
1097 value16 = value | (value << 8);
1098 break;
1099 default:
1100 if (address & 1) {
1101 value16 = cd->gate_array[reg] & 0xFF00 | value;
1102 } else {
1103 value16 = cd->gate_array[reg] & 0xFF | (value << 8);
1104 }
1105 }
1106 return main_gate_write16(address, vcontext, value16);
1107 }
1108
1109 segacd_context *alloc_configure_segacd(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info)
1110 {
1111 static memmap_chunk sub_cpu_map[] = {
1112 {0x000000, 0x01FEFF, 0xFFFFFF, .flags=MMAP_READ | MMAP_CODE, .write_16 = prog_ram_wp_write16, .write_8 = prog_ram_wp_write8},
1113 {0x01FF00, 0x07FFFF, 0xFFFFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE},
1114 {0x080000, 0x0BFFFF, 0x03FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 0,
1115 .read_16 = word_ram_2M_read16, .write_16 = word_ram_2M_write16, .read_8 = word_ram_2M_read8, .write_8 = word_ram_2M_write8},
1116 {0x0C0000, 0x0DFFFF, 0x01FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 1,
1117 .read_16 = word_ram_1M_read16, .write_16 = word_ram_1M_write16, .read_8 = word_ram_1M_read8, .write_8 = word_ram_1M_write8},
1118 {0xFE0000, 0xFEFFFF, 0x003FFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_ONLY_ODD},
1119 {0xFF0000, 0xFF7FFF, 0x003FFF, .read_16 = pcm_read16, .write_16 = pcm_write16, .read_8 = pcm_read8, .write_8 = pcm_write8},
1120 {0xFF8000, 0xFF81FF, 0x0001FF, .read_16 = sub_gate_read16, .write_16 = sub_gate_write16, .read_8 = sub_gate_read8, .write_8 = sub_gate_write8}
1121 };
1122
1123 segacd_context *cd = calloc(sizeof(segacd_context), 1);
1124 FILE *f = fopen("cdbios.bin", "rb");
1125 if (!f) {
1126 fatal_error("Failed to open CD firmware for reading");
1127 }
1128 long firmware_size = file_size(f);
1129 uint32_t adjusted_size = nearest_pow2(firmware_size);
1130 cd->rom = malloc(adjusted_size);
1131 if (firmware_size != fread(cd->rom, 1, firmware_size, f)) {
1132 fatal_error("Failed to read CD firmware");
1133 }
1134 cd->rom_mut = malloc(adjusted_size);
1135 byteswap_rom(adjusted_size, cd->rom);
1136 memcpy(cd->rom_mut, cd->rom, adjusted_size);
1137 cd->rom_mut[0x72/2] = 0xFFFF;
1138
1139 //memset(info, 0, sizeof(*info));
1140 //tern_node *db = get_rom_db();
1141 //*info = configure_rom(db, media->buffer, media->size, media->chain ? media->chain->buffer : NULL, media->chain ? media->chain->size : 0, NULL, 0);
1142
1143 cd->prog_ram = malloc(512*1024);
1144 cd->word_ram = malloc(256*1024);
1145 cd->pcm_ram = malloc(64*1024);
1146 //TODO: Load state from file
1147 cd->bram = malloc(8*1024);
1148
1149
1150 sub_cpu_map[0].buffer = sub_cpu_map[1].buffer = cd->prog_ram;
1151 sub_cpu_map[4].buffer = cd->bram;
1152 m68k_options *mopts = malloc(sizeof(m68k_options));
1153 init_m68k_opts(mopts, sub_cpu_map, sizeof(sub_cpu_map) / sizeof(*sub_cpu_map), 4, sync_components);
1154 cd->m68k = init_68k_context(mopts, NULL);
1155 cd->m68k->system = cd;
1156 cd->int2_cycle = CYCLE_NEVER;
1157 cd->busreq = 1;
1158 cd->busack = 1;
1159 cd->need_reset = 1;
1160 cd->reset = 1; //active low, so reset is not active on start
1161 cd->memptr_start_index = 0;
1162 cd->gate_array[1] = 1;
1163 cd->gate_array[0x1B] = 0x100;
1164 lc8951_init(&cd->cdc, handle_cdc_byte, cd);
1165 if (media->chain && media->type != MEDIA_CDROM) {
1166 media = media->chain;
1167 }
1168 cdd_mcu_init(&cd->cdd, media);
1169 cd_graphics_init(cd);
1170
1171 return cd;
1172 }
1173
1174 memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint8_t cart_boot, uint32_t *num_chunks)
1175 {
1176 static memmap_chunk main_cpu_map[] = {
1177 {0x000000, 0x01FFFF, 0x01FFFF, .flags=MMAP_READ},
1178 {0x020000, 0x03FFFF, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .ptr_index = 0,
1179 .read_16 = unmapped_prog_read16, .write_16 = unmapped_prog_write16, .read_8 = unmapped_prog_read8, .write_8 = unmapped_prog_write8},
1180 {0x040000, 0x05FFFF, 0x01FFFF, .flags=MMAP_READ}, //first ROM alias
1181 //TODO: additional ROM/prog RAM aliases
1182 {0x200000, 0x21FFFF, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .ptr_index = 1,
1183 .read_16 = unmapped_word_read16, .write_16 = unmapped_word_write16, .read_8 = unmapped_word_read8, .write_8 = unmapped_word_write8},
1184 {0x220000, 0x23FFFF, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .ptr_index = 2,
1185 .read_16 = cell_image_read16, .write_16 = cell_image_write16, .read_8 = cell_image_read8, .write_8 = cell_image_write8},
1186 {0xA12000, 0xA12FFF, 0xFFFFFF, .read_16 = main_gate_read16, .write_16 = main_gate_write16, .read_8 = main_gate_read8, .write_8 = main_gate_write8}
1187 };
1188 for (int i = 0; i < sizeof(main_cpu_map) / sizeof(*main_cpu_map); i++)
1189 {
1190 if (main_cpu_map[i].start < 0x800000) {
1191 if (cart_boot) {
1192 main_cpu_map[i].start |= 0x400000;
1193 main_cpu_map[i].end |= 0x400000;
1194 } else {
1195 main_cpu_map[i].start &= 0x3FFFFF;
1196 main_cpu_map[i].end &= 0x3FFFFF;
1197 }
1198 }
1199 }
1200 //TODO: support BRAM cart
1201 main_cpu_map[0].buffer = cd->rom_mut;
1202 main_cpu_map[2].buffer = cd->rom;
1203 main_cpu_map[1].buffer = cd->prog_ram;
1204 main_cpu_map[3].buffer = cd->word_ram;
1205 main_cpu_map[4].buffer = cd->word_ram + 0x10000;
1206 *num_chunks = sizeof(main_cpu_map) / sizeof(*main_cpu_map);
1207 return main_cpu_map;
1208 }