Mercurial > repos > blastem
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 } |