src/mess/machine/mac.c
| r3084 | r3085 | |
| 2 | 2 | |
| 3 | 3 | machine/mac.c |
| 4 | 4 | |
| 5 | | Mac hardware - Mac 128k, 512k, 512ke, Plus (SCSI, SCC, etc) |
| 5 | Mac hardware - Mac 128k, 512k, 512ke, Plus, SE, Classic, II (SCSI, SCC, ADB, etc) |
| 6 | 6 | |
| 7 | 7 | Nate Woods |
| 8 | 8 | Ernesto Corvi |
| 9 | 9 | Raphael Nabet |
| 10 | R. Belmont |
| 10 | 11 | |
| 11 | 12 | Mac Model Feature Summary: |
| 12 | 13 | |
| 13 | | CPU FDC Keyb PRAM ROMMir |
| 14 | | - Mac 128k 68k IWM orig orig ??? |
| 15 | | - Mac 512k 68k IWM orig orig ??? |
| 16 | | - Mac 512ke 68k IWM orig orig ??? |
| 17 | | - Mac Plus 68k IWM orig ext no |
| 18 | | - Mac SE 68k IWM ADB ext ??? |
| 19 | | - Mac Classic 68k IWM ADB ext ??? |
| 14 | CPU FDC Kbd/Mouse PRAM Video |
| 15 | - Mac 128k 68k IWM orig orig Original |
| 16 | - Mac 512k 68k IWM orig orig Original |
| 17 | - Mac 512ke 68k IWM orig orig Original |
| 18 | - Mac Plus 68k IWM orig ext Original |
| 19 | - Mac SE 68k IWM MacII ADB ext Original |
| 20 | - Mac Classic 68k SWIM ADB-??? ext Original |
| 21 | - Mac Portable 68k (16 MHz) SWIM ADB-PMU PMU 640x480 B&W |
| 22 | - PwrBook 100 68k (16 MHz) SWIM ADB-PMU PMU 640x480 B&W |
| 23 | - Mac II 020 IWM MacII ADB ext NuBus card |
| 24 | - Mac IIx 030 SWIM MacII ADB ext NuBus card |
| 25 | - Mac IIfx 030 SWIM ADB-IOP ext NuBus card |
| 26 | - Mac SE/30 030 SWIM MacII ADB ext Internal fake NuBus card (need video declaration ROM!) |
| 27 | - Mac IIcx 030 SWIM ADB-CUDA ext NuBus card |
| 28 | - Mac IIci 030 SWIM ADB-CUDA ext Internal "RBV" type |
| 20 | 29 | |
| 21 | 30 | Notes: |
| 22 | 31 | - The Mac Plus boot code seems to check to see the extent of ROM |
| 23 | 32 | mirroring to determine if SCSI is available. If the ROM is mirrored, |
| 24 | 33 | then SCSI is not available. Thanks to R. Belmont for making this |
| 25 | 34 | discovery. |
| 35 | - On the SE and most later Macs, the first access to 4xxxxx turns off the overlay. |
| 36 | However, the Mac II has the old-style VIA overlay control bit! |
| 37 | - The Mac II can have either a 68551 PMMU fitted or an Apple custom that handles 24 vs. 32 |
| 38 | bit addressing mode. The ROM is *not* 32-bit clean so Mac OS normally runs in 24 bit mode, |
| 39 | but A/UX can run 32. |
| 40 | - There are 5 known kinds of host-side ADB hardware: |
| 41 | * "Mac II ADB" used in the SE, II, IIx, IIcx, SE/30, IIci, Quadra 610, Quadra 650, Quadra 700, |
| 42 | Quadra 800, Centris 610 and Centris 650. This is a dumb state machine using the VIA. |
| 43 | * "ADB-PMU" used in the Mac Portable and all 680x0-based PowerBooks. |
| 44 | * "ADB-EGRET" used in the IIsi, IIvi, IIvx, Classic II, LC, LC II, LC III, Performa 460, |
| 45 | and Performa 600. This is a 68HC05 with a different internal ROM than CUDA. |
| 46 | * "ADB-IOP" (ADB driven by a 6502 coprocessor, similar to Lisa) used in the IIfx, |
| 47 | Quadra 900, and Quadra 950. |
| 48 | * "ADB-CUDA" (Apple's CUDA chip, which is a 68HC05 MCU) used in the Color Classic, LC 520, |
| 49 | LC 55x, LC 57x, LC 58x, Quadra 630, Quadra 660AV, Quadra 840AV, PowerMac 6100/7100/8100, |
| 50 | IIcx, IIci, and PowerMac 5200. |
| 26 | 51 | |
| 27 | 52 | TODO: |
| 53 | - Mac Portable and PowerBook 100 are similar to this hardware, but we need ROMs! |
| 28 | 54 | - Call the RTC timer |
| 29 | | |
| 30 | | - Support Mac 128k, 512k (easy, we just need the ROM image) |
| 31 | | - Support Mac SE, Classic (we need to find the ROMs and implement ADB; |
| 32 | | SE FDHD and Classic require SIWM support, too) |
| 55 | - SE FDHD and Classic require SWIM support. SWIM is 100% IWM compatible with 800k drives, but |
| 56 | becomes a different chip for 1.44MB. |
| 33 | 57 | - Check that 0x600000-0x6fffff still address RAM when overlay bit is off |
| 34 | 58 | (IM-III seems to say it does not on Mac 128k, 512k, and 512ke). |
| 35 | 59 | - What on earth are 0x700000-0x7fffff mapped to ? |
| r3084 | r3085 | |
| 64 | 88 | #define LOG_MEMORY 0 |
| 65 | 89 | #endif |
| 66 | 90 | |
| 91 | #define LOG_ADB 0 |
| 92 | |
| 93 | // ADB states |
| 94 | #define ADB_STATE_NEW_COMMAND (0) |
| 95 | #define ADB_STATE_XFER_EVEN (1) |
| 96 | #define ADB_STATE_XFER_ODD (2) |
| 97 | #define ADB_STATE_IDLE (3) |
| 98 | |
| 99 | // ADB commands |
| 100 | #define ADB_CMD_RESET (0) |
| 101 | #define ADB_CMD_FLUSH (1) |
| 102 | |
| 67 | 103 | static TIMER_CALLBACK(mac_scanline_tick); |
| 68 | | static emu_timer *mac_scanline_timer; |
| 104 | static TIMER_CALLBACK(mac_adb_tick); |
| 105 | static emu_timer *mac_scanline_timer, *mac_adb_timer; |
| 69 | 106 | static int scan_keyboard(running_machine *machine); |
| 70 | 107 | static TIMER_CALLBACK(inquiry_timeout_func); |
| 71 | 108 | static void keyboard_receive(running_machine *machine, int val); |
| 72 | 109 | static READ8_HANDLER(mac_via_in_a); |
| 73 | 110 | static READ8_HANDLER(mac_via_in_b); |
| 111 | static READ8_HANDLER(mac_adb_via_in_cb2); |
| 74 | 112 | static WRITE8_HANDLER(mac_via_out_a); |
| 75 | 113 | static WRITE8_HANDLER(mac_via_out_b); |
| 114 | static WRITE8_HANDLER(mac_adb_via_out_cb2); |
| 76 | 115 | static WRITE8_HANDLER(mac_via_out_cb2); |
| 77 | 116 | static void mac_via_irq(running_machine *machine, int state); |
| 78 | 117 | static offs_t mac_dasm_override(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram); |
| r3084 | r3085 | |
| 88 | 127 | mac_via_irq |
| 89 | 128 | }; |
| 90 | 129 | |
| 130 | static const struct via6522_interface mac_via6522_adb_intf = |
| 131 | { |
| 132 | mac_via_in_a, mac_via_in_b, |
| 133 | NULL, NULL, |
| 134 | NULL, mac_adb_via_in_cb2, |
| 135 | mac_via_out_a, mac_via_out_b, |
| 136 | NULL, NULL, |
| 137 | NULL, mac_adb_via_out_cb2, |
| 138 | mac_via_irq |
| 139 | }; |
| 140 | |
| 91 | 141 | /* tells which model is being emulated (set by macxxx_init) */ |
| 92 | 142 | typedef enum |
| 93 | 143 | { |
| r3084 | r3085 | |
| 100 | 150 | |
| 101 | 151 | static UINT32 mac_overlay = 0; |
| 102 | 152 | static mac_model_t mac_model; |
| 153 | static int mac_drive_select = 0; |
| 103 | 154 | |
| 155 | // returns non-zero if this Mac has ADB |
| 156 | static int has_adb(void) |
| 157 | { |
| 158 | return mac_model >= MODEL_MAC_SE; |
| 159 | } |
| 104 | 160 | |
| 161 | // handle disk enable lines |
| 162 | void mac_fdc_set_enable_lines(int enable_mask) |
| 163 | { |
| 164 | if (mac_model < MODEL_MAC_SE) |
| 165 | { |
| 166 | sony_set_enable_lines(enable_mask); |
| 167 | } |
| 168 | else |
| 169 | { |
| 170 | if (enable_mask) |
| 171 | { |
| 172 | sony_set_enable_lines(mac_drive_select ? 1 : 2); |
| 173 | } |
| 174 | else |
| 175 | { |
| 176 | sony_set_enable_lines(enable_mask); |
| 177 | } |
| 178 | } |
| 179 | } |
| 105 | 180 | |
| 106 | 181 | static void mac_install_memory(running_machine *machine, offs_t memory_begin, offs_t memory_end, |
| 107 | 182 | offs_t memory_size, void *memory_data, int is_rom, int bank) |
| r3084 | r3085 | |
| 1144 | 1219 | } |
| 1145 | 1220 | |
| 1146 | 1221 | /* ************************************************************************* |
| 1147 | | * ADB |
| 1222 | * ADB (Mac II-style) |
| 1148 | 1223 | * *************************************************************************/ |
| 1149 | 1224 | |
| 1150 | | static int adb_via_b3; |
| 1225 | // Mac ADB state |
| 1226 | static int adb_irq_pending, adb_waiting_cmd, adb_datasize, adb_buffer[8]; |
| 1227 | static int adb_state, adb_command, adb_send, adb_timer_ticks, adb_extclock, adb_direction; |
| 1228 | static int adb_listenreg, adb_listenaddr; |
| 1151 | 1229 | |
| 1152 | | static int has_adb(void) |
| 1230 | // ADB mouse state |
| 1231 | static int adb_mouseaddr = 3; |
| 1232 | static int adb_lastmousex, adb_lastmousey; |
| 1233 | |
| 1234 | #if LOG_ADB |
| 1235 | static const char *adb_statenames[4] = { "NEW", "EVEN", "ODD", "IDLE" }; |
| 1236 | #endif |
| 1237 | |
| 1238 | static void mac_adb_accummouse( running_machine *machine, UINT8 *MouseX, UINT8 *MouseY ) |
| 1153 | 1239 | { |
| 1154 | | return mac_model >= MODEL_MAC_SE; |
| 1240 | int MouseCountX = 0, MouseCountY = 0; |
| 1241 | int NewX, NewY; |
| 1242 | |
| 1243 | NewX = input_port_read(machine, "MOUSE2"); |
| 1244 | NewY = input_port_read(machine, "MOUSE1"); |
| 1245 | |
| 1246 | /* see if it moved in the x coord */ |
| 1247 | if (NewX != adb_lastmousex) |
| 1248 | { |
| 1249 | int diff = NewX - adb_lastmousex; |
| 1250 | |
| 1251 | /* check for wrap */ |
| 1252 | if (diff > 0x80) |
| 1253 | diff = 0x100-diff; |
| 1254 | if (diff < -0x80) |
| 1255 | diff = -0x100-diff; |
| 1256 | |
| 1257 | MouseCountX += diff; |
| 1258 | adb_lastmousex = NewX; |
| 1259 | } |
| 1260 | |
| 1261 | /* see if it moved in the y coord */ |
| 1262 | if (NewY != adb_lastmousey) |
| 1263 | { |
| 1264 | int diff = NewY - adb_lastmousey; |
| 1265 | |
| 1266 | /* check for wrap */ |
| 1267 | if (diff > 0x80) |
| 1268 | diff = 0x100-diff; |
| 1269 | if (diff < -0x80) |
| 1270 | diff = -0x100-diff; |
| 1271 | |
| 1272 | MouseCountY += diff; |
| 1273 | adb_lastmousey = NewY; |
| 1274 | } |
| 1275 | |
| 1276 | *MouseX = (UINT8)MouseCountX; |
| 1277 | *MouseY = (UINT8)MouseCountY; |
| 1155 | 1278 | } |
| 1156 | 1279 | |
| 1280 | static void mac_adb_talk(running_machine *machine) |
| 1281 | { |
| 1282 | int addr, reg; |
| 1157 | 1283 | |
| 1284 | addr = (adb_command>>4); |
| 1285 | reg = (adb_command & 3); |
| 1158 | 1286 | |
| 1287 | // printf("Mac sent %x\n", adb_command); |
| 1288 | |
| 1289 | if (adb_waiting_cmd) |
| 1290 | { |
| 1291 | switch ((adb_command>>2)&3) |
| 1292 | { |
| 1293 | case 0: |
| 1294 | case 1: |
| 1295 | switch (reg) |
| 1296 | { |
| 1297 | case ADB_CMD_RESET: |
| 1298 | adb_direction = 0; |
| 1299 | adb_send = 0; |
| 1300 | break; |
| 1301 | |
| 1302 | case ADB_CMD_FLUSH: |
| 1303 | adb_direction = 0; |
| 1304 | adb_send = 0; |
| 1305 | break; |
| 1306 | |
| 1307 | default: // reserved/unused |
| 1308 | break; |
| 1309 | } |
| 1310 | break; |
| 1311 | |
| 1312 | case 2: // listen |
| 1313 | // printf("ADB LISTEN: reg %x address %x\n", reg, addr); |
| 1314 | adb_direction = 1; // input from Mac |
| 1315 | adb_listenreg = reg; |
| 1316 | adb_listenaddr = addr; |
| 1317 | break; |
| 1318 | |
| 1319 | case 3: // talk |
| 1320 | // printf("ADB TALK: reg %x address %x\n", reg, addr); |
| 1321 | |
| 1322 | adb_direction = 0; // output to Mac |
| 1323 | if (addr == adb_mouseaddr) |
| 1324 | { |
| 1325 | UINT8 mouseX, mouseY; |
| 1326 | |
| 1327 | // printf("Talking to mouse, register %x\n", reg); |
| 1328 | |
| 1329 | switch (reg) |
| 1330 | { |
| 1331 | // read mouse |
| 1332 | case 0: |
| 1333 | mac_adb_accummouse(machine, &mouseX, &mouseY); |
| 1334 | adb_buffer[0] = (input_port_read(machine, "MOUSE0") & 0x01) ? 0x00 : 0x80; |
| 1335 | adb_buffer[0] |= mouseX & 0x7f; |
| 1336 | adb_buffer[1] = mouseY & 0x7f; |
| 1337 | adb_datasize = 2; |
| 1338 | break; |
| 1339 | |
| 1340 | // get ID/handler |
| 1341 | case 3: |
| 1342 | adb_buffer[0] = 0x60 | ((adb_mouseaddr<<8)&0xf); // SRQ enable, no exceptional event |
| 1343 | adb_buffer[1] = 0x01; // handler 1 |
| 1344 | adb_datasize = 2; |
| 1345 | break; |
| 1346 | |
| 1347 | default: |
| 1348 | break; |
| 1349 | } |
| 1350 | } |
| 1351 | break; |
| 1352 | } |
| 1353 | |
| 1354 | adb_waiting_cmd = 0; |
| 1355 | } |
| 1356 | else |
| 1357 | { |
| 1358 | printf("Got LISTEN data %x for device %x reg %x\n", adb_command, adb_listenreg, adb_listenaddr); |
| 1359 | } |
| 1360 | } |
| 1361 | |
| 1362 | static TIMER_CALLBACK(mac_adb_tick) |
| 1363 | { |
| 1364 | // do one clock transition on CB1 to advance the VIA shifter |
| 1365 | adb_extclock ^= 1; |
| 1366 | via_set_input_cb1(machine, 0, adb_extclock); |
| 1367 | adb_extclock ^= 1; |
| 1368 | via_set_input_cb1(machine, 0, adb_extclock); |
| 1369 | |
| 1370 | adb_timer_ticks--; |
| 1371 | if (!adb_timer_ticks) |
| 1372 | { |
| 1373 | timer_adjust_oneshot(mac_adb_timer, attotime_never, 0); |
| 1374 | |
| 1375 | if (adb_direction) |
| 1376 | { |
| 1377 | mac_adb_talk(machine); |
| 1378 | } |
| 1379 | } |
| 1380 | else |
| 1381 | { |
| 1382 | timer_adjust_oneshot(mac_adb_timer, attotime_make(0, DOUBLE_TO_ATTOSECONDS(0.001)), 0); |
| 1383 | } |
| 1384 | } |
| 1385 | |
| 1386 | static READ8_HANDLER(mac_adb_via_in_cb2) |
| 1387 | { |
| 1388 | UINT8 ret; |
| 1389 | |
| 1390 | ret = (adb_send & 0x80)>>7; |
| 1391 | adb_send <<= 1; |
| 1392 | |
| 1393 | // printf("IN CB2 = %x\n", ret); |
| 1394 | |
| 1395 | return ret; |
| 1396 | } |
| 1397 | |
| 1398 | static WRITE8_HANDLER(mac_adb_via_out_cb2) |
| 1399 | { |
| 1400 | // printf("OUT CB2 = %x\n", data); |
| 1401 | adb_command <<= 1; |
| 1402 | adb_command |= data & 1; |
| 1403 | } |
| 1404 | |
| 1159 | 1405 | static void mac_adb_newaction(int state) |
| 1160 | 1406 | { |
| 1161 | | adb_via_b3 = 1; |
| 1407 | if (state != adb_state) |
| 1408 | { |
| 1409 | #if LOG_ADB |
| 1410 | printf("New ADB state: %s\n", adb_statenames[state]); |
| 1411 | #endif |
| 1412 | |
| 1413 | adb_state = state; |
| 1414 | adb_timer_ticks = 8; |
| 1415 | |
| 1416 | switch (state) |
| 1417 | { |
| 1418 | case ADB_STATE_NEW_COMMAND: |
| 1419 | adb_command = adb_send = 0; |
| 1420 | adb_direction = 1; // Mac is shifting us a command |
| 1421 | adb_waiting_cmd = 1; // we're going to get a command |
| 1422 | break; |
| 1423 | |
| 1424 | case ADB_STATE_XFER_EVEN: |
| 1425 | case ADB_STATE_XFER_ODD: |
| 1426 | if (adb_datasize > 0) |
| 1427 | { |
| 1428 | int i; |
| 1429 | |
| 1430 | // is something trying to send to the Mac? |
| 1431 | if (adb_direction == 0) |
| 1432 | { |
| 1433 | // set up the byte |
| 1434 | adb_send = adb_buffer[0]; |
| 1435 | adb_datasize--; |
| 1436 | |
| 1437 | // move down the rest of the buffer, if any |
| 1438 | for (i = 0; i < adb_datasize; i++) |
| 1439 | { |
| 1440 | adb_buffer[i] = adb_buffer[i+1]; |
| 1441 | } |
| 1442 | } |
| 1443 | } |
| 1444 | else |
| 1445 | { |
| 1446 | adb_send = 0; |
| 1447 | } |
| 1448 | break; |
| 1449 | |
| 1450 | case ADB_STATE_IDLE: |
| 1451 | break; |
| 1452 | } |
| 1453 | |
| 1454 | // no matter what, generate 8 clocks (should this happen on IDLE?) |
| 1455 | timer_adjust_oneshot(mac_adb_timer, attotime_make(0, DOUBLE_TO_ATTOSECONDS(0.001)), 0); |
| 1456 | } |
| 1162 | 1457 | } |
| 1163 | 1458 | |
| 1459 | static void adb_reset(void) |
| 1460 | { |
| 1461 | adb_irq_pending = 0; // no interrupt |
| 1462 | adb_timer_ticks = 0; |
| 1463 | adb_command = 0; |
| 1464 | adb_extclock = 0; |
| 1465 | adb_send = 0; |
| 1466 | adb_waiting_cmd = 0; |
| 1467 | adb_state = ADB_STATE_IDLE; |
| 1468 | adb_direction = 0; |
| 1469 | adb_datasize = 0; |
| 1164 | 1470 | |
| 1471 | // mouse |
| 1472 | adb_mouseaddr = 3; |
| 1473 | adb_lastmousex = adb_lastmousey = 0; |
| 1474 | } |
| 1165 | 1475 | |
| 1166 | 1476 | /* ************************************************************************* |
| 1167 | 1477 | * VIA |
| r3084 | r3085 | |
| 1209 | 1519 | |
| 1210 | 1520 | if (has_adb()) |
| 1211 | 1521 | { |
| 1212 | | if (adb_via_b3) |
| 1522 | val |= adb_state<<4; |
| 1523 | |
| 1524 | if (!adb_irq_pending) |
| 1525 | { |
| 1213 | 1526 | val |= 0x08; |
| 1527 | } |
| 1214 | 1528 | } |
| 1215 | 1529 | else |
| 1216 | 1530 | { |
| r3084 | r3085 | |
| 1232 | 1546 | set_scc_waitrequest((data & 0x80) >> 7); |
| 1233 | 1547 | mac_set_screen_buffer((data & 0x40) >> 6); |
| 1234 | 1548 | sony_set_sel_line((data & 0x20) >> 5); |
| 1235 | | mac_set_sound_buffer((data & 0x08) >> 3); |
| 1549 | if (mac_model == MODEL_MAC_SE) // on SE this selects which floppy drive (0 = upper, 1 = lower) |
| 1550 | { |
| 1551 | mac_drive_select = ((data & 0x10) >> 4); |
| 1552 | } |
| 1553 | |
| 1554 | if (mac_model < MODEL_MAC_SE) // SE no longer has dual buffers |
| 1555 | { |
| 1556 | mac_set_sound_buffer((data & 0x08) >> 3); |
| 1557 | } |
| 1236 | 1558 | mac_set_volume(data & 0x07); |
| 1237 | 1559 | |
| 1238 | 1560 | /* Early Mac models had VIA A4 control overlaying. In the Mac SE (and |
| r3084 | r3085 | |
| 1254 | 1576 | rtc_rTCClk = new_rtc_rTCClk; |
| 1255 | 1577 | |
| 1256 | 1578 | if (has_adb()) |
| 1579 | { |
| 1257 | 1580 | mac_adb_newaction((data & 0x30) >> 4); |
| 1581 | } |
| 1258 | 1582 | } |
| 1259 | 1583 | |
| 1260 | 1584 | static void mac_via_irq(running_machine *machine, int state) |
| r3084 | r3085 | |
| 1318 | 1642 | /* setup sound */ |
| 1319 | 1643 | mac_set_sound_buffer(0); |
| 1320 | 1644 | |
| 1645 | if (has_adb()) |
| 1646 | { |
| 1647 | adb_reset(); |
| 1648 | |
| 1649 | mac_adb_timer = timer_alloc(mac_adb_tick, NULL); |
| 1650 | timer_adjust_oneshot(mac_adb_timer, attotime_never, 0); |
| 1651 | } |
| 1652 | |
| 1321 | 1653 | if (mac_model == MODEL_MAC_SE) |
| 1654 | { |
| 1322 | 1655 | timer_set(attotime_zero, NULL, 0, set_memory_overlay_callback); |
| 1656 | } |
| 1323 | 1657 | |
| 1324 | 1658 | mac_scanline_timer = timer_alloc(mac_scanline_tick, NULL); |
| 1325 | 1659 | timer_adjust_oneshot(mac_scanline_timer, video_screen_get_time_until_pos(machine->primary_screen, 0, 0), 0); |
| r3084 | r3085 | |
| 1351 | 1685 | set_memory_overlay(machine, 1); |
| 1352 | 1686 | |
| 1353 | 1687 | /* configure via */ |
| 1354 | | via_config(0, &mac_via6522_intf); |
| 1688 | if (has_adb()) |
| 1689 | { |
| 1690 | via_config(0, &mac_via6522_adb_intf); |
| 1691 | } |
| 1692 | else |
| 1693 | { |
| 1694 | via_config(0, &mac_via6522_intf); |
| 1695 | } |
| 1355 | 1696 | via_set_clock(0, 1000000); /* 6522 = 1 Mhz, 6522a = 2 Mhz */ |
| 1356 | 1697 | |
| 1357 | 1698 | /* setup keyboard */ |