src/mess/drivers/vk100.c
| r15630 | r15631 | |
| 5 | 5 | 12/05/2009 Skeleton driver. |
| 6 | 6 | 28/07/2009 added Guru-readme(TM) |
| 7 | 7 | |
| 8 | | Todo: attach hd46505sp CRTC |
| 8 | Todo: |
| 9 | 9 | hook up vram |
| 10 | 10 | - vram space is now present but not hooked to anything |
| 11 | 11 | emulate vector generator hardware |
| 12 | | - stubbing registers: |
| 13 | | done: X, Y, Err, Pattern, WOPS |
| 14 | 12 | |
| 15 | 13 | Tony DiCenzo, now the director of standards and architecture at Oracle, was on the team that developed the VK100 |
| 16 | 14 | see http://startup.nmnaturalhistory.org/visitorstories/view.php?ii=79 |
| r15630 | r15631 | |
| 96 | 94 | */ |
| 97 | 95 | #undef VG_VERBOSE |
| 98 | 96 | #undef LED_VERBOSE |
| 97 | #undef KBD_VERBOSE |
| 99 | 98 | |
| 100 | 99 | #include "emu.h" |
| 101 | 100 | #include "cpu/i8085/i8085.h" |
| r15630 | r15631 | |
| 112 | 111 | m_maincpu(*this, "maincpu"), |
| 113 | 112 | m_screen(*this, "screen"), |
| 114 | 113 | m_crtc(*this, "crtc"), |
| 115 | | m_speaker(*this, BEEPER_TAG)//, |
| 116 | | //m_uart(*this, "i8251") |
| 114 | m_speaker(*this, BEEPER_TAG), |
| 115 | m_uart(*this, "i8251") |
| 117 | 116 | { } |
| 118 | 117 | required_device<cpu_device> m_maincpu; |
| 119 | 118 | required_device<screen_device> m_screen; |
| 120 | 119 | required_device<mc6845_device> m_crtc; |
| 121 | 120 | required_device<device_t> m_speaker; |
| 122 | | //required_device<device_t> m_uart; |
| 121 | required_device<device_t> m_uart; |
| 123 | 122 | |
| 124 | 123 | UINT16 m_vgX; |
| 125 | 124 | UINT16 m_vgY; |
| r15630 | r15631 | |
| 131 | 130 | UINT8 m_vgDVM; |
| 132 | 131 | UINT8 m_vgDIR; |
| 133 | 132 | UINT8 m_vgWOPS; |
| 133 | UINT8 m_BAUD; |
| 134 | 134 | UINT8 m_GO; |
| 135 | 135 | |
| 136 | 136 | DECLARE_WRITE8_MEMBER(vgLD_X); |
| r15630 | r15631 | |
| 148 | 148 | DECLARE_WRITE8_MEMBER(vgEX_VEC); |
| 149 | 149 | DECLARE_WRITE8_MEMBER(vgEX_ER); |
| 150 | 150 | DECLARE_WRITE8_MEMBER(KBDW); |
| 151 | DECLARE_WRITE8_MEMBER(BAUD); |
| 151 | 152 | DECLARE_READ8_MEMBER(vk100_keyboard_column_r); |
| 152 | 153 | //DECLARE_READ8_MEMBER(SYSTAT_A); |
| 154 | DECLARE_READ8_MEMBER(SYSTAT_B); |
| 153 | 155 | }; |
| 154 | 156 | |
| 155 | 157 | /* |
| r15630 | r15631 | |
| 191 | 193 | * Blink --Background color-- Serial Port Select? Reverse |
| 192 | 194 | * Enable Green Red Blue ? ? ? BG/FG |
| 193 | 195 | * d7 d6 d5 d4 d3 d2 d1 d0 |
| 196 | * apparently, 00 = rs232/eia, 01 = 20ma, 02 = hardcopy, 03 = test/loopback on whichever 2 bits do port select |
| 194 | 197 | */ |
| 195 | 198 | WRITE8_MEMBER(vk100_state::vgSOPS) |
| 196 | 199 | { |
| r15630 | r15631 | |
| 325 | 328 | #endif |
| 326 | 329 | } |
| 327 | 330 | |
| 331 | /* port 0x6C: "BAUD" sets the dividers for the rx and tx clocks on the 8251 */ |
| 332 | WRITE8_MEMBER(vk100_state::BAUD) |
| 333 | { |
| 334 | m_BAUD = data; |
| 335 | logerror("IO: 0x6C: write of %02X, TODO: set the i8251 clocks as appropriate here!\n", m_BAUD); |
| 336 | } |
| 337 | |
| 328 | 338 | /* port 0x40: "SYSTAT A"; various status bits, poorly documented in the tech manual |
| 329 | | * /GO ? ? ? BIT3 BIT2 BIT1 BIT0 |
| 339 | * /GO BIT3 BIT2 BIT1 BIT0 ? ? ? |
| 330 | 340 | * d7 d6 d5 d4 d3 d2 d1 d0 |
| 331 | 341 | * bit3, 2, 1, 0 are the last 4 bits read by the vector generator from VRAM |
| 332 | 342 | * this appears to be the only way the vram can be READ by the cpu |
| 343 | |
| 344 | 31D reads and checks d7 in a loop |
| 345 | 205 reads, xors with 0x55 (from reg D), ANDS result with 0x78 and branches if it is not zero (checking for bit pattern 0101?) |
| 346 | 299 reads, rotates result right 3 times and ANDs the result with 0x0F |
| 347 | 2A4 reads, rotates result left 1 time and ANDS the result with 0xF0 |
| 333 | 348 | */ |
| 334 | 349 | /*READ8_MEMBER(vk100_state::SYSTAT_A) |
| 335 | 350 | { |
| 336 | 351 | return ((1-m_GO)<<7)|0x7F; |
| 337 | 352 | }*/ |
| 338 | 353 | |
| 354 | /* port 0x48: "SYSTAT B"; NOT documented in the tech manual */ |
| 355 | READ8_MEMBER(vk100_state::SYSTAT_B) |
| 356 | { |
| 357 | return ioport("SWITCHES")->read(); |
| 358 | } |
| 359 | |
| 339 | 360 | READ8_MEMBER(vk100_state::vk100_keyboard_column_r) |
| 340 | 361 | { |
| 341 | 362 | UINT8 code; |
| 342 | 363 | char kbdcol[8]; |
| 343 | 364 | sprintf(kbdcol,"COL%X", (offset&0xF)); |
| 344 | 365 | code = ioport(kbdcol)->read() | ioport("CAPSSHIFT")->read(); |
| 366 | #ifdef KBD_VERBOSE |
| 345 | 367 | logerror("Keyboard column %X read, returning %02X\n", offset&0xF, code); |
| 368 | #endif |
| 346 | 369 | return code; |
| 347 | 370 | } |
| 348 | 371 | |
| r15630 | r15631 | |
| 362 | 385 | AM_RANGE (0x40, 0x41) AM_WRITE(vgLD_X) //LD X LO + HI 12 bits |
| 363 | 386 | AM_RANGE (0x42, 0x43) AM_WRITE(vgLD_Y) //LD Y LO + HI 12 bits |
| 364 | 387 | AM_RANGE (0x44, 0x44) AM_WRITE(vgERR) //LD ERR ('error' in bresenham algorithm) |
| 365 | | AM_RANGE (0x45, 0x45) AM_WRITE(vgSOPS) //LD SOPS (screen options) |
| 388 | AM_RANGE (0x45, 0x45) AM_WRITE(vgSOPS) //LD SOPS (screen options (plus uart dest)) |
| 366 | 389 | AM_RANGE (0x46, 0x46) AM_WRITE(vgPAT) //LD PAT (pattern register) |
| 367 | 390 | AM_RANGE (0x47, 0x47) AM_WRITE(vgPMUL) //LD PMUL (pattern multiplier) |
| 368 | | AM_RANGE (0x60, 0x60) AM_WRITE(vgDU) //LD DU |
| 369 | | AM_RANGE (0x61, 0x61) AM_WRITE(vgDVM) //LD DVM |
| 391 | AM_RANGE (0x60, 0x60) AM_WRITE(vgDU) //LD DU (major) |
| 392 | AM_RANGE (0x61, 0x61) AM_WRITE(vgDVM) //LD DVM (minor) |
| 370 | 393 | AM_RANGE (0x62, 0x62) AM_WRITE(vgDIR) //LD DIR (direction) |
| 371 | 394 | AM_RANGE (0x63, 0x63) AM_WRITE(vgWOPS) //LD WOPS (write options) |
| 372 | 395 | AM_RANGE (0x64, 0x64) AM_WRITE(vgEX_MOV) //EX MOV |
| r15630 | r15631 | |
| 374 | 397 | AM_RANGE (0x66, 0x66) AM_WRITE(vgEX_VEC) //EX VEC |
| 375 | 398 | AM_RANGE (0x67, 0x67) AM_WRITE(vgEX_ER) //EX ER |
| 376 | 399 | AM_RANGE (0x68, 0x68) AM_WRITE(KBDW) //KBDW (probably AM_MIRROR(0x03)) |
| 377 | | //AM_RANGE (0x6C, 0x6C) AM_WRITE(baud) //LD BAUD (baud rate clock divider setting for i8251 tx and rx clocks) (probably AM_MIRROR(0x03)) |
| 378 | | //AM_RANGE (0x70, 0x70) AM_WRITE(comd) //LD COMD (one of the i8251 regs) |
| 379 | | //AM_RANGE (0x71, 0x71) AM_WRITE(com) //LD COM (the other i8251 reg) |
| 400 | AM_RANGE (0x6C, 0x6C) AM_WRITE(BAUD) //LD BAUD (baud rate clock divider setting for i8251 tx and rx clocks) (probably AM_MIRROR(0x03)) |
| 401 | AM_RANGE(0x70, 0x70) AM_DEVWRITE("i8251", i8251_device, data_w) //LD COMD (i8251 data reg) |
| 402 | AM_RANGE(0x71, 0x71) AM_DEVWRITE("i8251", i8251_device, control_w) //LD COM (i8251 control reg) |
| 380 | 403 | //AM_RANGE (0x74, 0x74) AM_WRITE(unknown_74) |
| 381 | 404 | //AM_RANGE (0x78, 0x78) AM_WRITE(kbdw) //KBDW ?(mirror?) |
| 382 | 405 | //AM_RANGE (0x7C, 0x7C) AM_WRITE(unknown_7C) |
| 383 | | //AM_RANGE (0x40, 0x40) AM_READ(SYSTAT_A) // SYSTAT A (dipswitches and state machine done) |
| 384 | | //AM_RANGE (0x48, 0x48) AM_READ(systat_b) // SYSTAT B (dipswitches?) |
| 385 | | //AM_RANGE (0x50, 0x50) AM_READ(uart_0) // UART O , low 2 bits control the i8251 dest: 00 = rs232/eia, 01 = 20ma, 02 = hardcopy, 03 = test/loopback |
| 386 | | //AM_RANGE (0x51, 0x51) AM_READ(uart_1) // UAR |
| 406 | //AM_RANGE (0x40, 0x40) AM_READ(SYSTAT_A) // SYSTAT A (state machine done and last 4 bits of vram) |
| 407 | AM_RANGE (0x48, 0x48) AM_READ(SYSTAT_B) // SYSTAT B (dipswitches?) |
| 408 | AM_RANGE(0x50, 0x50) AM_DEVREAD("i8251", i8251_device, data_r) // UART O |
| 409 | AM_RANGE(0x51, 0x51) AM_DEVREAD("i8251", i8251_device, status_r) // UAR |
| 387 | 410 | //AM_RANGE (0x58, 0x58) AM_READ(unknown_58) |
| 388 | 411 | //AM_RANGE (0x60, 0x60) AM_READ(unknown_60) |
| 389 | 412 | //AM_RANGE (0x68, 0x68) AM_READ(unknown_68) // NOT USED |
| r15630 | r15631 | |
| 393 | 416 | |
| 394 | 417 | /* Input ports */ |
| 395 | 418 | static INPUT_PORTS_START( vk100 ) |
| 419 | // the dipswitches are common ground: when open (upward) the lines are pulled to 5v, otherwise they read as 0 |
| 420 | PORT_START("SWITCHES") |
| 421 | PORT_DIPNAME( 0x01, 0x00, "Power Frequency" ) PORT_DIPLOCATION("SW:1") |
| 422 | PORT_DIPSETTING( 0x00, "60Hz" ) |
| 423 | PORT_DIPSETTING( 0x01, "50Hz" ) |
| 424 | PORT_DIPNAME( 0x02, 0x00, "Default Serial Port" ) PORT_DIPLOCATION("SW:2") |
| 425 | PORT_DIPSETTING( 0x00, "20ma port" ) |
| 426 | PORT_DIPSETTING( 0x02, "EIA port" ) |
| 427 | PORT_DIPNAME( 0x04, 0x00, "Default US/UK" ) PORT_DIPLOCATION("SW:3") |
| 428 | PORT_DIPSETTING( 0x00, "US" ) |
| 429 | PORT_DIPSETTING( 0x04, "UK" ) |
| 430 | PORT_DIPNAME( 0x18, 0x00, "Default Parity" ) PORT_DIPLOCATION("SW:4,5") |
| 431 | PORT_DIPSETTING( 0x00, "Off" ) |
| 432 | PORT_DIPSETTING( 0x10, "Even" ) |
| 433 | PORT_DIPSETTING( 0x08, "Odd" ) |
| 434 | PORT_DIPSETTING( 0x18, "Do Not Use This Setting" ) |
| 435 | PORT_DIPNAME( 0xe0, 0xe0, "Default Baud Rate" ) PORT_DIPLOCATION("SW:6,7,8") |
| 436 | PORT_DIPSETTING( 0x00, "110" ) |
| 437 | PORT_DIPSETTING( 0x80, "300" ) |
| 438 | PORT_DIPSETTING( 0x40, "600" ) |
| 439 | PORT_DIPSETTING( 0xc0, "1200" ) |
| 440 | PORT_DIPSETTING( 0x20, "2400" ) |
| 441 | PORT_DIPSETTING( 0xa0, "4800" ) |
| 442 | PORT_DIPSETTING( 0x60, "9600" ) |
| 443 | PORT_DIPSETTING( 0xe0, "19200" ) |
| 444 | |
| 396 | 445 | PORT_START("CAPSSHIFT") // CAPS LOCK and SHIFT appear as the high 2 bits on all rows |
| 397 | 446 | PORT_BIT(0x3f, IP_ACTIVE_HIGH, IPT_UNUSED) |
| 398 | 447 | PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Caps lock") PORT_CODE(KEYCODE_CAPSLOCK) |
| r15630 | r15631 | |
| 544 | 593 | state->m_vgDVM = 0; |
| 545 | 594 | state->m_vgDIR = 0; |
| 546 | 595 | state->m_vgWOPS = 0; |
| 596 | state->m_BAUD = 0; |
| 547 | 597 | state->m_GO = 0; |
| 548 | 598 | } |
| 549 | 599 | |
| r15630 | r15631 | |
| 583 | 633 | NULL |
| 584 | 634 | }; |
| 585 | 635 | |
| 636 | static const i8251_interface i8251_intf = |
| 637 | { |
| 638 | DEVCB_NULL, // in_rxd_cb |
| 639 | DEVCB_NULL, // out_txd_cb |
| 640 | DEVCB_NULL, // in_dsr_cb |
| 641 | DEVCB_NULL, // out_dtr_cb |
| 642 | DEVCB_NULL, // out_rts_cb |
| 643 | DEVCB_NULL, // out_rxrdy_cb TODO: this goes to an interrupt! |
| 644 | DEVCB_NULL, // out_txrdy_cb TODO: this goes to an interrupt! |
| 645 | DEVCB_NULL, // out_txempty_cb |
| 646 | DEVCB_NULL // out_syndet_cb |
| 647 | }; |
| 648 | |
| 586 | 649 | static MACHINE_CONFIG_START( vk100, vk100_state ) |
| 587 | 650 | /* basic machine hardware */ |
| 588 | 651 | MCFG_CPU_ADD("maincpu", I8085A, XTAL_5_0688MHz) |
| r15630 | r15631 | |
| 600 | 663 | MCFG_PALETTE_LENGTH(8) |
| 601 | 664 | MCFG_PALETTE_INIT(vk100) |
| 602 | 665 | |
| 666 | /* i8251 uart */ |
| 667 | MCFG_I8251_ADD("i8251", i8251_intf) |
| 603 | 668 | |
| 604 | 669 | MCFG_DEFAULT_LAYOUT( layout_vk100 ) |
| 605 | 670 | |
| r15630 | r15631 | |
| 659 | 724 | /* Driver */ |
| 660 | 725 | |
| 661 | 726 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ |
| 662 | | COMP( 1980, vk100, 0, 0, vk100, vk100, 0, "Digital Equipment Corporation", "VK 100", GAME_NOT_WORKING | GAME_NO_SOUND) |
| 727 | COMP( 1980, vk100, 0, 0, vk100, vk100, 0, "Digital Equipment Corporation", "VK100 'GIGI'", GAME_NOT_WORKING | GAME_IMPERFECT_SOUND) |