Mercurial > repos > blastem
comparison segacd.c @ 2054:8ee7ecbf3f21 segacd
Implement enough of Sega CD gate array and Sub CPU to pass Sik's Mode 1 test ROM
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 18 Jan 2022 00:03:50 -0800 |
parents | 95b3a1a8b26c |
children | c4d066d798c4 |
comparison
equal
deleted
inserted
replaced
2053:3414a4423de1 | 2054:8ee7ecbf3f21 |
---|---|
2 #include <string.h> | 2 #include <string.h> |
3 #include "segacd.h" | 3 #include "segacd.h" |
4 #include "genesis.h" | 4 #include "genesis.h" |
5 #include "util.h" | 5 #include "util.h" |
6 | 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 | |
41 GA_HINT_VECTOR = GA_CDC_REG_DATA | |
42 }; | |
43 //GA_SUB_CPU_CTRL | |
44 #define BIT_IEN2 0x8000 | |
45 #define BIT_IFL2 0x0100 | |
46 #define BIT_LEDG 0x0100 | |
47 #define BIT_LEDR 0x0080 | |
48 #define BIT_SBRQ 0x0002 | |
49 #define BIT_SRES 0x0001 | |
50 #define BIT_PRES 0x0001 | |
51 //GA_MEM_MODE | |
52 #define MASK_PROG_BANK 0x00C0 | |
53 #define MASK_PRIORITY 0x0018 | |
54 #define BIT_MEM_MODE 0x0004 | |
55 #define BIT_DMNA 0x0002 | |
56 #define BIT_RET 0x0001 | |
57 //GA_INT_MASK | |
58 #define BIT_MASK_IEN1 0x0002 | |
59 #define BIT_MASK_IEN2 0x0004 | |
60 #define BIT_MASK_IEN3 0x0008 | |
61 #define BIT_MASK_IEN4 0x0010 | |
62 #define BIT_MASK_IEN5 0x0020 | |
63 #define BIT_MASK_IEN6 0x0040 | |
64 | |
7 static void *prog_ram_wp_write16(uint32_t address, void *vcontext, uint16_t value) | 65 static void *prog_ram_wp_write16(uint32_t address, void *vcontext, uint16_t value) |
8 { | 66 { |
67 m68k_context *m68k = vcontext; | |
68 segacd_context *cd = m68k->system; | |
69 if (!(cd->gate_array[GA_MEM_MODE] & (1 << ((address >> 17) + 8)))) { | |
70 cd->prog_ram[address >> 1] = value; | |
71 m68k_invalidate_code_range(m68k, address, address + 2); | |
72 } | |
9 return vcontext; | 73 return vcontext; |
10 } | 74 } |
11 | 75 |
12 static void *prog_ram_wp_write8(uint32_t address, void *vcontext, uint8_t value) | 76 static void *prog_ram_wp_write8(uint32_t address, void *vcontext, uint8_t value) |
13 { | 77 { |
14 return vcontext; | 78 m68k_context *m68k = vcontext; |
15 } | 79 segacd_context *cd = m68k->system; |
16 | 80 if (!(cd->gate_array[GA_MEM_MODE] & (1 << ((address >> 17) + 8)))) { |
17 static uint16_t work_ram_2M_read16(uint32_t address, void *vcontext) | 81 ((uint8_t *)cd->prog_ram)[address ^ 1] = value; |
82 m68k_invalidate_code_range(m68k, address, address + 1); | |
83 } | |
84 return vcontext; | |
85 } | |
86 | |
87 static uint16_t word_ram_2M_read16(uint32_t address, void *vcontext) | |
18 { | 88 { |
19 return 0; | 89 return 0; |
20 } | 90 } |
21 | 91 |
22 static uint8_t work_ram_2M_read8(uint32_t address, void *vcontext) | 92 static uint8_t word_ram_2M_read8(uint32_t address, void *vcontext) |
23 { | 93 { |
24 return 0; | 94 return 0; |
25 } | 95 } |
26 | 96 |
27 static void *work_ram_2M_write16(uint32_t address, void *vcontext, uint16_t value) | 97 static void *word_ram_2M_write16(uint32_t address, void *vcontext, uint16_t value) |
28 { | 98 { |
29 return vcontext; | 99 return vcontext; |
30 } | 100 } |
31 | 101 |
32 static void *work_ram_2M_write8(uint32_t address, void *vcontext, uint8_t value) | 102 static void *word_ram_2M_write8(uint32_t address, void *vcontext, uint8_t value) |
33 { | 103 { |
34 return vcontext; | 104 return vcontext; |
35 } | 105 } |
36 | 106 |
37 static uint16_t work_ram_1M_read16(uint32_t address, void *vcontext) | 107 static uint16_t word_ram_1M_read16(uint32_t address, void *vcontext) |
38 { | 108 { |
39 return 0; | 109 return 0; |
40 } | 110 } |
41 | 111 |
42 static uint8_t work_ram_1M_read8(uint32_t address, void *vcontext) | 112 static uint8_t word_ram_1M_read8(uint32_t address, void *vcontext) |
43 { | 113 { |
44 return 0; | 114 return 0; |
45 } | 115 } |
46 | 116 |
47 static void *work_ram_1M_write16(uint32_t address, void *vcontext, uint16_t value) | 117 static void *word_ram_1M_write16(uint32_t address, void *vcontext, uint16_t value) |
48 { | 118 { |
49 return vcontext; | 119 return vcontext; |
50 } | 120 } |
51 | 121 |
52 static void *work_ram_1M_write8(uint32_t address, void *vcontext, uint8_t value) | 122 static void *word_ram_1M_write8(uint32_t address, void *vcontext, uint8_t value) |
123 { | |
124 return vcontext; | |
125 } | |
126 | |
127 | |
128 static uint16_t unmapped_prog_read16(uint32_t address, void *vcontext) | |
129 { | |
130 return 0xFFFF; | |
131 } | |
132 | |
133 static uint8_t unmapped_prog_read8(uint32_t address, void *vcontext) | |
134 { | |
135 return 0xFF; | |
136 } | |
137 | |
138 static void *unmapped_prog_write16(uint32_t address, void *vcontext, uint16_t value) | |
139 { | |
140 return vcontext; | |
141 } | |
142 | |
143 static void *unmapped_prog_write8(uint32_t address, void *vcontext, uint8_t value) | |
53 { | 144 { |
54 return vcontext; | 145 return vcontext; |
55 } | 146 } |
56 | 147 |
57 static uint8_t pcm_read8(uint32_t address, void *vcontext) | 148 static uint8_t pcm_read8(uint32_t address, void *vcontext) |
72 static void *pcm_write16(uint32_t address, void *vcontext, uint16_t value) | 163 static void *pcm_write16(uint32_t address, void *vcontext, uint16_t value) |
73 { | 164 { |
74 return pcm_write8(address+1, vcontext, value); | 165 return pcm_write8(address+1, vcontext, value); |
75 } | 166 } |
76 | 167 |
168 | |
169 static void timers_run(segacd_context *cd, uint32_t cycle) | |
170 { | |
171 uint32_t ticks = (cycle - cd->stopwatch_cycle) / TIMER_TICK_CLKS; | |
172 cd->stopwatch_cycle += ticks * TIMER_TICK_CLKS; | |
173 cd->gate_array[GA_STOP_WATCH] += ticks; | |
174 cd->gate_array[GA_STOP_WATCH] &= 0xFFF; | |
175 if (!cd->timer_value) { | |
176 --ticks; | |
177 cd->timer_value = cd->gate_array[GA_TIMER]; | |
178 } | |
179 if (cd->timer_value) { | |
180 while (ticks >= (cd->timer_value + 1)) { | |
181 ticks -= cd->timer_value + 1; | |
182 cd->timer_value = cd->gate_array[GA_TIMER]; | |
183 cd->timer_pending = 1; | |
184 } | |
185 cd->timer_value -= ticks; | |
186 if (!cd->timer_value) { | |
187 cd->timer_pending = 1; | |
188 } | |
189 } | |
190 } | |
191 | |
192 static uint32_t next_timer_int(segacd_context *cd) | |
193 { | |
194 if (cd->timer_pending) { | |
195 return cd->stopwatch_cycle; | |
196 } | |
197 if (cd->timer_value) { | |
198 return cd->stopwatch_cycle + TIMER_TICK_CLKS * cd->timer_value; | |
199 } | |
200 if (cd->gate_array[GA_TIMER]) { | |
201 return cd->stopwatch_cycle + TIMER_TICK_CLKS * (cd->gate_array[GA_TIMER] + 1); | |
202 } | |
203 return CYCLE_NEVER; | |
204 } | |
205 | |
206 static void calculate_target_cycle(m68k_context * context) | |
207 { | |
208 segacd_context *cd = context->system; | |
209 context->int_cycle = CYCLE_NEVER; | |
210 uint8_t mask = context->status & 0x7; | |
211 if (mask < 3) { | |
212 uint32_t next_timer; | |
213 if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN3) { | |
214 uint32_t next_timer_cycle = next_timer_int(cd); | |
215 if (next_timer_cycle < context->int_cycle) { | |
216 context->int_cycle = next_timer_cycle; | |
217 context->int_num = 3; | |
218 } | |
219 } | |
220 if (mask < 2) { | |
221 if (cd->int2_cycle < context->int_cycle && (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN2)) { | |
222 context->int_cycle = cd->int2_cycle; | |
223 context->int_num = 2; | |
224 } | |
225 } | |
226 } | |
227 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) { | |
228 context->int_pending = INT_PENDING_NONE; | |
229 } | |
230 if (context->current_cycle >= context->sync_cycle) { | |
231 context->should_return = 1; | |
232 context->target_cycle = context->current_cycle; | |
233 return; | |
234 } | |
235 if (context->status & M68K_STATUS_TRACE || context->trace_pending) { | |
236 context->target_cycle = context->current_cycle; | |
237 return; | |
238 } | |
239 context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle; | |
240 } | |
241 | |
77 static uint16_t sub_gate_read16(uint32_t address, void *vcontext) | 242 static uint16_t sub_gate_read16(uint32_t address, void *vcontext) |
78 { | 243 { |
79 m68k_context *m68k = vcontext; | 244 m68k_context *m68k = vcontext; |
80 segacd_context *cd = m68k->system; | 245 segacd_context *cd = m68k->system; |
81 return cd->gate_array[(address & 0x1FF) >> 1]; | 246 uint32_t reg = address >> 1; |
82 } | |
83 | |
84 static uint8_t sub_gate_read8(uint32_t address, void *vcontext) | |
85 { | |
86 m68k_context *m68k = vcontext; | |
87 segacd_context *cd = m68k->system; | |
88 uint16_t val = cd->gate_array[(address & 0x1FF) >> 1]; | |
89 return address & 1 ? val : val >> 8; | |
90 } | |
91 | |
92 static void *sub_gate_write16(uint32_t address, void *vcontext, uint16_t value) | |
93 { | |
94 m68k_context *m68k = vcontext; | |
95 segacd_context *cd = m68k->system; | |
96 uint32_t reg = (address & 0x1FF) >> 1; | |
97 switch (reg) | 247 switch (reg) |
98 { | 248 { |
99 case 0x7: | 249 case GA_SUB_CPU_CTRL: { |
250 uint16_t value = cd->gate_array[reg] & 0xFFFE; | |
251 if (cd->periph_reset_cycle == CYCLE_NEVER || (m68k->current_cycle - cd->periph_reset_cycle) > SCD_PERIPH_RESET_CLKS) { | |
252 value |= BIT_PRES; | |
253 } | |
254 return value; | |
255 } | |
256 case GA_MEM_MODE: | |
257 return cd->gate_array[reg] & 0xFF1F; | |
258 case GA_STOP_WATCH: | |
259 case GA_TIMER: | |
260 timers_run(cd, m68k->current_cycle); | |
261 return cd->gate_array[reg]; | |
262 default: | |
263 return cd->gate_array[reg]; | |
264 } | |
265 } | |
266 | |
267 static uint8_t sub_gate_read8(uint32_t address, void *vcontext) | |
268 { | |
269 uint16_t val = sub_gate_read16(address, vcontext); | |
270 return address & 1 ? val : val >> 8; | |
271 } | |
272 | |
273 static void *sub_gate_write16(uint32_t address, void *vcontext, uint16_t value) | |
274 { | |
275 m68k_context *m68k = vcontext; | |
276 segacd_context *cd = m68k->system; | |
277 uint32_t reg = address >> 1; | |
278 switch (reg) | |
279 { | |
280 case GA_SUB_CPU_CTRL: | |
281 cd->gate_array[reg] &= 0xF0; | |
282 cd->gate_array[reg] |= value & (BIT_LEDG|BIT_LEDR); | |
283 if (value & BIT_PRES) { | |
284 cd->periph_reset_cycle = m68k->current_cycle; | |
285 } | |
286 break; | |
287 case GA_MEM_MODE: { | |
288 uint16_t changed = value ^ cd->gate_array[reg]; | |
289 genesis_context *gen = cd->genesis; | |
290 if (changed & BIT_MEM_MODE) { | |
291 //FIXME: ram banks are supposed to be interleaved when in 2M mode | |
292 cd->gate_array[reg] &= ~BIT_DMNA; | |
293 if (value & BIT_MEM_MODE) { | |
294 //switch to 1M mode | |
295 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = (value & BIT_RET) ? cd->word_ram + 0x10000 : cd->word_ram; | |
296 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; | |
297 m68k->mem_pointers[0] = NULL; | |
298 m68k->mem_pointers[1] = (value & BIT_RET) ? cd->word_ram : cd->word_ram + 0x10000; | |
299 } else { | |
300 //switch to 2M mode | |
301 if (value & BIT_RET) { | |
302 //Main CPU will have word ram | |
303 genesis_context *gen = cd->genesis; | |
304 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = cd->word_ram; | |
305 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = cd->word_ram + 0x10000; | |
306 m68k->mem_pointers[0] = NULL; | |
307 m68k->mem_pointers[1] = NULL; | |
308 } else { | |
309 //sub cpu will have word ram | |
310 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = NULL; | |
311 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; | |
312 m68k->mem_pointers[0] = cd->word_ram; | |
313 m68k->mem_pointers[1] = NULL; | |
314 } | |
315 } | |
316 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); | |
317 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); | |
318 } else if (changed & BIT_RET) { | |
319 cd->gate_array[reg] &= ~BIT_DMNA; | |
320 if (value & BIT_MEM_MODE) { | |
321 //swapping banks in 1M mode | |
322 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = (value & BIT_RET) ? cd->word_ram + 0x10000 : cd->word_ram; | |
323 m68k->mem_pointers[1] = (value & BIT_RET) ? cd->word_ram : cd->word_ram + 0x10000; | |
324 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); | |
325 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); | |
326 } else if (value & BIT_RET) { | |
327 //giving word ram to main CPU in 2M mode | |
328 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = cd->word_ram; | |
329 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = cd->word_ram + 0x10000; | |
330 m68k->mem_pointers[0] = NULL; | |
331 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); | |
332 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); | |
333 } | |
334 } | |
335 cd->gate_array[reg] &= 0xFFC2; | |
336 cd->gate_array[reg] |= value & (BIT_RET|BIT_MEM_MODE|MASK_PRIORITY); | |
337 break; | |
338 } | |
339 case GA_STOP_WATCH: | |
340 //docs say you should only write zero to reset | |
341 //unclear what happens when other values are written | |
342 timers_run(cd, m68k->current_cycle); | |
343 cd->gate_array[reg] = value & 0xFFF; | |
344 break; | |
345 case GA_COMM_FLAG: | |
100 cd->gate_array[reg] &= 0xFF00; | 346 cd->gate_array[reg] &= 0xFF00; |
101 cd->gate_array[reg] |= value & 0xFF; | 347 cd->gate_array[reg] |= value & 0xFF; |
102 break; | 348 break; |
103 case 0x10: | 349 case GA_COMM_STATUS0: |
104 case 0x11: | 350 case GA_COMM_STATUS1: |
105 case 0x12: | 351 case GA_COMM_STATUS2: |
106 case 0x13: | 352 case GA_COMM_STATUS3: |
107 case 0x14: | 353 case GA_COMM_STATUS4: |
108 case 0x15: | 354 case GA_COMM_STATUS5: |
109 case 0x16: | 355 case GA_COMM_STATUS6: |
110 case 0x17: | 356 case GA_COMM_STATUS7: |
111 //no effects for these other than saving the value | 357 //no effects for these other than saving the value |
112 cd->gate_array[reg] = value; | 358 cd->gate_array[reg] = value; |
359 break; | |
360 case GA_TIMER: | |
361 timers_run(cd, m68k->current_cycle); | |
362 cd->gate_array[reg] = value & 0xFF; | |
363 calculate_target_cycle(m68k); | |
364 break; | |
365 case GA_INT_MASK: | |
366 cd->gate_array[reg] = value & (BIT_MASK_IEN6|BIT_MASK_IEN5|BIT_MASK_IEN4|BIT_MASK_IEN3|BIT_MASK_IEN2|BIT_MASK_IEN1); | |
367 calculate_target_cycle(m68k); | |
113 break; | 368 break; |
114 default: | 369 default: |
115 printf("Unhandled gate array write %X:%X\n", address, value); | 370 printf("Unhandled gate array write %X:%X\n", address, value); |
116 } | 371 } |
117 return vcontext; | 372 return vcontext; |
129 value16 = cd->gate_array[reg] & 0xFF | (value << 8); | 384 value16 = cd->gate_array[reg] & 0xFF | (value << 8); |
130 } | 385 } |
131 return sub_gate_write16(address, vcontext, value16); | 386 return sub_gate_write16(address, vcontext, value16); |
132 } | 387 } |
133 | 388 |
389 static uint8_t can_main_access_prog(segacd_context *cd) | |
390 { | |
391 //TODO: use actual busack | |
392 return cd->busreq || !cd->reset; | |
393 } | |
394 | |
395 static void scd_peripherals_run(segacd_context *cd, uint32_t cycle) | |
396 { | |
397 timers_run(cd, cycle); | |
398 } | |
399 | |
400 static m68k_context *sync_components(m68k_context * context, uint32_t address) | |
401 { | |
402 segacd_context *cd = context->system; | |
403 scd_peripherals_run(cd, context->current_cycle); | |
404 calculate_target_cycle(context); | |
405 return context; | |
406 } | |
407 | |
408 void scd_run(segacd_context *cd, uint32_t cycle) | |
409 { | |
410 uint8_t m68k_run = !can_main_access_prog(cd); | |
411 if (m68k_run) { | |
412 cd->m68k->sync_cycle = cycle; | |
413 if (cd->need_reset) { | |
414 cd->need_reset = 0; | |
415 m68k_reset(cd->m68k); | |
416 } else { | |
417 calculate_target_cycle(cd->m68k); | |
418 resume_68k(cd->m68k); | |
419 } | |
420 } else { | |
421 cd->m68k->current_cycle = cycle; | |
422 } | |
423 scd_peripherals_run(cd, cycle); | |
424 } | |
425 | |
426 uint32_t gen_cycle_to_scd(uint32_t cycle, genesis_context *gen) | |
427 { | |
428 return ((uint64_t)cycle) * ((uint64_t)gen->normal_clock) / ((uint64_t)SCD_MCLKS); | |
429 } | |
430 | |
431 void scd_adjust_cycle(segacd_context *cd, uint32_t deduction) | |
432 { | |
433 deduction = gen_cycle_to_scd(deduction, cd->genesis); | |
434 cd->m68k->current_cycle -= deduction; | |
435 cd->stopwatch_cycle -= deduction; | |
436 if (deduction >= cd->int2_cycle) { | |
437 cd->int2_cycle = 0; | |
438 } else if (cd->int2_cycle != CYCLE_NEVER) { | |
439 cd->int2_cycle -= deduction; | |
440 } | |
441 if (deduction >= cd->periph_reset_cycle) { | |
442 cd->periph_reset_cycle = CYCLE_NEVER; | |
443 } else if (cd->periph_reset_cycle != CYCLE_NEVER) { | |
444 cd->periph_reset_cycle -= deduction; | |
445 } | |
446 } | |
447 | |
134 static uint16_t main_gate_read16(uint32_t address, void *vcontext) | 448 static uint16_t main_gate_read16(uint32_t address, void *vcontext) |
135 { | |
136 m68k_context *m68k = vcontext; | |
137 segacd_context *cd = m68k->system; | |
138 return cd->gate_array[(address & 0x1FF) >> 1]; | |
139 } | |
140 | |
141 static uint8_t main_gate_read8(uint32_t address, void *vcontext) | |
142 { | |
143 m68k_context *m68k = vcontext; | |
144 segacd_context *cd = m68k->system; | |
145 uint16_t val = cd->gate_array[(address & 0x1FF) >> 1]; | |
146 return address & 1 ? val : val >> 8; | |
147 } | |
148 | |
149 static void *main_gate_write16(uint32_t address, void *vcontext, uint16_t value) | |
150 { | 449 { |
151 m68k_context *m68k = vcontext; | 450 m68k_context *m68k = vcontext; |
152 genesis_context *gen = m68k->system; | 451 genesis_context *gen = m68k->system; |
153 segacd_context *cd = gen->expansion; | 452 segacd_context *cd = gen->expansion; |
453 uint32_t scd_cycle = gen_cycle_to_scd(m68k->current_cycle, gen); | |
454 scd_run(cd, scd_cycle); | |
455 uint32_t offset = (address & 0x1FF) >> 1; | |
456 switch (offset) | |
457 { | |
458 case GA_SUB_CPU_CTRL: { | |
459 uint16_t value = 0; | |
460 if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN2) { | |
461 value |= BIT_IEN2; | |
462 } | |
463 if (cd->int2_cycle != CYCLE_NEVER) { | |
464 value |= BIT_IFL2; | |
465 } | |
466 if (can_main_access_prog(cd)) { | |
467 value |= BIT_SBRQ; | |
468 } | |
469 if (cd->reset) { | |
470 value |= BIT_SRES; | |
471 } | |
472 return value; | |
473 } | |
474 case GA_MEM_MODE: | |
475 //Main CPU can't read priority mode bits | |
476 return cd->gate_array[offset] & 0xFFE7; | |
477 case GA_HINT_VECTOR: | |
478 return cd->rom_mut[0x72/2]; | |
479 case GA_CDC_DMA_ADDR: | |
480 //TODO: open bus maybe? | |
481 return 0xFFFF; | |
482 default: | |
483 if (offset < GA_TIMER) { | |
484 return cd->gate_array[offset]; | |
485 } | |
486 //TODO: open bus maybe? | |
487 return 0xFFFF; | |
488 } | |
489 } | |
490 | |
491 static uint8_t main_gate_read8(uint32_t address, void *vcontext) | |
492 { | |
493 uint16_t val = main_gate_read16(address & 0xFE, vcontext); | |
494 return address & 1 ? val : val >> 8; | |
495 } | |
496 | |
497 static void *main_gate_write16(uint32_t address, void *vcontext, uint16_t value) | |
498 { | |
499 m68k_context *m68k = vcontext; | |
500 genesis_context *gen = m68k->system; | |
501 segacd_context *cd = gen->expansion; | |
502 uint32_t scd_cycle = gen_cycle_to_scd(m68k->current_cycle, gen); | |
503 scd_run(cd, scd_cycle); | |
154 uint32_t reg = (address & 0x1FF) >> 1; | 504 uint32_t reg = (address & 0x1FF) >> 1; |
155 switch (reg) | 505 switch (reg) |
156 { | 506 { |
157 case 0x7: | 507 case GA_SUB_CPU_CTRL: { |
508 uint8_t old_access = can_main_access_prog(cd); | |
509 cd->busreq = value & BIT_SBRQ; | |
510 uint8_t old_reset = cd->reset; | |
511 cd->reset = value & BIT_SRES; | |
512 if (cd->reset && !old_reset) { | |
513 cd->need_reset = 1; | |
514 } | |
515 cd->gate_array[reg] &= 0x7FFF; | |
516 cd->gate_array[reg] |= value & 0x8000; | |
517 uint8_t new_access = can_main_access_prog(cd); | |
518 uint32_t bank = cd->gate_array[GA_MEM_MODE] >> 6 & 0x3; | |
519 if (new_access) { | |
520 if (!old_access) { | |
521 m68k->mem_pointers[cd->memptr_start_index] = cd->prog_ram + bank * 0x10000; | |
522 m68k_invalidate_code_range(m68k, cd->base + 0x220000, cd->base + 0x240000); | |
523 } | |
524 } else if (old_access) { | |
525 m68k->mem_pointers[cd->memptr_start_index] = NULL; | |
526 m68k_invalidate_code_range(m68k, cd->base + 0x220000, cd->base + 0x240000); | |
527 m68k_invalidate_code_range(cd->m68k, bank * 0x20000, (bank + 1) * 0x20000); | |
528 } | |
529 break; | |
530 } | |
531 case GA_MEM_MODE: { | |
532 uint16_t changed = cd->gate_array[reg] ^ value; | |
533 //Main CPU can't write priority mode bits, MODE or RET | |
534 cd->gate_array[reg] &= 0x001D; | |
535 cd->gate_array[reg] |= value & 0xFFC0; | |
536 if ((cd->gate_array[reg] & BIT_MEM_MODE)) { | |
537 //1M mode | |
538 if (!(value & BIT_DMNA)) { | |
539 cd->gate_array[reg] |= BIT_DMNA; | |
540 } | |
541 } else { | |
542 cd->gate_array[reg] |= value & BIT_DMNA; | |
543 //2M mode | |
544 if (changed & value & BIT_DMNA) { | |
545 m68k->mem_pointers[cd->memptr_start_index + 1] = NULL; | |
546 m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; | |
547 cd->m68k->mem_pointers[0] = cd->word_ram; | |
548 | |
549 m68k_invalidate_code_range(m68k, cd->base + 0x200000, cd->base + 0x240000); | |
550 m68k_invalidate_code_range(cd->m68k, 0x080000, 0x0C0000); | |
551 } | |
552 } | |
553 if (changed & MASK_PROG_BANK) { | |
554 uint32_t bank = cd->gate_array[GA_MEM_MODE] >> 6 & 0x3; | |
555 m68k->mem_pointers[cd->memptr_start_index] = cd->word_ram + bank * 0x10000; | |
556 m68k_invalidate_code_range(m68k, cd->base + 0x220000, cd->base + 0x240000); | |
557 } | |
558 break; | |
559 } | |
560 case GA_HINT_VECTOR: | |
561 cd->rom_mut[0x72/2] = value; | |
562 break; | |
563 case GA_COMM_FLAG: | |
564 //Main CPU can only write the upper byte; | |
158 cd->gate_array[reg] &= 0xFF; | 565 cd->gate_array[reg] &= 0xFF; |
159 cd->gate_array[reg] |= value & 0xFF00; | 566 cd->gate_array[reg] |= value & 0xFF00; |
160 break; | 567 break; |
161 case 0x8: | 568 case GA_COMM_CMD0: |
162 case 0x9: | 569 case GA_COMM_CMD1: |
163 case 0xA: | 570 case GA_COMM_CMD2: |
164 case 0xB: | 571 case GA_COMM_CMD3: |
165 case 0xC: | 572 case GA_COMM_CMD4: |
166 case 0xD: | 573 case GA_COMM_CMD5: |
167 case 0xE: | 574 case GA_COMM_CMD6: |
168 case 0xF: | 575 case GA_COMM_CMD7: |
169 //no effects for these other than saving the value | 576 //no effects for these other than saving the value |
170 cd->gate_array[reg] = value; | 577 cd->gate_array[reg] = value; |
171 break; | 578 break; |
172 default: | 579 default: |
173 printf("Unhandled gate array write %X:%X\n", address, value); | 580 printf("Unhandled gate array write %X:%X\n", address, value); |
191 } | 598 } |
192 | 599 |
193 segacd_context *alloc_configure_segacd(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info) | 600 segacd_context *alloc_configure_segacd(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info) |
194 { | 601 { |
195 static memmap_chunk sub_cpu_map[] = { | 602 static memmap_chunk sub_cpu_map[] = { |
196 {0x000000, 0x00FEFF, 0x0000, .flags=MMAP_READ | MMAP_CODE, .write_16 = prog_ram_wp_write16, .write_8 = prog_ram_wp_write8}, | 603 {0x000000, 0x00FEFF, 0xFFFFFF, .flags=MMAP_READ | MMAP_CODE, .write_16 = prog_ram_wp_write16, .write_8 = prog_ram_wp_write8}, |
197 {0x00FF00, 0x07FFFF, 0x0000, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE}, | 604 {0x00FF00, 0x07FFFF, 0xFFFFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE}, |
198 {0x080000, 0x0BFFFF, 0x0000, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 0, | 605 {0x080000, 0x0BFFFF, 0x03FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 0, |
199 .read_16 = work_ram_2M_read16, .write_16 = work_ram_2M_write16, .read_8 = work_ram_2M_read8, .write_8 = work_ram_2M_write8}, | 606 .read_16 = word_ram_2M_read16, .write_16 = word_ram_2M_write16, .read_8 = word_ram_2M_read8, .write_8 = word_ram_2M_write8}, |
200 {0x0C0000, 0x0DFFFF, 0x0000, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 1, | 607 {0x0C0000, 0x0DFFFF, 0x01FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 1, |
201 .read_16 = work_ram_1M_read16, .write_16 = work_ram_1M_write16, .read_8 = work_ram_1M_read8, .write_8 = work_ram_1M_write8}, | 608 .read_16 = word_ram_1M_read16, .write_16 = word_ram_1M_write16, .read_8 = word_ram_1M_read8, .write_8 = word_ram_1M_write8}, |
202 {0xFE0000, 0xFEFFFF, 0x3FFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_ONLY_ODD}, | 609 {0xFE0000, 0xFEFFFF, 0x003FFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_ONLY_ODD}, |
203 {0xFF0000, 0xFF7FFF, 0x0000, .read_16 = pcm_read16, .write_16 = pcm_write16, .read_8 = pcm_read8, .write_8 = pcm_write8}, | 610 {0xFF0000, 0xFF7FFF, 0x003FFF, .read_16 = pcm_read16, .write_16 = pcm_write16, .read_8 = pcm_read8, .write_8 = pcm_write8}, |
204 {0xFF8000, 0xFF81FF, 0x0000, .read_16 = sub_gate_read16, .write_16 = sub_gate_write16, .read_8 = sub_gate_read8, .write_8 = sub_gate_write8} | 611 {0xFF8000, 0xFF81FF, 0x0001FF, .read_16 = sub_gate_read16, .write_16 = sub_gate_write16, .read_8 = sub_gate_read8, .write_8 = sub_gate_write8} |
205 }; | 612 }; |
206 memset(info, 0, sizeof(*info)); | 613 |
207 segacd_context *cd = calloc(sizeof(segacd_context), 1); | 614 segacd_context *cd = calloc(sizeof(segacd_context), 1); |
208 FILE *f = fopen("cdbios.bin", "rb"); | 615 FILE *f = fopen("cdbios.bin", "rb"); |
209 if (!f) { | 616 if (!f) { |
210 fatal_error("Failed to open CD firmware for reading"); | 617 fatal_error("Failed to open CD firmware for reading"); |
211 } | 618 } |
216 fatal_error("Failed to read CD firmware"); | 623 fatal_error("Failed to read CD firmware"); |
217 } | 624 } |
218 cd->rom_mut = malloc(adjusted_size); | 625 cd->rom_mut = malloc(adjusted_size); |
219 byteswap_rom(adjusted_size, cd->rom); | 626 byteswap_rom(adjusted_size, cd->rom); |
220 memcpy(cd->rom_mut, cd->rom, adjusted_size); | 627 memcpy(cd->rom_mut, cd->rom, adjusted_size); |
221 | 628 cd->rom_mut[0x72/2] = 0xFFFF; |
222 tern_node *db = get_rom_db(); | 629 |
223 *info = configure_rom(db, media->buffer, media->size, media->chain ? media->chain->buffer : NULL, media->chain ? media->chain->size : 0, NULL, 0); | 630 //memset(info, 0, sizeof(*info)); |
224 | 631 //tern_node *db = get_rom_db(); |
632 //*info = configure_rom(db, media->buffer, media->size, media->chain ? media->chain->buffer : NULL, media->chain ? media->chain->size : 0, NULL, 0); | |
633 | |
225 cd->prog_ram = malloc(512*1024); | 634 cd->prog_ram = malloc(512*1024); |
226 cd->work_ram = malloc(256*1024); | 635 cd->word_ram = malloc(256*1024); |
227 cd->pcm_ram = malloc(64*1024); | 636 cd->pcm_ram = malloc(64*1024); |
228 //TODO: Load state from file | 637 //TODO: Load state from file |
229 cd->bram = malloc(8*1024); | 638 cd->bram = malloc(8*1024); |
230 | 639 |
640 | |
231 sub_cpu_map[0].buffer = sub_cpu_map[1].buffer = cd->prog_ram; | 641 sub_cpu_map[0].buffer = sub_cpu_map[1].buffer = cd->prog_ram; |
232 sub_cpu_map[4].buffer = cd->bram; | 642 sub_cpu_map[4].buffer = cd->bram; |
233 m68k_options *mopts = malloc(sizeof(m68k_options)); | 643 m68k_options *mopts = malloc(sizeof(m68k_options)); |
234 init_m68k_opts(mopts, sub_cpu_map, sizeof(sub_cpu_map) / sizeof(*sub_cpu_map), 4); | 644 init_m68k_opts(mopts, sub_cpu_map, sizeof(sub_cpu_map) / sizeof(*sub_cpu_map), 4, sync_components); |
235 cd->m68k = init_68k_context(mopts, NULL); | 645 cd->m68k = init_68k_context(mopts, NULL); |
236 cd->m68k->system = cd; | 646 cd->m68k->system = cd; |
647 cd->int2_cycle = CYCLE_NEVER; | |
237 cd->busreq = 1; | 648 cd->busreq = 1; |
238 cd->busack = 1; | 649 cd->busack = 1; |
239 | 650 cd->need_reset = 1; |
651 cd->reset = 1; //active low, so reset is not active on start | |
652 cd->memptr_start_index = 0; | |
653 cd->gate_array[1] = 1; | |
654 cd->gate_array[0x1B] = 0x100; | |
655 | |
240 return cd; | 656 return cd; |
241 } | 657 } |
242 | 658 |
243 memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint32_t *num_chunks) | 659 memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint8_t cart_boot, uint32_t *num_chunks) |
244 { | 660 { |
245 static memmap_chunk main_cpu_map[] = { | 661 static memmap_chunk main_cpu_map[] = { |
246 {0x000000, 0x01FFFF, 0xFFFFFF, .flags=MMAP_READ}, | 662 {0x000000, 0x01FFFF, 0x01FFFF, .flags=MMAP_READ}, |
247 {0x020000, 0x03FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 0},//TODO: support running main CPU code from here | 663 {0x020000, 0x03FFFF, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .ptr_index = 0, |
248 {0x040000, 0x05FFFF, 0x1FFFF, .flags=MMAP_READ}, //first ROM alias | 664 .read_16 = unmapped_prog_read16, .write_16 = unmapped_prog_write16, .read_8 = unmapped_prog_read8, .write_8 = unmapped_prog_write8}, |
665 {0x040000, 0x05FFFF, 0x01FFFF, .flags=MMAP_READ}, //first ROM alias | |
249 //TODO: additional ROM/prog RAM aliases | 666 //TODO: additional ROM/prog RAM aliases |
250 {0x200000, 0x01FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 1}, | 667 {0x200000, 0x21FFFF, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .ptr_index = 1}, |
251 {0x220000, 0x03FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 2}, | 668 {0x220000, 0x23FFFF, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .ptr_index = 2}, |
252 {0xA12000, 0xA12FFF, 0xFFFFFF, .read_16 = main_gate_read16, .write_16 = main_gate_write16, .read_8 = main_gate_read8, .write_8 = main_gate_write8} | 669 {0xA12000, 0xA12FFF, 0xFFFFFF, .read_16 = main_gate_read16, .write_16 = main_gate_write16, .read_8 = main_gate_read8, .write_8 = main_gate_write8} |
253 }; | 670 }; |
254 //TODO: support cart boot maps | 671 for (int i = 0; i < sizeof(main_cpu_map) / sizeof(*main_cpu_map); i++) |
672 { | |
673 if (main_cpu_map[i].start < 0x800000) { | |
674 if (cart_boot) { | |
675 main_cpu_map[i].start |= 0x400000; | |
676 main_cpu_map[i].end |= 0x400000; | |
677 } else { | |
678 main_cpu_map[i].start &= 0x3FFFFF; | |
679 main_cpu_map[i].end &= 0x3FFFFF; | |
680 } | |
681 } | |
682 } | |
255 //TODO: support BRAM cart | 683 //TODO: support BRAM cart |
256 main_cpu_map[0].buffer = cd->rom_mut; | 684 main_cpu_map[0].buffer = cd->rom_mut; |
257 main_cpu_map[2].buffer = cd->rom; | 685 main_cpu_map[2].buffer = cd->rom; |
258 main_cpu_map[1].buffer = cd->prog_ram; | 686 main_cpu_map[1].buffer = cd->prog_ram; |
259 main_cpu_map[3].buffer = cd->work_ram; | 687 main_cpu_map[3].buffer = cd->word_ram; |
260 main_cpu_map[3].buffer = cd->work_ram + 0x10000; | 688 main_cpu_map[4].buffer = cd->word_ram + 0x10000; |
261 *num_chunks = sizeof(main_cpu_map) / sizeof(*main_cpu_map); | 689 *num_chunks = sizeof(main_cpu_map) / sizeof(*main_cpu_map); |
262 return main_cpu_map; | 690 return main_cpu_map; |
263 } | 691 } |