Mercurial > repos > blastem
comparison segacd.c @ 2134:9caebcfeac72
Implement word RAM interleaving in 1M mode, now passes mcd-verificator word RAM tests
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 18 Mar 2022 20:49:07 -0700 |
parents | d90d92ce5cab |
children | 95b3752925e0 |
comparison
equal
deleted
inserted
replaced
2133:8554751f17b5 | 2134:9caebcfeac72 |
---|---|
129 } | 129 } |
130 | 130 |
131 static uint16_t word_ram_2M_read16(uint32_t address, void *vcontext) | 131 static uint16_t word_ram_2M_read16(uint32_t address, void *vcontext) |
132 { | 132 { |
133 m68k_context *m68k = vcontext; | 133 m68k_context *m68k = vcontext; |
134 //TODO: fixme for interleaving | |
135 uint16_t* bank = m68k->mem_pointers[1]; | 134 uint16_t* bank = m68k->mem_pointers[1]; |
136 if (!bank) { | 135 if (!bank) { |
137 return 0xFFFF; | 136 return 0xFFFF; |
138 } | 137 } |
139 uint16_t raw = bank[address >> 2]; | 138 uint16_t raw = bank[address >> 1 & ~1]; |
140 if (address & 2) { | 139 if (address & 2) { |
141 return (raw & 0xF) | (raw << 4 & 0xF00); | 140 return (raw & 0xF) | (raw << 4 & 0xF00); |
142 } else { | 141 } else { |
143 return (raw >> 4 & 0xF00) | (raw >> 8 & 0xF); | 142 return (raw >> 4 & 0xF00) | (raw >> 8 & 0xF); |
144 } | 143 } |
155 | 154 |
156 static void *word_ram_2M_write8(uint32_t address, void *vcontext, uint8_t value) | 155 static void *word_ram_2M_write8(uint32_t address, void *vcontext, uint8_t value) |
157 { | 156 { |
158 m68k_context *m68k = vcontext; | 157 m68k_context *m68k = vcontext; |
159 segacd_context *cd = m68k->system; | 158 segacd_context *cd = m68k->system; |
160 value &= 0xF; | 159 if (!(cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE)) { |
161 uint16_t priority = cd->gate_array[GA_MEM_MODE] & MASK_PRIORITY; | 160 if (address & 1) { |
162 | 161 address >>= 1; |
163 if (priority == BIT_OVERWRITE && !value) { | 162 cd->word_ram[address] &= 0xFF00; |
164 return vcontext; | 163 cd->word_ram[address] |= value; |
165 } | 164 } else { |
166 if (priority == BIT_UNDERWRITE) { | 165 address >>= 1; |
167 if (!value) { | 166 cd->word_ram[address] &= 0x00FF; |
167 cd->word_ram[address] |= value << 8; | |
168 } | |
169 cd->sub_paused_wordram = 1; | |
170 m68k->sync_cycle = m68k->target_cycle = m68k->current_cycle; | |
171 m68k->should_return = 1; | |
172 } else { | |
173 value &= 0xF; | |
174 uint16_t priority = cd->gate_array[GA_MEM_MODE] & MASK_PRIORITY; | |
175 | |
176 if (priority == BIT_OVERWRITE && !value) { | |
168 return vcontext; | 177 return vcontext; |
169 } | 178 } |
170 uint8_t old = word_ram_2M_read8(address, vcontext); | 179 if (priority == BIT_UNDERWRITE) { |
171 if (old) { | 180 if (!value) { |
181 return vcontext; | |
182 } | |
183 uint8_t old = word_ram_2M_read8(address, vcontext); | |
184 if (old) { | |
185 return vcontext; | |
186 } | |
187 } | |
188 uint16_t* bank = m68k->mem_pointers[1]; | |
189 if (!bank) { | |
172 return vcontext; | 190 return vcontext; |
173 } | 191 } |
174 } | 192 uint16_t raw = bank[address >> 1 & ~1]; |
175 uint16_t* bank = m68k->mem_pointers[1]; | 193 uint16_t shift = ((address & 3) * 4); |
176 if (!bank) { | 194 raw &= ~(0xF000 >> shift); |
177 return vcontext; | 195 raw |= value << (12 - shift); |
178 } | 196 bank[address >> 1 & ~1] = raw; |
179 uint16_t raw = bank[address >> 2]; | 197 } |
180 uint16_t shift = ((address & 3) * 4); | |
181 raw &= ~(0xF000 >> shift); | |
182 raw |= value << (12 - shift); | |
183 bank[address >> 2] = raw; | |
184 return vcontext; | 198 return vcontext; |
185 } | 199 } |
186 | 200 |
187 | 201 |
188 static void *word_ram_2M_write16(uint32_t address, void *vcontext, uint16_t value) | 202 static void *word_ram_2M_write16(uint32_t address, void *vcontext, uint16_t value) |
232 return vcontext; | 246 return vcontext; |
233 } | 247 } |
234 | 248 |
235 static uint16_t unmapped_word_read16(uint32_t address, void *vcontext) | 249 static uint16_t unmapped_word_read16(uint32_t address, void *vcontext) |
236 { | 250 { |
237 return 0xFFFF; | 251 m68k_context *m68k = vcontext; |
252 genesis_context *gen = m68k->system; | |
253 segacd_context *cd = gen->expansion; | |
254 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { | |
255 return cd->word_ram[address + cd->bank_toggle]; | |
256 } else { | |
257 return 0xFFFF; | |
258 } | |
238 } | 259 } |
239 | 260 |
240 static uint8_t unmapped_word_read8(uint32_t address, void *vcontext) | 261 static uint8_t unmapped_word_read8(uint32_t address, void *vcontext) |
241 { | 262 { |
242 return 0xFF; | 263 m68k_context *m68k = vcontext; |
264 genesis_context *gen = m68k->system; | |
265 segacd_context *cd = gen->expansion; | |
266 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { | |
267 if (address & 1) { | |
268 return cd->word_ram[(address & ~1) + cd->bank_toggle]; | |
269 } else { | |
270 return cd->word_ram[address + cd->bank_toggle] >> 8; | |
271 } | |
272 } else { | |
273 return 0xFF; | |
274 } | |
243 } | 275 } |
244 | 276 |
245 static void *unmapped_word_write16(uint32_t address, void *vcontext, uint16_t value) | 277 static void *unmapped_word_write16(uint32_t address, void *vcontext, uint16_t value) |
246 { | 278 { |
279 m68k_context *m68k = vcontext; | |
280 genesis_context *gen = m68k->system; | |
281 segacd_context *cd = gen->expansion; | |
282 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { | |
283 cd->word_ram[address + cd->bank_toggle] = value; | |
284 m68k_invalidate_code_range(m68k, cd->base + address, address + 1); | |
285 } | |
247 return vcontext; | 286 return vcontext; |
248 } | 287 } |
249 | 288 |
250 static void *unmapped_word_write8(uint32_t address, void *vcontext, uint8_t value) | 289 static void *unmapped_word_write8(uint32_t address, void *vcontext, uint8_t value) |
251 { | 290 { |
291 m68k_context *m68k = vcontext; | |
292 genesis_context *gen = m68k->system; | |
293 segacd_context *cd = gen->expansion; | |
294 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { | |
295 if (address & 1) { | |
296 uint32_t offset = (address & ~1) + cd->bank_toggle; | |
297 cd->word_ram[offset] &= 0xFF00; | |
298 cd->word_ram[offset] |= value; | |
299 } else { | |
300 cd->word_ram[address + cd->bank_toggle] &= 0xFF; | |
301 cd->word_ram[address + cd->bank_toggle] |= value << 8; | |
302 } | |
303 m68k_invalidate_code_range(m68k, cd->base + (address & ~1), address + 1); | |
304 } | |
252 return vcontext; | 305 return vcontext; |
253 } | 306 } |
254 | 307 |
255 static uint32_t cell_image_translate_address(uint32_t address) | 308 static uint32_t cell_image_translate_address(uint32_t address) |
256 { | 309 { |
284 { | 337 { |
285 address = cell_image_translate_address(address); | 338 address = cell_image_translate_address(address); |
286 m68k_context *m68k = vcontext; | 339 m68k_context *m68k = vcontext; |
287 genesis_context *gen = m68k->system; | 340 genesis_context *gen = m68k->system; |
288 segacd_context *cd = gen->expansion; | 341 segacd_context *cd = gen->expansion; |
289 if (!m68k->mem_pointers[cd->memptr_start_index + 1]) { | 342 if (!(cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE)) { |
290 return 0xFFFF; | 343 return 0xFFFF; |
291 } | 344 } |
292 return m68k->mem_pointers[cd->memptr_start_index + 1][address>>1]; | 345 return cd->word_ram[address + cd->bank_toggle]; |
293 } | 346 } |
294 | 347 |
295 static uint8_t cell_image_read8(uint32_t address, void *vcontext) | 348 static uint8_t cell_image_read8(uint32_t address, void *vcontext) |
296 { | 349 { |
297 uint16_t word = cell_image_read16(address & 0xFFFFFE, vcontext); | 350 uint16_t word = cell_image_read16(address & 0xFFFFFE, vcontext); |
301 return word >> 8; | 354 return word >> 8; |
302 } | 355 } |
303 | 356 |
304 static void *cell_image_write16(uint32_t address, void *vcontext, uint16_t value) | 357 static void *cell_image_write16(uint32_t address, void *vcontext, uint16_t value) |
305 { | 358 { |
306 address = cell_image_translate_address(address); | |
307 m68k_context *m68k = vcontext; | 359 m68k_context *m68k = vcontext; |
308 genesis_context *gen = m68k->system; | 360 genesis_context *gen = m68k->system; |
309 segacd_context *cd = gen->expansion; | 361 segacd_context *cd = gen->expansion; |
310 if (m68k->mem_pointers[cd->memptr_start_index + 1]) { | 362 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { |
311 m68k->mem_pointers[cd->memptr_start_index + 1][address>>1] = value; | 363 address = cell_image_translate_address(address); |
364 cd->word_ram[address + cd->bank_toggle] = value; | |
312 } | 365 } |
313 return vcontext; | 366 return vcontext; |
314 } | 367 } |
315 | 368 |
316 static void *cell_image_write8(uint32_t address, void *vcontext, uint8_t value) | 369 static void *cell_image_write8(uint32_t address, void *vcontext, uint8_t value) |
318 uint32_t byte = address & 1; | 371 uint32_t byte = address & 1; |
319 address = cell_image_translate_address(address); | 372 address = cell_image_translate_address(address); |
320 m68k_context *m68k = vcontext; | 373 m68k_context *m68k = vcontext; |
321 genesis_context *gen = m68k->system; | 374 genesis_context *gen = m68k->system; |
322 segacd_context *cd = gen->expansion; | 375 segacd_context *cd = gen->expansion; |
323 if (m68k->mem_pointers[cd->memptr_start_index + 1]) { | 376 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { |
324 if (byte) { | 377 if (byte) { |
325 m68k->mem_pointers[cd->memptr_start_index + 1][address>>1] &= 0xFF00; | 378 cd->word_ram[address + cd->bank_toggle] &= 0xFF00; |
326 m68k->mem_pointers[cd->memptr_start_index + 1][address>>1] |= value; | 379 cd->word_ram[address + cd->bank_toggle] |= value; |
327 } else { | 380 } else { |
328 m68k->mem_pointers[cd->memptr_start_index + 1][address>>1] &= 0x00FF; | 381 cd->word_ram[address + cd->bank_toggle] &= 0x00FF; |
329 m68k->mem_pointers[cd->memptr_start_index + 1][address>>1] |= value << 8; | 382 cd->word_ram[address + cd->bank_toggle] |= value << 8; |
330 } | 383 } |
331 } | 384 } |
332 return vcontext; | 385 return vcontext; |
333 } | 386 } |
334 | 387 |
622 uint8_t old_bank_toggle = cd->bank_toggle; | 675 uint8_t old_bank_toggle = cd->bank_toggle; |
623 cd->bank_toggle = value & BIT_RET; | 676 cd->bank_toggle = value & BIT_RET; |
624 genesis_context *gen = cd->genesis; | 677 genesis_context *gen = cd->genesis; |
625 cd->gate_array[reg] &= 0xFFC0; | 678 cd->gate_array[reg] &= 0xFFC0; |
626 if (changed & BIT_MEM_MODE) { | 679 if (changed & BIT_MEM_MODE) { |
627 //FIXME: ram banks are supposed to be interleaved when in 2M mode | |
628 cd->main_swap_request = cd->bank_toggle && !old_bank_toggle; | 680 cd->main_swap_request = cd->bank_toggle && !old_bank_toggle; |
629 if (value & BIT_MEM_MODE) { | 681 if (value & BIT_MEM_MODE) { |
630 //switch to 1M mode | 682 //switch to 1M mode |
631 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = (value & BIT_RET) ? cd->word_ram + 0x10000 : cd->word_ram; | 683 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = NULL; //(value & BIT_RET) ? cd->word_ram + 0x10000 : cd->word_ram; |
632 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; | 684 gen->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; |
633 m68k->mem_pointers[0] = NULL; | 685 m68k->mem_pointers[0] = NULL; |
634 m68k->mem_pointers[1] = cd->bank_toggle ? cd->word_ram : cd->word_ram + 0x10000; | 686 m68k->mem_pointers[1] = cd->bank_toggle ? cd->word_ram : cd->word_ram + 1; |
635 cd->gate_array[reg] |= value & (MASK_PRIORITY|BIT_RET|BIT_MEM_MODE); | 687 cd->gate_array[reg] |= value & (MASK_PRIORITY|BIT_RET|BIT_MEM_MODE); |
636 if (cd->main_swap_request) { | 688 if (cd->main_swap_request) { |
637 cd->gate_array[reg] |= BIT_DMNA; | 689 cd->gate_array[reg] |= BIT_DMNA; |
638 } | 690 } |
639 } else { | 691 } else { |
657 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); | 709 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); |
658 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); | 710 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); |
659 } else if (value & BIT_MEM_MODE) { | 711 } else if (value & BIT_MEM_MODE) { |
660 //1M mode | 712 //1M mode |
661 if (old_bank_toggle != cd->bank_toggle) { | 713 if (old_bank_toggle != cd->bank_toggle) { |
662 gen->m68k->mem_pointers[cd->memptr_start_index + 1] = (value & BIT_RET) ? cd->word_ram + 0x10000 : cd->word_ram; | 714 m68k->mem_pointers[1] = (value & BIT_RET) ? cd->word_ram : cd->word_ram + 1; |
663 m68k->mem_pointers[1] = (value & BIT_RET) ? cd->word_ram : cd->word_ram + 0x10000; | |
664 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); | 715 m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); |
665 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); | 716 m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); |
666 cd->main_swap_request = 0; | 717 cd->main_swap_request = 0; |
667 } | 718 } |
668 cd->gate_array[reg] |= value & (MASK_PRIORITY|BIT_RET|BIT_MEM_MODE); | 719 cd->gate_array[reg] |= value & (MASK_PRIORITY|BIT_RET|BIT_MEM_MODE); |
918 cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; | 969 cd->gate_array[GA_CDC_DMA_ADDR] = dma_addr >> 3; |
919 break; | 970 break; |
920 case DST_WORD_RAM: | 971 case DST_WORD_RAM: |
921 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { | 972 if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) { |
922 //1M mode, write to bank assigned to Sub CPU | 973 //1M mode, write to bank assigned to Sub CPU |
923 dma_addr &= (1 << 17) - 1; | 974 dma_addr &= (1 << 17) - 2; |
924 cd->m68k->mem_pointers[1][dma_addr >> 1] = cd->gate_array[GA_CDC_HOST_DATA]; | 975 cd->m68k->mem_pointers[1][dma_addr] = cd->gate_array[GA_CDC_HOST_DATA]; |
925 m68k_invalidate_code_range(cd->m68k, 0x0C0000 + dma_addr - 1, 0x0C0000 + dma_addr + 1); | 976 m68k_invalidate_code_range(cd->m68k, 0x0C0000 + dma_addr - 1, 0x0C0000 + dma_addr + 1); |
926 } else { | 977 } else { |
927 //2M mode, check if Sub CPU has access | 978 //2M mode, check if Sub CPU has access |
928 if (cd->main_has_word2m) { | 979 if (cd->main_has_word2m) { |
929 return 0; | 980 return 0; |
999 | 1050 |
1000 void scd_run(segacd_context *cd, uint32_t cycle) | 1051 void scd_run(segacd_context *cd, uint32_t cycle) |
1001 { | 1052 { |
1002 uint8_t m68k_run = !can_main_access_prog(cd); | 1053 uint8_t m68k_run = !can_main_access_prog(cd); |
1003 while (cycle > cd->m68k->current_cycle) { | 1054 while (cycle > cd->m68k->current_cycle) { |
1004 if (m68k_run) { | 1055 if (m68k_run && !cd->sub_paused_wordram) { |
1005 uint32_t start = cd->m68k->current_cycle; | 1056 uint32_t start = cd->m68k->current_cycle; |
1006 cd->m68k->sync_cycle = cd->enter_debugger ? cd->m68k->current_cycle + 1 : cycle; | 1057 cd->m68k->sync_cycle = cd->enter_debugger ? cd->m68k->current_cycle + 1 : cycle; |
1007 if (cd->need_reset) { | 1058 if (cd->need_reset) { |
1008 cd->need_reset = 0; | 1059 cd->need_reset = 0; |
1009 m68k_reset(cd->m68k); | 1060 m68k_reset(cd->m68k); |
1200 m68k->mem_pointers[cd->memptr_start_index + 1] = NULL; | 1251 m68k->mem_pointers[cd->memptr_start_index + 1] = NULL; |
1201 m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; | 1252 m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; |
1202 cd->m68k->mem_pointers[0] = cd->word_ram; | 1253 cd->m68k->mem_pointers[0] = cd->word_ram; |
1203 cd->gate_array[reg] &= ~BIT_RET; | 1254 cd->gate_array[reg] &= ~BIT_RET; |
1204 cd->main_has_word2m = 0; | 1255 cd->main_has_word2m = 0; |
1256 if (cd->sub_paused_wordram) { | |
1257 cd->sub_paused_wordram = 0; | |
1258 } | |
1205 | 1259 |
1206 uint16_t dst = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; | 1260 uint16_t dst = cd->gate_array[GA_CDC_CTRL] >> 8 & 0x7; |
1207 if (dst == DST_WORD_RAM) { | 1261 if (dst == DST_WORD_RAM) { |
1208 lc8951_resume_transfer(&cd->cdc, cd->cdc.cycle); | 1262 lc8951_resume_transfer(&cd->cdc, cd->cdc.cycle); |
1209 } | 1263 } |
1287 {0x000000, 0x01FF00, 0xFFFFFF, .flags=MMAP_READ | MMAP_CODE, .write_16 = prog_ram_wp_write16, .write_8 = prog_ram_wp_write8}, | 1341 {0x000000, 0x01FF00, 0xFFFFFF, .flags=MMAP_READ | MMAP_CODE, .write_16 = prog_ram_wp_write16, .write_8 = prog_ram_wp_write8}, |
1288 {0x01FF00, 0x080000, 0xFFFFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE}, | 1342 {0x01FF00, 0x080000, 0xFFFFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE}, |
1289 {0x080000, 0x0C0000, 0x03FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 0, | 1343 {0x080000, 0x0C0000, 0x03FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 0, |
1290 .read_16 = word_ram_2M_read16, .write_16 = word_ram_2M_write16, .read_8 = word_ram_2M_read8, .write_8 = word_ram_2M_write8}, | 1344 .read_16 = word_ram_2M_read16, .write_16 = word_ram_2M_write16, .read_8 = word_ram_2M_read8, .write_8 = word_ram_2M_write8}, |
1291 {0x0C0000, 0x0E0000, 0x01FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 1, | 1345 {0x0C0000, 0x0E0000, 0x01FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 1, |
1292 .read_16 = word_ram_1M_read16, .write_16 = word_ram_1M_write16, .read_8 = word_ram_1M_read8, .write_8 = word_ram_1M_write8}, | 1346 .read_16 = word_ram_1M_read16, .write_16 = word_ram_1M_write16, .read_8 = word_ram_1M_read8, .write_8 = word_ram_1M_write8, .shift = 1}, |
1293 {0xFE0000, 0xFF0000, 0x003FFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_ONLY_ODD}, | 1347 {0xFE0000, 0xFF0000, 0x003FFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_ONLY_ODD}, |
1294 {0xFF0000, 0xFF8000, 0x003FFF, .read_16 = pcm_read16, .write_16 = pcm_write16, .read_8 = pcm_read8, .write_8 = pcm_write8}, | 1348 {0xFF0000, 0xFF8000, 0x003FFF, .read_16 = pcm_read16, .write_16 = pcm_write16, .read_8 = pcm_read8, .write_8 = pcm_write8}, |
1295 {0xFF8000, 0xFF8200, 0x0001FF, .read_16 = sub_gate_read16, .write_16 = sub_gate_write16, .read_8 = sub_gate_read8, .write_8 = sub_gate_write8} | 1349 {0xFF8000, 0xFF8200, 0x0001FF, .read_16 = sub_gate_read16, .write_16 = sub_gate_write16, .read_8 = sub_gate_read8, .write_8 = sub_gate_write8} |
1296 }; | 1350 }; |
1297 | 1351 |