trunk/src/mame/machine/snes.c
| r17409 | r17410 | |
| 13 | 13 | Thanks to Anomie for invaluable technical information. |
| 14 | 14 | Thanks to byuu for invaluable technical information. |
| 15 | 15 | |
| 16 | TODO: |
| 17 | - DMA takes some Master CPU clock cycles that aren't taken into account |
| 18 | for now. |
| 19 | |
| 16 | 20 | ***************************************************************************/ |
| 17 | 21 | #define __MACHINE_SNES_C |
| 18 | 22 | |
| r17409 | r17410 | |
| 55 | 59 | #include "machine/snes7110.c" |
| 56 | 60 | #include "machine/snesbsx.c" |
| 57 | 61 | |
| 58 | | #define USE_CYCLE_STEAL 1 |
| 59 | | |
| 60 | 62 | // ST-010 and ST-011 RAM interface |
| 61 | 63 | UINT8 st010_read_ram(snes_state *state, UINT16 addr) |
| 62 | 64 | { |
| r17409 | r17410 | |
| 892 | 894 | |
| 893 | 895 | */ |
| 894 | 896 | |
| 895 | | #if USE_CYCLE_STEAL |
| 896 | | /*FIXME: missing work RAM access steal / we need to do this less "aggressive" otherwise we lose too much CPU horsepower, why? */ |
| 897 | | static int snes_bank_0x00_0x3f_cycles(running_machine &machine,UINT32 offset) |
| 898 | | { |
| 899 | | /* |
| 900 | | $00-$3F | $0000-$1FFF | Slow | Address Bus A + /WRAM (mirror $7E:0000-$1FFF) |
| 901 | | | $2000-$20FF | Fast | Address Bus A |
| 902 | | | $2100-$21FF | Fast | Address Bus B |
| 903 | | | $2200-$3FFF | Fast | Address Bus A |
| 904 | | | $4000-$41FF | XSlow | Internal CPU registers (see Note 1 below) |
| 905 | | | $4200-$43FF | Fast | Internal CPU registers (see Note 1 below) |
| 906 | | | $4400-$5FFF | Fast | Address Bus A |
| 907 | | | $6000-$7FFF | Slow | Address Bus A |
| 908 | | | $8000-$FFFF | Slow | Address Bus A + /CART |
| 909 | | */ |
| 910 | | |
| 911 | | if(((offset & 0xff00) == 0x4000) || ((offset & 0xff00) == 0x4100)) |
| 912 | | return 0; //TODO: 12 |
| 913 | | if(((offset & 0xff00) == 0x4200) || ((offset & 0xff00) == 0x4300)) |
| 914 | | return 0; //TODO: 6 |
| 915 | | |
| 916 | | if((offset & 0xff00) <= 0x1f00) |
| 917 | | return 0; //TODO: 8 |
| 918 | | |
| 919 | | if((offset & 0xff00) >= 0x6000) |
| 920 | | return 8; |
| 921 | | |
| 922 | | return 0; //TODO: 6 |
| 923 | | } |
| 924 | | |
| 925 | | static int snes_bank_0x80_0xbf_cycles(running_machine &machine,UINT32 offset) |
| 926 | | { |
| 927 | | /* |
| 928 | | $80-$BF | $0000-$1FFF | Slow | Address Bus A + /WRAM (mirror $7E:0000-$1FFF) |
| 929 | | | $2000-$20FF | Fast | Address Bus A |
| 930 | | | $2100-$21FF | Fast | Address Bus B |
| 931 | | | $2200-$3FFF | Fast | Address Bus A |
| 932 | | | $4000-$41FF | XSlow | Internal CPU registers (see Note 1 below) |
| 933 | | | $4200-$43FF | Fast | Internal CPU registers (see Note 1 below) |
| 934 | | | $4400-$5FFF | Fast | Address Bus A |
| 935 | | | $6000-$7FFF | Slow | Address Bus A |
| 936 | | | $8000-$FFFF | Note2 | Address Bus A + /CART |
| 937 | | */ |
| 938 | | |
| 939 | | |
| 940 | | if(((offset & 0xff00) == 0x4000) || ((offset & 0xff00) == 0x4100)) |
| 941 | | return 0; //TODO: 12 |
| 942 | | |
| 943 | | if(((offset & 0xff00) == 0x4200) || ((offset & 0xff00) == 0x4300)) |
| 944 | | return 0; //TODO: 6 |
| 945 | | |
| 946 | | if((offset & 0xff00) <= 0x1f00) |
| 947 | | return 0; //TODO: 8 |
| 948 | | |
| 949 | | if(((offset & 0xff00) >= 0x6000) && ((offset & 0xff00) <= 0x7f00)) |
| 950 | | return 0; //TODO: 8 |
| 951 | | |
| 952 | | if(((offset & 0xff00) >= 0x8000) && ((offset & 0xff00) <= 0xff00)) |
| 953 | | return (snes_ram[MEMSEL] & 1) ? 6 : 8; |
| 954 | | |
| 955 | | return 0; //TODO: 6 |
| 956 | | } |
| 957 | | #endif |
| 958 | | |
| 959 | 897 | /* 0x000000 - 0x2fffff */ |
| 960 | 898 | READ8_HANDLER( snes_r_bank1 ) |
| 961 | 899 | { |
| r17409 | r17410 | |
| 1007 | 945 | else |
| 1008 | 946 | value = snes_ram[offset]; |
| 1009 | 947 | |
| 1010 | | #if USE_CYCLE_STEAL |
| 1011 | | if(!space->debugger_access()) |
| 1012 | | device_adjust_icount(&space->device(), -snes_bank_0x00_0x3f_cycles(space->machine(), offset)); |
| 1013 | | #endif |
| 1014 | | |
| 1015 | 948 | return value; |
| 1016 | 949 | } |
| 1017 | 950 | |
| r17409 | r17410 | |
| 1074 | 1007 | else |
| 1075 | 1008 | value = snes_ram[0x300000 + offset]; |
| 1076 | 1009 | |
| 1077 | | #if USE_CYCLE_STEAL |
| 1078 | | if(!space->debugger_access()) |
| 1079 | | device_adjust_icount(&space->device(), -snes_bank_0x00_0x3f_cycles(space->machine(), offset)); |
| 1080 | | #endif |
| 1081 | | |
| 1082 | 1010 | return value; |
| 1083 | 1011 | } |
| 1084 | 1012 | |
| r17409 | r17410 | |
| 1117 | 1045 | else /* Mode 21 & 25 + SuperFX games */ |
| 1118 | 1046 | value = snes_ram[0x400000 + offset]; |
| 1119 | 1047 | |
| 1120 | | #if USE_CYCLE_STEAL |
| 1121 | | if(!space->debugger_access()) |
| 1122 | | device_adjust_icount(&space->device(), -8); |
| 1123 | | #endif |
| 1124 | | |
| 1125 | 1048 | return value; |
| 1126 | 1049 | } |
| 1127 | 1050 | |
| r17409 | r17410 | |
| 1166 | 1089 | else if (state->m_cart[0].mode & 0x0a) /* Mode 21 & 25 */ |
| 1167 | 1090 | value = snes_ram[0x600000 + offset]; |
| 1168 | 1091 | |
| 1169 | | #if USE_CYCLE_STEAL |
| 1170 | | if(!space->debugger_access()) |
| 1171 | | device_adjust_icount(&space->device(), -8); |
| 1172 | | #endif |
| 1173 | | |
| 1174 | 1092 | return value; |
| 1175 | 1093 | } |
| 1176 | 1094 | |
| r17409 | r17410 | |
| 1204 | 1122 | else |
| 1205 | 1123 | value = snes_ram[0x700000 + offset]; |
| 1206 | 1124 | |
| 1207 | | #if USE_CYCLE_STEAL |
| 1208 | | if(!space->debugger_access()) |
| 1209 | | device_adjust_icount(&space->device(), -8); |
| 1210 | | #endif |
| 1211 | | |
| 1212 | 1125 | return value; |
| 1213 | 1126 | } |
| 1214 | 1127 | |
| r17409 | r17410 | |
| 1254 | 1167 | else |
| 1255 | 1168 | value = snes_ram[0x800000 + offset]; |
| 1256 | 1169 | |
| 1257 | | #if USE_CYCLE_STEAL |
| 1258 | | if(!space->debugger_access()) |
| 1259 | | device_adjust_icount(&space->device(), -snes_bank_0x80_0xbf_cycles(space->machine(), offset)); |
| 1260 | | #endif |
| 1261 | | |
| 1262 | 1170 | return value; |
| 1263 | 1171 | } |
| 1264 | 1172 | |
| r17409 | r17410 | |
| 1318 | 1226 | else /* Mode 21 & 25 + SuperFX Games */ |
| 1319 | 1227 | value = snes_ram[0xc00000 + offset]; |
| 1320 | 1228 | |
| 1321 | | #if USE_CYCLE_STEAL |
| 1322 | | if(!space->debugger_access()) |
| 1323 | | device_adjust_icount(&space->device(), -((snes_ram[MEMSEL] & 1) ? 6 : 8)); |
| 1324 | | #endif |
| 1325 | | |
| 1326 | 1229 | return value; |
| 1327 | 1230 | } |
| 1328 | 1231 | |
| r17409 | r17410 | |
| 1376 | 1279 | dsp_set_sr(data); |
| 1377 | 1280 | else |
| 1378 | 1281 | logerror( "(PC=%06x) Attempt to write to ROM address: %X\n",cpu_get_pc(&space->device()),offset ); |
| 1379 | | |
| 1380 | | #if USE_CYCLE_STEAL |
| 1381 | | if(!space->debugger_access()) |
| 1382 | | device_adjust_icount(&space->device(), -snes_bank_0x00_0x3f_cycles(space->machine(), offset)); |
| 1383 | | #endif |
| 1384 | 1282 | } |
| 1385 | 1283 | |
| 1386 | 1284 | /* 0x300000 - 0x3fffff */ |
| r17409 | r17410 | |
| 1438 | 1336 | dsp_set_sr(data); |
| 1439 | 1337 | else |
| 1440 | 1338 | logerror("(PC=%06x) Attempt to write to ROM address: %X\n",cpu_get_pc(&space->device()),offset + 0x300000); |
| 1441 | | |
| 1442 | | #if USE_CYCLE_STEAL |
| 1443 | | if(!space->debugger_access()) |
| 1444 | | device_adjust_icount(&space->device(), -snes_bank_0x00_0x3f_cycles(space->machine(), offset)); |
| 1445 | | #endif |
| 1446 | 1339 | } |
| 1447 | 1340 | |
| 1448 | 1341 | /* 0x600000 - 0x6fffff */ |
| r17409 | r17410 | |
| 1479 | 1372 | } |
| 1480 | 1373 | else if (state->m_cart[0].mode & 0x0a) |
| 1481 | 1374 | logerror("(PC=%06x) Attempt to write to ROM address: %X\n",cpu_get_pc(&space->device()),offset + 0x600000); |
| 1482 | | |
| 1483 | | #if USE_CYCLE_STEAL |
| 1484 | | if(!space->debugger_access()) |
| 1485 | | device_adjust_icount(&space->device(), -8); |
| 1486 | | #endif |
| 1487 | 1375 | } |
| 1488 | 1376 | |
| 1489 | 1377 | /* 0x700000 - 0x7dffff */ |
| r17409 | r17410 | |
| 1506 | 1394 | } |
| 1507 | 1395 | else if (state->m_cart[0].mode & 0x0a) |
| 1508 | 1396 | logerror("(PC=%06x) Attempt to write to ROM address: %X\n",cpu_get_pc(&space->device()),offset + 0x700000); |
| 1509 | | |
| 1510 | | #if USE_CYCLE_STEAL |
| 1511 | | if(!space->debugger_access()) |
| 1512 | | device_adjust_icount(&space->device(), -8); |
| 1513 | | #endif |
| 1514 | 1397 | } |
| 1515 | 1398 | |
| 1516 | 1399 | |
| r17409 | r17410 | |
| 1562 | 1445 | dsp_set_sr(data); |
| 1563 | 1446 | else |
| 1564 | 1447 | logerror("(PC=%06x) Attempt to write to ROM address: %X\n",cpu_get_pc(&space->device()),offset + 0x800000); |
| 1565 | | |
| 1566 | | #if USE_CYCLE_STEAL |
| 1567 | | if(!space->debugger_access()) |
| 1568 | | device_adjust_icount(&space->device(), -snes_bank_0x80_0xbf_cycles(space->machine(), offset)); |
| 1569 | | #endif |
| 1570 | 1448 | } |
| 1571 | 1449 | |
| 1572 | 1450 | |
| r17409 | r17410 | |
| 1617 | 1495 | } |
| 1618 | 1496 | else if (state->m_cart[0].mode & 0x0a) |
| 1619 | 1497 | logerror("(PC=%06x) Attempt to write to ROM address: %X\n",cpu_get_pc(&space->device()),offset + 0xc00000); |
| 1620 | | |
| 1621 | | #if USE_CYCLE_STEAL |
| 1622 | | if(!space->debugger_access()) |
| 1623 | | device_adjust_icount(&space->device(), -((snes_ram[MEMSEL] & 1) ? 6 : 8)); |
| 1624 | | #endif |
| 1625 | 1498 | } |
| 1626 | 1499 | |
| 1627 | 1500 | |
| r17409 | r17410 | |
| 2143 | 2016 | { |
| 2144 | 2017 | snes_state *state = space->machine().driver_data<snes_state>(); |
| 2145 | 2018 | |
| 2146 | | #if USE_CYCLE_STEAL |
| 2147 | | /* every byte transfer takes 8 master cycles */ |
| 2148 | | // FIXME: this cycle steal makes Final Fantasy VI (III in US) very glitchy! |
| 2149 | | // device_adjust_icount(&space->device(),-8); |
| 2150 | | #endif |
| 2151 | | |
| 2152 | 2019 | if (state->m_dma_channel[dma].dmap & 0x80) /* PPU->CPU */ |
| 2153 | 2020 | { |
| 2154 | 2021 | if (bbus == 0x2180 && ((abus & 0xfe0000) == 0x7e0000 || (abus & 0x40e000) == 0x0000)) |
| r17409 | r17410 | |
| 2355 | 2222 | |
| 2356 | 2223 | /* FIXME: we also need to round to the nearest 8 master cycles */ |
| 2357 | 2224 | |
| 2358 | | #if USE_CYCLE_STEAL |
| 2359 | | /* overhead steals 8 master cycles, correct? */ |
| 2360 | | device_adjust_icount(&space->device(),-8); |
| 2361 | | #endif |
| 2362 | | |
| 2363 | 2225 | /* Assume priority of the 8 DMA channels is 0-7 */ |
| 2364 | 2226 | for (i = 0; i < 8; i++) |
| 2365 | 2227 | { |
| r17409 | r17410 | |
| 2468 | 2330 | /* We're done, so write the new abus back to the registers */ |
| 2469 | 2331 | state->m_dma_channel[i].src_addr = abus; |
| 2470 | 2332 | state->m_dma_channel[i].trans_size = 0; |
| 2471 | | |
| 2472 | | #if USE_CYCLE_STEAL |
| 2473 | | /* active channel takes 8 master cycles */ |
| 2474 | | device_adjust_icount(&space->device(),-8); |
| 2475 | | #endif |
| 2476 | 2333 | } |
| 2477 | 2334 | } |
| 2478 | 2335 | |
| 2479 | | /* finally, take yet another 8 master cycles for the aforementioned overhead */ |
| 2480 | | #if USE_CYCLE_STEAL |
| 2481 | | device_adjust_icount(&space->device(),-8); |
| 2482 | | #endif |
| 2483 | 2336 | } |
| 2484 | 2337 | |
| 2485 | 2338 | READ8_HANDLER( superfx_r_bank1 ) |