src/mame/machine/snes.c
| r7651 | r7652 | |
| 232 | 232 | if (video_screen_get_vpos(machine->primary_screen) > 0) |
| 233 | 233 | { |
| 234 | 234 | /* Do HDMA */ |
| 235 | | if (snes_ram[HDMAEN]) |
| 235 | if (state->hdmaen) |
| 236 | 236 | snes_hdma(cpu0space); |
| 237 | 237 | |
| 238 | 238 | video_screen_update_partial(machine->primary_screen, (snes_ppu.interlace == 2) ? (snes_ppu.beam.current_vert*snes_ppu.interlace) : snes_ppu.beam.current_vert-1); |
| r7651 | r7652 | |
| 305 | 305 | visarea.max_x = (SNES_SCR_WIDTH * 2) - 1; |
| 306 | 306 | |
| 307 | 307 | // fixme: should compensate for SNES_DBG_video |
| 308 | | if (snes_ppu.mode == 5 || snes_ppu.mode == 6 ) |
| 308 | if (snes_ppu.mode == 5 || snes_ppu.mode == 6 || snes_ppu.pseudo_hires) |
| 309 | 309 | state->htmult = 2; |
| 310 | 310 | else |
| 311 | 311 | state->htmult = 1; |
| r7651 | r7652 | |
| 337 | 337 | return result; |
| 338 | 338 | } |
| 339 | 339 | |
| 340 | /************************************************* |
| 341 | |
| 342 | SNES VRAM accesses: |
| 343 | |
| 344 | VRAM accesses during active display are invalid. |
| 345 | Unlike OAM and CGRAM, they will not be written |
| 346 | anywhere at all. Thanks to byuu's researches, |
| 347 | the ranges where writes are invalid have been |
| 348 | validated on hardware, as has the edge case where |
| 349 | the S-CPU open bus can be written if the write |
| 350 | occurs during the very last clock cycle of |
| 351 | vblank. |
| 352 | Our implementation could be not 100% accurate |
| 353 | when interlace is active. |
| 354 | *************************************************/ |
| 355 | |
| 340 | 356 | INLINE UINT32 snes_get_vram_address( running_machine *machine ) |
| 341 | 357 | { |
| 342 | 358 | snes_state *state = (snes_state *)machine->driver_data; |
| r7651 | r7652 | |
| 352 | 368 | return addr; |
| 353 | 369 | } |
| 354 | 370 | |
| 355 | | /* VRAM accesses during active display are invalid. */ |
| 356 | | static UINT16 snes_vram_read( const address_space *space, UINT32 addr ) |
| 371 | static READ8_HANDLER( snes_vram_read ) |
| 357 | 372 | { |
| 358 | | UINT16 res = 0; |
| 373 | UINT8 res = 0; |
| 374 | offset &= 0x1ffff; |
| 359 | 375 | |
| 360 | 376 | if (snes_ppu.screen_disabled) |
| 361 | | res = snes_vram[addr & 0x1ffff] | snes_vram[(addr + 1) & 0x1ffff] << 8; |
| 377 | res = snes_vram[offset]; |
| 362 | 378 | else |
| 363 | 379 | { |
| 364 | 380 | UINT16 v = video_screen_get_vpos(space->machine->primary_screen); |
| r7651 | r7652 | |
| 375 | 391 | else if (v == snes_ppu.beam.last_visible_line - 1) |
| 376 | 392 | { |
| 377 | 393 | if (h == 1362) |
| 378 | | res = snes_vram[addr & 0x1ffff] | snes_vram[(addr + 1) & 0x1ffff] << 8; |
| 394 | res = snes_vram[offset]; |
| 379 | 395 | else |
| 380 | 396 | res = 0; |
| 381 | 397 | } |
| 382 | 398 | else |
| 383 | | res = snes_vram[addr & 0x1ffff] | snes_vram[(addr + 1) & 0x1ffff] << 8; |
| 399 | res = snes_vram[offset]; |
| 384 | 400 | } |
| 385 | 401 | return res; |
| 386 | 402 | } |
| 387 | 403 | |
| 388 | | static void snes_vram_write( const address_space *space, UINT32 addr, UINT8 data ) |
| 404 | static WRITE8_HANDLER( snes_vram_write ) |
| 389 | 405 | { |
| 406 | offset &= 0x1ffff; |
| 407 | |
| 390 | 408 | if (snes_ppu.screen_disabled) |
| 391 | | snes_vram[addr & 0x1ffff] = data; |
| 409 | snes_vram[offset] = data; |
| 392 | 410 | else |
| 393 | 411 | { |
| 394 | 412 | UINT16 v = video_screen_get_vpos(space->machine->primary_screen); |
| r7651 | r7652 | |
| 396 | 414 | if (v == 0) |
| 397 | 415 | { |
| 398 | 416 | if (h <= 4) |
| 399 | | snes_vram[addr & 0x1ffff] = data; |
| 417 | snes_vram[offset] = data; |
| 400 | 418 | else if (h == 6) |
| 401 | | snes_vram[addr & 0x1ffff] = snes_open_bus_r(space, 0); |
| 419 | snes_vram[offset] = snes_open_bus_r(space, 0); |
| 402 | 420 | else |
| 403 | 421 | { |
| 404 | 422 | //no write |
| r7651 | r7652 | |
| 415 | 433 | //no write |
| 416 | 434 | } |
| 417 | 435 | else |
| 418 | | snes_vram[addr & 0x1ffff] = data; |
| 436 | snes_vram[offset] = data; |
| 419 | 437 | } |
| 420 | 438 | else |
| 421 | | snes_vram[addr & 0x1ffff] = data; |
| 439 | snes_vram[offset] = data; |
| 422 | 440 | } |
| 423 | | |
| 424 | 441 | } |
| 425 | 442 | |
| 426 | 443 | /* |
| r7651 | r7652 | |
| 536 | 553 | |
| 537 | 554 | snes_ppu.ppu1_open_bus = (snes_oam[oam_addr] >> (snes_ram[OAMDATA] << 3)) & 0xff; |
| 538 | 555 | snes_ram[OAMDATA] = (snes_ram[OAMDATA] + 1) % 2; |
| 539 | | if (snes_ram[OAMDATA] == 0) |
| 556 | if (!snes_ram[OAMDATA]) |
| 540 | 557 | { |
| 541 | 558 | snes_ppu.oam.address++; |
| 542 | 559 | snes_ppu.oam.address &= 0x1ff; |
| r7651 | r7652 | |
| 552 | 569 | if (!state->vram_fgr_high) |
| 553 | 570 | { |
| 554 | 571 | state->vram_read_buffer = snes_vram_read(space, addr); |
| 572 | state->vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8); |
| 555 | 573 | |
| 556 | 574 | addr = ((snes_ram[VMADDH] << 8) | snes_ram[VMADDL]) + state->vram_fgr_increment; |
| 557 | 575 | snes_ram[VMADDL] = addr & 0xff; |
| r7651 | r7652 | |
| 568 | 586 | if (state->vram_fgr_high) |
| 569 | 587 | { |
| 570 | 588 | state->vram_read_buffer = snes_vram_read(space, addr); |
| 589 | state->vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8); |
| 571 | 590 | |
| 572 | 591 | addr = ((snes_ram[VMADDH] << 8) | snes_ram[VMADDL]) + state->vram_fgr_increment; |
| 573 | 592 | snes_ram[VMADDL] = addr & 0xff; |
| r7651 | r7652 | |
| 715 | 734 | return state->joy4h; |
| 716 | 735 | case DMAP0: case DMAP1: case DMAP2: case DMAP3: /*0x43n0*/ |
| 717 | 736 | case DMAP4: case DMAP5: case DMAP6: case DMAP7: |
| 737 | return state->dma_channel[(offset & 0x70) >> 4].dmap; |
| 718 | 738 | case BBAD0: case BBAD1: case BBAD2: case BBAD3: /*0x43n1*/ |
| 719 | 739 | case BBAD4: case BBAD5: case BBAD6: case BBAD7: |
| 740 | return state->dma_channel[(offset & 0x70) >> 4].dest_addr; |
| 720 | 741 | case A1T0L: case A1T1L: case A1T2L: case A1T3L: /*0x43n2*/ |
| 721 | 742 | case A1T4L: case A1T5L: case A1T6L: case A1T7L: |
| 743 | return state->dma_channel[(offset & 0x70) >> 4].src_addr & 0xff; |
| 722 | 744 | case A1T0H: case A1T1H: case A1T2H: case A1T3H: /*0x43n3*/ |
| 723 | 745 | case A1T4H: case A1T5H: case A1T6H: case A1T7H: |
| 746 | return (state->dma_channel[(offset & 0x70) >> 4].src_addr >> 8) & 0xff; |
| 724 | 747 | case A1B0: case A1B1: case A1B2: case A1B3: /*0x43n4*/ |
| 725 | 748 | case A1B4: case A1B5: case A1B6: case A1B7: |
| 749 | return state->dma_channel[(offset & 0x70) >> 4].bank; |
| 726 | 750 | case DAS0L: case DAS1L: case DAS2L: case DAS3L: /*0x43n5*/ |
| 727 | 751 | case DAS4L: case DAS5L: case DAS6L: case DAS7L: |
| 752 | return state->dma_channel[(offset & 0x70) >> 4].trans_size & 0xff; |
| 728 | 753 | case DAS0H: case DAS1H: case DAS2H: case DAS3H: /*0x43n6*/ |
| 729 | 754 | case DAS4H: case DAS5H: case DAS6H: case DAS7H: |
| 755 | return (state->dma_channel[(offset & 0x70) >> 4].trans_size >> 8) & 0xff; |
| 730 | 756 | case DSAB0: case DSAB1: case DSAB2: case DSAB3: /*0x43n7*/ |
| 731 | 757 | case DSAB4: case DSAB5: case DSAB6: case DSAB7: |
| 758 | return state->dma_channel[(offset & 0x70) >> 4].ibank; |
| 732 | 759 | case A2A0L: case A2A1L: case A2A2L: case A2A3L: /*0x43n8*/ |
| 733 | 760 | case A2A4L: case A2A5L: case A2A6L: case A2A7L: |
| 761 | return state->dma_channel[(offset & 0x70) >> 4].hdma_addr & 0xff; |
| 734 | 762 | case A2A0H: case A2A1H: case A2A2H: case A2A3H: /*0x43n9*/ |
| 735 | 763 | case A2A4H: case A2A5H: case A2A6H: case A2A7H: |
| 764 | return (state->dma_channel[(offset & 0x70) >> 4].hdma_addr >> 8) & 0xff; |
| 736 | 765 | case NTRL0: case NTRL1: case NTRL2: case NTRL3: /*0x43na*/ |
| 737 | 766 | case NTRL4: case NTRL5: case NTRL6: case NTRL7: |
| 767 | return state->dma_channel[(offset & 0x70) >> 4].hdma_line_counter; |
| 738 | 768 | case 0x430b: case 0x431b: case 0x432b: case 0x433b: /* according to bsnes, this does not return open_bus (even if its precise effect is unknown) */ |
| 739 | 769 | case 0x434b: case 0x435b: case 0x436b: case 0x437b: |
| 740 | | return snes_ram[offset]; |
| 770 | return state->dma_channel[(offset & 0x70) >> 4].unk; |
| 741 | 771 | |
| 742 | 772 | #ifndef MESS |
| 743 | 773 | case 0x4100: /* NSS Dip-Switches */ |
| r7651 | r7652 | |
| 994 | 1024 | snes_ram[offset] = data; |
| 995 | 1025 | addr = snes_get_vram_address(space->machine) << 1; |
| 996 | 1026 | state->vram_read_buffer = snes_vram_read(space, addr); |
| 1027 | state->vram_read_buffer |= (snes_vram_read(space, addr + 1) << 8); |
| 997 | 1028 | } |
| 998 | 1029 | break; |
| 999 | 1030 | case VMDATAL: /* 2118: Data for VRAM write (low) */ |
| r7651 | r7652 | |
| 1178 | 1209 | snes_ppu.layer[SNES_OAM].sub_window_enabled = BIT(data, 4); |
| 1179 | 1210 | break; |
| 1180 | 1211 | case CGWSEL: /* Initial settings for Fixed colour addition or screen addition */ |
| 1181 | | /* FIXME: We don't support direct select for modes 3 & 4 or subscreen window stuff */ |
| 1182 | 1212 | snes_ppu.clip_to_black = (data >> 6) & 0x03; |
| 1183 | 1213 | snes_ppu.prevent_color_math = (data >> 4) & 0x03; |
| 1184 | 1214 | snes_ppu.sub_add_mode = BIT(data, 1); |
| r7651 | r7652 | |
| 1305 | 1335 | data = 0; /* Once DMA is done we need to reset all bits to 0 */ |
| 1306 | 1336 | break; |
| 1307 | 1337 | case HDMAEN: /* HDMA channel designation */ |
| 1308 | | if (data) //if a HDMA is enabled, data is inited at the next scanline |
| 1338 | state->hdmaen = data; |
| 1339 | if (state->hdmaen) //if a HDMA is enabled, data is inited at the next scanline |
| 1309 | 1340 | timer_set(space->machine, video_screen_get_time_until_pos(space->machine->primary_screen, snes_ppu.beam.current_vert + 1, 0), NULL, 0, snes_reset_hdma); |
| 1310 | 1341 | break; |
| 1311 | 1342 | case MEMSEL: /* Access cycle designation in memory (2) area */ |
| r7651 | r7652 | |
| 1345 | 1376 | /* Below is all DMA related */ |
| 1346 | 1377 | case DMAP0: case DMAP1: case DMAP2: case DMAP3: /*0x43n0*/ |
| 1347 | 1378 | case DMAP4: case DMAP5: case DMAP6: case DMAP7: |
| 1379 | state->dma_channel[(offset & 0x70) >> 4].dmap = data; |
| 1380 | break; |
| 1348 | 1381 | case BBAD0: case BBAD1: case BBAD2: case BBAD3: /*0x43n1*/ |
| 1349 | 1382 | case BBAD4: case BBAD5: case BBAD6: case BBAD7: |
| 1383 | state->dma_channel[(offset & 0x70) >> 4].dest_addr = data; |
| 1384 | break; |
| 1350 | 1385 | case A1T0L: case A1T1L: case A1T2L: case A1T3L: /*0x43n2*/ |
| 1351 | 1386 | case A1T4L: case A1T5L: case A1T6L: case A1T7L: |
| 1387 | state->dma_channel[(offset & 0x70) >> 4].src_addr = (state->dma_channel[(offset & 0x70) >> 4].src_addr & 0xff00) | (data << 0); |
| 1388 | break; |
| 1352 | 1389 | case A1T0H: case A1T1H: case A1T2H: case A1T3H: /*0x43n3*/ |
| 1353 | 1390 | case A1T4H: case A1T5H: case A1T6H: case A1T7H: |
| 1391 | state->dma_channel[(offset & 0x70) >> 4].src_addr = (state->dma_channel[(offset & 0x70) >> 4].src_addr & 0x00ff) | (data << 8); |
| 1392 | break; |
| 1354 | 1393 | case A1B0: case A1B1: case A1B2: case A1B3: /*0x43n4*/ |
| 1355 | 1394 | case A1B4: case A1B5: case A1B6: case A1B7: |
| 1395 | state->dma_channel[(offset & 0x70) >> 4].bank = data; |
| 1396 | break; |
| 1356 | 1397 | case DAS0L: case DAS1L: case DAS2L: case DAS3L: /*0x43n5*/ |
| 1357 | 1398 | case DAS4L: case DAS5L: case DAS6L: case DAS7L: |
| 1399 | state->dma_channel[(offset & 0x70) >> 4].trans_size = (state->dma_channel[(offset & 0x70) >> 4].trans_size & 0xff00) | (data << 0); |
| 1400 | break; |
| 1358 | 1401 | case DAS0H: case DAS1H: case DAS2H: case DAS3H: /*0x43n6*/ |
| 1359 | 1402 | case DAS4H: case DAS5H: case DAS6H: case DAS7H: |
| 1403 | state->dma_channel[(offset & 0x70) >> 4].trans_size = (state->dma_channel[(offset & 0x70) >> 4].trans_size & 0x00ff) | (data << 8); |
| 1404 | break; |
| 1360 | 1405 | case DSAB0: case DSAB1: case DSAB2: case DSAB3: /*0x43n7*/ |
| 1361 | 1406 | case DSAB4: case DSAB5: case DSAB6: case DSAB7: |
| 1407 | state->dma_channel[(offset & 0x70) >> 4].ibank = data; |
| 1408 | break; |
| 1362 | 1409 | case A2A0L: case A2A1L: case A2A2L: case A2A3L: /*0x43n8*/ |
| 1363 | 1410 | case A2A4L: case A2A5L: case A2A6L: case A2A7L: |
| 1411 | state->dma_channel[(offset & 0x70) >> 4].hdma_addr = (state->dma_channel[(offset & 0x70) >> 4].hdma_addr & 0xff00) | (data << 0); |
| 1412 | break; |
| 1364 | 1413 | case A2A0H: case A2A1H: case A2A2H: case A2A3H: /*0x43n9*/ |
| 1365 | 1414 | case A2A4H: case A2A5H: case A2A6H: case A2A7H: |
| 1415 | state->dma_channel[(offset & 0x70) >> 4].hdma_addr = (state->dma_channel[(offset & 0x70) >> 4].hdma_addr & 0x00ff) | (data << 8); |
| 1416 | break; |
| 1366 | 1417 | case NTRL0: case NTRL1: case NTRL2: case NTRL3: /*0x43na*/ |
| 1367 | 1418 | case NTRL4: case NTRL5: case NTRL6: case NTRL7: |
| 1419 | state->dma_channel[(offset & 0x70) >> 4].hdma_line_counter = data; |
| 1420 | break; |
| 1368 | 1421 | case 0x430b: case 0x431b: case 0x432b: case 0x433b: |
| 1369 | 1422 | case 0x434b: case 0x435b: case 0x436b: case 0x437b: |
| 1423 | state->dma_channel[(offset & 0x70) >> 4].unk = data; |
| 1370 | 1424 | break; |
| 1371 | 1425 | } |
| 1372 | 1426 | |
| r7651 | r7652 | |
| 2398 | 2452 | |
| 2399 | 2453 | INLINE void snes_dma_transfer( const address_space *space, UINT8 dma, UINT32 abus, UINT16 bbus ) |
| 2400 | 2454 | { |
| 2455 | snes_state *state = (snes_state *)space->machine->driver_data; |
| 2401 | 2456 | UINT32 src, dst; |
| 2402 | 2457 | |
| 2403 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2458 | if (state->dma_channel[dma].dmap & 0x80) /* PPU->CPU */ |
| 2404 | 2459 | { |
| 2405 | 2460 | if (bbus == 0x2180 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) |
| 2406 | 2461 | { |
| r7651 | r7652 | |
| 2436 | 2491 | } |
| 2437 | 2492 | |
| 2438 | 2493 | #if 0 |
| 2439 | | INLINE void snes_dma_transfer( const address_space *space, UINT8 dma, UINT32 abus, UINT16 bbus ) |
| 2494 | // FIXME: we need to use snes_state->hdma_iaddr[i] where appropriate (we now still |
| 2495 | // use snes_state->trans_size[i] to avoid regressions in this first wip) |
| 2496 | // and try to make the addr recovering/updating a bit more abstract |
| 2497 | INLINE UINT32 snes_get_hdma_addr( running_machine *machine, int dma ) |
| 2440 | 2498 | { |
| 2441 | | /* TODO: implement open bus access when DMA tries to transfer from not accessible regs */ |
| 2442 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2443 | | memory_write_byte(space, abus, memory_read_byte(space, bbus)); |
| 2444 | | else /* CPU->PPU */ |
| 2445 | | memory_write_byte(space, bbus, memory_read_byte(space, abus)); |
| 2499 | snes_state *state = (snes_state *)machine->driver_data; |
| 2500 | return (state->dma_channel[dma].bank << 16) | (state->dma_channel[dma].hdma_addr++); |
| 2446 | 2501 | } |
| 2502 | |
| 2503 | INLINE UINT32 snes_get_hdma_iaddr( running_machine *machine, int dma ) |
| 2504 | { |
| 2505 | snes_state *state = (snes_state *)machine->driver_data; |
| 2506 | return (state->dma_channel[dma].ibank << 16) | (state->dma_channel[dma].hdma_iaddr++); |
| 2507 | } |
| 2447 | 2508 | #endif |
| 2448 | 2509 | |
| 2449 | 2510 | static void snes_hdma_init( running_machine *machine ) |
| 2450 | 2511 | { |
| 2451 | 2512 | snes_state *state = (snes_state *)machine->driver_data; |
| 2452 | | UINT8 mask = 1, dma = 0, i; |
| 2513 | int i; |
| 2453 | 2514 | |
| 2454 | | state->hdma_chnl = snes_ram[HDMAEN]; |
| 2455 | 2515 | for (i = 0; i < 8; i++) |
| 2456 | 2516 | { |
| 2457 | | if (snes_ram[HDMAEN] & mask) |
| 2517 | if (BIT(state->hdmaen, i)) |
| 2458 | 2518 | { |
| 2459 | | snes_ram[SNES_DMA_BASE + dma + 8] = snes_ram[SNES_DMA_BASE + dma + 2]; |
| 2460 | | snes_ram[SNES_DMA_BASE + dma + 9] = snes_ram[SNES_DMA_BASE + dma + 3]; |
| 2461 | | snes_ram[SNES_DMA_BASE + dma + 0xa] = 0; |
| 2519 | state->dma_channel[i].hdma_addr = state->dma_channel[i].src_addr; |
| 2520 | state->dma_channel[i].hdma_line_counter = 0; |
| 2462 | 2521 | } |
| 2463 | | dma += 0x10; |
| 2464 | | mask <<= 1; |
| 2465 | 2522 | } |
| 2466 | 2523 | } |
| 2467 | 2524 | |
| 2468 | 2525 | static void snes_hdma( const address_space *space ) |
| 2469 | 2526 | { |
| 2470 | 2527 | snes_state *state = (snes_state *)space->machine->driver_data; |
| 2471 | | UINT8 mask = 1, dma = 0, i, contmode; |
| 2528 | UINT8 i, contmode; |
| 2472 | 2529 | UINT16 bbus; |
| 2473 | 2530 | UINT32 abus; |
| 2474 | 2531 | |
| 2475 | 2532 | /* Assume priority of the 8 DMA channels is 0-7 */ |
| 2476 | 2533 | for (i = 0; i < 8; i++) |
| 2477 | 2534 | { |
| 2478 | | if (state->hdma_chnl & mask) |
| 2535 | if (BIT(state->hdmaen, i)) |
| 2479 | 2536 | { |
| 2480 | 2537 | /* Check if we need to read a new line from the table */ |
| 2481 | | if (!(snes_ram[SNES_DMA_BASE + dma + 0xa] & 0x7f)) |
| 2538 | if (!(state->dma_channel[i].hdma_line_counter & 0x7f)) |
| 2482 | 2539 | { |
| 2483 | | abus = (snes_ram[SNES_DMA_BASE + dma + 4] << 16) + (snes_ram[SNES_DMA_BASE + dma + 9] << 8) + snes_ram[SNES_DMA_BASE + dma + 8]; |
| 2540 | abus = (state->dma_channel[i].bank << 16) + state->dma_channel[i].hdma_addr; |
| 2484 | 2541 | |
| 2485 | 2542 | /* Get the number of lines */ |
| 2486 | | snes_ram[SNES_DMA_BASE + dma + 0xa] = memory_read_byte(space, abus); |
| 2487 | | if (!snes_ram[SNES_DMA_BASE + dma + 0xa]) |
| 2543 | state->dma_channel[i].hdma_line_counter = memory_read_byte(space, abus); |
| 2544 | if (!state->dma_channel[i].hdma_line_counter) |
| 2488 | 2545 | { |
| 2489 | 2546 | /* No more lines so clear HDMA */ |
| 2490 | | state->hdma_chnl &= ~mask; |
| 2547 | state->hdmaen &= ~(1 << i); |
| 2491 | 2548 | continue; |
| 2492 | 2549 | } |
| 2493 | 2550 | abus++; |
| 2494 | | snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff; |
| 2495 | | snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff; |
| 2496 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x40) |
| 2551 | state->dma_channel[i].hdma_addr = abus; |
| 2552 | if (state->dma_channel[i].dmap & 0x40) |
| 2497 | 2553 | { |
| 2498 | | snes_ram[SNES_DMA_BASE + dma + 5] = memory_read_byte(space, abus++); |
| 2499 | | snes_ram[SNES_DMA_BASE + dma + 6] = memory_read_byte(space, abus++); |
| 2500 | | snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff; |
| 2501 | | snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff; |
| 2554 | state->dma_channel[i].trans_size = memory_read_byte(space, abus++); |
| 2555 | state->dma_channel[i].trans_size |= (memory_read_byte(space, abus++) << 8); |
| 2556 | state->dma_channel[i].hdma_addr = abus; |
| 2502 | 2557 | } |
| 2503 | 2558 | } |
| 2504 | 2559 | |
| 2505 | | contmode = (--snes_ram[SNES_DMA_BASE + dma + 0xa]) & 0x80; |
| 2560 | contmode = (--state->dma_channel[i].hdma_line_counter) & 0x80; |
| 2506 | 2561 | |
| 2507 | 2562 | /* Transfer addresses */ |
| 2508 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x40) /* Indirect */ |
| 2509 | | abus = (snes_ram[SNES_DMA_BASE + dma + 7] << 16) + (snes_ram[SNES_DMA_BASE + dma + 6] << 8) + snes_ram[SNES_DMA_BASE + dma + 5]; |
| 2563 | if (state->dma_channel[i].dmap & 0x40) /* Indirect */ |
| 2564 | abus = (state->dma_channel[i].ibank << 16) + state->dma_channel[i].trans_size; |
| 2510 | 2565 | else /* Absolute */ |
| 2511 | | abus = (snes_ram[SNES_DMA_BASE + dma + 4] << 16) + (snes_ram[SNES_DMA_BASE + dma + 9] << 8) + snes_ram[SNES_DMA_BASE + dma + 8]; |
| 2512 | | bbus = 0x2100 + snes_ram[SNES_DMA_BASE + dma + 1]; |
| 2566 | abus = (state->dma_channel[i].bank << 16) + state->dma_channel[i].hdma_addr; |
| 2513 | 2567 | |
| 2568 | bbus = state->dma_channel[i].dest_addr + 0x2100; |
| 2569 | |
| 2514 | 2570 | #ifdef SNES_DBG_HDMA |
| 2515 | | mame_printf_debug( "HDMA-Ch: %d(%s) abus: %X bbus: %X type: %d(%X %X)\n", i, snes_ram[SNES_DMA_BASE + dma] & 0x40 ? "Indirect" : "Absolute", abus, bbus, snes_ram[SNES_DMA_BASE + dma] & 0x07, snes_ram[SNES_DMA_BASE + dma + 8],snes_ram[SNES_DMA_BASE + dma + 9] ); |
| 2571 | mame_printf_debug( "HDMA-Ch: %d(%s) abus: %X bbus: %X type: %d(%X)\n", i, state->dma_channel[i].dmap & 0x40 ? "Indirect" : "Absolute", abus, bbus, state->dma_channel[i].dmap & 0x07, state->dma_channel[i].hdma_addr); |
| 2516 | 2572 | #endif |
| 2517 | 2573 | |
| 2518 | | switch (snes_ram[SNES_DMA_BASE + dma] & 0x07) |
| 2574 | switch (state->dma_channel[i].dmap & 0x07) |
| 2519 | 2575 | { |
| 2520 | 2576 | case 0: /* 1 register write once (1 byte: p ) */ |
| 2521 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2577 | snes_dma_transfer(space, i, abus++, bbus); |
| 2522 | 2578 | break; |
| 2523 | 2579 | case 5: /* 2 registers write twice alternate (4 bytes: p, p+1, p, p+1) */ |
| 2524 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2525 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2526 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2527 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2580 | snes_dma_transfer(space, i, abus++, bbus); |
| 2581 | snes_dma_transfer(space, i, abus++, bbus + 1); |
| 2582 | snes_dma_transfer(space, i, abus++, bbus); |
| 2583 | snes_dma_transfer(space, i, abus++, bbus + 1); |
| 2528 | 2584 | break; |
| 2529 | 2585 | case 1: /* 2 registers write once (2 bytes: p, p+1 ) */ |
| 2530 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2531 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2586 | snes_dma_transfer(space, i, abus++, bbus); |
| 2587 | snes_dma_transfer(space, i, abus++, bbus + 1); |
| 2532 | 2588 | break; |
| 2533 | 2589 | case 2: /* 1 register write twice (2 bytes: p, p ) */ |
| 2534 | 2590 | case 6: |
| 2535 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2536 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2591 | snes_dma_transfer(space, i, abus++, bbus); |
| 2592 | snes_dma_transfer(space, i, abus++, bbus); |
| 2537 | 2593 | break; |
| 2538 | 2594 | case 3: /* 2 registers write twice each (4 bytes: p, p, p+1, p+1) */ |
| 2539 | 2595 | case 7: |
| 2540 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2541 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2542 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2543 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2596 | snes_dma_transfer(space, i, abus++, bbus); |
| 2597 | snes_dma_transfer(space, i, abus++, bbus); |
| 2598 | snes_dma_transfer(space, i, abus++, bbus + 1); |
| 2599 | snes_dma_transfer(space, i, abus++, bbus + 1); |
| 2544 | 2600 | break; |
| 2545 | 2601 | case 4: /* 4 registers write once (4 bytes: p, p+1, p+2, p+3) */ |
| 2546 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2547 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2548 | | memory_write_byte(space, bbus + 2, memory_read_byte(space, abus++)); |
| 2549 | | memory_write_byte(space, bbus + 3, memory_read_byte(space, abus++)); |
| 2602 | snes_dma_transfer(space, i, abus++, bbus); |
| 2603 | snes_dma_transfer(space, i, abus++, bbus + 1); |
| 2604 | snes_dma_transfer(space, i, abus++, bbus + 2); |
| 2605 | snes_dma_transfer(space, i, abus++, bbus + 3); |
| 2550 | 2606 | break; |
| 2551 | 2607 | default: |
| 2552 | 2608 | #ifdef MAME_DEBUG |
| 2553 | | mame_printf_debug( " HDMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x07); |
| 2609 | mame_printf_debug( " HDMA of unsupported type: %d\n", state->dma_channel[i].dmap & 0x07); |
| 2554 | 2610 | #endif |
| 2555 | 2611 | break; |
| 2556 | 2612 | } |
| r7651 | r7652 | |
| 2558 | 2614 | /* Update address */ |
| 2559 | 2615 | if (contmode) |
| 2560 | 2616 | { |
| 2561 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x40) /* Indirect */ |
| 2562 | | { |
| 2563 | | snes_ram[SNES_DMA_BASE + dma + 5] = abus & 0xff; |
| 2564 | | snes_ram[SNES_DMA_BASE + dma + 6] = (abus >> 8) & 0xff; |
| 2565 | | } |
| 2617 | if (state->dma_channel[i].dmap & 0x40) /* Indirect */ |
| 2618 | state->dma_channel[i].trans_size = abus; |
| 2566 | 2619 | else /* Absolute */ |
| 2567 | | { |
| 2568 | | snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff; |
| 2569 | | snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff; |
| 2570 | | } |
| 2620 | state->dma_channel[i].hdma_addr = abus; |
| 2571 | 2621 | } |
| 2572 | 2622 | |
| 2573 | | if (!(snes_ram[SNES_DMA_BASE + dma + 0xa] & 0x7f)) |
| 2623 | if (!(state->dma_channel[i].hdma_line_counter & 0x7f)) |
| 2574 | 2624 | { |
| 2575 | | if (!(snes_ram[SNES_DMA_BASE + dma] & 0x40)) /* Absolute */ |
| 2625 | if (!(state->dma_channel[i].dmap & 0x40)) /* Absolute */ |
| 2576 | 2626 | { |
| 2577 | 2627 | if (!contmode) |
| 2578 | | { |
| 2579 | | snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff; |
| 2580 | | snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff; |
| 2581 | | } |
| 2628 | state->dma_channel[i].hdma_addr = abus; |
| 2582 | 2629 | } |
| 2583 | 2630 | } |
| 2584 | 2631 | } |
| 2585 | | dma += 0x10; |
| 2586 | | mask <<= 1; |
| 2587 | 2632 | } |
| 2588 | 2633 | } |
| 2589 | 2634 | |
| 2590 | 2635 | static void snes_dma( const address_space *space, UINT8 channels ) |
| 2591 | 2636 | { |
| 2592 | 2637 | snes_state *state = (snes_state *)space->machine->driver_data; |
| 2593 | | UINT8 mask = 1, dma = 0, i; |
| 2638 | int i; |
| 2594 | 2639 | INT8 increment; |
| 2595 | 2640 | UINT16 bbus; |
| 2596 | 2641 | UINT32 abus, abus_bank, length; |
| r7651 | r7652 | |
| 2598 | 2643 | /* Assume priority of the 8 DMA channels is 0-7 */ |
| 2599 | 2644 | for (i = 0; i < 8; i++) |
| 2600 | 2645 | { |
| 2601 | | if (channels & mask) |
| 2646 | if (BIT(channels, i)) |
| 2602 | 2647 | { |
| 2603 | 2648 | /* FIXME: the following should be used to stop DMA if the same channel is used by HDMA (being set to 1 in snes_hdma) |
| 2604 | 2649 | However, this cannot be implemented as is atm, because currently DMA transfers always happen as soon as they are enabled... */ |
| 2605 | | state->dma_disabled[i] = 0; |
| 2650 | state->dma_channel[i].dma_disabled = 0; |
| 2606 | 2651 | |
| 2607 | 2652 | //printf( "Making a transfer on channel %d\n", i ); |
| 2608 | 2653 | /* Find transfer addresses */ |
| 2609 | | abus = (snes_ram[SNES_DMA_BASE + dma + 3] << 8) + snes_ram[SNES_DMA_BASE + dma + 2]; |
| 2610 | | abus_bank = (snes_ram[SNES_DMA_BASE + dma + 4] << 16); |
| 2611 | | bbus = 0x2100 + snes_ram[SNES_DMA_BASE + dma + 1]; |
| 2654 | abus = state->dma_channel[i].src_addr; |
| 2655 | abus_bank = state->dma_channel[i].bank << 16; |
| 2656 | bbus = state->dma_channel[i].dest_addr + 0x2100; |
| 2612 | 2657 | |
| 2613 | | //printf( "Address: %06x\n", abus | abus_bank ); |
| 2658 | //printf("Address: %06x\n", abus | abus_bank); |
| 2614 | 2659 | /* Auto increment */ |
| 2615 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x8) |
| 2616 | | { |
| 2660 | if (state->dma_channel[i].dmap & 0x8) |
| 2617 | 2661 | increment = 0; |
| 2618 | | } |
| 2619 | 2662 | else |
| 2620 | 2663 | { |
| 2621 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x10) |
| 2664 | if (state->dma_channel[i].dmap & 0x10) |
| 2622 | 2665 | increment = -1; |
| 2623 | 2666 | else |
| 2624 | 2667 | increment = 1; |
| 2625 | 2668 | } |
| 2626 | 2669 | |
| 2627 | 2670 | /* Number of bytes to transfer */ |
| 2628 | | length = (snes_ram[SNES_DMA_BASE + dma + 6] << 8) + snes_ram[SNES_DMA_BASE + dma + 5]; |
| 2671 | length = state->dma_channel[i].trans_size; |
| 2629 | 2672 | if (!length) |
| 2630 | 2673 | length = 0x10000; /* 0x0000 really means 0x10000 */ |
| 2631 | 2674 | |
| 2632 | | // printf( "DMA-Ch %d: len: %X, abus: %X, bbus: %X, incr: %d, dir: %s, type: %d\n", i, length, abus, bbus, increment, snes_ram[SNES_DMA_BASE + dma] & 0x80 ? "PPU->CPU" : "CPU->PPU", snes_ram[SNES_DMA_BASE + dma] & 0x07); |
| 2675 | // printf( "DMA-Ch %d: len: %X, abus: %X, bbus: %X, incr: %d, dir: %s, type: %d\n", i, length, abus, bbus, increment, state->dma_channel[i].dmap & 0x80 ? "PPU->CPU" : "CPU->PPU", state->dma_channel[i].dmap & 0x07); |
| 2633 | 2676 | |
| 2634 | 2677 | #ifdef SNES_DBG_DMA |
| 2635 | | mame_printf_debug( "DMA-Ch %d: len: %X, abus: %X, bbus: %X, incr: %d, dir: %s, type: %d\n", i, length, abus, bbus, increment, snes_ram[SNES_DMA_BASE + dma] & 0x80 ? "PPU->CPU" : "CPU->PPU", snes_ram[SNES_DMA_BASE + dma] & 0x07); |
| 2678 | mame_printf_debug( "DMA-Ch %d: len: %X, abus: %X, bbus: %X, incr: %d, dir: %s, type: %d\n", i, length, abus, bbus, increment, state->dma_channel[i].dmap & 0x80 ? "PPU->CPU" : "CPU->PPU", state->dma_channel[i].dmap & 0x07); |
| 2636 | 2679 | #endif |
| 2637 | 2680 | |
| 2638 | | switch (snes_ram[SNES_DMA_BASE + dma] & 0x07) |
| 2681 | switch (state->dma_channel[i].dmap & 0x07) |
| 2639 | 2682 | { |
| 2640 | 2683 | case 0: /* 1 register write once */ |
| 2641 | 2684 | case 2: /* 1 register write twice */ |
| 2642 | 2685 | case 6: /* 1 register write twice */ |
| 2643 | | |
| 2644 | | while (length-- && !state->dma_disabled[i]) |
| 2686 | while (length-- && !state->dma_channel[i].dma_disabled) |
| 2645 | 2687 | { |
| 2646 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2688 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus); |
| 2647 | 2689 | abus += increment; |
| 2648 | 2690 | } |
| 2649 | 2691 | break; |
| 2650 | 2692 | case 1: /* 2 registers write once */ |
| 2651 | 2693 | case 5: /* 2 registers write twice alternate */ |
| 2652 | | while (length-- && !state->dma_disabled[i]) |
| 2694 | while (length-- && !state->dma_channel[i].dma_disabled) |
| 2653 | 2695 | { |
| 2654 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2696 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus); |
| 2655 | 2697 | abus += increment; |
| 2656 | | if (!(length--) || state->dma_disabled[i]) |
| 2698 | if (!(length--) || state->dma_channel[i].dma_disabled) |
| 2657 | 2699 | break; |
| 2658 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2700 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2659 | 2701 | abus += increment; |
| 2660 | 2702 | } |
| 2661 | 2703 | break; |
| 2662 | 2704 | case 3: /* 2 registers write twice each */ |
| 2663 | 2705 | case 7: /* 2 registers write twice each */ |
| 2664 | | while (length-- && !state->dma_disabled[i]) |
| 2706 | while (length-- && !state->dma_channel[i].dma_disabled) |
| 2665 | 2707 | { |
| 2666 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2708 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus); |
| 2667 | 2709 | abus += increment; |
| 2668 | | if (!(length--) || state->dma_disabled[i]) |
| 2710 | if (!(length--) || state->dma_channel[i].dma_disabled) |
| 2669 | 2711 | break; |
| 2670 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2712 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus); |
| 2671 | 2713 | abus += increment; |
| 2672 | | if (!(length--) || state->dma_disabled[i]) |
| 2714 | if (!(length--) || state->dma_channel[i].dma_disabled) |
| 2673 | 2715 | break; |
| 2674 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2716 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2675 | 2717 | abus += increment; |
| 2676 | | if (!(length--) || state->dma_disabled[i]) |
| 2718 | if (!(length--) || state->dma_channel[i].dma_disabled) |
| 2677 | 2719 | break; |
| 2678 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2720 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2679 | 2721 | abus += increment; |
| 2680 | 2722 | } |
| 2681 | 2723 | break; |
| 2682 | 2724 | case 4: /* 4 registers write once */ |
| 2683 | | while (length-- && !state->dma_disabled[i]) |
| 2725 | while (length-- && !state->dma_channel[i].dma_disabled) |
| 2684 | 2726 | { |
| 2685 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2727 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus); |
| 2686 | 2728 | abus += increment; |
| 2687 | | if (!(length--) || state->dma_disabled[i]) |
| 2729 | if (!(length--) || state->dma_channel[i].dma_disabled) |
| 2688 | 2730 | break; |
| 2689 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2731 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2690 | 2732 | abus += increment; |
| 2691 | | if (!(length--) || state->dma_disabled[i]) |
| 2733 | if (!(length--) || state->dma_channel[i].dma_disabled) |
| 2692 | 2734 | break; |
| 2693 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 2); |
| 2735 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 2); |
| 2694 | 2736 | abus += increment; |
| 2695 | | if (!(length--) || state->dma_disabled[i]) |
| 2737 | if (!(length--) || state->dma_channel[i].dma_disabled) |
| 2696 | 2738 | break; |
| 2697 | | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 3); |
| 2739 | snes_dma_transfer(space, i, (abus & 0xffff) | abus_bank, bbus + 3); |
| 2698 | 2740 | abus += increment; |
| 2699 | 2741 | } |
| 2700 | 2742 | break; |
| 2701 | 2743 | default: |
| 2702 | 2744 | #ifdef MAME_DEBUG |
| 2703 | | mame_printf_debug( " DMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x07); |
| 2745 | mame_printf_debug(" DMA of unsupported type: %d\n", state->dma_channel[i].dmap & 0x07); |
| 2704 | 2746 | #endif |
| 2705 | 2747 | break; |
| 2706 | 2748 | } |
| 2707 | 2749 | |
| 2708 | | /* We're done so write the new abus back to the registers */ |
| 2709 | | snes_w_io(space, SNES_DMA_BASE + dma + 2, abus & 0xff); |
| 2710 | | snes_w_io(space, SNES_DMA_BASE + dma + 3, (abus >> 8) & 0xff); |
| 2711 | | snes_w_io(space, SNES_DMA_BASE + dma + 5, 0); |
| 2712 | | snes_w_io(space, SNES_DMA_BASE + dma + 6, 0); |
| 2750 | /* We're done, so write the new abus back to the registers */ |
| 2751 | state->dma_channel[i].src_addr = abus; |
| 2752 | state->dma_channel[i].trans_size = 0; |
| 2713 | 2753 | } |
| 2714 | | dma += 0x10; |
| 2715 | | mask <<= 1; |
| 2716 | 2754 | } |
| 2717 | 2755 | } |
| 2718 | 2756 | |