src/mess/machine/apollo_kbd.c
| r0 | r14540 | |
| 1 | /* |
| 2 | * apollo_kbd.c - Apollo keyboard and mouse emulation |
| 3 | * |
| 4 | * Created on: Dec 27, 2010 |
| 5 | * Author: Hans Ostermeyer |
| 6 | * |
| 7 | * Released for general non-commercial use under the MAME license |
| 8 | * Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | * |
| 10 | * see also http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf |
| 11 | * |
| 12 | */ |
| 13 | |
| 14 | #define VERBOSE 0 |
| 15 | |
| 16 | #include "machine/apollo_kbd.h" |
| 17 | #include "sound/beep.h" |
| 18 | |
| 19 | #include <unistd.h> |
| 20 | #include <fcntl.h> |
| 21 | #include <errno.h> |
| 22 | |
| 23 | #if defined(__linux__) |
| 24 | // on linux we may attach a real Apollo keyboard at /dev/ttyS0 |
| 25 | #include <termios.h> |
| 26 | #include <sys/ioctl.h> |
| 27 | #define KBD_TTY_NAME "/dev/ttyS0" |
| 28 | #endif |
| 29 | |
| 30 | #define LOG(x) { logerror ("%s apollo_kbd: ", m_device->cpu_context()); logerror x; logerror ("\n"); } |
| 31 | #define LOG1(x) { if (VERBOSE > 0) LOG(x)} |
| 32 | #define LOG2(x) { if (VERBOSE > 1) LOG(x)} |
| 33 | |
| 34 | #define MAP_APOLLO_KEYS 1 |
| 35 | |
| 36 | //************************************************************************** |
| 37 | // DEVICE DEFINITIONS |
| 38 | //************************************************************************** |
| 39 | |
| 40 | //const device_type APOLLO_KBD = apollo_kbd_device_config::static_alloc_device_config; |
| 41 | |
| 42 | //************************************************************************** |
| 43 | // CONSTANTS |
| 44 | //************************************************************************** |
| 45 | |
| 46 | #define KBD_MODE_0_COMPATIBILITY 0 |
| 47 | #define KBD_MODE_1_KEYSTATE 1 |
| 48 | #define KBD_MODE_2_RELATIVE_CURSOR_CONTROL 2 |
| 49 | #define KBD_MODE_3_ABSOLUTE_CURSOR_CONTROL 3 |
| 50 | |
| 51 | #define CODE_TABLE_DOWN_CODE 0 |
| 52 | #define CODE_TABLE_UP_CODE 1 |
| 53 | #define CODE_TABLE_UNSHIFTED_CODE 2 |
| 54 | #define CODE_TABLE_SHIFTED_CODE 3 |
| 55 | #define CODE_TABLE_CONTROL_CODE 4 |
| 56 | #define CODE_TABLE_CAPS_LOCK_CODE 5 |
| 57 | #define CODE_TABLE_UP_TRANS_CODE 6 |
| 58 | #define CODE_TABLE_AUTO_REPEAT_CODE 7 |
| 59 | #define CODE_TABLE_ENTRY_SIZE 8 |
| 60 | |
| 61 | #define NOP 0 |
| 62 | #define No 0 |
| 63 | #define Yes 1 |
| 64 | |
| 65 | /*************************************************************************** |
| 66 | IMPLEMENTATION |
| 67 | ***************************************************************************/ |
| 68 | |
| 69 | // device type definition |
| 70 | const device_type APOLLO_KBD = &device_creator<apollo_kbd_device>; |
| 71 | |
| 72 | //------------------------------------------------- |
| 73 | // apollo_kbd_device - constructor |
| 74 | //------------------------------------------------- |
| 75 | |
| 76 | apollo_kbd_device::apollo_kbd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 77 | : device_t(mconfig, APOLLO_KBD, "Apollo Keyboard", tag, owner, clock) |
| 78 | { |
| 79 | memset(static_cast<apollo_kbd_interface *>(this), 0, sizeof(apollo_kbd_interface)); |
| 80 | } |
| 81 | |
| 82 | //------------------------------------------------- |
| 83 | // static_set_interface - set the interface struct |
| 84 | //------------------------------------------------- |
| 85 | |
| 86 | void apollo_kbd_device::static_set_interface(device_t &device, const apollo_kbd_interface &interface) |
| 87 | { |
| 88 | apollo_kbd_device &kbd = downcast<apollo_kbd_device &>(device); |
| 89 | |
| 90 | static_cast<apollo_kbd_interface &>(kbd) = interface; |
| 91 | } |
| 92 | |
| 93 | //------------------------------------------------- |
| 94 | // device_start - device-specific startup |
| 95 | //------------------------------------------------- |
| 96 | |
| 97 | void apollo_kbd_device::device_start() |
| 98 | { |
| 99 | m_device = this; |
| 100 | LOG1(("start apollo_kbd")); |
| 101 | |
| 102 | m_beeper.start(this); |
| 103 | m_mouse.start(this); |
| 104 | m_tx_fifo.start(this); |
| 105 | m_keyboard_tty.start(this); |
| 106 | |
| 107 | m_timer = machine().scheduler().timer_alloc(FUNC(static_poll_callback), this); |
| 108 | } |
| 109 | |
| 110 | //------------------------------------------------- |
| 111 | // device_reset - device-specific reset |
| 112 | //------------------------------------------------- |
| 113 | |
| 114 | void apollo_kbd_device::device_reset() |
| 115 | { |
| 116 | LOG1(("reset apollo_kbd")); |
| 117 | |
| 118 | m_beeper.reset(); |
| 119 | m_mouse.reset(); |
| 120 | m_tx_fifo.reset(); |
| 121 | m_keyboard_tty.reset(); |
| 122 | |
| 123 | // init keyboard |
| 124 | m_loopback_mode = 1; |
| 125 | m_mode = KBD_MODE_0_COMPATIBILITY; |
| 126 | m_delay = 500; |
| 127 | m_repeat = 33; |
| 128 | m_last_pressed = 0; |
| 129 | memset(m_keytime, 0, sizeof(m_keytime)); |
| 130 | memset(m_keyon, 0, sizeof(m_keyon)); |
| 131 | |
| 132 | // start timer |
| 133 | m_timer->adjust( attotime::zero, 0, attotime::from_msec(5)); // every 5ms |
| 134 | } |
| 135 | |
| 136 | /*************************************************************************** |
| 137 | cpu_context - return a string describing the current CPU context |
| 138 | ***************************************************************************/ |
| 139 | |
| 140 | const char *apollo_kbd_device::cpu_context() |
| 141 | { |
| 142 | static char statebuf[64]; /* string buffer containing state description */ |
| 143 | |
| 144 | device_t *cpu = machine().firstcpu; |
| 145 | osd_ticks_t t = osd_ticks(); |
| 146 | int s = t / osd_ticks_per_second(); |
| 147 | int ms = (t % osd_ticks_per_second()) / 1000; |
| 148 | |
| 149 | /* if we have an executing CPU, output data */ |
| 150 | if (cpu != NULL) |
| 151 | { |
| 152 | sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(), |
| 153 | cpu_get_previouspc(cpu), tag()); |
| 154 | } |
| 155 | else |
| 156 | { |
| 157 | sprintf(statebuf, "%d.%03d", s, ms); |
| 158 | } |
| 159 | return statebuf; |
| 160 | } |
| 161 | |
| 162 | //************************************************************************** |
| 163 | // Beeper |
| 164 | //************************************************************************** |
| 165 | |
| 166 | apollo_kbd_device::beeper::beeper() : |
| 167 | m_device(NULL), |
| 168 | m_beeper(NULL), |
| 169 | m_timer(NULL) |
| 170 | { |
| 171 | } |
| 172 | |
| 173 | void apollo_kbd_device::beeper::start(apollo_kbd_device *device) |
| 174 | { |
| 175 | m_device = device; |
| 176 | LOG2(("start apollo_kbd::beeper")); |
| 177 | m_beeper = m_device->machine().device("beep"); |
| 178 | m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_beeper_callback), this); |
| 179 | } |
| 180 | |
| 181 | void apollo_kbd_device::beeper::reset() |
| 182 | { |
| 183 | LOG2(("reset apollo_kbd::beeper")); |
| 184 | on(); |
| 185 | } |
| 186 | |
| 187 | void apollo_kbd_device::beeper::off() |
| 188 | { |
| 189 | beep_set_state(m_beeper, 0); |
| 190 | } |
| 191 | |
| 192 | void apollo_kbd_device::beeper::on() |
| 193 | { |
| 194 | if (keyboard_has_beeper()) |
| 195 | { |
| 196 | beep_set_frequency(m_beeper, 1000); |
| 197 | beep_set_state(m_beeper, 1); |
| 198 | m_timer->adjust( attotime::from_msec(10), 0, attotime::zero); |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | int apollo_kbd_device::beeper::keyboard_has_beeper() |
| 203 | { |
| 204 | return m_device->apollo_kbd_has_beeper ? |
| 205 | (m_device->apollo_kbd_has_beeper)(m_device, 0) : 0; |
| 206 | } |
| 207 | |
| 208 | void apollo_kbd_device::beeper::beeper_callback() |
| 209 | { |
| 210 | off(); |
| 211 | } |
| 212 | |
| 213 | TIMER_CALLBACK( apollo_kbd_device::beeper::static_beeper_callback ) |
| 214 | { |
| 215 | reinterpret_cast<beeper *> (ptr)->beeper_callback(); |
| 216 | } |
| 217 | |
| 218 | //************************************************************************** |
| 219 | // Mouse |
| 220 | //************************************************************************** |
| 221 | |
| 222 | apollo_kbd_device::mouse::mouse() : |
| 223 | m_device(NULL) |
| 224 | { |
| 225 | } |
| 226 | |
| 227 | void apollo_kbd_device::mouse::start(apollo_kbd_device *device) |
| 228 | { |
| 229 | m_device = device; |
| 230 | LOG2(("start apollo_kbd::mouse")); |
| 231 | } |
| 232 | |
| 233 | void apollo_kbd_device::mouse::reset() |
| 234 | { |
| 235 | LOG2(("reset apollo_kbd::mouse")); |
| 236 | |
| 237 | m_last_b = -1; |
| 238 | m_last_x = 0; |
| 239 | m_last_y = 0; |
| 240 | m_tx_pending = 0; |
| 241 | } |
| 242 | |
| 243 | void apollo_kbd_device::mouse::read_mouse() |
| 244 | { |
| 245 | if (m_tx_pending > 0) |
| 246 | { |
| 247 | m_tx_pending -= 5; |
| 248 | } |
| 249 | else |
| 250 | { |
| 251 | int b = input_port_read(m_device->machine(), "mouse1"); |
| 252 | int x = input_port_read(m_device->machine(), "mouse2"); |
| 253 | int y = input_port_read(m_device->machine(), "mouse3"); |
| 254 | |
| 255 | if (m_last_b < 0) |
| 256 | { |
| 257 | m_last_b = b; |
| 258 | m_last_x = x; |
| 259 | m_last_y = y; |
| 260 | } |
| 261 | else if (b != m_last_b || x != m_last_x || y != m_last_y) |
| 262 | { |
| 263 | int dx = x - m_last_x; |
| 264 | int dy = y - m_last_y; |
| 265 | UINT8 mouse_data[4]; |
| 266 | int mouse_data_size; |
| 267 | |
| 268 | LOG2(("read_mouse: b=%02x x=%04x y=%04x dx=%d dy=%d", b, x, y, dx, dy)); |
| 269 | |
| 270 | if (m_device->m_mode == KBD_MODE_0_COMPATIBILITY) |
| 271 | { |
| 272 | mouse_data[0] = 0xdf; |
| 273 | mouse_data[1] = 0xf0 ^ b; |
| 274 | mouse_data[2] = dx; |
| 275 | mouse_data[3] = -dy; |
| 276 | mouse_data_size = 4; |
| 277 | } |
| 278 | else |
| 279 | { |
| 280 | if (m_device->m_mode != KBD_MODE_2_RELATIVE_CURSOR_CONTROL) |
| 281 | { |
| 282 | m_device->set_mode(KBD_MODE_2_RELATIVE_CURSOR_CONTROL); |
| 283 | } |
| 284 | |
| 285 | mouse_data[0] = 0xf0 ^ b; |
| 286 | mouse_data[1] = dx; |
| 287 | mouse_data[2] = -dy; |
| 288 | mouse_data_size = 3; |
| 289 | } |
| 290 | |
| 291 | if (m_device->m_tx_fifo.putdata(mouse_data, mouse_data_size)) |
| 292 | { |
| 293 | // mouse data submitted; update current mouse state |
| 294 | m_last_b = b; |
| 295 | m_last_x = x; |
| 296 | m_last_y = y; |
| 297 | } |
| 298 | m_tx_pending = 100; // mouse data packet will take 50 ms |
| 299 | } |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | //************************************************************************** |
| 304 | // tx fifo |
| 305 | //************************************************************************** |
| 306 | |
| 307 | apollo_kbd_device::tx_fifo::tx_fifo() : |
| 308 | m_device(NULL), |
| 309 | m_timer(NULL) |
| 310 | { |
| 311 | } |
| 312 | |
| 313 | void apollo_kbd_device::tx_fifo::start(apollo_kbd_device *device) |
| 314 | { |
| 315 | m_device = device; |
| 316 | LOG2(("start apollo_kbd::tx_fifo")); |
| 317 | m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_callback), this); |
| 318 | } |
| 319 | |
| 320 | void apollo_kbd_device::tx_fifo::reset() |
| 321 | { |
| 322 | LOG2(("reset apollo_kbd::tx_fifo")); |
| 323 | |
| 324 | memset(fifo, 0, sizeof(fifo)); |
| 325 | m_read_ptr = 0; |
| 326 | m_write_ptr = 0; |
| 327 | m_char_count = 0; |
| 328 | m_tx_pending = 0; |
| 329 | m_baud_rate = 1200; |
| 330 | |
| 331 | // reset timer |
| 332 | m_timer->adjust(attotime::never, 0); |
| 333 | } |
| 334 | |
| 335 | UINT8 apollo_kbd_device::tx_fifo::getchar() |
| 336 | { |
| 337 | UINT8 data; |
| 338 | |
| 339 | if (m_char_count == 0) |
| 340 | { |
| 341 | LOG(("apollo_kbd FIFO underflow")); |
| 342 | data = 0x0; |
| 343 | } |
| 344 | else |
| 345 | { |
| 346 | data = fifo[m_read_ptr++]; |
| 347 | if (m_read_ptr == TX_FIFO_SIZE) |
| 348 | { |
| 349 | m_read_ptr = 0; |
| 350 | } |
| 351 | m_char_count--; |
| 352 | } |
| 353 | return data; |
| 354 | } |
| 355 | |
| 356 | void apollo_kbd_device::tx_fifo::putchar(UINT8 data) |
| 357 | { |
| 358 | if (m_char_count >= TX_FIFO_SIZE) |
| 359 | { |
| 360 | LOG(("apollo_kbd FIFO overflow")); |
| 361 | } |
| 362 | else |
| 363 | { |
| 364 | fifo[m_write_ptr++] = data; |
| 365 | if (m_write_ptr == TX_FIFO_SIZE) |
| 366 | { |
| 367 | m_write_ptr = 0; |
| 368 | } |
| 369 | m_char_count++; |
| 370 | if ( m_tx_pending == 0) |
| 371 | { |
| 372 | flush(); |
| 373 | } |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | int apollo_kbd_device::tx_fifo::putdata(const UINT8 *data, int data_length) |
| 378 | { |
| 379 | if (m_char_count + data_length >= TX_FIFO_SIZE-5) |
| 380 | { |
| 381 | // tx fifo is full |
| 382 | return 0; |
| 383 | } |
| 384 | else |
| 385 | { |
| 386 | while (data_length-- > 0) { |
| 387 | putchar(*data++); |
| 388 | } |
| 389 | return 1; |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | void apollo_kbd_device::tx_fifo::flush() |
| 394 | { |
| 395 | if (m_char_count > 0) |
| 396 | { |
| 397 | m_tx_pending = 1; |
| 398 | |
| 399 | if (m_device->apollo_kbd_putchar) |
| 400 | (m_device->apollo_kbd_putchar)(m_device, 0, getchar()); |
| 401 | // 11 = one start, 8 data, one parity (even), one stop bit |
| 402 | m_timer->adjust(attotime::from_hz(m_baud_rate / 11), 0); |
| 403 | } |
| 404 | else |
| 405 | { |
| 406 | m_tx_pending = 0; |
| 407 | // m_timer->adjust(attotime::never, 0); |
| 408 | } |
| 409 | } |
| 410 | |
| 411 | void apollo_kbd_device::tx_fifo::timer_callback() |
| 412 | { |
| 413 | flush(); |
| 414 | } |
| 415 | |
| 416 | TIMER_CALLBACK( apollo_kbd_device::tx_fifo::static_timer_callback ) |
| 417 | { |
| 418 | reinterpret_cast<apollo_kbd_device::tx_fifo *> (ptr)->timer_callback(); |
| 419 | } |
| 420 | |
| 421 | //************************************************************************** |
| 422 | // Real Apollo keyboard connected at the keyboard tty (i.e. /dev/ttyS0) |
| 423 | //************************************************************************** |
| 424 | |
| 425 | apollo_kbd_device::keyboard_tty::keyboard_tty() : |
| 426 | m_device(NULL), |
| 427 | m_tty_name(NULL), |
| 428 | m_tty_fd(-1), |
| 429 | m_connected(0) |
| 430 | { |
| 431 | } |
| 432 | |
| 433 | void apollo_kbd_device::keyboard_tty::start(apollo_kbd_device *device) |
| 434 | { |
| 435 | m_device = device; |
| 436 | LOG2(("start apollo_kbd::keyboard_tty")); |
| 437 | #if defined(KBD_TTY_NAME) |
| 438 | m_tty_name = KBD_TTY_NAME; |
| 439 | #endif |
| 440 | } |
| 441 | |
| 442 | void apollo_kbd_device::keyboard_tty::reset() |
| 443 | { |
| 444 | LOG2(("reset apollo_kbd::keyboard_tty")); |
| 445 | |
| 446 | m_connected = 0; |
| 447 | |
| 448 | #if defined(KBD_TTY_NAME) |
| 449 | /* Open the tty line */ |
| 450 | m_tty_fd = open(m_tty_name, 2); |
| 451 | if (m_tty_fd < 0) |
| 452 | { |
| 453 | LOG1(("failed to open %s", m_tty_name)); |
| 454 | } |
| 455 | else |
| 456 | { |
| 457 | int serial; |
| 458 | struct termios tty_mode; |
| 459 | |
| 460 | // set nonblocking mode |
| 461 | fcntl(m_tty_fd, F_SETFL, fcntl(m_tty_fd, F_GETFL) | O_NONBLOCK); |
| 462 | |
| 463 | tcgetattr(m_tty_fd, &tty_mode); |
| 464 | tty_mode.c_iflag = INPCK; |
| 465 | tty_mode.c_oflag = 0; |
| 466 | tty_mode.c_cflag = B1200 | CS8 | CREAD | HUPCL | PARENB | CLOCAL; |
| 467 | tty_mode.c_lflag = 0; |
| 468 | tty_mode.c_cc[VTIME] = 0; |
| 469 | tty_mode.c_cc[VMIN] = 1; |
| 470 | tcsetattr(m_tty_fd, TCSANOW, &tty_mode); |
| 471 | |
| 472 | ioctl(m_tty_fd, TIOCMGET, &serial); |
| 473 | |
| 474 | if ((serial & TIOCM_RTS) && !(serial & TIOCM_CTS)) |
| 475 | { |
| 476 | // Apollo keyboard not connected |
| 477 | close(m_tty_fd); |
| 478 | m_tty_fd = -1; |
| 479 | m_connected = 0; |
| 480 | } |
| 481 | else |
| 482 | { |
| 483 | LOG1(("opened %s with RTS=%d CTS=%d", m_tty_name, |
| 484 | serial & TIOCM_RTS ? 1 : 0, serial & TIOCM_CTS ? 1 : 0 )); |
| 485 | } |
| 486 | } |
| 487 | #endif |
| 488 | } |
| 489 | |
| 490 | int apollo_kbd_device::keyboard_tty::isConnected() |
| 491 | { |
| 492 | return m_connected; |
| 493 | } |
| 494 | |
| 495 | int apollo_kbd_device::keyboard_tty::getchar() |
| 496 | { |
| 497 | UINT8 data; |
| 498 | if (m_tty_fd < 0 || read(m_tty_fd, &data, 1) != 1) { |
| 499 | return -1; |
| 500 | } else { |
| 501 | LOG2(("keyboard_tty::getchar <---- %02x", data)) |
| 502 | m_connected = 1; |
| 503 | return data; |
| 504 | } |
| 505 | } |
| 506 | |
| 507 | void apollo_kbd_device::keyboard_tty::putchar(UINT8 data) |
| 508 | { |
| 509 | if (isConnected() && m_tty_fd >= 0 ) { |
| 510 | while (write(m_tty_fd, &data, 1) != 1) { |
| 511 | LOG(("keyboard_tty::putchar data=%02x errno=%d", data, errno )); |
| 512 | } |
| 513 | LOG2(("keyboard_tty::putchar -> %02x", data)); |
| 514 | } |
| 515 | } |
| 516 | |
| 517 | /*------------------------------------------------- |
| 518 | keyboard_is_german - check for german keyboard |
| 519 | -------------------------------------------------*/ |
| 520 | |
| 521 | int apollo_kbd_device::keyboard_is_german() |
| 522 | { |
| 523 | return apollo_kbd_is_german ? |
| 524 | (*apollo_kbd_is_german)(this, 0) : 0; |
| 525 | } |
| 526 | |
| 527 | /*------------------------------------------------- |
| 528 | putchar - put keyboard char to sio |
| 529 | -------------------------------------------------*/ |
| 530 | |
| 531 | void apollo_kbd_device::set_mode(UINT16 mode) |
| 532 | { |
| 533 | putchar(0xff); |
| 534 | putchar(mode); |
| 535 | m_mode = mode; |
| 536 | } |
| 537 | |
| 538 | /*------------------------------------------------- |
| 539 | putchar - put keyboard char to sio |
| 540 | -------------------------------------------------*/ |
| 541 | |
| 542 | void apollo_kbd_device::putchar(const UINT8 data) |
| 543 | { |
| 544 | LOG1(("putchar(%d) -> %02x", m_mode, data)); |
| 545 | m_tx_fifo.putchar(data); |
| 546 | } |
| 547 | |
| 548 | /*------------------------------------------------- |
| 549 | putdata - put keyboard data to sio |
| 550 | -------------------------------------------------*/ |
| 551 | |
| 552 | void apollo_kbd_device::putdata(const UINT8 *data, int data_length) |
| 553 | { |
| 554 | // send data only if no real Apollo keyboard has been connected |
| 555 | if (!m_keyboard_tty.isConnected()) |
| 556 | { |
| 557 | if (m_mode > KBD_MODE_1_KEYSTATE) |
| 558 | { |
| 559 | set_mode(KBD_MODE_1_KEYSTATE); |
| 560 | } |
| 561 | m_tx_fifo.putdata(data, data_length); |
| 562 | } |
| 563 | } |
| 564 | |
| 565 | /*------------------------------------------------- |
| 566 | putstring - put keyboard string to sio |
| 567 | -------------------------------------------------*/ |
| 568 | |
| 569 | void apollo_kbd_device::putstring(const char *data) |
| 570 | { |
| 571 | putdata((UINT8 *) data, strlen(data)); |
| 572 | } |
| 573 | |
| 574 | /*------------------------------------------------- |
| 575 | apollo_kbd_getchar - get char from sio line |
| 576 | -------------------------------------------------*/ |
| 577 | |
| 578 | void apollo_kbd_getchar(device_t *device, UINT8 data) |
| 579 | { |
| 580 | downcast<apollo_kbd_device *> (device)->getchar(data); |
| 581 | } |
| 582 | |
| 583 | void apollo_kbd_device::getchar(UINT8 data) |
| 584 | { |
| 585 | static const UINT8 ff1116_data[] = { 0x00, 0xff, 0x00 }; |
| 586 | |
| 587 | LOG1(("getchar <- %02x", data)); |
| 588 | |
| 589 | if (m_keyboard_tty.isConnected()) |
| 590 | { |
| 591 | m_keyboard_tty.putchar(data); |
| 592 | } |
| 593 | |
| 594 | if (data == 0xff) |
| 595 | { |
| 596 | m_rx_message = data; |
| 597 | putdata(&data, 1); |
| 598 | m_loopback_mode = 1; |
| 599 | } |
| 600 | else if (data == 0x00) |
| 601 | { |
| 602 | if (m_loopback_mode) |
| 603 | { |
| 604 | set_mode(KBD_MODE_0_COMPATIBILITY); |
| 605 | m_loopback_mode = 0; |
| 606 | } |
| 607 | } |
| 608 | else |
| 609 | { |
| 610 | m_rx_message = m_rx_message << 8 | data; |
| 611 | |
| 612 | switch (m_rx_message) |
| 613 | { |
| 614 | case 0xff00: |
| 615 | putdata(&data, 1); |
| 616 | m_mode = KBD_MODE_0_COMPATIBILITY; |
| 617 | m_loopback_mode = 0; |
| 618 | m_rx_message = 0; |
| 619 | case 0xff01: |
| 620 | putdata(&data, 1); |
| 621 | m_mode = KBD_MODE_1_KEYSTATE; |
| 622 | m_rx_message = 0; |
| 623 | break; |
| 624 | case 0xff11: |
| 625 | putdata(&data, 1); |
| 626 | break; |
| 627 | case 0xff1116: |
| 628 | putdata(ff1116_data, sizeof(ff1116_data)); |
| 629 | m_loopback_mode = 0; |
| 630 | m_rx_message = 0; |
| 631 | break; |
| 632 | case 0xff1117: |
| 633 | m_rx_message = 0; |
| 634 | break; |
| 635 | case 0xff12: |
| 636 | putdata(&data, 1); |
| 637 | break; |
| 638 | case 0xff1221: // receive ID message |
| 639 | m_loopback_mode = 0; |
| 640 | putdata(&data, 1); |
| 641 | if (keyboard_is_german()) |
| 642 | { |
| 643 | putstring("3-A\r2-0\rSD-03863-MS\r"); |
| 644 | } |
| 645 | else |
| 646 | { |
| 647 | putstring("3-@\r2-0\rSD-03863-MS\r"); |
| 648 | } |
| 649 | |
| 650 | if (m_mode == KBD_MODE_0_COMPATIBILITY) |
| 651 | { |
| 652 | set_mode(KBD_MODE_0_COMPATIBILITY); |
| 653 | } |
| 654 | else |
| 655 | { |
| 656 | set_mode(KBD_MODE_1_KEYSTATE); |
| 657 | } |
| 658 | m_rx_message = 0; |
| 659 | break; |
| 660 | case 0xff2181: // beeper on (for 300 ms) |
| 661 | putdata(&data, 1); |
| 662 | m_rx_message = 0; |
| 663 | m_beeper.on(); |
| 664 | break; |
| 665 | case 0xff2182: // beeper off |
| 666 | putdata(&data, 1); |
| 667 | m_rx_message = 0; |
| 668 | m_beeper.off(); |
| 669 | break; |
| 670 | default: |
| 671 | if (m_loopback_mode && data != 0) |
| 672 | { |
| 673 | putdata(&data, 1); |
| 674 | } |
| 675 | break; |
| 676 | } |
| 677 | } |
| 678 | } |
| 679 | |
| 680 | int apollo_kbd_device::push_scancode(UINT8 code, UINT8 repeat) |
| 681 | { |
| 682 | int n_chars = 0; |
| 683 | UINT16 key_code = 0; |
| 684 | UINT8 caps = BIT(input_port_read(machine(), "keyboard4"),0); |
| 685 | UINT8 shift = BIT(input_port_read(machine(), "keyboard4"),1) | BIT(input_port_read(machine(), "keyboard4"),5); |
| 686 | UINT8 ctrl = BIT(input_port_read(machine(), "keyboard4"),2); |
| 687 | UINT8 numlock = BIT(input_port_read(machine(), "keyboard4"),6); |
| 688 | UINT16 index; |
| 689 | |
| 690 | if (keyboard_is_german()) |
| 691 | { |
| 692 | // map special keys for German keyboard |
| 693 | switch (code) |
| 694 | { |
| 695 | case 0x00: code = 0x68; break; // _ |
| 696 | case 0x0e: code = 0x6b; break; // # |
| 697 | case 0x29: code = 0x69; break; // <> |
| 698 | case 0x42: code = 0x6f; break; // NP- |
| 699 | case 0x46: code = 0x6e; break; // NP+ |
| 700 | case 0x4e: code = 0x73; break; // NP ENTER |
| 701 | } |
| 702 | } |
| 703 | |
| 704 | #if MAP_APOLLO_KEYS |
| 705 | if (numlock) |
| 706 | { |
| 707 | // don't map function keys to Apollo left keypad |
| 708 | switch (code) |
| 709 | { |
| 710 | case 0x52: code = 0x75; break; // F1 |
| 711 | case 0x53: code = 0x76; break; // F2 |
| 712 | case 0x54: code = 0x77; break; // F3 |
| 713 | case 0x55: code = 0x78; break; // F4 |
| 714 | case 0x56: code = 0x79; break; // F5 |
| 715 | case 0x57: code = 0x7a; break; // F6 |
| 716 | case 0x58: code = 0x7b; break; // F7 |
| 717 | case 0x59: code = 0x7c; break; // F8 |
| 718 | case 0x5a: code = 0x7d; break; // F9 |
| 719 | case 0x5b: code = 0x74; break; // F0 = F10 |
| 720 | } |
| 721 | } |
| 722 | #endif |
| 723 | |
| 724 | index = (code & 0x7f) * CODE_TABLE_ENTRY_SIZE; |
| 725 | if (m_mode == KBD_MODE_0_COMPATIBILITY) |
| 726 | { |
| 727 | if (code & 0x80) |
| 728 | { |
| 729 | // skip up code in ASCII mode |
| 730 | } |
| 731 | else if (repeat > 0 |
| 732 | && m_code_table[index + CODE_TABLE_AUTO_REPEAT_CODE] != Yes) |
| 733 | { |
| 734 | // skip repeat in ASCII mode |
| 735 | } |
| 736 | else if (ctrl) |
| 737 | { |
| 738 | key_code = m_code_table[index + CODE_TABLE_CONTROL_CODE]; |
| 739 | } |
| 740 | else if (shift) |
| 741 | { |
| 742 | key_code = m_code_table[index + CODE_TABLE_SHIFTED_CODE]; |
| 743 | } |
| 744 | else if (caps) |
| 745 | { |
| 746 | key_code = m_code_table[index + CODE_TABLE_CAPS_LOCK_CODE]; |
| 747 | } |
| 748 | else |
| 749 | { |
| 750 | key_code = m_code_table[index + CODE_TABLE_UNSHIFTED_CODE]; |
| 751 | } |
| 752 | } |
| 753 | else |
| 754 | { |
| 755 | if (repeat > 0) |
| 756 | { |
| 757 | if (repeat == 1) |
| 758 | { |
| 759 | // auto repeat (but only for first scanned key) |
| 760 | key_code = 0x7f; |
| 761 | } |
| 762 | } |
| 763 | else if (code & 0x80) |
| 764 | { |
| 765 | key_code = m_code_table[index + CODE_TABLE_UP_CODE]; |
| 766 | } |
| 767 | else |
| 768 | { |
| 769 | key_code = m_code_table[index + CODE_TABLE_DOWN_CODE]; |
| 770 | } |
| 771 | } |
| 772 | |
| 773 | if (key_code != 0) |
| 774 | { |
| 775 | LOG2(("scan_code = 0x%02x key_code = 0x%04x",code, key_code)); |
| 776 | if (m_mode > KBD_MODE_1_KEYSTATE) |
| 777 | { |
| 778 | set_mode(KBD_MODE_1_KEYSTATE); |
| 779 | } |
| 780 | |
| 781 | if (key_code & 0xff00) |
| 782 | { |
| 783 | putchar(key_code >> 8); |
| 784 | n_chars++; |
| 785 | } |
| 786 | putchar(key_code & 0xff); |
| 787 | n_chars++; |
| 788 | } |
| 789 | return n_chars; |
| 790 | } |
| 791 | |
| 792 | void apollo_kbd_device::scan_keyboard() |
| 793 | { |
| 794 | int x; |
| 795 | int repeat = 0; |
| 796 | |
| 797 | static const char * const keynames[] = { "keyboard1", "keyboard2", "keyboard3", "keyboard4" }; |
| 798 | |
| 799 | for (x = 0; x < 0x80; x++) |
| 800 | { |
| 801 | if (!(input_port_read(machine(), keynames[x / 32]) & (1 << (x % 32)))) |
| 802 | { |
| 803 | // no key pressed |
| 804 | if (m_keyon[x] != 0) |
| 805 | { |
| 806 | // a key has been released |
| 807 | push_scancode(0x80 + x, 0); |
| 808 | m_keytime[x] = 0; |
| 809 | m_keyon[x] = 0; |
| 810 | m_last_pressed = 0; |
| 811 | LOG2(("released key 0x%02x at time %d",x, m_keytime[x])); |
| 812 | } |
| 813 | } |
| 814 | else if (m_keyon[x] == 0) |
| 815 | { |
| 816 | // a key has been pressed |
| 817 | if (push_scancode(x, 0) > 0) |
| 818 | { |
| 819 | m_keytime[x] = m_mode == KBD_MODE_0_COMPATIBILITY ? m_delay : m_repeat; |
| 820 | m_keyon[x] = 1; |
| 821 | m_last_pressed = x; |
| 822 | LOG2(("pushed key 0x%02x at time %d",x, m_keytime[x])); |
| 823 | } |
| 824 | } |
| 825 | else if (m_last_pressed == x) |
| 826 | { |
| 827 | // a key is being held; adjust delay/repeat timers |
| 828 | m_keytime[x] -= 5; |
| 829 | if (m_keytime[x] <= 0) |
| 830 | { |
| 831 | push_scancode(x, ++repeat); |
| 832 | m_keytime[x] = m_repeat; |
| 833 | } |
| 834 | LOG2(("holding key 0x%02x at time %d",x, m_keytime[x])); |
| 835 | } |
| 836 | } |
| 837 | } |
| 838 | |
| 839 | void apollo_kbd_device::poll_callback() |
| 840 | { |
| 841 | int data; |
| 842 | while ((data = m_keyboard_tty.getchar()) >= 0) |
| 843 | { |
| 844 | putchar(data); |
| 845 | } |
| 846 | scan_keyboard(); |
| 847 | |
| 848 | // Note: we omit extra traffic while keyboard is in Compatibitlit mode |
| 849 | if (m_device->m_mode != KBD_MODE_0_COMPATIBILITY) |
| 850 | { |
| 851 | m_mouse.read_mouse(); |
| 852 | } |
| 853 | } |
| 854 | |
| 855 | TIMER_CALLBACK( apollo_kbd_device::static_poll_callback ) |
| 856 | { |
| 857 | reinterpret_cast<apollo_kbd_device *> (ptr)->poll_callback(); |
| 858 | } |
| 859 | |
| 860 | UINT16 apollo_kbd_device::m_code_table[] = { |
| 861 | |
| 862 | /* Key | Keycap | Down | Up |Unshifted|Shifted|Control|Caps Lock|Up Trans|Auto */ |
| 863 | /* Number| Legend | Code | Code|Code | Code | Code |Code | Code |Repeat*/ |
| 864 | |
| 865 | /* B14 ~ ' / ESC */ 0x24, 0xA4, 0x60, 0x7E, 0x1E, 0x60, NOP, No, |
| 866 | /* B1 ESC */ 0x17, 0x97, 0x1B, 0x1B, NOP, 0x1B, NOP, No, |
| 867 | /* B2 ! 1 */ 0x18, 0x98, 0x31, 0x21, NOP, 0x31, NOP, No, |
| 868 | /* B3 @ 2 */ 0x19, 0x99, 0x32, 0x40, NOP, 0x32, NOP, No, |
| 869 | /* B4 # 3 */ 0x1A, 0x9A, 0x33, 0x23, NOP, 0x33, NOP, No, |
| 870 | /* B5 $ 4 */ 0x1B, 0x9B, 0x34, 0x24, NOP, 0x34, NOP, No, |
| 871 | /* B6 % 5 */ 0x1C, 0x9C, 0x35, 0x25, NOP, 0x35, NOP, No, |
| 872 | /* B7 ^ 6 */ 0x1D, 0x9D, 0x36, 0x5E, NOP, 0x36, NOP, No, |
| 873 | /* B8 & 7 */ 0x1E, 0x9E, 0x37, 0x26, NOP, 0x37, NOP, No, |
| 874 | /* B9 * 8 */ 0x1F, 0x9F, 0x38, 0x2A, NOP, 0x38, NOP, No, |
| 875 | /* B10 ( 9 */ 0x20, 0xA0, 0x39, 0x28, NOP, 0x39, NOP, No, |
| 876 | /* B11 ) 0 */ 0x21, 0xA1, 0x30, 0x29, NOP, 0x30, NOP, No, |
| 877 | /* B12 _ - */ 0x22, 0xA2, 0x2D, 0x5F, NOP, 0x2D, NOP, Yes, |
| 878 | /* B13 + = */ 0x23, 0xA3, 0x3D, 0x2B, NOP, 0x3D, NOP, Yes, |
| 879 | /* B14 ~ ' / BS */ 0x24, 0xA4, 0x60, 0x7E, 0x1E, 0x60, NOP, No, |
| 880 | /* B15 BACKSPACE */ 0x25, 0xA5, 0xDE, 0xDE, NOP, 0xDE, NOP, Yes, |
| 881 | |
| 882 | /* C1 TAB */ 0x2C, 0xAC, 0xCA, 0xDA, 0xFA, 0xCA, NOP, No, |
| 883 | /* C2 Q */ 0x2D, 0xAD, 0x71, 0x51, 0x11, 0x51, NOP, No, |
| 884 | /* C3 W */ 0x2E, 0xAE, 0x77, 0x57, 0x17, 0x57, NOP, No, |
| 885 | /* C4 E */ 0x2F, 0xAF, 0x65, 0x45, 0x05, 0x45, NOP, No, |
| 886 | /* C5 R */ 0x30, 0xB0, 0x72, 0x52, 0x12, 0x52, NOP, No, |
| 887 | /* C6 T */ 0x31, 0xB1, 0x74, 0x54, 0x14, 0x54, NOP, No, |
| 888 | /* C7 V */ 0x32, 0xB2, 0x79, 0x59, 0x19, 0x59, NOP, No, |
| 889 | /* C8 U */ 0x33, 0xB3, 0x75, 0x55, 0x15, 0x55, NOP, No, |
| 890 | /* C9 I */ 0x34, 0xB4, 0x69, 0x49, 0x09, 0x49, NOP, No, |
| 891 | /* C10 O */ 0x35, 0xB5, 0x6F, 0x4F, 0x0F, 0x4F, NOP, No, |
| 892 | /* C11 P */ 0x36, 0xB6, 0x70, 0x50, 0x10, 0x50, NOP, No, |
| 893 | /* C12 { [ / Ü */ 0x37, 0xB7, 0x7B, 0x5B, 0x1B, 0x7B, NOP, No, |
| 894 | /* C13 } ] / Ö */ 0x38, 0xB8, 0x7D, 0x5D, 0x1D, 0x7D, NOP, No, |
| 895 | /* D13 RETURN */ 0x52, 0xD2, 0xCB, 0xDB, NOP, 0xCB, NOP, No, |
| 896 | |
| 897 | /* D2 A */ 0x46, 0xC6, 0x61, 0x41, 0x01, 0x41, NOP, No, |
| 898 | /* D3 S */ 0x47, 0xC7, 0x73, 0x53, 0x13, 0x53, NOP, No, |
| 899 | /* D4 D */ 0x48, 0xC8, 0x64, 0x44, 0x04, 0x44, NOP, No, |
| 900 | /* D5 F */ 0x49, 0xC9, 0x66, 0x46, 0x06, 0x46, NOP, No, |
| 901 | /* D6 G */ 0x4A, 0xCA, 0x67, 0x47, 0x07, 0x47, NOP, No, |
| 902 | /* D7 H */ 0x4B, 0xCB, 0x68, 0x48, 0x08, 0x48, NOP, No, |
| 903 | /* D8 J */ 0x4C, 0xCC, 0x6A, 0x4A, 0x0A, 0x4A, NOP, No, |
| 904 | /* D9 K */ 0x4D, 0xCD, 0x6B, 0x4B, 0x0B, 0x4B, NOP, No, |
| 905 | /* D10 L */ 0x4E, 0xCE, 0x6C, 0x4C, 0x0C, 0x4C, NOP, No, |
| 906 | /* D11 : ; */ 0x4F, 0xCF, 0x3B, 0x3A, 0xFB, 0x3B, NOP, No, |
| 907 | /* D12 " ' / Ä */ 0x50, 0xD0, 0x27, 0x22, 0xF8, 0x27, NOP, No, |
| 908 | /* D14 ! \ */ 0x53, 0xD3, 0xC8, 0xC9, NOP, 0xC8, NOP, No, |
| 909 | |
| 910 | /* E2 Z */ 0x60, 0xE0, 0x7A, 0x5A, 0x1A, 0x5A, NOP, No, |
| 911 | /* E3 X */ 0x61, 0xE1, 0x78, 0x58, 0x18, 0x58, NOP, No, |
| 912 | /* E4 C */ 0x62, 0xE2, 0x63, 0x43, 0x03, 0x43, NOP, No, |
| 913 | /* E5 V */ 0x63, 0xE3, 0x76, 0x56, 0x16, 0x56, NOP, No, |
| 914 | /* E6 8 */ 0x64, 0xE4, 0x62, 0x42, 0x02, 0x42, NOP, No, |
| 915 | /* E7 N */ 0x65, 0xE5, 0x6E, 0x4E, 0x0E, 0x4E, NOP, No, |
| 916 | /* E8 M */ 0x66, 0xE6, 0x6D, 0x4D, 0x0D, 0x4D, NOP, No, |
| 917 | /* E9 < , */ 0x67, 0xE7, 0x2C, 0x3C, NOP, 0x2C, NOP, No, |
| 918 | /* E10 > . */ 0x68, 0xE8, 0x2E, 0x3E, NOP, 0x2E, NOP, Yes, |
| 919 | /* E11 ? / */ 0x69, 0xE9, 0xCC, 0xDC, 0xFC, 0xCC, NOP, No, |
| 920 | |
| 921 | // /* B14 ~ ' */ 0x24, 0xA4, 0x60, 0x7E, 0x1E, 0x60, NOP, No, |
| 922 | /* _ */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, |
| 923 | /* F1 (space bar) */ 0x76, 0xF6, 0x20, 0x20, 0x20, 0x20, NOP, Yes, |
| 924 | /* LC0 Home */ 0x27, 0xA7, 0x84, 0x94, 0x84, 0x84, 0xA4, No, |
| 925 | #if !MAP_APOLLO_KEYS |
| 926 | /* C14 DELETE */ 0x3A, 0xBA, 0x7F, 0x7F, NOP, 0x7F, NOP, Yes, |
| 927 | #else |
| 928 | /* E13 POP */ 0x6C, 0xEC, 0x80, 0x90, 0x80, 0x80, 0xA0, No, |
| 929 | #endif |
| 930 | /* LF0 Roll Up */ 0x72, 0xF2, 0x8D, 0x9D, 0x8D, 0x8D, 0xAD, No, |
| 931 | /* LF2 Roll Down */ 0x74, 0xF4, 0x8F, 0x9F, 0x8F, 0x8F, 0xAF, No, |
| 932 | /* LC2 End */ 0x29, 0xA9, 0x86, 0x96, 0x86, 0x86, 0xA6, No, |
| 933 | /* LE0 Cursor left */ 0x59, 0xD9, 0x8A, 0x9A, 0x9A, 0x9A, 0xAA, Yes, |
| 934 | /* LD1 Cursor Up */ 0x41, 0xC1, 0x88, 0x98, 0x88, 0x88, 0xA8, Yes, |
| 935 | /* LE2 Cursor right*/ 0x5B, 0xDB, 0x8C, 0x9C, 0x8C, 0xBE, 0xAC, Yes, |
| 936 | /* LF1 Cursor down */ 0x73, 0xF3, 0x8E, 0x9E, 0x8E, 0x8E, 0xAE, Yes, |
| 937 | |
| 938 | #if !MAP_APOLLO_KEYS |
| 939 | /* Numpad CLR */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, |
| 940 | /* Numpad / */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, |
| 941 | /* Numpad * */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, |
| 942 | /* RD4 - */ 0x58, 0xD8, 0xFE2D, 0xFE5F, NOP, 0xFE2D, NOP, No, |
| 943 | /* RC1 7 */ 0x3C, 0xBC, 0xFE37, 0xFE26, NOP, 0xFE37, NOP, No, |
| 944 | /* RC2 8 */ 0x3D, 0xBD, 0xFE38, 0xFE2A, NOP, 0xFE38, NOP, No, |
| 945 | /* RC3 9 */ 0x3E, 0xBE, 0xFE39, 0xFE28, NOP, 0xFE39, NOP, No, |
| 946 | /* RC4 + */ 0x3F, 0xBF, 0xFE2B, 0xFE3D, NOP, 0xFE2B, NOP, No, |
| 947 | /* RD1 4 */ 0x55, 0xD5, 0xFE34, 0xFE24, NOP, 0xFE34, NOP, No, |
| 948 | /* RD2 5 */ 0x56, 0xD6, 0xFE35, 0xFE25, NOP, 0xFE35, NOP, No, |
| 949 | /* RD3 6 */ 0x57, 0xD7, 0xFE36, 0xFE5E, NOP, 0xFE36, NOP, No, |
| 950 | /* Numpad = */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, |
| 951 | /* RE1 1 */ 0x6E, 0xEE, 0xFE31, 0xFE21, NOP, 0xFE31, NOP, No, |
| 952 | /* RE2 2 */ 0x6F, 0xEF, 0xFE32, 0xFE40, NOP, 0xFE32, NOP, No, |
| 953 | /* RE3 3 */ 0x70, 0xF0, 0xFE33, 0xFE23, NOP, 0xFE33, NOP, No, |
| 954 | /* RF3 ENTER */ 0x7C, 0xFC, 0xFECB, 0xFEDB, NOP, 0xFECB, NOP, No, |
| 955 | /* RF1 0 */ 0x79, 0xF9, 0xFE30, 0xFE29, NOP, 0xFE30, NOP, No, |
| 956 | /* Numpad , */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, |
| 957 | /* RF2 . */ 0x7B, 0xFB, 0xFE2E, 0xFE2E, NOP, 0xFE2E, NOP, No, |
| 958 | /* A0 F0 */ 0x04, 0x84, 0x1C, 0x5C, 0x7C, 0x1C, 0xBC, No, |
| 959 | /* A1 F1 */ 0x05, 0x85, 0xC0, 0xD0, 0xF0, 0xC0, 0xE0, No, |
| 960 | /* A2 F2 */ 0x06, 0x86, 0xC1, 0x01, 0xF1, 0xC1, 0xE1, No, |
| 961 | /* A3 F3 */ 0x07, 0x87, 0xC2, 0x02, 0xF2, 0xC2, 0xE2, No, |
| 962 | /* A4 F4 */ 0x08, 0x88, 0xC3, 0x03, 0xF3, 0xC3, 0xE3, No, |
| 963 | /* A5 F5 */ 0x09, 0x89, 0xC4, 0x04, 0xF4, 0xC4, 0xE4, No, |
| 964 | /* A6 F6 */ 0x0A, 0x8A, 0xC5, 0x05, 0xF5, 0xC5, 0xE5, No, |
| 965 | /* A7 F7 */ 0x0B, 0x8B, 0xC6, 0x06, 0xF6, 0xC6, 0xE6, No, |
| 966 | /* A8 F8 */ 0x0C, 0x8C, 0xC7, 0x07, 0xF7, 0xC7, 0xE7, No, |
| 967 | /* A9 F9 */ 0x0D, 0x8D, 0x1F, 0x2F, 0x3F, 0x1F, 0xBD, No, |
| 968 | #else |
| 969 | /* E13 POP */ 0x6C, 0xEC, 0x80, 0x90, 0x80, 0x80, 0xA0, No, |
| 970 | /* LDO [<-] */ 0x40, 0xC0, 0x87, 0x97, 0x87, 0x87, 0xA7, No, |
| 971 | /* LD2 [->] */ 0x42, 0xC2, 0x89, 0x99, 0x89, 0x89, 0xA9, No, |
| 972 | /* RD4 Numpad - */ 0x58, 0xD8, 0xFE2D, 0xFE5F, NOP, 0xFE2D, NOP, No, |
| 973 | /* LC0 7 Home */ 0x27, 0xA7, 0x84, 0x94, 0x84, 0x84, 0xA4, No, |
| 974 | /* LD1 8 Cursor Up */ 0x41, 0xC1, 0x88, 0x98, 0x88, 0x88, 0xA8, Yes, |
| 975 | /* LF0 9 Roll Up */ 0x72, 0xF2, 0x8D, 0x9D, 0x8D, 0x8D, 0xAD, No, |
| 976 | /* RC4 Numpad + */ 0x3F, 0xBF, 0xFE2B, 0xFE3D, NOP, 0xFE2B, NOP, No, |
| 977 | /* LE0 4 Cursor left */ 0x59, 0xD9, 0x8A, 0x9A, 0x9A, 0x9A, 0xAA, Yes, |
| 978 | /* LE1 NEXT WINDOW */ 0x5A, 0xDA, 0x8B, 0x9B, 0x8B, 0x8B, 0xAB, No, |
| 979 | /* LE2 6 Cursor right*/ 0x5B, 0xDB, 0x8C, 0x9C, 0x8C, 0xBE, 0xAC, Yes, |
| 980 | /* Numpad = */ 0x7C, 0xFC, 0xFEC8, 0xFED8, NOP, 0xFECB, NOP, No, |
| 981 | /* LC2 1 End */ 0x29, 0xA9, 0x86, 0x96, 0x86, 0x86, 0xA6, No, |
| 982 | /* LF1 2 Cursor down */ 0x73, 0xF3, 0x8E, 0x9E, 0x8E, 0x8E, 0xAE, Yes, |
| 983 | /* LF2 3 Roll Down */ 0x74, 0xF4, 0x8F, 0x9F, 0x8F, 0x8F, 0xAF, No, |
| 984 | /* RF3 ENTER */ 0x7C, 0xFC, 0xFECB, 0xFEDB, NOP, 0xFECB, NOP, No, |
| 985 | /* LE1 NEXT WINDOW */ 0x5A, 0xDA, 0x8B, 0x9B, 0x8B, 0x8B, 0xAB, No, |
| 986 | /* Numpad , */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, |
| 987 | /* E13 POP */ 0x6C, 0xEC, 0x80, 0x90, 0x80, 0x80, 0xA0, No, |
| 988 | |
| 989 | /* LC1 F1/SHELL/CMD */ 0x28, 0xA8, 0x85, 0x95, 0x85, 0x85, 0xA5, No, |
| 990 | /* LB0 F2/CUT/COPY */ 0x13, 0x93, 0xB0, 0xB4, 0xB0, 0xB0, 0xB8, No, |
| 991 | /* LB1 F3/UNDO/PASTE */ 0x14, 0x94, 0xB1, 0xB5, 0xB1, 0xB1, 0xB9, No, |
| 992 | /* LB2 F4/MOVE/GROW */ 0x15, 0x95, 0xB2, 0xB6, 0xB2, 0xB2, 0xBA, No, |
| 993 | |
| 994 | /* LAO F5/INS/MARK */ 0x01, 0x81, 0x81, 0x91, 0x81, 0x81, 0xA1, No, |
| 995 | /* LA1 F6/LINE DEL */ 0x02, 0x82, 0x82, 0x92, 0x82, 0x82, 0xA2, No, |
| 996 | /* LA2 F7/CHAR DEL */ 0x03, 0x83, 0x83, 0x93, 0x83, 0x83, 0xA3, Yes, |
| 997 | /* RA0 F8/AGAIN */ 0x0E, 0x8E, 0xCD, 0xE9, 0xCD, 0xCD, 0xED, No, |
| 998 | |
| 999 | /* RA1 F9/READ */ 0x0F, 0x8F, 0xCE, 0xEA, 0xCE, 0xCE, 0xEE, No, |
| 1000 | /* RA2 F10/SAVE/EDIT */ 0x10, 0x90, 0xCF, 0xEB, 0xCF, 0xCF, 0xEF, No, |
| 1001 | #endif |
| 1002 | /* RA3 F11/ABORT/EXIT */ 0x11, 0x91, 0xDD, 0xEC, 0xD0, 0xD0, 0xFD, No, |
| 1003 | /* RA4 F12/HELP/HOLD */ 0x12, 0x92, 0xB3, 0xB7, 0xB3, 0xB3, 0xBB, No, |
| 1004 | |
| 1005 | /* LE1 NEXT WINDOW */ 0x5A, 0xDA, 0x8B, 0x9B, 0x8B, 0x8B, 0xAB, No, |
| 1006 | /* LE1 NEXT WINDOW */ 0x5A, 0xDA, 0x8B, 0x9B, 0x8B, 0x8B, 0xAB, No, |
| 1007 | |
| 1008 | /* D1 CAPS LOCK */ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, |
| 1009 | /* E1 SHIFT */ 0x5E, 0xDE, NOP, NOP, NOP, NOP, NOP, NOP, |
| 1010 | /* DO CTRL */ 0x43, 0xC3, NOP, NOP, NOP, NOP, NOP, NOP, |
| 1011 | // FIXME: ALT swapped! |
| 1012 | /* ?? ALT_R */ 0x77, 0xF7, 0xfe00, NOP, NOP, NOP, 0xfe01, No, |
| 1013 | /* ?? ALT_L */ 0x75, 0xF5, 0xfe02, NOP, NOP, NOP, 0xfe03, No, |
| 1014 | /* E12 SHIFT */ 0x6A, 0xEA, NOP, NOP, NOP, NOP, NOP, NOP, |
| 1015 | // not yet used: |
| 1016 | /* E0 REPEAT */ 0x5D, 0xDD, NOP, NOP, NOP, NOP, NOP, NOP, |
| 1017 | /* CAPS LOCK LED*/ 0x7E, 0xFE, NOP, NOP, NOP, NOP, NOP, NOP, |
| 1018 | // german kbd: |
| 1019 | /* 0x68 B1_DE _ */ 0x17, 0x97, 0x60, 0x7E, 0x1E, 0x60, NOP, No, |
| 1020 | /* 0x69 E1a_DE <> */ 0x5F, 0xDF, 0xBE, 0xBE, NOP, 0xBE, NOP, No, |
| 1021 | /* 0x6a B14_DE ESC */ 0x16, 0x96, 0x1B, 0x1B, NOP, 0x1B, NOP, No, |
| 1022 | /* 0x6b D14_DE # \ */ 0x51, 0xD1, 0xC8, 0xC9, NOP, 0xC8, NOP, No, |
| 1023 | |
| 1024 | /* 0x6c NPG NP ( */ 0x3F, 0xBF, 0xFE28, 0xFE0E, NOP, 0xFE28, NOP, No, |
| 1025 | /* 0x6d NPF NP ) */ 0x58, 0xD8, 0xFE29, 0xFE0F, NOP, 0xFE29, NOP, No, |
| 1026 | /* 0x6e NPD NP + */ 0x3B, 0xBB, 0xFE2B, 0xFE26, NOP, 0xFE2B, NOP, No, |
| 1027 | /* 0x6f NPC NP - */ 0x54, 0xD4, 0xFE2D, 0xFE7E, NOP, 0xFE2D, NOP, No, |
| 1028 | /* 0x70 NPB NP * */ 0x6D, 0xED, 0xFE2A, 0xFE21, NOP, 0xFE2A, NOP, No, |
| 1029 | /* 0x71 NPA NP / */ 0x78, 0xF8, 0xFECC, 0xFEC8, NOP, 0xFECC, NOP, No, |
| 1030 | /* 0x72 NPP NP . */ 0x7B, 0xFB, 0xFE2E, 0xFE2C, NOP, 0xFE2E, NOP, No, |
| 1031 | /* 0x73 NPE ENTER */ 0x7C, 0xFC, 0xFECB, 0xFE3D, NOP, 0xFECB, NOP, No, |
| 1032 | |
| 1033 | /* 0x74 A0 F0 */ 0x04, 0x84, 0x1C, 0x5C, 0x7C, 0x1C, 0xBC, No, |
| 1034 | /* 0x75 A1 F1 */ 0x05, 0x85, 0xC0, 0xD0, 0xF0, 0xC0, 0xE0, No, |
| 1035 | /* 0x76 A2 F2 */ 0x06, 0x86, 0xC1, 0x01, 0xF1, 0xC1, 0xE1, No, |
| 1036 | /* 0x77 A3 F3 */ 0x07, 0x87, 0xC2, 0x02, 0xF2, 0xC2, 0xE2, No, |
| 1037 | /* 0x78 A4 F4 */ 0x08, 0x88, 0xC3, 0x03, 0xF3, 0xC3, 0xE3, No, |
| 1038 | /* 0x79 A5 F5 */ 0x09, 0x89, 0xC4, 0x04, 0xF4, 0xC4, 0xE4, No, |
| 1039 | /* 0x7a A6 F6 */ 0x0A, 0x8A, 0xC5, 0x05, 0xF5, 0xC5, 0xE5, No, |
| 1040 | /* 0x7b A7 F7 */ 0x0B, 0x8B, 0xC6, 0x06, 0xF6, 0xC6, 0xE6, No, |
| 1041 | /* 0x7c A8 F8 */ 0x0C, 0x8C, 0xC7, 0x07, 0xF7, 0xC7, 0xE7, No, |
| 1042 | /* 0x7d A9 F9 */ 0x0D, 0x8D, 0x1F, 0x2F, 0x3F, 0x1F, 0xBD, No, |
| 1043 | |
| 1044 | /* Key | Keycap | Down | Up |Unshifted|Shifted|Control|Caps Lock|Up Trans|Auto */ |
| 1045 | /* Number| Legend | Code | Code|Code | Code | Code |Code | Code |Repeat*/ |
| 1046 | }; |
| 1047 | |
| 1048 | INPUT_PORTS_START( apollo_kbd ) |
| 1049 | |
| 1050 | PORT_START( "keyboard1" ) |
| 1051 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("~ '") PORT_CODE(KEYCODE_TILDE) /* ESC */ |
| 1052 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) /* ESC */ |
| 1053 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) /* 1 ! */ |
| 1054 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2) /* 2 " */ |
| 1055 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) /* 3 # */ |
| 1056 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) /* 4 $ */ |
| 1057 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) /* 5 % */ |
| 1058 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("6 &") PORT_CODE(KEYCODE_6) /* 6 & */ |
| 1059 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("7 \'") PORT_CODE(KEYCODE_7) /* 7 ' */ |
| 1060 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("8 (") PORT_CODE(KEYCODE_8) /* 8 ( */ |
| 1061 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("9 )") PORT_CODE(KEYCODE_9) /* 9 ) */ |
| 1062 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0") PORT_CODE(KEYCODE_0) /* 0 */ |
| 1063 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS) /* - _ */ |
| 1064 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("= +") PORT_CODE(KEYCODE_EQUALS) /* = + */ |
| 1065 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("@ ^") PORT_CODE(KEYCODE_BACKSLASH2) /* ~ ` */ |
| 1066 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_BACKSPACE) /* Backspace */ |
| 1067 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_TAB) /* Tab */ |
| 1068 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) /* Q */ |
| 1069 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("W") PORT_CODE(KEYCODE_W) /* W */ |
| 1070 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("E") PORT_CODE(KEYCODE_E) /* E */ |
| 1071 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("R") PORT_CODE(KEYCODE_R) /* R */ |
| 1072 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("T") PORT_CODE(KEYCODE_T) /* T */ |
| 1073 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) /* Y */ |
| 1074 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("U") PORT_CODE(KEYCODE_U) /* U */ |
| 1075 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("I") PORT_CODE(KEYCODE_I) /* I */ |
| 1076 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("O") PORT_CODE(KEYCODE_O) /* O */ |
| 1077 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("P") PORT_CODE(KEYCODE_P) /* P */ |
| 1078 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("[ {") PORT_CODE(KEYCODE_OPENBRACE) /* [ { */ |
| 1079 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) /* ] } */ |
| 1080 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) /* Return */ |
| 1081 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("A") PORT_CODE(KEYCODE_A) /* A */ |
| 1082 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("S") PORT_CODE(KEYCODE_S) /* S */ |
| 1083 | |
| 1084 | PORT_START( "keyboard2" ) |
| 1085 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("D") PORT_CODE(KEYCODE_D) /* D */ |
| 1086 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F") PORT_CODE(KEYCODE_F) /* F */ |
| 1087 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("G") PORT_CODE(KEYCODE_G) /* G */ |
| 1088 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("H") PORT_CODE(KEYCODE_H) /* H */ |
| 1089 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("J") PORT_CODE(KEYCODE_J) /* J */ |
| 1090 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K") PORT_CODE(KEYCODE_K) /* K */ |
| 1091 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("L") PORT_CODE(KEYCODE_L) /* L */ |
| 1092 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("; +") PORT_CODE(KEYCODE_COLON) /* ; + */ |
| 1093 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(": *") PORT_CODE(KEYCODE_QUOTE) /* : * */ |
| 1094 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH) /* \\ | */ |
| 1095 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) /* Z */ |
| 1096 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("X") PORT_CODE(KEYCODE_X) /* X */ |
| 1097 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("C") PORT_CODE(KEYCODE_C) /* C */ |
| 1098 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("V") PORT_CODE(KEYCODE_V) /* V */ |
| 1099 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("B") PORT_CODE(KEYCODE_B) /* B */ |
| 1100 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("N") PORT_CODE(KEYCODE_N) /* N */ |
| 1101 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("M") PORT_CODE(KEYCODE_M) /* M */ |
| 1102 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) /* , < */ |
| 1103 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) /* . > */ |
| 1104 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) /* / ? */ |
| 1105 | //?? |
| 1106 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("~ '") PORT_CODE(KEYCODE_TILDE) /* Underscore (shifted only?) */ |
| 1107 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE) /* Space */ |
| 1108 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Home") PORT_CODE(KEYCODE_HOME) /* Home */ |
| 1109 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Delete") PORT_CODE(KEYCODE_DEL) /* Del */ |
| 1110 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Roll Up") PORT_CODE(KEYCODE_PGUP) /* Roll Up */ |
| 1111 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Roll Down") PORT_CODE(KEYCODE_PGDN) /* Roll Down */ |
| 1112 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("End") PORT_CODE(KEYCODE_END) /* End */ |
| 1113 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor Left") PORT_CODE(KEYCODE_LEFT) /* Left */ |
| 1114 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor Up") PORT_CODE(KEYCODE_UP) /* Up */ |
| 1115 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor Right") PORT_CODE(KEYCODE_RIGHT) /* Right */ |
| 1116 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cursor Down") PORT_CODE(KEYCODE_DOWN) /* Down */ |
| 1117 | // PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad CLR") PORT_CODE(KEYCODE_NUMLOCK) /* CLR */ |
| 1118 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("MENU") PORT_CODE(KEYCODE_MENU) /* Menu = POP */ |
| 1119 | |
| 1120 | PORT_START( "keyboard3" ) |
| 1121 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad /") PORT_CODE(KEYCODE_SLASH_PAD) /* / (numpad) */ |
| 1122 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad *") PORT_CODE(KEYCODE_ASTERISK) /* * (numpad) */ |
| 1123 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad -") PORT_CODE(KEYCODE_MINUS_PAD) /* - (numpad) */ |
| 1124 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 7") PORT_CODE(KEYCODE_7_PAD) /* 7 (numpad) */ |
| 1125 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 8") PORT_CODE(KEYCODE_8_PAD) /* 8 (numpad) */ |
| 1126 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 9") PORT_CODE(KEYCODE_9_PAD) /* 9 (numpad) */ |
| 1127 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad +") PORT_CODE(KEYCODE_PLUS_PAD) /* + (numpad) */ |
| 1128 | PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 4") PORT_CODE(KEYCODE_4_PAD) /* 4 (numpad) */ |
| 1129 | PORT_BIT( 0x00000100, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 5") PORT_CODE(KEYCODE_5_PAD) /* 5 (numpad) */ |
| 1130 | PORT_BIT( 0x00000200, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 6") PORT_CODE(KEYCODE_6_PAD) /* 6 (numpad) */ |
| 1131 | PORT_BIT( 0x00000400, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad =") /* = (numpad) */ |
| 1132 | PORT_BIT( 0x00000800, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 1") PORT_CODE(KEYCODE_1_PAD) /* 1 (numpad) */ |
| 1133 | PORT_BIT( 0x00001000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 2") PORT_CODE(KEYCODE_2_PAD) /* 2 (numpad) */ |
| 1134 | PORT_BIT( 0x00002000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 3") PORT_CODE(KEYCODE_3_PAD) /* 3 (numpad) */ |
| 1135 | PORT_BIT( 0x00004000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad Enter") PORT_CODE(KEYCODE_ENTER_PAD) /* Enter (numpad) */ |
| 1136 | PORT_BIT( 0x00008000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad 0") PORT_CODE(KEYCODE_0_PAD) /* 0 (numpad) */ |
| 1137 | PORT_BIT( 0x00010000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad ,") /* , (numpad) */ |
| 1138 | PORT_BIT( 0x00020000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Numpad .") PORT_CODE(KEYCODE_DEL_PAD) /* 2 (numpad) */ |
| 1139 | |
| 1140 | PORT_BIT( 0x00040000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) /* F1 */ |
| 1141 | PORT_BIT( 0x00080000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) /* F2 */ |
| 1142 | PORT_BIT( 0x00100000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) /* F3 */ |
| 1143 | PORT_BIT( 0x00200000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) /* F4 */ |
| 1144 | PORT_BIT( 0x00400000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) /* F5 */ |
| 1145 | PORT_BIT( 0x00800000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) /* F6 */ |
| 1146 | PORT_BIT( 0x01000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) /* F7 */ |
| 1147 | PORT_BIT( 0x02000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) /* F8 */ |
| 1148 | PORT_BIT( 0x04000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F9") PORT_CODE(KEYCODE_F9) /* F9 */ |
| 1149 | PORT_BIT( 0x08000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F10") PORT_CODE(KEYCODE_F10) /* F10 */ |
| 1150 | PORT_BIT( 0x10000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F11") PORT_CODE(KEYCODE_F11) /* F11 */ |
| 1151 | PORT_BIT( 0x20000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F12") PORT_CODE(KEYCODE_F12) /* F12 */ |
| 1152 | PORT_BIT( 0x40000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Insert") PORT_CODE(KEYCODE_INSERT) /* Insert */ |
| 1153 | // PORT_BIT( 0x80000000, 0x0000, IPT_UNUSED ) |
| 1154 | PORT_BIT( 0x80000000, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("WIN_R") PORT_CODE(KEYCODE_RWIN) /* Windows Right = Next Window */ |
| 1155 | |
| 1156 | PORT_START( "keyboard4" ) |
| 1157 | |
| 1158 | PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Caps") PORT_CODE(KEYCODE_CAPSLOCK) /* Caps lock */ |
| 1159 | PORT_BIT( 0x00000002, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) /* Shift */ |
| 1160 | PORT_BIT( 0x00000004, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) /* Ctrl */ |
| 1161 | PORT_BIT( 0x00000008, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ALT_L") PORT_CODE(KEYCODE_LALT) /* ALT */ |
| 1162 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ALT_R") PORT_CODE(KEYCODE_RALT) /* ALT GR */ |
| 1163 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Shift") PORT_CODE(KEYCODE_RSHIFT) /* Shift */ |
| 1164 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num Lock") PORT_CODE(KEYCODE_NUMLOCK) /* Num Lock */ |
| 1165 | |
| 1166 | PORT_START("mouse1") // mouse buttons |
| 1167 | PORT_BIT( 0x00000010, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Left mouse button") PORT_CODE(MOUSECODE_BUTTON1) |
| 1168 | PORT_BIT( 0x00000020, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Right mouse button") PORT_CODE(MOUSECODE_BUTTON3) |
| 1169 | PORT_BIT( 0x00000040, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Center mouse button") PORT_CODE(MOUSECODE_BUTTON2) |
| 1170 | |
| 1171 | PORT_START("mouse2") // X-axis |
| 1172 | PORT_BIT( 0xfff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) |
| 1173 | |
| 1174 | PORT_START("mouse3") // Y-axis |
| 1175 | PORT_BIT( 0xfff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) |
| 1176 | |
| 1177 | INPUT_PORTS_END |
src/mess/machine/apollo.c
| r0 | r14540 | |
| 1 | /* |
| 2 | * apollo.c - Apollo DS3500 CPU Board |
| 3 | * |
| 4 | * Created on: Jan 20, 2011 |
| 5 | * Author: Hans Ostermeyer |
| 6 | * |
| 7 | * Released for general non-commercial use under the MAME license |
| 8 | * Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | * |
| 10 | * Contains: |
| 11 | * - apollo_config.c - APOLLO DS3500 configuration |
| 12 | * - apollo_csr.c - APOLLO DS3500 CPU Control and Status registers |
| 13 | * - apollo_dma.c - APOLLO DS3500 DMA controllers |
| 14 | * - apollo_pic.c - APOLLO DS3500 PIC8259 controllers |
| 15 | * - apollo_ptm.c - APOLLO DS3500 Programmable Timer 6840 |
| 16 | * - apollo_rtc.c - APOLLO DS3500 RTC MC146818 |
| 17 | * - apollo_sio.c - APOLLO DS3500 SIO |
| 18 | * - apollo_sio2.c - APOLLO DS3500 SIO2 |
| 19 | * - apollo_fdc.c - APOLLO DS3500 Floppy disk controller |
| 20 | * |
| 21 | * see also: |
| 22 | * - http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf |
| 23 | * - http://www.freescale.com/files/32bit/doc/inactive/MC68681UM.pdf |
| 24 | * |
| 25 | */ |
| 26 | |
| 27 | #include "includes/apollo.h" |
| 28 | #include "machine/apollo_kbd.h" |
| 29 | #include "machine/omti8621.h" |
| 30 | #include "machine/sc499.h" |
| 31 | #include "machine/3c505.h" |
| 32 | |
| 33 | #include "machine/6840ptm.h" |
| 34 | #include "machine/68681.h" |
| 35 | #include "machine/8237dma.h" |
| 36 | #include "machine/mc146818.h" |
| 37 | #include "machine/pic8259.h" |
| 38 | |
| 39 | #include "machine/pc_fdc.h" |
| 40 | #include "formats/basicdsk.h" |
| 41 | |
| 42 | #include "cpu/m68000/m68000.h" |
| 43 | //#include "cpu/m68000/m68kcpu.h" |
| 44 | |
| 45 | #include "emuopts.h" |
| 46 | |
| 47 | #include <fcntl.h> |
| 48 | #include <unistd.h> |
| 49 | |
| 50 | #define APOLLO_IRQ_VECTOR 0xa0 |
| 51 | #define APOLLO_IRQ_PTM 0 |
| 52 | #define APOLLO_IRQ_SIO1 1 |
| 53 | #define APOLLO_IRQ_PIC_SLAVE 3 |
| 54 | #define APOLLO_IRQ_CTAPE 5 |
| 55 | #define APOLLO_IRQ_FDC 6 |
| 56 | #define APOLLO_IRQ_RTC 8 // DN3000 only |
| 57 | #define APOLLO_IRQ_SIO2 8 // DN3500 |
| 58 | #define APOLLO_IRQ_ETH2 9 |
| 59 | #define APOLLO_IRQ_ETH1 10 |
| 60 | #define APOLLO_IRQ_DIAG 13 |
| 61 | #define APOLLO_IRQ_WIN1 14 |
| 62 | |
| 63 | #define APOLLO_DMA_ETH1 6 |
| 64 | #define APOLLO_DMA_ETH2 3 |
| 65 | |
| 66 | //########################################################################## |
| 67 | // machine/apollo_config.c - APOLLO DS3500 configuration |
| 68 | //########################################################################## |
| 69 | |
| 70 | #undef VERBOSE |
| 71 | #define VERBOSE 0 |
| 72 | |
| 73 | static UINT16 config = 0; |
| 74 | |
| 75 | /*************************************************************************** |
| 76 | apollo_config - check configuration setting |
| 77 | ***************************************************************************/ |
| 78 | |
| 79 | int apollo_config(int mask) |
| 80 | { |
| 81 | return config & mask ? 1 : 0; |
| 82 | } |
| 83 | |
| 84 | /*************************************************************************** |
| 85 | Input Ports |
| 86 | ***************************************************************************/ |
| 87 | |
| 88 | INPUT_PORTS_START( apollo_config ) |
| 89 | PORT_START( "apollo_config" ) |
| 90 | PORT_CONFNAME(APOLLO_CONF_SERVICE_MODE, 0x00, "Normal/Service" ) |
| 91 | PORT_CONFSETTING(0x00, "Service" ) |
| 92 | PORT_CONFSETTING(APOLLO_CONF_SERVICE_MODE, "Normal " ) |
| 93 | |
| 94 | PORT_CONFNAME(APOLLO_CONF_GERMAN_KBD, 0x00, "German Keyboard") |
| 95 | PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) |
| 96 | PORT_CONFSETTING(APOLLO_CONF_GERMAN_KBD, DEF_STR ( On ) ) |
| 97 | |
| 98 | PORT_CONFNAME(APOLLO_CONF_DATE_1990, 0x00, "20 Years Ago ...") |
| 99 | PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) |
| 100 | PORT_CONFSETTING(APOLLO_CONF_DATE_1990, DEF_STR ( On ) ) |
| 101 | |
| 102 | PORT_CONFNAME(APOLLO_CONF_NODE_ID, 0x00, "Node ID from Disk") |
| 103 | PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) |
| 104 | PORT_CONFSETTING(APOLLO_CONF_NODE_ID, DEF_STR ( On ) ) |
| 105 | |
| 106 | PORT_CONFNAME(APOLLO_CONF_IDLE_SLEEP, 0x00, "Idle Sleep") |
| 107 | PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) |
| 108 | PORT_CONFSETTING(APOLLO_CONF_IDLE_SLEEP, DEF_STR ( On ) ) |
| 109 | |
| 110 | PORT_CONFNAME(APOLLO_CONF_TRAP_TRACE, 0x00, "Trap Trace") |
| 111 | PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) |
| 112 | PORT_CONFSETTING(APOLLO_CONF_TRAP_TRACE, DEF_STR ( On ) ) |
| 113 | |
| 114 | PORT_CONFNAME(APOLLO_CONF_FPU_TRACE, 0x00, "FPU Trace") |
| 115 | PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) |
| 116 | PORT_CONFSETTING(APOLLO_CONF_FPU_TRACE, DEF_STR ( On ) ) |
| 117 | |
| 118 | PORT_CONFNAME(APOLLO_CONF_DISK_TRACE, 0x00, "Disk Trace") |
| 119 | PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) |
| 120 | PORT_CONFSETTING(APOLLO_CONF_DISK_TRACE, DEF_STR ( On ) ) |
| 121 | |
| 122 | PORT_CONFNAME(APOLLO_CONF_NET_TRACE, 0x00, "Network Trace") |
| 123 | PORT_CONFSETTING(0x00, DEF_STR ( Off ) ) |
| 124 | PORT_CONFSETTING(APOLLO_CONF_NET_TRACE, DEF_STR ( On ) ) |
| 125 | INPUT_PORTS_END |
| 126 | |
| 127 | /*------------------------------------------------- |
| 128 | device start callback |
| 129 | -------------------------------------------------*/ |
| 130 | |
| 131 | static DEVICE_START(apollo_config) |
| 132 | { |
| 133 | DLOG1(("start apollo_config")); |
| 134 | } |
| 135 | |
| 136 | /*------------------------------------------------- |
| 137 | device reset callback |
| 138 | -------------------------------------------------*/ |
| 139 | |
| 140 | static DEVICE_RESET(apollo_config) |
| 141 | { |
| 142 | DLOG1(("reset apollo_config")); |
| 143 | // load configuration |
| 144 | config = input_port_read(device->machine(), "apollo_config"); |
| 145 | } |
| 146 | |
| 147 | /*------------------------------------------------- |
| 148 | device get info callback |
| 149 | -------------------------------------------------*/ |
| 150 | |
| 151 | static DEVICE_GET_INFO(apollo_config) |
| 152 | { |
| 153 | switch (state) |
| 154 | { |
| 155 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 156 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(apollo_config); break; |
| 157 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(apollo_config);break; |
| 158 | |
| 159 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 160 | case DEVINFO_STR_NAME: strcpy(info->s, "Apollo Configuration");break; |
| 161 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Configuration"); break; |
| 162 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 163 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 164 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | static DECLARE_LEGACY_DEVICE(APOLLO_CONF, apollo_config); |
| 169 | |
| 170 | DEFINE_LEGACY_DEVICE(APOLLO_CONF, apollo_config); |
| 171 | |
| 172 | //########################################################################## |
| 173 | // machine/apollo_csr.c - APOLLO DS3500 CPU Control and Status registers |
| 174 | //########################################################################## |
| 175 | |
| 176 | #undef VERBOSE |
| 177 | #define VERBOSE 0 |
| 178 | |
| 179 | #define CPU_CONTROL_REGISTER_ADDRESS 0x010100 |
| 180 | |
| 181 | static UINT16 cpu_status_register = APOLLO_CSR_SR_BIT15 | APOLLO_CSR_SR_SERVICE; |
| 182 | static UINT16 cpu_control_register = 0x0000; |
| 183 | |
| 184 | /*------------------------------------------------- |
| 185 | apollo_csr_get/set_servicemode |
| 186 | -------------------------------------------------*/ |
| 187 | |
| 188 | static int apollo_csr_get_servicemode() |
| 189 | { |
| 190 | |
| 191 | return cpu_status_register & APOLLO_CSR_SR_SERVICE ? 0 : 1; |
| 192 | } |
| 193 | |
| 194 | static void apollo_csr_set_servicemode(int mode) |
| 195 | { |
| 196 | apollo_csr_set_status_register(1, mode ? APOLLO_CSR_SR_SERVICE : 0); |
| 197 | } |
| 198 | |
| 199 | UINT16 apollo_csr_get_control_register(void) |
| 200 | { |
| 201 | return cpu_control_register; |
| 202 | } |
| 203 | |
| 204 | UINT16 apollo_csr_get_status_register(void) |
| 205 | { |
| 206 | return cpu_status_register; |
| 207 | } |
| 208 | |
| 209 | void apollo_csr_set_status_register(UINT16 mask, UINT16 data) |
| 210 | { |
| 211 | UINT16 new_value = (cpu_status_register & ~mask) | (data & mask); |
| 212 | |
| 213 | if (new_value != cpu_status_register) |
| 214 | { |
| 215 | cpu_status_register = new_value; |
| 216 | LOG1(("#### setting CPU Status Register with data=%04x & %04x to %04x", data, mask, cpu_status_register)); |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | /*------------------------------------------------- |
| 221 | DN3000/DN3500 CPU Status Register at 0x8000/0x10000 |
| 222 | -------------------------------------------------*/ |
| 223 | |
| 224 | WRITE16_HANDLER( apollo_csr_status_register_w ) { |
| 225 | // To clear bus timeouts or parity conditions from status register, |
| 226 | // write to the status register. This register is readonly. |
| 227 | // in DN3500 bit 15 is always set (undocumented !?) |
| 228 | cpu_status_register &= (APOLLO_CSR_SR_BIT15 | APOLLO_CSR_SR_FP_TRAP | APOLLO_CSR_SR_SERVICE); |
| 229 | SLOG1(("writing CPU Status Register at offset %X = %04x & %04x (%04x)", offset, data, mem_mask, cpu_status_register)); |
| 230 | } |
| 231 | |
| 232 | READ16_HANDLER( apollo_csr_status_register_r ) { |
| 233 | SLOG2(("reading CPU Status Register at offset %X = %04x & %04x", offset, cpu_status_register, mem_mask)); |
| 234 | return cpu_status_register & mem_mask; |
| 235 | } |
| 236 | |
| 237 | /*------------------------------------------------- |
| 238 | DN3000/DN3500 CPU Control Register at 0x8100/0x10100 |
| 239 | -------------------------------------------------*/ |
| 240 | |
| 241 | WRITE16_HANDLER( apollo_csr_control_register_w ) |
| 242 | { |
| 243 | int leds; |
| 244 | |
| 245 | if ((mem_mask & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0) |
| 246 | { |
| 247 | // FPU Trap enable not involved |
| 248 | } |
| 249 | else if (((data ^ cpu_control_register) & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0) |
| 250 | { |
| 251 | // FPU Trap enable remains unchanged |
| 252 | } |
| 253 | else if ((data & APOLLO_CSR_CR_FPU_TRAP_ENABLE) == 0) |
| 254 | { |
| 255 | // enable FPU (i.e. FPU opcodes in CPU) |
| 256 | // apollo_set_cpu_has_fpu(&space->device(), 1); |
| 257 | } |
| 258 | else |
| 259 | { |
| 260 | // disable FPU (i.e. FPU opcodes in CPU) |
| 261 | // apollo_set_cpu_has_fpu(&space->device(), 0); |
| 262 | |
| 263 | if (!apollo_is_dn3000()) |
| 264 | { |
| 265 | // hack: set APOLLO_CSR_SR_FP_TRAP in cpu status register for /sau7/self_test |
| 266 | // APOLLO_CSR_SR_FP_TRAP in status register should be set by next fmove instruction |
| 267 | // cpu_status_register |= APOLLO_CSR_SR_FP_TRAP; |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | cpu_control_register = (cpu_control_register & ~mem_mask) | (data & mem_mask); |
| 272 | |
| 273 | output_set_value("internal_led_1", (cpu_control_register >> 15) & 1); |
| 274 | output_set_value("internal_led_2", (cpu_control_register >> 14) & 1); |
| 275 | output_set_value("internal_led_3", (cpu_control_register >> 13) & 1); |
| 276 | output_set_value("internal_led_4", (cpu_control_register >> 12) & 1); |
| 277 | output_set_value("external_led_a", (cpu_control_register >> 11) & 1); |
| 278 | output_set_value("external_led_b", (cpu_control_register >> 10) & 1); |
| 279 | output_set_value("external_led_c", (cpu_control_register >> 9) & 1); |
| 280 | output_set_value("external_led_d", (cpu_control_register >> 8) & 1); |
| 281 | |
| 282 | leds = ((cpu_control_register >> 8) & 0xff) ^ 0xff; |
| 283 | |
| 284 | SLOG1(("writing CPU Control Register at offset %X = %04x & %04x (%04x - %d%d%d%d %d%d%d%d)", |
| 285 | offset, data, mem_mask, cpu_control_register, |
| 286 | (leds >> 3) & 1,(leds >> 2) & 1, (leds >> 1) & 1, (leds >> 0) & 1, |
| 287 | (leds >> 7) & 1,(leds >> 6) & 1, (leds >> 5) & 1, (leds >> 4) & 1 )); |
| 288 | |
| 289 | if (data & APOLLO_CSR_CR_RESET_DEVICES) |
| 290 | { |
| 291 | // FIXME: reset all devices (but not SIO lines!) |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | READ16_HANDLER( apollo_csr_control_register_r ) |
| 296 | { |
| 297 | SLOG1(("reading CPU Control Register at offset %X = %04x & %04x", offset, cpu_control_register, mem_mask)); |
| 298 | return cpu_control_register & mem_mask; |
| 299 | } |
| 300 | |
| 301 | //########################################################################## |
| 302 | // machine/apollo_dma.c - APOLLO DS3500 DMA |
| 303 | //########################################################################## |
| 304 | |
| 305 | #undef VERBOSE |
| 306 | #define VERBOSE 0 |
| 307 | |
| 308 | static UINT16 address_translation_map[0x400]; |
| 309 | |
| 310 | static UINT16 dma_page_register[16] = |
| 311 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
| 312 | |
| 313 | static const UINT8 channel2page_register[8] = { 7, 3, 1, 2, 0, 11, 9, 10}; |
| 314 | |
| 315 | static UINT8 dn3000_dma_channel1 = 1; // 1 = memory/ctape, 2 = floppy dma channel |
| 316 | static UINT8 dn3000_dma_channel2 = 5; // 5 = memory dma channel |
| 317 | |
| 318 | INLINE device_t *get_device_dma8237_1(device_t *device) { |
| 319 | return device->machine().driver_data<apollo_state>()->dma8237_1; |
| 320 | } |
| 321 | |
| 322 | INLINE device_t *get_device_dma8237_2(device_t *device) { |
| 323 | return device->machine().driver_data<apollo_state>()->dma8237_2; |
| 324 | } |
| 325 | |
| 326 | static void apollo_dma_fdc_drq(device_t *device, int state) { |
| 327 | DLOG2(("apollo_dma_fdc_drq: state=%x", state)); |
| 328 | i8237_dreq2_w(get_device_dma8237_1(device), state); |
| 329 | } |
| 330 | |
| 331 | static void apollo_dma_ctape_drq(device_t *device, int state) { |
| 332 | DLOG1(("apollo_dma_ctape_drq: state=%x", state)); |
| 333 | i8237_dreq1_w(get_device_dma8237_1(device), state); |
| 334 | } |
| 335 | |
| 336 | /*------------------------------------------------- |
| 337 | DN3000/DN3500 DMA Controller 1 at 0x9000/0x10c00 |
| 338 | -------------------------------------------------*/ |
| 339 | |
| 340 | WRITE8_HANDLER(apollo_dma_1_w ) { |
| 341 | SLOG1(("apollo_dma_1_w: writing DMA Controller 1 at offset %02x = %02x", offset, data)); |
| 342 | i8237_w(get_device_dma8237_1(&space->device()), offset, data); |
| 343 | } |
| 344 | |
| 345 | READ8_HANDLER( apollo_dma_1_r ) { |
| 346 | UINT8 data = i8237_r(get_device_dma8237_1(&space->device()), offset); |
| 347 | SLOG1(("apollo_dma_1_r: reading DMA Controller 1 at offset %02x = %02x", offset, data)); |
| 348 | return data; |
| 349 | } |
| 350 | |
| 351 | /*------------------------------------------------- |
| 352 | DN3000/DN3500 DMA Controller 2 at 0x9100/0x10d00 |
| 353 | -------------------------------------------------*/ |
| 354 | |
| 355 | WRITE8_HANDLER(apollo_dma_2_w ) { |
| 356 | SLOG1(("apollo_dma_2_w: writing DMA Controller 2 at offset %02x = %02x", offset/2, data)); |
| 357 | i8237_w(get_device_dma8237_2(&space->device()), offset / 2, data); |
| 358 | } |
| 359 | |
| 360 | READ8_HANDLER( apollo_dma_2_r ) { |
| 361 | UINT8 data = i8237_r(get_device_dma8237_2(&space->device()), offset / 2); |
| 362 | SLOG1(("apollo_dma_2_r: reading DMA Controller 2 at offset %02x = %02x", offset/2, data)); |
| 363 | return data; |
| 364 | } |
| 365 | |
| 366 | /*************************************************************************** |
| 367 | DN3000 DMA Page Register at 0x9200 |
| 368 | ***************************************************************************/ |
| 369 | |
| 370 | WRITE8_HANDLER(apollo_dma_page_register_w ) { |
| 371 | dma_page_register[offset & 0x0f] = data; |
| 372 | SLOG1(("writing DMA Page Register at offset %02x = %02x", offset, data)); |
| 373 | } |
| 374 | |
| 375 | READ8_HANDLER( apollo_dma_page_register_r ) { |
| 376 | UINT8 data = dma_page_register[offset & 0x0f]; |
| 377 | SLOG1(("reading DMA Page Register at offset %02x = %02x", offset, data)); |
| 378 | return data; |
| 379 | } |
| 380 | |
| 381 | /*------------------------------------------------- |
| 382 | DN3500 Address Translation Map at 0x017000 |
| 383 | -------------------------------------------------*/ |
| 384 | |
| 385 | WRITE16_HANDLER(apollo_address_translation_map_w ) { |
| 386 | address_translation_map[offset & 0x3ff] = data; |
| 387 | SLOG2(("writing Address Translation Map at offset %02x = %04x", offset, data)); |
| 388 | } |
| 389 | |
| 390 | READ16_HANDLER( apollo_address_translation_map_r ) { |
| 391 | UINT16 data = address_translation_map[offset & 0x3ff]; |
| 392 | SLOG2(("reading Address Translation Map at offset %02x = %04x", offset, data)); |
| 393 | return data; |
| 394 | } |
| 395 | |
| 396 | static READ8_HANDLER( apollo_dma_read_byte ) { |
| 397 | UINT8 data; |
| 398 | offs_t page_offset; |
| 399 | |
| 400 | if (apollo_is_dn3000()) { |
| 401 | page_offset = dma_page_register[channel2page_register[dn3000_dma_channel1]] << 16; |
| 402 | } else { |
| 403 | // FIXME: address_translation_map[0x200] ? |
| 404 | page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 10)]) << 10) & 0x7FFFFC00; |
| 405 | offset &= 0x3ff; |
| 406 | } |
| 407 | |
| 408 | data = space->read_byte(page_offset + offset); |
| 409 | |
| 410 | if (VERBOSE > 1 || offset < 4 || (offset & 0xff) == 0 || (offset & 0xff) == 0xff) |
| 411 | { |
| 412 | SLOG1(("dma read byte at offset %x+%03x = %02x", page_offset, offset, data)); |
| 413 | } |
| 414 | |
| 415 | return data; |
| 416 | } |
| 417 | |
| 418 | static WRITE8_HANDLER( apollo_dma_write_byte ) { |
| 419 | offs_t page_offset; |
| 420 | if (apollo_is_dn3000()) { |
| 421 | page_offset = dma_page_register[channel2page_register[dn3000_dma_channel1]] << 16; |
| 422 | } else { |
| 423 | // FIXME: address_translation_map[0x200] ? |
| 424 | page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 10)]) << 10) & 0x7FFFFC00; |
| 425 | offset &= 0x3ff; |
| 426 | } |
| 427 | // FIXME: MSB not available, writing only LSB |
| 428 | space->write_byte(page_offset + offset, data); |
| 429 | |
| 430 | if (VERBOSE > 1 || offset < 4 || (offset & 0xff) == 0 || (offset & 0xff) == 0xff) |
| 431 | { |
| 432 | SLOG1(("dma write byte at offset %x+%03x = %02x", page_offset, offset , data)); |
| 433 | } |
| 434 | } |
| 435 | |
| 436 | static READ8_HANDLER( apollo_dma_read_word ) { |
| 437 | UINT16 data; |
| 438 | offs_t page_offset; |
| 439 | |
| 440 | if (apollo_is_dn3000()) { |
| 441 | page_offset = dma_page_register[channel2page_register[dn3000_dma_channel2]] << 16; |
| 442 | page_offset &= 0xfffe0000; |
| 443 | offset <<= 1; |
| 444 | } else { |
| 445 | // FIXME: address_translation_map[0x200] ? |
| 446 | page_offset = (((offs_t) address_translation_map[0x200 + (offset >> 9)]) << 10) & 0x7FFFFC00; |
| 447 | offset = (offset << 1) & 0x3ff; |
| 448 | } |
| 449 | |
| 450 | data = space->read_byte(page_offset + offset); |
| 451 | |
| 452 | SLOG1(("dma read word at offset %x+%03x = %04x", page_offset, offset , data)); |
| 453 | // FIXME: MSB will get lost |
| 454 | return data; |
| 455 | } |
| 456 | |
| 457 | static WRITE8_HANDLER( apollo_dma_write_word ) { |
| 458 | offs_t page_offset; |
| 459 | |
| 460 | SLOG1(("dma write word at offset %x = %02x", offset, data)); |
| 461 | |
| 462 | if (apollo_is_dn3000()) { |
| 463 | page_offset = dma_page_register[channel2page_register[dn3000_dma_channel2]] << 16; |
| 464 | page_offset &= 0xfffe0000; |
| 465 | offset <<= 1; |
| 466 | } else { |
| 467 | // FIXME: address_translation_map[0x200] ? |
| 468 | page_offset |
| 469 | = (((offs_t) address_translation_map[0x200 + (offset >> 9)]) |
| 470 | << 10) & 0x7FFFFC00; |
| 471 | offset = (offset << 1) & 0x3ff; |
| 472 | } |
| 473 | |
| 474 | space->write_byte(page_offset + offset, data); |
| 475 | SLOG1(("dma write word at offset %x+%03x = %02x", page_offset, offset, data)); |
| 476 | } |
| 477 | |
| 478 | static READ8_DEVICE_HANDLER( apollo_dma8237_ctape_dack_r ) { |
| 479 | |
| 480 | UINT8 data = sc499_dack_r(&device->machine()); |
| 481 | DLOG2(("dma ctape dack read %02x",data)); |
| 482 | |
| 483 | // hack for DN3000: select appropriate DMA channel No. |
| 484 | dn3000_dma_channel1 = 1; // 1 = ctape, 2 = floppy dma channel |
| 485 | |
| 486 | return data; |
| 487 | } |
| 488 | |
| 489 | static WRITE8_DEVICE_HANDLER( apollo_dma8237_ctape_dack_w ) { |
| 490 | DLOG2(("dma ctape dack write %02x", data)); |
| 491 | sc499_dack_w(&device->machine(), data); |
| 492 | |
| 493 | // hack for DN3000: select appropriate DMA channel No. |
| 494 | // Note: too late for this byte, but next bytes will be ok |
| 495 | dn3000_dma_channel1 = 1; // 1 = ctape, 2 = floppy dma channel |
| 496 | } |
| 497 | |
| 498 | static READ8_DEVICE_HANDLER( apollo_dma8237_fdc_dack_r ) { |
| 499 | UINT8 data = pc_fdc_dack_r(device->machine()); |
| 500 | // DLOG2(("dma fdc dack read %02x",data)); |
| 501 | |
| 502 | // hack for DN3000: select appropriate DMA channel No. |
| 503 | dn3000_dma_channel1 = 2; // 1 = ctape, 2 = floppy dma channel |
| 504 | |
| 505 | return data; |
| 506 | } |
| 507 | |
| 508 | static WRITE8_DEVICE_HANDLER( apollo_dma8237_fdc_dack_w ) { |
| 509 | // DLOG2(("dma fdc dack write %02x", data)); |
| 510 | pc_fdc_dack_w(device->machine(), data); |
| 511 | |
| 512 | // hack for DN3000: select appropriate DMA channel No. |
| 513 | // Note: too late for this byte, but next bytes will be ok |
| 514 | dn3000_dma_channel1 = 2; // 1 = ctape, 2 = floppy dma channel |
| 515 | } |
| 516 | |
| 517 | static READ8_DEVICE_HANDLER( apollo_dma8237_wdc_dack_r ) { |
| 518 | UINT8 data = 0xff; // omti8621_dack_r(device->machine); |
| 519 | DLOG1(("dma wdc dack read %02x (not used, not emulated!)",data)); |
| 520 | return data; |
| 521 | } |
| 522 | |
| 523 | static WRITE8_DEVICE_HANDLER( apollo_dma8237_wdc_dack_w ) { |
| 524 | DLOG1(("dma wdc dack write %02x (not used, not emulated!)", data)); |
| 525 | // omti8621_dack_w(device->machine, data); |
| 526 | } |
| 527 | |
| 528 | static WRITE_LINE_DEVICE_HANDLER( apollo_dma8237_out_eop ) { |
| 529 | DLOG1(("dma out eop state %02x", state)); |
| 530 | pc_fdc_set_tc_state(device->machine(), state ? 0 : 1); |
| 531 | sc499_set_tc_state(&device->machine(), state); |
| 532 | } |
| 533 | |
| 534 | static WRITE_LINE_DEVICE_HANDLER( apollo_dma_1_hrq_changed ) { |
| 535 | // DLOG2(("dma 1 hrq changed state %02x", state)); |
| 536 | i8237_dreq0_w(get_device_dma8237_2(device), state); |
| 537 | |
| 538 | /* Assert HLDA */ |
| 539 | i8237_hlda_w(device, state); |
| 540 | |
| 541 | // cascade mode? |
| 542 | // i8237_hlda_w(get_device_dma8237_2(device), state); |
| 543 | } |
| 544 | |
| 545 | static WRITE_LINE_DEVICE_HANDLER( apollo_dma_2_hrq_changed ) { |
| 546 | // DLOG2(("dma 2 hrq changed state %02x", state)); |
| 547 | cputag_set_input_line(device->machine(), MAINCPU, INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE); |
| 548 | |
| 549 | /* Assert HLDA */ |
| 550 | i8237_hlda_w(device, state); |
| 551 | } |
| 552 | |
| 553 | static I8237_INTERFACE( apollo_dma8237_1_config ) |
| 554 | { |
| 555 | DEVCB_LINE(apollo_dma_1_hrq_changed), |
| 556 | DEVCB_LINE(apollo_dma8237_out_eop), |
| 557 | DEVCB_MEMORY_HANDLER(MAINCPU, PROGRAM, apollo_dma_read_byte), |
| 558 | DEVCB_MEMORY_HANDLER(MAINCPU, PROGRAM, apollo_dma_write_byte), |
| 559 | { DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_ctape_dack_r), DEVCB_HANDLER(apollo_dma8237_fdc_dack_r), DEVCB_NULL}, |
| 560 | { DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_ctape_dack_w), DEVCB_HANDLER(apollo_dma8237_fdc_dack_w), DEVCB_NULL}, |
| 561 | { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL} |
| 562 | }; |
| 563 | |
| 564 | static I8237_INTERFACE( apollo_dma8237_2_config ) |
| 565 | { |
| 566 | DEVCB_LINE(apollo_dma_2_hrq_changed), |
| 567 | DEVCB_NULL, |
| 568 | DEVCB_MEMORY_HANDLER(MAINCPU, PROGRAM, apollo_dma_read_word), |
| 569 | DEVCB_MEMORY_HANDLER(MAINCPU, PROGRAM, apollo_dma_write_word), |
| 570 | { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_wdc_dack_r)}, |
| 571 | { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_HANDLER(apollo_dma8237_wdc_dack_w)}, |
| 572 | { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL} |
| 573 | }; |
| 574 | |
| 575 | //########################################################################## |
| 576 | // machine/apollo_pic.c - APOLLO DS3500 PIC 8259 controllers |
| 577 | //########################################################################## |
| 578 | |
| 579 | #undef VERBOSE |
| 580 | #define VERBOSE 0 |
| 581 | |
| 582 | INLINE device_t *get_pic8259_master(device_t *device) { |
| 583 | return device->machine().driver_data<apollo_state>()->pic8259_master; |
| 584 | } |
| 585 | |
| 586 | INLINE device_t *get_pic8259_slave(device_t *device) { |
| 587 | return device->machine().driver_data<apollo_state>()->pic8259_slave; |
| 588 | } |
| 589 | |
| 590 | /*------------------------------------------------- |
| 591 | Interrupt Controller 8259 PIC #1 at 0x9400/0x11000 |
| 592 | -------------------------------------------------*/ |
| 593 | |
| 594 | WRITE8_DEVICE_HANDLER(apollo_pic8259_master_w ) { |
| 595 | DLOG1(("writing %s at offset %X = %02x", device->tag(), offset, data)); |
| 596 | pic8259_w(device, offset, data); |
| 597 | } |
| 598 | |
| 599 | READ8_DEVICE_HANDLER( apollo_pic8259_master_r ) { |
| 600 | UINT8 data = pic8259_r(device, offset); |
| 601 | DLOG1(("reading %s at offset %X = %02x", device->tag(), offset, data)); |
| 602 | return data; |
| 603 | } |
| 604 | |
| 605 | /*------------------------------------------------- |
| 606 | Interrupt Controller 8259 PIC #2 at 0x9500/0x11100 |
| 607 | -------------------------------------------------*/ |
| 608 | |
| 609 | WRITE8_DEVICE_HANDLER(apollo_pic8259_slave_w ) { |
| 610 | DLOG1(("writing %s at offset %X = %02x", device->tag(), offset, data)); |
| 611 | pic8259_w(device, offset, data); |
| 612 | } |
| 613 | |
| 614 | READ8_DEVICE_HANDLER( apollo_pic8259_slave_r ) { |
| 615 | UINT8 data = pic8259_r(device, offset); |
| 616 | DLOG1(("reading %s at offset %X = %02x", device->tag(), offset, data)); |
| 617 | return data; |
| 618 | } |
| 619 | |
| 620 | static void apollo_pic_set_irq_line(device_t *device, int irq, int state) { |
| 621 | // don't log PTM interrupts |
| 622 | if (irq != APOLLO_IRQ_PTM) { |
| 623 | DLOG1(("apollo_pic_set_irq_line: irq=%d state=%d", irq, state)); |
| 624 | } |
| 625 | |
| 626 | switch (irq) { |
| 627 | case 0: pic8259_ir0_w(get_pic8259_master(device), state); break; |
| 628 | case 1: pic8259_ir1_w(get_pic8259_master(device), state); break; |
| 629 | case 2: pic8259_ir2_w(get_pic8259_master(device), state); break; |
| 630 | case 3: pic8259_ir3_w(get_pic8259_master(device), state); break; |
| 631 | case 4: pic8259_ir4_w(get_pic8259_master(device), state); break; |
| 632 | case 5: pic8259_ir5_w(get_pic8259_master(device), state); break; |
| 633 | case 6: pic8259_ir6_w(get_pic8259_master(device), state); break; |
| 634 | case 7: pic8259_ir7_w(get_pic8259_master(device), state); break; |
| 635 | |
| 636 | case 8: pic8259_ir0_w(get_pic8259_slave(device), state); break; |
| 637 | case 9: pic8259_ir1_w(get_pic8259_slave(device), state); break; |
| 638 | case 10: pic8259_ir2_w(get_pic8259_slave(device), state); break; |
| 639 | case 11: pic8259_ir3_w(get_pic8259_slave(device), state); break; |
| 640 | case 12: pic8259_ir4_w(get_pic8259_slave(device), state); break; |
| 641 | case 13: pic8259_ir5_w(get_pic8259_slave(device), state); break; |
| 642 | case 14: pic8259_ir6_w(get_pic8259_slave(device), state); break; |
| 643 | case 15: pic8259_ir7_w(get_pic8259_slave(device), state); break; |
| 644 | } |
| 645 | } |
| 646 | |
| 647 | IRQ_CALLBACK(apollo_pic_acknowledge) { |
| 648 | UINT32 vector = pic8259_acknowledge(get_pic8259_master(device)); |
| 649 | if ((vector & 0x0f) == APOLLO_IRQ_PIC_SLAVE) { |
| 650 | vector = pic8259_acknowledge(get_pic8259_slave(device)); |
| 651 | } |
| 652 | |
| 653 | // don't log ptm interrupts |
| 654 | if (vector != APOLLO_IRQ_VECTOR+APOLLO_IRQ_PTM) { |
| 655 | DLOG1(("apollo_pic_acknowledge: irq=%d vector=%x", vector & 0x0f, vector)); |
| 656 | } |
| 657 | |
| 658 | if (apollo_is_dn3000()) { |
| 659 | apollo_csr_set_status_register(APOLLO_CSR_SR_INTERRUPT_PENDING, 0); |
| 660 | } else { |
| 661 | // clear bit Interrupt Pending in Cache Status Register |
| 662 | apollo_set_cache_status_register(0x10, 0x00); |
| 663 | } |
| 664 | return vector; |
| 665 | } |
| 666 | |
| 667 | /************************************************************* |
| 668 | * pic8259 configuration |
| 669 | *************************************************************/ |
| 670 | |
| 671 | static WRITE_LINE_DEVICE_HANDLER( apollo_pic8259_master_set_int_line ) { |
| 672 | static int interrupt_line = -1; |
| 673 | if (state != interrupt_line) { |
| 674 | DLOG1(("apollo_pic8259_master_set_int_line: %x", state)); |
| 675 | } |
| 676 | interrupt_line = state; |
| 677 | |
| 678 | if (apollo_is_dn3000()) { |
| 679 | apollo_csr_set_status_register(APOLLO_CSR_SR_INTERRUPT_PENDING, |
| 680 | state ? APOLLO_CSR_SR_INTERRUPT_PENDING : 0); |
| 681 | } else { |
| 682 | // set bit Interrupt Pending in Cache Status Register |
| 683 | apollo_set_cache_status_register(0x10, state ? 0x10 : 0x00); |
| 684 | } |
| 685 | |
| 686 | cputag_set_input_line_and_vector(device->machine(), MAINCPU, M68K_IRQ_6,state ? ASSERT_LINE : CLEAR_LINE, M68K_INT_ACK_AUTOVECTOR); |
| 687 | } |
| 688 | |
| 689 | static WRITE_LINE_DEVICE_HANDLER( apollo_pic8259_slave_set_int_line ) { |
| 690 | static int interrupt_line = -1; |
| 691 | if (state != interrupt_line) { |
| 692 | DLOG1(("apollo_pic8259_slave_set_int_line: %x", state)); |
| 693 | interrupt_line = state; |
| 694 | apollo_pic_set_irq_line(device, 3, state); |
| 695 | } |
| 696 | } |
| 697 | |
| 698 | static const struct pic8259_interface apollo_pic8259_master_config = { |
| 699 | DEVCB_LINE(apollo_pic8259_master_set_int_line) }; |
| 700 | |
| 701 | static const struct pic8259_interface apollo_pic8259_slave_config = { |
| 702 | DEVCB_LINE(apollo_pic8259_slave_set_int_line) }; |
| 703 | |
| 704 | //########################################################################## |
| 705 | // machine/apollo_ptm.c - APOLLO DS3500 Programmable Timer 6840 |
| 706 | //########################################################################## |
| 707 | |
| 708 | #undef VERBOSE |
| 709 | #define VERBOSE 0 |
| 710 | |
| 711 | static emu_timer* ptm_timer; |
| 712 | static UINT32 ptm_counter = 0; |
| 713 | |
| 714 | static TIMER_CALLBACK(apollo_ptm_timer_callback) |
| 715 | { |
| 716 | ptm6840_device *device = downcast<ptm6840_device *>((device_t *) ptr); |
| 717 | |
| 718 | ptm_counter++; |
| 719 | device->set_c1( 1); |
| 720 | device->set_c1( 0); |
| 721 | device->set_c2(ptm_counter & 1); |
| 722 | |
| 723 | if ((ptm_counter & 1) == 0) |
| 724 | { |
| 725 | device->set_c3((ptm_counter >> 1) & 1); |
| 726 | } |
| 727 | |
| 728 | if (ptm_counter % 250000 == 0) |
| 729 | { |
| 730 | DLOG2(("apollo_ptm_timer_callback: %d", ptm_counter / 250000)); |
| 731 | } |
| 732 | } |
| 733 | |
| 734 | static WRITE_LINE_DEVICE_HANDLER( apollo_ptm_irq_function ) { |
| 735 | DLOG1(("apollo_ptm_irq_function: state=%d", state )); |
| 736 | |
| 737 | // ptm6840_device *ptm = device->machine().device<ptm6840_device>(APOLLO_PTM_TAG); |
| 738 | |
| 739 | apollo_pic_set_irq_line(device, APOLLO_IRQ_PTM, state); |
| 740 | } |
| 741 | |
| 742 | // Timer 1's input is a 250-kHz (4-microsecond period) signal. |
| 743 | // Timer 2's input is a 125-kHz (8-microsecond period) signal. |
| 744 | // Timer 3's input is a 62.5-kHz (16-microsecond period) signal. |
| 745 | // The Timer 3 input may be prescaled to make the effective input signal have a 128-microsecond period. |
| 746 | |
| 747 | static const ptm6840_interface apollo_ptm_config = { |
| 748 | 0, |
| 749 | { 250000, 125000, 62500 }, |
| 750 | { DEVCB_NULL, DEVCB_NULL, DEVCB_NULL }, |
| 751 | DEVCB_LINE(apollo_ptm_irq_function) |
| 752 | }; |
| 753 | |
| 754 | static DEVICE_START( apollo_ptm ) |
| 755 | { |
| 756 | DLOG1(("start apollo_ptm")); |
| 757 | // allocate and start ptm timer |
| 758 | ptm_timer = device->machine().scheduler().timer_alloc(FUNC(apollo_ptm_timer_callback), device); |
| 759 | ptm_timer->adjust( attotime::zero, 0, attotime::from_usec(4)); |
| 760 | } |
| 761 | |
| 762 | static DEVICE_RESET( apollo_ptm ) |
| 763 | { |
| 764 | DLOG1(("reset apollo_ptm")); |
| 765 | device->reset(); |
| 766 | } |
| 767 | |
| 768 | READ8_DEVICE_HANDLER(apollo_ptm_r) { |
| 769 | UINT8 data =downcast<ptm6840_device *>((device_t *) device)->read(offset / 2); |
| 770 | |
| 771 | // prevent excessive logging |
| 772 | static UINT8 previous = 255; |
| 773 | if (offset / 2 != 1 || data != previous) { |
| 774 | DLOG1(("apollo_ptm_read reg %x returned %02x", offset/2, data )); |
| 775 | if (offset / 2 == 1) { |
| 776 | previous = data; |
| 777 | } |
| 778 | } |
| 779 | return data; |
| 780 | } |
| 781 | |
| 782 | WRITE8_DEVICE_HANDLER(apollo_ptm_w) { |
| 783 | DLOG1(("apollo_ptm_write reg %x with %02x", offset/2, data )); |
| 784 | downcast<ptm6840_device *>((device_t *) device)->write(offset / 2, data); |
| 785 | } |
| 786 | |
| 787 | //########################################################################## |
| 788 | // machine/apollo_rtc.c - APOLLO DS3500 RTC MC146818 |
| 789 | //########################################################################## |
| 790 | |
| 791 | #undef VERBOSE |
| 792 | #define VERBOSE 0 |
| 793 | |
| 794 | /*************************************************************************** |
| 795 | DN3000/DN3500 Realtime Calendar MC146818 at 0x8900/0x10900 |
| 796 | ***************************************************************************/ |
| 797 | |
| 798 | static DEVICE_RESET( apollo_rtc ) { |
| 799 | address_space *space = device->machine().device(MAINCPU)->memory().space(AS_PROGRAM); |
| 800 | UINT8 year = apollo_rtc_r(space, 9); |
| 801 | |
| 802 | // change year according to configuration settings |
| 803 | if (year < 20 && apollo_config(APOLLO_CONF_DATE_1990)) |
| 804 | { |
| 805 | year+=80; |
| 806 | apollo_rtc_w(space, 9, year); |
| 807 | } |
| 808 | else if (year >= 80 && !apollo_config(APOLLO_CONF_DATE_1990)) |
| 809 | { |
| 810 | year -=80; |
| 811 | apollo_rtc_w(space, 9, year); |
| 812 | } |
| 813 | |
| 814 | SLOG1(("reset apollo_rtc year=%d", year)); |
| 815 | } |
| 816 | |
| 817 | WRITE8_HANDLER( apollo_rtc_w ) |
| 818 | { |
| 819 | mc146818_device *rtc = space->machine().device<mc146818_device> (APOLLO_RTC_TAG); |
| 820 | rtc->write(*space, 0, offset); |
| 821 | rtc->write(*space, 1, data); |
| 822 | if (offset >= 0x0b && offset <= 0x0c) |
| 823 | { |
| 824 | SLOG2(("writing MC146818 at offset %02x = %02x", offset, data)); |
| 825 | } |
| 826 | } |
| 827 | |
| 828 | READ8_HANDLER( apollo_rtc_r ) |
| 829 | { |
| 830 | UINT8 data; |
| 831 | mc146818_device *rtc = space->machine().device<mc146818_device> (APOLLO_RTC_TAG); |
| 832 | rtc->write(*space, 0, offset); |
| 833 | data = rtc->read(*space, 1); |
| 834 | if (offset >= 0x0b && offset <= 0x0c) |
| 835 | { |
| 836 | SLOG2(("reading MC146818 at offset %02x = %02x", offset, data)); |
| 837 | } |
| 838 | return data; |
| 839 | } |
| 840 | |
| 841 | static TIMER_CALLBACK( apollo_rtc_timer ) |
| 842 | { |
| 843 | address_space *space = machine.device(MAINCPU)->memory().space(AS_PROGRAM); |
| 844 | |
| 845 | // FIXME: reading register 0x0c will clear all interrupt flags |
| 846 | if ((apollo_rtc_r(space, 0x0c) & 0x80)) |
| 847 | { |
| 848 | SLOG2(("apollo_rtc_timer - set_irq_line %d", APOLLO_IRQ_RTC)); |
| 849 | apollo_pic_set_irq_line(&space->device(), APOLLO_IRQ_RTC, 1); |
| 850 | } |
| 851 | } |
| 852 | |
| 853 | //########################################################################## |
| 854 | // machine/apollo_sio.c - APOLLO DS3500 SIO |
| 855 | //########################################################################## |
| 856 | |
| 857 | #undef VERBOSE |
| 858 | #define VERBOSE 0 |
| 859 | |
| 860 | #define SIO_SLEEP_DELAY_TIME 30000 // ms |
| 861 | |
| 862 | static int isInitialized = 0; |
| 863 | static int input_from_stdin = 0; |
| 864 | |
| 865 | static UINT8 sio_input_data = 0xff; |
| 866 | static UINT8 sio_output_data = 0xff; |
| 867 | |
| 868 | static emu_timer *kbd_timer; |
| 869 | static int sleep_time = 0; |
| 870 | |
| 871 | static int sio_irq_line = 0; |
| 872 | |
| 873 | static UINT8 sio_csrb = 0; |
| 874 | |
| 875 | /*------------------------------------------------- |
| 876 | sio_sleep - sleep to reduce the CPU usage |
| 877 | -------------------------------------------------*/ |
| 878 | |
| 879 | // we reduce the CPU usage, if SRB is being polled for input |
| 880 | // but only as long as the transmitter is empty and ready |
| 881 | // and the initial delay time has passed w/o IO |
| 882 | |
| 883 | static void sio_sleep(int delay) { |
| 884 | if (!apollo_config(APOLLO_CONF_IDLE_SLEEP)) { |
| 885 | // nothing to do; sleeping is not enabled |
| 886 | } else if (delay <= 0) { |
| 887 | //reset the sleep delay time |
| 888 | if (sleep_time > 0) { |
| 889 | LOG2(("sio_sleep: sleeping stopped")) |
| 890 | sleep_time = 0; |
| 891 | } |
| 892 | } else if (sleep_time < delay) { |
| 893 | // sleep delay pending (i.e. don't sleep) |
| 894 | sleep_time++; |
| 895 | } else { |
| 896 | if (sleep_time == delay) { |
| 897 | LOG2(("sio_sleep: sleeping started after %d ms",sleep_time)); |
| 898 | sleep_time++; |
| 899 | } |
| 900 | // Note: ticks_per_second/100 will sleep for 6 ms (= 4-10 ms) |
| 901 | osd_sleep(osd_ticks_per_second() / 50); |
| 902 | } |
| 903 | } |
| 904 | |
| 905 | /*------------------------------------------------- |
| 906 | apollo_sio_rx_data - get character from keyboard/stdin |
| 907 | -------------------------------------------------*/ |
| 908 | |
| 909 | void apollo_sio_rx_data(device_t* device, int ch, UINT8 data) { |
| 910 | // omit logging for channel 1 |
| 911 | if (ch == 0) { |
| 912 | DLOG1(("apollo_sio_rx_data ch=%d <- data=%02x", ch, data )); |
| 913 | } |
| 914 | |
| 915 | if (ch == 1 && !isInitialized && data == '\r' && apollo_csr_get_servicemode()) { |
| 916 | // force baudrate recognition |
| 917 | data = 0xff; |
| 918 | isInitialized = 1; |
| 919 | } |
| 920 | |
| 921 | duart68681_rx_data(device, ch, data); |
| 922 | } |
| 923 | |
| 924 | /*------------------------------------------------- |
| 925 | apollo_sio_tx_data - put character to display/stdout |
| 926 | -------------------------------------------------*/ |
| 927 | |
| 928 | static void apollo_sio_tx_data(device_t *device, int channel, UINT8 data) { |
| 929 | if (channel == 0) { |
| 930 | DLOG1(("apollo_sio_tx_data ch=%d -> data=%02x", channel, data )); |
| 931 | device_t *keyboard = device->machine().device( APOLLO_KBD_TAG ); |
| 932 | if (keyboard != NULL) { |
| 933 | apollo_kbd_getchar(keyboard, data); |
| 934 | } |
| 935 | } else if (channel == 1) { |
| 936 | DLOG2(("apollo_sio_tx_data ch=%d -> data=%02x", channel, data )); |
| 937 | |
| 938 | if (data != '\r') { |
| 939 | // output data to stdout |
| 940 | putchar(data); |
| 941 | fflush(stdout); |
| 942 | |
| 943 | if (apollo_is_dsp3x00()) { |
| 944 | // output data to terminal emulator |
| 945 | apollo_terminal_write(data); |
| 946 | } |
| 947 | } |
| 948 | } |
| 949 | } |
| 950 | |
| 951 | /*------------------------------------------------- |
| 952 | sio configuration |
| 953 | -------------------------------------------------*/ |
| 954 | |
| 955 | static void sio_irq_handler(device_t *device, UINT8 vector) { |
| 956 | DLOG2(("sio_irq_handler: vector=%02x", vector )); |
| 957 | apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO1, 1); |
| 958 | sio_irq_line = 1; |
| 959 | } |
| 960 | |
| 961 | static UINT8 sio_input(device_t *device) { |
| 962 | // necessary for DN3000? |
| 963 | // sio_input_data = sio_input_data ? 0 : 0x0f; |
| 964 | DLOG2(("reading 2681 input: %02x", sio_input_data )); |
| 965 | return sio_input_data; |
| 966 | } |
| 967 | |
| 968 | static void sio_output(device_t *device, UINT8 data) { |
| 969 | DLOG1(("writing 2681 output: %02x", data )); |
| 970 | |
| 971 | if ((data & 0x80) != (sio_output_data & 0x80)) { |
| 972 | apollo_pic_set_irq_line(device, APOLLO_IRQ_DIAG, (data & 0x80) ? 1 : 0); |
| 973 | sio_output_data = data; |
| 974 | } |
| 975 | } |
| 976 | |
| 977 | const duart68681_config apollo_sio_config = { |
| 978 | sio_irq_handler, |
| 979 | apollo_sio_tx_data, |
| 980 | sio_input, |
| 981 | sio_output |
| 982 | }; |
| 983 | |
| 984 | /*------------------------------------------------- |
| 985 | DN3000/DS3500 SIO at 0x8400/0x10400 |
| 986 | -------------------------------------------------*/ |
| 987 | |
| 988 | READ8_DEVICE_HANDLER(apollo_sio_r) { |
| 989 | static int last_read8_offset[2] = { -1, -1 }; |
| 990 | static int last_read8_value[2] = { -1, -1 }; |
| 991 | |
| 992 | static const char * const duart68681_reg_read_names[0x10] = { "MRA", "SRA", |
| 993 | "BRG Test", "RHRA", "IPCR", "ISR", "CTU", "CTL", "MRB", "SRB", |
| 994 | "1X/16X Test", "RHRB", "IVR", "Input Ports", "Start Counter", |
| 995 | "Stop Counter" }; |
| 996 | |
| 997 | int data = duart68681_r(device, offset / 2); |
| 998 | |
| 999 | if (sio_irq_line) { |
| 1000 | apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO1, 0); |
| 1001 | sio_irq_line = 0; |
| 1002 | } |
| 1003 | |
| 1004 | switch (offset / 2) { |
| 1005 | case 0x0b: /* RHRB */ |
| 1006 | if (data == 0x0d && sio_csrb == 0x77) { |
| 1007 | // special for MD command SK (Select keyboard) with baudrate set to 2000 |
| 1008 | data = 0xff; |
| 1009 | } |
| 1010 | break; |
| 1011 | } |
| 1012 | |
| 1013 | // omit logging if sio is being polled from the boot rom |
| 1014 | if ((offset != last_read8_offset[1] || data != last_read8_value[1]) |
| 1015 | && (offset != last_read8_offset[0] || data != last_read8_value[0])) { |
| 1016 | last_read8_offset[0] = last_read8_offset[1]; |
| 1017 | last_read8_value[0] = last_read8_value[1]; |
| 1018 | last_read8_offset[1] = offset; |
| 1019 | last_read8_value[1] = data; |
| 1020 | DLOG2(("reading 2681 reg %x (%s) returned %02x", |
| 1021 | offset, duart68681_reg_read_names[offset/2], data )); |
| 1022 | } |
| 1023 | |
| 1024 | return data; |
| 1025 | } |
| 1026 | |
| 1027 | WRITE8_DEVICE_HANDLER(apollo_sio_w) |
| 1028 | { |
| 1029 | static const char * const duart68681_reg_write_names[0x10] = { "MRA", |
| 1030 | "CSRA", "CRA", "THRA", "ACR", "IMR", "CRUR", "CTLR", "MRB", "CSRB", |
| 1031 | "CRB", "THRB", "IVR", "OPCR", "Set OP Bits", "Reset OP Bits" }; |
| 1032 | |
| 1033 | if (sio_irq_line) { |
| 1034 | apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO1, 0); |
| 1035 | sio_irq_line = 0; |
| 1036 | } |
| 1037 | |
| 1038 | // don't log THRB |
| 1039 | if (offset != 0x17) { |
| 1040 | DLOG2(("writing 2681 reg %x (%s) with %02x", offset, duart68681_reg_write_names[(offset/2) & 15], data )); |
| 1041 | } |
| 1042 | |
| 1043 | switch (offset / 2) { |
| 1044 | case 0x09: /* CSRB */ |
| 1045 | // remember CSRB to handle MD command SK on DSP3x00 |
| 1046 | sio_csrb = data; |
| 1047 | break; |
| 1048 | case 0x0b: /* THRB */ |
| 1049 | // stop sleeping |
| 1050 | sio_sleep(0); |
| 1051 | break; |
| 1052 | case 0x0d: /* OPCR */ |
| 1053 | if ((data & 0x0c) == 0x04) { |
| 1054 | // Unhandled OPCR value; used for RAM refresh circuit |
| 1055 | // ignore value; omit error message |
| 1056 | data &= ~0x0c; |
| 1057 | } |
| 1058 | break; |
| 1059 | } |
| 1060 | duart68681_w(device, offset / 2, data); |
| 1061 | } |
| 1062 | |
| 1063 | /*------------------------------------------------- |
| 1064 | kbd tty timer callback |
| 1065 | -------------------------------------------------*/ |
| 1066 | |
| 1067 | static TIMER_CALLBACK(kbd_timer_callback) |
| 1068 | { |
| 1069 | |
| 1070 | #if defined(__linux__) |
| 1071 | device_t *device = (device_t *) ptr; |
| 1072 | UINT8 data; |
| 1073 | |
| 1074 | #define SRA 0x01 |
| 1075 | #define SRB 0x09 |
| 1076 | |
| 1077 | if (!(duart68681_r(device, SRB) & 0x02)) |
| 1078 | { |
| 1079 | // Channel B FIFO not yet full (STATUS_FIFO_FULL) |
| 1080 | if (read(STDIN_FILENO, &data, 1) == 1) |
| 1081 | { |
| 1082 | apollo_sio_rx_data(device, 1, data == '\n' ? '\r' : data); |
| 1083 | input_from_stdin = 1; |
| 1084 | // stop sleeping to reduce CPU usage |
| 1085 | sio_sleep(0); |
| 1086 | } |
| 1087 | else if (input_from_stdin && (duart68681_r(device, SRB) & 0x0c) == 0x0c) |
| 1088 | { |
| 1089 | // we reduce the CPU usage, if SRB is being polled for input |
| 1090 | // but only as long as the transmitter is empty and ready |
| 1091 | // and the initial delay time has has passed |
| 1092 | sio_sleep(SIO_SLEEP_DELAY_TIME); |
| 1093 | } |
| 1094 | } |
| 1095 | #endif |
| 1096 | |
| 1097 | // The counter/timer on the SIO chip is used for the refresh count. |
| 1098 | // This is set up in the timer mode to produce a square wave output on output OP3. |
| 1099 | // The period of the output is 15 microseconds. |
| 1100 | |
| 1101 | // toggle memory refresh counter |
| 1102 | sio_input_data ^= 0x01; |
| 1103 | } |
| 1104 | |
| 1105 | /*------------------------------------------------- |
| 1106 | device start callback |
| 1107 | -------------------------------------------------*/ |
| 1108 | |
| 1109 | static DEVICE_START(apollo_sio) |
| 1110 | { |
| 1111 | kbd_timer = device->machine().scheduler().timer_alloc(FUNC(kbd_timer_callback), device); |
| 1112 | } |
| 1113 | |
| 1114 | /*------------------------------------------------- |
| 1115 | device reset callback |
| 1116 | -------------------------------------------------*/ |
| 1117 | |
| 1118 | static DEVICE_RESET(apollo_sio) |
| 1119 | { |
| 1120 | DLOG1(("reset apollo_sio")); |
| 1121 | |
| 1122 | isInitialized = 0; |
| 1123 | input_from_stdin = 0; |
| 1124 | sleep_time = 0; |
| 1125 | sio_input_data = apollo_get_ram_config_byte(); |
| 1126 | sio_output_data = 0xff; |
| 1127 | |
| 1128 | #if defined(__linux__) |
| 1129 | // FIXME: unavailable in mingw |
| 1130 | // set stdin to nonblocking to allow polling in sio_poll_rxb |
| 1131 | fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK); |
| 1132 | #endif |
| 1133 | |
| 1134 | // start the keyboard timer |
| 1135 | kbd_timer->adjust( attotime::zero, 0, attotime::from_msec(1)); |
| 1136 | } |
| 1137 | |
| 1138 | //########################################################################## |
| 1139 | // machine/apollo_sio2.c - APOLLO DS3500 SIO2 |
| 1140 | //########################################################################## |
| 1141 | |
| 1142 | #undef VERBOSE |
| 1143 | #define VERBOSE 0 |
| 1144 | |
| 1145 | /*------------------------------------------------- |
| 1146 | sio2 configuration (DN3500 only) |
| 1147 | -------------------------------------------------*/ |
| 1148 | |
| 1149 | static void sio2_irq_handler(device_t *device, UINT8 vector) |
| 1150 | { |
| 1151 | DLOG1(("sio2_irq_handler: vector=%02x", vector )); |
| 1152 | apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO2, 1); |
| 1153 | } |
| 1154 | |
| 1155 | static void sio2_tx_data(device_t *device, int channel, UINT8 data) |
| 1156 | { |
| 1157 | DLOG1(("apollo_sio2_tx_data ch=%d -> data=%02x", channel, data )); |
| 1158 | } |
| 1159 | |
| 1160 | static UINT8 sio2_input(device_t *device) |
| 1161 | { |
| 1162 | UINT8 data = 0x00; |
| 1163 | DLOG1(("reading 2681 input: %02x", data )); |
| 1164 | return data; |
| 1165 | } |
| 1166 | |
| 1167 | static void sio2_output(device_t *device, UINT8 data) |
| 1168 | { |
| 1169 | DLOG1(("writing 2681 output: %02x", data )); |
| 1170 | } |
| 1171 | |
| 1172 | const duart68681_config apollo_sio2_config = { |
| 1173 | sio2_irq_handler, |
| 1174 | sio2_tx_data, |
| 1175 | sio2_input, |
| 1176 | sio2_output |
| 1177 | }; |
| 1178 | |
| 1179 | /*------------------------------------------------- |
| 1180 | DN3500 SIO2 at 0x10500 |
| 1181 | -------------------------------------------------*/ |
| 1182 | |
| 1183 | READ8_DEVICE_HANDLER(apollo_sio2_r) |
| 1184 | { |
| 1185 | static const char * const duart68681_reg_read_names[0x10] = { "MRA", "SRA", |
| 1186 | "BRG Test", "RHRA", "IPCR", "ISR", "CTU", "CTL", "MRB", "SRB", |
| 1187 | "1X/16X Test", "RHRB", "IVR", "Input Ports", "Start Counter", |
| 1188 | "Stop Counter" }; |
| 1189 | |
| 1190 | apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO2, 0); |
| 1191 | |
| 1192 | int data = duart68681_r(device, offset / 2); |
| 1193 | |
| 1194 | DLOG2(("reading 2681 reg %x (%s) returned %02x", |
| 1195 | offset, duart68681_reg_read_names[offset/2], data )); |
| 1196 | return data; |
| 1197 | } |
| 1198 | |
| 1199 | WRITE8_DEVICE_HANDLER(apollo_sio2_w) |
| 1200 | { |
| 1201 | static const char * const duart68681_reg_write_names[0x10] = { "MRA", |
| 1202 | "CSRA", "CRA", "THRA", "ACR", "IMR", "CRUR", "CTLR", "MRB", "CSRB", |
| 1203 | "CRB", "THRB", "IVR", "OPCR", "Set OP Bits", "Reset OP Bits" }; |
| 1204 | |
| 1205 | DLOG2(("writing 2681 reg %x (%s) with %02x", offset, duart68681_reg_write_names[(offset/2) & 15], data )); |
| 1206 | |
| 1207 | apollo_pic_set_irq_line(device, APOLLO_IRQ_SIO2, 0); |
| 1208 | |
| 1209 | switch (offset / 2) { |
| 1210 | case 0x04: /* ACR */ |
| 1211 | if (data == 0x80) { |
| 1212 | // FIXME: unhandled ACR value |
| 1213 | // data = 0xe0; |
| 1214 | } |
| 1215 | break; |
| 1216 | } |
| 1217 | |
| 1218 | duart68681_w(device, offset / 2, data); |
| 1219 | } |
| 1220 | |
| 1221 | /*------------------------------------------------- |
| 1222 | device start callback |
| 1223 | -------------------------------------------------*/ |
| 1224 | |
| 1225 | static DEVICE_START(apollo_sio2) |
| 1226 | { |
| 1227 | DLOG1(("start apollo_sio2")); |
| 1228 | } |
| 1229 | |
| 1230 | /*------------------------------------------------- |
| 1231 | device reset callback |
| 1232 | -------------------------------------------------*/ |
| 1233 | |
| 1234 | static DEVICE_RESET(apollo_sio2) |
| 1235 | { |
| 1236 | DLOG1(("reset apollo_sio2")); |
| 1237 | } |
| 1238 | |
| 1239 | //########################################################################## |
| 1240 | // machine/apollo_fdc.c - APOLLO DS3500 Floppy disk controller |
| 1241 | //########################################################################## |
| 1242 | |
| 1243 | #undef VERBOSE |
| 1244 | #define VERBOSE 0 |
| 1245 | |
| 1246 | static device_t *apollo_fdc_device = NULL; |
| 1247 | |
| 1248 | static LEGACY_FLOPPY_OPTIONS_START( apollo ) |
| 1249 | LEGACY_FLOPPY_OPTION( img2d, "afd", "Apollo floppy disk image", basicdsk_identify_default, basicdsk_construct_default, NULL, |
| 1250 | HEADS([2]) |
| 1251 | TRACKS([77]) |
| 1252 | SECTORS([8]) |
| 1253 | SECTOR_LENGTH([1024]) |
| 1254 | FIRST_SECTOR_ID([1])) |
| 1255 | LEGACY_FLOPPY_OPTIONS_END0 |
| 1256 | |
| 1257 | static const floppy_interface apollo_fdc_floppy_config = { // |
| 1258 | DEVCB_NULL, // |
| 1259 | DEVCB_NULL, // |
| 1260 | DEVCB_NULL, // |
| 1261 | DEVCB_NULL, // |
| 1262 | DEVCB_NULL, // |
| 1263 | FLOPPY_STANDARD_5_25_DSHD, // |
| 1264 | LEGACY_FLOPPY_OPTIONS_NAME(apollo), // |
| 1265 | NULL, // |
| 1266 | NULL // |
| 1267 | }; |
| 1268 | |
| 1269 | /************************************* |
| 1270 | * Floppy Disk Controller |
| 1271 | *************************************/ |
| 1272 | |
| 1273 | static void apollo_fdc_interrupt(running_machine &machine, int state) { |
| 1274 | apollo_pic_set_irq_line( machine.firstcpu, APOLLO_IRQ_FDC, state); |
| 1275 | } |
| 1276 | |
| 1277 | static void apollo_fdc_dma_drq(running_machine &machine, int state) { |
| 1278 | apollo_dma_fdc_drq(machine.firstcpu, state); |
| 1279 | } |
| 1280 | |
| 1281 | static device_t *apollo_fdc_get_image(running_machine &machine, |
| 1282 | int floppy_index) { |
| 1283 | return floppy_get_device(machine, 0); |
| 1284 | } |
| 1285 | |
| 1286 | static device_t * apollo_fdc_get_device(running_machine &machine) { |
| 1287 | return apollo_fdc_device; |
| 1288 | } |
| 1289 | |
| 1290 | static const struct pc_fdc_interface apollo_fdc_interface = { |
| 1291 | apollo_fdc_interrupt, // |
| 1292 | apollo_fdc_dma_drq, // |
| 1293 | apollo_fdc_get_image, // |
| 1294 | apollo_fdc_get_device // |
| 1295 | }; |
| 1296 | |
| 1297 | /*------------------------------------------------- |
| 1298 | FDC upd765 at 0x5f800 - 0x5f807 |
| 1299 | -------------------------------------------------*/ |
| 1300 | |
| 1301 | static DEVICE_START( apollo_fdc ) { |
| 1302 | DLOG1(("device_start_apollo_fdc")); |
| 1303 | apollo_fdc_device = device; |
| 1304 | pc_fdc_init(device->machine(), &apollo_fdc_interface); |
| 1305 | |
| 1306 | // hack to make upd765.c work again for apollo with MESS version >= 0.142u6 |
| 1307 | // 2011-07-23 Hans Ostermyer |
| 1308 | // extern void upd765_hack_for_apollo(); |
| 1309 | // upd765_hack_for_apollo(); |
| 1310 | } |
| 1311 | |
| 1312 | WRITE8_HANDLER(apollo_fdc_w ) { |
| 1313 | SLOG1(("writing FDC upd765 at offset %X = %02x", offset, data)); |
| 1314 | pc_fdc_w(space, offset, data); |
| 1315 | } |
| 1316 | |
| 1317 | READ8_HANDLER( apollo_fdc_r ) { |
| 1318 | UINT8 data = pc_fdc_r(space, offset); |
| 1319 | SLOG1(("reading FDC upd765 at offset %X = %02x", offset, data)); |
| 1320 | return data; |
| 1321 | } |
| 1322 | |
| 1323 | /*************************************************************************** |
| 1324 | DN3500 3c505 DEVICE Configuration |
| 1325 | ***************************************************************************/ |
| 1326 | |
| 1327 | static void apollo_3c505_set_irq(device_t *device, int state) { |
| 1328 | // DLOG2(("apollo_3c505_interrupt: state=%x", state )); |
| 1329 | apollo_pic_set_irq_line(device->machine().firstcpu, APOLLO_IRQ_ETH1, state); |
| 1330 | } |
| 1331 | |
| 1332 | static int apollo_3c505_tx_data(device_t *device, |
| 1333 | const UINT8 tx_data_buffer[], int tx_data_length) { |
| 1334 | |
| 1335 | // transmit all transmitted packets to the apollo_netserver |
| 1336 | apollo_netserver_receive(device, tx_data_buffer, tx_data_length); |
| 1337 | |
| 1338 | // transmit all transmitted packets to the host ethernet (ignore any errors) |
| 1339 | return apollo_eth_transmit(device, tx_data_buffer, tx_data_length); |
| 1340 | } |
| 1341 | |
| 1342 | static int apollo_3c505_setfilter(device_t *device, int node_id) |
| 1343 | { |
| 1344 | return apollo_eth_setfilter(device, node_id); |
| 1345 | } |
| 1346 | |
| 1347 | static int apollo_3c505_rx_data(device_t *device, |
| 1348 | const UINT8 rx_data_buffer[], int rx_data_length) { |
| 1349 | |
| 1350 | // transmit all received packets to the threecom3c505 receiver |
| 1351 | return threecom3c505_receive(device, rx_data_buffer, rx_data_length); |
| 1352 | } |
| 1353 | |
| 1354 | static void apollo_3c505_tx_init(device_t *device) { |
| 1355 | |
| 1356 | apollo_eth_init(device, apollo_3c505_rx_data); |
| 1357 | |
| 1358 | // setup to receive all packets from the apollo_netserver |
| 1359 | apollo_netserver_init(device->machine().options().media_path(), apollo_3c505_rx_data); |
| 1360 | } |
| 1361 | |
| 1362 | static THREECOM3C505_INTERFACE(apollo_3c505_config) = { |
| 1363 | apollo_3c505_set_irq, |
| 1364 | apollo_3c505_tx_init, |
| 1365 | apollo_3c505_tx_data, |
| 1366 | apollo_3c505_setfilter |
| 1367 | }; |
| 1368 | |
| 1369 | /*************************************************************************** |
| 1370 | DN3500 OMTI 8621 DEVICE Configuration |
| 1371 | ***************************************************************************/ |
| 1372 | |
| 1373 | static void apollo_wdc_set_irq(const running_machine *machine, int state) { |
| 1374 | // FIXME: |
| 1375 | // MLOG2(("apollo_wdc_set_irq: state=%x", state )); |
| 1376 | apollo_pic_set_irq_line(machine->firstcpu, APOLLO_IRQ_WIN1, state); |
| 1377 | } |
| 1378 | |
| 1379 | static const omti8621_config apollo_wdc_config = { |
| 1380 | apollo_wdc_set_irq |
| 1381 | }; |
| 1382 | |
| 1383 | /*************************************************************************** |
| 1384 | DN3500 Cartridge Tape DEVICE Configuration |
| 1385 | ***************************************************************************/ |
| 1386 | |
| 1387 | static void apollo_ctape_set_irq(const device_t *device, int state) { |
| 1388 | DLOG2(("apollo_ctape_set_irq: state=%x", state )); |
| 1389 | apollo_pic_set_irq_line(device->machine().firstcpu, APOLLO_IRQ_CTAPE, state); |
| 1390 | } |
| 1391 | |
| 1392 | |
| 1393 | static void apollo_ctape_dma_drq(const device_t *device, int state) { |
| 1394 | DLOG2(("apollo_ctape_dma_drq: state=%x", state )); |
| 1395 | apollo_dma_ctape_drq(device->machine().firstcpu, state); |
| 1396 | } |
| 1397 | |
| 1398 | static const sc499_interface apollo_ctape_config = { |
| 1399 | apollo_ctape_set_irq, |
| 1400 | apollo_ctape_dma_drq, |
| 1401 | }; |
| 1402 | |
| 1403 | //########################################################################## |
| 1404 | // machine/apollo.c - APOLLO DS3500 CPU Board |
| 1405 | //########################################################################## |
| 1406 | |
| 1407 | #undef VERBOSE |
| 1408 | #define VERBOSE 0 |
| 1409 | |
| 1410 | MACHINE_CONFIG_FRAGMENT( apollo ) |
| 1411 | // configuration MUST be reset first ! |
| 1412 | MCFG_DEVICE_ADD(APOLLO_CONF_TAG, APOLLO_CONF, 0) |
| 1413 | |
| 1414 | MCFG_I8237_ADD( APOLLO_DMA1_TAG, XTAL_14_31818MHz/3, apollo_dma8237_1_config ) |
| 1415 | MCFG_I8237_ADD( APOLLO_DMA2_TAG, XTAL_14_31818MHz/3, apollo_dma8237_2_config ) |
| 1416 | MCFG_PIC8259_ADD( APOLLO_PIC1_TAG, apollo_pic8259_master_config ) |
| 1417 | MCFG_PIC8259_ADD( APOLLO_PIC2_TAG, apollo_pic8259_slave_config ) |
| 1418 | MCFG_PTM6840_ADD(APOLLO_PTM_TAG, apollo_ptm_config) |
| 1419 | MCFG_MC146818_ADD( APOLLO_RTC_TAG, MC146818_UTC ) |
| 1420 | MCFG_DUART68681_ADD( APOLLO_SIO_TAG, XTAL_3_6864MHz, apollo_sio_config ) |
| 1421 | MCFG_DUART68681_ADD( APOLLO_SIO2_TAG, XTAL_3_6864MHz, apollo_sio2_config ) |
| 1422 | |
| 1423 | MCFG_UPD765A_ADD(APOLLO_FDC_TAG, pc_fdc_upd765_connected_1_drive_interface) |
| 1424 | #ifdef MCFG_FLOPPY_DRIVE_ADD |
| 1425 | MCFG_FLOPPY_DRIVE_ADD(FLOPPY_0, apollo_fdc_floppy_config) |
| 1426 | #else |
| 1427 | MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, apollo_fdc_floppy_config) |
| 1428 | #endif |
| 1429 | MCFG_OMTI8621_ADD(APOLLO_WDC_TAG, apollo_wdc_config) |
| 1430 | MCFG_SC499_ADD(APOLLO_CTAPE_TAG, apollo_ctape_config) |
| 1431 | MCFG_THREECOM3C505_ADD(APOLLO_ETH_TAG, apollo_3c505_config) |
| 1432 | MACHINE_CONFIG_END |
| 1433 | |
| 1434 | DRIVER_INIT( apollo ) |
| 1435 | { |
| 1436 | MLOG1(("driver_init_apollo")); |
| 1437 | } |
| 1438 | |
| 1439 | MACHINE_START( apollo ) |
| 1440 | { |
| 1441 | MLOG1(("machine_start_apollo")); |
| 1442 | |
| 1443 | device_start_apollo_fdc (machine.device(APOLLO_FDC_TAG)); |
| 1444 | device_start_apollo_ptm (machine.device(APOLLO_PTM_TAG) ); |
| 1445 | device_start_apollo_sio(machine.device(APOLLO_SIO_TAG)); |
| 1446 | device_start_apollo_sio2(machine.device(APOLLO_SIO2_TAG)); |
| 1447 | |
| 1448 | if (apollo_is_dn3000()) |
| 1449 | { |
| 1450 | MLOG1(("faking mc146818 interrupts (DN3000 only)")); |
| 1451 | // fake mc146818 interrupts (DN3000 only) |
| 1452 | machine.scheduler().timer_pulse(attotime::from_hz(2), FUNC(apollo_rtc_timer)); |
| 1453 | } |
| 1454 | } |
| 1455 | |
| 1456 | MACHINE_RESET( apollo ) |
| 1457 | { |
| 1458 | apollo_state *st = machine.driver_data<apollo_state>(); |
| 1459 | MLOG1(("machine_reset_apollo")); |
| 1460 | |
| 1461 | st->dma8237_1 = machine.device(APOLLO_DMA1_TAG); |
| 1462 | st->dma8237_2 = machine.device(APOLLO_DMA2_TAG); |
| 1463 | st->pic8259_master = machine.device(APOLLO_PIC1_TAG); |
| 1464 | st->pic8259_slave = machine.device(APOLLO_PIC2_TAG); |
| 1465 | |
| 1466 | // set configuration |
| 1467 | apollo_csr_set_servicemode(apollo_config(APOLLO_CONF_SERVICE_MODE)); |
| 1468 | |
| 1469 | device_reset_apollo_ptm(machine.device(APOLLO_PTM_TAG)); |
| 1470 | device_reset_apollo_rtc(machine.device(APOLLO_RTC_TAG)); |
| 1471 | device_reset_apollo_sio(machine.device(APOLLO_SIO_TAG)); |
| 1472 | device_reset_apollo_sio2(machine.device(APOLLO_SIO2_TAG)); |
| 1473 | } |
src/mess/machine/3c505.c
| r0 | r14540 | |
| 1 | /* |
| 2 | * 3c505.c - 3COM 3C505 ethernet controller (for Apollo DN3x00) |
| 3 | * |
| 4 | * Created on: August 27, 2010 |
| 5 | * Author: Hans Ostermeyer |
| 6 | * |
| 7 | * Released for general non-commercial use under the MAME license |
| 8 | * Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | * |
| 10 | * see also: |
| 11 | * - http://lxr.free-electrons.com/source/drivers/net/3c505.h |
| 12 | * - http://lxr.free-electrons.com/source/drivers/net/3c505.c |
| 13 | * - http://stason.org/TULARC/pc/network-cards/O/OLIVETTI-Ethernet-NPU-9144-3C505.html |
| 14 | * - http://www.bitsavers.org/pdf/3Com/3C500_Mar83.pdf |
| 15 | */ |
| 16 | |
| 17 | #include "machine/3c505.h" |
| 18 | |
| 19 | #define VERBOSE 0 |
| 20 | |
| 21 | static int verbose = VERBOSE; |
| 22 | |
| 23 | #define LOG(x) { logerror ("%s: ", m_device->cpu_context()); logerror x; logerror ("\n"); } |
| 24 | #define LOG1(x) { if (verbose > 0) LOG(x)} |
| 25 | #define LOG2(x) { if (verbose > 1) LOG(x)} |
| 26 | |
| 27 | #define MAINCPU "maincpu" |
| 28 | |
| 29 | //************************************************************************** |
| 30 | // DEVICE DEFINITIONS |
| 31 | //************************************************************************** |
| 32 | |
| 33 | //const device_type THREECOM3C505 = threecom3c505_device_config::static_alloc_device_config; |
| 34 | |
| 35 | //************************************************************************** |
| 36 | // CONSTANTS |
| 37 | //************************************************************************** |
| 38 | |
| 39 | // Apollo microcode version |
| 40 | #define APOLLO_MC_VERSION_SR10_2 0x0302 |
| 41 | #define APOLLO_MC_VERSION_SR10_4 0x0303 |
| 42 | |
| 43 | #define PORT_DATA_FIFO_SIZE 20 |
| 44 | |
| 45 | /* |
| 46 | * I/O register offsets |
| 47 | */ |
| 48 | #define PORT_COMMAND 0x00 /* read/write, 8-bit */ |
| 49 | #define PORT_STATUS 0x02 /* read only, 8-bit */ |
| 50 | #define PORT_AUXDMA 0x02 /* write only, 8-bit */ |
| 51 | #define PORT_DATA 0x04 /* read/write, 16-bit */ |
| 52 | #define PORT_CONTROL 0x06 /* read/write, 8-bit */ |
| 53 | |
| 54 | #define ELP_IO_EXTENT 0x10 /* size of used IO registers */ |
| 55 | |
| 56 | /* |
| 57 | * host control registers bits |
| 58 | */ |
| 59 | #define ATTN 0x80 /* attention */ |
| 60 | #define FLSH 0x40 /* flush data register */ |
| 61 | #define DMAE 0x20 /* DMA enable */ |
| 62 | #define DIR_ 0x10 /* direction */ |
| 63 | #define TCEN 0x08 /* terminal count interrupt enable */ |
| 64 | #define CMDE 0x04 /* command register interrupt enable */ |
| 65 | #define HSF2 0x02 /* host status flag 2 */ |
| 66 | #define HSF1 0x01 /* host status flag 1 */ |
| 67 | |
| 68 | /* |
| 69 | * combinations of HSF flags used for PCB transmission |
| 70 | */ |
| 71 | #define HSF_PCB_ACK HSF1 |
| 72 | #define HSF_PCB_NAK HSF2 |
| 73 | #define HSF_PCB_END (HSF2|HSF1) |
| 74 | #define HSF_PCB_MASK (HSF2|HSF1) |
| 75 | |
| 76 | /* |
| 77 | * host status register bits |
| 78 | */ |
| 79 | #define HRDY 0x80 /* data register ready */ |
| 80 | #define HCRE 0x40 /* command register empty */ |
| 81 | #define ACRF 0x20 /* adapter command register full */ |
| 82 | /* #define DIR_ 0x10 direction - same as in control register */ |
| 83 | #define DONE 0x08 /* DMA done */ |
| 84 | #define ASF3 0x04 /* adapter status flag 3 */ |
| 85 | #define ASF2 0x02 /* adapter status flag 2 */ |
| 86 | #define ASF1 0x01 /* adapter status flag 1 */ |
| 87 | |
| 88 | /* |
| 89 | * combinations of ASF flags used for PCB reception |
| 90 | */ |
| 91 | #define ASF_PCB_ACK ASF1 |
| 92 | #define ASF_PCB_NAK ASF2 |
| 93 | #define ASF_PCB_END (ASF2|ASF1) |
| 94 | #define ASF_PCB_MASK (ASF3|ASF2|ASF1) |
| 95 | |
| 96 | /* |
| 97 | * host aux DMA register bits |
| 98 | */ |
| 99 | #define DMA_BRST 0x01 /* DMA burst */ |
| 100 | |
| 101 | /* |
| 102 | * maximum amount of data allowed in a PCB |
| 103 | */ |
| 104 | #define MAX_PCB_DATA 62 |
| 105 | |
| 106 | #define CMD_RESPONSE_OFFSET 0x30 |
| 107 | enum |
| 108 | { |
| 109 | /* host PCB commands */ |
| 110 | CMD_CONFIGURE_ADAPTER_MEMORY = 0x01, |
| 111 | CMD_CONFIGURE_82586 = 0x02, |
| 112 | CMD_STATION_ADDRESS = 0x03, |
| 113 | CMD_DMA_DOWNLOAD = 0x04, |
| 114 | CMD_DMA_UPLOAD = 0x05, |
| 115 | CMD_PIO_DOWNLOAD = 0x06, |
| 116 | CMD_PIO_UPLOAD = 0x07, |
| 117 | CMD_RECEIVE_PACKET = 0x08, |
| 118 | CMD_TRANSMIT_PACKET = 0x09, |
| 119 | CMD_NETWORK_STATISTICS = 0x0a, |
| 120 | CMD_LOAD_MULTICAST_LIST = 0x0b, |
| 121 | CMD_CLEAR_PROGRAM = 0x0c, |
| 122 | CMD_DOWNLOAD_PROGRAM = 0x0d, |
| 123 | CMD_EXECUTE_PROGRAM = 0x0e, |
| 124 | CMD_SELF_TEST = 0x0f, |
| 125 | CMD_SET_STATION_ADDRESS = 0x10, |
| 126 | CMD_ADAPTER_INFO = 0x11, |
| 127 | |
| 128 | CMD_MC_17 = 0x17, |
| 129 | CMD_TRANSMIT_PACKET_18 = 0x18, |
| 130 | CMD_MC_F8 =0xf8, |
| 131 | CMD_MC_F9 =0xf9, |
| 132 | CMD_MC_FA =0xfa, |
| 133 | |
| 134 | /*adapter PCB commands */ |
| 135 | CMD_CONFIGURE_ADAPTER_RESPONSE = 0x31, |
| 136 | CMD_CONFIGURE_82586_RESPONSE = 0x32, |
| 137 | CMD_ADDRESS_RESPONSE = 0x33, |
| 138 | CMD_DOWNLOAD_DATA_REQUEST = 0x34, |
| 139 | CMD_UPLOAD_DATA_REQUEST = 0x35, |
| 140 | CMD_RECEIVE_PACKET_COMPLETE = 0x38, |
| 141 | CMD_TRANSMIT_PACKET_COMPLETE = 0x39, |
| 142 | CMD_NETWORK_STATISTICS_RESPONSE = 0x3a, |
| 143 | CMD_LOAD_MULTICAST_RESPONSE = 0x3b, |
| 144 | CMD_CLEAR_PROGRAM_RESPONSE = 0x3c, |
| 145 | CMD_DOWNLOAD_PROGRAM_RESPONSE = 0x3d, |
| 146 | CMD_EXECUTE_PROGRAM_RESPONSE = 0x3e, |
| 147 | CMD_SELF_TEST_RESPONSE = 0x3f, |
| 148 | CMD_SET_ADDRESS_RESPONSE = 0x40, |
| 149 | CMD_ADAPTER_INFO_RESPONSE = 0x41, |
| 150 | |
| 151 | CMD_MC_17_COMPLETE = 0x47, |
| 152 | CMD_TRANSMIT_PACKET_18_COMPLETE = 0x48, |
| 153 | |
| 154 | CMD_MC_E1_RESPONSE = 0xe1, |
| 155 | CMD_MC_E2_RESPONSE = 0xe2 |
| 156 | }; |
| 157 | |
| 158 | /* These defines for 'configure' */ |
| 159 | #define RECV_STATION 0x00 |
| 160 | #define RECV_BROAD 0x01 |
| 161 | #define RECV_MULTI 0x02 |
| 162 | #define RECV_PROMISC 0x04 |
| 163 | #define NO_LOOPBACK 0x00 |
| 164 | #define INT_LOOPBACK 0x08 |
| 165 | #define EXT_LOOPBACK 0x10 |
| 166 | |
| 167 | // FIXME: |
| 168 | // #define lsb_first(a) (((a & 255) << 8) | ((a >>8) & 255)) |
| 169 | #define lsb_first(a) (a) |
| 170 | |
| 171 | /*************************************************************************** |
| 172 | IMPLEMENTATION |
| 173 | ***************************************************************************/ |
| 174 | |
| 175 | // device type definition |
| 176 | const device_type THREECOM3C505 = &device_creator<threecom3c505_device>; |
| 177 | |
| 178 | //------------------------------------------------- |
| 179 | // sc499_device - constructor |
| 180 | //------------------------------------------------- |
| 181 | |
| 182 | threecom3c505_device::threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 183 | : device_t(mconfig, THREECOM3C505, "Threecom 3C505", tag, owner, clock) |
| 184 | { |
| 185 | memset(static_cast<threecom3c505_interface *>(this), 0, sizeof(threecom3c505_interface)); |
| 186 | } |
| 187 | |
| 188 | //------------------------------------------------- |
| 189 | // static_set_interface - set the interface struct |
| 190 | //------------------------------------------------- |
| 191 | |
| 192 | void threecom3c505_device::static_set_interface(device_t &device, const threecom3c505_interface &interface) |
| 193 | { |
| 194 | threecom3c505_device &threecom3c505 = downcast<threecom3c505_device &>(device); |
| 195 | static_cast<threecom3c505_interface &>(threecom3c505) = interface; |
| 196 | } |
| 197 | |
| 198 | //------------------------------------------------- |
| 199 | // device_start - device-specific startup |
| 200 | //------------------------------------------------- |
| 201 | |
| 202 | void threecom3c505_device::device_start() |
| 203 | { |
| 204 | m_device = this; |
| 205 | LOG1(("start 3COM 3C505")); |
| 206 | |
| 207 | m_rx_fifo.start(this, RX_FIFO_SIZE, ETH_BUFFER_SIZE); |
| 208 | m_rx_data_buffer.start(this, ETH_BUFFER_SIZE); |
| 209 | m_tx_data_buffer.start(this, ETH_BUFFER_SIZE); |
| 210 | m_program_buffer.start(this, PGM_BUFFER_SIZE); |
| 211 | |
| 212 | if (tx_init != NULL) |
| 213 | { |
| 214 | (*tx_init)(this); |
| 215 | } |
| 216 | |
| 217 | m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_set_interrupt), this); |
| 218 | } |
| 219 | |
| 220 | //------------------------------------------------- |
| 221 | // device_reset - device-specific reset |
| 222 | //------------------------------------------------- |
| 223 | |
| 224 | void threecom3c505_device::device_reset() |
| 225 | { |
| 226 | LOG1(("reset 3COM 3C505")); |
| 227 | |
| 228 | m_rx_fifo.reset(); |
| 229 | m_rx_data_buffer.reset(); |
| 230 | m_tx_data_buffer.reset(); |
| 231 | m_program_buffer.reset(); |
| 232 | |
| 233 | memset(m_reg, 0, sizeof(m_reg)); |
| 234 | m_status = HCRE; |
| 235 | m_control = 0; |
| 236 | m_command_index = 0; |
| 237 | m_command_pending = 0; |
| 238 | m_rx_data_index = 0; |
| 239 | m_rx_pending = 0; |
| 240 | m_tx_data_length = 0; |
| 241 | m_response_length = 0; |
| 242 | m_response_index = 0; |
| 243 | m_microcode_running = 0; |
| 244 | m_microcode_version = 0; |
| 245 | m_i82586_config = 0; |
| 246 | memset(m_station_address, 0 , sizeof(m_station_address)); |
| 247 | memset(m_multicast_list, 0 , sizeof(m_multicast_list)); |
| 248 | set_filter_list(); |
| 249 | } |
| 250 | |
| 251 | /*************************************************************************** |
| 252 | cpu_context - return a string describing the current CPU context |
| 253 | ***************************************************************************/ |
| 254 | |
| 255 | const char *threecom3c505_device::cpu_context() |
| 256 | { |
| 257 | static char statebuf[64]; /* string buffer containing state description */ |
| 258 | |
| 259 | device_t *cpu = machine().device(MAINCPU); |
| 260 | osd_ticks_t t = osd_ticks(); |
| 261 | int s = t / osd_ticks_per_second(); |
| 262 | int ms = (t % osd_ticks_per_second()) / 1000; |
| 263 | |
| 264 | /* if we have an executing CPU, output data */ |
| 265 | if (cpu != NULL) |
| 266 | { |
| 267 | sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(), |
| 268 | cpu_get_previouspc(cpu), tag()); |
| 269 | } |
| 270 | else |
| 271 | { |
| 272 | sprintf(statebuf, "%d.%03d", s, ms); |
| 273 | } |
| 274 | return statebuf; |
| 275 | } |
| 276 | |
| 277 | //************************************************************************** |
| 278 | // data_buffer |
| 279 | //************************************************************************** |
| 280 | |
| 281 | threecom3c505_device::data_buffer::data_buffer() : |
| 282 | m_device(NULL), |
| 283 | m_size(0L), |
| 284 | m_data(NULL) |
| 285 | { |
| 286 | } |
| 287 | |
| 288 | void threecom3c505_device::data_buffer::start(threecom3c505_device *device, INT32 size) |
| 289 | { |
| 290 | m_device = device; |
| 291 | LOG2(("start threecom3c505_device::data_buffer with size %0x", size)); |
| 292 | m_size = size; |
| 293 | m_data = auto_alloc_array(device->machine(), UINT8, size); |
| 294 | } |
| 295 | |
| 296 | void threecom3c505_device::data_buffer::reset() |
| 297 | { |
| 298 | LOG2(("reset threecom3c505_device::data_buffer")); |
| 299 | m_length = 0; |
| 300 | } |
| 301 | |
| 302 | void threecom3c505_device::data_buffer::copy(data_buffer *db) const |
| 303 | { |
| 304 | db->m_size = m_size; |
| 305 | db->m_length = m_length; |
| 306 | memcpy(db->m_data, m_data, m_size); |
| 307 | } |
| 308 | |
| 309 | int threecom3c505_device::data_buffer::append(UINT8 data) |
| 310 | { |
| 311 | if (m_length >= m_size) |
| 312 | { |
| 313 | return 0; |
| 314 | } |
| 315 | else |
| 316 | { |
| 317 | m_data[m_length++] = data; |
| 318 | return 1; |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | void threecom3c505_device::data_buffer::log(const char * title) const |
| 323 | { |
| 324 | if (verbose > 0) |
| 325 | { |
| 326 | int i; |
| 327 | logerror("%s: %s (length=%02x)", m_device->cpu_context(), title, m_length); |
| 328 | for (i = 0; i < m_length; i++) |
| 329 | { |
| 330 | logerror(" %02x", m_data[i]); |
| 331 | if (i >= 1023) |
| 332 | { |
| 333 | logerror(" ..."); |
| 334 | break; |
| 335 | } |
| 336 | } |
| 337 | logerror("\n"); |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | //************************************************************************** |
| 342 | // data_buffer fifo |
| 343 | //************************************************************************** |
| 344 | |
| 345 | threecom3c505_device::data_buffer_fifo::data_buffer_fifo() : |
| 346 | m_device(NULL), |
| 347 | m_size(0) |
| 348 | { |
| 349 | } |
| 350 | |
| 351 | void threecom3c505_device::data_buffer_fifo::start( |
| 352 | threecom3c505_device *device, INT32 size, INT32 db_size) |
| 353 | { |
| 354 | m_device = device; |
| 355 | LOG2(("start threecom3c505_device::data_buffer_fifo")); |
| 356 | |
| 357 | int i; |
| 358 | // FIXME: fifo size is hardcoded |
| 359 | m_size = RX_FIFO_SIZE; // size; |
| 360 | for (i = 0; i < m_size; i++) |
| 361 | { |
| 362 | m_db[i] = new data_buffer(); |
| 363 | m_db[i]->start(device, db_size); |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | void threecom3c505_device::data_buffer_fifo::reset() |
| 368 | { |
| 369 | LOG2(("reset threecom3c505_device::data_buffer_fifo")); |
| 370 | m_get_index = m_put_index = 0; |
| 371 | m_count = 0; |
| 372 | } |
| 373 | |
| 374 | int threecom3c505_device::data_buffer_fifo::put(const UINT8 data[], const int length) |
| 375 | { |
| 376 | UINT16 next_index = (m_put_index + 1) % m_size; |
| 377 | |
| 378 | LOG2(("threecom3c505_device::data_buffer_fifo::put %d", m_count)); |
| 379 | |
| 380 | if (next_index == m_get_index) |
| 381 | { |
| 382 | // overflow, fifo full |
| 383 | return 0; |
| 384 | } |
| 385 | else |
| 386 | { |
| 387 | memcpy(m_db[m_put_index]->m_data, data, length); |
| 388 | m_db[m_put_index]->m_length = length; |
| 389 | m_put_index = next_index; |
| 390 | m_count++; |
| 391 | return 1; |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | int threecom3c505_device::data_buffer_fifo::get(data_buffer *db) |
| 396 | { |
| 397 | LOG2(("threecom3c505_device::data_buffer_fifo::get %d", m_count)); |
| 398 | |
| 399 | if (m_get_index == m_put_index) |
| 400 | { |
| 401 | // fifo empty |
| 402 | return 0; |
| 403 | } |
| 404 | else |
| 405 | { |
| 406 | m_db[m_get_index]->copy(db); |
| 407 | m_get_index = (m_get_index + 1) % m_size; |
| 408 | m_count--; |
| 409 | return 1; |
| 410 | } |
| 411 | } |
| 412 | |
| 413 | /*------------------------------------------------- |
| 414 | set_filter_list - set the ethernet packet filter list |
| 415 | -------------------------------------------------*/ |
| 416 | |
| 417 | void threecom3c505_device::set_filter_list() |
| 418 | { |
| 419 | memset(m_filter_list, 0 , sizeof(m_filter_list)); |
| 420 | memcpy(m_filter_list, m_station_address, ETHERNET_ADDR_SIZE); |
| 421 | memset(m_filter_list+ETHERNET_ADDR_SIZE,0xff, ETHERNET_ADDR_SIZE); |
| 422 | memcpy(m_filter_list+ETHERNET_ADDR_SIZE*2, m_multicast_list, sizeof(m_multicast_list)); |
| 423 | |
| 424 | if (setfilter != NULL) |
| 425 | { |
| 426 | int node_id = (((m_station_address[3] << 8) + m_station_address[4]) << 8) + m_station_address[5]; |
| 427 | LOG1(("set_filter_list node_id=%x",node_id)); |
| 428 | (*setfilter)(this, node_id); |
| 429 | } |
| 430 | |
| 431 | } |
| 432 | |
| 433 | /*------------------------------------------------- |
| 434 | set_interrupt - set the IRQ state |
| 435 | -------------------------------------------------*/ |
| 436 | |
| 437 | void threecom3c505_device::set_interrupt(enum line_state state) |
| 438 | { |
| 439 | if (state != irq_state) |
| 440 | { |
| 441 | LOG1(("set_interrupt(%d)",state)); |
| 442 | if (set_irq != NULL) |
| 443 | { |
| 444 | (*set_irq)(this, state); |
| 445 | } |
| 446 | irq_state = state; |
| 447 | |
| 448 | // FIXME: hack? |
| 449 | if ( m_command_buffer[0] == CMD_EXECUTE_PROGRAM && state == 1) |
| 450 | { |
| 451 | m_status |= ASF_PCB_END; |
| 452 | } |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | TIMER_CALLBACK( threecom3c505_device::static_set_interrupt ) |
| 457 | { |
| 458 | reinterpret_cast<threecom3c505_device *> (ptr)->set_interrupt(ASSERT_LINE); |
| 459 | } |
| 460 | |
| 461 | // ------------------------------------- |
| 462 | |
| 463 | void threecom3c505_device::log_command() |
| 464 | { |
| 465 | if (verbose > 0) |
| 466 | { |
| 467 | int i; |
| 468 | logerror("%s: Command ", cpu_context()); |
| 469 | switch (m_command_buffer[0]) |
| 470 | { |
| 471 | case CMD_CONFIGURE_ADAPTER_MEMORY: // 0x01 |
| 472 | logerror("CMD_CONFIGURE_ADAPTER_MEMORY"); |
| 473 | break; |
| 474 | case CMD_CONFIGURE_82586: // 0x02 |
| 475 | logerror("CMD_CONFIGURE_82586"); |
| 476 | break; |
| 477 | case CMD_RECEIVE_PACKET: // 0x08 |
| 478 | logerror("CMD_RECEIVE_PACKET"); |
| 479 | break; |
| 480 | case CMD_TRANSMIT_PACKET: // 0x09 |
| 481 | logerror("CMD_TRANSMIT_PACKET"); |
| 482 | break; |
| 483 | case CMD_NETWORK_STATISTICS: // 0x0a |
| 484 | logerror("CMD_NETWORK_STATISTICS"); |
| 485 | break; |
| 486 | case CMD_LOAD_MULTICAST_LIST: // 0x0b, |
| 487 | logerror("CMD_LOAD_MULTICAST_LIST"); |
| 488 | break; |
| 489 | case CMD_CLEAR_PROGRAM: // 0x0c |
| 490 | logerror("!!! Unexpected CMD_CLEAR_PROGRAM"); |
| 491 | break; |
| 492 | case CMD_DOWNLOAD_PROGRAM: // 0x0d |
| 493 | logerror("CMD_DOWNLOAD_PROGRAM"); |
| 494 | break; |
| 495 | case CMD_EXECUTE_PROGRAM: // 0x0e |
| 496 | logerror("CMD_EXECUTE_PROGRAM"); |
| 497 | break; |
| 498 | case CMD_SET_STATION_ADDRESS: // 0x10 |
| 499 | logerror("CMD_SET_STATION_ADDRESS"); |
| 500 | break; |
| 501 | case CMD_ADAPTER_INFO: // 0x11 |
| 502 | logerror("CMD_ADAPTER_INFO"); |
| 503 | break; |
| 504 | case CMD_MC_17: // 0x17 |
| 505 | logerror("CMD_MC_17"); |
| 506 | break; |
| 507 | case CMD_TRANSMIT_PACKET_18: // 0x18 |
| 508 | logerror("CMD_TRANSMIT_PACKET_18"); |
| 509 | break; |
| 510 | |
| 511 | case CMD_MC_F8: // 0xf8 |
| 512 | logerror("CMD_MC_F8"); |
| 513 | break; |
| 514 | case CMD_MC_F9: // 0xf9 |
| 515 | logerror("CMD_MC_F9"); |
| 516 | break; |
| 517 | case CMD_MC_FA: // 0xfa |
| 518 | logerror("CMD_MC_FA"); |
| 519 | break; |
| 520 | |
| 521 | default: |
| 522 | logerror("!!! Unexpected Command !!!"); |
| 523 | } |
| 524 | |
| 525 | switch (m_command_buffer[0]) |
| 526 | { |
| 527 | case CMD_MC_F9: // 0xf9 |
| 528 | // logerror(" (%02x, length=00)", m_command_buffer[0]); |
| 529 | break; |
| 530 | |
| 531 | default: |
| 532 | logerror(" (%02x, length=%02x)", m_command_buffer[0], |
| 533 | m_command_buffer[1]); |
| 534 | for (i = 2; i < m_command_index; i++) |
| 535 | { |
| 536 | logerror(" %02x", m_command_buffer[i]); |
| 537 | } |
| 538 | break; |
| 539 | } |
| 540 | logerror("\n"); |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | void threecom3c505_device::log_response() |
| 545 | { |
| 546 | if (verbose > 0) |
| 547 | { |
| 548 | int i; |
| 549 | logerror("%s: Response ", cpu_context()); |
| 550 | switch (m_response.command) |
| 551 | { |
| 552 | case CMD_CONFIGURE_ADAPTER_RESPONSE: // 0x31 |
| 553 | logerror("CMD_CONFIGURE_ADAPTER_RESPONSE"); |
| 554 | break; |
| 555 | case CMD_CONFIGURE_82586_RESPONSE: // 0x32 |
| 556 | logerror("CMD_CONFIGURE_82586_RESPONSE"); |
| 557 | break; |
| 558 | case CMD_RECEIVE_PACKET_COMPLETE: // 0x38 |
| 559 | logerror("CMD_RECEIVE_PACKET_COMPLETE"); |
| 560 | break; |
| 561 | case CMD_TRANSMIT_PACKET_COMPLETE: // 0x39 |
| 562 | logerror("CMD_TRANSMIT_PACKET_COMPLETE"); |
| 563 | break; |
| 564 | case CMD_NETWORK_STATISTICS_RESPONSE: // 0x3a |
| 565 | logerror("CMD_NETWORK_STATISTICS_RESPONSE"); |
| 566 | break; |
| 567 | case CMD_LOAD_MULTICAST_RESPONSE: // 0x3b |
| 568 | logerror("CMD_LOAD_MULTICAST_RESPONSE"); |
| 569 | break; |
| 570 | case CMD_DOWNLOAD_PROGRAM_RESPONSE: // 0x3d |
| 571 | logerror("CMD_DOWNLOAD_PROGRAM_RESPONSE"); |
| 572 | break; |
| 573 | case CMD_EXECUTE_PROGRAM_RESPONSE: // 0x3e |
| 574 | logerror("CMD_EXECUTE_PROGRAM_RESPONSE"); |
| 575 | break; |
| 576 | case CMD_SET_ADDRESS_RESPONSE: // 0x40 |
| 577 | logerror("CMD_SET_ADDRESS_RESPONSE"); |
| 578 | break; |
| 579 | case CMD_ADAPTER_INFO_RESPONSE: // 0x41 |
| 580 | logerror("CMD_ADAPTER_INFO_RESPONSE"); |
| 581 | break; |
| 582 | case CMD_MC_17_COMPLETE: // 0x47 |
| 583 | logerror("CMD_MC_17_COMPLETE"); |
| 584 | break; |
| 585 | case CMD_TRANSMIT_PACKET_18_COMPLETE: // 0x48 |
| 586 | logerror("CMD_TRANSMIT_PACKET_18_COMPLETE"); |
| 587 | break; |
| 588 | case CMD_MC_E1_RESPONSE: // 0xe1 |
| 589 | logerror("CMD_MC_E1_RESPONSE"); |
| 590 | break; |
| 591 | case CMD_MC_E2_RESPONSE: // 0xe2 |
| 592 | logerror("CMD_MC_E2_RESPONSE"); |
| 593 | break; |
| 594 | default: |
| 595 | logerror("!!! Unexpected Response !!!"); |
| 596 | } |
| 597 | logerror(" (%02x, length=%02x)", m_response.command, m_response.length); |
| 598 | for (i = 0; i < m_response.length; i++) |
| 599 | { |
| 600 | logerror(" %02x", m_response.data.raw[i]); |
| 601 | } |
| 602 | logerror("\n"); |
| 603 | } |
| 604 | } |
| 605 | |
| 606 | void threecom3c505_device::do_receive_command() |
| 607 | { |
| 608 | LOG2(("do_receive_command - data_length=%x rx_pending=%d", |
| 609 | m_rx_data_buffer.get_length(), m_rx_pending)); |
| 610 | #if 0 |
| 611 | if (m_microcode_running && m_microcode_version == APOLLO_MC_VERSION_SR10_4) |
| 612 | { |
| 613 | m_response.command = CMD_MC_E1_RESPONSE; |
| 614 | m_response.length = 0; |
| 615 | m_response_length = 0; |
| 616 | m_response_index = 0; |
| 617 | |
| 618 | m_rx_pending++; |
| 619 | } |
| 620 | else |
| 621 | #endif |
| 622 | |
| 623 | { |
| 624 | m_response.command = CMD_RECEIVE_PACKET_COMPLETE; // 0x38 |
| 625 | m_response.length = 16; |
| 626 | m_response.data.rcv_resp.buf_ofs = 0; |
| 627 | m_response.data.rcv_resp.buf_seg = 0; |
| 628 | m_response.data.rcv_resp.buf_len = m_rx_data_buffer.get_length(); |
| 629 | m_response.data.rcv_resp.pkt_len = m_rx_data_buffer.get_length(); // (?) |
| 630 | m_response.data.rcv_resp.timeout = 0; // successful completion |
| 631 | m_response.data.rcv_resp.status = m_rx_data_buffer.get_length() > 0 ? 0 : 0xffff; |
| 632 | m_response.data.rcv_resp.timetag = 0L; // TODO |
| 633 | |
| 634 | m_response_length = m_response.length + 2; |
| 635 | m_response_index = 0; |
| 636 | } |
| 637 | |
| 638 | m_status |= ACRF; /* adapter command register full */ |
| 639 | |
| 640 | if (m_control & CMDE) |
| 641 | { |
| 642 | LOG2(("do_receive_command - set_interrupt(%d)", ASSERT_LINE)); |
| 643 | // set_interrupt(ASSERT_LINE); |
| 644 | |
| 645 | // interrupt later |
| 646 | m_timer->adjust( attotime::from_usec(10)); |
| 647 | } |
| 648 | } |
| 649 | |
| 650 | void threecom3c505_device::set_command_pending(int onoff) |
| 651 | { |
| 652 | m_command_pending = onoff; |
| 653 | LOG1(("set_command_pending %d m_rx_pending=%d m_rx_data_buffer.get_length()=%x%s", m_command_pending, m_rx_pending, m_rx_data_buffer.get_length(), onoff ? "" :"\n")); |
| 654 | |
| 655 | if (!m_command_pending) |
| 656 | { |
| 657 | // clear previous command byte |
| 658 | m_command_buffer[0] = 0; |
| 659 | |
| 660 | if (m_rx_pending > 0 && m_rx_data_buffer.get_length() > 0) |
| 661 | { |
| 662 | m_rx_pending--; |
| 663 | m_command_pending = 1; |
| 664 | |
| 665 | LOG1(("set_command_pending %d m_rx_pending=%d", m_command_pending, m_rx_pending)); |
| 666 | |
| 667 | do_receive_command(); |
| 668 | } |
| 669 | } |
| 670 | } |
| 671 | |
| 672 | /*************************************************************************** |
| 673 | do_command |
| 674 | ***************************************************************************/ |
| 675 | |
| 676 | void threecom3c505_device::do_command() |
| 677 | { |
| 678 | // default to successful completion |
| 679 | m_response.command = m_command_buffer[0] + CMD_RESPONSE_OFFSET; |
| 680 | m_response.length = 1; |
| 681 | m_response.data.failed = 0; // successful completion |
| 682 | |
| 683 | switch (m_command_buffer[0]) |
| 684 | { |
| 685 | case CMD_CONFIGURE_ADAPTER_MEMORY: // 0x01 |
| 686 | m_i82586_config = m_program_buffer.get_word(1); |
| 687 | break; |
| 688 | |
| 689 | // case CMD_MC_F8: |
| 690 | case CMD_RECEIVE_PACKET: // 0x08 |
| 691 | if (m_rx_data_buffer.get_length() == 0 && !m_rx_fifo.get(&m_rx_data_buffer)) |
| 692 | { |
| 693 | m_rx_pending++; |
| 694 | set_command_pending(0); |
| 695 | } |
| 696 | else |
| 697 | { |
| 698 | do_receive_command(); |
| 699 | } |
| 700 | return; |
| 701 | // break; |
| 702 | |
| 703 | // case CMD_MC_F8: |
| 704 | case CMD_MC_F9: |
| 705 | // case CMD_MC_FA: |
| 706 | // FIXME: |
| 707 | m_response.command = CMD_TRANSMIT_PACKET_COMPLETE; |
| 708 | // break; |
| 709 | |
| 710 | case CMD_TRANSMIT_PACKET: // 0x09 |
| 711 | case CMD_TRANSMIT_PACKET_18: // 0x18 |
| 712 | m_response.length = 8; |
| 713 | m_response.data.xmit_resp.buf_ofs = 0; |
| 714 | m_response.data.xmit_resp.buf_seg = 0; |
| 715 | m_response.data.xmit_resp.c_stat = 0; // successful completion |
| 716 | m_response.data.xmit_resp.status = 0; |
| 717 | break; |
| 718 | |
| 719 | case CMD_EXECUTE_PROGRAM: // 0x0e |
| 720 | m_response.length = 0; |
| 721 | m_microcode_running = 1; |
| 722 | m_microcode_version = m_program_buffer.get_word(1); |
| 723 | break; |
| 724 | |
| 725 | case CMD_NETWORK_STATISTICS: // 0x0a |
| 726 | m_response.length = sizeof(struct Netstat); |
| 727 | // FIXME: replace test data; must be LSB first! |
| 728 | m_response.data.netstat.tot_recv = 1; |
| 729 | m_response.data.netstat.tot_xmit = 2; |
| 730 | m_response.data.netstat.err_CRC = 3; |
| 731 | m_response.data.netstat.err_align = 4; |
| 732 | m_response.data.netstat.err_res = 5; |
| 733 | m_response.data.netstat.err_ovrrun = 6; |
| 734 | break; |
| 735 | |
| 736 | case CMD_ADAPTER_INFO: // 0x11 |
| 737 | m_response.length = sizeof(struct Info); |
| 738 | // FIXME: replace test data; must be LSB first! |
| 739 | m_response.data.info.minor_vers = 1; |
| 740 | m_response.data.info.major_vers = 2; |
| 741 | m_response.data.info.ROM_cksum = lsb_first(3); |
| 742 | m_response.data.info.RAM_sz = lsb_first(4); |
| 743 | m_response.data.info.free_ofs = lsb_first(5); |
| 744 | m_response.data.info.free_seg = lsb_first(6); |
| 745 | break; |
| 746 | |
| 747 | case CMD_LOAD_MULTICAST_LIST:// 0x0b |
| 748 | if (m_command_buffer[1] > sizeof(m_multicast_list) || |
| 749 | (m_command_buffer[1] % ETHERNET_ADDR_SIZE) != 0) |
| 750 | { |
| 751 | LOG(("CMD_LOAD_MULTICAST_LIST - !!! unexpected data size %d !!!", m_command_buffer[1])); |
| 752 | } |
| 753 | else |
| 754 | { |
| 755 | memset(m_multicast_list, 0 , sizeof(m_multicast_list)); |
| 756 | memcpy(m_multicast_list, m_command_buffer+2 , m_command_buffer[1]-2); |
| 757 | set_filter_list(); |
| 758 | } |
| 759 | break; |
| 760 | |
| 761 | case CMD_SET_STATION_ADDRESS: // 0x10 |
| 762 | if (m_command_buffer[1] != sizeof(m_station_address)) |
| 763 | { |
| 764 | LOG(("CMD_SET_STATION_ADDRESS - !!! unexpected data size %d !!!", m_command_buffer[1])); |
| 765 | memset(m_station_address, 0 , sizeof(m_station_address)); |
| 766 | } |
| 767 | else |
| 768 | { |
| 769 | memcpy(m_station_address, m_command_buffer+2 , m_command_buffer[1]); |
| 770 | } |
| 771 | set_filter_list(); |
| 772 | break; |
| 773 | |
| 774 | case CMD_CONFIGURE_82586: // 0x02 |
| 775 | case CMD_DOWNLOAD_PROGRAM: // 0x0d |
| 776 | case CMD_MC_17: // 0x17 |
| 777 | default: |
| 778 | break; |
| 779 | } |
| 780 | |
| 781 | m_response_index = 0; |
| 782 | m_response_length = m_response.length + 2; |
| 783 | m_status |= ACRF; /* adapter command register full */ |
| 784 | |
| 785 | if (m_control & CMDE) |
| 786 | { |
| 787 | switch (m_command_buffer[0]) |
| 788 | { |
| 789 | case CMD_NETWORK_STATISTICS: // 0x0a |
| 790 | case CMD_DOWNLOAD_PROGRAM: // 0xd |
| 791 | case CMD_EXECUTE_PROGRAM: // 0x0e |
| 792 | case CMD_ADAPTER_INFO: // 0x11 |
| 793 | // interrupt later |
| 794 | m_timer->adjust( attotime::from_msec(10)); |
| 795 | break; |
| 796 | |
| 797 | default: |
| 798 | // interrupt at once |
| 799 | set_interrupt(ASSERT_LINE); |
| 800 | break; |
| 801 | } |
| 802 | } |
| 803 | } |
| 804 | |
| 805 | /*************************************************************************** |
| 806 | ethernet_packet_is_for_me - check if ethernet address is for me |
| 807 | ***************************************************************************/ |
| 808 | |
| 809 | int threecom3c505_device::ethernet_packet_is_for_me(const UINT8 mac_address[]) |
| 810 | { |
| 811 | // tcpdump -i eth0 -q ether host 08:00:1e:01:ae:a5 or ether broadcast or ether dst 09:00:1e:00:00:00 or ether dst 09:00:1e:00:00:01 |
| 812 | // wireshark filter: eth.addr eq 08:00:1e:01:ae:a5 or eth.dst eq ff:ff:ff:ff:ff:ff or eth.dst eq 09:00:1e:00:00:00 or eth.dst eq 09:00:1e:00:00:01 |
| 813 | |
| 814 | int i; |
| 815 | for (i = 0; i + ETHERNET_ADDR_SIZE < sizeof(m_filter_list); i += ETHERNET_ADDR_SIZE) |
| 816 | { |
| 817 | if (memcmp(mac_address, m_filter_list + i, ETHERNET_ADDR_SIZE) == 0) |
| 818 | { |
| 819 | return 1; |
| 820 | } |
| 821 | } |
| 822 | return 0; |
| 823 | } |
| 824 | |
| 825 | /*************************************************************************** |
| 826 | threecom3c505_receive - receive and process an ethernet packet |
| 827 | ***************************************************************************/ |
| 828 | |
| 829 | int threecom3c505_device::threecom3c505_receive(const UINT8 data[], int length) |
| 830 | { |
| 831 | if (length < ETHERNET_ADDR_SIZE || !ethernet_packet_is_for_me(data)) |
| 832 | { |
| 833 | // skip packet |
| 834 | return 0; |
| 835 | } |
| 836 | // else if (m_command_pending && m_command_buffer[0] == CMD_MC_F9) |
| 837 | // { |
| 838 | // LOG(("threecom3c505_receive: data_length=%x !!!! skipped data while CMD_MC_F9 is pending!", length)); |
| 839 | // return 0; |
| 840 | // } |
| 841 | else if (!m_rx_fifo.put(data, length)) |
| 842 | { |
| 843 | // fifo overrun |
| 844 | LOG1(("threecom3c505_receive: data_length=%x !!! RX FIFO OVERRUN !!!", length)); |
| 845 | return 0; |
| 846 | } |
| 847 | else |
| 848 | { |
| 849 | LOG1(("threecom3c505_receive: data_length=%x m_rx_pending=%d", length, m_rx_pending)); |
| 850 | |
| 851 | if (m_rx_data_buffer.get_length() == 0) |
| 852 | { |
| 853 | m_rx_fifo.get(&m_rx_data_buffer); |
| 854 | } |
| 855 | |
| 856 | // if (m_command_pending && m_command_buffer[0] == CMD_MC_F9) |
| 857 | // { |
| 858 | // verbose = 2; |
| 859 | // } |
| 860 | |
| 861 | if (!m_command_pending && m_rx_pending > 0 |
| 862 | && m_rx_data_buffer.get_length() > 0) |
| 863 | { |
| 864 | m_rx_pending--; |
| 865 | set_command_pending(1); |
| 866 | do_receive_command(); |
| 867 | } |
| 868 | |
| 869 | // guessing! |
| 870 | // else if (m_control & CMDE) |
| 871 | // { |
| 872 | // m_status |= ACRF; /* adapter command register full */ |
| 873 | // |
| 874 | // LOG(("threecom3c505_receive - set_interrupt(%d)",ASSERT_LINE)); |
| 875 | // set_interrupt(ASSERT_LINE); |
| 876 | // } |
| 877 | |
| 878 | return 1; |
| 879 | } |
| 880 | } |
| 881 | |
| 882 | void threecom3c505_device::write_command_port( UINT8 data) |
| 883 | { |
| 884 | LOG2(("writing 3C505 command port %02x - m_status=%02x m_control=%02x m_command_index=%02x", data, m_status, m_control, m_command_index)); |
| 885 | |
| 886 | if ((m_control & HSF_PCB_MASK) != HSF_PCB_END) |
| 887 | { |
| 888 | m_command_buffer[m_command_index++] = data; |
| 889 | m_status |= HCRE; /* command register empty */ |
| 890 | |
| 891 | if (m_command_index == 1) |
| 892 | { |
| 893 | switch (data) |
| 894 | { |
| 895 | case 0: |
| 896 | // spurious data; set command register empty |
| 897 | m_command_index = 0; |
| 898 | m_status |= HCRE; |
| 899 | // verbose = 2; |
| 900 | break; |
| 901 | |
| 902 | case CMD_MC_F9: |
| 903 | // case CMD_MC_FA: |
| 904 | // read data length from data port (not from command port) |
| 905 | m_tx_data_buffer.reset(); |
| 906 | m_status |= HRDY; /* data register ready */ |
| 907 | set_command_pending(1); |
| 908 | break; |
| 909 | |
| 910 | default: |
| 911 | set_command_pending(1); |
| 912 | break; |
| 913 | } |
| 914 | } |
| 915 | } |
| 916 | else |
| 917 | { |
| 918 | m_status &= ~ASF_PCB_MASK; |
| 919 | m_status |= (data == m_command_index) ? ASF_PCB_END : ASF_PCB_NAK; |
| 920 | |
| 921 | log_command(); |
| 922 | |
| 923 | switch (m_command_buffer[0]) |
| 924 | { |
| 925 | case CMD_TRANSMIT_PACKET_18: |
| 926 | // read transmit data into m_tx_data_buffer |
| 927 | m_tx_data_buffer.reset(); |
| 928 | m_tx_data_length = m_command_buffer[2] + (m_command_buffer[3] << 8); |
| 929 | m_status |= HRDY; /* data register ready */ |
| 930 | break; |
| 931 | |
| 932 | case CMD_TRANSMIT_PACKET: |
| 933 | // read transmit data into m_tx_data_buffer |
| 934 | m_tx_data_buffer.reset(); |
| 935 | m_tx_data_length = m_command_buffer[6] + (m_command_buffer[7] << 8); |
| 936 | m_status |= HRDY; /* data register ready */ |
| 937 | break; |
| 938 | |
| 939 | case CMD_DOWNLOAD_PROGRAM: |
| 940 | // read program data into m_program_buffer |
| 941 | m_program_buffer.reset(); |
| 942 | m_program_length = m_command_buffer[2] + (m_command_buffer[3] << 8); |
| 943 | m_status |= HRDY; /* data register ready */ |
| 944 | break; |
| 945 | |
| 946 | default: |
| 947 | do_command(); |
| 948 | break; |
| 949 | } |
| 950 | } |
| 951 | } |
| 952 | |
| 953 | UINT8 threecom3c505_device::read_command_port() |
| 954 | { |
| 955 | UINT8 data; |
| 956 | if (m_response_index == 0) |
| 957 | { |
| 958 | // set_command_pending(1); |
| 959 | data = m_response.command; |
| 960 | } |
| 961 | else if (m_response_index == 1) |
| 962 | { |
| 963 | data = m_response.length; |
| 964 | } |
| 965 | else if (m_response_index < m_response_length) |
| 966 | { |
| 967 | data = m_response.data.raw[m_response_index - 2]; |
| 968 | } |
| 969 | else if (m_response_index == m_response_length) |
| 970 | { |
| 971 | data = m_response.length + 2; |
| 972 | } |
| 973 | else if (m_response_index == m_response_length+1 /*&& m_microcode_running*/) |
| 974 | { |
| 975 | // FIXME: special for SR10.4 microcode, content doesn't matter? |
| 976 | data = 0; // ? |
| 977 | m_response_index++; |
| 978 | |
| 979 | m_status &= ~ACRF; /* adapter command register no longer full */ |
| 980 | |
| 981 | LOG2(("FIXME: reading 3C505 Command Register at offset %02x with index %02x = %02x", |
| 982 | PORT_COMMAND, m_response_index, data)); |
| 983 | } |
| 984 | else |
| 985 | { |
| 986 | // should never happen |
| 987 | data = 0; // 0xff; |
| 988 | LOG(("UNEXPECTED: reading 3C505 Command Register at offset %02x = %02x", PORT_COMMAND, data)); |
| 989 | } |
| 990 | |
| 991 | if (m_response_index <= m_response_length + 1) |
| 992 | { |
| 993 | if (++m_response_index == m_response_length) |
| 994 | { |
| 995 | m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_END; |
| 996 | } |
| 997 | else if (m_response_index == m_response_length + 1) |
| 998 | { |
| 999 | // FIXME: |
| 1000 | if (!(m_status & DIR_)) |
| 1001 | { |
| 1002 | m_status &= ~HRDY; /* data register no longer ready */ |
| 1003 | } |
| 1004 | |
| 1005 | log_response(); |
| 1006 | |
| 1007 | switch (m_response.command) |
| 1008 | { |
| 1009 | case CMD_MC_E1_RESPONSE: |
| 1010 | m_status |= HRDY; /* data register ready */ |
| 1011 | // prepend data length |
| 1012 | m_rx_data_index = -2; |
| 1013 | break; |
| 1014 | |
| 1015 | case CMD_RECEIVE_PACKET_COMPLETE: |
| 1016 | m_status |= HRDY; /* data register ready */ |
| 1017 | m_rx_data_index = 0; |
| 1018 | break; |
| 1019 | |
| 1020 | case CMD_TRANSMIT_PACKET_COMPLETE: |
| 1021 | case CMD_TRANSMIT_PACKET_18_COMPLETE: |
| 1022 | if (tx_data != NULL && // |
| 1023 | (*tx_data)(this, m_tx_data_buffer.get_data(), m_tx_data_buffer.get_length()) == 0) |
| 1024 | { |
| 1025 | // FIXME: failed to transmit the ethernet packet |
| 1026 | LOG(("read_command_port(): failed to transmit ethernet packet")); |
| 1027 | } |
| 1028 | |
| 1029 | m_tx_data_buffer.reset(); |
| 1030 | set_command_pending(0); |
| 1031 | break; |
| 1032 | |
| 1033 | case CMD_DOWNLOAD_PROGRAM_RESPONSE: |
| 1034 | m_program_buffer.reset(); |
| 1035 | set_command_pending(0); |
| 1036 | break; |
| 1037 | |
| 1038 | default: |
| 1039 | set_command_pending(0); |
| 1040 | break; |
| 1041 | } |
| 1042 | } |
| 1043 | } |
| 1044 | return data; |
| 1045 | } |
| 1046 | |
| 1047 | void threecom3c505_device::write_data_port( UINT8 data) |
| 1048 | { |
| 1049 | if (m_control & FLSH) |
| 1050 | { |
| 1051 | // flush input data |
| 1052 | } |
| 1053 | else if ((m_status & HRDY) == 0) |
| 1054 | { |
| 1055 | // this will happen in ether.dex Test 20/1 |
| 1056 | LOG(("write_data_port: failed to write tx data (data register not ready), data length=%x status=%x", |
| 1057 | m_tx_data_buffer.get_length(), m_status)); |
| 1058 | } |
| 1059 | |
| 1060 | #if 0 |
| 1061 | else if (m_command_buffer[0] == CMD_MC_F8) |
| 1062 | { |
| 1063 | // FIXME: what does it do? |
| 1064 | LOG(("write_data_port: !!! TODO: CMD_MC_F8 !!! command=%x data=%02x", m_command_buffer[0], data)); |
| 1065 | } |
| 1066 | #endif |
| 1067 | |
| 1068 | else if (m_command_buffer[0] == CMD_MC_F9) |
| 1069 | { |
| 1070 | switch (m_command_index) { |
| 1071 | case 1: |
| 1072 | m_command_buffer[m_command_index++] = data; |
| 1073 | break; |
| 1074 | case 2: |
| 1075 | m_command_buffer[m_command_index++] = data; |
| 1076 | m_tx_data_length = m_command_buffer[1] + (m_command_buffer[2] << 8); |
| 1077 | log_command(); |
| 1078 | break; |
| 1079 | default: |
| 1080 | if (!m_tx_data_buffer.append(data)) |
| 1081 | { |
| 1082 | LOG(("write_data_port: failed to write tx data (buffer size exceeded), data length=%x", |
| 1083 | m_tx_data_buffer.get_length())); |
| 1084 | } |
| 1085 | if (m_tx_data_buffer.get_length() == m_tx_data_length) |
| 1086 | { |
| 1087 | // CMD_TRANSMIT_PACKET_COMPLETE |
| 1088 | #if 0 |
| 1089 | if (m_command_buffer[0] == CMD_MC_F8) |
| 1090 | { |
| 1091 | // FIXME: what does it do? |
| 1092 | LOG(("write_data_port: !!! TODO: CMD_MC_F8 !!! command=%x data length=%x", m_command_buffer[0], m_tx_data_length)); |
| 1093 | } |
| 1094 | #endif |
| 1095 | m_tx_data_buffer.log("Tx Data"); |
| 1096 | do_command(); |
| 1097 | } |
| 1098 | break; |
| 1099 | } |
| 1100 | } |
| 1101 | else if (m_command_buffer[0] == CMD_TRANSMIT_PACKET || |
| 1102 | m_command_buffer[0] == CMD_TRANSMIT_PACKET_18) |
| 1103 | { |
| 1104 | if (!m_tx_data_buffer.append(data)) |
| 1105 | { |
| 1106 | LOG(("write_data_port: failed to write tx data (buffer size exceeded), data length=%x", |
| 1107 | m_tx_data_buffer.get_length())); |
| 1108 | } |
| 1109 | |
| 1110 | if (m_tx_data_buffer.get_length() == m_tx_data_length) |
| 1111 | { |
| 1112 | // CMD_TRANSMIT_PACKET_COMPLETE |
| 1113 | m_tx_data_buffer.log("Tx Data"); |
| 1114 | do_command(); |
| 1115 | } |
| 1116 | } |
| 1117 | else if (m_command_buffer[0] == CMD_DOWNLOAD_PROGRAM) |
| 1118 | { |
| 1119 | if (!m_program_buffer.append(data)) |
| 1120 | { |
| 1121 | LOG(("write_data_port: failed to write program data (buffer size exceeded), data length=%x", |
| 1122 | m_program_buffer.get_length())); |
| 1123 | } |
| 1124 | |
| 1125 | if (m_program_buffer.get_length() == m_program_length) |
| 1126 | { |
| 1127 | m_program_buffer.log("Program Data"); |
| 1128 | do_command(); |
| 1129 | } |
| 1130 | } |
| 1131 | else if (m_tx_data_buffer.get_length() < PORT_DATA_FIFO_SIZE) |
| 1132 | { |
| 1133 | // write to data fifo |
| 1134 | if (!m_tx_data_buffer.append(data)) |
| 1135 | { |
| 1136 | LOG(("write_data_port: failed to write tx data (buffer size exceeded), data length=%x", |
| 1137 | m_tx_data_buffer.get_length())); |
| 1138 | } |
| 1139 | } |
| 1140 | else |
| 1141 | { |
| 1142 | LOG(("write_data_port: !!! UNEXPECTED !!! command=%x data=%02x", m_command_buffer[0], data)); |
| 1143 | } |
| 1144 | |
| 1145 | if (m_tx_data_buffer.get_length() >= PORT_DATA_FIFO_SIZE |
| 1146 | && m_tx_data_buffer.get_length() >= m_tx_data_length) |
| 1147 | { |
| 1148 | m_status &= ~HRDY; /* data register not ready */ |
| 1149 | if (m_tx_data_buffer.get_length() > PORT_DATA_FIFO_SIZE |
| 1150 | && m_tx_data_buffer.get_length() > m_tx_data_length) |
| 1151 | { |
| 1152 | LOG(("write_data_port: port_data tx fifo exhausted, data length=%x status=%x", |
| 1153 | m_tx_data_buffer.get_length(), m_status)); |
| 1154 | } |
| 1155 | } |
| 1156 | } |
| 1157 | |
| 1158 | UINT8 threecom3c505_device::read_data_port(){ |
| 1159 | UINT8 data; |
| 1160 | UINT16 data_length = m_rx_data_buffer.get_length(); |
| 1161 | // DomainOS will read words (i.e. even number of bytes); must handle packets with odd byte length |
| 1162 | UINT16 even_data_length = (data_length+1) & ~1; |
| 1163 | |
| 1164 | if (m_rx_data_index < even_data_length) |
| 1165 | { |
| 1166 | // eventually prepend data length (for CMD_MC_E1_RESPONSE) |
| 1167 | data = m_rx_data_index == -2 ? (data_length & 0xff) : // |
| 1168 | m_rx_data_index == -1 ? (data_length << 8) : // |
| 1169 | m_rx_data_buffer.get(m_rx_data_index); |
| 1170 | |
| 1171 | m_rx_data_index++; |
| 1172 | |
| 1173 | if (m_rx_data_index == even_data_length) |
| 1174 | { |
| 1175 | m_status &= ~HRDY; /* data register no longer ready */ |
| 1176 | m_rx_data_buffer.log("Rx Data"); |
| 1177 | m_rx_data_buffer.reset(); |
| 1178 | set_command_pending(0); |
| 1179 | } |
| 1180 | } |
| 1181 | |
| 1182 | #if 0 |
| 1183 | else if (m_rx_data_index == data_length && (data_length & 1)) |
| 1184 | { |
| 1185 | // data length is odd, pad with 0 to next even size |
| 1186 | data = 0; |
| 1187 | m_rx_data_index++; |
| 1188 | LOG(("!!!: padding 3C505 Rx Data with odd data length %2x with value %02x", data_length, data)); |
| 1189 | } |
| 1190 | #endif |
| 1191 | |
| 1192 | else |
| 1193 | { |
| 1194 | // FIXME: should never happen |
| 1195 | data = 0xff; |
| 1196 | m_status &= ~HRDY; /* data register no longer ready */ |
| 1197 | set_command_pending(0); |
| 1198 | LOG(("UNEXPECTED: reading 3C505 data Register as %02x (data_length=%02x)", data, data_length)); |
| 1199 | } |
| 1200 | return data; |
| 1201 | } |
| 1202 | |
| 1203 | void threecom3c505_device::write_control_port( UINT8 data) |
| 1204 | { |
| 1205 | // if (cpu_get_previouspc(m_device->machine->firstcpu) == 0x3C4BAD48) verbose = 3; |
| 1206 | // if (cpu_get_previouspc(m_device->machine->firstcpu) == 0x010464DC) verbose = 3; |
| 1207 | |
| 1208 | if (verbose <= 2 && (data & (DMAE | TCEN /*| CMDE*/)) != 0) |
| 1209 | { |
| 1210 | // dma or interrupts enabled |
| 1211 | LOG1(("writing 3C505 Control Register at offset %02x = %02x", PORT_CONTROL, data)); |
| 1212 | } |
| 1213 | |
| 1214 | m_status = (m_status & ~DIR_) | (data & DIR_); |
| 1215 | |
| 1216 | switch (data & HSF_PCB_MASK) |
| 1217 | { |
| 1218 | case HSF_PCB_ACK: // HSF1 |
| 1219 | break; |
| 1220 | case HSF_PCB_NAK: // HSF2 |
| 1221 | if (m_microcode_running) |
| 1222 | { |
| 1223 | m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_ACK; |
| 1224 | } |
| 1225 | break; |
| 1226 | case HSF_PCB_END: // (HSF2|HSF1) |
| 1227 | m_status &= ~(ATTN | DMAE | ASF_PCB_MASK); |
| 1228 | if (m_microcode_running) |
| 1229 | { |
| 1230 | m_status = (m_status & ~ASF_PCB_MASK) | ASF_PCB_ACK; |
| 1231 | } |
| 1232 | break; |
| 1233 | default: // 0 |
| 1234 | m_command_index = 0; |
| 1235 | m_status |= HCRE; /* command register empty */ |
| 1236 | |
| 1237 | if (data == 0x00) |
| 1238 | { |
| 1239 | // hardware reset |
| 1240 | m_status |= HRDY; /* data register ready */ |
| 1241 | // flush data register (reset tx data fifo) |
| 1242 | m_tx_data_length = 0; |
| 1243 | // FIXME: Don't do this (but why?) |
| 1244 | // m_tx_data_buffer.reset(); |
| 1245 | } |
| 1246 | else if (data == DIR_) |
| 1247 | { |
| 1248 | // why?? dex ether 20 expects HRDY |
| 1249 | // m_status &= ~HRDY; /* data register not ready */ |
| 1250 | m_status |= HRDY; /* data register ready */ |
| 1251 | } |
| 1252 | else if (data & FLSH) |
| 1253 | { |
| 1254 | if (data & DIR_) |
| 1255 | { |
| 1256 | m_status &= ~HRDY; /* data register not ready */ |
| 1257 | } |
| 1258 | else |
| 1259 | { |
| 1260 | // flush data register (reset tx data fifo) |
| 1261 | // m_tx_data_length = 0; |
| 1262 | m_tx_data_buffer.reset(); |
| 1263 | m_status |= HRDY; /* data register ready */ |
| 1264 | } |
| 1265 | } |
| 1266 | break; |
| 1267 | } |
| 1268 | |
| 1269 | if ((m_control & (ATTN | FLSH)) == (ATTN | FLSH) && (data & (ATTN | FLSH)) == 0) |
| 1270 | { |
| 1271 | m_status |= ASF_PCB_END; |
| 1272 | } |
| 1273 | |
| 1274 | m_control = data; |
| 1275 | } |
| 1276 | |
| 1277 | UINT8 threecom3c505_device::read_status_port() |
| 1278 | { |
| 1279 | UINT8 data = m_status; |
| 1280 | m_status &= ~ASF_PCB_MASK; |
| 1281 | |
| 1282 | switch (data & ASF_PCB_MASK) { |
| 1283 | case ASF_PCB_END: |
| 1284 | m_status |= ASF_PCB_ACK; |
| 1285 | break; |
| 1286 | } |
| 1287 | return data; |
| 1288 | } |
| 1289 | |
| 1290 | void threecom3c505_device::write_port(offs_t offset, UINT8 data) |
| 1291 | { |
| 1292 | m_reg[offset & 0x0f] = data; |
| 1293 | LOG2(("writing 3C505 Register at offset %02x = %02x", offset, data)); |
| 1294 | |
| 1295 | switch (offset) |
| 1296 | { |
| 1297 | case PORT_COMMAND: /* 0x00 read/write, 8-bit */ |
| 1298 | write_command_port(data); |
| 1299 | break; |
| 1300 | case PORT_AUXDMA: /* 0x02 write only, 8-bit */ |
| 1301 | break; |
| 1302 | case PORT_DATA: /* 0x04 read/write, 16-bit */ |
| 1303 | case PORT_DATA + 1: /* 0x04 read/write, 16-bit */ |
| 1304 | write_data_port(data); |
| 1305 | break; |
| 1306 | case PORT_CONTROL: /* 0x06 read/write, 8-bit */ |
| 1307 | write_control_port(data); |
| 1308 | break; |
| 1309 | default: |
| 1310 | break; |
| 1311 | } |
| 1312 | } |
| 1313 | |
| 1314 | //READ8_DEVICE_HANDLER( threecom3c505_r ) |
| 1315 | UINT8 threecom3c505_device::read_port(offs_t offset) |
| 1316 | { |
| 1317 | // data to omit excessive logging |
| 1318 | static UINT8 last_data = 0xff; |
| 1319 | static UINT32 last_pc = 0; |
| 1320 | |
| 1321 | UINT8 data = m_reg[offset & 0x0f]; |
| 1322 | switch (offset) |
| 1323 | { |
| 1324 | case PORT_COMMAND: /* 0x00 read/write, 8-bit */ |
| 1325 | data = read_command_port(); |
| 1326 | break; |
| 1327 | case PORT_STATUS: /* 0x02 read only, 8-bit */ |
| 1328 | data=read_status_port(); |
| 1329 | |
| 1330 | set_interrupt(CLEAR_LINE); |
| 1331 | |
| 1332 | // omit excessive logging |
| 1333 | if (data == last_data) |
| 1334 | { |
| 1335 | UINT32 pc = cpu_get_previouspc(machine().device(MAINCPU)); |
| 1336 | if (pc == last_pc) { |
| 1337 | return data; |
| 1338 | } |
| 1339 | last_pc = pc; |
| 1340 | } |
| 1341 | last_data = data; |
| 1342 | |
| 1343 | break; |
| 1344 | case PORT_DATA: /* 0x04 read/write, 16-bit */ |
| 1345 | case PORT_DATA + 1: /* 0x04 read/write, 16-bit */ |
| 1346 | data = read_data_port(); |
| 1347 | break; |
| 1348 | case PORT_CONTROL: /* 0x06 read/write, 8-bit */ |
| 1349 | // just return current value |
| 1350 | break; |
| 1351 | default: |
| 1352 | break; |
| 1353 | } |
| 1354 | |
| 1355 | LOG2(("reading 3C505 Register at offset %02x = %02x", offset, data)); |
| 1356 | return data; |
| 1357 | } |
| 1358 | |
| 1359 | //************************************************************************** |
| 1360 | // GLOBAL STUBS |
| 1361 | //************************************************************************** |
| 1362 | |
| 1363 | READ8_DEVICE_HANDLER( threecom3c505_r ) |
| 1364 | { |
| 1365 | return downcast<threecom3c505_device *> (device)->read_port(offset); |
| 1366 | } |
| 1367 | |
| 1368 | WRITE8_DEVICE_HANDLER( threecom3c505_w ) |
| 1369 | { |
| 1370 | downcast<threecom3c505_device *> (device)->write_port(offset, data); |
| 1371 | } |
| 1372 | |
| 1373 | int threecom3c505_receive(device_t *device, const UINT8 data[], int length) |
| 1374 | { |
| 1375 | return downcast<threecom3c505_device *> (device)->threecom3c505_receive(data,length); |
| 1376 | } |
| 1377 | |
| 1378 | void threecom3c505_set_verbose(int on_off) |
| 1379 | { |
| 1380 | verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1; |
| 1381 | } |
src/mess/machine/sc499.c
| r0 | r14540 | |
| 1 | /* |
| 2 | * sc499.c - ARCHIVE SC-499 cartridge tape controller (for Apollo DN3x00) |
| 3 | *_DeviceClass |
| 4 | * Created on: April 17, 2011 |
| 5 | * Author: Hans Ostermeyer |
| 6 | * |
| 7 | * Released for general non-commercial use under the MAME license |
| 8 | * Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | * |
| 10 | * see also: |
| 11 | * - http://www.bitsavers.org/pdf/apollo/002398-04_Domain_Engineering_Handbook_Rev4_Jan87.pdf |
| 12 | * - http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf |
| 13 | * - http://www.bitsavers.org/pdf/archive/20271-001_scorpPrDesc_Mar84.pdf |
| 14 | * - http://www.bitsavers.org/pdf/archive/SidewinderProdDescr.pdf |
| 15 | * |
| 16 | */ |
| 17 | |
| 18 | #include "machine/sc499.h" |
| 19 | |
| 20 | #define VERBOSE 0 |
| 21 | |
| 22 | static int verbose = VERBOSE; |
| 23 | |
| 24 | #define LOG(x) { logerror ("%s: ", cpu_context()); logerror x; logerror ("\n"); } |
| 25 | #define LOG1(x) { if (verbose > 0) LOG(x)} |
| 26 | #define LOG2(x) { if (verbose > 1) LOG(x)} |
| 27 | #define LOG3(x) { if (verbose > 2) LOG(x)} |
| 28 | |
| 29 | #define MAINCPU "maincpu" |
| 30 | |
| 31 | //************************************************************************** |
| 32 | // DEVICE DEFINITIONS |
| 33 | //************************************************************************** |
| 34 | |
| 35 | //const device_type SC499 = sc499_device_config::static_alloc_device_config; |
| 36 | |
| 37 | sc499_device *sc499_device::m_device; |
| 38 | |
| 39 | //************************************************************************** |
| 40 | // CONSTANTS |
| 41 | //************************************************************************** |
| 42 | |
| 43 | // I/O register offsets |
| 44 | |
| 45 | #define SC499_PORT_DATA 0x00 // read data (status data) |
| 46 | #define SC499_PORT_COMMAND 0x00 // write command |
| 47 | #define SC499_PORT_STATUS 0x01 // read status |
| 48 | #define SC499_PORT_CONTROL 0x01 // write control |
| 49 | #define SC499_PORT_DMAGO 0x02 // write only, Start DMA |
| 50 | #define SC499_PORT_RSTDMA 0x03 // write only, Reset DMA |
| 51 | |
| 52 | // Tape Status Byte 0 (LSB) |
| 53 | |
| 54 | #define SC499_ST0 0x8000 // 0=> Status byte 0 |
| 55 | #define SC499_ST0_NOC 0x4000 // 1=> Cartridge not in place |
| 56 | #define SC499_ST0_USD 0x2000 // 1=> Unselected drive |
| 57 | #define SC499_ST0_WP 0x1000 // 1=> Write protected cartridge |
| 58 | #define SC499_ST0_EOM 0x0800 // 1=> End of media (EOM) |
| 59 | #define SC499_ST0_UDE 0x0400 // 1=> Unrecoverable data error |
| 60 | #define SC499_ST0_BNL 0x0200 // 1=> Bad block not located |
| 61 | #define SC499_ST0_FM 0x0100 // 1=> Filemark detected |
| 62 | #define SC499_ST0_MASK 0x7f00 |
| 63 | |
| 64 | // Tape Status Byte 1 (MSB) |
| 65 | |
| 66 | #define SC499_ST1 0x0080 // 1=> Status byte 1 |
| 67 | #define SC499_ST1_ILL 0x0040 // 1=> Illegal command |
| 68 | #define SC499_ST1_NOD 0x0020 // 1=> No data detected |
| 69 | #define SC499_ST1_MGN 0x0010 // 1=> Marginal block detected |
| 70 | #define SC499_ST1_BOM 0x0008 // 1=> Beginning of media (BOM) |
| 71 | #define SC499_ST1_BPE 0x0004 // 1=> Reserved for bus parity error |
| 72 | #define SC499_ST1_ERM 0x0002 // 1=> Reserved for end of recorded media |
| 73 | #define SC499_ST1_POR 0x0001 // 1=> Power on/reset occurred |
| 74 | #define SC499_ST1_MASK 0x007f |
| 75 | |
| 76 | #define SC499_ST_CLEAR_ALL ~(SC499_ST0_NOC | SC499_ST0_USD | SC499_ST0_WP | SC499_ST0_EOM | SC499_ST1_BOM) |
| 77 | #define SC499_ST_READ_ERROR (SC499_ST0_UDE | SC499_ST0_BNL | SC499_ST1_NOD) |
| 78 | |
| 79 | // Tape Status word |
| 80 | |
| 81 | //dc.w $EFFF,$C000 // 3a No cartridge |
| 82 | //dc.w $FFFF,$F000 // 39 No drive |
| 83 | //dc.w $FFFF,$8800 // 38 End of media |
| 84 | //dc.w $EFFF,$8488 // 37 Write abort |
| 85 | //dc.w $EFFF,$8400 // 36 Read error, bad blk xfer |
| 86 | //dc.w $EFFF,$8600 // 35 Read error, filler blk xfer |
| 87 | //dc.w $EFFF,$86A0 // 34 Read error, no data |
| 88 | //dc.w $EFFF,$8EA0 // 33 Read error, no data and EOM |
| 89 | //dc.w $EFE9,$86A8 // 32 Read error, no data and BOM |
| 90 | //dc.w $EFFF,$8100 // 31 Filemark read |
| 91 | //dc.w $0FF7,$00C0 // 30 Illegal command |
| 92 | |
| 93 | // Command Register (write) [50000 | 3FF9C00 ] |
| 94 | |
| 95 | #define SC499_CMD_SELECT 0x00 // Select |
| 96 | #define SC499_CMD_SEL_1 0x01 // select tape 1 |
| 97 | #define SC499_CMD_SEL_2 0x02 // select tape 2 |
| 98 | #define SC499_CMD_SEL_3 0x04 // select tape 3 |
| 99 | #define SC499_CMD_SEL_4 0x08 // select tape 4 |
| 100 | #define SC499_CMD_POSITION 0x20 // Position |
| 101 | #define SC499_CMD_REWIND 0x21 // rewind tape |
| 102 | #define SC499_CMD_ERASE 0x22 // erase tape |
| 103 | #define SC499_CMD_RETEN 0x24 // retension tape |
| 104 | #define SC499_CMD_WRITE_DATA 0x40 // Write Data |
| 105 | #define SC499_CMD_WRITE_FILEMARK 0x60 // Write File Mark |
| 106 | #define SC499_CMD_READ_DATA 0x80 // Read Data |
| 107 | #define SC499_CMD_READ_FILE_MARK 0xa0 // Read File Mark |
| 108 | #define SC499_CMD_READ_STATUS 0xc0 // Read Status |
| 109 | #define SC499_CMD_RESERVED 0xe0 // Reserved |
| 110 | #define SC499_CMD_NO_COMMAND 0xff // no command |
| 111 | |
| 112 | #define SC499_CMD_TYPE_MASK 0xe0 // command type mask |
| 113 | #define SC499_CMD_DATA_MASK 0x1f // command data mask |
| 114 | |
| 115 | // Status Register (read only) |
| 116 | |
| 117 | #define SC499_STAT_IRQ 0x80 // active high, Interrupt request flag ('or' of rdy and exc), and done if dni is set. |
| 118 | #define SC499_STAT_RDY 0x40 // active low, Ready from LSI chip. |
| 119 | #define SC499_STAT_EXC 0x20 // active low, Exception, from LSI chip. |
| 120 | #define SC499_STAT_DON 0x10 // active high, DMA done (from DMA logic) |
| 121 | #define SC499_STAT_DIR 0x08 // active high, Direction, indicates direction of bus is from controller to DN3000. |
| 122 | |
| 123 | // Control Register (write only) [50001 | 3FF9C01 ] |
| 124 | |
| 125 | // Note: All of these bits are cleared automatically when writing to SC499_PORT_RSTDMA. |
| 126 | // So SC499_CTR_IEN and SC499_CTR_DNI must be reprogrammed before the write to AR_START_DMA_PORT. |
| 127 | |
| 128 | #define SC499_CTR_RST 0x80 // 1=> Reset controller microprocessor. |
| 129 | #define SC499_CTR_REQ 0x40 // 1=> Request to LSI chip. |
| 130 | #define SC499_CTR_IEN 0x20 // 1=> Enables interrupts. |
| 131 | #define SC499_CTR_DNI 0x10 // 1=> Enables DONE int, dni = 0 masks DONE int |
| 132 | |
| 133 | // ctape device data |
| 134 | |
| 135 | #define SC499_CTAPE_TAG "sc499_ctape" |
| 136 | #define SC499_CTAPE_BLOCK_SIZE 512 |
| 137 | #define SC499_CTAPE_MAX_BLOCK_COUNT (60*1024*1024/SC499_CTAPE_BLOCK_SIZE) |
| 138 | |
| 139 | // mean time to read one block from ctape (should be 5-6 msec) |
| 140 | #define SC499_CTAPE_READ_BLOCK_TIME 6 |
| 141 | |
| 142 | // Timer type |
| 143 | #define SC499_TIMER_1 1 |
| 144 | #define SC499_TIMER_2 2 |
| 145 | #define SC499_TIMER_3 3 |
| 146 | #define SC499_TIMER_4 4 |
| 147 | #define SC499_TIMER_5 5 |
| 148 | #define SC499_TIMER_6 6 |
| 149 | #define SC499_TIMER_7 7 |
| 150 | |
| 151 | typedef struct _ctape_data ctape_data; |
| 152 | struct _ctape_data |
| 153 | { |
| 154 | device_image_interface *image; |
| 155 | }; |
| 156 | |
| 157 | /*************************************************************************** |
| 158 | IMPLEMENTATION |
| 159 | ***************************************************************************/ |
| 160 | |
| 161 | // device type definition |
| 162 | const device_type SC499 = &device_creator<sc499_device>; |
| 163 | |
| 164 | //------------------------------------------------- |
| 165 | // sc499_device - constructor |
| 166 | //------------------------------------------------- |
| 167 | |
| 168 | sc499_device::sc499_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 169 | : device_t(mconfig, SC499, "Archive SC-499", tag, owner, clock) |
| 170 | { |
| 171 | memset(static_cast<sc499_interface *>(this), 0, sizeof(sc499_interface)); |
| 172 | } |
| 173 | |
| 174 | //------------------------------------------------- |
| 175 | // static_set_interface - set the interface struct |
| 176 | //------------------------------------------------- |
| 177 | |
| 178 | void sc499_device::static_set_interface(device_t &device, const sc499_interface &interface) |
| 179 | { |
| 180 | sc499_device &sc499 = downcast<sc499_device &>(device); |
| 181 | static_cast<sc499_interface &>(sc499) = interface; |
| 182 | } |
| 183 | |
| 184 | //------------------------------------------------- |
| 185 | // device_start - device-specific startup |
| 186 | //------------------------------------------------- |
| 187 | |
| 188 | void sc499_device::device_start() |
| 189 | { |
| 190 | // FIXME: temporary hack: we allow only one device: |
| 191 | sc499_device::m_device = this; |
| 192 | |
| 193 | LOG1(("start sc499")); |
| 194 | |
| 195 | m_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_func), this); |
| 196 | m_timer1 = m_device->machine().scheduler().timer_alloc(FUNC(static_timer_func), this); |
| 197 | |
| 198 | device_t *ctape_device = machine().device(SC499_CTAPE_TAG); |
| 199 | ctape_data *ctape = (ctape_data *) downcast<legacy_device_base *> (ctape_device)->token(); |
| 200 | m_image = ctape->image; |
| 201 | |
| 202 | if (m_image->image_core_file() == NULL) |
| 203 | { |
| 204 | LOG2(("start sc499: no cartridge tape")); |
| 205 | } |
| 206 | else |
| 207 | { |
| 208 | LOG2(("start sc499: cartridge tape image is %s",m_image->filename())); |
| 209 | } |
| 210 | |
| 211 | m_ctape_block_buffer = auto_alloc_array(machine(), UINT8, SC499_CTAPE_BLOCK_SIZE); |
| 212 | assert(m_ctape_block_buffer!= NULL); |
| 213 | } |
| 214 | |
| 215 | //------------------------------------------------- |
| 216 | // device_reset - device-specific reset |
| 217 | //------------------------------------------------- |
| 218 | |
| 219 | void sc499_device::device_reset() |
| 220 | { |
| 221 | LOG1(("reset sc499")); |
| 222 | |
| 223 | m_data = 0; |
| 224 | m_command = SC499_CMD_NO_COMMAND; |
| 225 | m_status = SC499_STAT_RDY; // | SC499_STAT_EXC; |
| 226 | m_control = 0; |
| 227 | |
| 228 | m_first_block_hack = 1; |
| 229 | m_nasty_readahead = 0; |
| 230 | m_read_block_pending = 0; |
| 231 | |
| 232 | m_current_command = m_command; |
| 233 | |
| 234 | m_data_error_counter = 0; |
| 235 | m_underrun_counter = 0; |
| 236 | |
| 237 | m_image_length = 0; |
| 238 | |
| 239 | check_tape(); |
| 240 | |
| 241 | m_data_index = 0; |
| 242 | m_ctape_block_index = 0; |
| 243 | m_tape_pos = 0; |
| 244 | |
| 245 | irq_state = CLEAR_LINE; |
| 246 | dma_drq_state = CLEAR_LINE; |
| 247 | } |
| 248 | |
| 249 | /*------------------------------------------------- |
| 250 | cpu_context - return a string describing the current CPU context |
| 251 | -------------------------------------------------*/ |
| 252 | |
| 253 | const char *sc499_device::cpu_context() |
| 254 | { |
| 255 | static char statebuf[64]; /* string buffer containing state description */ |
| 256 | |
| 257 | device_t *cpu = machine().device(MAINCPU); |
| 258 | osd_ticks_t t = osd_ticks(); |
| 259 | int s = t / osd_ticks_per_second(); |
| 260 | int ms = (t % osd_ticks_per_second()) / 1000; |
| 261 | |
| 262 | /* if we have an executing CPU, output data */ |
| 263 | if (cpu != NULL) |
| 264 | { |
| 265 | sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(), |
| 266 | cpu_get_previouspc(cpu), tag()); |
| 267 | } |
| 268 | else |
| 269 | { |
| 270 | sprintf(statebuf, "%d.%03d", s, ms); |
| 271 | } |
| 272 | return statebuf; |
| 273 | } |
| 274 | |
| 275 | /*------------------------------------------------- |
| 276 | tape_status_clear - clear bits in tape status |
| 277 | -------------------------------------------------*/ |
| 278 | |
| 279 | void sc499_device::tape_status_clear(UINT16 value) |
| 280 | { |
| 281 | m_tape_status &= ~value; |
| 282 | tape_status_set(0); |
| 283 | } |
| 284 | |
| 285 | /*------------------------------------------------- |
| 286 | tape_status_set - set bits in tape status |
| 287 | -------------------------------------------------*/ |
| 288 | |
| 289 | void sc499_device::tape_status_set(UINT16 value) |
| 290 | { |
| 291 | m_tape_status |= value; |
| 292 | m_tape_status &= ~(SC499_ST0 | SC499_ST1); |
| 293 | if (m_tape_status & SC499_ST0_MASK) |
| 294 | { |
| 295 | m_tape_status |= SC499_ST0; |
| 296 | } |
| 297 | if (m_tape_status & SC499_ST1_MASK) |
| 298 | { |
| 299 | m_tape_status |= SC499_ST1; |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | /*------------------------------------------------- |
| 304 | check_tape - check tape |
| 305 | -------------------------------------------------*/ |
| 306 | |
| 307 | void sc499_device::check_tape() |
| 308 | { |
| 309 | m_tape_status = 0; |
| 310 | m_is_writable = m_image->exists() && m_image->is_writeable(); |
| 311 | |
| 312 | if (m_image->exists()) |
| 313 | { |
| 314 | m_has_cartridge = 1; // we have a cartridge |
| 315 | tape_status_set(SC499_ST1_BOM); // Beginning of media (BOM) |
| 316 | if (!m_is_writable) |
| 317 | { |
| 318 | tape_status_set(SC499_ST0_WP); |
| 319 | } |
| 320 | |
| 321 | if (m_image_length != m_image->length()) |
| 322 | { |
| 323 | // tape has changed, get new size |
| 324 | m_image_length = m_image->length(); |
| 325 | m_ctape_block_count = (UINT32)((m_image_length+SC499_CTAPE_BLOCK_SIZE-1) / SC499_CTAPE_BLOCK_SIZE); |
| 326 | } |
| 327 | |
| 328 | LOG1(("check_tape: tape image is %s with %d blocks", m_image->filename(), m_ctape_block_count)); |
| 329 | } |
| 330 | else |
| 331 | { |
| 332 | m_has_cartridge = 0; // we have no cartridge |
| 333 | tape_status_set(SC499_ST0_NOC); // Cartridge not in place |
| 334 | m_image_length = 0; |
| 335 | m_ctape_block_count = 0; |
| 336 | |
| 337 | LOG1(("check_tape: no cartridge tape")); |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | /*------------------------------------------------- |
| 342 | timer_func - handle timer interrupts |
| 343 | -------------------------------------------------*/ |
| 344 | |
| 345 | void sc499_device::timer_func(int timer_type) |
| 346 | { |
| 347 | LOG2(("timer_func param=%d status=%x",timer_type, m_status)); |
| 348 | |
| 349 | switch (timer_type) |
| 350 | { |
| 351 | case SC499_TIMER_1: // set ready |
| 352 | m_status &= ~SC499_STAT_RDY; |
| 353 | if (m_control & SC499_CTR_IEN) |
| 354 | { |
| 355 | set_interrupt(ASSERT_LINE); |
| 356 | m_status |= SC499_STAT_IRQ; |
| 357 | } |
| 358 | break; |
| 359 | |
| 360 | case SC499_TIMER_2: // set exception, clear interrupt (?) |
| 361 | m_status &= ~SC499_STAT_EXC; |
| 362 | m_status &= ~SC499_STAT_IRQ; |
| 363 | break; |
| 364 | |
| 365 | case SC499_TIMER_3: // start dma to read data |
| 366 | set_dma_drq(ASSERT_LINE); |
| 367 | m_status |= SC499_STAT_RDY; |
| 368 | break; |
| 369 | |
| 370 | case SC499_TIMER_4: // ready to read next status byte |
| 371 | m_status &= ~SC499_STAT_RDY; |
| 372 | |
| 373 | switch (++m_data_index) |
| 374 | { |
| 375 | case 1: m_data = m_tape_status >> 8; break; |
| 376 | case 2: m_data = m_tape_status & 0xff; break; |
| 377 | case 3: m_data = m_data_error_counter >> 8; break; |
| 378 | case 4: m_data = m_data_error_counter & 0xff; break; |
| 379 | case 5: m_data = m_underrun_counter >> 8; break; |
| 380 | case 6: m_data = m_underrun_counter & 0xff; break; |
| 381 | default: |
| 382 | m_data_index=0; |
| 383 | m_command = SC499_CMD_NO_COMMAND; |
| 384 | m_current_command = m_command; |
| 385 | m_status &= ~SC499_STAT_DIR; |
| 386 | tape_status_clear(SC499_ST_CLEAR_ALL); |
| 387 | break; |
| 388 | } |
| 389 | |
| 390 | if (m_control & SC499_CTR_IEN) |
| 391 | { |
| 392 | set_interrupt(ASSERT_LINE); |
| 393 | m_status |= SC499_STAT_IRQ; |
| 394 | } |
| 395 | break; |
| 396 | |
| 397 | case SC499_TIMER_5: // read next data block for SC499_CMD_READ_DATA |
| 398 | case SC499_TIMER_6: // read next data block for SC499_CMD_READ_FILE_MARK |
| 399 | if (m_read_block_pending && (m_status & SC499_STAT_DIR)) |
| 400 | { |
| 401 | // handle data underruns in a loaded Apollo emulation |
| 402 | // the real ctape will stop, go back and restart reading if appropriate |
| 403 | if (++m_underrun_counter >= 5000) |
| 404 | { |
| 405 | // stop tape (after 30 seconds) - probably the DMA handshake failed. |
| 406 | m_timer1->adjust(attotime::never, timer_type, attotime::never); |
| 407 | m_status &= ~SC499_STAT_EXC; |
| 408 | m_status &= ~SC499_STAT_DIR; |
| 409 | tape_status_clear(SC499_ST_CLEAR_ALL); |
| 410 | tape_status_set(SC499_ST_READ_ERROR); |
| 411 | |
| 412 | LOG(("timer_func param=%d status=%x tape_pos=%d - read data underrun aborted at %d", |
| 413 | timer_type, m_status, m_tape_pos, m_underrun_counter)); |
| 414 | } |
| 415 | else |
| 416 | { |
| 417 | LOG2(("timer_func param=%d status=%x tape_pos=%d - read data underrun %d", |
| 418 | timer_type, m_status, m_tape_pos, m_underrun_counter)); |
| 419 | } |
| 420 | break; |
| 421 | } |
| 422 | else if ( m_tape_pos > m_ctape_block_count || !(m_status & SC499_STAT_RDY)) |
| 423 | { |
| 424 | LOG1(("timer_func param=%d status=%x tape_pos=%d - end-of-tape or not ready", |
| 425 | timer_type, m_status, m_tape_pos)); |
| 426 | m_timer1->adjust(attotime::never, timer_type, attotime::never); |
| 427 | m_status &= ~SC499_STAT_EXC; |
| 428 | m_status &= ~SC499_STAT_DIR; |
| 429 | tape_status_clear(SC499_ST_CLEAR_ALL); |
| 430 | tape_status_set(SC499_ST_READ_ERROR); |
| 431 | } |
| 432 | else if (m_nasty_readahead > 0 ) |
| 433 | { |
| 434 | m_nasty_readahead = 0; |
| 435 | } |
| 436 | else |
| 437 | { |
| 438 | if (m_underrun_counter > 0) |
| 439 | { |
| 440 | LOG1(("timer_func param=%d status=%x tape_pos=%d - read data underrun ended at %d", |
| 441 | timer_type, m_status, m_tape_pos, m_underrun_counter)); |
| 442 | } |
| 443 | |
| 444 | read_block(); |
| 445 | m_underrun_counter = 0; |
| 446 | if (block_is_filemark()) |
| 447 | { |
| 448 | m_timer1->adjust(attotime::never, timer_type, attotime::never); |
| 449 | } |
| 450 | else if (m_current_command == SC499_CMD_READ_DATA) |
| 451 | { |
| 452 | m_read_block_pending = 1; |
| 453 | m_status &= ~SC499_STAT_RDY; |
| 454 | } |
| 455 | } |
| 456 | |
| 457 | if (m_control & SC499_CTR_IEN) |
| 458 | { |
| 459 | if (m_current_command == SC499_CMD_READ_DATA || (m_status & SC499_STAT_EXC) == 0) |
| 460 | { |
| 461 | set_interrupt(ASSERT_LINE); |
| 462 | m_status |= SC499_STAT_IRQ; |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | break; |
| 467 | |
| 468 | case SC499_TIMER_7: // reset |
| 469 | // set exception |
| 470 | m_status &= ~SC499_STAT_EXC; |
| 471 | if (m_control & SC499_CTR_IEN) |
| 472 | { |
| 473 | set_interrupt(ASSERT_LINE); |
| 474 | m_status |= SC499_STAT_IRQ; |
| 475 | } |
| 476 | break; |
| 477 | |
| 478 | default: |
| 479 | LOG(("timer_func param=%d UNEXPECTED",timer_type)); |
| 480 | m_timer->reset(); |
| 481 | break; |
| 482 | } |
| 483 | |
| 484 | } |
| 485 | |
| 486 | TIMER_CALLBACK( sc499_device::static_timer_func ) |
| 487 | { |
| 488 | reinterpret_cast<sc499_device *> (ptr)->timer_func(param); |
| 489 | } |
| 490 | |
| 491 | /*------------------------------------------------- |
| 492 | set_interrupt - set the IRQ state |
| 493 | -------------------------------------------------*/ |
| 494 | |
| 495 | void sc499_device::set_interrupt(enum line_state state) |
| 496 | { |
| 497 | if (set_irq != NULL && state != irq_state) |
| 498 | { |
| 499 | LOG2(("set_interrupt(%d)",state)); |
| 500 | (*set_irq)(this, state); |
| 501 | irq_state = state; |
| 502 | } |
| 503 | } |
| 504 | |
| 505 | /*------------------------------------------------- |
| 506 | set_dma_drq - set dma request output |
| 507 | -------------------------------------------------*/ |
| 508 | |
| 509 | void sc499_device::set_dma_drq(enum line_state state) |
| 510 | { |
| 511 | if (dma_drq != NULL && state != dma_drq_state) |
| 512 | { |
| 513 | LOG2(("set_dma_drq(%d)",state)); |
| 514 | (*dma_drq)(this, state); |
| 515 | dma_drq_state = state; |
| 516 | } |
| 517 | } |
| 518 | |
| 519 | // ------------------------------------- |
| 520 | |
| 521 | void sc499_device::log_command(UINT8 data) |
| 522 | { |
| 523 | switch (data) |
| 524 | { |
| 525 | case SC499_CMD_SELECT: |
| 526 | case SC499_CMD_SEL_1: |
| 527 | case SC499_CMD_SEL_2: |
| 528 | case SC499_CMD_SEL_3: |
| 529 | case SC499_CMD_SEL_4: |
| 530 | LOG1(("write_command_port: %02x Select %x", data, data & 0x1f)); |
| 531 | break; |
| 532 | case SC499_CMD_REWIND: // rewind tape |
| 533 | LOG1(("write_command_port: %02x Rewind Tape", data)); |
| 534 | break; |
| 535 | case SC499_CMD_ERASE: // erase tape |
| 536 | LOG1(("write_command_port: %02x Erase Tape", data)); |
| 537 | break; |
| 538 | case SC499_CMD_RETEN: // retention tape |
| 539 | LOG1(("write_command_port: %02x Retention Tape", data)); |
| 540 | break; |
| 541 | case SC499_CMD_WRITE_DATA: |
| 542 | LOG1(("write_command_port: %02x Write Data %d ...", data, m_tape_pos)); |
| 543 | break; |
| 544 | case SC499_CMD_WRITE_FILEMARK: |
| 545 | LOG1(("write_command_port: %02x Write File Mark %d", data, m_tape_pos)); |
| 546 | break; |
| 547 | case SC499_CMD_READ_DATA: |
| 548 | LOG1(("write_command_port: %02x Read Data %d ...", data, m_tape_pos)); |
| 549 | break; |
| 550 | case SC499_CMD_READ_FILE_MARK: |
| 551 | LOG1(("write_command_port: %02x Read File Mark %d", data, m_tape_pos)); |
| 552 | break; |
| 553 | case SC499_CMD_READ_STATUS: |
| 554 | LOG1(("write_command_port: %02x Read Status (%04x %04x %04x)", data, |
| 555 | m_tape_status, m_data_error_counter, m_underrun_counter)); |
| 556 | break; |
| 557 | case SC499_CMD_RESERVED: // Reserved |
| 558 | default: |
| 559 | LOG(("write_command_port: %02x Unexpected Command!", data)); |
| 560 | break; |
| 561 | } |
| 562 | } |
| 563 | |
| 564 | void sc499_device::do_command(UINT8 data) |
| 565 | { |
| 566 | m_status |= SC499_STAT_RDY; |
| 567 | m_status &= ~SC499_STAT_DON; |
| 568 | m_read_block_pending = 0; |
| 569 | |
| 570 | switch (data & SC499_CMD_TYPE_MASK) |
| 571 | { |
| 572 | case SC499_CMD_SELECT: |
| 573 | m_timer->adjust(attotime::from_usec(100), SC499_TIMER_1); |
| 574 | break; |
| 575 | |
| 576 | case SC499_CMD_POSITION: |
| 577 | switch (data) |
| 578 | { |
| 579 | case SC499_CMD_REWIND: // rewind tape |
| 580 | break; |
| 581 | case SC499_CMD_ERASE: // erase tape |
| 582 | // TODO: |
| 583 | break; |
| 584 | case SC499_CMD_RETEN: // retention tape |
| 585 | break; |
| 586 | } |
| 587 | m_first_block_hack = 0; |
| 588 | m_tape_pos = 0; |
| 589 | tape_status_clear(SC499_ST_CLEAR_ALL); |
| 590 | tape_status_set(SC499_ST1_BOM); |
| 591 | |
| 592 | m_timer->adjust(attotime::from_msec(500), SC499_TIMER_4); |
| 593 | break; |
| 594 | |
| 595 | case SC499_CMD_WRITE_DATA: |
| 596 | if (!m_is_writable) |
| 597 | { |
| 598 | m_status &= ~SC499_STAT_EXC; |
| 599 | } |
| 600 | m_timer->adjust(attotime::from_usec(100), SC499_TIMER_1); |
| 601 | break; |
| 602 | |
| 603 | case SC499_CMD_WRITE_FILEMARK: |
| 604 | if (!m_is_writable) |
| 605 | { |
| 606 | m_status &= ~SC499_STAT_EXC; |
| 607 | } |
| 608 | else |
| 609 | { |
| 610 | block_set_filemark(); |
| 611 | write_block(); |
| 612 | } |
| 613 | m_timer->adjust( attotime::from_msec(100), SC499_TIMER_1); |
| 614 | break; |
| 615 | |
| 616 | case SC499_CMD_READ_DATA: |
| 617 | m_status |= SC499_STAT_DIR; |
| 618 | // start reading blocks from tape |
| 619 | m_nasty_readahead = 0; |
| 620 | m_timer1->adjust( attotime::from_msec(200), SC499_TIMER_5, attotime::from_msec(SC499_CTAPE_READ_BLOCK_TIME)); |
| 621 | break; |
| 622 | |
| 623 | case SC499_CMD_READ_FILE_MARK: |
| 624 | if (m_current_command == SC499_CMD_READ_DATA) |
| 625 | { |
| 626 | // SC499_CMD_READ_DATA pending |
| 627 | m_status &= ~SC499_STAT_DIR; |
| 628 | LOG1(("do_command: Read data -> Read File Mark at %d", m_tape_pos)); |
| 629 | } |
| 630 | else |
| 631 | { |
| 632 | // start reading blocks from tape |
| 633 | m_timer1->adjust( attotime::from_msec(200), SC499_TIMER_6, attotime::from_msec(SC499_CTAPE_READ_BLOCK_TIME)); |
| 634 | } |
| 635 | break; |
| 636 | |
| 637 | case SC499_CMD_READ_STATUS: |
| 638 | m_status |= SC499_STAT_DIR; |
| 639 | m_status |= SC499_STAT_EXC; |
| 640 | |
| 641 | set_interrupt(CLEAR_LINE); |
| 642 | set_dma_drq(CLEAR_LINE); |
| 643 | m_timer1->adjust( attotime::never, SC499_TIMER_6, attotime::never); |
| 644 | |
| 645 | m_data_index = 0; |
| 646 | m_timer->adjust( attotime::from_usec(100), SC499_TIMER_4); |
| 647 | break; |
| 648 | |
| 649 | default: |
| 650 | tape_status_clear(SC499_ST_CLEAR_ALL); |
| 651 | tape_status_set(SC499_ST1 | SC499_ST1_ILL); |
| 652 | m_status &= ~SC499_STAT_EXC; |
| 653 | // Note: 100 usec is too fast for DN3000 |
| 654 | m_timer->adjust( attotime::from_usec(200), SC499_TIMER_1); |
| 655 | break; |
| 656 | } |
| 657 | } |
| 658 | |
| 659 | // ------------------------------------- |
| 660 | |
| 661 | void sc499_device::do_reset() |
| 662 | { |
| 663 | LOG1(("do_reset: Reset controller microprocessor")); |
| 664 | |
| 665 | m_data = 0; |
| 666 | m_command = SC499_CMD_NO_COMMAND; |
| 667 | m_current_command = m_command; |
| 668 | m_status = ~(SC499_STAT_DIR | SC499_STAT_EXC); |
| 669 | m_control = 0; |
| 670 | |
| 671 | if (m_has_cartridge) |
| 672 | { |
| 673 | tape_status_set(SC499_ST1_POR | SC499_ST1_BOM); |
| 674 | } |
| 675 | |
| 676 | m_tape_pos = 0; |
| 677 | m_data_error_counter = 0; |
| 678 | m_underrun_counter = 0; |
| 679 | |
| 680 | set_interrupt(CLEAR_LINE); |
| 681 | set_dma_drq(CLEAR_LINE); |
| 682 | |
| 683 | m_timer1->adjust( attotime::never, SC499_TIMER_6, attotime::never); |
| 684 | } |
| 685 | |
| 686 | // ------------------------------------- |
| 687 | |
| 688 | void sc499_device::write_command_port(UINT8 data) |
| 689 | { |
| 690 | m_command = data; |
| 691 | log_command(data); |
| 692 | } |
| 693 | |
| 694 | UINT8 sc499_device::read_data_port() |
| 695 | { |
| 696 | static UINT8 m_last_data = 0xff; |
| 697 | |
| 698 | // omit excessive logging |
| 699 | if (m_last_data != m_data) |
| 700 | { |
| 701 | LOG2(("read_data_port: %02x", m_data)); |
| 702 | m_last_data = m_data; |
| 703 | } |
| 704 | |
| 705 | if (m_control & SC499_CTR_IEN) |
| 706 | { |
| 707 | set_interrupt(CLEAR_LINE); |
| 708 | m_status &= ~SC499_STAT_IRQ; |
| 709 | } |
| 710 | |
| 711 | return m_data; |
| 712 | } |
| 713 | |
| 714 | void sc499_device::write_control_port( UINT8 data) |
| 715 | { |
| 716 | LOG2(("write_control_port: %02x", data)); |
| 717 | |
| 718 | if ((data ^ m_control) & SC499_CTR_RST) |
| 719 | { |
| 720 | if (data & SC499_CTR_RST) |
| 721 | { |
| 722 | // SC499_CTR_RST has changed to 1 |
| 723 | do_reset(); |
| 724 | } |
| 725 | else |
| 726 | { |
| 727 | m_status |= SC499_STAT_EXC; |
| 728 | m_timer->adjust(attotime::from_msec(200), SC499_TIMER_7); |
| 729 | } |
| 730 | } |
| 731 | |
| 732 | if ((data ^ m_control) & SC499_CTR_REQ) |
| 733 | { |
| 734 | // Request to LSI chip has changed |
| 735 | if (data & SC499_CTR_REQ) |
| 736 | { |
| 737 | LOG3(("write_control_port: Request to LSI chip = On")); |
| 738 | |
| 739 | if (m_command == SC499_CMD_READ_STATUS) { |
| 740 | m_status |= SC499_STAT_EXC; |
| 741 | } |
| 742 | |
| 743 | if (m_command == SC499_CMD_READ_FILE_MARK && m_current_command == SC499_CMD_READ_DATA) |
| 744 | { |
| 745 | m_current_command= SC499_CMD_READ_FILE_MARK; |
| 746 | m_status &= ~SC499_STAT_DIR; |
| 747 | } |
| 748 | |
| 749 | if (!(m_status & SC499_STAT_DIR)) |
| 750 | { |
| 751 | // write command and command data |
| 752 | // (SC499_STAT_RDY follows SC499_CTR_REQ) |
| 753 | m_status &= ~SC499_STAT_RDY; |
| 754 | } |
| 755 | else |
| 756 | { |
| 757 | m_status |= SC499_STAT_RDY; |
| 758 | } |
| 759 | } |
| 760 | else |
| 761 | { |
| 762 | LOG2(("write_control_port: Request to LSI chip = Off (%d)", m_data_index)); |
| 763 | |
| 764 | if (!(m_status & SC499_STAT_DIR)) |
| 765 | { |
| 766 | do_command(m_command); |
| 767 | m_current_command = m_command; |
| 768 | } |
| 769 | else if (m_command == SC499_CMD_READ_STATUS) |
| 770 | { |
| 771 | // if (m_data_index > 0) |
| 772 | { |
| 773 | m_timer->adjust( attotime::from_usec(20), SC499_TIMER_4); |
| 774 | } |
| 775 | } |
| 776 | } |
| 777 | } |
| 778 | m_control = data; |
| 779 | } |
| 780 | |
| 781 | UINT8 sc499_device::read_status_port() |
| 782 | { |
| 783 | static UINT8 m_last_status = 0xff; |
| 784 | |
| 785 | // omit excessive logging |
| 786 | if (m_last_status != m_status) |
| 787 | { |
| 788 | LOG2(("read_status_port: %02x", m_status)); |
| 789 | m_last_status = m_status; |
| 790 | } |
| 791 | |
| 792 | // reset pending interrupts |
| 793 | set_interrupt(CLEAR_LINE); |
| 794 | m_status &= ~SC499_STAT_IRQ; |
| 795 | |
| 796 | return m_last_status; |
| 797 | } |
| 798 | |
| 799 | // Start DMA (DMAGO). Any write to this register will cause DMAGO to be active. |
| 800 | |
| 801 | void sc499_device::write_dma_go( UINT8 data) |
| 802 | { |
| 803 | LOG2(("write_dma_go: %02x", data)); |
| 804 | |
| 805 | m_status &= ~SC499_STAT_DON; |
| 806 | |
| 807 | switch (data) |
| 808 | { |
| 809 | case 0: |
| 810 | // delay set_dma_drq(ASSERT_LINE); |
| 811 | // Note: 200 usec may fail for MD LD; 400 usec may fail for RBAK_SHELL; 500 usec may fail for DN3000 |
| 812 | m_timer->adjust( attotime::from_msec(1), SC499_TIMER_3); |
| 813 | |
| 814 | // Note: proper sequence is: |
| 815 | // pc=3c4ad714 - ctape: write_dma_go: 00 |
| 816 | // pc=3c4ad718 - ctape: write_control_port: 30 |
| 817 | // pc=3c40ebda: apollo_dma_1_w: writing DMA Controller 1 at offset 02 = 00 |
| 818 | // pc=3c40ebe8: apollo_dma_1_w: writing DMA Controller 1 at offset 02 = 22 |
| 819 | // pc=3c40ebf4: apollo_dma_1_w: writing DMA Controller 1 at offset 0c = 00 |
| 820 | // pc=3c40ec04: apollo_dma_1_w: writing DMA Controller 1 at offset 03 = ff |
| 821 | // pc=3c40ec12: apollo_dma_1_w: writing DMA Controller 1 at offset 03 = 01 |
| 822 | // pc=3c40ec1e: apollo_dma_1_w: writing DMA Controller 1 at offset 0b = 45 |
| 823 | // pc=3c40ec2e: apollo_dma_1_w: writing DMA Controller 1 at offset 0a = 01 |
| 824 | // pc=3c41a154 - ctape: timer_func param=3 status=2f |
| 825 | // pc=3c41a154 - ctape: set_dma_drq(1) |
| 826 | // pc=3c41a154 - maincpu: apollo_dma_ctape_drq: state=1 |
| 827 | // pc=3c41a154 - ctape: dack_read: data[0]=55 status=6f |
| 828 | // pc=3c41a154: dma write byte at offset 17f9c00+200 = 55 |
| 829 | // pc=3c41a154: dma write byte at offset 17f9c00+2ff = 6d |
| 830 | // pc=3c41a154: dma write byte at offset 17f9c00+300 = 65 |
| 831 | // pc=3c41a154 - ctape: dack_read: data[511]=60 status=6f |
| 832 | // pc=3c41a154: dma write byte at offset 17f9c00+3ff = 60 |
| 833 | // pc=3c41a154 - dma8237_1: dma out eop state 00 |
| 834 | // pc=3c41a154 - ctape: set_tc_state: block=21 state=0 |
| 835 | // pc=3c41a154 - ctape: set_dma_drq(0) |
| 836 | // pc=3c41a154 - maincpu: apollo_dma_ctape_drq: state=0 |
| 837 | // pc=3c41a154 - dma8237_1: dma out eop state 01 |
| 838 | // pc=3c41a154 - ctape: set_tc_state: block=21 state=1 |
| 839 | |
| 840 | break; |
| 841 | } |
| 842 | } |
| 843 | |
| 844 | // Reset DMA (RSTDMA). Any write to this register will cause RSTDMA to be active. |
| 845 | |
| 846 | void sc499_device::write_dma_reset( UINT8 data) |
| 847 | { |
| 848 | LOG2(("write_dma_reset: %02x", data)); |
| 849 | |
| 850 | m_status &= ~SC499_STAT_DON; |
| 851 | m_control = 0; |
| 852 | } |
| 853 | |
| 854 | void sc499_device::write_port(offs_t offset, UINT8 data) |
| 855 | { |
| 856 | switch (offset) |
| 857 | { |
| 858 | case SC499_PORT_COMMAND: // write command |
| 859 | write_command_port(data); |
| 860 | break; |
| 861 | case SC499_PORT_CONTROL: // write control |
| 862 | write_control_port(data); |
| 863 | break; |
| 864 | case SC499_PORT_DMAGO: // write only, Start DMA |
| 865 | write_dma_go(data); |
| 866 | break; |
| 867 | case SC499_PORT_RSTDMA: // write only, Reset DMA |
| 868 | write_dma_reset(data); |
| 869 | break; |
| 870 | default: |
| 871 | LOG(("writing sc499 Register at offset %02x = %02x", offset, data)); |
| 872 | break; |
| 873 | } |
| 874 | } |
| 875 | |
| 876 | //READ8_DEVICE_HANDLER( sc499_r ) |
| 877 | UINT8 sc499_device::read_port(offs_t offset) |
| 878 | { |
| 879 | UINT8 data = 0xff; |
| 880 | |
| 881 | switch (offset) |
| 882 | { |
| 883 | case SC499_PORT_DATA: // read data (status data) |
| 884 | data = read_data_port(); |
| 885 | break; |
| 886 | case SC499_PORT_STATUS: // read status |
| 887 | data=read_status_port(); |
| 888 | // set_interrupt(CLEAR_LINE); |
| 889 | break; |
| 890 | default: |
| 891 | LOG(("reading sc499 Register at offset %02x = %02x", offset, data)); |
| 892 | break; |
| 893 | } |
| 894 | |
| 895 | return data; |
| 896 | } |
| 897 | |
| 898 | void sc499_device::set_tc_state(int state) |
| 899 | { |
| 900 | LOG2(("set_tc_state: block=%d state=%x", m_tape_pos-1, state)); |
| 901 | if (state == 0) |
| 902 | { |
| 903 | m_status |= SC499_STAT_DON; // 37ec |
| 904 | set_dma_drq(CLEAR_LINE); |
| 905 | |
| 906 | switch (m_current_command & SC499_CMD_TYPE_MASK) |
| 907 | { |
| 908 | case SC499_CMD_READ_DATA: |
| 909 | m_read_block_pending = 0; |
| 910 | break; |
| 911 | |
| 912 | case SC499_CMD_WRITE_DATA: |
| 913 | m_status &= ~SC499_STAT_RDY; |
| 914 | if ((m_control & SC499_CTR_IEN) && (m_control & SC499_CTR_DNI)) |
| 915 | { |
| 916 | set_interrupt(ASSERT_LINE); |
| 917 | m_status | SC499_STAT_IRQ; |
| 918 | } |
| 919 | break; |
| 920 | } |
| 921 | } |
| 922 | } |
| 923 | |
| 924 | UINT8 sc499_device::dack_read() { |
| 925 | UINT8 data = 0xff; |
| 926 | |
| 927 | // set_dma_drq(CLEAR_LINE); |
| 928 | |
| 929 | if (m_ctape_block_index >= SC499_CTAPE_BLOCK_SIZE) |
| 930 | { |
| 931 | LOG3(("dack_read: read_block")); |
| 932 | read_block(); |
| 933 | m_nasty_readahead++; |
| 934 | |
| 935 | if (block_is_filemark()) |
| 936 | { |
| 937 | set_dma_drq(CLEAR_LINE); |
| 938 | m_status &= ~SC499_STAT_EXC; |
| 939 | m_status &= ~SC499_STAT_DIR; |
| 940 | } |
| 941 | } |
| 942 | |
| 943 | data = m_ctape_block_buffer[m_ctape_block_index++]; |
| 944 | if (m_ctape_block_index < 2 || m_ctape_block_index > 511) |
| 945 | { |
| 946 | LOG2(("dack_read: data[%d]=%x status=%x", m_ctape_block_index-1, data, m_status)); |
| 947 | } |
| 948 | |
| 949 | // if (m_ctape_block_index < SC499_CTAPE_BLOCK_SIZE) |
| 950 | // { |
| 951 | // set_dma_drq(ASSERT_LINE); |
| 952 | // } |
| 953 | |
| 954 | return data; |
| 955 | } |
| 956 | |
| 957 | void sc499_device::dack_write(UINT8 data) { |
| 958 | LOG3(("dack_write: data=%x", data)); |
| 959 | |
| 960 | if (m_ctape_block_index < SC499_CTAPE_BLOCK_SIZE) |
| 961 | { |
| 962 | m_ctape_block_buffer[m_ctape_block_index++] = data; |
| 963 | } |
| 964 | |
| 965 | if (m_ctape_block_index == SC499_CTAPE_BLOCK_SIZE) |
| 966 | { |
| 967 | LOG3(("dack_write: write_block")); |
| 968 | write_block(); |
| 969 | } |
| 970 | } |
| 971 | |
| 972 | /*------------------------------------------------- |
| 973 | log_block - log block data |
| 974 | -------------------------------------------------*/ |
| 975 | |
| 976 | void sc499_device::log_block(const char *text) |
| 977 | { |
| 978 | int data_length = 16; |
| 979 | |
| 980 | if (verbose > 0) { |
| 981 | int i; |
| 982 | logerror("%s: %s %d -", cpu_context(), text, m_tape_pos); |
| 983 | for (i = 0; i < data_length && i < SC499_CTAPE_BLOCK_SIZE; i++) { |
| 984 | logerror(" %02x", m_ctape_block_buffer[i]); |
| 985 | } |
| 986 | |
| 987 | if (i < SC499_CTAPE_BLOCK_SIZE) { |
| 988 | logerror(" ..."); |
| 989 | } |
| 990 | |
| 991 | if (m_ctape_block_index > 0 && m_ctape_block_index != SC499_CTAPE_BLOCK_SIZE) |
| 992 | { |
| 993 | logerror(" block_index = %d !!!", m_ctape_block_index); |
| 994 | } |
| 995 | |
| 996 | logerror("\n"); |
| 997 | } |
| 998 | } |
| 999 | |
| 1000 | /*------------------------------------------------- |
| 1001 | read_block - read block from m_tape_pos to m_ctape_block_buffer |
| 1002 | -------------------------------------------------*/ |
| 1003 | |
| 1004 | void sc499_device::read_block() |
| 1005 | { |
| 1006 | if (m_tape_pos == 0) |
| 1007 | { |
| 1008 | // check if tape has been replaced or removed |
| 1009 | check_tape(); |
| 1010 | } |
| 1011 | |
| 1012 | m_image->fseek((UINT64) m_tape_pos * SC499_CTAPE_BLOCK_SIZE, SEEK_SET); |
| 1013 | |
| 1014 | if (m_image->image_feof()) |
| 1015 | { |
| 1016 | m_status &= ~SC499_STAT_EXC; |
| 1017 | m_status &= ~SC499_STAT_DIR; |
| 1018 | m_status &= ~SC499_STAT_DON; |
| 1019 | tape_status_clear(SC499_ST_CLEAR_ALL); |
| 1020 | tape_status_set(SC499_ST_READ_ERROR); |
| 1021 | } |
| 1022 | else |
| 1023 | { |
| 1024 | m_image->fread(m_ctape_block_buffer, SC499_CTAPE_BLOCK_SIZE); |
| 1025 | |
| 1026 | // if (verbose > 1 || m_tape_pos % 100 == 0) |
| 1027 | { |
| 1028 | log_block("read_block"); |
| 1029 | } |
| 1030 | |
| 1031 | m_ctape_block_index = 0; |
| 1032 | m_tape_pos++; |
| 1033 | |
| 1034 | if (m_first_block_hack) |
| 1035 | { |
| 1036 | // FIXME: we must read first block twice (in MD for 'di c' and 'ld' or 'ex ...') |
| 1037 | // why is this necessary??? |
| 1038 | m_tape_pos = 0; |
| 1039 | LOG(("read_block - duplicating block %d", m_tape_pos)); |
| 1040 | } |
| 1041 | m_first_block_hack = 0; |
| 1042 | |
| 1043 | // we are no longer at Beginning of media (BOM) |
| 1044 | tape_status_clear(SC499_ST1_BOM); |
| 1045 | |
| 1046 | if (block_is_filemark()) |
| 1047 | { |
| 1048 | m_status &= ~SC499_STAT_EXC; |
| 1049 | m_status &= ~SC499_STAT_DIR; |
| 1050 | tape_status_clear(SC499_ST_CLEAR_ALL); |
| 1051 | tape_status_set(SC499_ST0_FM); |
| 1052 | } |
| 1053 | else |
| 1054 | { |
| 1055 | tape_status_clear(SC499_ST0_FM); |
| 1056 | } |
| 1057 | } |
| 1058 | // if (m_tape_pos == 69400) verbose = 2; |
| 1059 | } |
| 1060 | |
| 1061 | /*------------------------------------------------- |
| 1062 | write_block - write block from m_ctape_block_buffer to m_tape_pos |
| 1063 | -------------------------------------------------*/ |
| 1064 | |
| 1065 | void sc499_device::write_block() |
| 1066 | { |
| 1067 | log_block("write_block"); |
| 1068 | |
| 1069 | if (m_tape_pos == 0) |
| 1070 | { |
| 1071 | // check if tape has been replaced or removed |
| 1072 | check_tape(); |
| 1073 | } |
| 1074 | |
| 1075 | m_image->fseek((UINT64) m_tape_pos * SC499_CTAPE_BLOCK_SIZE, SEEK_SET); |
| 1076 | m_image->fwrite(m_ctape_block_buffer, SC499_CTAPE_BLOCK_SIZE); |
| 1077 | m_ctape_block_count = m_tape_pos; |
| 1078 | m_ctape_block_index = 0; |
| 1079 | m_tape_pos++; |
| 1080 | |
| 1081 | // we are no longer at Beginning of media (BOM) |
| 1082 | tape_status_clear(SC499_ST1_BOM); |
| 1083 | } |
| 1084 | |
| 1085 | /*------------------------------------------------- |
| 1086 | block_is_filemark - returns 1 is current block buffer data is filemark |
| 1087 | -------------------------------------------------*/ |
| 1088 | |
| 1089 | int sc499_device::block_is_filemark() |
| 1090 | { |
| 1091 | static const UINT8 fm_pattern[] = {0xDE, 0xAF, 0xFA, 0xED}; |
| 1092 | |
| 1093 | int is_filemark = memcmp(m_ctape_block_buffer, fm_pattern, 4) == 0 && |
| 1094 | memcmp(m_ctape_block_buffer, m_ctape_block_buffer+4, SC499_CTAPE_BLOCK_SIZE-4) == 0; |
| 1095 | |
| 1096 | LOG3(("block_is_filemark for block %d = %d", m_tape_pos-1, is_filemark)); |
| 1097 | return is_filemark; |
| 1098 | } |
| 1099 | |
| 1100 | /*------------------------------------------------- |
| 1101 | block_set_filemark - set current block buffer data to filemark |
| 1102 | -------------------------------------------------*/ |
| 1103 | |
| 1104 | void sc499_device::block_set_filemark() |
| 1105 | { |
| 1106 | static const UINT8 fm_pattern[] = {0xDE, 0xAF, 0xFA, 0xED}; |
| 1107 | |
| 1108 | memcpy(m_ctape_block_buffer, fm_pattern, 4); |
| 1109 | memcpy(m_ctape_block_buffer+4, m_ctape_block_buffer, SC499_CTAPE_BLOCK_SIZE-4); |
| 1110 | } |
| 1111 | |
| 1112 | //************************************************************************** |
| 1113 | // GLOBAL STUBS |
| 1114 | //************************************************************************** |
| 1115 | |
| 1116 | READ8_DEVICE_HANDLER( sc499_r ) |
| 1117 | { |
| 1118 | return downcast<sc499_device *> (device)->read_port(offset); |
| 1119 | } |
| 1120 | |
| 1121 | WRITE8_DEVICE_HANDLER( sc499_w ) |
| 1122 | { |
| 1123 | downcast<sc499_device *> (device)->write_port(offset, data); |
| 1124 | } |
| 1125 | |
| 1126 | void sc499_set_tc_state(running_machine *machine, int state) |
| 1127 | { |
| 1128 | sc499_device::m_device->set_tc_state(state); |
| 1129 | } |
| 1130 | |
| 1131 | UINT8 sc499_dack_r(running_machine *machine) |
| 1132 | { |
| 1133 | return sc499_device::m_device->dack_read(); |
| 1134 | } |
| 1135 | |
| 1136 | void sc499_dack_w(running_machine *machine, UINT8 data) |
| 1137 | { |
| 1138 | sc499_device::m_device->dack_write(data); |
| 1139 | } |
| 1140 | |
| 1141 | void sc499_set_verbose(int on_off) |
| 1142 | { |
| 1143 | verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1; |
| 1144 | } |
| 1145 | |
| 1146 | //########################################################################## |
| 1147 | |
| 1148 | DECLARE_LEGACY_IMAGE_DEVICE(SC499_CTAPE, sc499_ctape); |
| 1149 | |
| 1150 | /*------------------------------------------------- |
| 1151 | ctape device start callback |
| 1152 | -------------------------------------------------*/ |
| 1153 | |
| 1154 | static DEVICE_START( sc499_ctape ) |
| 1155 | { |
| 1156 | assert(device != NULL); |
| 1157 | assert(device->type() == SC499_CTAPE); |
| 1158 | ctape_data *ctape = (ctape_data *) downcast<legacy_device_base *>(device)->token(); |
| 1159 | |
| 1160 | ctape->image = dynamic_cast<device_image_interface *> (device); |
| 1161 | } |
| 1162 | |
| 1163 | /*------------------------------------------------- |
| 1164 | ctape device get info callback |
| 1165 | -------------------------------------------------*/ |
| 1166 | |
| 1167 | DEVICE_GET_INFO( sc499_ctape ) |
| 1168 | { |
| 1169 | switch (state) |
| 1170 | { |
| 1171 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 1172 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(ctape_data); break; |
| 1173 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 1174 | case DEVINFO_INT_IMAGE_TYPE: info->i = IO_MAGTAPE; break; |
| 1175 | case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break; |
| 1176 | case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break; |
| 1177 | case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break; |
| 1178 | |
| 1179 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 1180 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(sc499_ctape); break; |
| 1181 | |
| 1182 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 1183 | case DEVINFO_STR_NAME: strcpy(info->s, "Cartridge Tape"); break; |
| 1184 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Cartridge Tape"); break; |
| 1185 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 1186 | |
| 1187 | case DEVINFO_STR_IMAGE_INSTANCE_NAME: strcpy(info->s, "ctape"); break; |
| 1188 | case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME: strcpy(info->s, "ct"); break; |
| 1189 | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "act"); break; |
| 1190 | } |
| 1191 | } |
| 1192 | |
| 1193 | DEFINE_LEGACY_IMAGE_DEVICE(SC499_CTAPE, sc499_ctape); |
| 1194 | |
| 1195 | MACHINE_CONFIG_FRAGMENT( sc499_ctape ) |
| 1196 | MCFG_DEVICE_ADD(SC499_CTAPE_TAG, SC499_CTAPE, 0) |
| 1197 | MACHINE_CONFIG_END |
src/mess/machine/apollo_dbg.c
| r0 | r14540 | |
| 1 | /* |
| 2 | * debug/apollo.c - APOLLO DN3500/DN3000 debug functions |
| 3 | * |
| 4 | * Created on: Nov. 21, 2010 |
| 5 | * Author: Hans Ostermeyer |
| 6 | * |
| 7 | * Released for general non-commercial use under the MAME license |
| 8 | * Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | * |
| 10 | */ |
| 11 | |
| 12 | #define VERBOSE 1 |
| 13 | |
| 14 | #include "includes/apollo.h" |
| 15 | #include "cpu/m68000/m68kcpu.h" |
| 16 | |
| 17 | //------------------------------------------------------ |
| 18 | // TRAP 0 |
| 19 | //------------------------------------------------------ |
| 20 | |
| 21 | static const char* trap0[] = { |
| 22 | /* 0x00 */NULL, NULL, |
| 23 | /* 0x01 */"FIM_$GET_FIM_ADDR", "", |
| 24 | /* 0x02 */NULL, NULL, |
| 25 | /* 0x03 */"DTTY_$RELOAD_FONT", "", |
| 26 | /* 0x04 */"FILE_$UNLOCK_ALL", "", |
| 27 | /* 0x05 */NULL, NULL, |
| 28 | /* 0x06 */NULL, NULL, |
| 29 | /* 0x07 */"PROC2_$MY_PID", "", |
| 30 | /* 0x08 */"SMD_$OP_WAIT_U", "", |
| 31 | /* 0x09 */"TPAD_$RE_RANGE", "", |
| 32 | /* 0x0a */NULL, NULL, |
| 33 | /* 0x0b */NULL, NULL, |
| 34 | /* 0x0c */NULL, NULL, |
| 35 | /* 0x0d */"ACL_$UP", "", |
| 36 | /* 0x0e */"ACL_$DOWN", "", |
| 37 | /* 0x0f */NULL, NULL, |
| 38 | /* 0x10 */"TPAD_$INQ_DTYPE", "", |
| 39 | /* 0x11 */NULL, NULL, |
| 40 | /* 0x12 */"CACHE_$CLEAR", "", |
| 41 | /* 0x13 */"RIP_$ANNOUNCE_NS", "", |
| 42 | /* 0x14 */NULL, NULL, |
| 43 | /* 0x15 */NULL, NULL, |
| 44 | /* 0x16 */NULL, NULL, |
| 45 | /* 0x17 */NULL, NULL, |
| 46 | /* 0x18 */"PROC2_$DELIVER_PENDING", "", |
| 47 | /* 0x19 */"PROC2_$COMPLETE_FORK", "", |
| 48 | /* 0x1a */"PACCT_$STOP", "", |
| 49 | /* 0x1b */"PACCT_$ON", "", |
| 50 | /* 0x1c */"ACL_$GET_LOCAL_LOCKSMITH", "", |
| 51 | /* 0x1d */"ACL_$IS_SUSER", "", |
| 52 | /* 0x1e */NULL, NULL, |
| 53 | /* 0x1f */"SMD_$N_DEVICES", "", |
| 54 | /* 0x20 */"PROC1_$GET_MAXID", "", |
| 55 | /* 0x21 */"THREAD_$DELETE", "", |
| 56 | /* 0x22 */"THREAD_$SELF_OS", "", |
| 57 | /* 0x23 */"THREAD_$NUMBER_THREADS", "", |
| 58 | /* 0x24 */"ACL_$GET_PROTECT_OPTION", "", |
| 59 | /* 0x25 */"ACL_$PROTECT_CHECK", "", |
| 60 | /* 0x26 */"THREAD_$YIELD", "" }; |
| 61 | |
| 62 | //------------------------------------------------------ |
| 63 | // TRAP1 |
| 64 | //------------------------------------------------------ |
| 65 | |
| 66 | static const char* trap1[] = { |
| 67 | /* 0x00 */NULL, NULL, |
| 68 | /* 0x01 */NULL, NULL, |
| 69 | /* 0x02 */"FIM_$INSTALL", "x", |
| 70 | /* 0x03 */"NETWORK_$READ_SERVICE", "x", |
| 71 | /* 0x04 */"PROC1_$GET_CPUT", "x", |
| 72 | /* 0x05 */"SET_LITES_LOC", "x", |
| 73 | /* 0x06 */"TIME_$CLOCK", "x", |
| 74 | /* 0x07 */"ASKNODE_$READ_FAILURE_REC", "x", |
| 75 | /* 0x08 */"CAL_$APPLY_LOCAL_OFFSET", "x", |
| 76 | /* 0x09 */"CAL_$GET_INFO", "x", |
| 77 | /* 0x0a */"CAL_$GET_LOCAL_TIME", "x", |
| 78 | /* 0x0b */"CAL_$REMOVE_LOCAL_OFFSET", "x", |
| 79 | /* 0x0c */"CAL_$SET_DRIFT", "x", |
| 80 | /* 0x0d */"DISK_$GET_ERROR_INFO", "x", |
| 81 | /* 0x0e */NULL, NULL, |
| 82 | /* 0x0f */"MSG_$CLOSE", "x", |
| 83 | /* 0x10 */"PROC2_$WHO_AM_I", "u", |
| 84 | /* 0x11 */"SMD_$CLEAR_KBD_CURSOR", "x", |
| 85 | /* 0x12 */NULL, NULL, |
| 86 | /* 0x13 */NULL, NULL, |
| 87 | /* 0x14 */"SMD_$SEND_RESPONSE", "x", |
| 88 | /* 0x15 */"SMD_$STOP_TP_CURSOR", "x", |
| 89 | /* 0x16 */NULL, NULL, |
| 90 | /* 0x17 */NULL, NULL, |
| 91 | /* 0x18 */"SMD_$UNMAP_DISPLAY_U", "x", |
| 92 | /* 0x19 */"UID_$GEN", "x", |
| 93 | /* 0x1a */"TONE_$TIME", "x", |
| 94 | /* 0x1b */"SMD_$INQ_DISP_TYPE", "x", |
| 95 | /* 0x1c */NULL, NULL, |
| 96 | /* 0x1d */NULL, NULL, |
| 97 | /* 0x1e */NULL, NULL, |
| 98 | /* 0x1f */"TPAD_$SET_CURSOR", "x", |
| 99 | /* 0x20 */NULL, NULL, |
| 100 | /* 0x21 */NULL, NULL, |
| 101 | /* 0x22 */"NAME_$GET_WDIR_UID", "u", |
| 102 | /* 0x23 */"NAME_$GET_NDIR_UID", "u", |
| 103 | /* 0x24 */"NAME_$GET_ROOT_UID", "u", |
| 104 | /* 0x25 */"NAME_$GET_NODE_UID", "u", |
| 105 | /* 0x26 */"NAME_$GET_NODE_DATA_UID", "u", |
| 106 | /* 0x27 */"NAME_$GET_CANNED_ROOT_UID", "u", |
| 107 | /* 0x28 */"MSG_$GET_MY_NET", "x", |
| 108 | /* 0x29 */"MSG_$GET_MY_NODE", "x", |
| 109 | /* 0x2a */NULL, NULL, |
| 110 | /* 0x2b */NULL, NULL, |
| 111 | /* 0x2c */NULL, NULL, |
| 112 | /* 0x2d */NULL, NULL, |
| 113 | /* 0x2e */NULL, NULL, |
| 114 | /* 0x2f */NULL, NULL, |
| 115 | /* 0x30 */"GPU_$INIT", "x", |
| 116 | /* 0x31 */NULL, NULL, |
| 117 | /* 0x32 */"SMD_$INIT_STATE", "x", |
| 118 | /* 0x33 */"SMD_$CLR_TRK_RECT", "x", |
| 119 | /* 0x34 */"PROC2_$GET_SIG_MASK", "x", |
| 120 | /* 0x35 */"FIM_$FRESTORE", "x", |
| 121 | /* 0x36 */"TIME_$GET_TIME_OF_DAY", "x", |
| 122 | /* 0x37 */"PROC1_$GET_LOADAV", "x", |
| 123 | /* 0x38 */"PROC2_$GET_BOOT_FLAGS", "x", |
| 124 | /* 0x39 */NULL, NULL, |
| 125 | /* 0x3a */"PROC2_$SET_TTY", "x", |
| 126 | /* 0x3b */"OS_$SHUTDOWN", "x", |
| 127 | /* 0x3c */"PBU_$FAULTED_UNITS", "x", |
| 128 | /* 0x3d */"PROC2_$GET_CPU_USAGE", "x", |
| 129 | /* 0x3e */NULL, NULL, |
| 130 | /* 0x3f */NULL, NULL, |
| 131 | /* 0x40 */NULL, NULL, |
| 132 | /* 0x41 */"TIME_$GET_ADJUST", "x", |
| 133 | /* 0x42 */"FILE_$SYNC", "x", |
| 134 | /* 0x43 */"XPAGE_$IS_MAPPED", "x", |
| 135 | /* 0x44 */"THREAD_$SUSPEND_FOR_FORK", "x", |
| 136 | /* 0x45 */"THREAD_$RESUME_FOR_FORK", "x" }; |
| 137 | |
| 138 | //------------------------------------------------------ |
| 139 | // TRAP2 |
| 140 | //------------------------------------------------------ |
| 141 | |
| 142 | static const char* trap2[] = { |
| 143 | /* 0x00 */NULL, NULL, |
| 144 | /* 0x01 */NULL, NULL, |
| 145 | /* 0x02 */"FILE_$DELETE", "x,x", |
| 146 | /* 0x03 */"EC2_$WAKEUP", "x,x", |
| 147 | /* 0x04 */NULL, NULL, |
| 148 | /* 0x05 */"ACL_$GET_SID", "x,x", |
| 149 | /* 0x06 */"FILE_$MK_PERMANENT", "x,x", |
| 150 | /* 0x07 */"FILE_$UNLOCK_VOL", "x,x", |
| 151 | /* 0x08 */"CAL_$READ_TIMEZONE", "x,x", |
| 152 | /* 0x09 */"CAL_$SEC_TO_CLOCK", "x,x", |
| 153 | /* 0x0a */"CAL_$WRITE_TIMEZONE", "x,x", |
| 154 | /* 0x0b */"DISK_$UNASSIGN", "x,x", |
| 155 | /* 0x0c */"FILE_$FORCE_UNLOCK", "x,x", |
| 156 | /* 0x0d */"FILE_$FW_FILE", "x,x", |
| 157 | /* 0x0e */"FILE_$MK_IMMUTABLE", "x,x", |
| 158 | /* 0x0f */"FILE_$PURIFY", "x,x", |
| 159 | /* 0x10 */"GET_BUILD_TIME", "x,x", |
| 160 | /* 0x11 */NULL, NULL, |
| 161 | /* 0x12 */NULL, NULL, |
| 162 | /* 0x13 */"MSG_$ALLOCATE", "x,x", |
| 163 | /* 0x14 */"MSG_$OPEN", "x,x", |
| 164 | /* 0x15 */"MSG_$WAIT", "x,x", |
| 165 | /* 0x16 */NULL, NULL, |
| 166 | /* 0x17 */NULL, NULL, |
| 167 | /* 0x18 */"PBU_$DEVICE_INTERRUPTING", "x,x", |
| 168 | /* 0x19 */"PBU_$DISABLE_DEVICE", "x,x", |
| 169 | /* 0x1a */"PBU_$ENABLE_DEVICE", "x,x", |
| 170 | /* 0x1b */"PBU_$FREE_MAP", "x,x", |
| 171 | /* 0x1c */"PROC2_$QUIT", "x,x", |
| 172 | /* 0x1d */"PROC2_$RESUME", "x,x", |
| 173 | /* 0x1e */"PROC2_$SUSPEND", "x,x", |
| 174 | /* 0x1f */NULL, NULL, |
| 175 | /* 0x20 */NULL, NULL, |
| 176 | /* 0x21 */NULL, NULL, |
| 177 | /* 0x22 */NULL, NULL, |
| 178 | /* 0x23 */NULL, NULL, |
| 179 | /* 0x24 */NULL, NULL, |
| 180 | /* 0x25 */NULL, NULL, |
| 181 | /* 0x26 */"SMD_$MAP_DISPLAY_U", "x,x", |
| 182 | /* 0x27 */"SMD_$MOVE_KBD_CURSOR", "x,x", |
| 183 | /* 0x28 */NULL, NULL, |
| 184 | /* 0x29 */"SMD_$RETURN_DISPLAY", "x,x", |
| 185 | /* 0x2a */NULL, NULL, |
| 186 | /* 0x2b */NULL, NULL, |
| 187 | /* 0x2c */NULL, NULL, |
| 188 | /* 0x2d */NULL, NULL, |
| 189 | /* 0x2e */"PEB_$GET_INFO", "x,x", |
| 190 | /* 0x2f */NULL, NULL, |
| 191 | /* 0x30 */"EC2_$GET_VAL", "x,x", |
| 192 | /* 0x31 */"AST_$ADD_ASTES", "x,x", |
| 193 | /* 0x32 */"PBU_$DISSOC", "x,x", |
| 194 | /* 0x33 */"PROC2_$MAKE_ORPHAN", "x,x", |
| 195 | /* 0x34 */"FILE_$DELETE_FORCE", "x,x", |
| 196 | /* 0x35 */"FILE_$DELETE_WHEN_UNLOCKED", "x,x", |
| 197 | /* 0x36 */"FILE_$MK_TEMPORARY", "x,x", |
| 198 | /* 0x37 */NULL, NULL, |
| 199 | /* 0x38 */NULL, NULL, |
| 200 | /* 0x39 */NULL, NULL, |
| 201 | /* 0x3a */NULL, NULL, |
| 202 | /* 0x3b */"SMD_$INQ_KBD_CURSOR", "x,x", |
| 203 | /* 0x3c */"ACL_$ENTER_SUBS", "u,x", |
| 204 | /* 0x3d */NULL, NULL, |
| 205 | /* 0x3e */NULL, NULL, |
| 206 | /* 0x3f */NULL, NULL, |
| 207 | /* 0x40 */NULL, NULL, |
| 208 | /* 0x41 */NULL, NULL, |
| 209 | /* 0x42 */"FILE_$DELETE_FORCE_WHEN_UNLOCKED", "x,x", |
| 210 | /* 0x43 */NULL, NULL, |
| 211 | /* 0x44 */"CT_$ACQUIRE", "x,x", |
| 212 | /* 0x45 */"HINT_$ADD", "x,x", |
| 213 | /* 0x46 */"DIR_$FIX_DIR", "x,x", |
| 214 | /* 0x47 */"NAME_$SET_WDIRUS", "u,x", |
| 215 | /* 0x48 */"NAME_$SET_NDIRUS", "u,x", |
| 216 | /* 0x49 */NULL, NULL, |
| 217 | /* 0x4a */NULL, NULL, |
| 218 | /* 0x4b */"MSG_$CLOSEI", "x,x", |
| 219 | /* 0x4c */"NETWORK_$ADD_PAGE_SERVERS", "x,x", |
| 220 | /* 0x4d */"NETWORK_$ADD_REQUEST_SERVERS", "x,x", |
| 221 | /* 0x4e */"ACL_$ADD_PROJ", "x,x", |
| 222 | /* 0x4f */"ACL_$DELETE_PROJ", "x,x", |
| 223 | /* 0x50 */NULL, NULL, |
| 224 | /* 0x51 */NULL, NULL, |
| 225 | /* 0x52 */"SMD_$SET_TP_REPORTING", "x,x", |
| 226 | /* 0x53 */"SMD_$DISABLE_TRACKING", "x,x", |
| 227 | /* 0x54 */NULL, NULL, |
| 228 | /* 0x55 */NULL, NULL, |
| 229 | /* 0x56 */NULL, NULL, |
| 230 | /* 0x57 */NULL, NULL, |
| 231 | /* 0x58 */"HINT_$ADDI", "x,x", |
| 232 | /* 0x59 */NULL, NULL, |
| 233 | /* 0x5a */NULL, NULL, |
| 234 | /* 0x5b */"PBU_$ALLOCATE_EC", "x,x", |
| 235 | /* 0x5c */"SMD_$SET_DISP_UNIT", "x,x", |
| 236 | /* 0x5d */"SMD_$VIDEO_CTL", "x,x", |
| 237 | /* 0x5e */"SMD_$SET_CURSOR_POS", "x,x", |
| 238 | /* 0x5f */"TERM_$SEND_KBD_STRING", "x,x", |
| 239 | /* 0x60 */"AUDIT_$CONTROL", "x,x", |
| 240 | /* 0x61 */"PROC2_$SIGBLOCK", "x,x", |
| 241 | /* 0x62 */"PROC2_$SIGSETMASK", "x,x", |
| 242 | /* 0x63 */"PROC2_$SIGPAUSE", "x,x", |
| 243 | /* 0x64 */"ACL_$FIPS_CTL", "x,x", |
| 244 | /* 0x65 */"AS_$GET_ADDR", "x,x", |
| 245 | /* 0x66 */"PROC2_$GET_ASID", "x,x", |
| 246 | /* 0x67 */"TTY_$K_FLUSH_INPUT", "x,x", |
| 247 | /* 0x68 */"TTY_$K_FLUSH_OUTPUT", "x,x", |
| 248 | /* 0x69 */"TTY_$K_DRAIN_OUTPUT", "x,x", |
| 249 | /* 0x6a */"PROC2_$DEBUG", "x,x", |
| 250 | /* 0x6b */"PROC2_$UNDEBUG", "x,x", |
| 251 | /* 0x6c */"ACL_$DEF_ACLDATA", "x,x", |
| 252 | /* 0x6d */"PROC2_$OVERRIDE_DEBUG", "x,x", |
| 253 | /* 0x6e */"TIME_$SET_TIME_OF_DAY", "x,x", |
| 254 | /* 0x6f */"CAL_$DECODE_TIME", "x,x", |
| 255 | /* 0x70 */"ACL_$INHERIT_SUBSYS", "x,x", |
| 256 | /* 0x71 */"ACL_$SET_LOCAL_LOCKSMITH", "x,x", |
| 257 | /* 0x72 */NULL, NULL, |
| 258 | /* 0x73 */"SMD_$DISSOC", "x,x", |
| 259 | /* 0x74 */"SMD_$BUSY_WAIT", "x,x", |
| 260 | /* 0x75 */"TTY_$K_OLD_RESET", "x,x", |
| 261 | /* 0x76 */NULL, NULL, |
| 262 | /* 0x77 */NULL, NULL, |
| 263 | /* 0x78 */NULL, NULL, |
| 264 | /* 0x79 */"SCSI_$ABORT_OPERATION", "x,x", |
| 265 | /* 0x7a */"SCSI_$RELEASE", "x,x", |
| 266 | /* 0x7b */"SCSI_$RESET_DEVICE", "x,x", |
| 267 | /* 0x7c */NULL, NULL, |
| 268 | /* 0x7d */"TPAD_$RE_RANGE_UNIT", "x,x", |
| 269 | /* 0x7e */"DISK_$FORMAT_WHOLE", "x,x", |
| 270 | /* 0x7f */NULL, NULL, |
| 271 | /* 0x80 */NULL, NULL, |
| 272 | /* 0x81 */NULL, NULL, |
| 273 | /* 0x82 */NULL, NULL, |
| 274 | /* 0x83 */NULL, NULL, |
| 275 | /* 0x84 */"SMD_$SEND_UNIT_RESPONSE", "x,x", |
| 276 | /* 0x85 */NULL, NULL, |
| 277 | /* 0x86 */"MST_$FW_XTAL", "x,x", |
| 278 | /* 0x87 */"THREAD_$TERMINATE", "x,x", |
| 279 | /* 0x88 */"THREAD_$TERMINATE_ALL", "u,x", |
| 280 | /* 0x89 */"THREAD_$SUSPEND", "x,x", |
| 281 | /* 0x8a */"THREAD_$RESUME", "x,x", |
| 282 | /* 0x8b */"THREAD_$HANDLE_SIGNALS", "x,x", |
| 283 | /* 0x8c */"THREAD_$ABORT", "x,x", |
| 284 | /* 0x8d */"ACL_$SET_PROTECT_OPTION", "x,x", |
| 285 | /* 0x8e */"TTY_$K_SUSPEND_INPUT", "x,x", |
| 286 | /* 0x8f */"TTY_$K_RESUME_INPUT", "x,x", |
| 287 | /* 0x90 */"TTY_$K_SUSPEND_OUTPUT", "x,x", |
| 288 | /* 0x91 */"TTY_$K_RESUME_OUTPUT", "x,x" }; |
| 289 | |
| 290 | //------------------------------------------------------ |
| 291 | // TRAP3 |
| 292 | //------------------------------------------------------ |
| 293 | |
| 294 | static const char* trap3[] = { |
| 295 | /* 0x00 */"PBU2_$DMA_STOP", "x,x,x", |
| 296 | /* 0x01 */NULL, NULL, |
| 297 | /* 0x02 */"FILE_$CREATE", "x,x,x", |
| 298 | /* 0x03 */"FILE_$UNLOCK", "u,x,x", |
| 299 | /* 0x04 */"FILE_$TRUNCATE", "u,x,x", |
| 300 | /* 0x05 */"MST_$UNMAPS", "x,x,x", |
| 301 | /* 0x06 */"VFMT_$WRITE", "s,x,x", |
| 302 | /* 0x07 */"FILE_$ATTRIBUTES", "x,x,x", |
| 303 | /* 0x08 */"FILE_$SET_LEN", "x,x,x", |
| 304 | /* 0x09 */"FILE_$SET_TYPE", "x,x,x", |
| 305 | /* 0x0a */NULL, NULL, |
| 306 | /* 0x0b */NULL, NULL, |
| 307 | /* 0x0c */NULL, NULL, |
| 308 | /* 0x0d */NULL, NULL, |
| 309 | /* 0x0e */"NETWORK_$SET_SERVICE", "x,x,x", |
| 310 | /* 0x0f */"ASKNODE_$WHO", "s,x,x", |
| 311 | /* 0x10 */"FILE_$ACT_ATTRIBUTES", "x,x,x", |
| 312 | /* 0x11 */"FILE_$LOCATE", "x,x,x", |
| 313 | /* 0x12 */"FILE_$NEIGHBORS", "x,x,x", |
| 314 | /* 0x13 */"FILE_$READ_LOCK_ENTRYU", "x,x,x", |
| 315 | /* 0x14 */"FILE_$SET_ACL", "x,x,x", |
| 316 | /* 0x15 */"FILE_$SET_DIRPTR", "x,x,x", |
| 317 | /* 0x16 */"FILE_$SET_TROUBLE", "x,x,x", |
| 318 | /* 0x17 */NULL, NULL, |
| 319 | /* 0x18 */NULL, NULL, |
| 320 | /* 0x19 */NULL, NULL, |
| 321 | /* 0x1a */NULL, NULL, |
| 322 | /* 0x1b */NULL, NULL, |
| 323 | /* 0x1c */"PBU_$DMA_STOP", "x,x,x", |
| 324 | /* 0x1d */"PBU_$SETDOWN", "x,x,x", |
| 325 | /* 0x1e */"PBU_$SETUP", "x,x,x", |
| 326 | /* 0x1f */"PROC2_$LIST", "x,x,x", |
| 327 | /* 0x20 */"FIM_$SINGLE_STEP", "x,x,x", |
| 328 | /* 0x21 */"SMD_$ASSOC", "x,x,x", |
| 329 | /* 0x22 */"SMD_$BORROW_DISPLAY", "x,x,x", |
| 330 | /* 0x23 */NULL, NULL, |
| 331 | /* 0x24 */NULL, NULL, |
| 332 | /* 0x25 */"SMD_$SET_TP_CURSOR", "x,x,x", |
| 333 | /* 0x26 */"TIME_$WAIT", "x,x,x", |
| 334 | /* 0x27 */"RINGLOG_$CNTL", "x,x,x", |
| 335 | /* 0x28 */"SMD_$ALLOC_HDM", "x,x,x", |
| 336 | /* 0x29 */"SMD_$FREE_HDM", "x,x,x", |
| 337 | /* 0x2a */NULL, NULL, |
| 338 | /* 0x2b */"OS_$GET_EC", "x,x,x", |
| 339 | /* 0x2c */"TIME_$GET_EC", "x,x,x", |
| 340 | /* 0x2d */NULL, NULL, |
| 341 | /* 0x2e */"PROC2_$UPID_TO_UID", "x,u,x", |
| 342 | /* 0x2f */"MSG_$GET_EC", "x,x,x", |
| 343 | /* 0x30 */"DISK_$AS_OPTIONS", "x,x,x", |
| 344 | /* 0x31 */"SMD_$GET_EC", "x,x,x", |
| 345 | /* 0x32 */"NAME_$SET_ACL", "x,x,x", |
| 346 | /* 0x33 */"FILE_$SET_REFCNT", "x,x,x", |
| 347 | /* 0x34 */NULL, NULL, |
| 348 | /* 0x35 */"PROC1_$GET_INFO", "x,x,x", |
| 349 | /* 0x36 */NULL, NULL, |
| 350 | /* 0x37 */NULL, NULL, |
| 351 | /* 0x38 */NULL, NULL, |
| 352 | /* 0x39 */NULL, NULL, |
| 353 | /* 0x3a */NULL, NULL, |
| 354 | /* 0x3b */NULL, NULL, |
| 355 | /* 0x3c */"AS_$GET_INFO", "x,x,x", |
| 356 | /* 0x3d */"FILE_$SET_DTM", "x,x,x", |
| 357 | /* 0x3e */"FILE_$SET_DTU", "x,x,x", |
| 358 | /* 0x3f */NULL, NULL, |
| 359 | /* 0x40 */"LOG_$READ", "x,x,x", |
| 360 | /* 0x41 */"PROC2_$SET_PGROUP", "x,x,x", |
| 361 | /* 0x42 */"SMD_$SET_BLANK_TIMEOUT", "x,x,x", |
| 362 | /* 0x43 */"SMD_$INQ_BLANK_TIMEOUT", "x,x,x", |
| 363 | /* 0x44 */"FILE_$REMOVE_WHEN_UNLOCKED", "x,x,x", |
| 364 | /* 0x45 */"CT_$RELEASE", "x,x,x", |
| 365 | /* 0x46 */"PROC2_$UPGID_TO_UID", "x,x,x", |
| 366 | /* 0x47 */"TIME_$GET_ITIMER", "x,x,x", |
| 367 | /* 0x48 */"DIR_$SET_DAD", "x,x,x", |
| 368 | /* 0x49 */NULL, NULL, |
| 369 | /* 0x4a */NULL, NULL, |
| 370 | /* 0x4b */NULL, NULL, |
| 371 | /* 0x4c */NULL, NULL, |
| 372 | /* 0x4d */NULL, NULL, |
| 373 | /* 0x4e */NULL, NULL, |
| 374 | /* 0x4f */"RIP_$TABLE", "x,x,x", |
| 375 | /* 0x50 */"FILE_$LOCATEI", "x,x,x", |
| 376 | /* 0x51 */"MSG_$OPENI", "x,x,x", |
| 377 | /* 0x52 */"MSG_$ALLOCATEI", "x,x,x", |
| 378 | /* 0x53 */"MSG_$WAITI", "x,x,x", |
| 379 | /* 0x54 */"ACL_$SET_PROJ_LIST", "x,x,x", |
| 380 | /* 0x55 */"ACL_$GET_RE_SIDS", "x,x,x", |
| 381 | /* 0x56 */NULL, NULL, |
| 382 | /* 0x57 */"MSG_$SET_HPIPC", "x,x,x", |
| 383 | /* 0x58 */"DIR_$VALIDATE_ROOT_ENTRY", "x,x,x", |
| 384 | /* 0x59 */"SMD_$ENABLE_TRACKING", "x,x,x", |
| 385 | /* 0x5a */"FILE_$READ_LOCK_ENTRYUI", "x,x,x", |
| 386 | /* 0x5b */NULL, NULL, |
| 387 | /* 0x5c */"ROUTE_$SERVICE", "x,x,x", |
| 388 | /* 0x5d */NULL, NULL, |
| 389 | /* 0x5e */NULL, NULL, |
| 390 | /* 0x5f */NULL, NULL, |
| 391 | /* 0x60 */"PBU_$ADVANCE_EC", "x,x,x", |
| 392 | /* 0x61 */"PBU_$RELEASE_EC", "x,x,x", |
| 393 | /* 0x62 */NULL, NULL, |
| 394 | /* 0x63 */"SMD_$GET_IDM_EVENT", "x,x,x", |
| 395 | /* 0x64 */"MSG_$TEST_FOR_MESSAGE", "x,x,x", |
| 396 | /* 0x65 */"SMD_$ADD_TRK_RECT", "x,x,x", |
| 397 | /* 0x66 */"SMD_$DEL_TRK_RECT", "x,x,x", |
| 398 | /* 0x67 */"SMD_$SET_KBD_TYPE", "x,x,x", |
| 399 | /* 0x68 */NULL, NULL, |
| 400 | /* 0x69 */"FILE_$SET_AUDITED", "x,x,x", |
| 401 | /* 0x6a */"PROC2_$ACKNOWLEDGE", "x,x,x", |
| 402 | /* 0x6b */"PROC2_$GET_MY_UPIDS", "x,x,x", |
| 403 | /* 0x6c */"TTY_$K_INQ_INPUT_FLAGS", "x,x,x", |
| 404 | /* 0x6d */"TTY_$K_INQ_OUTPUT_FLAGS", "x,x,x", |
| 405 | /* 0x6e */"TTY_$K_INQ_ECHO_FLAGS", "x,x,x", |
| 406 | /* 0x6f */"TTY_$K_SET_INPUT_BREAK_MODE", "x,x,x", |
| 407 | /* 0x70 */"TTY_$K_INQ_INPUT_BREAK_MODE", "x,x,x", |
| 408 | /* 0x71 */"TTY_$K_SET_PGROUP", "x,x,x", |
| 409 | /* 0x72 */"TTY_$K_INQ_PGROUP", "x,x,x", |
| 410 | /* 0x73 */"TTY_$K_SIMULATE_TERMINAL_INPUT", "x,x,x", |
| 411 | /* 0x74 */"TTY_$K_INQ_FUNC_ENABLED", "x,x,x", |
| 412 | /* 0x75 */"SIO_$K_TIMED_BREAK", "x,x,x", |
| 413 | /* 0x76 */"FILE_$SET_DEVNO", "x,x,x", |
| 414 | /* 0x77 */"XPD_$SET_PTRACE_OPTS", "x,x,x", |
| 415 | /* 0x78 */"XPD_$INQ_PTRACE_OPTS", "x,x,x", |
| 416 | /* 0x79 */"FILE_$SET_MAND_LOCK", "x,x,x", |
| 417 | /* 0x7a */"TIME_$SET_CPU_LIMIT", "x,x,x", |
| 418 | /* 0x7b */"CAL_$WEEKDAY", "x,x,x", |
| 419 | /* 0x7c */"SIO_$K_SIGNAL_WAIT", "x,x,x", |
| 420 | /* 0x7d */"TERM_$SET_DISCIPLINE", "x,x,x", |
| 421 | /* 0x7e */"PROC2_$SET_SERVER", "x,x,x", |
| 422 | /* 0x7f */"PACCT_$START", "x,x,x", |
| 423 | /* 0x80 */"FILE_$SET_DTU_F", "x,x,x", |
| 424 | /* 0x81 */"PROC2_$PGUID_TO_UPGID", "x,x,x", |
| 425 | /* 0x82 */"TERM_$INQ_DISCIPLINE", "x,x,x", |
| 426 | /* 0x83 */"PBU_$DMA_STATUS", "x,x,x", |
| 427 | /* 0x84 */NULL, NULL, |
| 428 | /* 0x85 */"MST_$UNMAPS_AND_FREE_AREA", "x,x,x", |
| 429 | /* 0x86 */"SMD_$ASSOC_CSRS", "x,x,x", |
| 430 | /* 0x87 */"SMD_$INQ_DISP_INFO", "x,x,x", |
| 431 | /* 0x88 */"SMD_$INQ_DISP_UID", "x,x,x", |
| 432 | /* 0x89 */"SMD_$DISPLAY_LOGO", "x,x,x", |
| 433 | /* 0x8a */"TERM_$SET_REAL_LINE_DISCIPLINE", "x,x,x", |
| 434 | /* 0x8b */"TIME_$ADJUST_TIME_OF_DAY", "x,x,x", |
| 435 | /* 0x8c */"PROC2_$UID_TO_UPID", "x,x,x", |
| 436 | /* 0x8d */"PROC2_$SET_SESSION_ID", "x,x,x", |
| 437 | /* 0x8e */"SMD_$GET_UNIT_EVENT", "x,x,x", |
| 438 | /* 0x8f */"TPAD_$SET_UNIT_CURSOR", "x,x,x", |
| 439 | /* 0x90 */"TPAD_$SET_PUNCH_IMPACT", "x,x,x", |
| 440 | /* 0x91 */"TPAD_$INQ_PUNCH_IMPACT", "x,x,x", |
| 441 | /* 0x92 */"TTY_$K_INQ_SESSION_ID", "x,x,x", |
| 442 | /* 0x93 */"TTY_$K_SET_SESSION_ID", "x,x,x", |
| 443 | /* 0x94 */NULL, NULL, |
| 444 | /* 0x95 */NULL, NULL, |
| 445 | /* 0x96 */NULL, NULL, |
| 446 | /* 0x97 */NULL, NULL, |
| 447 | /* 0x98 */"SMD_$SHARE_DEVICE", "x,x,x", |
| 448 | /* 0x99 */"SMD_$SET_UNIT_CURSOR_POS", "x,x,x", |
| 449 | /* 0x9a */"SMD_$CLR_AND_LOAD_TRK_RECT", "x,x,x", |
| 450 | /* 0x9b */"PROC2_$GET_PARM", "x,x,x", |
| 451 | /* 0x9c */NULL, NULL, |
| 452 | /* 0x9d */NULL, NULL, |
| 453 | /* 0x9e */NULL, NULL, |
| 454 | /* 0x9f */"FILE_$CW_READ", "x,x,x", |
| 455 | /* 0xa0 */"FILE_$CW_WRITE", "x,x,x", |
| 456 | /* 0xa1 */"MST_$TRUNC_XTAL", "x,x,x", |
| 457 | /* 0xa2 */"MST_$SET_LEN_XTAL", "x,x,x", |
| 458 | /* 0xa3 */"THREAD_$CREATE", "x,x,x", |
| 459 | /* 0xa4 */"THREAD_$CLEANUP", "x,x,x", |
| 460 | /* 0xa5 */"THREAD_$SET_INH_PTR", "x,x,x", |
| 461 | /* 0xa6 */"SMD_$BORROW_DISPLAY_AND_KBD", "x,x,x", |
| 462 | /* 0xa7 */"THREAD_$CLEANUP_ALL", "x,x,x", |
| 463 | /* 0xa8 */"DIR_$ADD_MOUNT", "x,x,x", |
| 464 | /* 0xa9 */"DIR_$REMOVE_MOUNT", "x,x,x", |
| 465 | /* 0xaa */NULL, NULL, |
| 466 | /* 0xab */"TTY_$K_RESET", "x,x,x", |
| 467 | /* 0xac */"MST_$SHADOW_MAP", "x,x,x", |
| 468 | /* 0xad */NULL, NULL }; |
| 469 | |
| 470 | //------------------------------------------------------ |
| 471 | // TRAP4 |
| 472 | //------------------------------------------------------ |
| 473 | |
| 474 | static const char* trap4[] = { |
| 475 | /* 0x00 */NULL, NULL, |
| 476 | /* 0x01 */"MST_$SET_GUARD", "u,x,x,x", |
| 477 | /* 0x02 */"MST_$UNMAP_GLOBAL", "u,x,x,x", |
| 478 | /* 0x03 */"MST_$GET_UID", "x,u,x,x", |
| 479 | /* 0x04 */"EC2_$WAIT", "x,x,x,x", |
| 480 | /* 0x05 */"FILE_$READ_LOCK_ENTRY", "x,x,x,x", |
| 481 | /* 0x06 */"MST_$UNMAP", "u,x,x,x", |
| 482 | /* 0x07 */"MST_$GROW_AREA", "x,x,x,x", |
| 483 | /* 0x08 */NULL, NULL, |
| 484 | /* 0x09 */NULL, NULL, |
| 485 | /* 0x0a */NULL, NULL, |
| 486 | /* 0x0b */NULL, NULL, |
| 487 | /* 0x0c */"TERM_$CONTROL", "x,x,x,x", |
| 488 | /* 0x0d */"TERM_$READ", "x,s,x,x", |
| 489 | /* 0x0e */"TERM_$WRITE", "x,x,x,x", |
| 490 | /* 0x0f */"DISK_$FORMAT", "x,x,x,x", |
| 491 | /* 0x10 */"DISK_$LV_ASSIGN", "x,x,x,x", |
| 492 | /* 0x11 */"FILE_$FW_PARTIAL", "x,x,x,x", |
| 493 | /* 0x12 */NULL, NULL, |
| 494 | /* 0x13 */NULL, NULL, |
| 495 | /* 0x14 */NULL, NULL, |
| 496 | /* 0x15 */NULL, NULL, |
| 497 | /* 0x16 */NULL, NULL, |
| 498 | /* 0x17 */NULL, NULL, |
| 499 | /* 0x18 */NULL, NULL, |
| 500 | /* 0x19 */NULL, NULL, |
| 501 | /* 0x1a */NULL, NULL, |
| 502 | /* 0x1b */NULL, NULL, |
| 503 | /* 0x1c */NULL, NULL, |
| 504 | /* 0x1d */NULL, NULL, |
| 505 | /* 0x1e */NULL, NULL, |
| 506 | /* 0x1f */NULL, NULL, |
| 507 | /* 0x20 */NULL, NULL, |
| 508 | /* 0x21 */NULL, NULL, |
| 509 | /* 0x22 */NULL, NULL, |
| 510 | /* 0x23 */"PBU_$WAIT", "x,x,x,x", |
| 511 | /* 0x24 */"PBU_$GET_PTR", "x,x,x,x", |
| 512 | /* 0x25 */"PCHIST_$CNTL", "x,x,x,x", |
| 513 | /* 0x26 */"PROC2_$GET_INFO", "u,x,x,x", |
| 514 | /* 0x27 */NULL, NULL, |
| 515 | /* 0x28 */NULL, NULL, |
| 516 | /* 0x29 */NULL, NULL, |
| 517 | /* 0x2a */"SMD_$SIGNAL", "x,x,x,x", |
| 518 | /* 0x2b */NULL, NULL, |
| 519 | /* 0x2c */NULL, NULL, |
| 520 | /* 0x2d */"TERM_$INQUIRE", "x,x,x,x", |
| 521 | /* 0x2e */NULL, NULL, |
| 522 | /* 0x2f */NULL, NULL, |
| 523 | /* 0x30 */NULL, NULL, |
| 524 | /* 0x31 */"TERM_$GET_EC", "x,x,x,x", |
| 525 | /* 0x32 */NULL, NULL, |
| 526 | /* 0x33 */"PBU_$GET_EC", "x,x,x,x", |
| 527 | /* 0x34 */NULL, NULL, |
| 528 | /* 0x35 */NULL, NULL, |
| 529 | /* 0x36 */NULL, NULL, |
| 530 | /* 0x37 */NULL, NULL, |
| 531 | /* 0x38 */"TERM_$READ_COND", "x,x,x,x", |
| 532 | /* 0x39 */NULL, NULL, |
| 533 | /* 0x3a */NULL, NULL, |
| 534 | /* 0x3b */"PBU2_$WIRE", "x,x,x,x", |
| 535 | /* 0x3c */"PROC2_$SET_NAME", "x,x,x,x", |
| 536 | /* 0x3d */"PROC2_$SET_PRIORITY", "x,x,x,x", |
| 537 | /* 0x3e */"PROC2_$GET_EC", "u,x,x,x", |
| 538 | /* 0x3f */"PROC2_$LIST_PGROUP", "x,x,x,x", |
| 539 | /* 0x40 */NULL, NULL, |
| 540 | /* 0x41 */NULL, NULL, |
| 541 | /* 0x42 */NULL, NULL, |
| 542 | /* 0x43 */"CT_$CONTROL", "x,x,x,x", |
| 543 | /* 0x44 */"CT_$WAIT", "x,x,x,x", |
| 544 | /* 0x45 */"DIR_$DROP_DIRU", "x,x,x,x", |
| 545 | /* 0x46 */"DIR_$SET_DEFAULT_ACL", "x,x,x,x", |
| 546 | /* 0x47 */"DIR_$GET_DEFAULT_ACL", "x,x,x,x", |
| 547 | /* 0x48 */"NAME_$READ_DIRS_PS", "x,x,x,x", |
| 548 | /* 0x49 */NULL, NULL, |
| 549 | /* 0x4a */"ACL_$GET_PROJ_LIST", "x,x,x,x", |
| 550 | /* 0x4b */"MST_$CHANGE_RIGHTS", "x,x,x,x", |
| 551 | /* 0x4c */NULL, NULL, |
| 552 | /* 0x4d */"FILE_$READ_LOCK_ENTRYI", "x,x,x,x", |
| 553 | /* 0x4e */"ROUTE_$INCOMING", "x,x,x,x", |
| 554 | /* 0x4f */NULL, NULL, |
| 555 | /* 0x50 */"SMD_$INQ_KBD_TYPE", "x,x,x,x", |
| 556 | /* 0x51 */"ROUTE_$GET_EC", "x,x,x,x", |
| 557 | /* 0x52 */NULL, NULL, |
| 558 | /* 0x53 */"SMD_$DM_COND_EVENT_WAIT", "x,x,x,x", |
| 559 | /* 0x54 */"DISK_$READ_MFG_BADSPOTS", "x,x,x,x", |
| 560 | /* 0x55 */"DISK_$GET_MNT_INFO", "x,x,x,x", |
| 561 | /* 0x56 */"PROC2_$SET_SIG_MASK", "x,x,x,x", |
| 562 | /* 0x57 */"PROC2_$SIGRETURN", "x,x,x,x", |
| 563 | /* 0x58 */"PROC2_$WAIT", "x,x,x,x", |
| 564 | /* 0x59 */"PROC2_$SIGNAL", "x,x,x,x", |
| 565 | /* 0x5a */"PROC2_$SIGNAL_PGROUP", "x,x,x,x", |
| 566 | /* 0x5b */"PROC2_$GET_CR_REC", "x,x,x,x", |
| 567 | /* 0x5c */"TTY_$K_SET_FUNC_CHAR", "x,x,x,x", |
| 568 | /* 0x5d */"TTY_$K_INQ_FUNC_CHAR", "x,x,x,x", |
| 569 | /* 0x5e */"TTY_$K_SET_INPUT_FLAG", "x,x,x,x", |
| 570 | /* 0x5f */"TTY_$K_SET_OUTPUT_FLAG", "x,x,x,x", |
| 571 | /* 0x60 */"TTY_$K_SET_ECHO_FLAG", "x,x,x,x", |
| 572 | /* 0x61 */"TTY_$K_ENABLE_FUNC", "x,x,x,x", |
| 573 | /* 0x62 */"SIO_$K_SET_PARAM", "x,x,x,x", |
| 574 | /* 0x63 */"SIO_$K_INQ_PARAM", "x,x,x,x", |
| 575 | /* 0x64 */"FILE_$SET_MGR_ATTR", "x,x,x,x", |
| 576 | /* 0x65 */"XPD_$GET_REGISTERS", "x,x,x,x", |
| 577 | /* 0x66 */"XPD_$PUT_REGISTERS", "x,x,x,x", |
| 578 | /* 0x67 */"FILE_$RESERVE", "u,x,x,x", |
| 579 | /* 0x68 */NULL, NULL, |
| 580 | /* 0x69 */"ACL_$GET_RES_SIDS", "x,x,x,x", |
| 581 | /* 0x6a */"FILE_$FW_PAGES", "x,x,x,x", |
| 582 | /* 0x6b */"PROC2_$SET_ACCT_INFO", "s,x,x,x", |
| 583 | /* 0x6c */"FILE_$IMPORT_LK", "x,x,x,x", |
| 584 | /* 0x6d */"FILE_$UNLOCK_D", "u,x,x,x", |
| 585 | /* 0x6e */"FILE_$SET_LEN_D", "x,x,x,x", |
| 586 | /* 0x6f */"FILE_$TRUNCATE_D", "x,x,x,x", |
| 587 | /* 0x70 */"FILE_$SET_DTM_F", "x,x,x,x", |
| 588 | /* 0x71 */"TTY_$K_SET_FLAG", "x,x,x,x", |
| 589 | /* 0x72 */NULL, NULL, |
| 590 | /* 0x73 */"MST_$UNMAP_AND_FREE_AREA", "x,x,x,x", |
| 591 | /* 0x74 */NULL, NULL, |
| 592 | /* 0x75 */"PROC2_$NAME_TO_UID", "S,w,u,x", |
| 593 | /* 0x76 */NULL, NULL, |
| 594 | /* 0x77 */NULL, NULL, |
| 595 | /* 0x78 */NULL, NULL, |
| 596 | /* 0x79 */"SCSI_$GET_EC", "x,x,x,x", |
| 597 | /* 0x7a */"SCSI_$GET_INFO", "x,x,x,x", |
| 598 | /* 0x7b */"SCSI_$SETUP", "x,x,x,x", |
| 599 | /* 0x7c */"SCSI_$WIRE", "x,x,x,x", |
| 600 | /* 0x7d */"MSG_$SHARE_SOCKET", "x,x,x,x", |
| 601 | /* 0x7e */"TTY_$K_INQ_DELAY", "x,x,x,x", |
| 602 | /* 0x7f */"TTY_$K_SET_DELAY", "x,x,x,x", |
| 603 | /* 0x80 */NULL, NULL, |
| 604 | /* 0x81 */NULL, NULL, |
| 605 | /* 0x82 */"PROC2_$PGROUP_INFO", "x,x,x,x", |
| 606 | /* 0x83 */"PROC2_$SET_PARM", "x,x,x,x", |
| 607 | /* 0x84 */NULL, NULL, |
| 608 | /* 0x85 */NULL, NULL, |
| 609 | /* 0x86 */"XPAGE_$PAGER_RENDEZVOUS", "x,x,x,x", |
| 610 | /* 0x87 */"FILE_$SET_DEVNO32", "x,x,x,x", |
| 611 | /* 0x88 */"MST_$SET_LIMIT", "x,x,x,x", |
| 612 | /* 0x89 */"THREAD_$SET_PRIORITY", "x,x,x,x", |
| 613 | /* 0x8a */"THREAD_$INFO", "x,x,x,x", |
| 614 | /* 0x8b */"TTY_$K_SET_DELAY_STYLE", "x,x,x,x", |
| 615 | /* 0x8c */"TTY_$K_INQ_DELAY_STYLE", "x,x,x,x" }; |
| 616 | |
| 617 | //------------------------------------------------------ |
| 618 | // TRAP5 |
| 619 | //------------------------------------------------------ |
| 620 | |
| 621 | static const char* trap5[] = { |
| 622 | /* 0x00 */NULL, NULL, |
| 623 | /* 0x01 */"MST_$MAP_AREA", "x,x,x,u,x", |
| 624 | /* 0x02 */NULL, NULL, |
| 625 | /* 0x03 */NULL, NULL, |
| 626 | /* 0x04 */NULL, NULL, |
| 627 | /* 0x05 */"ACL_$RIGHTS", "x,x,x,x,x", |
| 628 | /* 0x06 */NULL, NULL, |
| 629 | /* 0x07 */"ASKNODE_$INFO", "x,x,x,x,x", |
| 630 | /* 0x08 */"DISK_$AS_READ", "x,x,x,x,x", |
| 631 | /* 0x09 */"DISK_$AS_WRITE", "x,x,x,x,x", |
| 632 | /* 0x0a */NULL, NULL, |
| 633 | /* 0x0b */NULL, NULL, |
| 634 | /* 0x0c */NULL, NULL, |
| 635 | /* 0x0d */NULL, NULL, |
| 636 | /* 0x0e */NULL, NULL, |
| 637 | /* 0x0f */NULL, NULL, |
| 638 | /* 0x10 */NULL, NULL, |
| 639 | /* 0x11 */"PBU_$GET_DCTE", "x,x,x,x,x", |
| 640 | /* 0x12 */"PBU_$READ_CSR", "x,x,x,x,x", |
| 641 | /* 0x13 */"PBU_$CONTROL", "x,x,x,x,x", |
| 642 | /* 0x14 */"PBU2_$WIRE_MAP", "x,x,x,x,x", |
| 643 | /* 0x15 */"PBU_$WRITE_CSR", "x,x,x,x,x", |
| 644 | /* 0x16 */"TPAD_$INQUIRE", "x,x,x,x,x", |
| 645 | /* 0x17 */"TPAD_$SET_MODE", "x,x,x,x,x", |
| 646 | /* 0x18 */"VFMT_$MAIN", "x,x,x,x,x", |
| 647 | /* 0x19 */"VOLX_$GET_INFO", "x,x,x,x,x", |
| 648 | /* 0x1a */"VTOC_$GET_UID", "x,x,x,x,x", |
| 649 | /* 0x1b */"NETLOG_$CNTL", "x,x,x,x,x", |
| 650 | /* 0x1c */"PROC2_$GET_UPIDS", "x,x,x,x,x", |
| 651 | /* 0x1d */NULL, NULL, |
| 652 | /* 0x1e */NULL, NULL, |
| 653 | /* 0x1f */"PBU2_$ALLOCATE_MAP", "x,x,x,x,x", |
| 654 | /* 0x20 */"PBU2_$MAP", "x,x,x,x,x", |
| 655 | /* 0x21 */"PBU2_$UNMAP", "x,x,x,x,x", |
| 656 | /* 0x22 */"PBU2_$UNWIRE", "x,x,x,x,x", |
| 657 | /* 0x23 */"MST_$GET_UID_ASID", "x,x,x,x,x", |
| 658 | /* 0x24 */"MST_$INVALIDATE", "x,x,u,x,x", |
| 659 | /* 0x25 */"FILE_$INVALIDATE", "x,x,x,x,x", |
| 660 | /* 0x26 */NULL, NULL, |
| 661 | /* 0x27 */NULL, NULL, |
| 662 | /* 0x28 */NULL, NULL, |
| 663 | /* 0x29 */"MST_$SET_TOUCH_AHEAD_CNT", "x,x,x,x,x", |
| 664 | /* 0x2a */"OS_$CHKSUM", "x,x,x,x,x", |
| 665 | /* 0x2b */"FILE_$GET_SEGMENT_MAP", "x,x,x,x,x", |
| 666 | /* 0x2c */NULL, NULL, |
| 667 | /* 0x2d */"PBU2_$ASSOC", "x,x,x,x,x", |
| 668 | /* 0x2e */"FILE_$UNLOCK_PROC", "x,x,x,x,x", |
| 669 | /* 0x2f */"CT_$READ", "x,x,x,x,x", |
| 670 | /* 0x30 */"CT_$WRITE", "x,x,x,x,x", |
| 671 | /* 0x31 */"DIR_$ADDU", "u,S,w,u,x", |
| 672 | /* 0x32 */"DIR_$DROPU", "x,x,x,x,x", |
| 673 | /* 0x33 */"DIR_$CREATE_DIRU", "x,x,x,x,x", |
| 674 | /* 0x34 */"DIR_$ADD_BAKU", "x,x,x,x,x", |
| 675 | /* 0x35 */NULL, NULL, |
| 676 | /* 0x36 */NULL, NULL, |
| 677 | /* 0x37 */NULL, NULL, |
| 678 | /* 0x38 */"DIR_$ADD_HARD_LINKU", "x,x,x,x,x", |
| 679 | /* 0x39 */NULL, NULL, |
| 680 | /* 0x3a */"RIP_$UPDATE", "x,x,x,x,x", |
| 681 | /* 0x3b */"DIR_$DROP_LINKU", "x,x,x,x,x", |
| 682 | /* 0x3c */"ACL_$CHECK_RIGHTS", "x,x,x,x,x", |
| 683 | /* 0x3d */"DIR_$DROP_HARD_LINKU", "x,x,x,x,x", |
| 684 | /* 0x3e */"ROUTE_$OUTGOING", "x,x,x,x,x", |
| 685 | /* 0x3f */NULL, NULL, |
| 686 | /* 0x40 */NULL, NULL, |
| 687 | /* 0x41 */NULL, NULL, |
| 688 | /* 0x42 */"NET_$GET_INFO", "x,x,x,x,x", |
| 689 | /* 0x43 */"DIR_$GET_ENTRYU", "x,x,x,x,x", |
| 690 | /* 0x44 */"AUDIT_$LOG_EVENT", "x,x,x,x,x", |
| 691 | /* 0x45 */"FILE_$SET_PROT", "x,x,x,x,x", |
| 692 | /* 0x46 */"TTY_$K_GET", "x,x,s,x,x", |
| 693 | /* 0x47 */"TTY_$K_PUT", "x,x,S,w,x", |
| 694 | /* 0x48 */"PROC2_$ALIGN_CTL", "x,x,x,x,x", |
| 695 | /* 0x49 */NULL, NULL, |
| 696 | /* 0x4a */"XPD_$READ_PROC", "x,x,x,x,x", |
| 697 | /* 0x4b */"XPD_$WRITE_PROC", "x,x,x,x,x", |
| 698 | /* 0x4c */"DIR_$SET_DEF_PROTECTION", "x,x,x,x,x", |
| 699 | /* 0x4d */"DIR_$GET_DEF_PROTECTION", "x,x,x,x,x", |
| 700 | /* 0x4e */"ACL_$COPY", "u,u,x,x,x", |
| 701 | /* 0x4f */"ACL_$CONVERT_FUNKY_ACL", "x,x,x,x,x", |
| 702 | /* 0x50 */"DIR_$SET_PROTECTION", "x,x,x,x,x", |
| 703 | /* 0x51 */"FILE_$OLD_AP", "x,x,x,x,x", |
| 704 | /* 0x52 */"ACL_$SET_RE_ALL_SIDS", "x,x,x,x,x", |
| 705 | /* 0x53 */"ACL_$GET_RE_ALL_SIDS", "x,x,x,x,x", |
| 706 | /* 0x54 */"FILE_$EXPORT_LK", "x,x,x,x,x", |
| 707 | /* 0x55 */"FILE_$CHANGE_LOCK_D", "x,x,x,x,x", |
| 708 | /* 0x56 */"XPD_$READ_PROC_ASYNC", "x,x,x,x,x", |
| 709 | /* 0x57 */NULL, NULL, |
| 710 | /* 0x58 */"SMD_$MAP_DISPLAY_MEMORY", "x,x,x,x,x", |
| 711 | /* 0x59 */NULL, NULL, |
| 712 | /* 0x5a */NULL, NULL, |
| 713 | /* 0x5b */NULL, NULL, |
| 714 | /* 0x5c */NULL, NULL, |
| 715 | /* 0x5d */"SCSI_$UNWIRE", "x,x,x,x,x", |
| 716 | /* 0x5e */"SMD_$UNMAP_DISPLAY_MEMORY", "x,x,x,x,x", |
| 717 | /* 0x5f */"SMD_$SET_COLOR_TABLE", "x,x,x,x,x", |
| 718 | /* 0x60 */"RIP_$TABLE_D", "x,x,x,x,x", |
| 719 | /* 0x61 */NULL, NULL, |
| 720 | /* 0x62 */"SMD_$DEVICE_INFO", "x,x,x,x,x", |
| 721 | /* 0x63 */NULL, NULL, |
| 722 | /* 0x64 */NULL, NULL, |
| 723 | /* 0x65 */"THREAD_$GET_STATE", "x,x,x,p,x", |
| 724 | /* 0x66 */"THREAD_$SET_STATE", "x,x,x,p,x", |
| 725 | /* 0x67 */"THREAD_$SET_STACK", "x,u,x,x,x", |
| 726 | /* 0x68 */NULL, NULL }; |
| 727 | |
| 728 | //------------------------------------------------------ |
| 729 | // TRAP7 |
| 730 | //------------------------------------------------------ |
| 731 | |
| 732 | static const char* trap7[] = { |
| 733 | /* 0x00 */"FILE_$LOCK", "u,x,x,x,x,x,x", |
| 734 | /* 0x01 */"VFMT_$WRITE", "s,x,x,x,x,x,x", |
| 735 | /* 0x02 */"MST_$MAP_AREA_AT", "x,x,x,x,x,x,x", |
| 736 | /* 0x03 */NULL, NULL, |
| 737 | /* 0x04 */NULL, NULL, |
| 738 | /* 0x05 */NULL, NULL, |
| 739 | /* 0x06 */NULL, NULL, |
| 740 | /* 0x07 */NULL, NULL, |
| 741 | /* 0x08 */NULL, NULL, |
| 742 | /* 0x09 */NULL, NULL, |
| 743 | /* 0x0a */NULL, NULL, |
| 744 | /* 0x0b */NULL, NULL, |
| 745 | /* 0x0c */NULL, NULL, |
| 746 | /* 0x0d */"VFMT_$ENCODE/VFMT_$FORMAT", "x,x,x,x,x,x,x", |
| 747 | /* 0x0e */"VFMT_$ENCODE/VFMT_$FORMAT", "x,x,x,x,x,x,x", |
| 748 | /* 0x0f */"STOP_$WATCH", "x,x,x,x,x,x,x", |
| 749 | /* 0x10 */NULL, NULL, |
| 750 | /* 0x11 */NULL, NULL, |
| 751 | /* 0x12 */"ASKNODE_$GET_INFO", "x,x,x,x,x,x,x", |
| 752 | /* 0x13 */"DISK_$DIAG_IO", "x,x,x,x,x,x,x", |
| 753 | /* 0x14 */NULL, NULL, |
| 754 | /* 0x15 */NULL, NULL, |
| 755 | /* 0x16 */NULL, NULL, |
| 756 | /* 0x17 */"CT_$DIAG", "x,x,x,x,x,x,x", |
| 757 | /* 0x18 */"TIME_$SET_ITIMER", "x,x,x,x,x,x,x", |
| 758 | /* 0x19 */"OSINFO_$GET_STATS", "x,x,x,x,x,x,x", |
| 759 | /* 0x1a */"DIR_$CNAMEU", "x,x,x,x,x,x,x", |
| 760 | /* 0x1b */"DIR_$DELETE_FILEU", "u,S,w,x,x,x,x", |
| 761 | /* 0x1c */"DIR_$ADD_LINKU", "x,x,x,x,x,x,x", |
| 762 | /* 0x1d */NULL, NULL, |
| 763 | /* 0x1e */NULL, NULL, |
| 764 | /* 0x1f */NULL, NULL, |
| 765 | /* 0x20 */NULL, NULL, |
| 766 | /* 0x21 */"ASKNODE_$WHO_REMOTE", "x,x,x,x,x,x,x", |
| 767 | /* 0x22 */"MST_$REMAP", "x,x,x,x,x,x,x", |
| 768 | /* 0x23 */"DIR_$ROOT_ADDU", "x,x,x,x,x,x,x", |
| 769 | /* 0x24 */NULL, NULL, |
| 770 | /* 0x25 */NULL, NULL, |
| 771 | /* 0x26 */NULL, NULL, |
| 772 | /* 0x27 */NULL, NULL, |
| 773 | /* 0x28 */"ASKNODE_$WHO_NOTOPO", "x,x,x,x,x,x,x", |
| 774 | /* 0x29 */"NET_$OPEN", "x,x,x,x,x,x,x", |
| 775 | /* 0x2a */"NET_$CLOSE", "x,x,x,x,x,x,x", |
| 776 | /* 0x2b */"NET_$IOCTL", "x,x,x,x,x,x,x", |
| 777 | /* 0x2c */"DIR_$FIND_UID", "u,u,x,S,w,x,x", |
| 778 | /* 0x2d */"FILE_$GET_ATTRIBUTES", "u,x,x,x,x,x,-", |
| 779 | /* 0x2e */NULL, NULL, |
| 780 | /* 0x2f */"PCHIST_$UNIX_PROFIL_CNTL", "x,x,x,x,x,x,x", |
| 781 | /* 0x30 */"XPD_$RESTART", "x,x,x,x,x,x,x", |
| 782 | /* 0x31 */"FILE_$GET_ATTR_INFO", "u,x,x,x,x,x,p", |
| 783 | /* 0x32 */"ACL_$PRIM_CREATE", "x,x,x,x,x,x,x", |
| 784 | /* 0x33 */"PROC2_$GET_REGS", "x,x,x,x,x,x,x", |
| 785 | /* 0x34 */"ACL_$CONVERT_TO_9ACL", "x,x,x,x,x,x,x", |
| 786 | /* 0x35 */"ACL_$SET_RES_ALL_SIDS", "x,x,x,x,x,x,x", |
| 787 | /* 0x36 */"ACL_$GET_RES_ALL_SIDS", "x,x,x,x,x,x,x", |
| 788 | /* 0x37 */"FILE_$LOCK_D", "u,x,x,x,x,x,p", |
| 789 | /* 0x38 */"FILE_$CREATE_IT", "x,x,u,x,u,x,u", |
| 790 | /* 0x39 */"ACL_$RIGHTS_CHECK", "x,x,x,x,x,x,x", |
| 791 | /* 0x3a */"RIP_$UPDATE_D", "x,x,x,x,x,x,x", |
| 792 | /* 0x3b */"VOLX_$SWAPON", "x,x,x,x,x,x,x", |
| 793 | /* 0x3c */"MST_$ADDMAP", "x,x,x,x,x,x,x", }; |
| 794 | |
| 795 | //------------------------------------------------------ |
| 796 | // TRAP8 |
| 797 | //------------------------------------------------------ |
| 798 | |
| 799 | static const char* trap8[] = { |
| 800 | |
| 801 | /* 0x00 - 0x07 */"MST_$MAP", "u,x,x,x,x,x,x", |
| 802 | /* 0x01 - 0x08 */"MST_$MAP_AT", "x,u,x,x,x,x,x,x", |
| 803 | /* 0x02 - 0x07 */"MST_$MAP_GLOBAL", "u,x,x,x,x,x,x", |
| 804 | /* 0x03 - 0x0A */"VFMT_$WRITE", "s,x,x,x,x,x,x,x,x,x", |
| 805 | /* 0x04 - 0x06 */"VOLX_$DISMOUNT", "x,x,x,x,x,x", |
| 806 | /* 0x05 - 0x06 */"VOLX_$GET_UIDS", "x,x,x,x,x,x", |
| 807 | /* 0x06 - 0x07 */NULL, NULL, |
| 808 | /* 0x07 - 0x07 */"DISK_$PV_ASSIGN", "x,x,x,x,x,x,x", |
| 809 | /* 0x08 - 0x0B */"MSG_$RCV", "x,x,x,x,x,x,x,x,x,x,x", |
| 810 | /* 0x09 - 0x10 */"MSG_$SAR", "x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x", |
| 811 | /* 0x0a - 0x0A */"MSG_$SEND", "x,x,x,x,x,x,x,x,x,x", |
| 812 | /* 0x0b - 0x06 */NULL, NULL, |
| 813 | /* 0x0c - 0x07 */"SMD_$LOAD_CRSR_BITMAP", "x,x,x,x,x,x,x", |
| 814 | /* 0x0d - 0x07 */"SMD_$READ_CRSR_BITMAP", "x,x,x,x,x,x,x", |
| 815 | /* 0x0e - 0x0D */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x,x,x,x,x,x", |
| 816 | /* 0x0f - 0x08 */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x", |
| 817 | /* 0x10 - 0x0D */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x,x,x,x,x,x", |
| 818 | /* 0x11 - 0x08 */"VFMT_$ENCODE/VFMT_$FORMAT", "s,x,x,x,x,x,x,x", |
| 819 | /* 0x12 - 0x06 */"CAL_$WRITE_CALENDAR", "x,x,x,x,x,x", |
| 820 | /* 0x13 - 0x08 */"MSG_$RCV_CONTIG", "x,x,x,x,x,x,x,x", |
| 821 | /* 0x14 - 0x06 */"OSINFO_$GET_MMAP", "x,x,x,x,x,x", |
| 822 | /* 0x15 - 0x06 */"ASKNODE_$INTERNET_INFO", "x,x,x,x,x,x", |
| 823 | /* 0x16 - 0x07 */"MST_$GET_VA_INFO", "x,x,x,x,x,x,x", |
| 824 | /* 0x17 - 0x0D */"MSG_$SENDI", "x,x,x,x,x,x,x,x,x,x,x,x,x", |
| 825 | /* 0x18 - 0x0F */"MSG_$RCVI", "x,x,x,x,x,x,x,x,x,x,x,x,x,x,x", |
| 826 | /* 0x19 - 0x0C */"MSG_$RCV_CONTIGI", "x,x,x,x,x,x,x,x,x,x,x,x", |
| 827 | /* 0x1a - 0x11 */"MSG_$SARI", "x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x", |
| 828 | /* 0x1b - 0x06 */NULL, NULL, |
| 829 | /* 0x1c - 0x0E */"MSG_$SEND_HW", "x,x,x,x,x,x,x,x,x,x,x,x,x,x", |
| 830 | /* 0x1d - 0x07 */"PBU_$WIRE_SPECIAL", "x,x,x,x,x,x,x", |
| 831 | /* 0x1e - 0x06 */"PBU_$DMA_START", "x,x,x,x,x,x", |
| 832 | /* 0x1f - 0x08 */NULL, NULL, |
| 833 | /* 0x20 - 0x07 */"MST_$MAP_TOP", "x,x,x,x,x,x,x", |
| 834 | /* 0x21 - 0x08 */"NET_$SEND", "x,x,x,x,x,x,x,x", |
| 835 | /* 0x22 - 0x08 */"NET_$RCV", "x,x,x,x,x,x,x,x", |
| 836 | /* 0x23 - 0x08 */"DIR_$DIR_READU", "u,S,w,x,x,x,x,x", |
| 837 | /* 0x24 - 0x07 */"DIR_$READ_LINKU", "x,x,x,x,x,x,x", |
| 838 | /* 0x25 - 0x07 */"PBU2_$DMA_START", "x,x,x,x,x,x,x", |
| 839 | /* 0x26 - 0x09 */NULL, NULL, |
| 840 | /* 0x27 - 0x09 */NULL, NULL, |
| 841 | /* 0x28 - 0x07 */"PROC2_$COMPLETE_VFORK", "x,x,x,x,x,x,x", |
| 842 | /* 0x29 - 0x07 */NULL, NULL, |
| 843 | /* 0x2a - 0x06 */NULL, NULL, |
| 844 | /* 0x2b - 0x0A */"DIR_$RESOLVE", "S,w,u,u,x,x,x,x,x,x", |
| 845 | /* 0x2c - 0x08 */"VOLX_$MOUNT", "x,x,x,x,x,x,x,x", |
| 846 | /* 0x2d - 0x06 */"ACL_$IMAGE", "x,x,x,x,x,x", |
| 847 | /* 0x2e - 0x09 */"DISK_$PV_ASSIGN_N", "x,x,x,x,x,x,x,x,x", |
| 848 | /* 0x2f - 0x07 */"DISK_$AS_XFER_MULTI", "x,x,x,x,x,x,x", |
| 849 | /* 0x30 - 0x07 */"PROC2_$FORK", "x,x,x,x,x,x,x", |
| 850 | /* 0x31 - 0x06 */"SCSI_$DO_COMMAND", "x,x,x,x,x,x", |
| 851 | /* 0x32 - 0x07 */"SCSI_$WAIT", "x,x,x,x,x,x,x", |
| 852 | /* 0x33 - 0x0A */"PROC2_$CREATE", "x,x,x,x,x,x,x,x,x,x", |
| 853 | /* 0x34 - 0x06 */"TPAD_$SET_UNIT_MODE", "x,x,x,x,x,x", |
| 854 | /* 0x35 - 0x06 */"TPAD_$INQUIRE_UNIT", "x,x,x,x,x,x", |
| 855 | /* 0x36 - 0x0B */"SCSI_$DO_SYS_DEVICE_CMD", "x,x,x,x,x,x,x,x,x,x,x", |
| 856 | /* 0x37 - 0x0D */"MSG_$RCV_HW", "x,x,x,x,x,x,x,x,x,x,x,x,x", |
| 857 | /* 0x38 - 0x06 */"VOLX_$VOL_INFO", "x,x,x,x,x,x", |
| 858 | /* 0x39 - 0x08 */"MST_$MAP_XTAL", "x,x,x,x,x,x,x,x", |
| 859 | /* 0x3a - 0x08 */"MST_$MAP_U", "x,u,x,x,x,x,x,x", |
| 860 | /* 0x3b - 0x06 */"MST_$GET_INFO_BY_VA", "x,x,x,x,x,x", |
| 861 | /* 0x3c - 0x06 */"VOLX_$QUOTA_CONTROL", "x,x,x,x,x,x", |
| 862 | /* 0x3d - 0x06 */"VOLX_$READ_QUOTA_TABLE", "x,x,x,x,x,x", |
| 863 | /* 0x3e - 0x06 */"THREAD_$LIST", "x,x,x,x,x,x", |
| 864 | /* 0x3f - 0x07 */"SCSI_$DO_COMMAND_2", "x,x,x,x,x,x,x" }; |
| 865 | |
| 866 | // get parameter string for parameter type and value at addr |
| 867 | |
| 868 | static const char *get_param(m68ki_cpu_core *m68k, UINT32 addr, char type) |
| 869 | { |
| 870 | UINT32 value = ~0; |
| 871 | |
| 872 | // FIXME: |
| 873 | static char sb[256]; |
| 874 | |
| 875 | int i; |
| 876 | char ch; |
| 877 | int maxlen = sizeof(sb) - 2; |
| 878 | UINT32 value1; |
| 879 | |
| 880 | sb[0] = 0; |
| 881 | |
| 882 | if (!m68k->mmu_tmp_buserror_occurred) |
| 883 | { |
| 884 | value = m68k->memory.read32(addr); |
| 885 | if (!m68k->mmu_tmp_buserror_occurred && (value != ~0)) |
| 886 | { |
| 887 | switch (type) |
| 888 | { |
| 889 | case 'S': // string w/o terminating 0 |
| 890 | value1 = m68k->memory.read32(addr + 4); |
| 891 | if (!m68k->mmu_tmp_buserror_occurred && (value1 != ~0)) |
| 892 | { |
| 893 | maxlen = m68k->memory.read16(value1); |
| 894 | if (maxlen > sizeof(sb) - 2) |
| 895 | { |
| 896 | maxlen = sizeof(sb) - 2; |
| 897 | } |
| 898 | } |
| 899 | case 's': // string |
| 900 | i = 0; |
| 901 | sb[i++] = '"'; |
| 902 | while (i <= maxlen && (ch = m68k->memory.read8(value++)) != 0 |
| 903 | && !m68k->mmu_tmp_buserror_occurred) |
| 904 | { |
| 905 | sb[i++] = ch < 32 ? '.' : ch; |
| 906 | } |
| 907 | sb[i++] = '"'; |
| 908 | sb[i] = 0; |
| 909 | break; |
| 910 | case 'b': // byte (1 byte) |
| 911 | sprintf(sb, "0x%x", m68k->memory.read8(value)); |
| 912 | break; |
| 913 | case 'p': // pointer |
| 914 | sprintf(sb, "0x%x", value); |
| 915 | break; |
| 916 | case 'w': // word (2 byte) |
| 917 | sprintf(sb, "0x%x", m68k->memory.read16(value)); |
| 918 | break; |
| 919 | case 'x': // default (hex 32 bit) |
| 920 | sprintf(sb, "0x%x", m68k->memory.read32(value)); |
| 921 | break; |
| 922 | case 'u': // uid |
| 923 | sprintf(sb, "%08x.%08x", m68k->memory.read32(value), |
| 924 | m68k->memory.read32(value + 4)); |
| 925 | break; |
| 926 | default: |
| 927 | sprintf(sb, "%c", type); |
| 928 | break; |
| 929 | } |
| 930 | } |
| 931 | m68k->mmu_tmp_buserror_occurred = 0; |
| 932 | } |
| 933 | return sb; |
| 934 | } |
| 935 | |
| 936 | // get the svc call string |
| 937 | |
| 938 | static const char* get_svc_call(m68ki_cpu_core *m68k, int trap_no, |
| 939 | int trap_code, char *sb) |
| 940 | { |
| 941 | UINT32 sp = REG_A(m68k)[7]; |
| 942 | UINT32 pa; |
| 943 | const char * name = NULL; |
| 944 | const char * param = NULL; |
| 945 | |
| 946 | switch (trap_no) |
| 947 | { |
| 948 | case 0: |
| 949 | if (trap_no < sizeof(trap0) / 8) |
| 950 | { |
| 951 | name = trap0[trap_code * 2]; |
| 952 | param = trap0[trap_code * 2 + 1]; |
| 953 | } |
| 954 | break; |
| 955 | case 1: |
| 956 | if (trap_no < sizeof(trap1) / 8) |
| 957 | { |
| 958 | name = trap1[trap_code * 2]; |
| 959 | param = trap1[trap_code * 2 + 1]; |
| 960 | } |
| 961 | break; |
| 962 | case 2: |
| 963 | if (trap_no < sizeof(trap2) / 8) |
| 964 | { |
| 965 | name = trap2[trap_code * 2]; |
| 966 | param = trap2[trap_code * 2 + 1]; |
| 967 | } |
| 968 | break; |
| 969 | case 3: |
| 970 | if (trap_no < sizeof(trap3) / 8) |
| 971 | { |
| 972 | name = trap3[trap_code * 2]; |
| 973 | param = trap3[trap_code * 2 + 1]; |
| 974 | } |
| 975 | break; |
| 976 | case 4: |
| 977 | if (trap_no < sizeof(trap4) / 8) |
| 978 | { |
| 979 | name = trap4[trap_code * 2]; |
| 980 | param = trap4[trap_code * 2 + 1]; |
| 981 | } |
| 982 | break; |
| 983 | case 5: |
| 984 | if (trap_no < sizeof(trap5) / 8) |
| 985 | { |
| 986 | name = trap5[trap_code * 2]; |
| 987 | param = trap5[trap_code * 2 + 1]; |
| 988 | } |
| 989 | break; |
| 990 | case 7: |
| 991 | if (trap_no < sizeof(trap7) / 8) |
| 992 | { |
| 993 | name = trap7[trap_code * 2]; |
| 994 | param = trap7[trap_code * 2 + 1]; |
| 995 | } |
| 996 | break; |
| 997 | case 8: |
| 998 | if (trap_no < sizeof(trap8) / 8) |
| 999 | { |
| 1000 | name = trap8[trap_code * 2]; |
| 1001 | param = trap8[trap_code * 2 + 1]; |
| 1002 | } |
| 1003 | break; |
| 1004 | } |
| 1005 | |
| 1006 | sb[0] = '\0'; |
| 1007 | |
| 1008 | if (name == NULL) |
| 1009 | { |
| 1010 | strcat(sb, "???"); |
| 1011 | } |
| 1012 | else |
| 1013 | { |
| 1014 | strcat(sb, name); |
| 1015 | if (param != NULL) |
| 1016 | { |
| 1017 | int i; |
| 1018 | strcat(sb, "("); |
| 1019 | for (i = 0, pa = sp + 4; param[i] != '\0'; i++) |
| 1020 | { |
| 1021 | switch (param[i]) |
| 1022 | { |
| 1023 | case ',': |
| 1024 | strcat(sb, ", "); |
| 1025 | pa += 4; |
| 1026 | break; |
| 1027 | default: |
| 1028 | strcat(sb, get_param(m68k, pa, param[i])); |
| 1029 | break; |
| 1030 | } |
| 1031 | } |
| 1032 | strcat(sb, ")"); |
| 1033 | } |
| 1034 | } |
| 1035 | return sb; |
| 1036 | } |
| 1037 | |
| 1038 | static const char * disassemble(m68ki_cpu_core *m68k, offs_t pc, char* sb) |
| 1039 | { |
| 1040 | UINT8 oprom[10]; |
| 1041 | UINT8 opram[10]; |
| 1042 | UINT32 options = 0; |
| 1043 | |
| 1044 | // remember bus error state |
| 1045 | UINT32 tmp_buserror_occurred = m68k->mmu_tmp_buserror_occurred; |
| 1046 | UINT32 tmp_buserror_address = m68k->mmu_tmp_buserror_address; |
| 1047 | |
| 1048 | m68k->mmu_tmp_buserror_occurred = 0; |
| 1049 | m68k->mmu_tmp_rw = 1; |
| 1050 | |
| 1051 | int i; |
| 1052 | for (i = 0; i < sizeof(oprom); i++) |
| 1053 | { |
| 1054 | oprom[i] = opram[i] = m68k->memory.read8(pc + i); |
| 1055 | if (m68k->mmu_tmp_buserror_occurred) |
| 1056 | { |
| 1057 | |
| 1058 | sprintf(sb, "- (apollo_disassemble failed at %08x)", pc + i); |
| 1059 | |
| 1060 | // restore previous bus error state |
| 1061 | m68k->mmu_tmp_buserror_occurred = tmp_buserror_occurred; |
| 1062 | m68k->mmu_tmp_buserror_address = tmp_buserror_address; |
| 1063 | |
| 1064 | return sb; |
| 1065 | } |
| 1066 | } |
| 1067 | m68k->device->disassemble(sb, pc, oprom, opram, options); |
| 1068 | |
| 1069 | // restore previous bus error state |
| 1070 | m68k->mmu_tmp_buserror_occurred = tmp_buserror_occurred; |
| 1071 | m68k->mmu_tmp_buserror_address = tmp_buserror_address; |
| 1072 | |
| 1073 | return sb; |
| 1074 | } |
| 1075 | |
| 1076 | static const UINT16 *get_data(m68ki_cpu_core *m68k, offs_t addr) |
| 1077 | { |
| 1078 | static UINT16 data[4]; |
| 1079 | |
| 1080 | // remember bus error state |
| 1081 | UINT32 tmp_buserror_occurred = m68k->mmu_tmp_buserror_occurred; |
| 1082 | UINT32 tmp_buserror_address = m68k->mmu_tmp_buserror_address; |
| 1083 | |
| 1084 | m68k->mmu_tmp_buserror_occurred = 0; |
| 1085 | m68k->mmu_tmp_rw = 1; |
| 1086 | |
| 1087 | int i; |
| 1088 | for (i = 0; i < sizeof(data); i += 2) |
| 1089 | { |
| 1090 | data[i/2] = m68k->memory.read16(addr + i); |
| 1091 | } |
| 1092 | |
| 1093 | // restore previous bus error state |
| 1094 | m68k->mmu_tmp_buserror_occurred = tmp_buserror_occurred; |
| 1095 | m68k->mmu_tmp_buserror_address = tmp_buserror_address; |
| 1096 | |
| 1097 | return data; |
| 1098 | } |
| 1099 | |
| 1100 | //------------------------------------------------- |
| 1101 | // instruction_hook - should be called by the CPU core |
| 1102 | // before executing each instruction |
| 1103 | //------------------------------------------------- |
| 1104 | |
| 1105 | int apollo_debug_instruction_hook(device_t *device, offs_t curpc) |
| 1106 | { |
| 1107 | // trap data remembered for next rte |
| 1108 | static struct { |
| 1109 | UINT32 pc; |
| 1110 | UINT32 sp; |
| 1111 | UINT16 trap_no; |
| 1112 | UINT16 trap_code; |
| 1113 | } trap = { 0, 0, 0, 0 }; |
| 1114 | |
| 1115 | if (apollo_config( APOLLO_CONF_TRAP_TRACE | APOLLO_CONF_FPU_TRACE)) |
| 1116 | { |
| 1117 | UINT32 ppc_save; |
| 1118 | UINT16 ir; |
| 1119 | m68ki_cpu_core *m68k = (m68ki_cpu_core *) downcast<legacy_cpu_device *> (device)->token(); |
| 1120 | m68k->mmu_tmp_buserror_occurred = 0; |
| 1121 | |
| 1122 | /* Read next instruction */ |
| 1123 | ir = (m68k->pref_addr == REG_PC(m68k)) ? m68k->pref_data : m68k->memory.readimm16(REG_PC(m68k)); |
| 1124 | |
| 1125 | // apollo_cpu_context expects the PC of current opcode in REG_PPC (not the previous PC) |
| 1126 | ppc_save = REG_PPC(m68k); |
| 1127 | REG_PPC(m68k) = REG_PC(m68k); |
| 1128 | |
| 1129 | if (m68k->mmu_tmp_buserror_occurred) |
| 1130 | { |
| 1131 | m68k->mmu_tmp_buserror_occurred = 0; |
| 1132 | // give up |
| 1133 | } |
| 1134 | else if ((ir & 0xff00) == 0xf200 && (apollo_config( APOLLO_CONF_FPU_TRACE))) |
| 1135 | { |
| 1136 | char sb[256]; |
| 1137 | LOG(("%s sp=%08x FPU: %x %s", apollo_cpu_context(device->machine().firstcpu), |
| 1138 | REG_A(m68k)[7], ir, disassemble(m68k, REG_PC(m68k), sb))); |
| 1139 | } |
| 1140 | else if (!m68k->pmmu_enabled) |
| 1141 | { |
| 1142 | // skip |
| 1143 | } |
| 1144 | else if (ir == 0x4e73) // RTE |
| 1145 | { |
| 1146 | const UINT16 *data = get_data(m68k, REG_A(m68k)[7]); |
| 1147 | if ( REG_USP(m68k) == 0 && (data[0] & 0x2000) == 0) { |
| 1148 | LOG(("%s sp=%08x RTE: sr=%04x pc=%04x%04x v=%04x usp=%08x", |
| 1149 | apollo_cpu_context(device->machine().firstcpu), |
| 1150 | REG_A(m68k)[7], data[0], data[1], data[2], data[3], REG_USP(m68k))); |
| 1151 | } |
| 1152 | } |
| 1153 | else if ((ir & 0xfff0) == 0x4e40 && (ir & 0x0f) <= 8 && apollo_config(APOLLO_CONF_TRAP_TRACE)) |
| 1154 | { |
| 1155 | // trap n |
| 1156 | trap.pc = REG_PC(m68k); |
| 1157 | trap.sp = REG_A(m68k)[7]; |
| 1158 | trap.trap_no = ir & 0x0f; |
| 1159 | trap.trap_code = REG_D(m68k)[0] & 0xffff; |
| 1160 | |
| 1161 | char sb[1000]; |
| 1162 | LOG(("%s sp=%08x Domain/OS SVC: trap %x 0x%02x: %s", |
| 1163 | apollo_cpu_context(device->machine().firstcpu), trap.sp, |
| 1164 | trap.trap_no, trap.trap_code, |
| 1165 | get_svc_call(m68k, trap.trap_no, trap.trap_code, sb))); |
| 1166 | |
| 1167 | } |
| 1168 | else if (trap.pc == REG_PC(m68k) - 2 && trap.sp == REG_A(m68k)[7]) |
| 1169 | { |
| 1170 | // rte |
| 1171 | char sb[1000]; |
| 1172 | LOG(("%s sp=%08x Domain/OS SVC: %s D0=0x%x", |
| 1173 | apollo_cpu_context(device->machine().firstcpu), trap.sp, |
| 1174 | get_svc_call(m68k, trap.trap_no, trap.trap_code, sb), REG_D(m68k)[0])); |
| 1175 | |
| 1176 | trap.pc = 0; |
| 1177 | trap.sp = 0; |
| 1178 | trap.trap_no = 0; |
| 1179 | trap.trap_code = 0; |
| 1180 | } |
| 1181 | // restore previous PC |
| 1182 | REG_PPC(m68k) = ppc_save; |
| 1183 | } |
| 1184 | return 0; |
| 1185 | } |
src/mess/machine/apollo_net.c
| r0 | r14540 | |
| 1 | /* |
| 2 | * apollo_net.c - simple APOLLO netserver emulation (netman, ARP, IP echo, ...) |
| 3 | * |
| 4 | * Created on: May 12, 2010 |
| 5 | * Author: Hans Ostermeyer |
| 6 | * |
| 7 | * Released for general non-commercial use under the MAME license |
| 8 | * Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | * |
| 10 | * see also: |
| 11 | * - http://www.bitsavers.org/pdf/apollo/AEGIS_Internals_and_Data_Structures_Jan86.pdf |
| 12 | */ |
| 13 | |
| 14 | #define VERBOSE 0 |
| 15 | |
| 16 | // FIXME: these three should not be hardcoded |
| 17 | #define NETSERVER_NODE_ID 0x012340 |
| 18 | #define NETSERVER_IP_ADDRESS {192,168,2,3} /* 192.168.2.3 */ |
| 19 | #define NETSERVER_ROOT_PATH "apollo" |
| 20 | |
| 21 | #include "includes/apollo.h" |
| 22 | #include "machine/3c505.h" |
| 23 | |
| 24 | typedef struct { |
| 25 | UINT8 dest[6]; |
| 26 | UINT8 source[6]; |
| 27 | UINT16 proto; |
| 28 | } ethernet_header; |
| 29 | |
| 30 | typedef struct |
| 31 | { |
| 32 | UINT8 version; |
| 33 | UINT8 tos; |
| 34 | UINT16 tot_len; |
| 35 | UINT16 id; |
| 36 | UINT16 frag_off; |
| 37 | UINT8 ttl; |
| 38 | UINT8 protocol; |
| 39 | UINT16 check; |
| 40 | UINT32 saddr; |
| 41 | UINT32 daddr; |
| 42 | } ip_header; |
| 43 | |
| 44 | typedef struct |
| 45 | { |
| 46 | UINT8 type; |
| 47 | UINT8 code; |
| 48 | UINT16 checksum; |
| 49 | UINT16 id; |
| 50 | UINT16 sequence; |
| 51 | } icmp_header; |
| 52 | |
| 53 | //typedef struct { |
| 54 | // UINT16 version; |
| 55 | // UINT16 checksum; |
| 56 | // UINT16 packet_type; |
| 57 | // UINT16 control_header; |
| 58 | // UINT16 header_length; |
| 59 | // UINT16 header_data_length; |
| 60 | // UINT16 transaction_id; |
| 61 | //} control_header; |
| 62 | // |
| 63 | //typedef struct { |
| 64 | // UINT16 length; |
| 65 | // UINT16 current; |
| 66 | // UINT16 source_socket; |
| 67 | // UINT16 new_route; |
| 68 | //} packet_address; |
| 69 | |
| 70 | #define ETHERNET_HEADER_SIZE sizeof(ethernet_header) |
| 71 | |
| 72 | /* Ethernet protocol ID's */ |
| 73 | #define ETHERNET_PACKET_TYPE_IP 0x0800 /* IP */ |
| 74 | #define ETHERNET_PACKET_TYPE_ARP 0x0806 /* Address resolution */ |
| 75 | #define ETHERNET_PACKET_TYPE_APOLLO 0x8019 |
| 76 | |
| 77 | #define ETHERNET_APOLLO_PREFIX 0x08001e |
| 78 | #define ETHERNET_APOLLO_DOMAIN_PREFIX 0x09001e |
| 79 | |
| 80 | #define ICMP_ECHOREPLY 0 /* Echo Reply */ |
| 81 | #define ICMP_ECHO 8 /* Echo Request */ |
| 82 | |
| 83 | #define PACKET_HEADER_SIZE 64 |
| 84 | |
| 85 | // #define ETH_BUFFER_SIZE 2000 |
| 86 | |
| 87 | // Note: these three pathnames are hardcoded in Apollo DomainOS; don't change them |
| 88 | #define APOLLO_NETBOOT_PATH "/sys/net/netboot" |
| 89 | #define APOLLO_SAU7_PATH "/sau7" |
| 90 | #define APOLLO_SAU8_PATH "/sau8" |
| 91 | #define APOLLO_SAU14_PATH "/sau14" |
| 92 | |
| 93 | static emu_file *current_file = NULL; |
| 94 | |
| 95 | static UINT16 current_sector = 0; |
| 96 | static UINT16 current_last_sector = 0; |
| 97 | static char current_pathname[256]; |
| 98 | |
| 99 | static UINT8 current_rx_data_buffer[ETH_BUFFER_SIZE]; |
| 100 | static int current_rx_data_length; |
| 101 | |
| 102 | static apollo_netserver_transmit tx_callback = NULL; |
| 103 | |
| 104 | static UINT32 my_node_id; |
| 105 | static UINT8 my_ip_address[4] = NETSERVER_IP_ADDRESS; /* 192.168.2.3 */ |
| 106 | static UINT8 my_mac_address[6]; |
| 107 | |
| 108 | static astring root_path; |
| 109 | |
| 110 | // boot_$volun (find partner node) |
| 111 | static UINT8 response_0006[] = { |
| 112 | 0x00,0x01, // 0x40: |
| 113 | 0x00,0x01, |
| 114 | 0x00,0x07, // 0x44: packet type (07 = 06+1) |
| 115 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 116 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 117 | 0x00,0x00,0x00,0x00,0x00,0x00 |
| 118 | }; |
| 119 | |
| 120 | static UINT8 list_directory_header[] = { |
| 121 | 0x00,0x01, // 0x40: |
| 122 | 0x00,0x01, |
| 123 | 0x00,0x0d, // 0x44: packet type (0d = 0c+1) |
| 124 | 0x00,0x00,0x00,0x00, // 0x46: |
| 125 | 0x00,0x01,0x00,0x01, |
| 126 | 0x73,0x61,0x6d,0x62,0x61,0x2f,0x73,0x61,0x75,0x37, // "samba/sau7" |
| 127 | 0x00,0x00,0x28,0xd8,0x00,0x00,0x00,0x00, |
| 128 | 0x75,0x37,0xd8,0xa0,0x76,0x08,0xb5,0x52, |
| 129 | 0x75,0x37,0xe6,0xc6,0x75,0x37,0xd8,0xac |
| 130 | }; |
| 131 | |
| 132 | static UINT8 receive_data_header[] = { |
| 133 | 0x00,0x01, // 0x40: |
| 134 | 0x00,0x01, // 0x42: |
| 135 | 0x00,0x09, // 0x44: packet type (09 = 08+1) |
| 136 | 0x00,0x00,0x00,0x00, // 0x46: |
| 137 | 0x00,0x13,0xfc,0xaf, // 0x4A: high |
| 138 | 0x00,0x13,0xd8,0x00, // 0x4E: low |
| 139 | 0x00,0x13,0xd8,0x2a, // 0x52: start |
| 140 | 0x00,0x13,0xd8,0x00, // 0x56: current load address |
| 141 | 0x00,0x00 // 0x5a: |
| 142 | }; |
| 143 | |
| 144 | static UINT8 not_found_data_header[] = { |
| 145 | 0x00,0x01, // 0x40: |
| 146 | 0x00,0x01, // 0x42: ? |
| 147 | 0x00,0x13, // 0x44: packet type (13 = 12+1) |
| 148 | 0x00,0x0e,0x00,0x07, |
| 149 | 0x00,0x12, // 0x4a = string length |
| 150 | 0x2f,0x2f,0x73,0x61,0x6d,0x62,0x61,0x2f, 0x73,0x61,0x75,0x37,0x2f,0x78,0x78,0x78, /*//samba/sau7/xxxxx */ |
| 151 | 0x78,0x78, |
| 152 | |
| 153 | 0x07,0x48,0x00,0x08,0x07,0x6a,0x00,0x08, 0x07,0x6c,0x00,0x04,0x0c,0x94 |
| 154 | }; |
| 155 | |
| 156 | // boot_$get_uids |
| 157 | static UINT8 response_070a[] = { |
| 158 | 0x00,0x01, // 0x40: |
| 159 | 0x00,0x01, |
| 160 | 0x00,0x0b, // 0x44: packet type (0b = 0a+1) |
| 161 | 0x00,0x00,0x00,0x00, |
| 162 | // d993195c (2010-04-28 07:27:15) |
| 163 | 0xd9,0x93,0x19,0x5c,0x60,0x04,0x20,0xe8, // FIXME: UID of OS paging file (?) |
| 164 | // 7742b564 (1996-08-14 19:12:59) |
| 165 | 0x77,0x42,0xb5,0x64,0xf0,0x04,0x20,0xe8, // 7742B564.F00420E8 is UID of // |
| 166 | 0x77,0x42,0xb5,0x64,0xe0,0x04,0x20,0xe8 // 7742B564.E00420E8 is UID of / (resp. //samba) |
| 167 | }; |
| 168 | |
| 169 | // get (dex) file parameters |
| 170 | static UINT8 response_0718[] = { |
| 171 | 0x00,0x01, // 0x40: |
| 172 | 0x00,0x01, // 0x42: |
| 173 | 0x00,0x19, // 0x44: packet type (19 = 18+1) |
| 174 | 0x00,0x00,0x00,0x00, // 0x46: |
| 175 | 0x01, |
| 176 | 0x01, // 0x4b: systyp (1=dir, 0=file) i.e. is directory |
| 177 | 0x90,0x00, |
| 178 | 0x77,0x43,0x02,0x58,0xe0,0x04,0x20,0xe8, // 0x4e: source UID |
| 179 | 0x00,0x00, // 0x56 |
| 180 | 0x00,0x00, // 0x58: file type (0x0321 = UASC file) |
| 181 | 0x00,0x00,0x00,0x00, // 0x5A: |
| 182 | 0x77,0x43,0x02,0x58,0xe8,0x04,0x20,0xe8, // 0x5E: source UID |
| 183 | 0x00,0x00,0x10,0x00, // 0x66: file size |
| 184 | 0x00,0x00,0x00,0x04, // 0x6A: n sectors (?) |
| 185 | 0xd9,0x8f,0xb5,0xef, // 0x6E: |
| 186 | 0x80,0x27,0x94,0x1e, // 0x72: |
| 187 | 0x77,0x42,0xb5,0x64,0xe0,0x04,0x20,0xe8, // source UID |
| 188 | 0x8d,0x15,0x00,0x02, |
| 189 | 0x00,0x00,0x00,0x00, |
| 190 | 0x00,0x00,0x00,0x00 |
| 191 | }; |
| 192 | |
| 193 | static UINT8 get_byte(const UINT8 *data) { |
| 194 | return data[0]; |
| 195 | } |
| 196 | |
| 197 | static void set_byte(UINT8 *data, const UINT8 value) { |
| 198 | data[0] = value; |
| 199 | } |
| 200 | |
| 201 | static UINT16 get_word(const UINT8 *data) { |
| 202 | return (data[0] << 8) | data[1]; |
| 203 | } |
| 204 | |
| 205 | static void set_word(UINT8 *data, const UINT16 value) { |
| 206 | data[0] = value >> 8; |
| 207 | data[1] = value & 0xff; |
| 208 | } |
| 209 | |
| 210 | static UINT32 get_3byte(const UINT8 *data) { |
| 211 | return (((data[0] << 8) | data[1]) << 8) | data[2]; |
| 212 | } |
| 213 | |
| 214 | static void set_3byte(UINT8 *data, const UINT32 value) { |
| 215 | data[0] = (value >> 16) & 0xff; |
| 216 | data[1] = (value >> 8) & 0xff; |
| 217 | data[2] = value & 0xff; |
| 218 | } |
| 219 | |
| 220 | static UINT32 get_long(const UINT8 *data) { |
| 221 | return (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]; |
| 222 | } |
| 223 | |
| 224 | static void set_long(UINT8 *data, const UINT32 value) { |
| 225 | data[0] = (value >> 24) & 0xff; |
| 226 | data[1] = (value >> 16) & 0xff; |
| 227 | data[2] = (value >> 8) & 0xff; |
| 228 | data[3] = value & 0xff; |
| 229 | } |
| 230 | |
| 231 | static char *get_string(const UINT8 *data) { |
| 232 | static char sb[256]; |
| 233 | int i; |
| 234 | int stringLength = get_word(data); |
| 235 | for (i = 0; i < stringLength && i < sizeof(sb) - 1; i++) { |
| 236 | sb[i] = data[i + 2]; |
| 237 | } |
| 238 | sb[stringLength] = 0; |
| 239 | return sb; |
| 240 | } |
| 241 | |
| 242 | static char *get_file_name(const UINT8 *data) { |
| 243 | char * s = get_string(data); |
| 244 | int i = strlen(s); |
| 245 | while (--i >= 0) { |
| 246 | s[i] = tolower(s[i]); |
| 247 | } |
| 248 | return s; |
| 249 | } |
| 250 | |
| 251 | static int get_file_size(const char *path) { |
| 252 | int file_size = 0; |
| 253 | emu_file file(OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD); |
| 254 | file_error filerr = file.open(path); |
| 255 | if (filerr == FILERR_NONE) |
| 256 | { |
| 257 | file_size = file.size(); |
| 258 | file.close(); |
| 259 | } |
| 260 | LOG1(("##### %s - file_size=%d",path, file_size)); |
| 261 | return file_size; |
| 262 | } |
| 263 | |
| 264 | static int is_directory(const char *path) { |
| 265 | int is_directory = 0; |
| 266 | osd_directory *curdir; |
| 267 | if ((curdir = osd_opendir(path)) != NULL) |
| 268 | { |
| 269 | osd_closedir(curdir); |
| 270 | is_directory = 1; |
| 271 | } |
| 272 | LOG1(("##### %s - is_directory=%d",path, is_directory)); |
| 273 | return is_directory; |
| 274 | } |
| 275 | |
| 276 | static int get_file_type(const char *path) { |
| 277 | if (!is_directory(path)) { |
| 278 | const char *suffix = path + strlen(path); |
| 279 | while (suffix != path && *--suffix != '.') { |
| 280 | } |
| 281 | |
| 282 | if (strcmp(suffix, ".cmd") == 0 || strcmp(suffix, ".hlp") == 0) { |
| 283 | return 0x0321; // UASC file |
| 284 | } |
| 285 | } |
| 286 | return 0; |
| 287 | } |
| 288 | |
| 289 | static int set_ethernet_header(UINT8 *data, UINT8 client_ethernet_address[6]) { |
| 290 | memcpy(data + 0, client_ethernet_address, 6); |
| 291 | set_3byte(data + 6, ETHERNET_APOLLO_PREFIX); |
| 292 | set_3byte(data + 9, my_node_id); |
| 293 | set_word(data + 12, ETHERNET_PACKET_TYPE_APOLLO); |
| 294 | return ETHERNET_HEADER_SIZE; |
| 295 | } |
| 296 | |
| 297 | //static int set_packet_header1(UINT8 *packet_buffer, UINT32 dest_node_id, |
| 298 | // UINT32 source_node_id) { |
| 299 | // |
| 300 | // //0000 08 00 1e 02 61 6d 08 00 1e 04 20 e8 80 19 ff ff |
| 301 | // //0010 00 20 00 be 00 00 47 11 08 00 1e 02 61 6d 06 20 |
| 302 | // //0020 00 00 00 00 08 00 1e 04 20 e8 00 01 00 02 61 6d |
| 303 | // //0030 20 00 00 00 00 04 20 e8 02 00 20 00 00 4e 00 02 |
| 304 | // //0040 00 00 00 00 2e 04 00 01 20 e8 00 01 00 04 20 e8 |
| 305 | // |
| 306 | // //0050 61 6d 06 20 ff ff 00 20 00 04 00 00 47 11 00 00 |
| 307 | // //0060 00 02 61 6d 06 20 00 00 00 00 00 00 00 04 20 e8 |
| 308 | // //0070 00 01 00 00 00 00 80 31 00 01 |
| 309 | // |
| 310 | // set_packet_header(packet_buffer, dest_node_id, source_node_id); |
| 311 | // set_word(packet_buffer + 8, 0x4711); // Apollo network number |
| 312 | // set_word(packet_buffer + 16, 0x0620); // ? was 0x0000 |
| 313 | // set_word(packet_buffer + 28, 0x0001); // ? was 0x0003 |
| 314 | |
| 315 | // set_long(packet_buffer + 34, 0x20000000L); // ? was 0x24000000L |
| 316 | // set_long(packet_buffer + 42, 0x02002000L); // ? was 0x01002400L |
| 317 | // set_word(packet_buffer + 46, 0x004e); // ? data_size + 0x22 |
| 318 | // set_word(packet_buffer + 48, 0x0002); // ? data_size |
| 319 | // set_word(packet_buffer + 54, 0x2e04); // ? 0x0401 |
| 320 | // set_word(packet_buffer + 56, 0x0001); // ? 0x0003 |
| 321 | // set_word(packet_buffer + 60, 0x616d); |
| 322 | // set_word(packet_buffer + 62, 0x0000); |
| 323 | // return PACKET_HEADER_SIZE; |
| 324 | //} |
| 325 | |
| 326 | static int set_packet_header(UINT8 *packet_buffer, UINT32 dest_node_id, |
| 327 | UINT32 source_node_id) { |
| 328 | // --------- apollo header -------------- |
| 329 | set_word(packet_buffer, 0xffff); |
| 330 | // set_word(packet_buffer + 2, data_size + PACKET_HEADER_SIZE); |
| 331 | set_word(packet_buffer + 4, 0x00be); |
| 332 | set_word(packet_buffer + 6, 0x0000); |
| 333 | set_word(packet_buffer + 8, 0x0000); // Apollo network number |
| 334 | set_3byte(packet_buffer + 10, ETHERNET_APOLLO_PREFIX); |
| 335 | set_3byte(packet_buffer + 13, dest_node_id); |
| 336 | set_word(packet_buffer + 16, 0x0000); |
| 337 | set_word(packet_buffer + 18, 0x0000); |
| 338 | set_word(packet_buffer + 20, 0x0000); |
| 339 | set_3byte(packet_buffer + 22, ETHERNET_APOLLO_PREFIX); |
| 340 | set_3byte(packet_buffer + 25, source_node_id); |
| 341 | set_word(packet_buffer + 28, 0x0003); |
| 342 | // --------- data header -------------- |
| 343 | set_long(packet_buffer + 30, dest_node_id); |
| 344 | set_long(packet_buffer + 34, 0x24000000L); |
| 345 | set_long(packet_buffer + 38, source_node_id); |
| 346 | set_long(packet_buffer + 42, 0x01002400L); |
| 347 | // set_word(packet_buffer + 46, data_size + 0x22); |
| 348 | // set_word(packet_buffer + 48, data_size); |
| 349 | set_word(packet_buffer + 50, 0x0000); |
| 350 | set_word(packet_buffer + 52, 0x0000); |
| 351 | // --------- data -------------- |
| 352 | set_word(packet_buffer + 54, 0x0401); |
| 353 | set_word(packet_buffer + 56, 0x0003); |
| 354 | set_word(packet_buffer + 58, 0x20e8); |
| 355 | set_word(packet_buffer + 60, 0x616d); |
| 356 | set_word(packet_buffer + 62, 0x0000); |
| 357 | return PACKET_HEADER_SIZE; |
| 358 | } |
| 359 | |
| 360 | static int set_packet(UINT8 *packet_buffer, UINT8 *packet_data, |
| 361 | int packet_data_size) { |
| 362 | set_word(packet_buffer + 2, packet_data_size + PACKET_HEADER_SIZE); |
| 363 | set_word(packet_buffer + 46, packet_data_size + 0x22); |
| 364 | set_word(packet_buffer + 48, packet_data_size); |
| 365 | |
| 366 | memcpy(packet_buffer + PACKET_HEADER_SIZE, packet_data, packet_data_size); |
| 367 | |
| 368 | return packet_data_size; |
| 369 | } |
| 370 | |
| 371 | static int get_packet_size(UINT8 *packet_buffer) { |
| 372 | return get_word(packet_buffer + 2); |
| 373 | } |
| 374 | |
| 375 | static int get_dir_data(const char *pathname, UINT8 *packet_buffer) { |
| 376 | int nBytes, lineLength; |
| 377 | char *data_buffer; |
| 378 | osd_directory *curdir; |
| 379 | const osd_directory_entry *dir; |
| 380 | |
| 381 | char dir_path[1024]; |
| 382 | strcpy(dir_path, root_path); |
| 383 | strcat (dir_path, pathname); |
| 384 | |
| 385 | set_packet(packet_buffer, list_directory_header, |
| 386 | sizeof(list_directory_header)); |
| 387 | data_buffer = (char *) (packet_buffer + get_packet_size(packet_buffer)); |
| 388 | |
| 389 | strcpy(data_buffer, "\n\r"); |
| 390 | strcat(data_buffer, pathname); |
| 391 | strcat(data_buffer, "\n\r"); |
| 392 | |
| 393 | if ((curdir = osd_opendir(dir_path)) == NULL) |
| 394 | { |
| 395 | strcat(data_buffer, "Error: failed to open directory "); |
| 396 | strcat(data_buffer, dir_path); |
| 397 | strcat(data_buffer, "\r\n"); |
| 398 | } |
| 399 | else |
| 400 | { |
| 401 | osd_closedir(curdir); |
| 402 | |
| 403 | // open a path to the netserver directory |
| 404 | file_enumerator path(dir_path); |
| 405 | |
| 406 | lineLength = 99; |
| 407 | while ((dir = path.next()) != NULL) |
| 408 | { |
| 409 | int length = strlen(dir->name); |
| 410 | LOG1(("##### %d %s",length, dir->name)); |
| 411 | |
| 412 | if (strcmp(dir->name, ".") != 0 && strcmp(dir->name, "..") != 0) |
| 413 | { |
| 414 | lineLength += 3 + strlen(dir->name); |
| 415 | if (lineLength > 72) { |
| 416 | strcat(data_buffer, "\n\r"); |
| 417 | lineLength = 3 + strlen(dir->name); |
| 418 | } |
| 419 | strcat(data_buffer, " "); |
| 420 | strcat(data_buffer, dir->name); |
| 421 | } |
| 422 | } |
| 423 | strcat(data_buffer, "\n\r"); |
| 424 | } |
| 425 | |
| 426 | nBytes = strlen(data_buffer); |
| 427 | nBytes = (nBytes + 1) & 0xfffffffe; |
| 428 | |
| 429 | set_word(packet_buffer + 2, get_word(packet_buffer + 2) + nBytes); |
| 430 | set_word(packet_buffer + 50, nBytes); |
| 431 | |
| 432 | return nBytes + sizeof(list_directory_header); |
| 433 | } |
| 434 | |
| 435 | static int get_file_data(const char *pathname, UINT8 *packet_buffer, |
| 436 | UINT16 first_sector, UINT16 last_sector) { |
| 437 | UINT8 *packet_data = packet_buffer + PACKET_HEADER_SIZE; |
| 438 | UINT8 *data_buffer; |
| 439 | int nBytes; |
| 440 | UINT32 fileSize = 0; |
| 441 | file_error filerr; |
| 442 | |
| 443 | if(current_file == NULL) |
| 444 | { |
| 445 | current_file = global_alloc(emu_file(root_path, OPEN_FLAG_READ)); |
| 446 | // skip leading '/' |
| 447 | filerr = current_file->open( pathname+1); |
| 448 | |
| 449 | if (filerr != FILERR_NONE) |
| 450 | { |
| 451 | global_free(current_file); |
| 452 | current_file = NULL; |
| 453 | } |
| 454 | |
| 455 | fileSize = current_file == NULL ? 0 : current_file->size(); |
| 456 | current_sector = 0; |
| 457 | |
| 458 | LOG1(("##### %s - %s filerr=%d fileSize=%d", root_path.cstr(), pathname, filerr, fileSize)); |
| 459 | } else { |
| 460 | current_sector++; |
| 461 | } |
| 462 | current_last_sector = last_sector; |
| 463 | |
| 464 | if (current_file == NULL) |
| 465 | { |
| 466 | set_packet(packet_buffer, not_found_data_header, |
| 467 | sizeof(not_found_data_header)); |
| 468 | |
| 469 | set_word(packet_data + 0x0A, strlen(pathname)); |
| 470 | strncpy((char *) packet_data + 0x0C, pathname, 0x24); |
| 471 | return sizeof(not_found_data_header); |
| 472 | } else { |
| 473 | set_packet(packet_buffer, receive_data_header, |
| 474 | sizeof(receive_data_header)); |
| 475 | |
| 476 | data_buffer = (packet_buffer + get_packet_size(packet_buffer)); |
| 477 | |
| 478 | nBytes = current_file->read(data_buffer, 1024); |
| 479 | |
| 480 | if (nBytes < 0) { |
| 481 | nBytes = 0; |
| 482 | } |
| 483 | |
| 484 | // help in dex will fail, if size is odd (5.5.2010 - ost) |
| 485 | nBytes = (nBytes + 1) & 0xfffffffe; |
| 486 | |
| 487 | if (nBytes < 1024) |
| 488 | { |
| 489 | current_file->close(); |
| 490 | global_free(current_file); |
| 491 | current_file = NULL; |
| 492 | } |
| 493 | else if (current_sector == 0) { |
| 494 | // set header addresses from first sector read |
| 495 | UINT32 low = get_long(data_buffer + 0); |
| 496 | UINT32 start = get_long(data_buffer + 4); |
| 497 | UINT32 high = low + fileSize - 1; |
| 498 | |
| 499 | set_long(receive_data_header + 0x0A, high); |
| 500 | set_long(receive_data_header + 0x0E, low); |
| 501 | set_long(receive_data_header + 0x12, start); |
| 502 | set_long(receive_data_header + 0x16, low); |
| 503 | |
| 504 | set_packet(packet_buffer, receive_data_header, |
| 505 | sizeof(receive_data_header)); |
| 506 | } |
| 507 | |
| 508 | if (VERBOSE > 1) { |
| 509 | LOG1(("##### %s: 3C505 current address = %0x first/last/current sector = %0x / %0x / %0x", |
| 510 | pathname, get_long(receive_data_header + 0x16), first_sector, last_sector, current_sector)); |
| 511 | } |
| 512 | |
| 513 | set_long(receive_data_header + 0x16, get_long(receive_data_header + 0x16) + nBytes); |
| 514 | set_word(packet_data + 0x1A, nBytes < 1024 ? 0xffff : current_sector == last_sector ? 0x00ff : 0); |
| 515 | |
| 516 | set_word(packet_buffer + 2, get_word(packet_buffer + 2) + nBytes); |
| 517 | set_word(packet_buffer + 50, nBytes); |
| 518 | |
| 519 | return nBytes + sizeof(receive_data_header); |
| 520 | } |
| 521 | } |
| 522 | |
| 523 | static void log_data(const device_t *device, const char *type, |
| 524 | const UINT8 *data, int data_length) { |
| 525 | if (VERBOSE > 1) { |
| 526 | int i; |
| 527 | logerror("%s - %s: Net Server %s Data (length=%2x)", apollo_cpu_context( |
| 528 | device->machine().firstcpu), device->tag(), type, data_length); |
| 529 | for (i = 0; i < data_length; i++) { |
| 530 | logerror(" %02x", data[i]); |
| 531 | } |
| 532 | logerror("\n"); |
| 533 | } |
| 534 | } |
| 535 | |
| 536 | static UINT16 get_socket(const UINT8 rx_data_buffer[], int rx_data_length) { |
| 537 | |
| 538 | const UINT8 * packet_buffer = rx_data_buffer + ETHERNET_HEADER_SIZE; |
| 539 | int packet_length = rx_data_length - ETHERNET_HEADER_SIZE; |
| 540 | |
| 541 | UINT16 socket = packet_length < 0x11 ? 0xffff : get_word(packet_buffer + 0x10); // 0x10: dest socket |
| 542 | |
| 543 | return socket; |
| 544 | } |
| 545 | |
| 546 | /*************************************************************************** |
| 547 | netman server |
| 548 | ***************************************************************************/ |
| 549 | |
| 550 | static int netman_server(const device_t *device, |
| 551 | const UINT8 rx_data_buffer[], int rx_data_length, UINT8 tx_data_buffer[]) { |
| 552 | UINT16 service; |
| 553 | UINT16 node_type; // SAU7, SAU8 or SAU14 |
| 554 | char pathname[256]; |
| 555 | |
| 556 | int tx_data_length; |
| 557 | |
| 558 | UINT8 *packet_buffer = tx_data_buffer + ETHERNET_HEADER_SIZE; |
| 559 | |
| 560 | UINT32 client_node_id; |
| 561 | UINT8 client_ethernet_address[6]; |
| 562 | |
| 563 | UINT16 last_sector; |
| 564 | UINT16 first_sector; |
| 565 | |
| 566 | client_node_id = get_3byte(rx_data_buffer + 9); |
| 567 | memcpy(client_ethernet_address, rx_data_buffer + 6, 6); |
| 568 | |
| 569 | log_data(device, "Rx", rx_data_buffer, rx_data_length); |
| 570 | |
| 571 | // strip off the ethernet header; |
| 572 | rx_data_buffer += ETHERNET_HEADER_SIZE; |
| 573 | rx_data_length -= ETHERNET_HEADER_SIZE; |
| 574 | |
| 575 | service = (rx_data_length > 0x45) ? get_word(rx_data_buffer + 0x44) : 0xffff; |
| 576 | first_sector = (rx_data_length > 0x6b) ? get_word(rx_data_buffer + 0x6a) : 0; |
| 577 | // FIXME: hack |
| 578 | // last_sector = (rx_data_length > 0x6d) ? get_word(rx_data_buffer + 0x6c) : 0; |
| 579 | last_sector = (rx_data_length > 0x6d) ? get_word(rx_data_buffer + 0x6c) : 0x0f; |
| 580 | |
| 581 | set_ethernet_header(tx_data_buffer, client_ethernet_address); |
| 582 | set_packet_header(packet_buffer, client_node_id, my_node_id); |
| 583 | |
| 584 | node_type = service >> 8; |
| 585 | |
| 586 | switch (service & 0xff) { |
| 587 | case 6: // boot_$volun (find partner node) |
| 588 | DLOG1(("Net Server service=%04x (boot_$volun)", service)); |
| 589 | set_packet(packet_buffer, response_0006, sizeof(response_0006)); |
| 590 | break; |
| 591 | |
| 592 | case 8: // boot_$sysboot (get netboot) |
| 593 | get_file_data(APOLLO_NETBOOT_PATH, packet_buffer, first_sector, last_sector); |
| 594 | DLOG1(("Net Server service=%04x (boot_$sysboot - sector %x of %x-%x)", service, current_sector, first_sector, last_sector)); |
| 595 | break; |
| 596 | case 0x0a: // boot_$get_uids (get UIDs for OS paging file, network root and the node entry directory) |
| 597 | set_packet(packet_buffer, response_070a, sizeof(response_070a)); |
| 598 | DLOG1(("Net Server service=%04x (boot_$get_uids)", service)); |
| 599 | break; |
| 600 | case 0x0c: // boot_$mult_ld (list directory for sau7, SAU8, SAU14) |
| 601 | get_dir_data( node_type == 7 ? APOLLO_SAU7_PATH : node_type == 8 ? APOLLO_SAU8_PATH : APOLLO_SAU14_PATH, packet_buffer); |
| 602 | DLOG1(("Net Server service=%04x (boot_$mult_ld)", service)); |
| 603 | break; |
| 604 | case 0x12: // boot_$load (ex /sau7/self_test, domain_os, ...) |
| 605 | strcpy(pathname, node_type == 7 ? APOLLO_SAU7_PATH : node_type == 8 ? APOLLO_SAU8_PATH : APOLLO_SAU14_PATH); |
| 606 | strcat(pathname, "/"); |
| 607 | strcat(pathname, get_file_name(rx_data_buffer + 0x48)); |
| 608 | get_file_data(pathname, packet_buffer, first_sector, last_sector); |
| 609 | DLOG1(("Net Server service=%04x (boot_$load %s - sector %x of %x-%x)", service, pathname, current_sector, first_sector, last_sector)); |
| 610 | break; |
| 611 | case 0x18: // boot_$set_path (set current path and get attributes of current path) |
| 612 | set_packet(packet_buffer, response_0718, sizeof(response_0718)); |
| 613 | |
| 614 | if (get_long(rx_data_buffer + 0x6e) == 0L && get_long(rx_data_buffer + 0x72) == 0L) { |
| 615 | // reset path name to root dir |
| 616 | strcpy(current_pathname, root_path); |
| 617 | } |
| 618 | |
| 619 | // FIXME: why is this necessary??? |
| 620 | if (is_directory(current_pathname)) { |
| 621 | strcat(current_pathname, "/"); |
| 622 | strcat(current_pathname, get_file_name(rx_data_buffer + 0x48)); |
| 623 | } |
| 624 | |
| 625 | // 0x4b: systyp (1=dir, 0=file) |
| 626 | set_byte(packet_buffer + 0x4b, is_directory(current_pathname)); |
| 627 | set_word(packet_buffer + 0x58, get_file_type(current_pathname)); |
| 628 | set_long(packet_buffer + 0x66, get_file_size(current_pathname)); |
| 629 | |
| 630 | DLOG1(("Net Server service=%04x (boot_$set_path %s)", service, current_pathname + strlen(root_path))); |
| 631 | break; |
| 632 | case 0x1a: // boot_$load_file (?): load /sau7/cmd/startup.cmd, /sau7/cpu.dex, ... |
| 633 | get_file_data(current_pathname + strlen(root_path), packet_buffer, first_sector, last_sector); |
| 634 | DLOG1(("Net Server service=%04x (boot_$load_file %s - sector %x of %x-%x)", service, current_pathname + strlen(root_path), current_sector, first_sector, last_sector)); |
| 635 | break; |
| 636 | default: |
| 637 | DLOG(("Net Server - unexpected service %04x", service&0xff)); |
| 638 | return 0; |
| 639 | } |
| 640 | |
| 641 | set_word(packet_buffer + 0x44, (service & 0xff) + 1); // 0x44: response packet type |
| 642 | |
| 643 | tx_data_length = ETHERNET_HEADER_SIZE + get_packet_size(packet_buffer); |
| 644 | |
| 645 | log_data(device, "Tx", tx_data_buffer, tx_data_length); |
| 646 | return tx_data_length; |
| 647 | } |
| 648 | |
| 649 | static int is_ethernet_broadcast_address(const UINT8 ethernet_header[]) { |
| 650 | return get_3byte(ethernet_header + 0) == 0xffffff && // |
| 651 | get_3byte(ethernet_header + 3) == 0xffffff; |
| 652 | } |
| 653 | |
| 654 | static int is_apollo_multicast_address(const UINT8 ethernet_header[]) { |
| 655 | return get_3byte(ethernet_header + 0) == ETHERNET_APOLLO_DOMAIN_PREFIX && // |
| 656 | (get_3byte(ethernet_header + 3) == 0L || get_3byte(ethernet_header + 3) == 1L); |
| 657 | } |
| 658 | |
| 659 | static int is_my_ethernet_address(const UINT8 mac_address[]) { |
| 660 | return memcmp(mac_address, my_mac_address, 6) == 0; |
| 661 | } |
| 662 | |
| 663 | static int is_my_ip_address(const UINT8 ip_address[]) { |
| 664 | return memcmp (ip_address, my_ip_address, 4) == 0; |
| 665 | } |
| 666 | |
| 667 | static int is_my_node_id(const UINT8 node_id[]) { |
| 668 | return get_long(node_id) == my_node_id; |
| 669 | } |
| 670 | |
| 671 | static int ethernet_packet_is_for_me(const UINT8 ethernet_header[], |
| 672 | const int data_length) { |
| 673 | return data_length >= ETHERNET_HEADER_SIZE && ( |
| 674 | is_ethernet_broadcast_address(ethernet_header) || |
| 675 | is_apollo_multicast_address(ethernet_header) || |
| 676 | is_my_ethernet_address(ethernet_header)); |
| 677 | } |
| 678 | |
| 679 | static int is_apollo_request(const UINT8 ethernet_header[], |
| 680 | const int data_length) { |
| 681 | |
| 682 | return data_length >= 0x30 && // |
| 683 | get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_APOLLO; |
| 684 | } |
| 685 | |
| 686 | static int is_apollo_arp_request(const UINT8 ethernet_header[], const int data_length) { |
| 687 | return data_length >= 0x30 && // |
| 688 | get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_ARP && // |
| 689 | get_word(ethernet_header + 0x10) == ETHERNET_PACKET_TYPE_APOLLO && // |
| 690 | is_apollo_multicast_address(ethernet_header) && // |
| 691 | is_my_node_id(ethernet_header + 0x26); |
| 692 | } |
| 693 | |
| 694 | static int is_ip_arp_request(const UINT8 ethernet_header[], const int data_length) { |
| 695 | return data_length >= 0x30 && // |
| 696 | get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_ARP && // |
| 697 | get_word(ethernet_header + 0x10) == ETHERNET_PACKET_TYPE_IP && // |
| 698 | is_ethernet_broadcast_address(ethernet_header) && // |
| 699 | is_my_ip_address (ethernet_header + 0x26); |
| 700 | } |
| 701 | |
| 702 | static int is_ip_echo_request(const UINT8 ethernet_header[], const int data_length) { |
| 703 | return data_length >= 0x30 && // |
| 704 | get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_IP && // |
| 705 | get_byte(ethernet_header + 0x22) == ICMP_ECHO && // |
| 706 | is_my_ethernet_address(ethernet_header); |
| 707 | } |
| 708 | |
| 709 | static UINT16 in_checksum(UINT8 *ptr, UINT32 nbytes) |
| 710 | { |
| 711 | UINT32 sum = 0; |
| 712 | while (nbytes > 1) |
| 713 | { |
| 714 | // MSB first |
| 715 | sum += (*ptr++) << 8; |
| 716 | sum += *ptr++; |
| 717 | nbytes -=2; |
| 718 | } |
| 719 | if (nbytes == 1) |
| 720 | { |
| 721 | sum += (*ptr++) << 8; |
| 722 | } |
| 723 | sum = (sum >> 16) + (sum & 0xffff); |
| 724 | sum += (sum >> 16); |
| 725 | |
| 726 | return (~sum) & 0xffff; |
| 727 | } |
| 728 | |
| 729 | /*************************************************************************** |
| 730 | simple ARP Server emulation |
| 731 | ***************************************************************************/ |
| 732 | |
| 733 | static int arp_server(const device_t *device, |
| 734 | const UINT8 rx_data[], int rx_data_length, |
| 735 | UINT8 tx_data[]) { |
| 736 | |
| 737 | // static UINT8 arp_response[] = { |
| 738 | // 0x08,0x00,0x1e,0x02,0x61,0x6d, // 0x00: Ethernet address of destination |
| 739 | // 0x08,0x00,0x1e,0x04,0x20,0xe8, // 0x06: Ethernet address of sender |
| 740 | // 0x08,0x06, // 0x0c: Protocol type |
| 741 | // 0x00,0x01, // 0x0e: Hardware address space |
| 742 | // 0x80,0x19, // 0x10: Protocol address space |
| 743 | // 0x06, // 0x12: byte length of each hardware address |
| 744 | // 0x04, // 0x13: byte length of each protocol address |
| 745 | // 0x00,0x02, // 0x14: opcode (ares_op$REQUEST | ares_op$REPLY) |
| 746 | // 0x08,0x00,0x1e,0x04,0x20,0xe8, // 0x16: Hardware address of sender of this packet |
| 747 | // 0x00,0x04,0x20,0xe8, // 0x1c: Protocol address of sender of this packet |
| 748 | // 0x08,0x00,0x1e,0x02,0x61,0x6d, // 0x20: Hardware address of target of this packet (if known) |
| 749 | // 0x00,0x02,0x61,0x6d, // 0x26: Protocol address of target |
| 750 | // ... |
| 751 | // }; |
| 752 | |
| 753 | UINT16 tx_data_length = rx_data_length; |
| 754 | memcpy(tx_data, rx_data, tx_data_length); |
| 755 | |
| 756 | // 0x00: Ethernet address of destination |
| 757 | memcpy(tx_data + 0x00, rx_data + 0x06, 6); |
| 758 | // 0x06: Ethernet address of sender |
| 759 | memcpy(tx_data + 0x06, my_mac_address, 6); |
| 760 | // 0x14: opcode (ares_op$REQUEST | ares_op$REPLY) |
| 761 | set_word(tx_data + 0x14, 2); |
| 762 | // 0x16: Hardware address of sender |
| 763 | memcpy(tx_data + 0x16, my_mac_address, 6); |
| 764 | // 0x1c: Protocol address of sender |
| 765 | memcpy(tx_data + 0x1c, rx_data + 0x26, 4); |
| 766 | // 0x20: Hardware address of target (if known) |
| 767 | memcpy(tx_data + 0x20, rx_data + 0x16, 6); |
| 768 | // 0x26: Protocol address of target |
| 769 | memcpy(tx_data + 0x26, rx_data + 0x1c, 4); |
| 770 | |
| 771 | log_data(device, "ARP Rx", rx_data, rx_data_length); |
| 772 | log_data(device, "ARP Tx", tx_data, tx_data_length); |
| 773 | return tx_data_length; |
| 774 | } |
| 775 | |
| 776 | /*************************************************************************** |
| 777 | simple Echo (ping) Server emulation |
| 778 | ***************************************************************************/ |
| 779 | |
| 780 | static int echo_server(const device_t *device, |
| 781 | const UINT8 rx_data[], int rx_data_length, |
| 782 | UINT8 tx_data[]) { |
| 783 | |
| 784 | static const UINT32 ip_offset = sizeof(ethernet_header); |
| 785 | static const UINT32 icmp_offset = ip_offset + sizeof(ip_header); |
| 786 | |
| 787 | UINT16 tx_data_length = rx_data_length; |
| 788 | memcpy(tx_data, rx_data, tx_data_length); |
| 789 | |
| 790 | // 0x00: Ethernet address of destination |
| 791 | memcpy(tx_data + 0x00, rx_data + 0x06, 6); |
| 792 | // 0x06: Ethernet address of sender |
| 793 | memcpy(tx_data + 0x06, rx_data + 0x00, 6); |
| 794 | // 0x12: ip.id |
| 795 | set_word(tx_data + 0x12, 0x0573); |
| 796 | // 0x18: ip.checksum |
| 797 | set_word(tx_data + 0x18, 0); |
| 798 | set_word(tx_data + 0x18, in_checksum(tx_data + ip_offset, sizeof(ip_header))); |
| 799 | |
| 800 | // 0x1a: Protocol address of sender |
| 801 | memcpy(tx_data + 0x1a, rx_data + 0x1e, 4); |
| 802 | // 0x1e: Protocol address of target |
| 803 | memcpy(tx_data + 0x1e, rx_data + 0x1a, 4); |
| 804 | // 0x22: icmp.type |
| 805 | set_byte(tx_data + 0x22, ICMP_ECHOREPLY); |
| 806 | // 0x24: icmp.cksump |
| 807 | set_word(tx_data + 0x24, 0); |
| 808 | set_word(tx_data + 0x24, in_checksum(tx_data + icmp_offset, tx_data_length-icmp_offset)); |
| 809 | |
| 810 | log_data(device, "Echo Rx", rx_data, rx_data_length); |
| 811 | log_data(device, "Echo Tx", tx_data, tx_data_length); |
| 812 | return tx_data_length; |
| 813 | } |
| 814 | |
| 815 | /*************************************************************************** |
| 816 | netserver |
| 817 | ***************************************************************************/ |
| 818 | |
| 819 | static int netserver(const device_t *device, |
| 820 | const UINT8 rx_data[], int rx_data_length, |
| 821 | UINT8 tx_data[]) { |
| 822 | |
| 823 | if (!ethernet_packet_is_for_me(rx_data, rx_data_length)) |
| 824 | return 0; // skip |
| 825 | else if (is_apollo_request(rx_data, rx_data_length)) |
| 826 | { |
| 827 | UINT16 socket = get_socket(rx_data, rx_data_length); |
| 828 | |
| 829 | switch (socket) { |
| 830 | case 1: // Paging socket |
| 831 | break; |
| 832 | case 2: // File socket |
| 833 | // return file_server(device, rx_data, rx_data_length, tx_data); |
| 834 | break; |
| 835 | case 3: // NETMAN socket |
| 836 | return netman_server(device, rx_data, rx_data_length, tx_data); |
| 837 | case 4: // Information socket |
| 838 | break; |
| 839 | case 5: // Receives internet asknode "who" replies |
| 840 | break; |
| 841 | case 6: // File server overflow socket |
| 842 | break; |
| 843 | case 7: // Software diagnostic socket |
| 844 | break; |
| 845 | case 8: // routing information protocol (RIP) socket |
| 846 | break; |
| 847 | case 9: // Mailbox socket |
| 848 | break; |
| 849 | case 10: // NS Helper socket |
| 850 | break; |
| 851 | case 11: // TCP/IP |
| 852 | break; |
| 853 | case 12: // ? |
| 854 | break; |
| 855 | default: |
| 856 | break; |
| 857 | } |
| 858 | |
| 859 | DLOG1(("Net Server - socket %d not yet supported", socket)); |
| 860 | return 0; |
| 861 | } else if (is_apollo_arp_request(rx_data, rx_data_length)) { |
| 862 | return arp_server(device, rx_data, rx_data_length, tx_data); |
| 863 | } else if (is_ip_arp_request(rx_data, rx_data_length)) { |
| 864 | return arp_server(device, rx_data, rx_data_length, tx_data); |
| 865 | } else if (is_ip_echo_request(rx_data, rx_data_length)) { |
| 866 | return echo_server(device, rx_data, rx_data_length, tx_data); |
| 867 | } else { |
| 868 | log_data(device, "unexpected Rx", rx_data, rx_data_length); |
| 869 | return 0; |
| 870 | } |
| 871 | } |
| 872 | |
| 873 | /*************************************************************************** |
| 874 | receive_interrupt |
| 875 | ***************************************************************************/ |
| 876 | |
| 877 | static TIMER_CALLBACK(receive_interrupt) { |
| 878 | device_t *device = (device_t *)ptr; |
| 879 | |
| 880 | UINT8 tx_data_buffer[ETH_BUFFER_SIZE]; |
| 881 | |
| 882 | int tx_data_length = netserver(device, current_rx_data_buffer, current_rx_data_length, tx_data_buffer); |
| 883 | |
| 884 | DLOG2(("Net Server rx/tx_data_length = %x/%x current_sector=%x current_last_sector=%x", |
| 885 | current_rx_data_length, tx_data_length, current_sector, current_last_sector )); |
| 886 | |
| 887 | if (tx_data_length > 0 && tx_callback != NULL) { |
| 888 | // threecom3c505_receive(device, tx_data_buffer, tx_data_length); |
| 889 | (*tx_callback)(device, tx_data_buffer, tx_data_length); |
| 890 | } |
| 891 | |
| 892 | if (current_file != NULL && current_sector < current_last_sector) |
| 893 | { |
| 894 | // more packets pending |
| 895 | machine.scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device); |
| 896 | } else { |
| 897 | current_rx_data_length = 0; |
| 898 | } |
| 899 | } |
| 900 | |
| 901 | /*************************************************************************** |
| 902 | apollo_netserver_receive - receive and process an ethernet packet |
| 903 | ***************************************************************************/ |
| 904 | |
| 905 | int apollo_netserver_receive(device_t *device, const UINT8 rx_data_buffer[], |
| 906 | int rx_data_length) |
| 907 | { |
| 908 | if (!ethernet_packet_is_for_me(rx_data_buffer, rx_data_length)) |
| 909 | { |
| 910 | return 1; // skip packet |
| 911 | } |
| 912 | else if (current_rx_data_length > 0) |
| 913 | { |
| 914 | LOG(("!!!! apollo_netserver_receive: busy - skipped data with length %02x",rx_data_length)); |
| 915 | return 0; |
| 916 | } |
| 917 | else |
| 918 | { |
| 919 | memcpy(current_rx_data_buffer, rx_data_buffer, rx_data_length); |
| 920 | current_rx_data_length = rx_data_length; |
| 921 | |
| 922 | // delay response to multicast requests |
| 923 | int ms = is_apollo_multicast_address(rx_data_buffer) ? 100 : 1; |
| 924 | device->machine().scheduler().timer_set(attotime::from_msec(ms), FUNC(receive_interrupt), 0, device); |
| 925 | return 1; |
| 926 | } |
| 927 | } |
| 928 | |
| 929 | /*************************************************************************** |
| 930 | apollo_netserver_init - specify the transmitter call back function |
| 931 | ***************************************************************************/ |
| 932 | |
| 933 | void apollo_netserver_init(const char *root_path, apollo_netserver_transmit tx_data) |
| 934 | { |
| 935 | ::root_path.cat(root_path); |
| 936 | ::root_path.cat(PATH_SEPARATOR); |
| 937 | ::root_path.cat(NETSERVER_ROOT_PATH); |
| 938 | |
| 939 | ::tx_callback = tx_data; |
| 940 | |
| 941 | my_node_id = NETSERVER_NODE_ID; |
| 942 | set_3byte(my_mac_address, ETHERNET_APOLLO_PREFIX); |
| 943 | set_3byte(my_mac_address + 3, my_node_id); |
| 944 | |
| 945 | current_rx_data_length = 0; |
| 946 | } |
src/mess/machine/omti8621.c
| r0 | r14540 | |
| 1 | /* |
| 2 | * omti8621.c - SMS OMTI 8621 disk controller (for Apollo DN3x00) |
| 3 | * |
| 4 | * Created on: August 30, 2010 |
| 5 | * Author: Hans Ostermeyer |
| 6 | * |
| 7 | * Released for general non-commercial use under the MAME license |
| 8 | * Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | * |
| 10 | * see also: |
| 11 | * * http://www.bitsavers.org/pdf/sms/pc/OMTI_AT_Controller_Series_Jan87.pdf |
| 12 | */ |
| 13 | |
| 14 | #define VERBOSE 0 |
| 15 | |
| 16 | static int verbose = VERBOSE; |
| 17 | |
| 18 | #include "machine/omti8621.h" |
| 19 | #include "image.h" |
| 20 | |
| 21 | #define LOG(x) { logerror ("%s: ", cpu_context(state->device)); logerror x; logerror ("\n"); } |
| 22 | #define LOG1(x) { if (verbose > 0) LOG(x)} |
| 23 | #define LOG2(x) { if (verbose > 1) LOG(x)} |
| 24 | #define LOG3(x) { if (verbose > 2) LOG(x)} |
| 25 | |
| 26 | #define DLOG(x) { logerror ("%s: ", cpu_context(disk->device)); logerror x; logerror ("\n"); } |
| 27 | #define DLOG1(x) { if (verbose > 0) DLOG(x)} |
| 28 | #define DLOG2(x) { if (verbose > 1) DLOG(x)} |
| 29 | |
| 30 | #define OMTI_DISK_SECTOR_SIZE 1056 |
| 31 | |
| 32 | #define OMTI_DISK_TYPE_155_MB 0x607 // Micropolis 1355 (170 MB Dtype = 607) |
| 33 | #define OMTI_DISK_TYPE_348_MB 0x604 // Maxtor EXT-4380-E (380 MB Dtype = 604) |
| 34 | #define OMTI_DISK_TYPE_DEFAULT OMTI_DISK_TYPE_348_MB // new disks will have this type (and size) |
| 35 | |
| 36 | #define OMTI_MAX_BLOCK_COUNT 32 |
| 37 | |
| 38 | #define OMTI_MAX_LUN 1 |
| 39 | #define OMTI_DISK0_TAG "omti_disk0" |
| 40 | #define OMTI_DISK1_TAG "omti_disk1" |
| 41 | |
| 42 | #define CDB_SIZE 10 |
| 43 | |
| 44 | /* |
| 45 | * I/O register offsets |
| 46 | */ |
| 47 | |
| 48 | #define OMTI_PORT_DATA_IN 0x00 /* read, 8-bit */ |
| 49 | #define OMTI_PORT_DATA_OUT 0x00 /* write, 8-bit */ |
| 50 | #define OMTI_PORT_STATUS 0x01 /* read, 8-bit */ |
| 51 | #define OMTI_PORT_RESET 0x01 /* write, 8-bit */ |
| 52 | #define OMTI_PORT_CONFIG 0x02 /* read, 8-bit */ |
| 53 | #define OMTI_PORT_SELECT 0x02 /* write, 8-bit */ |
| 54 | #define OMTI_PORT_MASK 0x03 /* write only, 8-bit */ |
| 55 | |
| 56 | // port status |
| 57 | |
| 58 | #define OMTI_STATUS_REQ 0x01 // Request (1 = request transfer of data via data in/out register) |
| 59 | #define OMTI_STATUS_IO 0x02 // In/Out (1 = direction of transfer is from controller to host) |
| 60 | #define OMTI_STATUS_CD 0x04 // Command/Data ( 1 = byte transfered is command or status byte) |
| 61 | #define OMTI_STATUS_BUSY 0x08 // Busy (0 = controller is idle, 1 = controller selected) |
| 62 | #define OMTI_STATUS_DREQ 0x10 // Data Request (0 = no DMA request, 1 = DMA cycle requested) |
| 63 | #define OMTI_STATUS_IREQ 0x20 // Interrupt Request (0 = no interrupt, 1 = command complete) |
| 64 | #define OMTI_STATUS_NU6 0x40 // not used |
| 65 | #define OMTI_STATUS_NU7 0x80 // not used |
| 66 | |
| 67 | #define OMTI_CONFIG_W23 0x01 // jumper W23 |
| 68 | #define OMTI_CONFIG_W22 0x02 // jumper W22 |
| 69 | #define OMTI_CONFIG_W21 0x04 // jumper W21 |
| 70 | #define OMTI_CONFIG_W20 0x08 // jumper W20 |
| 71 | |
| 72 | #define OMTI_MASK_DMAE 0x01 // DMA enable |
| 73 | #define OMTI_MASK_INTE 0x02 // Interrupt enable |
| 74 | |
| 75 | #define OMTI_COMMAND_STATUS_ERROR 0x02 // error bit |
| 76 | #define OMTI_COMMAND_STATUS_LUN 0x20 // drive 0 is 0 |
| 77 | |
| 78 | #define OMTI_SENSE_CODE_NO_ERROR 0x00 |
| 79 | #define OMTI_SENSE_CODE_DRIVE_NOT_READY 0x04 |
| 80 | #define OMTI_SENSE_CODE_ADDRESS_VALID 0x80 |
| 81 | #define OMTI_SENSE_CODE_SECTOR_NOT_FOUND 0x14 |
| 82 | #define OMTI_SENSE_CODE_ECC_ERROR 0x11 |
| 83 | #define OMTI_SENSE_CODE_BAD_TRACK 0x19 |
| 84 | #define OMTI_SENSE_CODE_ALTERNATE_TRACK 0x1C |
| 85 | #define OMTI_SENSE_CODE_INVALID_COMMAND 0x20 |
| 86 | #define OMTI_SENSE_CODE_ILLEGAL_ADDRESS 0x21 |
| 87 | |
| 88 | enum { |
| 89 | OMTI_STATE_RESET, |
| 90 | OMTI_STATE_IDLE, |
| 91 | OMTI_STATE_SELECTION, |
| 92 | OMTI_STATE_COMMAND, |
| 93 | OMTI_STATE_DATA, |
| 94 | OMTI_STATE_STATUS, |
| 95 | }; |
| 96 | |
| 97 | // OMTI commands |
| 98 | |
| 99 | #define OMTI_CMD_TEST_DRIVE_READY 0x00 |
| 100 | #define OMTI_CMD_RECALIBRATE 0x01 |
| 101 | |
| 102 | #define OMTI_CMD_REQUEST_SENSE 0x03 |
| 103 | #define OMTI_CMD_FORMAT_DRIVEUNIT 0x04 |
| 104 | #define OMTI_CMD_READ_VERIFY 0x05 |
| 105 | #define OMTI_CMD_FORMAT_TRACK 0x06 |
| 106 | #define OMTI_CMD_FORMAT_BAD_TRACK 0x07 |
| 107 | #define OMTI_CMD_READ 0x08 |
| 108 | |
| 109 | #define OMTI_CMD_WRITE 0x0a |
| 110 | #define OMTI_CMD_SEEK 0x0b |
| 111 | |
| 112 | #define OMTI_CMD_READ_SECTOR_BUFFER 0x0e |
| 113 | #define OMTI_CMD_WRITE_SECTOR_BUFFER 0x0f |
| 114 | |
| 115 | #define OMTI_CMD_ASSIGN_ALTERNATE_TRACK 0x11 |
| 116 | |
| 117 | #define OMTI_CMD_READ_DATA_TO_BUFFER 0x1e |
| 118 | #define OMTI_CMD_WRITE_DATA_FROM_BUFFER 0x1f |
| 119 | #define OMTI_CMD_COPY 0x20 |
| 120 | |
| 121 | #define OMTI_CMD_READ_ESDI_DEFECT_LIST 0x37 |
| 122 | |
| 123 | #define OMTI_CMD_RAM_DIAGNOSTICS 0xe0 |
| 124 | #define OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC 0xe4 |
| 125 | #define OMTI_CMD_READ_LONG 0xe5 |
| 126 | #define OMTI_CMD_WRITE_LONG 0xe6 |
| 127 | |
| 128 | #define OMTI_CMD_READ_CONFIGURATION 0xec |
| 129 | #define OMTI_CMD_INVALID_COMMAND 0xff |
| 130 | |
| 131 | typedef struct _disk_data disk_data; |
| 132 | struct _disk_data |
| 133 | { |
| 134 | device_t *device; |
| 135 | UINT16 type; |
| 136 | UINT16 cylinders; |
| 137 | UINT16 heads; |
| 138 | UINT16 sectors; |
| 139 | UINT32 sectorbytes; |
| 140 | UINT32 sector_count; |
| 141 | |
| 142 | device_image_interface *image; |
| 143 | |
| 144 | // configuration data |
| 145 | UINT8 config_data[10]; |
| 146 | |
| 147 | // ESDI defect list data |
| 148 | UINT8 esdi_defect_list[256]; |
| 149 | }; |
| 150 | |
| 151 | typedef struct _omti8621_state omti8621_state; |
| 152 | struct _omti8621_state { |
| 153 | device_t *device; |
| 154 | omti8621_set_irq irq_handler; |
| 155 | |
| 156 | disk_data *disk[OMTI_MAX_LUN+1]; |
| 157 | |
| 158 | UINT16 jumper; |
| 159 | |
| 160 | /* stored tc state - state present at pins */ |
| 161 | int tc_state; |
| 162 | |
| 163 | /* stored int state */ |
| 164 | int int_state; |
| 165 | |
| 166 | UINT8 omti_state; |
| 167 | |
| 168 | UINT8 status_port; |
| 169 | UINT8 config_port; |
| 170 | UINT8 mask_port; |
| 171 | |
| 172 | // command descriptor block |
| 173 | UINT8 command_buffer[CDB_SIZE]; |
| 174 | int command_length; |
| 175 | int command_index; |
| 176 | int command_status; |
| 177 | |
| 178 | // data buffer |
| 179 | UINT8 *sector_buffer; |
| 180 | UINT8 *data_buffer; |
| 181 | int data_length; |
| 182 | int data_index; |
| 183 | |
| 184 | // sense data |
| 185 | UINT8 sense_data[4]; |
| 186 | |
| 187 | // these are used only to satisfy dex |
| 188 | UINT32 diskaddr_ecc_error; |
| 189 | UINT32 diskaddr_format_bad_track; |
| 190 | UINT8 alternate_track_buffer[4]; |
| 191 | UINT32 alternate_track_address[2]; |
| 192 | }; |
| 193 | |
| 194 | /*************************************************************************** |
| 195 | get_safe_token - makes sure that the passed |
| 196 | in device is, in fact, a 8621 controller |
| 197 | ***************************************************************************/ |
| 198 | |
| 199 | INLINE omti8621_state *get_safe_token(device_t *device) { |
| 200 | assert(device != NULL); |
| 201 | assert(device->type() == OMTI8621); |
| 202 | return (omti8621_state *) downcast<legacy_device_base *>(device)->token(); |
| 203 | } |
| 204 | |
| 205 | /*************************************************************************** |
| 206 | cpu_context - return a string describing the current CPU context |
| 207 | ***************************************************************************/ |
| 208 | |
| 209 | static const char *cpu_context(const device_t *device) { |
| 210 | static char statebuf[64]; /* string buffer containing state description */ |
| 211 | |
| 212 | device_t *cpu = device->machine().firstcpu; |
| 213 | |
| 214 | /* if we have an executing CPU, output data */ |
| 215 | if (cpu != NULL) { |
| 216 | osd_ticks_t t = osd_ticks(); |
| 217 | int s = t / osd_ticks_per_second(); |
| 218 | int ms = (t % osd_ticks_per_second()) / 1000; |
| 219 | |
| 220 | sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(), |
| 221 | cpu_get_previouspc(cpu), device->tag()); |
| 222 | } else { |
| 223 | strcpy(statebuf, "(no context)"); |
| 224 | } |
| 225 | return statebuf; |
| 226 | } |
| 227 | |
| 228 | /*------------------------------------------------- |
| 229 | set_interrupt - update the IRQ state |
| 230 | -------------------------------------------------*/ |
| 231 | |
| 232 | static void set_interrupt(const omti8621_state *state, enum line_state line_state) { |
| 233 | if (state->irq_handler != NULL) { |
| 234 | LOG2(("set_interrupt: status_port=%x", state->status_port)); |
| 235 | (*state->irq_handler)(&state->device->machine(), line_state); |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | static TIMER_CALLBACK(set_interrupt_caba ) { |
| 240 | const omti8621_state *state =(omti8621_state *)ptr; |
| 241 | set_interrupt(state, ASSERT_LINE); |
| 242 | } |
| 243 | |
| 244 | /*************************************************************************** |
| 245 | clear_sense_data - clear the sense data |
| 246 | ***************************************************************************/ |
| 247 | |
| 248 | static void clear_sense_data(omti8621_state *state) { |
| 249 | LOG2(("clear_sense_data")); |
| 250 | memset(state->sense_data, 0, sizeof(state->sense_data)); |
| 251 | } |
| 252 | |
| 253 | /*************************************************************************** |
| 254 | set_sense_data - set the sense data from code and command descriptor block |
| 255 | ***************************************************************************/ |
| 256 | |
| 257 | static void set_sense_data(omti8621_state *state, UINT8 code, const UINT8 * cdb) { |
| 258 | LOG2(("set_sense_data code=%x", code)); |
| 259 | state->sense_data[0]=code; |
| 260 | state->sense_data[1]=cdb[1]; |
| 261 | state->sense_data[2]=cdb[2]; |
| 262 | state->sense_data[3]=cdb[3]; |
| 263 | } |
| 264 | |
| 265 | /*************************************************************************** |
| 266 | set_configuration_data - set the configuration data for drive lun |
| 267 | ***************************************************************************/ |
| 268 | |
| 269 | static void set_configuration_data(omti8621_state *state, UINT8 lun) { |
| 270 | LOG2(("set_configuration_data lun=%x", lun)); |
| 271 | |
| 272 | // initialize the configuration data |
| 273 | disk_data *disk = state->disk[lun]; |
| 274 | |
| 275 | disk->config_data[0] = (disk->cylinders - 1) >> 8; // Number of Cylinders (MSB) |
| 276 | disk->config_data[1] = (disk->cylinders - 1) & 0xff; // Number of Cylinders (LSB) (-1) |
| 277 | disk->config_data[2] = disk->heads - 1; // Number of Heads (-1) |
| 278 | disk->config_data[3] = disk->sectors - 1; // Number of Sectors (-1) |
| 279 | disk->config_data[4] = 0x02; // Drive Configuration Word (MSB) |
| 280 | disk->config_data[5] = 0x44; // Drive Configuration Word (LSB) |
| 281 | disk->config_data[6] = 0x00; // ISG AFTER INDEX |
| 282 | disk->config_data[7] = 0x00; // PLO SYN Field (ID) |
| 283 | disk->config_data[8] = 0x00; // PLO SYN Field (DATA) |
| 284 | disk->config_data[9] = 0x00; // ISG AFTER SECTOR |
| 285 | } |
| 286 | |
| 287 | /*************************************************************************** |
| 288 | omti_reset - reset the OMTI controller |
| 289 | ***************************************************************************/ |
| 290 | |
| 291 | static void omti_reset(omti8621_state *state) { |
| 292 | LOG2(("omti_reset")); |
| 293 | |
| 294 | // should go from reset to idle after 100 us |
| 295 | // state->omti_state = OMTI_STATE_RESET; |
| 296 | state->omti_state = OMTI_STATE_IDLE; |
| 297 | |
| 298 | state->status_port = OMTI_STATUS_NU6 | OMTI_STATUS_NU7; |
| 299 | state->config_port = ~state->jumper; |
| 300 | state->mask_port = 0; |
| 301 | |
| 302 | // default the sector data buffer with model and status information |
| 303 | // (i.e. set sector data buffer for cmd=0x0e READ SECTOR BUFFER) |
| 304 | |
| 305 | memset(state->sector_buffer, 0, OMTI_DISK_SECTOR_SIZE); |
| 306 | memcpy(state->sector_buffer, "8621VB.4060487xx", 0x10); |
| 307 | state->sector_buffer[0x10] = 0; // ROM Checksum error |
| 308 | state->sector_buffer[0x11] = 0; // Processor Register error |
| 309 | state->sector_buffer[0x12] = 0; // Buffer RAM error |
| 310 | state->sector_buffer[0x13] = 0; // Sequencer Register File error |
| 311 | state->sector_buffer[0x14] = 0xc0; // 32K buffer size |
| 312 | // TODO: add missing Default values for LUN 0, 1 and 3 |
| 313 | |
| 314 | state->command_length = 0; |
| 315 | state->command_index = 0; |
| 316 | state->command_status = 0; |
| 317 | |
| 318 | state->data_index = 0; |
| 319 | state->data_length = 0; |
| 320 | |
| 321 | clear_sense_data(state) ; |
| 322 | |
| 323 | state->diskaddr_ecc_error = 0; |
| 324 | state->diskaddr_format_bad_track = 0; |
| 325 | state->alternate_track_address[0] = 0; |
| 326 | state->alternate_track_address[1] = 0; |
| 327 | } |
| 328 | |
| 329 | /*************************************************************************** |
| 330 | get_lun - get logical unit number from a command descriptor block (in bit 5) |
| 331 | ***************************************************************************/ |
| 332 | |
| 333 | static UINT8 get_lun(const UINT8 * cdb) |
| 334 | { |
| 335 | return (cdb[1] & 0x20) >> 5; |
| 336 | } |
| 337 | |
| 338 | /*************************************************************************** |
| 339 | check_disk_address - check disk address, set sense data and return true for no error |
| 340 | ***************************************************************************/ |
| 341 | |
| 342 | static UINT8 check_disk_address(omti8621_state *state, const UINT8 *cdb) |
| 343 | { |
| 344 | UINT8 sense_code = OMTI_SENSE_CODE_NO_ERROR; |
| 345 | UINT8 lun = get_lun(cdb); |
| 346 | UINT16 head = cdb[1] & 0x1f; |
| 347 | UINT16 sector = cdb[2] & 0x3f; |
| 348 | UINT32 cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3); |
| 349 | UINT8 block_count = cdb[4]; |
| 350 | disk_data *disk = state->disk[lun]; |
| 351 | |
| 352 | UINT32 disk_track = cylinder * disk->heads + head; |
| 353 | UINT32 disk_addr = (disk_track * disk->sectors) + sector; |
| 354 | |
| 355 | if (block_count > OMTI_MAX_BLOCK_COUNT) { |
| 356 | LOG(("########### check_disk_address: unexpected block count %x", block_count)); |
| 357 | sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID; |
| 358 | } |
| 359 | |
| 360 | if (lun > OMTI_MAX_LUN) { |
| 361 | sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY; |
| 362 | } else if (!disk->image->exists()) { |
| 363 | sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY; |
| 364 | } else if (sector >= OMTI_MAX_BLOCK_COUNT) { |
| 365 | sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID; |
| 366 | } else if (head >= disk->heads) { |
| 367 | sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID; |
| 368 | } else if (cylinder >= disk->cylinders) { |
| 369 | sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID; |
| 370 | } else if ( disk_track == state->diskaddr_format_bad_track && disk_track != 0) { |
| 371 | sense_code = OMTI_SENSE_CODE_BAD_TRACK; |
| 372 | } else if (disk_addr == state->diskaddr_ecc_error && disk_addr != 0) { |
| 373 | sense_code = OMTI_SENSE_CODE_ECC_ERROR; |
| 374 | } else if (disk_track == state->alternate_track_address[1] && disk_track != 0) { |
| 375 | sense_code = OMTI_SENSE_CODE_ALTERNATE_TRACK; |
| 376 | } |
| 377 | |
| 378 | if (sense_code == OMTI_SENSE_CODE_NO_ERROR) { |
| 379 | clear_sense_data(state); |
| 380 | } else { |
| 381 | state->command_status |= OMTI_COMMAND_STATUS_ERROR; |
| 382 | set_sense_data(state, sense_code, cdb); |
| 383 | } |
| 384 | return sense_code == OMTI_SENSE_CODE_NO_ERROR; |
| 385 | } |
| 386 | |
| 387 | /*************************************************************************** |
| 388 | get_disk_track - get disk track from a command descriptor block |
| 389 | ***************************************************************************/ |
| 390 | |
| 391 | static UINT32 get_disk_track(const omti8621_state *state, const UINT8 * cdb) { |
| 392 | UINT8 lun = get_lun(cdb); |
| 393 | UINT16 head = cdb[1] & 0x1f; |
| 394 | UINT32 cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3); |
| 395 | return cylinder * state->disk[lun]->heads + head; |
| 396 | } |
| 397 | |
| 398 | /*************************************************************************** |
| 399 | get_disk_address - get disk address from a command descriptor block |
| 400 | ***************************************************************************/ |
| 401 | |
| 402 | static UINT32 get_disk_address(const omti8621_state *state, const UINT8 * cdb) { |
| 403 | UINT8 lun = get_lun(cdb); |
| 404 | UINT16 sector = cdb[2] & 0x3f; |
| 405 | return get_disk_track(state, cdb) * state->disk[lun]->sectors + sector; |
| 406 | } |
| 407 | |
| 408 | /*************************************************************************** |
| 409 | set_data_transfer - setup for data transfer from/to data |
| 410 | ***************************************************************************/ |
| 411 | |
| 412 | static void set_data_transfer(omti8621_state *state, UINT8 *data, UINT16 length) { |
| 413 | // set controller for read data transfer |
| 414 | state->omti_state = OMTI_STATE_DATA; |
| 415 | state->status_port |= OMTI_STATUS_REQ | OMTI_STATUS_IO | OMTI_STATUS_BUSY; |
| 416 | state->status_port &= ~OMTI_STATUS_CD; |
| 417 | |
| 418 | state->data_buffer = data; |
| 419 | state->data_length = length; |
| 420 | state->data_index = 0; |
| 421 | } |
| 422 | |
| 423 | /*************************************************************************** |
| 424 | read_sectors_from_disk - read sectors starting at diskaddr into sector_buffer |
| 425 | ***************************************************************************/ |
| 426 | |
| 427 | static void read_sectors_from_disk(omti8621_state *state, INT32 diskaddr, |
| 428 | UINT8 count, UINT8 lun) { |
| 429 | |
| 430 | UINT8 *data_buffer = state->sector_buffer; |
| 431 | device_image_interface *image = state->disk[lun]->image; |
| 432 | |
| 433 | while (count-- > 0) { |
| 434 | LOG2(("read_sectors_from_disk lun=%d diskaddr=%x", lun, diskaddr)); |
| 435 | |
| 436 | image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); |
| 437 | image->fread( data_buffer, OMTI_DISK_SECTOR_SIZE); |
| 438 | |
| 439 | diskaddr++; |
| 440 | data_buffer += OMTI_DISK_SECTOR_SIZE; |
| 441 | } |
| 442 | } |
| 443 | |
| 444 | /*************************************************************************** |
| 445 | write_sectors_to_disk - write sectors starting at diskaddr from sector_buffer |
| 446 | ***************************************************************************/ |
| 447 | |
| 448 | static void write_sectors_to_disk(omti8621_state *state, INT32 diskaddr, |
| 449 | UINT8 count, UINT8 lun) { |
| 450 | |
| 451 | UINT8 *data_buffer = state->sector_buffer; |
| 452 | device_image_interface *image = state->disk[lun]->image; |
| 453 | |
| 454 | while (count-- > 0) { |
| 455 | LOG2(("write_sectors_to_disk lun=%d diskaddr=%x", lun, diskaddr)); |
| 456 | |
| 457 | image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); |
| 458 | image->fwrite( data_buffer, OMTI_DISK_SECTOR_SIZE); |
| 459 | |
| 460 | if (diskaddr == state->diskaddr_ecc_error) { |
| 461 | // reset previous ECC error |
| 462 | state->diskaddr_ecc_error = 0; |
| 463 | } |
| 464 | |
| 465 | diskaddr++; |
| 466 | data_buffer += OMTI_DISK_SECTOR_SIZE; |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | /*************************************************************************** |
| 471 | copy_sectors - copy sectors |
| 472 | ***************************************************************************/ |
| 473 | |
| 474 | static void copy_sectors(omti8621_state *state, INT32 dst_addr, INT32 src_addr, |
| 475 | UINT8 count, UINT8 lun) { |
| 476 | device_image_interface *image = state->disk[lun]->image; |
| 477 | |
| 478 | LOG2(("copy_sectors lun=%d src_addr=%x dst_addr=%x count=%x", lun, src_addr, dst_addr, count)); |
| 479 | |
| 480 | while (count-- > 0) { |
| 481 | image->fseek( src_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); |
| 482 | image->fread( state->sector_buffer, OMTI_DISK_SECTOR_SIZE); |
| 483 | |
| 484 | image->fseek( dst_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); |
| 485 | image->fwrite( state->sector_buffer, OMTI_DISK_SECTOR_SIZE); |
| 486 | |
| 487 | if (dst_addr == state->diskaddr_ecc_error) { |
| 488 | // reset previous ECC error |
| 489 | state->diskaddr_ecc_error = 0; |
| 490 | } |
| 491 | |
| 492 | src_addr++; |
| 493 | dst_addr++; |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | /*************************************************************************** |
| 498 | format track - format a track |
| 499 | ***************************************************************************/ |
| 500 | |
| 501 | static void format_track(omti8621_state *state, const UINT8 * cdb) { |
| 502 | UINT8 lun = get_lun(cdb); |
| 503 | UINT32 disk_addr = get_disk_address(state, cdb); |
| 504 | UINT32 disk_track = get_disk_track(state, cdb); |
| 505 | |
| 506 | if (state->diskaddr_ecc_error == disk_addr) { |
| 507 | // reset previous ECC error |
| 508 | state->diskaddr_ecc_error = 0; |
| 509 | } |
| 510 | |
| 511 | if (state->diskaddr_format_bad_track == disk_track) { |
| 512 | // reset previous bad track formatting |
| 513 | state->diskaddr_format_bad_track = 0; |
| 514 | } |
| 515 | |
| 516 | if (state->alternate_track_address[0] == disk_track) { |
| 517 | // reset source of alternate track address |
| 518 | state->alternate_track_address[0] = 0; |
| 519 | } |
| 520 | |
| 521 | if (state->alternate_track_address[1] == disk_track) { |
| 522 | // reset alternate track address |
| 523 | state->alternate_track_address[1] = 0; |
| 524 | } |
| 525 | |
| 526 | if (check_disk_address(state, cdb) ) { |
| 527 | if ((cdb[5] & 0x40) == 0) { |
| 528 | memset(state->sector_buffer, 0x6C, OMTI_DISK_SECTOR_SIZE * state->disk[lun]->sectors); |
| 529 | } |
| 530 | write_sectors_to_disk(state, disk_addr, state->disk[lun]->sectors, lun); |
| 531 | } |
| 532 | |
| 533 | } |
| 534 | |
| 535 | /*************************************************************************** |
| 536 | set_esdi_defect_list - setup the (emty) ESDI defect list |
| 537 | ***************************************************************************/ |
| 538 | |
| 539 | static void set_esdi_defect_list(omti8621_state *state, UINT8 lun, UINT8 head) |
| 540 | { |
| 541 | disk_data *disk = state->disk[lun]; |
| 542 | |
| 543 | memset(disk->esdi_defect_list, 0, sizeof(disk->esdi_defect_list)); |
| 544 | disk->esdi_defect_list[0] = 1; // month |
| 545 | disk->esdi_defect_list[1] = 1; // day |
| 546 | disk->esdi_defect_list[2] = 90; // year |
| 547 | disk->esdi_defect_list[3] = head; |
| 548 | memset(disk->esdi_defect_list+6, 0xff, 5); // end of defect list |
| 549 | } |
| 550 | |
| 551 | /*************************************************************************** |
| 552 | log_command - log command from a command descriptor block |
| 553 | ***************************************************************************/ |
| 554 | |
| 555 | static void log_command(const omti8621_state *state, |
| 556 | const UINT8 cdb[], const UINT16 cdb_length) { |
| 557 | if (verbose > 0) { |
| 558 | int i; |
| 559 | logerror("%s: OMTI command ", cpu_context(state->device)); |
| 560 | switch (cdb[0]) { |
| 561 | case OMTI_CMD_TEST_DRIVE_READY: // 0x00 |
| 562 | logerror("Test Drive Ready"); |
| 563 | break; |
| 564 | case OMTI_CMD_RECALIBRATE: // 0x01 |
| 565 | logerror("Recalibrate"); |
| 566 | break; |
| 567 | case OMTI_CMD_REQUEST_SENSE: // 0x03 |
| 568 | logerror("Request Sense"); |
| 569 | break; |
| 570 | case OMTI_CMD_READ_VERIFY: // 0x05 |
| 571 | logerror("Read Verify"); |
| 572 | break; |
| 573 | case OMTI_CMD_FORMAT_TRACK: // 0x06 |
| 574 | logerror("Format Track"); |
| 575 | break; |
| 576 | case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07 |
| 577 | logerror("Format Bad Track"); |
| 578 | break; |
| 579 | case OMTI_CMD_READ: // 0x08 |
| 580 | logerror("Read"); |
| 581 | break; |
| 582 | case OMTI_CMD_WRITE: // 0x0A |
| 583 | logerror("Write"); |
| 584 | break; |
| 585 | case OMTI_CMD_SEEK: // 0x0B |
| 586 | logerror("Seek"); |
| 587 | break; |
| 588 | case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E |
| 589 | logerror("Read Sector Buffer"); |
| 590 | break; |
| 591 | case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F |
| 592 | logerror("Write Sector Buffer"); |
| 593 | break; |
| 594 | case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11 |
| 595 | logerror("Assign Alternate Track"); |
| 596 | break; |
| 597 | case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E |
| 598 | logerror("Read Data to Buffer"); |
| 599 | break; |
| 600 | case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F |
| 601 | logerror("Write Data from Buffer"); |
| 602 | break; |
| 603 | case OMTI_CMD_COPY: // 0x20 |
| 604 | logerror("Copy"); |
| 605 | break; |
| 606 | case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37 |
| 607 | logerror("Read ESDI Defect List"); |
| 608 | break; |
| 609 | case OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0 |
| 610 | logerror("RAM. Diagnostic"); |
| 611 | break; |
| 612 | case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4 |
| 613 | logerror("Controller Int. Diagnostic"); |
| 614 | break; |
| 615 | case OMTI_CMD_READ_LONG: // 0xE5 |
| 616 | logerror("Read Long"); |
| 617 | break; |
| 618 | case OMTI_CMD_WRITE_LONG: // 0xE6 |
| 619 | logerror("Write Long"); |
| 620 | break; |
| 621 | case OMTI_CMD_READ_CONFIGURATION: // 0xEC |
| 622 | logerror("Read Configuration"); |
| 623 | break; |
| 624 | case OMTI_CMD_INVALID_COMMAND: // 0xFF |
| 625 | logerror("Invalid Command"); |
| 626 | break; |
| 627 | default: |
| 628 | logerror("!!! Unexpected Command !!!"); |
| 629 | } |
| 630 | // logerror(" (%02x, length=%02x)", cdb[0], cdb_length); |
| 631 | for (i = 0; i < cdb_length; i++) { |
| 632 | logerror(" %02x", cdb[i]); |
| 633 | } |
| 634 | |
| 635 | switch (cdb[0]) { |
| 636 | case OMTI_CMD_READ_VERIFY: // 0x05 |
| 637 | case OMTI_CMD_READ: // 0x08 |
| 638 | case OMTI_CMD_WRITE: // 0x0a |
| 639 | case OMTI_CMD_SEEK: // 0x0b |
| 640 | case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E |
| 641 | case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F |
| 642 | case OMTI_CMD_COPY: // 0x20 |
| 643 | logerror(" (diskaddr=%x count=%x)", get_disk_address(state, cdb), cdb[4]); |
| 644 | break; |
| 645 | } |
| 646 | logerror("\n"); |
| 647 | } |
| 648 | } |
| 649 | |
| 650 | /*************************************************************************** |
| 651 | log_data - log data in the common data buffer |
| 652 | ***************************************************************************/ |
| 653 | |
| 654 | static void log_data(const omti8621_state *state) { |
| 655 | if (verbose > 0) { |
| 656 | int i; |
| 657 | logerror("%s: OMTI data (length=%02x)", cpu_context(state->device), |
| 658 | state->data_length); |
| 659 | for (i = 0; i < state->data_length && i < OMTI_DISK_SECTOR_SIZE; i++) { |
| 660 | logerror(" %02x", state->data_buffer[i]); |
| 661 | } |
| 662 | |
| 663 | if (i < state->data_length) { |
| 664 | logerror(" ..."); |
| 665 | } |
| 666 | logerror("\n"); |
| 667 | } |
| 668 | } |
| 669 | |
| 670 | /*************************************************************************** |
| 671 | do_command |
| 672 | ***************************************************************************/ |
| 673 | |
| 674 | static void do_command(omti8621_state *state, |
| 675 | const UINT8 cdb[], const UINT16 cdb_length) { |
| 676 | |
| 677 | UINT8 lun = get_lun(cdb); |
| 678 | disk_data *disk = state->disk[lun]; |
| 679 | int command_duration = 0; // ms |
| 680 | |
| 681 | log_command( state, cdb, cdb_length); |
| 682 | |
| 683 | // default to read status and status is successful completion |
| 684 | state->omti_state = OMTI_STATE_STATUS; |
| 685 | state->status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD; |
| 686 | state->command_status = lun ? OMTI_COMMAND_STATUS_LUN : 0; |
| 687 | |
| 688 | if (state->mask_port & OMTI_MASK_INTE) { |
| 689 | set_interrupt(state, CLEAR_LINE); |
| 690 | } |
| 691 | |
| 692 | if (!disk->image->exists()) { |
| 693 | state->command_status |= OMTI_COMMAND_STATUS_ERROR; // no such drive |
| 694 | } |
| 695 | |
| 696 | switch (cdb[0]) { |
| 697 | case OMTI_CMD_TEST_DRIVE_READY: // 0x00 |
| 698 | if (!disk->image->exists()) |
| 699 | { |
| 700 | set_sense_data(state, OMTI_SENSE_CODE_DRIVE_NOT_READY, cdb); |
| 701 | } |
| 702 | break; |
| 703 | |
| 704 | case OMTI_CMD_RECALIBRATE: // 0x01 |
| 705 | break; |
| 706 | |
| 707 | case OMTI_CMD_REQUEST_SENSE: // 0x03 |
| 708 | set_data_transfer(state, state->sense_data, sizeof(state->sense_data)); |
| 709 | break; |
| 710 | |
| 711 | case OMTI_CMD_READ_VERIFY: // 0x05 |
| 712 | check_disk_address(state, cdb); |
| 713 | break; |
| 714 | |
| 715 | case OMTI_CMD_FORMAT_TRACK: // 0x06 |
| 716 | format_track(state, cdb); |
| 717 | break; |
| 718 | |
| 719 | case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07 |
| 720 | state->diskaddr_format_bad_track = get_disk_address(state, cdb); |
| 721 | break; |
| 722 | |
| 723 | case OMTI_CMD_READ: // 0x08 |
| 724 | if (check_disk_address(state, cdb)) { |
| 725 | // read data from controller |
| 726 | read_sectors_from_disk(state, get_disk_address(state, cdb), cdb[4], lun); |
| 727 | set_data_transfer(state, state->sector_buffer, OMTI_DISK_SECTOR_SIZE*cdb[4]); |
| 728 | } |
| 729 | break; |
| 730 | |
| 731 | case OMTI_CMD_WRITE: // 0x0A |
| 732 | log_data(state); |
| 733 | if (check_disk_address(state, cdb)) { |
| 734 | write_sectors_to_disk(state, get_disk_address(state, cdb), cdb[4], lun); |
| 735 | } |
| 736 | break; |
| 737 | |
| 738 | case OMTI_CMD_SEEK: // 0x0B |
| 739 | check_disk_address(state, cdb); |
| 740 | break; |
| 741 | |
| 742 | case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E |
| 743 | set_data_transfer(state, state->sector_buffer, OMTI_DISK_SECTOR_SIZE*cdb[4]); |
| 744 | break; |
| 745 | |
| 746 | case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F |
| 747 | log_data(state); |
| 748 | break; |
| 749 | |
| 750 | case OMTI_CMD_COPY: // 0x20 |
| 751 | if (check_disk_address(state, cdb) && check_disk_address(state, cdb+4)) { |
| 752 | // copy sectors |
| 753 | copy_sectors (state, get_disk_address(state, cdb+4), get_disk_address(state, cdb), cdb[4], lun); |
| 754 | } |
| 755 | break; |
| 756 | |
| 757 | case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37 |
| 758 | set_esdi_defect_list(state, get_lun(cdb), cdb[1] & 0x1f); |
| 759 | set_data_transfer(state, disk->esdi_defect_list, sizeof(disk->esdi_defect_list)); |
| 760 | break; |
| 761 | |
| 762 | case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11 |
| 763 | log_data(state); |
| 764 | state->alternate_track_address[0] = get_disk_track(state, cdb); |
| 765 | state->alternate_track_address[1] = get_disk_track(state, state->alternate_track_buffer-1);; |
| 766 | break; |
| 767 | |
| 768 | case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E |
| 769 | if (check_disk_address(state, cdb)) { |
| 770 | // read data from controller |
| 771 | read_sectors_from_disk (state, get_disk_address(state, cdb), cdb[4], lun); |
| 772 | // Domain/OS doesn't expect zero access time |
| 773 | command_duration += 1; // 1 ms is enough, average time would be 30 ms) |
| 774 | } |
| 775 | break; |
| 776 | |
| 777 | case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F |
| 778 | log_data(state); |
| 779 | if (check_disk_address(state, cdb)) { |
| 780 | write_sectors_to_disk(state, get_disk_address(state, cdb), cdb[4], lun); |
| 781 | } |
| 782 | break; |
| 783 | |
| 784 | case OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0 |
| 785 | break; |
| 786 | |
| 787 | case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4 |
| 788 | break; |
| 789 | |
| 790 | case OMTI_CMD_READ_LONG: // 0xE5 |
| 791 | if (check_disk_address(state, cdb)) { |
| 792 | // read data from controller |
| 793 | read_sectors_from_disk(state, get_disk_address(state, cdb), cdb[4], lun); |
| 794 | set_data_transfer(state, state->sector_buffer, OMTI_DISK_SECTOR_SIZE+6); |
| 795 | } |
| 796 | break; |
| 797 | |
| 798 | case OMTI_CMD_WRITE_LONG: // 0xE6 |
| 799 | log_data(state); |
| 800 | if (check_disk_address(state, cdb)) { |
| 801 | UINT32 diskaddr = get_disk_address(state, cdb); |
| 802 | write_sectors_to_disk(state, diskaddr, cdb[4], lun); |
| 803 | // this will spoil the ECC code |
| 804 | state->diskaddr_ecc_error = diskaddr; |
| 805 | } |
| 806 | break; |
| 807 | |
| 808 | case OMTI_CMD_READ_CONFIGURATION: // 0xEC |
| 809 | set_configuration_data(state, get_lun(cdb)); |
| 810 | set_data_transfer(state, disk->config_data, sizeof(disk->config_data)); |
| 811 | break; |
| 812 | |
| 813 | case OMTI_CMD_INVALID_COMMAND: // 0xFF |
| 814 | set_sense_data(state, OMTI_SENSE_CODE_INVALID_COMMAND, cdb); |
| 815 | state->command_status |= OMTI_COMMAND_STATUS_ERROR; |
| 816 | break; |
| 817 | |
| 818 | default: |
| 819 | LOG(("do_command: UNEXPECTED command %02x",cdb[0])); |
| 820 | set_sense_data(state, OMTI_SENSE_CODE_INVALID_COMMAND, cdb); |
| 821 | state->command_status |= OMTI_COMMAND_STATUS_ERROR; |
| 822 | break; |
| 823 | } |
| 824 | |
| 825 | if (state->mask_port & OMTI_MASK_INTE) { |
| 826 | // if (state->omti_state != OMTI_STATE_STATUS) { |
| 827 | // LOG(("do_command: UNEXPECTED omti_state %02x",state->omti_state)); |
| 828 | // } |
| 829 | state->status_port |= OMTI_STATUS_IREQ; |
| 830 | if (command_duration == 0) { |
| 831 | set_interrupt(state, ASSERT_LINE); |
| 832 | } else { |
| 833 | // FIXME: should delay state->omti_state and state->status_port as well |
| 834 | state->device->machine().scheduler().timer_set(attotime::from_msec(command_duration), FUNC(set_interrupt_caba), 0, state); |
| 835 | } |
| 836 | } |
| 837 | } |
| 838 | |
| 839 | /*************************************************************************** |
| 840 | get_command_length |
| 841 | ***************************************************************************/ |
| 842 | |
| 843 | static UINT8 get_command_length(UINT8 command_byte) { |
| 844 | return command_byte == OMTI_CMD_COPY ? 10 : 6; |
| 845 | } |
| 846 | |
| 847 | /*************************************************************************** |
| 848 | get_data |
| 849 | ***************************************************************************/ |
| 850 | |
| 851 | static UINT16 get_data(omti8621_state *state) { |
| 852 | UINT16 data = 0xff; |
| 853 | if (state->data_index < state->data_length) { |
| 854 | data = state->data_buffer[state->data_index++] << 8; |
| 855 | data |= state->data_buffer[state->data_index++]; |
| 856 | if (state->data_index >= state->data_length) { |
| 857 | state->omti_state = OMTI_STATE_STATUS; |
| 858 | state->status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD; |
| 859 | log_data(state); |
| 860 | } |
| 861 | } else { |
| 862 | LOG(("UNEXPECTED reading OMTI 8621 data (buffer length exceeded)")); |
| 863 | } |
| 864 | return data; |
| 865 | } |
| 866 | |
| 867 | /*************************************************************************** |
| 868 | set_data |
| 869 | ***************************************************************************/ |
| 870 | |
| 871 | static void set_data(omti8621_state *state, UINT16 data) { |
| 872 | if (state->data_index < state->data_length) { |
| 873 | state->data_buffer[state->data_index++] = data >> 8; |
| 874 | state->data_buffer[state->data_index++] = data & 0xff; |
| 875 | if (state->data_index >= state->data_length) { |
| 876 | do_command(state, state->command_buffer, state->command_index); |
| 877 | } |
| 878 | } else { |
| 879 | LOG(("UNEXPECTED writing OMTI 8621 data (buffer length exceeded)")); |
| 880 | } |
| 881 | } |
| 882 | |
| 883 | /*************************************************************************** |
| 884 | DN3500 Disk Controller-AT Register at 0x4D000 |
| 885 | ***************************************************************************/ |
| 886 | |
| 887 | static WRITE8_DEVICE_HANDLER( omti8621_w8 ) { |
| 888 | omti8621_state *state = get_safe_token(device); |
| 889 | |
| 890 | switch (offset) { |
| 891 | case OMTI_PORT_DATA_OUT: // 0x00 |
| 892 | switch (state->omti_state) { |
| 893 | case OMTI_STATE_COMMAND: |
| 894 | LOG2(("writing OMTI 8621 Command Register at offset %02x = %02x", offset, data)); |
| 895 | if (state->command_index == 0) { |
| 896 | state->command_length = get_command_length(data); |
| 897 | } |
| 898 | |
| 899 | if (state->command_index < state->command_length) { |
| 900 | state->command_buffer[state->command_index++] = data; |
| 901 | } else { |
| 902 | LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (command length exceeded)", offset, data)); |
| 903 | } |
| 904 | |
| 905 | if (state->command_index == state->command_length) { |
| 906 | switch (state->command_buffer[0]) { |
| 907 | case OMTI_CMD_WRITE: // 0x0A |
| 908 | // TODO: check diskaddr |
| 909 | // Fall through |
| 910 | case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F |
| 911 | set_data_transfer(state, state->sector_buffer, |
| 912 | OMTI_DISK_SECTOR_SIZE * state->command_buffer[4]); |
| 913 | state->status_port &= ~OMTI_STATUS_IO; |
| 914 | break; |
| 915 | |
| 916 | case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11 |
| 917 | set_data_transfer(state, state->alternate_track_buffer, sizeof(state->alternate_track_buffer)); |
| 918 | state->status_port &= ~OMTI_STATUS_IO; |
| 919 | break; |
| 920 | |
| 921 | case OMTI_CMD_WRITE_LONG: // 0xE6 |
| 922 | // TODO: check diskaddr |
| 923 | set_data_transfer(state, state->sector_buffer, |
| 924 | (OMTI_DISK_SECTOR_SIZE +6) * state->command_buffer[4]); |
| 925 | state->status_port &= ~OMTI_STATUS_IO; |
| 926 | break; |
| 927 | |
| 928 | default: |
| 929 | do_command(state, state->command_buffer, state->command_index); |
| 930 | break; |
| 931 | } |
| 932 | } |
| 933 | break; |
| 934 | |
| 935 | case OMTI_STATE_DATA: |
| 936 | LOG(("UNEXPECTED: writing OMTI 8621 Data Register at offset %02x = %02x", offset, data)); |
| 937 | break; |
| 938 | |
| 939 | default: |
| 940 | LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state)); |
| 941 | break; |
| 942 | } |
| 943 | break; |
| 944 | |
| 945 | case OMTI_PORT_RESET: // 0x01 |
| 946 | LOG2(("writing OMTI 8621 Reset Register at offset %02x = %02x", offset, data)); |
| 947 | omti_reset(state); |
| 948 | break; |
| 949 | |
| 950 | case OMTI_PORT_SELECT: // 0x02 |
| 951 | LOG2(("writing OMTI 8621 Select Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state)); |
| 952 | state->omti_state = OMTI_STATE_COMMAND; |
| 953 | |
| 954 | state->status_port |= OMTI_STATUS_BUSY | OMTI_STATUS_REQ | OMTI_STATUS_CD; |
| 955 | state->status_port &= ~OMTI_STATUS_IO; |
| 956 | |
| 957 | state->command_status = 0; |
| 958 | state->command_index = 0; |
| 959 | break; |
| 960 | |
| 961 | case OMTI_PORT_MASK: // 0x03 |
| 962 | LOG2(("writing OMTI 8621 Mask Register at offset %02x = %02x", offset, data)); |
| 963 | state->mask_port = data; |
| 964 | |
| 965 | if ((data & OMTI_MASK_INTE) == 0) { |
| 966 | state->status_port &= ~OMTI_STATUS_IREQ; |
| 967 | set_interrupt(state, CLEAR_LINE); |
| 968 | } |
| 969 | |
| 970 | if ((data & OMTI_MASK_DMAE) == 0) { |
| 971 | state->status_port &= ~OMTI_STATUS_DREQ; |
| 972 | } |
| 973 | break; |
| 974 | |
| 975 | default: |
| 976 | LOG(("UNEXPECTED writing OMTI 8621 Register at offset %02x = %02x", offset, data)); |
| 977 | break; |
| 978 | } |
| 979 | } |
| 980 | |
| 981 | static READ8_DEVICE_HANDLER( omti8621_r8 ) { |
| 982 | omti8621_state *state = get_safe_token(device); |
| 983 | UINT8 data = 0xff; |
| 984 | |
| 985 | static UINT8 last_data = 0xff; |
| 986 | |
| 987 | switch (offset) { |
| 988 | case OMTI_PORT_DATA_IN: // 0x00 |
| 989 | if (state->status_port && OMTI_STATUS_CD) { |
| 990 | data = state->command_status; |
| 991 | switch (state->omti_state) { |
| 992 | case OMTI_STATE_COMMAND: |
| 993 | LOG2(("reading OMTI 8621 Data Status Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state)); |
| 994 | break; |
| 995 | case OMTI_STATE_STATUS: |
| 996 | state->omti_state = OMTI_STATE_IDLE; |
| 997 | state->status_port &= ~(OMTI_STATUS_BUSY | OMTI_STATUS_CD | OMTI_STATUS_IO | OMTI_STATUS_REQ); |
| 998 | LOG2(("reading OMTI 8621 Data Status Register at offset %02x = %02x", offset, data)); |
| 999 | break; |
| 1000 | default: |
| 1001 | LOG(("UNEXPECTED reading OMTI 8621 Data Status Register at offset %02x = %02x (omti state = %02x)", offset, data, state->omti_state)); |
| 1002 | break; |
| 1003 | } |
| 1004 | } else { |
| 1005 | LOG(("UNEXPECTED reading OMTI 8621 Data Register at offset %02x = %02x (status bit C/D = 0)", offset, data)); |
| 1006 | } |
| 1007 | break; |
| 1008 | |
| 1009 | case OMTI_PORT_STATUS: // 0x01 |
| 1010 | data = state->status_port; |
| 1011 | // omit excessive logging |
| 1012 | if (data != last_data) { |
| 1013 | LOG2(("reading OMTI 8621 Status Register at offset %02x = %02x", offset, data)); |
| 1014 | // last_data = data; |
| 1015 | } |
| 1016 | break; |
| 1017 | |
| 1018 | case OMTI_PORT_CONFIG: // 0x02 |
| 1019 | data = state->config_port; |
| 1020 | LOG2(("reading OMTI 8621 Configuration Register at offset %02x = %02x", offset, data)); |
| 1021 | break; |
| 1022 | |
| 1023 | case OMTI_PORT_MASK: // 0x03 |
| 1024 | data = state->mask_port ; |
| 1025 | // win.dex will update the mask register with read-modify-write |
| 1026 | // LOG2(("reading OMTI 8621 Mask Register at offset %02x = %02x (UNEXPECTED!)", offset, data)); |
| 1027 | break; |
| 1028 | |
| 1029 | default: |
| 1030 | LOG(("UNEXPECTED reading OMTI 8621 Register at offset %02x = %02x", offset, data)); |
| 1031 | break; |
| 1032 | } |
| 1033 | |
| 1034 | return data; |
| 1035 | } |
| 1036 | |
| 1037 | WRITE16_DEVICE_HANDLER(omti8621_w ) { |
| 1038 | omti8621_state *state = get_safe_token(device); |
| 1039 | |
| 1040 | switch (mem_mask) { |
| 1041 | case 0x00ff: |
| 1042 | omti8621_w8(device, offset*2+1, data); |
| 1043 | break; |
| 1044 | case 0xff00: |
| 1045 | omti8621_w8(device, offset*2, data>>8); |
| 1046 | break; |
| 1047 | default: |
| 1048 | LOG3(("writing OMTI 8621 Data Word Register to %0x = %04x & %04x", offset, data, mem_mask)); |
| 1049 | set_data(state, data); |
| 1050 | break; |
| 1051 | } |
| 1052 | } |
| 1053 | |
| 1054 | READ16_DEVICE_HANDLER( omti8621_r ) { |
| 1055 | omti8621_state *state = get_safe_token(device); |
| 1056 | UINT16 data; |
| 1057 | switch (mem_mask) { |
| 1058 | case 0x00ff: |
| 1059 | data = omti8621_r8(device, offset*2+1); |
| 1060 | break; |
| 1061 | case 0xff00: |
| 1062 | data = omti8621_r8(device, offset*2) << 8; |
| 1063 | break; |
| 1064 | default: |
| 1065 | data = get_data(state); |
| 1066 | LOG3(("reading OMTI 8621 Data Word Register from %0x = %04x & %04x", offset, data, mem_mask)); |
| 1067 | break; |
| 1068 | } |
| 1069 | return data; |
| 1070 | } |
| 1071 | |
| 1072 | void omti8621_set_verbose(int on_off) |
| 1073 | { |
| 1074 | verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1; |
| 1075 | } |
| 1076 | |
| 1077 | /*************************************************************************** |
| 1078 | omti8621_get_sector - get sector diskaddr of logical unit lun into data_buffer |
| 1079 | ***************************************************************************/ |
| 1080 | |
| 1081 | UINT32 omti8621_get_sector(device_t *device, INT32 diskaddr, UINT8 *data_buffer, UINT32 length, UINT8 lun) |
| 1082 | { |
| 1083 | omti8621_state *state = get_safe_token(device); |
| 1084 | disk_data *disk = state->disk[lun]; |
| 1085 | |
| 1086 | if (disk->image == NULL || !disk->image->exists()) |
| 1087 | { |
| 1088 | return 0; |
| 1089 | } |
| 1090 | else |
| 1091 | { |
| 1092 | LOG1(("omti8621_get_sector %x on lun %d", diskaddr, lun)); |
| 1093 | |
| 1094 | // restrict length to size of 1 sector (i.e. 1024 Byte) |
| 1095 | length = length < OMTI_DISK_SECTOR_SIZE ? length : OMTI_DISK_SECTOR_SIZE; |
| 1096 | |
| 1097 | disk->image->fseek(diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET); |
| 1098 | disk->image->fread(data_buffer, length); |
| 1099 | |
| 1100 | return length; |
| 1101 | } |
| 1102 | } |
| 1103 | |
| 1104 | |
| 1105 | /*************************************************************************** |
| 1106 | omti_set_jumper - set OMI jumpers |
| 1107 | ***************************************************************************/ |
| 1108 | |
| 1109 | static void omti_set_jumper(omti8621_state *state, UINT16 disk_type) |
| 1110 | { |
| 1111 | LOG1(("omti_set_jumper: disk type=%x", disk_type)); |
| 1112 | |
| 1113 | switch (disk_type) |
| 1114 | { |
| 1115 | case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted) |
| 1116 | state->jumper = OMTI_CONFIG_W22 | OMTI_CONFIG_W23; |
| 1117 | break; |
| 1118 | |
| 1119 | case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted) |
| 1120 | default: |
| 1121 | state->jumper = OMTI_CONFIG_W20; |
| 1122 | break; |
| 1123 | } |
| 1124 | } |
| 1125 | |
| 1126 | /*------------------------------------------------- |
| 1127 | device start callback |
| 1128 | -------------------------------------------------*/ |
| 1129 | |
| 1130 | static DEVICE_START( omti8621 ) { |
| 1131 | omti8621_state *state = get_safe_token(device); |
| 1132 | |
| 1133 | const omti8621_config *config = |
| 1134 | (const omti8621_config *) device->static_config(); |
| 1135 | |
| 1136 | /* validate basic stuff */ |
| 1137 | assert(device != NULL); |
| 1138 | assert(device->type() == OMTI8621); |
| 1139 | |
| 1140 | /* store a pointer back to the device */ |
| 1141 | state->device = device; |
| 1142 | |
| 1143 | // note: we must have state->device before we can log |
| 1144 | LOG2(("device_start_omti8621")); |
| 1145 | |
| 1146 | state->irq_handler = config->set_irq; |
| 1147 | |
| 1148 | state->sector_buffer = auto_alloc_array(device->machine(), UINT8, |
| 1149 | OMTI_DISK_SECTOR_SIZE*OMTI_MAX_BLOCK_COUNT); |
| 1150 | assert(state->sector_buffer != NULL); |
| 1151 | |
| 1152 | device_t *device0 = device->machine().device(OMTI_DISK0_TAG); |
| 1153 | state->disk[0] = (disk_data *) downcast<legacy_device_base *>(device0)->token(); |
| 1154 | |
| 1155 | device_t *device1 = device->machine().device(OMTI_DISK1_TAG); |
| 1156 | state->disk[1] = (disk_data *) downcast<legacy_device_base *>(device1)->token(); |
| 1157 | } |
| 1158 | |
| 1159 | /*------------------------------------------------- |
| 1160 | device reset callback |
| 1161 | -------------------------------------------------*/ |
| 1162 | |
| 1163 | static DEVICE_RESET( omti8621 ) |
| 1164 | { |
| 1165 | omti8621_state *state = get_safe_token(device); |
| 1166 | LOG2(("device_reset_omti8621")); |
| 1167 | |
| 1168 | omti_set_jumper(state, state->disk[0]->type); |
| 1169 | omti_reset(state); |
| 1170 | } |
| 1171 | |
| 1172 | /*------------------------------------------------- |
| 1173 | device get info callback |
| 1174 | -------------------------------------------------*/ |
| 1175 | |
| 1176 | DEVICE_GET_INFO( omti8621 ) |
| 1177 | { |
| 1178 | switch (state) |
| 1179 | { |
| 1180 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 1181 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(omti8621_state); break; |
| 1182 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = sizeof(omti8621_config); break; |
| 1183 | |
| 1184 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 1185 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(omti8621); break; |
| 1186 | case DEVINFO_FCT_STOP: /* Nothing */ break; |
| 1187 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(omti8621); break; |
| 1188 | |
| 1189 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 1190 | case DEVINFO_STR_NAME: strcpy(info->s, "OMTI 8621"); break; |
| 1191 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Winchester Disk Controller");break; |
| 1192 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 1193 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 1194 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; |
| 1195 | } |
| 1196 | } |
| 1197 | |
| 1198 | DEFINE_LEGACY_DEVICE(OMTI8621, omti8621); |
| 1199 | |
| 1200 | //########################################################################## |
| 1201 | |
| 1202 | DECLARE_LEGACY_IMAGE_DEVICE(OMTI_DISK0, omti_disk0); |
| 1203 | DECLARE_LEGACY_IMAGE_DEVICE(OMTI_DISK1, omti_disk1); |
| 1204 | |
| 1205 | /*************************************************************************** |
| 1206 | get_safe_disk_token - makes sure that the passed in device is a OMTI disk |
| 1207 | ***************************************************************************/ |
| 1208 | |
| 1209 | INLINE disk_data *get_safe_disk_token(device_t *device) { |
| 1210 | assert(device != NULL); |
| 1211 | assert(device->type() == OMTI_DISK0 || device->type() == OMTI_DISK1); |
| 1212 | return (disk_data *) downcast<legacy_device_base *>(device)->token(); |
| 1213 | } |
| 1214 | |
| 1215 | /*************************************************************************** |
| 1216 | omti_disk_config - configure disk parameters |
| 1217 | ***************************************************************************/ |
| 1218 | |
| 1219 | static void omti_disk_config(disk_data *disk, UINT16 disk_type) |
| 1220 | { |
| 1221 | DLOG1(("omti_disk_config: configuring disk with type %x", disk_type)); |
| 1222 | |
| 1223 | switch (disk_type) |
| 1224 | { |
| 1225 | case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted) |
| 1226 | disk->cylinders = 1223; |
| 1227 | disk->heads = 15; |
| 1228 | disk->sectors = 18; |
| 1229 | break; |
| 1230 | |
| 1231 | case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted) |
| 1232 | default: |
| 1233 | disk->cylinders = 1023; |
| 1234 | disk->heads = 8; |
| 1235 | disk->sectors = 18; |
| 1236 | break; |
| 1237 | } |
| 1238 | |
| 1239 | disk->type = disk_type; |
| 1240 | disk->sectorbytes = OMTI_DISK_SECTOR_SIZE; |
| 1241 | disk->sector_count = disk->cylinders * disk->heads * disk->sectors; |
| 1242 | } |
| 1243 | |
| 1244 | /*------------------------------------------------- |
| 1245 | device start callback |
| 1246 | -------------------------------------------------*/ |
| 1247 | |
| 1248 | static DEVICE_START( omti_disk ) |
| 1249 | { |
| 1250 | disk_data *disk = get_safe_disk_token(device); |
| 1251 | |
| 1252 | disk->device = device; |
| 1253 | // note: we must have disk->device before we can log |
| 1254 | |
| 1255 | disk->image = dynamic_cast<device_image_interface *> (disk->device); |
| 1256 | |
| 1257 | if (disk->image->image_core_file() == NULL) |
| 1258 | { |
| 1259 | DLOG1(("device_start_omti_disk: no disk")); |
| 1260 | } |
| 1261 | else |
| 1262 | { |
| 1263 | DLOG1(("device_start_omti_disk: with disk image %s",disk->image->basename() )); |
| 1264 | } |
| 1265 | |
| 1266 | // default disk type |
| 1267 | omti_disk_config(disk, OMTI_DISK_TYPE_DEFAULT); |
| 1268 | } |
| 1269 | |
| 1270 | /*------------------------------------------------- |
| 1271 | device reset callback |
| 1272 | -------------------------------------------------*/ |
| 1273 | |
| 1274 | static DEVICE_RESET( omti_disk ) |
| 1275 | { |
| 1276 | disk_data *disk = get_safe_disk_token(device); |
| 1277 | DLOG1(("device_reset_omti_disk")); |
| 1278 | |
| 1279 | if (disk->image->exists() && disk->image->fseek(0, SEEK_END) == 0) |
| 1280 | { |
| 1281 | UINT32 disk_size = (UINT32)(disk->image->ftell() / OMTI_DISK_SECTOR_SIZE); |
| 1282 | UINT16 disk_type = disk_size >= 300000 ? OMTI_DISK_TYPE_348_MB : OMTI_DISK_TYPE_155_MB; |
| 1283 | if (disk_type != disk->type) { |
| 1284 | DLOG1(("device_reset_omti_disk: disk size=%d blocks, disk type=%x", disk_size, disk_type )); |
| 1285 | omti_disk_config(disk, disk_type); |
| 1286 | } |
| 1287 | } |
| 1288 | } |
| 1289 | |
| 1290 | /*------------------------------------------------- |
| 1291 | disk image create callback |
| 1292 | -------------------------------------------------*/ |
| 1293 | |
| 1294 | DEVICE_IMAGE_CREATE( omti_disk ) |
| 1295 | { |
| 1296 | disk_data *disk = get_safe_disk_token(&image.device()); |
| 1297 | DLOG(("device_create_omti_disk: creating OMTI Disk with %d blocks", disk->sector_count)); |
| 1298 | |
| 1299 | int x; |
| 1300 | unsigned char sectordata[OMTI_DISK_SECTOR_SIZE]; // empty block data |
| 1301 | |
| 1302 | |
| 1303 | memset(sectordata, 0x55, sizeof(sectordata)); |
| 1304 | for (x = 0; x < disk->sector_count; x++) |
| 1305 | { |
| 1306 | if (image.fwrite(sectordata, OMTI_DISK_SECTOR_SIZE) |
| 1307 | < OMTI_DISK_SECTOR_SIZE) |
| 1308 | { |
| 1309 | return IMAGE_INIT_FAIL; |
| 1310 | } |
| 1311 | } |
| 1312 | return IMAGE_INIT_PASS; |
| 1313 | } |
| 1314 | |
| 1315 | /*------------------------------------------------- |
| 1316 | device get info callback |
| 1317 | -------------------------------------------------*/ |
| 1318 | |
| 1319 | DEVICE_GET_INFO( omti_disk0 ) |
| 1320 | { |
| 1321 | switch (state) |
| 1322 | { |
| 1323 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 1324 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(disk_data); break; |
| 1325 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 1326 | case DEVINFO_INT_IMAGE_TYPE: info->i = IO_HARDDISK; break; |
| 1327 | case DEVINFO_INT_IMAGE_READABLE: info->i = 1; break; |
| 1328 | case DEVINFO_INT_IMAGE_WRITEABLE: info->i = 1; break; |
| 1329 | case DEVINFO_INT_IMAGE_CREATABLE: info->i = 1; break; |
| 1330 | |
| 1331 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 1332 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(omti_disk); break; |
| 1333 | case DEVINFO_FCT_STOP: /* Nothing */ break; |
| 1334 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(omti_disk); break; |
| 1335 | // case DEVINFO_FCT_IMAGE_LOAD: info->f = (genf *) DEVICE_IMAGE_LOAD_NAME(omti_disk); break; |
| 1336 | // case DEVINFO_FCT_IMAGE_UNLOAD: info->f = (genf *) DEVICE_IMAGE_UNLOAD_NAME(omti_disk); break; |
| 1337 | case DEVINFO_FCT_IMAGE_CREATE: info->f = (genf *)DEVICE_IMAGE_CREATE_NAME(omti_disk); break; |
| 1338 | |
| 1339 | |
| 1340 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 1341 | case DEVINFO_STR_NAME: strcpy(info->s, "Winchester"); break; |
| 1342 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Winchester"); break; |
| 1343 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 1344 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 1345 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; |
| 1346 | |
| 1347 | case DEVINFO_STR_IMAGE_INSTANCE_NAME: strcpy(info->s, "disk"); break; |
| 1348 | case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME: strcpy(info->s, "disk"); break; |
| 1349 | case DEVINFO_STR_IMAGE_FILE_EXTENSIONS: strcpy(info->s, "awd"); break; |
| 1350 | } |
| 1351 | } |
| 1352 | |
| 1353 | DEVICE_GET_INFO( omti_disk1 ) |
| 1354 | { |
| 1355 | switch (state) |
| 1356 | { |
| 1357 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 1358 | case DEVINFO_STR_NAME: strcpy(info->s, "Winchester 1"); break; |
| 1359 | case DEVINFO_STR_IMAGE_INSTANCE_NAME: strcpy(info->s, "disk1"); break; |
| 1360 | case DEVINFO_STR_IMAGE_BRIEF_INSTANCE_NAME: strcpy(info->s, "disk1"); break; |
| 1361 | |
| 1362 | default: DEVICE_GET_INFO_CALL( omti_disk0 ); break; |
| 1363 | } |
| 1364 | } |
| 1365 | |
| 1366 | DEFINE_LEGACY_IMAGE_DEVICE(OMTI_DISK0, omti_disk0); |
| 1367 | DEFINE_LEGACY_IMAGE_DEVICE(OMTI_DISK1, omti_disk1); |
| 1368 | |
| 1369 | MACHINE_CONFIG_FRAGMENT( omti_disk ) |
| 1370 | MCFG_DEVICE_ADD(OMTI_DISK0_TAG, OMTI_DISK0, 0) |
| 1371 | MCFG_DEVICE_ADD(OMTI_DISK1_TAG, OMTI_DISK1, 0) |
| 1372 | MACHINE_CONFIG_END |
| 1373 | |
src/mess/video/apollo.c
| r0 | r14540 | |
| 1 | /* |
| 2 | * video/apollo.c |
| 3 | * |
| 4 | * Created on: May 12, 2010 |
| 5 | * Author: Hans Ostermeyer |
| 6 | * |
| 7 | * Released for general non-commercial use under the MAME license |
| 8 | * Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | * |
| 10 | * |
| 11 | * see also: |
| 12 | * - Domain Series 3000/Series 4000 Hardware Architecture Handbook (Order No. 007861 Rev. 02) |
| 13 | * - http://www.bitsavers.org/pdf/apollo/002398-04_Domain_Engineering_Handbook_Rev4_Jan87.pdf (page 12-16 ...) |
| 14 | */ |
| 15 | |
| 16 | #define VERBOSE 0 |
| 17 | |
| 18 | #include "includes/apollo.h" |
| 19 | |
| 20 | #include "apollo.lh" |
| 21 | #include "apollo_15i.lh" |
| 22 | |
| 23 | |
| 24 | /*************************************************************************** |
| 25 | TYPE DEFINITIONS |
| 26 | ***************************************************************************/ |
| 27 | |
| 28 | // monochrome 1280x1024 |
| 29 | #define SCREEN_DEVICE_ID_19I 0x09 |
| 30 | |
| 31 | // monochrome 1024x800 |
| 32 | #define SCREEN_DEVICE_ID_15I 0x0b |
| 33 | |
| 34 | #define VIDEO_SCREEN_TAG "screen" |
| 35 | |
| 36 | // status register |
| 37 | #define SR_BLANK 0x80 |
| 38 | #define SR_V_BLANK 0x40 |
| 39 | #define SR_H_SYNC 0x20 |
| 40 | #define SR_R_M_W 0x10 |
| 41 | #define SR_ALT 0x08 |
| 42 | #define SR_V_SYNC 0x04 |
| 43 | #define SR_H_CK 0x02 |
| 44 | #define SR_V_DATA 0x01 |
| 45 | |
| 46 | // control register 0 |
| 47 | #define CR0_MODE(a) ((a) >> 5) |
| 48 | #define CR0_MODE_0 0 |
| 49 | #define CR0_MODE_1 1 |
| 50 | #define CR0_MODE_VECTOR 2 |
| 51 | #define CR0_MODE_3 3 |
| 52 | #define CR0_MODE_BLT 4 |
| 53 | #define CR0_MODE_NORMAL 7 |
| 54 | #define CR0_SHIFT(a) ((a) & 0x1f) |
| 55 | |
| 56 | // control register 1 |
| 57 | #define CR1_INV 0x80 |
| 58 | #define CR1_DADDR_16 0x40 |
| 59 | #define CR1_DV_CK 0x40 |
| 60 | #define CR1_DH_CK 0x20 |
| 61 | #define CR1_ROP_EN 0x10 |
| 62 | #define CR1_RESET 0x08 |
| 63 | #define CR1_DP_CK 0x04 |
| 64 | #define CR1_SYNC_EN 0x02 |
| 65 | #define CR1_DISP_EN 0x01 |
| 66 | |
| 67 | // control register 2 |
| 68 | #define CR2_S_DATA(a) ((a) >> 6) |
| 69 | #define CR2_CONST_ACCESS 0x00 |
| 70 | #define CR2_PIXEL_ACCESS 0x01 |
| 71 | #define CR2_SHIFT_ACCESS 0x02 |
| 72 | #define CR2_PLANE_ACCESS 0x03 |
| 73 | |
| 74 | typedef struct _screen_data screen_data_t; |
| 75 | struct _screen_data { |
| 76 | UINT16 width; |
| 77 | UINT16 height; |
| 78 | UINT16 buffer_width; |
| 79 | UINT16 buffer_height; |
| 80 | |
| 81 | UINT8 status_register; |
| 82 | UINT8 device_id; |
| 83 | UINT16 write_enable_register; |
| 84 | UINT16 rop_register_0; |
| 85 | UINT16 diag_mem_request; |
| 86 | UINT8 cr0; |
| 87 | UINT8 cr1; |
| 88 | UINT8 cr2; |
| 89 | UINT8 cr3a; |
| 90 | |
| 91 | UINT8 update_flag; |
| 92 | UINT8 update_pending; |
| 93 | |
| 94 | UINT8 blt_cycle_count; |
| 95 | UINT32 guard_latch; |
| 96 | offs_t image_offset; |
| 97 | |
| 98 | int h_clock; |
| 99 | int v_clock; |
| 100 | int pixel_clock; |
| 101 | int data_clock; |
| 102 | |
| 103 | UINT16 *image_memory; |
| 104 | int image_memory_size; |
| 105 | |
| 106 | screen_device *screen; |
| 107 | }; |
| 108 | |
| 109 | /***************************************************************************** |
| 110 | INLINE FUNCTIONS |
| 111 | *****************************************************************************/ |
| 112 | |
| 113 | INLINE screen_data_t *get_safe_token(device_t *device) { |
| 114 | assert(device != NULL); |
| 115 | assert(device->type() == APOLLO_MONO15I || device->type() == APOLLO_MONO19I ); |
| 116 | return (screen_data_t *)downcast<legacy_device_base *>(device)->token(); |
| 117 | } |
| 118 | |
| 119 | /*************************************************************************** |
| 120 | Monochrome Controller Registers at 0x5d800 - 0x5dc07 |
| 121 | ***************************************************************************/ |
| 122 | |
| 123 | static void log_cr1(const char * text, device_t *device, screen_data_t *screen_data) { |
| 124 | |
| 125 | DLOG1(("%s: cr0=%02x cr1=%02x sr=%02x pixel_clock=%3d/%3d bl=%d vb=%d vs=%d hs=%d hc=%d vck=%d hck=%d pck=%d vd=%d", |
| 126 | text, |
| 127 | screen_data->cr0, |
| 128 | screen_data->cr1, |
| 129 | screen_data->status_register, |
| 130 | screen_data->pixel_clock, |
| 131 | screen_data->data_clock, |
| 132 | screen_data->status_register & SR_BLANK ? 1 : 0, |
| 133 | screen_data->status_register & SR_V_BLANK ? 1 : 0, |
| 134 | screen_data->status_register & SR_V_SYNC ? 1 : 0, |
| 135 | screen_data->status_register & SR_H_SYNC ? 1 : 0, |
| 136 | screen_data->status_register & SR_H_CK ? 1 : 0, |
| 137 | screen_data->cr1 & CR1_DV_CK ? 1 : 0, |
| 138 | screen_data->cr1 & CR1_DH_CK ? 1 : 0, |
| 139 | screen_data->cr1 & CR1_DP_CK ? 1 : 0, |
| 140 | screen_data->status_register & SR_V_DATA ? 1 : 0)); |
| 141 | } |
| 142 | |
| 143 | static void set_cr1(device_t *device, screen_data_t *screen_data, |
| 144 | UINT8 data) { |
| 145 | UINT8 diffs = screen_data->cr1 ^ data; |
| 146 | screen_data->cr1 = data; |
| 147 | |
| 148 | // if (screen_data->cr1 & CR1_SYNC_EN) { |
| 149 | // // normal mode |
| 150 | // } else |
| 151 | |
| 152 | if ((screen_data->cr1 & CR1_RESET) == 0) { |
| 153 | if (diffs & CR1_RESET) { |
| 154 | screen_data->blt_cycle_count = 0; |
| 155 | screen_data->image_offset = 0; |
| 156 | screen_data->guard_latch = 0; |
| 157 | |
| 158 | screen_data->h_clock = 0; |
| 159 | screen_data->v_clock = 0; |
| 160 | screen_data->pixel_clock = 0; |
| 161 | if (screen_data->device_id == SCREEN_DEVICE_ID_19I) { |
| 162 | screen_data->data_clock = -11; // TODO: why not 0 ???? |
| 163 | screen_data->status_register = SR_H_CK | SR_V_BLANK | SR_H_SYNC |
| 164 | | SR_V_SYNC; |
| 165 | } else { |
| 166 | screen_data->data_clock = -9; // TODO: why not 0 ???? |
| 167 | screen_data->status_register = SR_V_BLANK | SR_V_SYNC; |
| 168 | } |
| 169 | } |
| 170 | log_cr1("CR1_RESET", device, screen_data); |
| 171 | } else { |
| 172 | if ((diffs & CR1_RESET) && (screen_data->cr1 & CR1_RESET) != 0) { |
| 173 | log_cr1("CR1_RESET", device, screen_data); |
| 174 | } |
| 175 | |
| 176 | if ((diffs & CR1_DH_CK) && (screen_data->cr1 & CR1_DH_CK) == 0) { |
| 177 | if (screen_data->device_id == SCREEN_DEVICE_ID_19I) { |
| 178 | switch (screen_data->h_clock %= 108) { |
| 179 | case 8: |
| 180 | screen_data->status_register |= SR_BLANK; |
| 181 | break; |
| 182 | case 88: |
| 183 | screen_data->status_register &= ~SR_BLANK; |
| 184 | break; |
| 185 | case 93: |
| 186 | screen_data->status_register &= ~SR_H_SYNC; |
| 187 | // trigger Dp_Ck |
| 188 | diffs |= CR1_DP_CK; |
| 189 | screen_data->cr1 &= ~CR1_DP_CK; |
| 190 | break; |
| 191 | case 104: |
| 192 | screen_data->status_register |= SR_H_SYNC; |
| 193 | break; |
| 194 | } |
| 195 | } else { |
| 196 | switch (screen_data->h_clock %= 84) { |
| 197 | case 1: |
| 198 | screen_data->status_register |= SR_H_SYNC; |
| 199 | break; |
| 200 | case 8: |
| 201 | screen_data->status_register |= SR_BLANK; |
| 202 | break; |
| 203 | case 72: |
| 204 | screen_data->status_register &= ~SR_BLANK; |
| 205 | break; |
| 206 | case 77: |
| 207 | screen_data->status_register &= ~SR_H_SYNC; |
| 208 | diffs |= CR1_DV_CK; |
| 209 | data &= ~CR1_DV_CK; |
| 210 | break; |
| 211 | } |
| 212 | } |
| 213 | screen_data->h_clock++; |
| 214 | log_cr1("CR1_DH_CK",device, screen_data); |
| 215 | } |
| 216 | |
| 217 | if ((diffs & CR1_DV_CK) && (screen_data->cr1 & CR1_DV_CK) == 0) { |
| 218 | // this is used for disp.dex Test 19: Video RAM Shift Reg. Test |
| 219 | if (screen_data->device_id == SCREEN_DEVICE_ID_15I) { |
| 220 | switch (screen_data->v_clock %= 842) { |
| 221 | case 799: |
| 222 | screen_data->status_register &= ~SR_V_BLANK; |
| 223 | break; |
| 224 | case 804: |
| 225 | screen_data->status_register &= ~SR_V_SYNC; |
| 226 | break; |
| 227 | case 808: |
| 228 | screen_data->status_register |= SR_V_SYNC; |
| 229 | break; |
| 230 | case 841: |
| 231 | screen_data->status_register |= SR_V_BLANK; |
| 232 | break; |
| 233 | } |
| 234 | screen_data->v_clock++; |
| 235 | log_cr1("CR1_DV_CK",device, screen_data); |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | if ((diffs & CR1_DP_CK) && (screen_data->cr1 & CR1_DP_CK) == 0) { |
| 240 | if (screen_data->device_id == SCREEN_DEVICE_ID_19I) { |
| 241 | switch (screen_data->pixel_clock %= 1066) { |
| 242 | case 1023: |
| 243 | screen_data->status_register &= ~SR_V_BLANK; |
| 244 | break; |
| 245 | case 1028: |
| 246 | screen_data->status_register &= ~SR_V_SYNC; |
| 247 | break; |
| 248 | case 1032: |
| 249 | screen_data->status_register |= SR_V_SYNC; |
| 250 | break; |
| 251 | case 1065: |
| 252 | screen_data->status_register |= SR_V_BLANK; |
| 253 | break; |
| 254 | } |
| 255 | } else /*if (screen_data->pixel_clock == 0)*/ { |
| 256 | // this is used for disp.dex Test 6: Vertical Counter Test |
| 257 | switch (screen_data->pixel_clock %= 842) { |
| 258 | case 799: |
| 259 | screen_data->status_register &= ~SR_V_BLANK; |
| 260 | break; |
| 261 | case 804: |
| 262 | screen_data->status_register &= ~SR_V_SYNC; |
| 263 | break; |
| 264 | case 808: |
| 265 | screen_data->status_register |= SR_V_SYNC; |
| 266 | break; |
| 267 | case 841: |
| 268 | screen_data->status_register |= SR_V_BLANK; |
| 269 | break; |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | if ((screen_data->cr1 & CR1_DISP_EN) == 0) { |
| 274 | screen_data->status_register &= ~SR_V_DATA; |
| 275 | }else { |
| 276 | UINT16 pixel = screen_data->image_memory[screen_data->data_clock / 16] |
| 277 | & (0x8000 >> (screen_data->data_clock % 16)); |
| 278 | pixel = (pixel ? 1 : 0) ^ ((screen_data->cr1 & CR1_INV) ? 0 : 1); |
| 279 | |
| 280 | if (pixel) { |
| 281 | screen_data->status_register |= SR_V_DATA; |
| 282 | } else { |
| 283 | screen_data->status_register &= ~SR_V_DATA; |
| 284 | } |
| 285 | screen_data->data_clock++; |
| 286 | } |
| 287 | |
| 288 | screen_data->pixel_clock++; |
| 289 | if ((screen_data->pixel_clock % 8) == 0) { |
| 290 | screen_data->status_register ^= SR_H_CK; |
| 291 | } |
| 292 | |
| 293 | log_cr1("CR1_DP_CK", device, screen_data); |
| 294 | } |
| 295 | |
| 296 | if ((screen_data->status_register & SR_V_BLANK) == 0) { |
| 297 | screen_data->status_register &= ~SR_BLANK; |
| 298 | } |
| 299 | |
| 300 | if (diffs & CR1_DISP_EN) { |
| 301 | // update screen |
| 302 | screen_data->update_flag = 1; |
| 303 | } |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | static void set_cr3(device_t *device, screen_data_t *screen_data, UINT8 data) { |
| 308 | screen_data->cr3a = data; |
| 309 | if ((data & 0x80) == 0) { |
| 310 | int shift = (data & 0x0f) >> 1; |
| 311 | UINT8 bit_mask = 1 << shift; |
| 312 | if (data & 0x01) { |
| 313 | set_cr1(device, screen_data, screen_data->cr1 | bit_mask); |
| 314 | } else { |
| 315 | set_cr1(device, screen_data, screen_data->cr1 & ~bit_mask); |
| 316 | } |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | READ16_DEVICE_HANDLER( apollo_mcr_r ) { |
| 321 | screen_data_t *screen_data = get_safe_token(device); |
| 322 | UINT16 data; |
| 323 | switch (offset & 0x203) { |
| 324 | case 0: |
| 325 | case 1: |
| 326 | case 2: |
| 327 | case 3: |
| 328 | data = (screen_data->status_register << 8) |
| 329 | | screen_data->device_id; |
| 330 | break; |
| 331 | case 0x200: |
| 332 | data = screen_data->cr0 << 8 | 0xff; |
| 333 | break; |
| 334 | case 0x201: |
| 335 | data = screen_data->cr1 << 8 | 0xff; |
| 336 | break; |
| 337 | case 0x202: |
| 338 | data = screen_data->cr2 << 8 | 0xff; |
| 339 | break; |
| 340 | case 0x203: |
| 341 | data = screen_data->cr3a << 8 | 0xff; |
| 342 | break; |
| 343 | default: |
| 344 | data = screen_data->device_id; |
| 345 | break; |
| 346 | } |
| 347 | DLOG1(("reading Monochrome Controller at offset %03x = %04x and %04x", offset, data, mem_mask)); |
| 348 | return data; |
| 349 | } |
| 350 | |
| 351 | WRITE16_DEVICE_HANDLER(apollo_mcr_w ) { |
| 352 | screen_data_t *screen_data = get_safe_token(device); |
| 353 | if (offset != 0 && data != 0) |
| 354 | DLOG1(("writing Monochrome Controller at offset %03x = %04x and %04x", offset, data, mem_mask)); |
| 355 | |
| 356 | switch (offset & 0x203) { |
| 357 | case 0: |
| 358 | screen_data->write_enable_register = data; |
| 359 | screen_data->blt_cycle_count = 0; |
| 360 | screen_data->status_register &= ~SR_ALT; |
| 361 | break; |
| 362 | case 1: |
| 363 | screen_data->rop_register_0 = data; |
| 364 | switch (data & 0x0f) { |
| 365 | case 0: // zero |
| 366 | case 3: // Source |
| 367 | case 0x0c: // ~Source |
| 368 | case 0x0f: // one |
| 369 | screen_data->status_register &= ~SR_R_M_W; |
| 370 | break; |
| 371 | default: |
| 372 | screen_data->status_register |= SR_R_M_W; |
| 373 | break; |
| 374 | } |
| 375 | break; |
| 376 | case 2: |
| 377 | // trigger memory refresh in diagnostic mode |
| 378 | screen_data->diag_mem_request = data; |
| 379 | break; |
| 380 | case 0x200: |
| 381 | screen_data->cr0 = data >> 8; |
| 382 | screen_data->blt_cycle_count = 0; |
| 383 | break; |
| 384 | case 0x201: |
| 385 | set_cr1(device, screen_data, data >> 8); |
| 386 | break; |
| 387 | case 0x202: |
| 388 | screen_data->cr2 = data >> 8; |
| 389 | break; |
| 390 | case 0x203: |
| 391 | set_cr3(device, screen_data, data >> 8); |
| 392 | break; |
| 393 | } |
| 394 | } |
| 395 | |
| 396 | /*************************************************************************** |
| 397 | Monochrome graphics memory space at FA0000 - FDFFFF |
| 398 | ***************************************************************************/ |
| 399 | |
| 400 | static UINT32 get_source_data(screen_data_t *screen_data, UINT32 src_data) { |
| 401 | switch (CR2_S_DATA(screen_data->cr2)) { |
| 402 | case CR2_CONST_ACCESS: // 0x00 |
| 403 | // set source to all ones (used for vectors) |
| 404 | src_data= 0xffff; |
| 405 | break; |
| 406 | case CR2_PIXEL_ACCESS: // 0x01 |
| 407 | // replicate 4 LSB of data bus |
| 408 | src_data= src_data & 1 ? 0xffff : 0; |
| 409 | break; |
| 410 | case CR2_SHIFT_ACCESS: // 0x02 |
| 411 | // replicate LSB of shifter |
| 412 | src_data = src_data & 0xffff; |
| 413 | break; |
| 414 | case CR2_PLANE_ACCESS: // 0x03 |
| 415 | // use source data unchanged (normal use) |
| 416 | if (CR0_SHIFT(screen_data->cr0) >= 16) { |
| 417 | src_data = (src_data << 16) | (src_data >> 16); |
| 418 | } |
| 419 | src_data >>= (CR0_SHIFT(screen_data->cr0) & 0x0f); |
| 420 | break; |
| 421 | } |
| 422 | return src_data; |
| 423 | } |
| 424 | |
| 425 | static UINT16 rop(screen_data_t *screen_data, UINT16 dest_data) { |
| 426 | |
| 427 | UINT32 src_data = get_source_data(screen_data, screen_data->guard_latch); |
| 428 | |
| 429 | if ((screen_data->cr1 & CR1_ROP_EN) |
| 430 | /*&& (CR2_S_DATA(screen_data->cr2) == CR2_PLANE_ACCESS)*/) { |
| 431 | switch (screen_data->rop_register_0 & 0x0f) { |
| 432 | case 0: // zero |
| 433 | src_data = 0; |
| 434 | break; |
| 435 | case 1: // Source AND Destination |
| 436 | src_data = src_data & dest_data; |
| 437 | break; |
| 438 | case 2: // Source AND ~Destination |
| 439 | src_data = src_data & (~dest_data); |
| 440 | break; |
| 441 | case 3: // Source |
| 442 | break; |
| 443 | case 4: // ~Source AND Destination |
| 444 | src_data = (~src_data) & dest_data; |
| 445 | break; |
| 446 | case 5: // Destination |
| 447 | src_data = dest_data; |
| 448 | break; |
| 449 | case 6: // Source XOR Destination |
| 450 | src_data = src_data ^ dest_data; |
| 451 | break; |
| 452 | case 7: // Source OR Destination |
| 453 | src_data = src_data | dest_data; |
| 454 | break; |
| 455 | case 8: // Source NOR Destination |
| 456 | src_data = ~(src_data | dest_data); |
| 457 | break; |
| 458 | case 9: // Source XNOR Destination |
| 459 | src_data = ~(src_data ^ dest_data); |
| 460 | break; |
| 461 | case 0x0a: // ~Destination |
| 462 | src_data = ~dest_data; |
| 463 | break; |
| 464 | case 0x0b: // Source OR ~Destination |
| 465 | src_data = src_data | (~dest_data); |
| 466 | break; |
| 467 | case 0x0c: // ~Source |
| 468 | src_data = ~src_data; |
| 469 | break; |
| 470 | case 0x0d: // ~Source OR Destination |
| 471 | src_data = (~src_data) | dest_data; |
| 472 | break; |
| 473 | case 0x0e: // Source NAND Destination |
| 474 | src_data = ~(src_data & dest_data); |
| 475 | break; |
| 476 | case 0x0f: // One |
| 477 | src_data = 0xffff; |
| 478 | break; |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | return src_data & 0xffff; |
| 483 | } |
| 484 | |
| 485 | READ16_DEVICE_HANDLER( apollo_mgm_r ) { |
| 486 | screen_data_t *screen_data = get_safe_token(device); |
| 487 | UINT16 data; |
| 488 | |
| 489 | if (CR0_MODE(screen_data->cr0) == CR0_MODE_0 |
| 490 | && screen_data->blt_cycle_count > 0) { |
| 491 | offset = screen_data->image_offset; |
| 492 | screen_data->blt_cycle_count = 0; |
| 493 | } |
| 494 | |
| 495 | if (offset >= screen_data->image_memory_size) { |
| 496 | // 128 kB display buffer of 15" screen seems to be shadowed from $fa0000 to $fc0000 |
| 497 | DLOG1(("reading Monochrome Graphics Memory at invalid offset %05x", offset)); |
| 498 | offset %= screen_data->image_memory_size; |
| 499 | } |
| 500 | |
| 501 | switch (CR0_MODE(screen_data->cr0)) { |
| 502 | case CR0_MODE_VECTOR: |
| 503 | // vector or fill mode |
| 504 | UINT16 src_data, dest_data; |
| 505 | screen_data->status_register &= ~SR_ALT; |
| 506 | |
| 507 | dest_data = screen_data->image_memory[offset]; |
| 508 | src_data = rop(screen_data, dest_data); |
| 509 | |
| 510 | src_data &= ~screen_data->write_enable_register; |
| 511 | dest_data &= (screen_data->write_enable_register | ~mem_mask); |
| 512 | screen_data->image_memory[offset] = dest_data | src_data; |
| 513 | data = screen_data->image_memory[offset]; |
| 514 | break; |
| 515 | case CR0_MODE_3: |
| 516 | // CPU source BLT: read internal data bus |
| 517 | data = screen_data->guard_latch; |
| 518 | break; |
| 519 | default: |
| 520 | data = screen_data->image_memory[offset]; |
| 521 | screen_data->guard_latch <<= 16; |
| 522 | screen_data->guard_latch |= data; |
| 523 | break; |
| 524 | } |
| 525 | DLOG1(("reading Monochrome Graphics Memory with mode %d: offset %05x = %04x & %04x", CR0_MODE(screen_data->cr0), offset, data, mem_mask)); |
| 526 | return data; |
| 527 | } |
| 528 | |
| 529 | WRITE16_DEVICE_HANDLER( apollo_mgm_w ) { |
| 530 | screen_data_t *screen_data = get_safe_token(device); |
| 531 | UINT16 src_data, dest_data; |
| 532 | UINT32 dest_addr; |
| 533 | |
| 534 | if (offset >= screen_data->image_memory_size) { |
| 535 | // 128 kB display buffer of 15" screen seems to be shadowed from $fa0000 to $fc0000 |
| 536 | DLOG1(("writing Monochrome Graphics Memory at invalid offset %05x = %04x & %04x ", offset, data, mem_mask)); |
| 537 | offset %= screen_data->image_memory_size; |
| 538 | } |
| 539 | |
| 540 | DLOG1(("writing Monochrome Graphics Memory with mode %d: offset=%04x data=%04x mask=%04x", CR0_MODE(screen_data->cr0), offset, data, mem_mask)); |
| 541 | switch (CR0_MODE(screen_data->cr0)) { |
| 542 | case CR0_MODE_0: |
| 543 | // CPU destination BLT |
| 544 | // bus write to provide display memory address |
| 545 | // bus read to get data |
| 546 | screen_data->image_offset = offset; |
| 547 | screen_data->blt_cycle_count = 1; |
| 548 | break; |
| 549 | case CR0_MODE_1: |
| 550 | // Alternating BLT |
| 551 | // alternating bus writes provide src/dest address |
| 552 | // second write provides Write-enables |
| 553 | if (++screen_data->blt_cycle_count == 1) { |
| 554 | screen_data->status_register |= SR_ALT; |
| 555 | screen_data->guard_latch <<= 16; |
| 556 | screen_data->guard_latch |= screen_data->image_memory[offset]; |
| 557 | } else { |
| 558 | screen_data->blt_cycle_count = 0; |
| 559 | screen_data->status_register &= ~SR_ALT; |
| 560 | |
| 561 | dest_data = screen_data->image_memory[offset]; |
| 562 | src_data = rop(screen_data, dest_data); |
| 563 | |
| 564 | src_data &= (~data & mem_mask); |
| 565 | dest_data &= (data | ~mem_mask); |
| 566 | screen_data->image_memory[offset] = dest_data | src_data; |
| 567 | } |
| 568 | break; |
| 569 | case CR0_MODE_VECTOR: |
| 570 | // Vector or fill mode |
| 571 | // write provides Write-enables and address |
| 572 | screen_data->status_register &= ~SR_ALT; |
| 573 | |
| 574 | dest_data = screen_data->image_memory[offset]; |
| 575 | src_data = rop(screen_data, dest_data); |
| 576 | |
| 577 | src_data &= (~data & mem_mask); |
| 578 | dest_data &= (data | ~mem_mask); |
| 579 | screen_data->image_memory[offset] = dest_data | src_data; |
| 580 | break; |
| 581 | case CR0_MODE_3: |
| 582 | // CPU source BLT |
| 583 | // bus write to provide src data |
| 584 | // bus write to provide Write-enables and address |
| 585 | if (++screen_data->blt_cycle_count == 1) { |
| 586 | screen_data->status_register |= SR_ALT; |
| 587 | |
| 588 | // strange: must fix byte access for /systest/grtest on sr10.2 |
| 589 | if (mem_mask == 0xff00) |
| 590 | { |
| 591 | data >>=8; |
| 592 | mem_mask >>= 8; |
| 593 | } |
| 594 | |
| 595 | screen_data->guard_latch <<= 16; |
| 596 | screen_data->guard_latch |= data; |
| 597 | |
| 598 | } else { |
| 599 | screen_data->blt_cycle_count = 0; |
| 600 | screen_data->status_register &= ~SR_ALT; |
| 601 | |
| 602 | dest_data = screen_data->image_memory[offset]; |
| 603 | dest_data &= (data | ~mem_mask); |
| 604 | |
| 605 | src_data = rop(screen_data, dest_data); |
| 606 | src_data &= (~data & mem_mask); |
| 607 | |
| 608 | screen_data->image_memory[offset] = dest_data | src_data; |
| 609 | } |
| 610 | break; |
| 611 | case CR0_MODE_BLT: |
| 612 | // Double access BLT |
| 613 | // bus write to provide src addr on address lines |
| 614 | // dest addr on data lines (16-bit WORD Offset) |
| 615 | screen_data->guard_latch <<= 16; |
| 616 | screen_data->guard_latch |= screen_data->image_memory[offset]; |
| 617 | |
| 618 | dest_addr = (data & mem_mask); |
| 619 | if (screen_data->device_id == SCREEN_DEVICE_ID_19I && (screen_data->cr1 |
| 620 | & CR1_DADDR_16)) { |
| 621 | dest_addr += 0x10000; |
| 622 | } |
| 623 | dest_data = screen_data->image_memory[dest_addr]; |
| 624 | |
| 625 | src_data = rop(screen_data, dest_data); |
| 626 | src_data &= ~screen_data->write_enable_register; |
| 627 | |
| 628 | dest_data &= (screen_data->write_enable_register | ~mem_mask); |
| 629 | screen_data->image_memory[dest_addr] = dest_data | src_data; |
| 630 | break; |
| 631 | case CR0_MODE_NORMAL: |
| 632 | screen_data->guard_latch <<= 16; |
| 633 | screen_data->guard_latch |= (data & mem_mask);; |
| 634 | dest_data = screen_data->image_memory[offset]; |
| 635 | src_data = rop(screen_data, dest_data); |
| 636 | |
| 637 | src_data &= ~screen_data->write_enable_register; |
| 638 | dest_data &= (screen_data->write_enable_register | ~mem_mask); |
| 639 | screen_data->image_memory[offset] = dest_data | src_data; |
| 640 | break; |
| 641 | default: |
| 642 | DLOG(("writing Monochrome Graphics Memory - unexpected cr0 mode %d", CR0_MODE(screen_data->cr0))); |
| 643 | } |
| 644 | screen_data->update_flag = 1; |
| 645 | } |
| 646 | |
| 647 | /*************************************************************************** |
| 648 | VIDEO HARDWARE |
| 649 | ***************************************************************************/ |
| 650 | |
| 651 | static void apollo_screen_update(device_t *device, bitmap_ind16 &bitmap, |
| 652 | const rectangle &cliprect) { |
| 653 | screen_data_t *screen_data = get_safe_token(device); |
| 654 | |
| 655 | UINT16 *source_ptr = screen_data->image_memory; |
| 656 | int x, y; |
| 657 | UINT16 data, mask; |
| 658 | UINT16 inverse = (screen_data->cr1 & CR1_INV) ? 0xffff : 0; |
| 659 | |
| 660 | DLOG1(("apollo_screen_update: size=%0x rowpixels=%d", screen_data->image_memory_size, bitmap.rowpixels())); |
| 661 | |
| 662 | if ((screen_data->cr1 & CR1_DISP_EN) == 0) { |
| 663 | // display is disabled |
| 664 | for (y = 0; y < screen_data->height; y++) { |
| 665 | int dest = 0; |
| 666 | for (x = 0; x < screen_data->width; x += 16) { |
| 667 | for (mask = 0x8000; mask; mask >>= 1) { |
| 668 | bitmap.pix16(y, dest++) = 0; |
| 669 | } |
| 670 | } |
| 671 | source_ptr += (screen_data->buffer_width - screen_data->width) / 16; |
| 672 | } |
| 673 | } else { |
| 674 | for (y = 0; y < screen_data->height; y++) { |
| 675 | int dest = 0; |
| 676 | for (x = 0; x < screen_data->width; x += 16) { |
| 677 | data = *source_ptr++ ^ inverse; |
| 678 | for (mask = 0x8000; mask; mask >>= 1) { |
| 679 | bitmap.pix16(y, dest++) = data & mask ? 0 : 1; |
| 680 | } |
| 681 | } |
| 682 | source_ptr += (screen_data->buffer_width - screen_data->width) / 16; |
| 683 | } |
| 684 | } |
| 685 | } |
| 686 | |
| 687 | /*------------------------------------------------- |
| 688 | vblank_state_changed - |
| 689 | called on each state change of the VBLANK signal |
| 690 | -------------------------------------------------*/ |
| 691 | |
| 692 | static void vblank_state_changed(device_t *device, screen_device &screen, bool vblank_state) |
| 693 | { |
| 694 | screen_data_t *screen_data = get_safe_token(device); |
| 695 | |
| 696 | if ((screen_data->cr1 & CR1_RESET) && (screen_data->cr1 & CR1_SYNC_EN)) { |
| 697 | if (vblank_state) { |
| 698 | screen_data->status_register &= ~(SR_V_BLANK | SR_BLANK); |
| 699 | // faking V_DATA for disp.dex test 16 |
| 700 | if (screen_data->image_memory[0]) { |
| 701 | screen_data->status_register |= SR_V_DATA; |
| 702 | } |
| 703 | } else { |
| 704 | screen_data->status_register |= (SR_V_BLANK | SR_BLANK); |
| 705 | screen_data->status_register &= ~SR_V_DATA; |
| 706 | } |
| 707 | } |
| 708 | } |
| 709 | |
| 710 | VIDEO_START( apollo_screen ) { |
| 711 | } |
| 712 | |
| 713 | SCREEN_UPDATE_IND16( apollo_screen ) { |
| 714 | // FIXME: omit using APOLLO_SCREEN_TAG |
| 715 | device_t *apollo_screen = screen.machine().device( APOLLO_SCREEN_TAG ); |
| 716 | screen_data_t *screen_data = get_safe_token(apollo_screen); |
| 717 | |
| 718 | int has_changed = 0; |
| 719 | |
| 720 | if (screen_data->update_flag && !screen_data->update_pending) { |
| 721 | has_changed = 1; |
| 722 | screen_data->update_flag = 0; |
| 723 | screen_data->update_pending = 1; |
| 724 | apollo_screen_update(apollo_screen, bitmap, cliprect); |
| 725 | screen_data->update_pending = 0; |
| 726 | } |
| 727 | return has_changed ? 0 : UPDATE_HAS_NOT_CHANGED; |
| 728 | } |
| 729 | |
| 730 | /*************************************************************************** |
| 731 | MACHINE DRIVERS |
| 732 | ***************************************************************************/ |
| 733 | MACHINE_CONFIG_FRAGMENT( apollo_mono19i ) |
| 734 | MCFG_DEFAULT_LAYOUT( layout_apollo ) |
| 735 | MCFG_SCREEN_ADD(VIDEO_SCREEN_TAG, RASTER) |
| 736 | MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_AFTER_VBLANK) |
| 737 | // MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) |
| 738 | MCFG_PALETTE_LENGTH(2) |
| 739 | MCFG_PALETTE_INIT(black_and_white) |
| 740 | // dot clock, htotal, hstart, hend, vtotal, vstart, vend |
| 741 | // MCFG_SCREEN_RAW_PARAMS(118000000, 1280, 0, 1728, 1024, 0, 1065) |
| 742 | MCFG_SCREEN_REFRESH_RATE(64) |
| 743 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(616)) |
| 744 | MCFG_SCREEN_SIZE(1280, 1024) |
| 745 | MCFG_SCREEN_VISIBLE_AREA(0, 1279, 0, 1023) |
| 746 | MCFG_VIDEO_START(apollo_screen) |
| 747 | MCFG_SCREEN_UPDATE_STATIC(apollo_screen) |
| 748 | MACHINE_CONFIG_END |
| 749 | |
| 750 | MACHINE_CONFIG_FRAGMENT( apollo_mono15i ) |
| 751 | MCFG_DEFAULT_LAYOUT( layout_apollo_15i ) |
| 752 | MCFG_SCREEN_ADD(VIDEO_SCREEN_TAG, RASTER) |
| 753 | MCFG_VIDEO_ATTRIBUTES(VIDEO_UPDATE_AFTER_VBLANK) |
| 754 | // MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16) |
| 755 | MCFG_PALETTE_LENGTH(2) |
| 756 | MCFG_PALETTE_INIT(black_and_white) |
| 757 | // dot clock, htotal, hstart, hend, vtotal, vstart, vend |
| 758 | // MCFG_SCREEN_RAW_PARAMS(85963000, 1024, 0, 1344, 800, 0, 842) |
| 759 | MCFG_SCREEN_REFRESH_RATE(76) |
| 760 | MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(657)) |
| 761 | MCFG_SCREEN_SIZE(1024, 800) |
| 762 | MCFG_SCREEN_VISIBLE_AREA(0, 1023, 0, 799) |
| 763 | MCFG_VIDEO_START(apollo_screen) |
| 764 | MCFG_SCREEN_UPDATE_STATIC(apollo_screen) |
| 765 | MACHINE_CONFIG_END |
| 766 | |
| 767 | /*------------------------------------------------- |
| 768 | DEVICE_START( apollo_mono19i/15i ) |
| 769 | -------------------------------------------------*/ |
| 770 | |
| 771 | static DEVICE_START( apollo_mono ) { |
| 772 | screen_data_t *screen_data = get_safe_token(device); |
| 773 | |
| 774 | /* get the video screen */ |
| 775 | screen_data->screen = (screen_device *)device->machine().device(VIDEO_SCREEN_TAG); |
| 776 | assert(screen_data->screen != NULL); |
| 777 | |
| 778 | /* allocate the memory image */ |
| 779 | screen_data->image_memory_size = screen_data->buffer_height |
| 780 | * screen_data->buffer_width / 16; |
| 781 | // screen_data->image_memory = (UINT16 *) malloc(screen_data->image_memory_size * 2); |
| 782 | screen_data->image_memory = auto_alloc_array(device->machine(), UINT16, screen_data->image_memory_size); |
| 783 | assert(screen_data->image_memory != NULL); |
| 784 | |
| 785 | DLOG1(("device start apollo screen buffer=%p size=%0x", screen_data->image_memory, screen_data->image_memory_size)); |
| 786 | } |
| 787 | |
| 788 | static DEVICE_START( apollo_mono19i ) { |
| 789 | screen_data_t *screen_data = get_safe_token(device); |
| 790 | |
| 791 | memset(screen_data, 0, sizeof(screen_data_t)); |
| 792 | |
| 793 | // monochrome 1280x1024 |
| 794 | screen_data->device_id = SCREEN_DEVICE_ID_19I; |
| 795 | screen_data->width = 1280; |
| 796 | screen_data->height = 1024; |
| 797 | screen_data->buffer_width = 2048; |
| 798 | screen_data->buffer_height = 1024; |
| 799 | |
| 800 | device_start_apollo_mono(device); |
| 801 | } |
| 802 | |
| 803 | static DEVICE_START( apollo_mono15i ) { |
| 804 | screen_data_t *screen_data = get_safe_token(device); |
| 805 | |
| 806 | memset(screen_data, 0, sizeof(screen_data_t)); |
| 807 | |
| 808 | // monochrome 1024x800 |
| 809 | screen_data->device_id = SCREEN_DEVICE_ID_15I; |
| 810 | screen_data->width = 1024; |
| 811 | screen_data->height = 800; |
| 812 | screen_data->buffer_width = 1024; |
| 813 | screen_data->buffer_height = 1024; |
| 814 | |
| 815 | device_start_apollo_mono(device); |
| 816 | } |
| 817 | |
| 818 | /*------------------------------------------------- |
| 819 | DEVICE_RESET( apollo_mono19i/15i ) |
| 820 | -------------------------------------------------*/ |
| 821 | |
| 822 | static DEVICE_RESET( apollo_mono19i ) { |
| 823 | screen_data_t *screen_data = get_safe_token(device); |
| 824 | |
| 825 | DLOG1(("device reset apollo screen")); |
| 826 | |
| 827 | memset(screen_data->image_memory, 0, screen_data->image_memory_size * 2); |
| 828 | |
| 829 | /* register for VBLANK callbacks */ |
| 830 | screen_data->screen->register_vblank_callback(vblank_state_delegate(FUNC(vblank_state_changed), device)); |
| 831 | } |
| 832 | |
| 833 | static DEVICE_RESET( apollo_mono15i ) { |
| 834 | DEVICE_RESET_CALL(apollo_mono19i); |
| 835 | } |
| 836 | |
| 837 | /*------------------------------------------------- |
| 838 | DEVICE_GET_INFO( apollo_mono19i/15i ) |
| 839 | -------------------------------------------------*/ |
| 840 | |
| 841 | DEVICE_GET_INFO( apollo_mono19i ) { |
| 842 | switch (state) { |
| 843 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 844 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 845 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(screen_data_t); break; |
| 846 | |
| 847 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 848 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(apollo_mono19i); break; |
| 849 | case DEVINFO_FCT_STOP: /* Nothing */ break; |
| 850 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(apollo_mono19i); break; |
| 851 | |
| 852 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 853 | case DEVINFO_STR_NAME: strcpy(info->s, "Apollo 19\" Monochrome Screen"); break; |
| 854 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Terminal"); break; |
| 855 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 856 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 857 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break; |
| 858 | } |
| 859 | } |
| 860 | |
| 861 | DEVICE_GET_INFO( apollo_mono15i ) { |
| 862 | switch (state) { |
| 863 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 864 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 865 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(screen_data_t); break; |
| 866 | |
| 867 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 868 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(apollo_mono15i); break; |
| 869 | case DEVINFO_FCT_STOP: /* Nothing */ break; |
| 870 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(apollo_mono15i); break; |
| 871 | |
| 872 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 873 | case DEVINFO_STR_NAME: strcpy(info->s, "Apollo 15\" Monochrome Screen"); break; |
| 874 | case DEVINFO_STR_FAMILY: strcpy(info->s, "Terminal"); break; |
| 875 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 876 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 877 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break; |
| 878 | } |
| 879 | } |
| 880 | |
| 881 | DEFINE_LEGACY_DEVICE(APOLLO_MONO19I, apollo_mono19i); |
| 882 | DEFINE_LEGACY_DEVICE(APOLLO_MONO15I, apollo_mono15i); |
src/mess/drivers/apollo.c
| r0 | r14540 | |
| 1 | /* |
| 2 | * apollo.c - APOLLO DN3500/DN3000 driver |
| 3 | * |
| 4 | * Created on: May 12, 2010 |
| 5 | * Author: Hans Ostermeyer |
| 6 | * |
| 7 | * Released for general non-commercial use under the MAME license |
| 8 | * Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | * |
| 10 | * Adapted February 19, 2012 for general MAME/MESS standards by R. Belmont |
| 11 | * |
| 12 | * TODO: use MESS ram device and MCFG_RAM_* to handle RAM sizing. |
| 13 | * AT bus stuff indicates ISA compatibility? If so, convert to use MESS ISA bus infrastructure, including 3c505? |
| 14 | * Remove need for instruction hook. |
| 15 | * Convert to modern address map. |
| 16 | * |
| 17 | * see also: |
| 18 | * - Domain Series 3000/Series 4000 Hardware Architecture Handbook (Order No. 007861 Rev. 02) |
| 19 | * - Domain Personal Workstations and Servers Technical Reference (Apollo Order No. 008778-A01) |
| 20 | * - Servicing the Domain Personal Workstations and Servers (Apollo Order No. 007859-A01) |
| 21 | * - http://www.bitsavers.org/pdf/apollo/002398-04_Domain_Engineering_Handbook_Rev4_Jan87.pdf |
| 22 | * - http://www.bitsavers.org/pdf/apollo/008778-03_DOMAIN_Series_3000_4000_Technical_Reference_Aug87.pdf |
| 23 | * - http://www.bitsavers.org/pdf/apollo/AEGIS_Internals_and_Data_Structures_Jan86.pdf |
| 24 | * - http://www.bitsavers.org/pdf/apollo/019411-A00_Addendum_to_Domain_Personal_Workstations_and_Servers_Hardware_Architecture_Handbook_1991.pdf |
| 25 | * - data sheets from Intel and Motorola |
| 26 | */ |
| 27 | |
| 28 | #define VERBOSE 0 |
| 29 | |
| 30 | #include "includes/apollo.h" |
| 31 | #include "machine/apollo_kbd.h" |
| 32 | #include "machine/omti8621.h" |
| 33 | #include "machine/sc499.h" |
| 34 | #include "machine/3c505.h" |
| 35 | #include "machine/68681.h" |
| 36 | |
| 37 | #include "debugger.h" |
| 38 | |
| 39 | #include "cpu/m68000/m68000.h" |
| 40 | #include "cpu/m68000/m68kcpu.h" |
| 41 | |
| 42 | #include "machine/terminal.h" |
| 43 | #include "machine/ram.h" |
| 44 | |
| 45 | #include "sound/beep.h" |
| 46 | |
| 47 | #include "apollo_dsp.lh" |
| 48 | |
| 49 | // we use this to prevent excessive logging (if emulation runs amok) |
| 50 | // error.log will be 10 MB for 100000 lines |
| 51 | #define APOLLO_MAX_NO_OF_LOG_LINES 500000 |
| 52 | |
| 53 | #define ATBUS_IO_BASE 0x040000 |
| 54 | #define ATBUS_IO_END 0x05ffff |
| 55 | #define ATBUS_MEMORY_BASE 0x080000 |
| 56 | #define ATBUS_MEMORY_END 0xffffff |
| 57 | |
| 58 | #define DN3500_RAM_SIZE 16 // 8 or 16 MB |
| 59 | |
| 60 | #if DN3500_RAM_SIZE == 8 |
| 61 | #define DN3500_RAM_BASE 0x1000000 |
| 62 | #define DN3500_RAM_END 0x17fffff |
| 63 | #define DN3500_RAM_CONFIG_BYTE 0x64 // or 0xe8 |
| 64 | #else /* DN3500_RAM_SIZE == 16 */ |
| 65 | #define DN3500_RAM_BASE 0x1000000 |
| 66 | #define DN3500_RAM_END 0x1ffffff |
| 67 | #define DN3500_RAM_CONFIG_BYTE 0x60 // 4-4-4-4 |
| 68 | //#define DN3500_RAM_CONFIG_BYTE 0x14 // 8-8-0-0 |
| 69 | #endif |
| 70 | |
| 71 | #define DN3000_RAM_BASE 0x100000 |
| 72 | #define DN3000_RAM_END 0x8fffff |
| 73 | #define DN3000_RAM_CONFIG_8MB 0xA8 |
| 74 | |
| 75 | #define DN5500_RAM_SIZE 32 // 16 or 32 MB |
| 76 | |
| 77 | #if DN5500_RAM_SIZE == 16 |
| 78 | #define DN5500_RAM_BASE 0x1000000 |
| 79 | #define DN5500_RAM_END 0x1ffffff |
| 80 | #define DN5500_RAM_CONFIG_BYTE 0x14 // 8-8-0-0 |
| 81 | #define DN5500_MEM_PRESENT_BYTE 0xAA // 8-8-0-0 |
| 82 | #else /* DN5500_RAM_SIZE == 32 */ |
| 83 | #define DN5500_RAM_BASE 0x1000000 |
| 84 | #define DN5500_RAM_END 0x2ffffff |
| 85 | #define DN5500_RAM_CONFIG_BYTE 0x20 // 8-8-8-8 |
| 86 | #define DN5500_MEM_PRESENT_BYTE 0x00 // 8-8-8-8 |
| 87 | #endif |
| 88 | |
| 89 | #define NODE_TYPE_DN3000 3000 |
| 90 | #define NODE_TYPE_DN3500 3500 |
| 91 | #define NODE_TYPE_DN5500 5500 |
| 92 | #define NODE_TYPE_DSP3000 -3000 |
| 93 | #define NODE_TYPE_DSP3500 -3500 |
| 94 | #define NODE_TYPE_DSP5500 -5500 |
| 95 | |
| 96 | #define DEFAULT_NODE_ID 0x12345 |
| 97 | |
| 98 | static UINT8 cache_control_register = 0x00; |
| 99 | static UINT8 cache_status_register = 0xff; |
| 100 | static UINT8 task_alias_register = 0x00; |
| 101 | |
| 102 | static offs_t parity_error_offset = 0; |
| 103 | static UINT16 parity_error_byte_mask = 0; |
| 104 | static int parity_error_handler_is_installed = 0; |
| 105 | static int parity_error_handler_install_counter = 0; |
| 106 | |
| 107 | static UINT16 latch_page_on_parity_error_register = 0x0000; |
| 108 | static UINT16 master_req_register = 0x0000; |
| 109 | |
| 110 | // DN3000: Node Id 1D117 at 0x9600 - 0x961f |
| 111 | // DN3500: Node Id 2616D at 0x11200 - 0x1121f |
| 112 | |
| 113 | static UINT32 node_id = DEFAULT_NODE_ID; |
| 114 | |
| 115 | static UINT32 ram_base_address; |
| 116 | static UINT32 ram_end_address; |
| 117 | |
| 118 | static generic_ptr messram_ptr; |
| 119 | static size_t messram_size = 0; |
| 120 | |
| 121 | static int node_type; |
| 122 | |
| 123 | // FIXME: value of ram_config_byte must match with default/selected RAM size |
| 124 | static UINT8 ram_config_byte; |
| 125 | |
| 126 | static device_t *dsp_terminal = NULL; |
| 127 | |
| 128 | static UINT32 log_line_counter = 0; |
| 129 | |
| 130 | /*************************************************************************** |
| 131 | cpu_context - return a string describing which CPU is currently executing and their PC |
| 132 | ***************************************************************************/ |
| 133 | |
| 134 | const char *apollo_cpu_context(device_t *cpu) { |
| 135 | static char statebuf[64]; /* string buffer containing state description */ |
| 136 | |
| 137 | /* if we have an executing CPU, output data */ |
| 138 | if (cpu != NULL) { |
| 139 | osd_ticks_t t = osd_ticks(); |
| 140 | int s = t / osd_ticks_per_second(); |
| 141 | int ms = (t % osd_ticks_per_second()) / 1000; |
| 142 | |
| 143 | sprintf(statebuf, "%d.%03d %s pc=%08x", s, ms, cpu->tag(), cpu_get_previouspc(cpu)); |
| 144 | } else { |
| 145 | strcpy(statebuf, "(no context)"); |
| 146 | } |
| 147 | return statebuf; |
| 148 | } |
| 149 | |
| 150 | /*------------------------------------------------- |
| 151 | apollo_set_cpu_has_fpu - enable/disable the FPU |
| 152 | -------------------------------------------------*/ |
| 153 | |
| 154 | /*void apollo_set_cpu_has_fpu(device_t *device, int onoff) |
| 155 | { |
| 156 | if (device == NULL || (device->type() != M68020PMMU && device->type() != M68030)) |
| 157 | { |
| 158 | DLOG1(("set_cpu_has_fpu: unexpected CPU device")); |
| 159 | } |
| 160 | else |
| 161 | { |
| 162 | m68ki_cpu_core *cpu = (m68ki_cpu_core *) downcast<legacy_cpu_device *> (device)->token(); |
| 163 | cpu->has_fpu = onoff; |
| 164 | DLOG1(("set_cpu_has_fpu: FPU has been %s", onoff ? "enabled" : "disabled")); |
| 165 | } |
| 166 | }*/ |
| 167 | |
| 168 | /*************************************************************************** |
| 169 | apollo_check_log - check for excessive logging |
| 170 | ***************************************************************************/ |
| 171 | |
| 172 | void apollo_check_log() { |
| 173 | if (++log_line_counter >= APOLLO_MAX_NO_OF_LOG_LINES) { |
| 174 | fatalerror("apollo_check_log: maximum number of log lines exceeded.\n"); |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | /*************************************************************************** |
| 179 | apollo_is_dn3000 - return 1 if node is DN3000 or DSP3000, 0 otherwise |
| 180 | ***************************************************************************/ |
| 181 | |
| 182 | int apollo_is_dn3000(void) { |
| 183 | return node_type == NODE_TYPE_DN3000 || node_type == NODE_TYPE_DSP3000; |
| 184 | } |
| 185 | |
| 186 | /*************************************************************************** |
| 187 | apollo_is_dn5500 - return 1 if node is DN5500 or DSP5500, 0 otherwise |
| 188 | ***************************************************************************/ |
| 189 | |
| 190 | int apollo_is_dn5500(void) { |
| 191 | return node_type == NODE_TYPE_DN5500 || node_type == NODE_TYPE_DSP5500; |
| 192 | } |
| 193 | |
| 194 | /*************************************************************************** |
| 195 | apollo_is_dsp3x00 - return 1 if node is DSP3x00 or DSP5500, 0 otherwise |
| 196 | ***************************************************************************/ |
| 197 | |
| 198 | int apollo_is_dsp3x00(void) { |
| 199 | switch (node_type) |
| 200 | { |
| 201 | case NODE_TYPE_DSP3000: |
| 202 | case NODE_TYPE_DSP3500: |
| 203 | case NODE_TYPE_DSP5500: |
| 204 | return 1; |
| 205 | } |
| 206 | return 0; |
| 207 | } |
| 208 | |
| 209 | /*************************************************************************** |
| 210 | apollo_get_ram_config_byte - get the ram configuration byte |
| 211 | ***************************************************************************/ |
| 212 | |
| 213 | UINT8 apollo_get_ram_config_byte(void) { |
| 214 | return ram_config_byte; |
| 215 | } |
| 216 | |
| 217 | /*************************************************************************** |
| 218 | apollo_get_node_id - get the node id |
| 219 | ***************************************************************************/ |
| 220 | |
| 221 | UINT32 apollo_get_node_id(void) { |
| 222 | return node_id; |
| 223 | } |
| 224 | |
| 225 | /*************************************************************************** |
| 226 | apollo_instruction_hook |
| 227 | must be called by the CPU core before executing each instruction |
| 228 | ***************************************************************************/ |
| 229 | int apollo_instruction_hook(device_t *device, offs_t curpc) |
| 230 | { |
| 231 | m68ki_cpu_core *m68k = (m68ki_cpu_core *) downcast<legacy_cpu_device *> (device)->token(); |
| 232 | |
| 233 | static UINT16 idle_counter = 0; |
| 234 | |
| 235 | // m68k->ir still has previous instruction |
| 236 | UINT16 last_ir = m68k->ir; |
| 237 | |
| 238 | // get next instruction (or 0 if unavailable) |
| 239 | UINT16 next_ir = (m68k->pref_addr == REG_PC(m68k)) ? m68k->pref_data : 0; |
| 240 | |
| 241 | // check for NULLPROC: |
| 242 | // 027C F8FF AND.W #F8FF,SR |
| 243 | // 60FA BRA *-4 |
| 244 | |
| 245 | if ((next_ir == 0x60fa && last_ir == 0x027c) || (next_ir == 0x027c && last_ir == 0x60fa)) |
| 246 | { |
| 247 | // we are within the idle loop, slow down CPU to reduce power usage |
| 248 | m68k->remaining_cycles -= 500; |
| 249 | |
| 250 | if (apollo_config(APOLLO_CONF_IDLE_SLEEP) && apollo_is_dsp3x00() && ++idle_counter >= 1000) |
| 251 | { |
| 252 | // slow down even more on DSP3x00 |
| 253 | idle_counter -= 100; |
| 254 | // sleep 1 ms |
| 255 | osd_sleep(osd_ticks_per_second() / 1000); |
| 256 | } |
| 257 | } |
| 258 | else |
| 259 | { |
| 260 | // we are outside of the idle loop |
| 261 | idle_counter = 0; |
| 262 | } |
| 263 | |
| 264 | if (!m68k->has_fpu && !m68k->pmmu_enabled && (m68k->ir & 0xff00) == 0xf200) |
| 265 | { |
| 266 | // set APOLLO_CSR_SR_FP_TRAP in cpu status register for /sau7/self_test |
| 267 | apollo_csr_set_status_register(APOLLO_CSR_SR_FP_TRAP, APOLLO_CSR_SR_FP_TRAP); |
| 268 | } |
| 269 | |
| 270 | if (m68k->t1_flag && !m68k->s_flag) |
| 271 | { |
| 272 | // FIXME: trace emulation is disabled in m68kcpu.h; why??? |
| 273 | m68ki_exception_trace(m68k); |
| 274 | } |
| 275 | |
| 276 | return apollo_debug_instruction_hook(device, curpc); |
| 277 | } |
| 278 | |
| 279 | /*************************************************************************** |
| 280 | apollo bus error |
| 281 | ***************************************************************************/ |
| 282 | |
| 283 | static void apollo_bus_error(running_machine &machine) |
| 284 | { |
| 285 | cputag_set_input_line(machine, MAINCPU, M68K_LINE_BUSERROR, ASSERT_LINE); |
| 286 | cputag_set_input_line(machine, MAINCPU, M68K_LINE_BUSERROR, CLEAR_LINE); |
| 287 | |
| 288 | apollo_csr_set_status_register(APOLLO_CSR_SR_CPU_TIMEOUT, APOLLO_CSR_SR_CPU_TIMEOUT); |
| 289 | } |
| 290 | |
| 291 | static IRQ_CALLBACK(apollo_irq_acknowledge) { |
| 292 | int result = M68K_INT_ACK_AUTOVECTOR; |
| 293 | |
| 294 | cputag_set_input_line(device->machine(), MAINCPU, irqline, CLEAR_LINE); |
| 295 | |
| 296 | DLOG2(("apollo_irq_acknowledge: interrupt level=%d", irqline)); |
| 297 | |
| 298 | if (irqline == 6) { |
| 299 | result = apollo_pic_acknowledge(device, irqline); |
| 300 | } |
| 301 | return result; |
| 302 | } |
| 303 | |
| 304 | /*************************************************************************** |
| 305 | DN3500 Cache Control/Status Register at 0x10200 |
| 306 | ***************************************************************************/ |
| 307 | |
| 308 | static WRITE8_HANDLER(cache_control_register_w ) { |
| 309 | if (apollo_is_dn5500()) |
| 310 | { |
| 311 | SLOG1(("Error: writing DN5500 Cache Status Register at offset %02x = %02x", offset, data)); |
| 312 | } |
| 313 | else |
| 314 | { |
| 315 | cache_control_register = data; |
| 316 | cache_status_register = (cache_status_register & 0x7f) | (cache_control_register & 0x80); |
| 317 | SLOG2(("writing Cache Control Register at offset %02x = %02x", offset, data)); |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | static READ8_HANDLER( cache_status_register_r ) { |
| 322 | UINT8 data = cache_status_register; |
| 323 | |
| 324 | if (apollo_is_dn5500()) { |
| 325 | #define DN5500_CSR_NOT_HSI_PRESENT 8 |
| 326 | #define DN5500_CSR_MEM_TIME 1 |
| 327 | data |= DN5500_CSR_NOT_HSI_PRESENT; |
| 328 | } |
| 329 | |
| 330 | SLOG2(("reading Cache Status Register at offset %02x = %02x", offset, data)); |
| 331 | return data; |
| 332 | } |
| 333 | |
| 334 | void apollo_set_cache_status_register(UINT8 mask, UINT8 data) { |
| 335 | UINT16 new_value = (cache_status_register & ~mask) | (data & mask); |
| 336 | if (new_value != cache_status_register) { |
| 337 | cache_status_register = new_value; |
| 338 | LOG2(("setting Cache Status Register with data=%02x and mask=%02x to %02x", |
| 339 | data, mask, cache_status_register)); |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | /*************************************************************************** |
| 344 | DN3500 Task Alias Register at 0x10300 |
| 345 | ***************************************************************************/ |
| 346 | |
| 347 | static WRITE8_HANDLER(task_alias_register_w ) { |
| 348 | task_alias_register = data; |
| 349 | apollo_set_cache_status_register(0x07, data); |
| 350 | SLOG(("writing Task Alias Register at offset %02x = %02x",offset, data)); |
| 351 | } |
| 352 | |
| 353 | static READ8_HANDLER( task_alias_register_r ) { |
| 354 | UINT8 data = 0xff; |
| 355 | SLOG(("reading Task Alias Register at offset %02x = %02x", offset, data)); |
| 356 | return data; |
| 357 | } |
| 358 | |
| 359 | /*************************************************************************** |
| 360 | DN3000/DN3500 Node Id PROM at 0x9600/0x11200 |
| 361 | ***************************************************************************/ |
| 362 | |
| 363 | static WRITE16_HANDLER(apollo_node_id_w ) { |
| 364 | SLOG1(("Error: writing node id ROM at offset %02x = %04x & %04x", offset, data, mem_mask)); |
| 365 | } |
| 366 | |
| 367 | static READ16_HANDLER( apollo_node_id_r ) { |
| 368 | UINT16 data; |
| 369 | switch (offset & 0x0f) { |
| 370 | case 1: // msb |
| 371 | data = (node_id >> 16) & 0xff; |
| 372 | break; |
| 373 | case 2: |
| 374 | data = (node_id >> 8) & 0xff; |
| 375 | break; |
| 376 | case 3: // lsb |
| 377 | data = node_id & 0xff; |
| 378 | break; |
| 379 | case 15: // checksum |
| 380 | data = ((node_id >> 16) + (node_id >> 8) + node_id) & 0xff; |
| 381 | break; |
| 382 | default: |
| 383 | data = 0; |
| 384 | break; |
| 385 | } |
| 386 | data <<= 8; |
| 387 | SLOG2(("reading node id ROM at offset %02x = %04x & %04x", offset, data, mem_mask)); |
| 388 | return data; |
| 389 | } |
| 390 | |
| 391 | /*************************************************************************** |
| 392 | DN3000/DN3500 Latch Page on Parity Error Register at 0x9300/0x11300 |
| 393 | ***************************************************************************/ |
| 394 | |
| 395 | static WRITE16_HANDLER(latch_page_on_parity_error_register_w ) { |
| 396 | latch_page_on_parity_error_register = data; |
| 397 | SLOG1(("writing Latch Page on Error Parity Register at offset %02x = %04x", offset*2, data)); |
| 398 | } |
| 399 | |
| 400 | static READ16_HANDLER( latch_page_on_parity_error_register_r ) { |
| 401 | UINT16 data = latch_page_on_parity_error_register; |
| 402 | SLOG2(("reading Latch Page on Error Parity Register at offset %02x = %04x", offset*2, data)); |
| 403 | return data; |
| 404 | } |
| 405 | |
| 406 | /*************************************************************************** |
| 407 | DN3500 Master REQ Register at 0x11600 |
| 408 | ***************************************************************************/ |
| 409 | |
| 410 | static WRITE8_HANDLER(master_req_register_w ) { |
| 411 | master_req_register = data; |
| 412 | SLOG2(("writing Master REQ Register at offset %02x = %02x", offset, data)); |
| 413 | } |
| 414 | |
| 415 | static READ8_HANDLER( master_req_register_r ) { |
| 416 | UINT8 data = 0xff; |
| 417 | SLOG1(("reading Master REQ Register at offset %02x = %02x", offset, data)); |
| 418 | return data; |
| 419 | } |
| 420 | |
| 421 | /*************************************************************************** |
| 422 | DN3500 Selective Clear Locations at 0x11600 |
| 423 | ***************************************************************************/ |
| 424 | |
| 425 | static WRITE16_HANDLER(selective_clear_locations_w ) { |
| 426 | SLOG2(("writing Selective Clear Locations at offset %02x = %02x", offset*2, data)); |
| 427 | switch (offset * 2) { |
| 428 | case 0x00: // Clear All |
| 429 | apollo_csr_set_status_register(APOLLO_CSR_SR_CLEAR_ALL, 0); |
| 430 | break; |
| 431 | case 0x04: // clear floating-point trap |
| 432 | apollo_csr_set_status_register(APOLLO_CSR_SR_FP_TRAP, 0); |
| 433 | break; |
| 434 | case 0x06: // clear Parity error interrupt |
| 435 | apollo_csr_set_status_register(APOLLO_CSR_SR_PARITY_BYTE_MASK, 0); |
| 436 | break; |
| 437 | case 0x08: // clear Bus Error Status (CPU Timeout) |
| 438 | apollo_csr_set_status_register(APOLLO_CSR_SR_CPU_TIMEOUT, 0); |
| 439 | break; |
| 440 | case 0x0e: // Clear (Flush) Cache |
| 441 | break; |
| 442 | } |
| 443 | } |
| 444 | |
| 445 | static READ16_HANDLER(selective_clear_locations_r ) { |
| 446 | UINT16 data = 0xffff; |
| 447 | SLOG1(("reading Selective Clear Locations at offset %02x = %02x", offset*2, data)); |
| 448 | return data; |
| 449 | } |
| 450 | |
| 451 | /*************************************************************************** |
| 452 | DN3000/DN3500 RAM with parity (and null proc loop delay for DomainOS) |
| 453 | ***************************************************************************/ |
| 454 | |
| 455 | static READ32_HANDLER( ram_with_parity_r ) { |
| 456 | UINT32 data = messram_ptr.u32[parity_error_offset+offset]; |
| 457 | |
| 458 | SLOG2(("memory dword read with parity error at %08x = %08x & %08x parity_byte=%04x", |
| 459 | ram_base_address + parity_error_offset*4 + offset*4,data, mem_mask, parity_error_byte_mask)); |
| 460 | |
| 461 | if (parity_error_byte_mask != 0) { |
| 462 | latch_page_on_parity_error_register = (ram_base_address + parity_error_offset * 4) >> 10; |
| 463 | |
| 464 | apollo_csr_set_status_register(APOLLO_CSR_CR_PARITY_BYTE_MASK, apollo_csr_get_status_register() |parity_error_byte_mask); |
| 465 | |
| 466 | if (apollo_csr_get_control_register() & APOLLO_CSR_CR_INTERRUPT_ENABLE) { |
| 467 | // force parity error (if NMI is enabled) |
| 468 | // cpu_set_input_line_and_vector(&space->device(), 7, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR); |
| 469 | cputag_set_input_line_and_vector(space->machine(), MAINCPU, 7, ASSERT_LINE, M68K_INT_ACK_AUTOVECTOR); |
| 470 | |
| 471 | } |
| 472 | } |
| 473 | return data; |
| 474 | } |
| 475 | |
| 476 | static WRITE32_HANDLER( ram_with_parity_w ) { |
| 477 | |
| 478 | COMBINE_DATA(messram_ptr.u32+offset); |
| 479 | |
| 480 | if (apollo_csr_get_control_register() & APOLLO_CSR_CR_FORCE_BAD_PARITY) { |
| 481 | parity_error_byte_mask = (apollo_csr_get_control_register() |
| 482 | & APOLLO_CSR_CR_PARITY_BYTE_MASK); |
| 483 | |
| 484 | if (!apollo_is_dn3000()) { |
| 485 | parity_error_byte_mask ^= APOLLO_CSR_CR_PARITY_BYTE_MASK; |
| 486 | } |
| 487 | |
| 488 | parity_error_offset = offset; |
| 489 | |
| 490 | // SLOG1(("memory dword write with parity to %08x = %08x & %08x parity_byte=%04x", |
| 491 | // ram_base_address +offset * 4, data, mem_mask, parity_error_byte_mask)); |
| 492 | |
| 493 | if (parity_error_handler_is_installed == 0) { |
| 494 | // no more than 192 read/write handlers may be used |
| 495 | // see table_assign_handler in memory.c |
| 496 | if (parity_error_handler_install_counter < 40) { |
| 497 | //memory_install_read32_handler(space, ram_base_address+offset*4, ram_base_address+offset*4+3, 0xffffffff, 0, ram_with_parity_r); |
| 498 | space->install_legacy_read_handler(ram_base_address+offset*4, ram_base_address+offset*4+3, 0xffffffff,0,FUNC(ram_with_parity_r)); |
| 499 | parity_error_handler_is_installed = 1; |
| 500 | parity_error_handler_install_counter++; |
| 501 | } |
| 502 | } |
| 503 | } else if (parity_error_handler_is_installed && offset == parity_error_offset) { |
| 504 | SLOG1(("memory dword write with parity to %08x = %08x & %08x reset %d", |
| 505 | ram_base_address +parity_error_offset*4, data, mem_mask, parity_error_handler_install_counter)); |
| 506 | |
| 507 | // uninstall not supported, reinstall previous read handler instead |
| 508 | |
| 509 | // memory_install_rom(space, ram_base_address, ram_end_address, 0xffffffff, 0, messram_ptr.v); |
| 510 | space->install_rom(ram_base_address,ram_end_address,0xffffffff,0,messram_ptr.v); |
| 511 | |
| 512 | parity_error_handler_is_installed = 0; |
| 513 | parity_error_byte_mask = 0; |
| 514 | } |
| 515 | } |
| 516 | |
| 517 | /*************************************************************************** |
| 518 | DN3000/DN3500 unmapped memory |
| 519 | ***************************************************************************/ |
| 520 | |
| 521 | static READ32_HANDLER( apollo_unmapped_r ) |
| 522 | { |
| 523 | offs_t address = offset * 4; |
| 524 | |
| 525 | m68ki_cpu_core *m68k = (m68ki_cpu_core *) downcast<legacy_cpu_device *>(&space->device())->token(); |
| 526 | |
| 527 | if ((address & 0xfff00000) == 0xfa800000 && VERBOSE < 2) { |
| 528 | // ? |
| 529 | } else if ((address & 0xfff00ff7) == 0xfd800000 && VERBOSE < 2) { |
| 530 | // omit logging for memory sizing in FPA address space |
| 531 | // strange: MD seems to search for the 3C505 Boot ROM |
| 532 | // note (6.10.2010): might be color7 address space (!?!) |
| 533 | } else if ((address & 0xfc03ffff) == 0x00000000 && VERBOSE < 2) { |
| 534 | // omit logging for memory sizing in standalone utilities |
| 535 | } else if (address == 0xfff90000 && VERBOSE < 2) { |
| 536 | // omit logging for FPA trial access |
| 537 | } else if (address == 0x00030000 && VERBOSE < 2) { |
| 538 | // omit logging for Bus error test address in DN3500 boot prom and self_test |
| 539 | } else if (address == 0x0000ac00 && VERBOSE < 2) { |
| 540 | // omit logging for Bus error test address in DN3000 boot prom |
| 541 | } else { |
| 542 | SLOG1(("unmapped memory dword read from %08x with mask %08x (ir=%04x)", address , mem_mask, m68k->ir)); |
| 543 | } |
| 544 | |
| 545 | // if (address == 0xfffffffc) { |
| 546 | // // temporary hack for disp7d.dex @ 010456D8 |
| 547 | // return 0xffffffff; |
| 548 | // } |
| 549 | /* unmapped; access causes a bus error */ |
| 550 | apollo_bus_error(space->machine()); |
| 551 | |
| 552 | return 0xffffffff; |
| 553 | } |
| 554 | |
| 555 | static WRITE32_HANDLER( apollo_unmapped_w ) |
| 556 | { |
| 557 | SLOG(("unmapped memory dword write to %08x = %08x & %08x", offset * 4, data, mem_mask)); |
| 558 | |
| 559 | /* unmapped; access causes a bus error */ |
| 560 | apollo_bus_error(space->machine()); |
| 561 | } |
| 562 | |
| 563 | /*************************************************************************** |
| 564 | DN3000/DN3500 ROM write |
| 565 | ***************************************************************************/ |
| 566 | |
| 567 | static WRITE32_HANDLER( apollo_rom_w ) |
| 568 | { |
| 569 | offs_t address = offset * 4; |
| 570 | offs_t pc = cpu_get_previouspc(&space->device()); |
| 571 | |
| 572 | if (pc == 0x00002c1c && address == 0x00000004 && VERBOSE < 2) { |
| 573 | // don't log invalid code in 3500_boot_12191_7.bin |
| 574 | } else { |
| 575 | SLOG1(("ROM dword write to %08x = %08x & %08x", offset * 4, data, mem_mask)); |
| 576 | } |
| 577 | } |
| 578 | |
| 579 | /*************************************************************************** |
| 580 | DN3000/DN3500 AT Bus I/O space |
| 581 | ***************************************************************************/ |
| 582 | |
| 583 | static READ16_HANDLER( apollo_atbus_io_r ) { |
| 584 | UINT16 data = 0xffff; |
| 585 | offs_t address = ATBUS_IO_BASE + offset * 2; |
| 586 | |
| 587 | switch (address & ~7) { |
| 588 | case 0x04d000: /* Fixed Disk Controller 1 */ |
| 589 | case 0x04d400: /* Fixed Disk Controller 2 */ |
| 590 | case 0x050000: /* Tape Controller */ |
| 591 | case 0x054000: /* domain_os at 0x3C4BF15A ? */ |
| 592 | case 0x054400: /* domain_os at 0x3C4BF1A8 ? */ |
| 593 | case 0x054800: /* domain_os at 0x3C4BF15A ? */ |
| 594 | case 0x054c00: /* domain_os at 0x3C4BF1A8 ? */ |
| 595 | case 0x055808: /* domain_os at 0x3C4C4784 ? */ |
| 596 | case 0x055c08: /* domain_os at 0x3C4C4784 ? */ |
| 597 | case 0x058800: /* alternate 802.3 Network Controller */ |
| 598 | case 0x059000: /* Apollo Token Ring Controller 0 */ |
| 599 | case 0x05a000: /* alternate Network Controller */ |
| 600 | case 0x05d800: /* alternate color or mono graphics */ |
| 601 | case 0x05dc00: /* alternate color or mono graphics */ |
| 602 | case 0x05e800: /* alternate mono or color graphics */ |
| 603 | case 0x05ec00: /* alternate mono or color graphics */ |
| 604 | // omit logging |
| 605 | break; |
| 606 | default: |
| 607 | SLOG1(("AT Bus I/O word read from %08x = %04x & %04x", address, data, mem_mask)); |
| 608 | } |
| 609 | |
| 610 | // set bit AT-Compatible I/O Timeout in CPU Status Register |
| 611 | // Note: should be set for broken hardware only |
| 612 | // apollo_csr_set_status_register(APOLLO_CSR_SR_ATBUS_IO_TIMEOUT, APOLLO_CSR_SR_ATBUS_IO_TIMEOUT); |
| 613 | return data; |
| 614 | } |
| 615 | |
| 616 | static WRITE16_HANDLER( apollo_atbus_io_w ) { |
| 617 | offs_t address = ATBUS_IO_BASE + offset * 2; |
| 618 | |
| 619 | switch (address & ~7) { |
| 620 | case 0x04d000: /* Fixed Disk Controller 1 */ |
| 621 | case 0x04d400: /* Fixed Disk Controller 2 */ |
| 622 | case 0x050000: /* Tape Controller */ |
| 623 | case 0x054000: /* domain_os at 0x3C4BF15A ? */ |
| 624 | case 0x054400: /* domain_os at 0x3C4BF1A8 ? */ |
| 625 | case 0x054800: /* domain_os at 0x3C4BF15A ? */ |
| 626 | case 0x054c00: /* domain_os at 0x3C4BF1A8 ? */ |
| 627 | case 0x058800: /* alternate 802.3 Network Controller */ |
| 628 | case 0x059000: /* Apollo Token Ring Controller 0 */ |
| 629 | case 0x05a000: /* alternate Network Controller */ |
| 630 | case 0x05d800: /* alternate color or mono graphics */ |
| 631 | case 0x05dc00: /* alternate color or mono graphics */ |
| 632 | case 0x05e800: /* alternate mono or color graphics */ |
| 633 | case 0x05ec00: /* alternate mono or color graphics */ |
| 634 | // omit logging |
| 635 | break; |
| 636 | default: |
| 637 | SLOG1(("AT Bus I/O word write to %08x = %04x & %04x ", |
| 638 | ATBUS_IO_BASE+ offset * 2, data, mem_mask)) |
| 639 | ; |
| 640 | } |
| 641 | |
| 642 | // set bit AT-Compatible I/O Timeout in CPU Status Register |
| 643 | // Note: should be set for broken hardware only |
| 644 | // apollo_csr_set_status_register(APOLLO_CSR_SR_ATBUS_IO_TIMEOUT, APOLLO_CSR_SR_ATBUS_IO_TIMEOUT); |
| 645 | } |
| 646 | |
| 647 | /*************************************************************************** |
| 648 | DN3000/DN3500 AT Bus memory space |
| 649 | ***************************************************************************/ |
| 650 | |
| 651 | static READ32_HANDLER( apollo_atbus_memory_r ) { |
| 652 | UINT32 data = 0xffffffff; |
| 653 | offs_t address = ATBUS_MEMORY_BASE + offset * 4; |
| 654 | if (VERBOSE < 2 && (address & 0xfff) == 0 && address >= 0x80000 && address < 0x1000000) { |
| 655 | // omit logging for memory sizing the AT Bus memory |
| 656 | } else { |
| 657 | SLOG1(("AT Bus memory dword read from %08x = %08x & %08x",address, data, mem_mask)); |
| 658 | } |
| 659 | |
| 660 | // set bit AT-Compatible Memory Timeout in CPU Status Register |
| 661 | // Note: should be set for broken hardware only |
| 662 | // apollo_csr_set_status_register(APOLLO_CSR_SR_ATBUS_MEM_TIMEOUT, APOLLO_CSR_SR_ATBUS_MEM_TIMEOUT); |
| 663 | |
| 664 | return data; |
| 665 | } |
| 666 | |
| 667 | static WRITE32_HANDLER( apollo_atbus_memory_w ) { |
| 668 | SLOG1(("AT Bus memory dword write to %08x = %08x & %08x ", |
| 669 | ATBUS_MEMORY_BASE+offset * 4, data, mem_mask)); |
| 670 | |
| 671 | // set bit AT-Compatible Memory Timeout in CPU Status Register |
| 672 | // Note: should be set for broken hardware only |
| 673 | // apollo_csr_set_status_register(APOLLO_CSR_SR_ATBUS_MEM_TIMEOUT, APOLLO_CSR_SR_ATBUS_MEM_TIMEOUT); |
| 674 | } |
| 675 | |
| 676 | /*************************************************************************** |
| 677 | DN5500 Memory Present Register at 0x11400-0x114ff |
| 678 | Strange: documented but not used |
| 679 | ***************************************************************************/ |
| 680 | |
| 681 | static WRITE8_HANDLER( dn5500_memory_present_register_w ) { |
| 682 | SLOG(("Error: writing DN5500 Memory Present Register at offset %02x = %02x", offset, data)); |
| 683 | } |
| 684 | |
| 685 | static READ8_HANDLER( dn5500_memory_present_register_r ) { |
| 686 | UINT8 data = DN5500_MEM_PRESENT_BYTE; |
| 687 | SLOG(("reading DN5500 Memory Present Register at offset %02x = %02x", offset, data)); |
| 688 | return data; |
| 689 | } |
| 690 | |
| 691 | /*************************************************************************** |
| 692 | DN5500 11500 Registers at 0x11500-0x115ff (undocumented, what does it do?) |
| 693 | ***************************************************************************/ |
| 694 | |
| 695 | static WRITE8_HANDLER( dn5500_11500_w ) { |
| 696 | SLOG1(("writing DN5500 11500 at offset %02x = %02x", offset, data)); |
| 697 | } |
| 698 | |
| 699 | static READ8_HANDLER( dn5500_11500_r ) { |
| 700 | UINT8 data = 0xff; |
| 701 | SLOG1(("reading DN5500 11500 at offset %02x = %02x", offset, data)); |
| 702 | return data; |
| 703 | } |
| 704 | |
| 705 | /*************************************************************************** |
| 706 | DN5500 I/O Protection Map at 0x7000000-0x700FFFF |
| 707 | ***************************************************************************/ |
| 708 | |
| 709 | static WRITE8_HANDLER(dn5500_io_protection_map_w ) { |
| 710 | // TODO |
| 711 | SLOG1(("writing DN5500 I/O Protection Map at offset %02x = %02x", offset, data)); |
| 712 | } |
| 713 | |
| 714 | static READ8_HANDLER( dn5500_io_protection_map_r ) { |
| 715 | UINT8 data = 0xff; |
| 716 | SLOG1(("reading DN5500 I/O Protection Map at offset %02x = %02x", offset, data)); |
| 717 | return data; |
| 718 | } |
| 719 | |
| 720 | #if 0 |
| 721 | /*************************************************************************** |
| 722 | DN3000/DN3500 at f8000000 - ffffffff (used by fpa and/or color7?) |
| 723 | ***************************************************************************/ |
| 724 | |
| 725 | static READ32_HANDLER( apollo_f8_r ) { |
| 726 | offs_t address = 0xf8000000 + offset * 4; |
| 727 | UINT32 data = 0xffffffff; |
| 728 | SLOG2(("unexpected memory dword read from %08x = %08x & %08x", |
| 729 | address, data, mem_mask)); |
| 730 | return data; |
| 731 | } |
| 732 | |
| 733 | static WRITE32_HANDLER( apollo_f8_w ) { |
| 734 | offs_t address = 0xf8000000 +offset * 4; |
| 735 | |
| 736 | SLOG2(("unexpected memory dword write to %08x = %08x & %08x", |
| 737 | address, data, mem_mask)); |
| 738 | } |
| 739 | #endif |
| 740 | |
| 741 | /*************************************************************************** |
| 742 | ADDRESS MAPS |
| 743 | ***************************************************************************/ |
| 744 | |
| 745 | static ADDRESS_MAP_START(dn3500_map, AS_PROGRAM, 32) |
| 746 | AM_RANGE(0x000000, 0x00ffff) AM_ROM /* boot ROM */ |
| 747 | AM_RANGE(0x000000, 0x00ffff) AM_WRITE(apollo_rom_w) |
| 748 | AM_RANGE(0x010000, 0x0100ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff) |
| 749 | AM_RANGE(0x010100, 0x0101ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff) |
| 750 | AM_RANGE(0x010200, 0x0102ff) AM_READWRITE8( cache_status_register_r, cache_control_register_w, 0xffffffff ) |
| 751 | AM_RANGE(0x010300, 0x0103ff) AM_READWRITE8( task_alias_register_r , task_alias_register_w , 0xffffffff ) |
| 752 | AM_RANGE(0x010400, 0x0104ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff ) |
| 753 | AM_RANGE(0x010500, 0x0105ff) AM_DEVREADWRITE8( APOLLO_SIO2_TAG, apollo_sio2_r, apollo_sio2_w, 0xffffffff ) |
| 754 | AM_RANGE(0x010800, 0x0108ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff ) |
| 755 | AM_RANGE(0x010900, 0x0109ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff ) |
| 756 | AM_RANGE(0x010c00, 0x010cff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff ) |
| 757 | AM_RANGE(0x010d00, 0x010dff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff ) |
| 758 | AM_RANGE(0x011000, 0x0110ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff) |
| 759 | AM_RANGE(0x011100, 0x0111ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff) |
| 760 | AM_RANGE(0x011200, 0x0112ff) AM_READWRITE16( apollo_node_id_r, apollo_node_id_w, 0xffffffff) |
| 761 | AM_RANGE(0x011300, 0x0113ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff ) |
| 762 | AM_RANGE(0x011600, 0x0116ff) AM_READWRITE8( master_req_register_r, master_req_register_w, 0xffffffff) |
| 763 | |
| 764 | AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16( selective_clear_locations_r, selective_clear_locations_w, 0xffffffff ) |
| 765 | AM_RANGE(0x017000, 0x017fff) AM_READWRITE16( apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff ) |
| 766 | |
| 767 | AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff) |
| 768 | AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff) |
| 769 | AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff) |
| 770 | AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff) |
| 771 | |
| 772 | AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff) |
| 773 | AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff) |
| 774 | |
| 775 | AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff) |
| 776 | |
| 777 | AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM */ |
| 778 | |
| 779 | // FIXME: must match with RAM size in driver/apollo_sio.c |
| 780 | // AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */ |
| 781 | AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) |
| 782 | |
| 783 | AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w) |
| 784 | |
| 785 | // AM_RANGE(0x03020000, 0x0303ffff) Cache Tag Store (DN4500 only) |
| 786 | // AM_RANGE(0x04000000, 0x0400ffff) Cache Tag Data (DN4500 only) |
| 787 | // AM_RANGE(0x0e000000, 0x0fffffff) FPA address space |
| 788 | |
| 789 | // AM_RANGE(0xf8000000, 0xffffffff) AM_READWRITE(apollo_f8_r, apollo_f8_w) |
| 790 | AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w) |
| 791 | ADDRESS_MAP_END |
| 792 | |
| 793 | static ADDRESS_MAP_START(dsp3500_map, AS_PROGRAM, 32) |
| 794 | AM_RANGE(0x000000, 0x00ffff) AM_ROM /* boot ROM */ |
| 795 | AM_RANGE(0x000000, 0x00ffff) AM_WRITE(apollo_rom_w) |
| 796 | AM_RANGE(0x010000, 0x0100ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff) |
| 797 | AM_RANGE(0x010100, 0x0101ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff) |
| 798 | AM_RANGE(0x010200, 0x0102ff) AM_READWRITE8( cache_status_register_r, cache_control_register_w, 0xffffffff ) |
| 799 | AM_RANGE(0x010300, 0x0103ff) AM_READWRITE8( task_alias_register_r , task_alias_register_w , 0xffffffff ) |
| 800 | AM_RANGE(0x010400, 0x0104ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff ) |
| 801 | AM_RANGE(0x010500, 0x0105ff) AM_DEVREADWRITE8( APOLLO_SIO2_TAG, apollo_sio2_r, apollo_sio2_w, 0xffffffff ) |
| 802 | AM_RANGE(0x010800, 0x0108ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff ) |
| 803 | AM_RANGE(0x010900, 0x0109ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff ) |
| 804 | AM_RANGE(0x010c00, 0x010cff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff ) |
| 805 | AM_RANGE(0x010d00, 0x010dff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff ) |
| 806 | AM_RANGE(0x011000, 0x0110ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff) |
| 807 | AM_RANGE(0x011100, 0x0111ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff) |
| 808 | AM_RANGE(0x011200, 0x0112ff) AM_READWRITE16( apollo_node_id_r, apollo_node_id_w, 0xffffffff) |
| 809 | AM_RANGE(0x011300, 0x0113ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff ) |
| 810 | AM_RANGE(0x011600, 0x0116ff) AM_READWRITE8( master_req_register_r, master_req_register_w, 0xffffffff) |
| 811 | |
| 812 | AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16( selective_clear_locations_r, selective_clear_locations_w, 0xffffffff ) |
| 813 | AM_RANGE(0x017000, 0x017fff) AM_READWRITE16( apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff ) |
| 814 | |
| 815 | AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff) |
| 816 | AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff) |
| 817 | AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff) |
| 818 | AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff) |
| 819 | |
| 820 | // AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff) |
| 821 | // AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff) |
| 822 | |
| 823 | AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff) |
| 824 | |
| 825 | AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM */ |
| 826 | |
| 827 | // FIXME: must match with RAM size in driver/apollo_sio.c |
| 828 | // AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */ |
| 829 | AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) |
| 830 | |
| 831 | AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w) |
| 832 | |
| 833 | // AM_RANGE(0xf8000000, 0xffffffff) AM_READWRITE(apollo_f8_r, apollo_f8_w) |
| 834 | AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w) |
| 835 | ADDRESS_MAP_END |
| 836 | |
| 837 | static ADDRESS_MAP_START(dn3000_map, AS_PROGRAM, 32) |
| 838 | AM_RANGE(0x000000, 0x007fff) AM_ROM /* boot ROM */ |
| 839 | AM_RANGE(0x000000, 0x007fff) AM_WRITE(apollo_rom_w) |
| 840 | AM_RANGE(0x008000, 0x0080ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff) |
| 841 | AM_RANGE(0x008100, 0x0081ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff) |
| 842 | AM_RANGE(0x008400, 0x0087ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff ) |
| 843 | AM_RANGE(0x008800, 0x0088ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff ) |
| 844 | AM_RANGE(0x008900, 0x0089ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff ) |
| 845 | |
| 846 | AM_RANGE(0x009000, 0x0090ff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff ) |
| 847 | AM_RANGE(0x009100, 0x0091ff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff ) |
| 848 | AM_RANGE(0x009200, 0x0092ff) AM_READWRITE8( apollo_dma_page_register_r, apollo_dma_page_register_w, 0xffffffff ) |
| 849 | AM_RANGE(0x009300, 0x0093ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff ) |
| 850 | AM_RANGE(0x009400, 0x0094ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff) |
| 851 | AM_RANGE(0x009500, 0x0095ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff) |
| 852 | AM_RANGE(0x009600, 0x0096ff) AM_READWRITE16(apollo_node_id_r, apollo_node_id_w, 0xffffffff) |
| 853 | |
| 854 | AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff) |
| 855 | AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff) |
| 856 | AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff) |
| 857 | AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff) |
| 858 | |
| 859 | AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff) |
| 860 | AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff) |
| 861 | |
| 862 | AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff) |
| 863 | |
| 864 | AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM */ |
| 865 | |
| 866 | // FIXME: must match with RAM size in driver/apollo_sio.c |
| 867 | // AM_RANGE(DN3000_RAM_BASE, DN3000_RAM_END) AM_RAM AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */ |
| 868 | AM_RANGE(DN3000_RAM_BASE, DN3000_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) |
| 869 | |
| 870 | AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w) |
| 871 | |
| 872 | AM_RANGE(0x000000, 0xffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w) |
| 873 | ADDRESS_MAP_END |
| 874 | |
| 875 | static ADDRESS_MAP_START(dsp3000_map, AS_PROGRAM, 32) |
| 876 | AM_RANGE(0x000000, 0x007fff) AM_ROM /* boot ROM */ |
| 877 | AM_RANGE(0x000000, 0x007fff) AM_WRITE(apollo_rom_w) |
| 878 | AM_RANGE(0x008000, 0x0080ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff) |
| 879 | AM_RANGE(0x008100, 0x0081ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff) |
| 880 | AM_RANGE(0x008400, 0x0087ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff ) |
| 881 | AM_RANGE(0x008800, 0x0088ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff ) |
| 882 | AM_RANGE(0x008900, 0x0089ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff ) |
| 883 | |
| 884 | AM_RANGE(0x009000, 0x0090ff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff ) |
| 885 | AM_RANGE(0x009100, 0x0091ff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff ) |
| 886 | AM_RANGE(0x009200, 0x0092ff) AM_READWRITE8( apollo_dma_page_register_r, apollo_dma_page_register_w, 0xffffffff ) |
| 887 | AM_RANGE(0x009300, 0x0093ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff ) |
| 888 | AM_RANGE(0x009400, 0x0094ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff) |
| 889 | AM_RANGE(0x009500, 0x0095ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff) |
| 890 | AM_RANGE(0x009600, 0x0096ff) AM_READWRITE16(apollo_node_id_r, apollo_node_id_w, 0xffffffff) |
| 891 | |
| 892 | AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff) |
| 893 | AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff) |
| 894 | AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff) |
| 895 | AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff) |
| 896 | |
| 897 | // AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff) |
| 898 | // AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff) |
| 899 | |
| 900 | AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff) |
| 901 | |
| 902 | AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM */ |
| 903 | |
| 904 | // FIXME: must match with RAM size in driver/apollo_sio.c |
| 905 | // AM_RANGE(DN3000_RAM_BASE, DN3000_RAM_END) AM_RAM AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */ |
| 906 | AM_RANGE(DN3000_RAM_BASE, DN3000_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) |
| 907 | |
| 908 | AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w) |
| 909 | |
| 910 | AM_RANGE(0x000000, 0xffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w) |
| 911 | ADDRESS_MAP_END |
| 912 | |
| 913 | |
| 914 | static ADDRESS_MAP_START(dn5500_map, AS_PROGRAM, 32) |
| 915 | AM_RANGE(0x000000, 0x00ffff) AM_ROM /* boot ROM */ |
| 916 | AM_RANGE(0x000000, 0x00ffff) AM_WRITE(apollo_rom_w) |
| 917 | AM_RANGE(0x010000, 0x0100ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff) |
| 918 | AM_RANGE(0x010100, 0x0101ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff) |
| 919 | AM_RANGE(0x010200, 0x0102ff) AM_READWRITE8( cache_status_register_r, cache_control_register_w, 0xffffffff ) |
| 920 | AM_RANGE(0x010300, 0x0103ff) AM_READWRITE8( task_alias_register_r , task_alias_register_w , 0xffffffff ) |
| 921 | AM_RANGE(0x010400, 0x0104ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff ) |
| 922 | AM_RANGE(0x010500, 0x0105ff) AM_DEVREADWRITE8( APOLLO_SIO2_TAG, apollo_sio2_r, apollo_sio2_w, 0xffffffff ) |
| 923 | AM_RANGE(0x010800, 0x0108ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff ) |
| 924 | AM_RANGE(0x010900, 0x0109ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff ) |
| 925 | AM_RANGE(0x010c00, 0x010cff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff ) |
| 926 | AM_RANGE(0x010d00, 0x010dff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff ) |
| 927 | AM_RANGE(0x011000, 0x0110ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff) |
| 928 | AM_RANGE(0x011100, 0x0111ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff) |
| 929 | AM_RANGE(0x011200, 0x0112ff) AM_READWRITE16( apollo_node_id_r, apollo_node_id_w, 0xffffffff) |
| 930 | AM_RANGE(0x011300, 0x0113ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff ) |
| 931 | AM_RANGE(0x011400, 0x0114ff) AM_READWRITE8( dn5500_memory_present_register_r, dn5500_memory_present_register_w, 0xffffffff ) |
| 932 | AM_RANGE(0x011500, 0x0115ff) AM_READWRITE8( dn5500_11500_r, dn5500_11500_w, 0xffffffff ) |
| 933 | AM_RANGE(0x011600, 0x0116ff) AM_READWRITE8( master_req_register_r, master_req_register_w, 0xffffffff) |
| 934 | |
| 935 | AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16( selective_clear_locations_r, selective_clear_locations_w, 0xffffffff ) |
| 936 | AM_RANGE(0x017000, 0x017fff) AM_READWRITE16( apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff ) |
| 937 | |
| 938 | AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff) |
| 939 | AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff) |
| 940 | AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff) |
| 941 | AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff) |
| 942 | |
| 943 | AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff) |
| 944 | AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff) |
| 945 | |
| 946 | AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff) |
| 947 | |
| 948 | AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM */ |
| 949 | |
| 950 | // FIXME: must match with RAM size in driver/apollo_sio.c |
| 951 | // AM_RANGE(DN3500_RAM_BASE, DN3500_RAM_END) AM_RAM AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) /* 8MB RAM */ |
| 952 | AM_RANGE(DN5500_RAM_BASE, DN5500_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) |
| 953 | |
| 954 | AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w) |
| 955 | |
| 956 | // AM_RANGE(0x03020000, 0x0303ffff) Cache Tag Store (DN4500 only) |
| 957 | // AM_RANGE(0x04000000, 0x0400ffff) Cache Tag Data (DN4500 only) |
| 958 | AM_RANGE(0x07000000, 0x0700FFFF) AM_READWRITE8( dn5500_io_protection_map_r, dn5500_io_protection_map_w, 0xffffffff ) |
| 959 | // AM_RANGE(0x0e000000, 0x0fffffff) FPA address space |
| 960 | |
| 961 | // AM_RANGE(0xf8000000, 0xffffffff) AM_READWRITE(apollo_f8_r, apollo_f8_w) |
| 962 | AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w) |
| 963 | ADDRESS_MAP_END |
| 964 | |
| 965 | |
| 966 | static ADDRESS_MAP_START(dsp5500_map, AS_PROGRAM, 32) |
| 967 | AM_RANGE(0x000000, 0x00ffff) AM_ROM /* boot ROM */ |
| 968 | AM_RANGE(0x000000, 0x00ffff) AM_WRITE(apollo_rom_w) |
| 969 | AM_RANGE(0x010000, 0x0100ff) AM_READWRITE16(apollo_csr_status_register_r, apollo_csr_status_register_w, 0xffffffff) |
| 970 | AM_RANGE(0x010100, 0x0101ff) AM_READWRITE16(apollo_csr_control_register_r, apollo_csr_control_register_w, 0xffffffff) |
| 971 | AM_RANGE(0x010200, 0x0102ff) AM_READWRITE8( cache_status_register_r, cache_control_register_w, 0xffffffff ) |
| 972 | AM_RANGE(0x010300, 0x0103ff) AM_READWRITE8( task_alias_register_r , task_alias_register_w , 0xffffffff ) |
| 973 | AM_RANGE(0x010400, 0x0104ff) AM_DEVREADWRITE8( APOLLO_SIO_TAG, apollo_sio_r, apollo_sio_w, 0xffffffff ) |
| 974 | AM_RANGE(0x010500, 0x0105ff) AM_DEVREADWRITE8( APOLLO_SIO2_TAG, apollo_sio2_r, apollo_sio2_w, 0xffffffff ) |
| 975 | AM_RANGE(0x010800, 0x0108ff) AM_DEVREADWRITE8( APOLLO_PTM_TAG, apollo_ptm_r, apollo_ptm_w, 0xffffffff ) |
| 976 | AM_RANGE(0x010900, 0x0109ff) AM_READWRITE8( apollo_rtc_r, apollo_rtc_w, 0xffffffff ) |
| 977 | AM_RANGE(0x010c00, 0x010cff) AM_READWRITE8( /*"dma1",*/apollo_dma_1_r, apollo_dma_1_w, 0xffffffff ) |
| 978 | AM_RANGE(0x010d00, 0x010dff) AM_READWRITE8( /*"dma2",*/apollo_dma_2_r, apollo_dma_2_w, 0xffffffff ) |
| 979 | AM_RANGE(0x011000, 0x0110ff) AM_DEVREADWRITE8( APOLLO_PIC1_TAG, apollo_pic8259_master_r, apollo_pic8259_master_w, 0xffffffff) |
| 980 | AM_RANGE(0x011100, 0x0111ff) AM_DEVREADWRITE8( APOLLO_PIC2_TAG, apollo_pic8259_slave_r, apollo_pic8259_slave_w, 0xffffffff) |
| 981 | AM_RANGE(0x011200, 0x0112ff) AM_READWRITE16( apollo_node_id_r, apollo_node_id_w, 0xffffffff) |
| 982 | AM_RANGE(0x011300, 0x0113ff) AM_READWRITE16( latch_page_on_parity_error_register_r, latch_page_on_parity_error_register_w, 0xffffffff ) |
| 983 | AM_RANGE(0x011400, 0x0114ff) AM_READWRITE8( dn5500_memory_present_register_r, dn5500_memory_present_register_w, 0xffffffff ) |
| 984 | AM_RANGE(0x011500, 0x0115ff) AM_READWRITE8( dn5500_11500_r, dn5500_11500_w, 0xffffffff ) |
| 985 | AM_RANGE(0x011600, 0x0116ff) AM_READWRITE8( master_req_register_r, master_req_register_w, 0xffffffff) |
| 986 | |
| 987 | AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16( selective_clear_locations_r, selective_clear_locations_w, 0xffffffff ) |
| 988 | AM_RANGE(0x017000, 0x017fff) AM_READWRITE16( apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff ) |
| 989 | |
| 990 | AM_RANGE(0x04D000, 0x04D007) AM_DEVREADWRITE16( APOLLO_WDC_TAG, omti8621_r, omti8621_w, 0xffffffff) |
| 991 | AM_RANGE(0x050000, 0x050007) AM_DEVREADWRITE8( APOLLO_CTAPE_TAG, sc499_r, sc499_w, 0xffffffff) |
| 992 | AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8( APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff) |
| 993 | AM_RANGE(0x05f800, 0x05f807) AM_READWRITE8( apollo_fdc_r, apollo_fdc_w, 0xffffffff) |
| 994 | |
| 995 | // AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff) |
| 996 | // AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16( APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff) |
| 997 | |
| 998 | AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff) |
| 999 | |
| 1000 | AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM */ |
| 1001 | |
| 1002 | // FIXME: must match with RAM size in driver/apollo_sio.c |
| 1003 | AM_RANGE(DN5500_RAM_BASE, DN5500_RAM_END) AM_RAM_WRITE(ram_with_parity_w) AM_BASE(&messram_ptr.u32) AM_SIZE(&messram_size) |
| 1004 | |
| 1005 | AM_RANGE(ATBUS_MEMORY_BASE, ATBUS_MEMORY_END) AM_READWRITE(apollo_atbus_memory_r, apollo_atbus_memory_w) |
| 1006 | |
| 1007 | AM_RANGE(0x07000000, 0x0700FFFF) AM_READWRITE8( dn5500_io_protection_map_r, dn5500_io_protection_map_w, 0xffffffff ) |
| 1008 | // AM_RANGE(0xf8000000, 0xffffffff) AM_READWRITE(apollo_f8_r, apollo_f8_w) |
| 1009 | AM_RANGE(0x00000000, 0xffffffff) AM_READWRITE(apollo_unmapped_r, apollo_unmapped_w) |
| 1010 | ADDRESS_MAP_END |
| 1011 | |
| 1012 | /*************************************************************************** |
| 1013 | Machine Reset |
| 1014 | ***************************************************************************/ |
| 1015 | |
| 1016 | static MACHINE_RESET( dn3500 ) |
| 1017 | { |
| 1018 | device_t *cpu = machine.device(MAINCPU); |
| 1019 | |
| 1020 | MLOG1(("machine_reset_dn3500")); |
| 1021 | |
| 1022 | MACHINE_RESET_CALL(apollo); |
| 1023 | |
| 1024 | // set configuration |
| 1025 | omti8621_set_verbose(apollo_config(APOLLO_CONF_DISK_TRACE)); |
| 1026 | threecom3c505_set_verbose(apollo_config(APOLLO_CONF_NET_TRACE)); |
| 1027 | |
| 1028 | if (apollo_config(APOLLO_CONF_NODE_ID)) |
| 1029 | { |
| 1030 | UINT8 db[0x50]; |
| 1031 | UINT16 sector1 = apollo_is_dn5500() ? 4 : 1; |
| 1032 | |
| 1033 | // check label of physical volume and get sector data of logical volume 1 |
| 1034 | // Note: sector data starts with 32 byte block header |
| 1035 | if (omti8621_get_sector(machine.device(APOLLO_WDC_TAG), 0, db, sizeof(db), 0) == sizeof(db) && |
| 1036 | memcmp (db+0x22, "APOLLO", 6) == 0 && |
| 1037 | omti8621_get_sector(machine.device(APOLLO_WDC_TAG), sector1, db, sizeof(db), 0) == sizeof(db)) |
| 1038 | { |
| 1039 | MLOG2(("machine_reset_dn3500: node ID is %06X (from ROM)", node_id)); |
| 1040 | |
| 1041 | // set node_id from UID of logical volume 1 of logical unit 0 |
| 1042 | node_id = (((db[0x49] << 8) | db[0x4a]) << 8) | db[0x4b]; |
| 1043 | |
| 1044 | MLOG2(("machine_reset_dn3500: node ID is %06X (from disk)", node_id)); |
| 1045 | } |
| 1046 | } |
| 1047 | |
| 1048 | m68k_set_instruction_hook(cpu, apollo_instruction_hook); |
| 1049 | } |
| 1050 | |
| 1051 | static void apollo_reset_instr_callback(device_t *device) |
| 1052 | { |
| 1053 | DLOG1(("apollo_reset_instr_callback")); |
| 1054 | // FIXME: this will reset the CPU too |
| 1055 | // device->machine().schedule_soft_reset(); // needs to call reset on the devices other than the CPU |
| 1056 | } |
| 1057 | |
| 1058 | /*************************************************************************** |
| 1059 | Machine Start |
| 1060 | ***************************************************************************/ |
| 1061 | |
| 1062 | static MACHINE_START( dn3500 ) { |
| 1063 | MLOG1(("machine_start_dn3500: ram size is %d MB", (int)messram_size/(1024*1024))); |
| 1064 | |
| 1065 | // clear ram |
| 1066 | memset(messram_ptr.u8, 0x55, messram_size); |
| 1067 | |
| 1068 | MACHINE_START_CALL(apollo); |
| 1069 | } |
| 1070 | |
| 1071 | /*************************************************************************** |
| 1072 | Driver Init |
| 1073 | ***************************************************************************/ |
| 1074 | |
| 1075 | static DRIVER_INIT( dn3500 ) { |
| 1076 | MLOG1(("driver_init_dn3500")); |
| 1077 | |
| 1078 | device_set_irq_callback(machine.device(MAINCPU), apollo_irq_acknowledge); |
| 1079 | |
| 1080 | /* hook the RESET line, which resets a slew of other components */ |
| 1081 | m68k_set_reset_callback(machine.device(MAINCPU), apollo_reset_instr_callback); |
| 1082 | |
| 1083 | ram_base_address = DN3500_RAM_BASE; |
| 1084 | ram_end_address = DN3500_RAM_END; |
| 1085 | |
| 1086 | node_type= NODE_TYPE_DN3500; |
| 1087 | ram_config_byte= DN3500_RAM_CONFIG_BYTE; |
| 1088 | |
| 1089 | DRIVER_INIT_CALL(apollo); |
| 1090 | } |
| 1091 | |
| 1092 | static DRIVER_INIT( dsp3500 ) { |
| 1093 | DRIVER_INIT_CALL( dn3500 ); |
| 1094 | MLOG1(("driver_init_dsp3500")); |
| 1095 | node_type = NODE_TYPE_DSP3500; |
| 1096 | dsp_terminal = machine.device(TERMINAL_TAG); |
| 1097 | } |
| 1098 | |
| 1099 | static DRIVER_INIT( dn3000 ) { |
| 1100 | DRIVER_INIT_CALL( dn3500 ); |
| 1101 | MLOG1(("driver_init_dn3000")); |
| 1102 | |
| 1103 | ram_base_address = DN3000_RAM_BASE; |
| 1104 | ram_end_address = DN3000_RAM_END; |
| 1105 | |
| 1106 | node_type = NODE_TYPE_DN3000; |
| 1107 | ram_config_byte= DN3000_RAM_CONFIG_8MB; |
| 1108 | } |
| 1109 | |
| 1110 | static DRIVER_INIT( dsp3000 ) { |
| 1111 | DRIVER_INIT_CALL( dn3000 ); |
| 1112 | MLOG1(("driver_init_dsp3000")); |
| 1113 | node_type = NODE_TYPE_DSP3000; |
| 1114 | dsp_terminal = machine.device(TERMINAL_TAG); |
| 1115 | } |
| 1116 | |
| 1117 | static DRIVER_INIT( dn5500 ) { |
| 1118 | DRIVER_INIT_CALL( dn3500 ); |
| 1119 | MLOG1(("driver_init_dn5500")); |
| 1120 | |
| 1121 | ram_base_address = DN5500_RAM_BASE; |
| 1122 | ram_end_address = DN5500_RAM_END; |
| 1123 | |
| 1124 | node_type = NODE_TYPE_DN5500; |
| 1125 | ram_config_byte= DN5500_RAM_CONFIG_BYTE; |
| 1126 | } |
| 1127 | |
| 1128 | static DRIVER_INIT( dsp5500 ) { |
| 1129 | DRIVER_INIT_CALL( dn5500 ); |
| 1130 | MLOG1(("driver_init_dsp5500")); |
| 1131 | node_type = NODE_TYPE_DSP5500; |
| 1132 | dsp_terminal = machine.device(TERMINAL_TAG); |
| 1133 | } |
| 1134 | |
| 1135 | /*************************************************************************** |
| 1136 | Input Ports |
| 1137 | ***************************************************************************/ |
| 1138 | |
| 1139 | static INPUT_PORTS_START( dn3500 ) |
| 1140 | PORT_INCLUDE(apollo_config) |
| 1141 | PORT_INCLUDE(apollo_kbd) |
| 1142 | INPUT_PORTS_END |
| 1143 | |
| 1144 | static INPUT_PORTS_START( dsp3500 ) |
| 1145 | PORT_INCLUDE(apollo_config) |
| 1146 | INPUT_PORTS_END |
| 1147 | |
| 1148 | static WRITE8_DEVICE_HANDLER( apollo_kbd_putchar ) { |
| 1149 | // put keyboard character to the keyboard sio |
| 1150 | // DLOG1(("apollo_kbd_putchar: 0x%02x", data)); |
| 1151 | apollo_sio_rx_data(device->machine().device(APOLLO_SIO_TAG), 0, data); |
| 1152 | } |
| 1153 | |
| 1154 | static READ8_DEVICE_HANDLER( apollo_kbd_has_beeper ) { |
| 1155 | return 1; // apollo_config(APOLLO_CONF_KBD_BEEPER); |
| 1156 | } |
| 1157 | |
| 1158 | static READ8_DEVICE_HANDLER( apollo_kbd_is_german ) { |
| 1159 | return apollo_config(APOLLO_CONF_GERMAN_KBD); |
| 1160 | } |
| 1161 | |
| 1162 | static APOLLO_KBD_INTERFACE( apollo_kbd_config ) = { |
| 1163 | apollo_kbd_putchar, |
| 1164 | apollo_kbd_has_beeper, |
| 1165 | apollo_kbd_is_german |
| 1166 | }; |
| 1167 | |
| 1168 | static WRITE8_DEVICE_HANDLER( terminal_kbd_putchar ) { |
| 1169 | apollo_sio_rx_data(device->machine().device(APOLLO_SIO_TAG), 1, data); |
| 1170 | } |
| 1171 | |
| 1172 | static GENERIC_TERMINAL_INTERFACE( apollo_terminal_config ) { |
| 1173 | DEVCB_HANDLER(terminal_kbd_putchar) |
| 1174 | }; |
| 1175 | |
| 1176 | void apollo_terminal_write(UINT8 data) { |
| 1177 | if (dsp_terminal != NULL) { |
| 1178 | // output data to the terminal emulator |
| 1179 | terminal_write(dsp_terminal, 0, data); |
| 1180 | } |
| 1181 | } |
| 1182 | |
| 1183 | /*************************************************************************** |
| 1184 | MACHINE DRIVERS |
| 1185 | ***************************************************************************/ |
| 1186 | |
| 1187 | static MACHINE_CONFIG_START( dn3500, apollo_state ) |
| 1188 | /* basic machine hardware */ |
| 1189 | MCFG_CPU_ADD(MAINCPU, M68030, 25000000) /* 25 MHz 68030 */ |
| 1190 | MCFG_CPU_PROGRAM_MAP(dn3500_map) |
| 1191 | MCFG_QUANTUM_TIME(attotime::from_hz(60)) |
| 1192 | |
| 1193 | MCFG_MACHINE_START( dn3500 ) |
| 1194 | MCFG_MACHINE_RESET( dn3500 ) |
| 1195 | |
| 1196 | MCFG_FRAGMENT_ADD( apollo ) |
| 1197 | |
| 1198 | /* keyboard beeper */ |
| 1199 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 1200 | MCFG_SOUND_ADD("beep", BEEP, 0) |
| 1201 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) |
| 1202 | |
| 1203 | /* internal ram */ |
| 1204 | MCFG_RAM_ADD("messram") |
| 1205 | MCFG_RAM_DEFAULT_SIZE("8M") |
| 1206 | MCFG_RAM_EXTRA_OPTIONS("4M,8M,16M,32M") |
| 1207 | MACHINE_CONFIG_END |
| 1208 | |
| 1209 | static MACHINE_CONFIG_DERIVED( dsp3500, dn3500 ) |
| 1210 | // strange: MCFG_CPU_PROGRAM_MAP will fail w/o MCFG_CPU_REPLACE |
| 1211 | MCFG_CPU_REPLACE(MAINCPU, M68030, 25000000) /* 25 MHz 68030 */ |
| 1212 | MCFG_CPU_PROGRAM_MAP(dsp3500_map) |
| 1213 | /* terminal hardware */ |
| 1214 | MCFG_DEFAULT_LAYOUT( layout_apollo_dsp ) |
| 1215 | // MCFG_FRAGMENT_ADD( generic_terminal ) |
| 1216 | MCFG_GENERIC_TERMINAL_ADD(TERMINAL_TAG, apollo_terminal_config) |
| 1217 | MACHINE_CONFIG_END |
| 1218 | |
| 1219 | static MACHINE_CONFIG_DERIVED( dn3500_19i, dn3500 ) |
| 1220 | /* video hardware 19" monochrome */ |
| 1221 | MCFG_APOLLO_MONO19I_ADD(APOLLO_SCREEN_TAG) |
| 1222 | MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config ) |
| 1223 | MACHINE_CONFIG_END |
| 1224 | |
| 1225 | static MACHINE_CONFIG_DERIVED( dn3500_15i, dn3500 ) |
| 1226 | /* video hardware 15" monochrome */ |
| 1227 | MCFG_APOLLO_MONO15I_ADD(APOLLO_SCREEN_TAG) |
| 1228 | MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config ) |
| 1229 | MACHINE_CONFIG_END |
| 1230 | |
| 1231 | static MACHINE_CONFIG_DERIVED( dn3000, dn3500 ) |
| 1232 | MCFG_CPU_REPLACE(MAINCPU, M68020PMMU, 12000000) /* 12 MHz */ |
| 1233 | MCFG_CPU_PROGRAM_MAP(dn3000_map) |
| 1234 | MCFG_DEVICE_REMOVE( APOLLO_SIO2_TAG ) |
| 1235 | |
| 1236 | MCFG_MACHINE_START( dn3500 ) |
| 1237 | MCFG_MACHINE_RESET( dn3500 ) |
| 1238 | |
| 1239 | MCFG_RAM_MODIFY("messram") |
| 1240 | MCFG_RAM_DEFAULT_SIZE("8M") |
| 1241 | MCFG_RAM_EXTRA_OPTIONS("4M") |
| 1242 | MACHINE_CONFIG_END |
| 1243 | |
| 1244 | static MACHINE_CONFIG_DERIVED( dsp3000, dn3000 ) |
| 1245 | // strange: MCFG_CPU_PROGRAM_MAP will fail w/o MCFG_CPU_REPLACE |
| 1246 | MCFG_CPU_REPLACE(MAINCPU, M68020PMMU, 12000000) /* 12 MHz */ |
| 1247 | MCFG_CPU_PROGRAM_MAP(dsp3000_map) |
| 1248 | /* terminal hardware */ |
| 1249 | MCFG_DEFAULT_LAYOUT( layout_apollo_dsp ) |
| 1250 | // MCFG_FRAGMENT_ADD( generic_terminal ) |
| 1251 | MCFG_GENERIC_TERMINAL_ADD(TERMINAL_TAG, apollo_terminal_config) |
| 1252 | MACHINE_CONFIG_END |
| 1253 | |
| 1254 | static MACHINE_CONFIG_DERIVED( dn3000_19i, dn3000 ) |
| 1255 | /* video hardware 19" monochrome */ |
| 1256 | MCFG_APOLLO_MONO19I_ADD(APOLLO_SCREEN_TAG) |
| 1257 | MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config ) |
| 1258 | MACHINE_CONFIG_END |
| 1259 | |
| 1260 | static MACHINE_CONFIG_DERIVED( dn3000_15i, dn3000 ) |
| 1261 | /* video hardware 15" monochrome */ |
| 1262 | MCFG_APOLLO_MONO15I_ADD(APOLLO_SCREEN_TAG) |
| 1263 | MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config ) |
| 1264 | MACHINE_CONFIG_END |
| 1265 | |
| 1266 | static MACHINE_CONFIG_DERIVED( dn5500, dn3500 ) |
| 1267 | MCFG_CPU_REPLACE(MAINCPU, M68040, 25000000) /* 25 MHz */ |
| 1268 | MCFG_CPU_PROGRAM_MAP(dn5500_map) |
| 1269 | |
| 1270 | MCFG_MACHINE_START( dn3500 ) |
| 1271 | MCFG_MACHINE_RESET( dn3500 ) |
| 1272 | MACHINE_CONFIG_END |
| 1273 | |
| 1274 | static MACHINE_CONFIG_DERIVED( dsp5500, dn5500 ) |
| 1275 | // strange: MCFG_CPU_PROGRAM_MAP will fail w/o MCFG_CPU_REPLACE |
| 1276 | MCFG_CPU_REPLACE(MAINCPU, M68040, 25000000) /* 25 MHz */ |
| 1277 | MCFG_CPU_PROGRAM_MAP(dsp5500_map) |
| 1278 | /* terminal hardware */ |
| 1279 | MCFG_DEFAULT_LAYOUT( layout_apollo_dsp ) |
| 1280 | // MCFG_FRAGMENT_ADD( generic_terminal ) |
| 1281 | MCFG_GENERIC_TERMINAL_ADD(TERMINAL_TAG, apollo_terminal_config) |
| 1282 | MACHINE_CONFIG_END |
| 1283 | |
| 1284 | static MACHINE_CONFIG_DERIVED( dn5500_19i, dn5500 ) |
| 1285 | /* video hardware 19" monochrome */ |
| 1286 | MCFG_APOLLO_MONO19I_ADD(APOLLO_SCREEN_TAG) |
| 1287 | MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config ) |
| 1288 | MACHINE_CONFIG_END |
| 1289 | |
| 1290 | static MACHINE_CONFIG_DERIVED( dn5500_15i, dn5500 ) |
| 1291 | /* video hardware 15" monochrome */ |
| 1292 | MCFG_APOLLO_MONO15I_ADD(APOLLO_SCREEN_TAG) |
| 1293 | MCFG_APOLLO_KBD_ADD( APOLLO_KBD_TAG, apollo_kbd_config ) |
| 1294 | MACHINE_CONFIG_END |
| 1295 | |
| 1296 | /*************************************************************************** |
| 1297 | ROM Definitions |
| 1298 | ***************************************************************************/ |
| 1299 | |
| 1300 | ROM_START( dn3500 ) |
| 1301 | // dn3500 boot ROM (Note: use sha1sum -b <rom file>) |
| 1302 | ROM_REGION( 0x0100000, MAINCPU, 0 ) /* 68000 code */ |
| 1303 | |
| 1304 | // http://www.bitsavers.org/bits/Apollo/firmware/3500_BOOT_12191_7.bin |
| 1305 | // Note: file name must be converted to lower case (i.e. 3500_boot_12191_7.bin) |
| 1306 | // Note: this duplicates boot rom md7c-rev-8.00-1989-08-16-17-23-52.bin |
| 1307 | ROM_SYSTEM_BIOS( 0, "md7c-rev-8.00", "MD7C REV 8.00, 1989/08/16.17:23:52" ) |
| 1308 | ROMX_LOAD( "3500_boot_12191_7.bin", 0x00000, 0x10000, SHA1(36f3c83d9f2df42f2537b09ca2f051a8c9dfbfc2) , ROM_BIOS(1) ) |
| 1309 | |
| 1310 | ROM_LOAD_OPTIONAL( "3000_3c505_010728-00.bin", 0x80000, 0x02000, SHA1(7ac36cc6fc90b90ddfc56c45303b514cbe18ae58) ) |
| 1311 | ROM_END |
| 1312 | |
| 1313 | ROM_START( dn5500 ) |
| 1314 | // dn5500 boot ROM (Note: use sha1sum -b <rom file>) |
| 1315 | ROM_REGION( 0x0100000, MAINCPU, 0 ) /* 68000 code */ |
| 1316 | |
| 1317 | ROM_SYSTEM_BIOS( 0, "md7c-rev-8.00", "MD7C REV 8.00, 1989/08/16.17:23:52" ) |
| 1318 | ROMX_LOAD( "5500_boot_a1631-80046_1-30-92.bin", 0x00000, 0x10000, SHA1(7315a884ec4551c44433c6079cc06509223cb02b) , ROM_BIOS(1) ) |
| 1319 | |
| 1320 | ROM_LOAD_OPTIONAL( "3000_3c505_010728-00.bin", 0x80000, 0x02000, SHA1(7ac36cc6fc90b90ddfc56c45303b514cbe18ae58) ) |
| 1321 | ROM_END |
| 1322 | |
| 1323 | ROM_START( dn3000) |
| 1324 | ROM_REGION( 0x0090000, MAINCPU, 0 ) /* 68000 code */ |
| 1325 | |
| 1326 | ROM_SYSTEM_BIOS( 0, "md8-rev-7.0", "MD8 REV 7.0, 1988/08/16.15:14:39" ) |
| 1327 | ROMX_LOAD( "3000_boot_8475_7.bin", 0x00000, 0x08000, SHA1(6c383d2266719a3d069b7bf015f6945179395e7a), ROM_BIOS(1) ) |
| 1328 | |
| 1329 | ROM_LOAD_OPTIONAL( "3000_3c505_010728-00.bin", 0x80000, 0x02000, SHA1(7ac36cc6fc90b90ddfc56c45303b514cbe18ae58) ) |
| 1330 | ROM_END |
| 1331 | |
| 1332 | #define rom_dsp3500 rom_dn3500 |
| 1333 | #define rom_dn3500_15i rom_dn3500 |
| 1334 | #define rom_dn3500_19i rom_dn3500 |
| 1335 | |
| 1336 | #define rom_dsp3000 rom_dn3000 |
| 1337 | #define rom_dn3000_15i rom_dn3000 |
| 1338 | |
| 1339 | #define rom_dsp5500 rom_dn5500 |
| 1340 | #define rom_dn5500_15i rom_dn5500 |
| 1341 | #define rom_dn5500_19i rom_dn5500 |
| 1342 | |
| 1343 | /*************************************************************************** |
| 1344 | GAME DRIVERS |
| 1345 | ***************************************************************************/ |
| 1346 | |
| 1347 | #define DN_FLAGS 0 |
| 1348 | #define DSP_FLAGS 0 |
| 1349 | //#define DSP_FLAGS GAME_NO_SOUND |
| 1350 | |
| 1351 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ |
| 1352 | COMP( 1989, dn3500, 0, 0, dn3500_19i, dn3500, dn3500, "Apollo", "Apollo DN3500 19\" Monochrome", DN_FLAGS ) |
| 1353 | COMP( 1989, dsp3500, dn3500, 0, dsp3500, dsp3500,dsp3500,"Apollo", "Apollo DSP3500", DSP_FLAGS ) |
| 1354 | COMP( 1989, dn3500_15i, dn3500, 0, dn3500_15i, dn3500, dn3500, "Apollo", "Apollo DN3500 15\" Monochrome", DN_FLAGS ) |
| 1355 | |
| 1356 | COMP( 1988, dn3000, dn3500, 0, dn3000_19i, dn3500, dn3000, "Apollo", "Apollo DN3000 19\" Monochrome", DN_FLAGS ) |
| 1357 | COMP( 1988, dsp3000, dn3500, 0, dsp3000, dsp3500,dsp3000,"Apollo", "Apollo DSP3000", DSP_FLAGS ) |
| 1358 | COMP( 1988, dn3000_15i, dn3500, 0, dn3000_15i, dn3500, dn3000, "Apollo", "Apollo DN3000 15\" Monochrome", DN_FLAGS ) |
| 1359 | |
| 1360 | COMP( 1991, dn5500, dn3500, 0, dn5500_19i, dn3500, dn5500, "Apollo", "Apollo DN5500 19\" Monochrome", GAME_NOT_WORKING ) |
| 1361 | COMP( 1991, dsp5500, dn3500, 0, dsp5500, dsp3500,dsp5500,"Apollo", "Apollo DSP5500", GAME_NOT_WORKING ) |
| 1362 | COMP( 1991, dn5500_15i, dn3500, 0, dn5500_15i, dn3500, dn5500, "Apollo", "Apollo DN5500 15\" Monochrome", GAME_NOT_WORKING ) |