src/mess/drivers/pcw.c
| r5366 | r5367 | |
| 102 | 102 | // pcw/pcw16 beeper |
| 103 | 103 | #include "sound/beep.h" |
| 104 | 104 | |
| 105 | | #define VERBOSE |
| 105 | #define VERBOSE 1 |
| 106 | 106 | #define LOG(x) do { if (VERBOSE) logerror x; } while (0) |
| 107 | 107 | |
| 108 | 108 | static NEC765_INTERRUPT( pcw_fdc_interrupt ); |
| r5366 | r5367 | |
| 118 | 118 | unsigned char pcw_vdu_video_control_register; |
| 119 | 119 | static int pcw_interrupt_counter; |
| 120 | 120 | |
| 121 | | static unsigned long pcw_banks[4]; |
| 121 | static UINT8 pcw_banks[4]; |
| 122 | 122 | static unsigned char pcw_bank_force = 0; |
| 123 | 123 | |
| 124 | 124 | |
| r5366 | r5367 | |
| 150 | 150 | ((fdc_interrupt_code==1) && ((pcw_system_status & (1<<5))!=0)) |
| 151 | 151 | ) |
| 152 | 152 | { |
| 153 | | cputag_set_input_line(machine, "maincpu", 0,HOLD_LINE); |
| 153 | if(cpu_get_reg(cputag_get_cpu(machine,"maincpu"),Z80_IFF1)) |
| 154 | cputag_set_input_line(machine, "maincpu", 0,ASSERT_LINE); |
| 154 | 155 | } |
| 155 | 156 | else |
| 156 | 157 | { |
| r5366 | r5367 | |
| 194 | 195 | { |
| 195 | 196 | /* I'll pulse it because if I used hold-line I'm not sure |
| 196 | 197 | it would clear - to be checked */ |
| 197 | | cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, PULSE_LINE); |
| 198 | cputag_set_input_line(machine, "maincpu", INPUT_LINE_NMI, ASSERT_LINE); |
| 198 | 199 | } |
| 199 | 200 | } |
| 200 | 201 | } |
| r5366 | r5367 | |
| 218 | 219 | /* fdc interrupt callback. set/clear fdc int */ |
| 219 | 220 | static NEC765_INTERRUPT( pcw_fdc_interrupt ) |
| 220 | 221 | { |
| 221 | | pcw_system_status &= ~(1<<5); |
| 222 | 222 | |
| 223 | | if (state) |
| 224 | | { |
| 225 | | /* fdc interrupt occured */ |
| 223 | if (state == CLEAR_LINE) |
| 224 | pcw_system_status &= ~(1<<5); |
| 225 | else |
| 226 | 226 | pcw_system_status |= (1<<5); |
| 227 | | } |
| 228 | 227 | |
| 229 | 228 | pcw_trigger_fdc_int(device->machine); |
| 230 | 229 | } |
| r5366 | r5367 | |
| 263 | 262 | static void pcw_update_read_memory_block(running_machine *machine, int block, int bank) |
| 264 | 263 | { |
| 265 | 264 | const address_space *space = cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM); |
| 266 | | memory_set_bankptr(machine, block + 1, mess_ram + ((bank * 0x4000) % mess_ram_size)); |
| 267 | 265 | |
| 268 | 266 | /* bank 3? */ |
| 269 | 267 | if (bank == 3) |
| r5366 | r5367 | |
| 273 | 271 | memory_install_read8_handler(space, |
| 274 | 272 | block * 0x04000 + 0x3ff0, block * 0x04000 + 0x3fff, 0, 0, |
| 275 | 273 | pcw_keyboard_r); |
| 274 | LOG(("MEM: read block %i -> bank %i\n",block,bank)); |
| 276 | 275 | } |
| 277 | 276 | else |
| 278 | 277 | { |
| r5366 | r5367 | |
| 280 | 279 | memory_install_read8_handler(space, |
| 281 | 280 | block * 0x04000 + 0x0000, block * 0x04000 + 0x3fff, 0, 0, |
| 282 | 281 | (read8_space_func) (STATIC_BANK1 + (FPTR)block)); |
| 282 | LOG(("MEM: read block %i -> bank %i\n",block,bank)); |
| 283 | 283 | } |
| 284 | memory_set_bankptr(machine, block + 1, mess_ram + ((bank * 0x4000) % mess_ram_size)); |
| 284 | 285 | } |
| 285 | 286 | |
| 286 | 287 | |
| r5366 | r5367 | |
| 288 | 289 | static void pcw_update_write_memory_block(running_machine *machine, int block, int bank) |
| 289 | 290 | { |
| 290 | 291 | memory_set_bankptr(machine, block + 5, mess_ram + ((bank * 0x4000) % mess_ram_size)); |
| 292 | LOG(("MEM: write block %i -> bank %i\n",block,bank)); |
| 291 | 293 | } |
| 292 | 294 | |
| 293 | 295 | |
| r5366 | r5367 | |
| 322 | 324 | { |
| 323 | 325 | case 0: |
| 324 | 326 | { |
| 325 | | mask = (1<<6); |
| 327 | mask = (1<<7); |
| 326 | 328 | } |
| 327 | 329 | break; |
| 328 | 330 | |
| r5366 | r5367 | |
| 334 | 336 | |
| 335 | 337 | case 2: |
| 336 | 338 | { |
| 337 | | mask = (1<<5); |
| 339 | mask = (1<<6); |
| 338 | 340 | } |
| 339 | 341 | break; |
| 340 | 342 | |
| 341 | 343 | case 3: |
| 342 | 344 | { |
| 343 | | mask = (1<<7); |
| 345 | mask = (1<<5); |
| 344 | 346 | } |
| 345 | 347 | break; |
| 346 | 348 | } |
| r5366 | r5367 | |
| 374 | 376 | /* from Jacob Nevins docs */ |
| 375 | 377 | static int pcw_get_sys_status(running_machine *machine) |
| 376 | 378 | { |
| 377 | | return pcw_interrupt_counter | (input_port_read(machine, "EXTRA") & (0x040 | 0x010)) | pcw_system_status; |
| 379 | return pcw_interrupt_counter | (input_port_read(machine, "EXTRA") & (0x040 | 0x010)) | (pcw_system_status & 0x20); |
| 378 | 380 | } |
| 379 | 381 | |
| 380 | 382 | static READ8_HANDLER(pcw_interrupt_counter_r) |
| r5366 | r5367 | |
| 390 | 392 | /* update interrupt */ |
| 391 | 393 | pcw_interrupt_handle(space->machine); |
| 392 | 394 | /* return data */ |
| 395 | LOG(("SYS: IRQ counter read, returning %02x\n",data)); |
| 393 | 396 | return data; |
| 394 | 397 | } |
| 395 | 398 | |
| r5366 | r5367 | |
| 420 | 423 | |
| 421 | 424 | roller_ram_addr = (((data>>5) & 0x07)<<14) | |
| 422 | 425 | ((data & 0x01f)<<9); |
| 426 | LOG(("Roller-RAM: Address set to 0x%05x\n",roller_ram_addr)); |
| 423 | 427 | } |
| 424 | 428 | |
| 425 | 429 | static WRITE8_HANDLER(pcw_pointer_table_top_scan_w) |
| 426 | 430 | { |
| 427 | 431 | roller_ram_offset = data; |
| 432 | LOG(("Roller-RAM: offset set to 0x%05x\n",roller_ram_offset)); |
| 428 | 433 | } |
| 429 | 434 | |
| 430 | 435 | static WRITE8_HANDLER(pcw_vdu_video_control_register_w) |
| 431 | 436 | { |
| 432 | 437 | pcw_vdu_video_control_register = data; |
| 438 | LOG(("Roller-RAM: control reg set to 0x%02x\n",data)); |
| 433 | 439 | } |
| 434 | 440 | |
| 435 | 441 | static WRITE8_HANDLER(pcw_system_control_w) |
| r5366 | r5367 | |
| 451 | 457 | /* reboot */ |
| 452 | 458 | case 1: |
| 453 | 459 | { |
| 460 | popmessage("SYS: Reboot"); |
| 454 | 461 | } |
| 455 | 462 | break; |
| 456 | 463 | |
| r5366 | r5367 | |
| 505 | 512 | fdc_interrupt_code = 2; |
| 506 | 513 | |
| 507 | 514 | /* previously connected to NMI or INT? */ |
| 508 | | if ((fdc_previous_interrupt_code == 0) || (fdc_previous_interrupt_code == 1)) |
| 515 | if ((fdc_previous_interrupt_code == 0)) |
| 509 | 516 | { |
| 510 | 517 | /* yes */ |
| 511 | 518 | |
| r5366 | r5367 | |
| 513 | 520 | cputag_set_input_line(space->machine, "maincpu", INPUT_LINE_NMI, CLEAR_LINE); |
| 514 | 521 | |
| 515 | 522 | } |
| 523 | pcw_interrupt_handle(space->machine); |
| 516 | 524 | |
| 517 | | pcw_interrupt_handle(space->machine); |
| 518 | 525 | } |
| 519 | 526 | break; |
| 520 | 527 | |
| r5366 | r5367 | |
| 587 | 594 | static READ8_HANDLER(pcw_system_status_r) |
| 588 | 595 | { |
| 589 | 596 | /* from Jacob Nevins docs */ |
| 590 | | return pcw_get_sys_status(space->machine); |
| 597 | UINT8 ret = pcw_get_sys_status(space->machine); |
| 598 | |
| 599 | LOG(("SYS: Status port returning %02x\n",ret)); |
| 600 | return ret; |
| 591 | 601 | } |
| 592 | 602 | |
| 593 | 603 | /* read from expansion hardware - additional hardware not part of |
| r5366 | r5367 | |
| 596 | 606 | { |
| 597 | 607 | logerror("pcw expansion r: %04x\n",offset+0x080); |
| 598 | 608 | |
| 599 | | switch (offset-0x080) |
| 609 | switch (offset+0x080) |
| 600 | 610 | { |
| 601 | 611 | case 0x0e0: |
| 602 | 612 | { |
| r5366 | r5367 | |
| 619 | 629 | } |
| 620 | 630 | |
| 621 | 631 | case 0x0e1: |
| 632 | case 0x0e3: |
| 622 | 633 | { |
| 623 | | return 0x07f; |
| 634 | return 0x7f; |
| 624 | 635 | } |
| 625 | 636 | |
| 626 | 637 | case 0x085: |
| r5366 | r5367 | |
| 691 | 702 | |
| 692 | 703 | static READ8_HANDLER(pcw_printer_status_r) |
| 693 | 704 | { |
| 694 | | return 0x0ff; |
| 705 | return 0xff; |
| 695 | 706 | } |
| 696 | 707 | |
| 697 | 708 | /* TODO: Implement parallel port! */ |
| r5366 | r5367 | |
| 714 | 725 | |
| 715 | 726 | |
| 716 | 727 | static ADDRESS_MAP_START(pcw_io, ADDRESS_SPACE_IO, 8) |
| 717 | | AM_RANGE(0x000, 0x07f) AM_READWRITE(pcw_fdc_r, pcw_fdc_w) |
| 728 | ADDRESS_MAP_GLOBAL_MASK(0xff) |
| 729 | AM_RANGE(0x000, 0x07f) AM_READWRITE(pcw_fdc_r, pcw_fdc_w) |
| 718 | 730 | AM_RANGE(0x080, 0x0ef) AM_READWRITE(pcw_expansion_r, pcw_expansion_w) |
| 719 | 731 | AM_RANGE(0x0f0, 0x0f3) AM_WRITE( pcw_bank_select_w) |
| 720 | 732 | AM_RANGE(0x0f4, 0x0f4) AM_READWRITE(pcw_interrupt_counter_r, pcw_bank_force_selection_w) |
| r5366 | r5367 | |
| 729 | 741 | |
| 730 | 742 | |
| 731 | 743 | static ADDRESS_MAP_START(pcw9512_io, ADDRESS_SPACE_IO, 8) |
| 744 | ADDRESS_MAP_GLOBAL_MASK(0xff) |
| 732 | 745 | AM_RANGE(0x000, 0x07f) AM_READWRITE(pcw_fdc_r, pcw_fdc_w) |
| 733 | 746 | AM_RANGE(0x080, 0x0ef) AM_READWRITE(pcw_expansion_r, pcw_expansion_w) |
| 734 | 747 | AM_RANGE(0x0f0, 0x0f3) AM_WRITE( pcw_bank_select_w) |
| r5366 | r5367 | |
| 752 | 765 | |
| 753 | 766 | static MACHINE_START( pcw ) |
| 754 | 767 | { |
| 755 | | fdc_interrupt_code = 0; |
| 768 | fdc_interrupt_code = 2; |
| 756 | 769 | floppy_drive_set_geometry(image_from_devtype_and_index(machine, IO_FLOPPY, 0), FLOPPY_DRIVE_DS_80); |
| 757 | 770 | } |
| 758 | 771 | |
| 772 | static MACHINE_RESET( pcw ) |
| 773 | { |
| 774 | /* ram paging is actually undefined at power-on */ |
| 775 | pcw_bank_force = 0x00; |
| 776 | |
| 777 | pcw_banks[0] = 0x00; |
| 778 | pcw_banks[1] = 0x01; |
| 779 | pcw_banks[2] = 0x02; |
| 780 | pcw_banks[3] = 0x03; |
| 759 | 781 | |
| 782 | pcw_update_mem(machine, 0, pcw_banks[0]); |
| 783 | pcw_update_mem(machine, 1, pcw_banks[1]); |
| 784 | pcw_update_mem(machine, 2, pcw_banks[2]); |
| 785 | pcw_update_mem(machine, 3, pcw_banks[3]); |
| 786 | } |
| 787 | |
| 760 | 788 | static DRIVER_INIT(pcw) |
| 761 | 789 | { |
| 762 | | pcw_boot = 1; |
| 790 | UINT8* code = memory_region(machine,"bootcode"); |
| 791 | int x; |
| 792 | pcw_boot = 0; |
| 763 | 793 | |
| 764 | 794 | cpu_set_input_line_vector(cputag_get_cpu(machine, "maincpu"), 0, 0x0ff); |
| 765 | 795 | |
| 796 | /* copy boot code into RAM - yes, it's skipping a step, |
| 797 | but there is no verified dump of the boot sequence */ |
| 766 | 798 | |
| 767 | | /* ram paging is actually undefined at power-on */ |
| 768 | | pcw_banks[0] = 0; |
| 769 | | pcw_banks[1] = 1; |
| 770 | | pcw_banks[2] = 2; |
| 771 | | pcw_banks[3] = 3; |
| 799 | memset(mess_ram,0x00,mess_ram_size); |
| 800 | for(x=0;x<256;x++) |
| 801 | mess_ram[x+2] = code[x]; |
| 772 | 802 | |
| 773 | | pcw_update_mem(machine, 0, pcw_banks[0]); |
| 774 | | pcw_update_mem(machine, 1, pcw_banks[1]); |
| 775 | | pcw_update_mem(machine, 2, pcw_banks[2]); |
| 776 | | pcw_update_mem(machine, 3, pcw_banks[3]); |
| 777 | | |
| 778 | 803 | /* lower 4 bits are interrupt counter */ |
| 779 | 804 | pcw_system_status = 0x000; |
| 780 | 805 | pcw_system_status &= ~((1<<6) | (1<<5) | (1<<4)); |
| r5366 | r5367 | |
| 989 | 1014 | MDRV_CPU_ADD("maincpu", Z80, 4000000) /* clock supplied to chip, but in reality it is 3.4 MHz */ |
| 990 | 1015 | MDRV_CPU_PROGRAM_MAP(pcw_map) |
| 991 | 1016 | MDRV_CPU_IO_MAP(pcw_io) |
| 992 | | MDRV_QUANTUM_TIME(HZ(60)) |
| 1017 | MDRV_QUANTUM_TIME(HZ(50)) |
| 993 | 1018 | |
| 994 | 1019 | MDRV_MACHINE_START(pcw) |
| 1020 | MDRV_MACHINE_RESET(pcw) |
| 995 | 1021 | |
| 996 | 1022 | /* video hardware */ |
| 997 | 1023 | MDRV_SCREEN_ADD("screen", RASTER) |
| r5366 | r5367 | |
| 1031 | 1057 | |
| 1032 | 1058 | /* I am loading the boot-program outside of the Z80 memory area, because it |
| 1033 | 1059 | is banked. */ |
| 1060 | /* 8256boot.bin is not a real ROM, it is what is loaded into RAM by the boot sequence |
| 1061 | It was typed in by hand based on the disassembly found at |
| 1062 | http://www.chiark.greenend.org.uk/~jacobn/cpm/pcwboot.html */ |
| 1034 | 1063 | |
| 1035 | 1064 | // for now all models use the same rom |
| 1036 | 1065 | #define ROM_PCW(model) \ |
| 1037 | 1066 | ROM_START(model) \ |
| 1038 | | ROM_REGION(0x014000, "maincpu",0) \ |
| 1039 | | ROM_LOAD("pcwboot.bin", 0x010000, 608, BAD_DUMP CRC(679b0287) SHA1(5dde974304e3376ace00850d6b4c8ec3b674199e)) \ |
| 1067 | ROM_REGION(0x010000, "maincpu",0) \ |
| 1068 | ROM_FILL(0x0000,0x10000,0x00) \ |
| 1069 | /* ROM_LOAD("pcwboot.bin", 0x010000, 608, BAD_DUMP CRC(679b0287) SHA1(5dde974304e3376ace00850d6b4c8ec3b674199e))*/ \ |
| 1070 | ROM_REGION(256,"bootcode",0) \ |
| 1071 | ROM_LOAD("8256boot.bin", 0, 256, NO_DUMP CRC(d55925bd) SHA1(bca6a47d657557be99cb8580d4bf90968d8dde4a)) \ |
| 1040 | 1072 | ROM_END \ |
| 1041 | 1073 | |
| 1042 | 1074 | ROM_PCW(pcw8256) |