src/mess/drivers/pockstat.c
| r6300 | r6301 | |
| 4 | 4 | |
| 5 | 5 | 05/2009 Skeleton driver written. |
| 6 | 6 | 11/2009 Initial bring-up commenced by Harmony. |
| 7 | 11/2009 Playable state achieved by Harmony. |
| 7 | 8 | |
| 8 | 9 | PocketStation games were dowloaded from PS1 games into flash RAM after |
| 9 | 10 | the unit had been inserted in the memory card slot, and so this should |
| r6300 | r6301 | |
| 22 | 23 | * http://exophase.devzero.co.uk/ps_info.txt |
| 23 | 24 | * http://members.at.infoseek.co.jp/DrHell/pocket/index.html |
| 24 | 25 | |
| 25 | | The current reason why the driver fails to run is: |
| 26 | | - The BIOS is displeased by the RTC data that it is getting. |
| 26 | Currently, a handful of games run, but some die due to odd hardware |
| 27 | issues. |
| 27 | 28 | |
| 28 | 29 | ****************************************************************************/ |
| 29 | 30 | |
| 30 | 31 | #include "driver.h" |
| 31 | 32 | #include "cpu/arm7/arm7.h" |
| 32 | 33 | #include "cpu/arm7/arm7core.h" |
| 34 | #include "devices/cartslot.h" |
| 35 | #include "sound/dac.h" |
| 33 | 36 | |
| 34 | 37 | #define DEFAULT_CLOCK 2000000 |
| 35 | 38 | |
| r6300 | r6301 | |
| 53 | 56 | 0x7a0000 |
| 54 | 57 | }; |
| 55 | 58 | |
| 56 | | #define VERBOSE_LEVEL ( 0 ) |
| 59 | #define VERBOSE_LEVEL (0) |
| 57 | 60 | |
| 58 | | #define ENABLE_VERBOSE_LOG (0) |
| 61 | #define ENABLE_VERBOSE_LOG (0) |
| 59 | 62 | |
| 60 | 63 | #if ENABLE_VERBOSE_LOG |
| 61 | 64 | INLINE void ATTR_PRINTF(3,4) verboselog( running_machine *machine, int n_level, const char *s_fmt, ... ) |
| r6300 | r6301 | |
| 146 | 149 | UINT32 count; |
| 147 | 150 | UINT32 control; |
| 148 | 151 | emu_timer *timer; |
| 149 | | emu_timer *int_reset_timer; // Probably not right |
| 150 | 152 | } ps_timer_t; |
| 151 | 153 | |
| 152 | 154 | typedef struct |
| r6300 | r6301 | |
| 183 | 185 | { |
| 184 | 186 | case 0x0000/4: |
| 185 | 187 | verboselog(space->machine, 0, "ps_ftlb_r: FlashROM TLB Control = %08x & %08x\n", ftlb_regs.control, mem_mask ); |
| 186 | | return ftlb_regs.control; |
| 188 | return ftlb_regs.control | 1; // ??? |
| 187 | 189 | case 0x0004/4: |
| 188 | 190 | verboselog(space->machine, 0, "ps_ftlb_r: Unknown (F_STAT) = %08x & %08x\n", ftlb_regs.stat, mem_mask ); |
| 189 | 191 | return ftlb_regs.stat; |
| r6300 | r6301 | |
| 194 | 196 | verboselog(space->machine, 0, "ps_ftlb_r: Unknown (F_WAIT1) = %08x & %08x\n", ftlb_regs.wait1, mem_mask ); |
| 195 | 197 | return ftlb_regs.wait1; |
| 196 | 198 | case 0x0010/4: |
| 197 | | verboselog(space->machine, 0, "ps_ftlb_r: Unknown (F_WAIT2) = %08x & %08x\n", ftlb_regs.wait2, mem_mask ); |
| 198 | | return ftlb_regs.wait2; |
| 199 | verboselog(space->machine, 0, "ps_ftlb_r: Unknown (F_WAIT2) = %08x & %08x\n", ftlb_regs.wait2 | 0x08, mem_mask ); |
| 200 | return ftlb_regs.wait2 | 0x08; |
| 199 | 201 | case 0x0100/4: |
| 200 | 202 | case 0x0104/4: |
| 201 | 203 | case 0x0108/4: |
| r6300 | r6301 | |
| 296 | 298 | else |
| 297 | 299 | { |
| 298 | 300 | intc_regs.status &= ~line; |
| 301 | intc_regs.hold &= ~line; |
| 299 | 302 | } |
| 300 | 303 | } |
| 301 | 304 | if(intc_regs.hold & PS_INT_IRQ_MASK) |
| r6300 | r6301 | |
| 420 | 423 | verboselog(space->machine, 0, "ps_timer_r: Timer %d Count = %08x & %08x\n", offset / (0x10/4), timer_regs.timer[offset / (0x10/4)].count, mem_mask ); |
| 421 | 424 | if(timer_regs.timer[offset / (0x10/4)].control & 4) |
| 422 | 425 | { |
| 426 | timer_regs.timer[offset / (0x10/4)].count -= 0x100; |
| 427 | if(timer_regs.timer[offset / (0x10/4)].count > timer_regs.timer[offset / (0x10/4)].period) |
| 428 | { |
| 429 | timer_regs.timer[offset / (0x10/4)].count = timer_regs.timer[offset / (0x10/4)].period; |
| 430 | } |
| 423 | 431 | return --timer_regs.timer[offset / (0x10/4)].count; |
| 424 | 432 | } |
| 425 | 433 | return timer_regs.timer[offset / (0x10/4)].count; |
| r6300 | r6301 | |
| 586 | 594 | break; |
| 587 | 595 | case 0x0004/4: |
| 588 | 596 | verboselog(space->machine, 0, "ps_rtc_w: RTC Control = %08x & %08x\n", data, mem_mask ); |
| 589 | | COMBINE_DATA(&rtc_regs.control); |
| 597 | if(rtc_regs.control == 1 && data == 1) |
| 598 | { |
| 599 | switch(rtc_regs.mode >> 1) |
| 600 | { |
| 601 | case 0: // Seconds |
| 602 | rtc_regs.time += 0x00000001; |
| 603 | if((rtc_regs.time & 0x0000000f) == 0x0000000a) |
| 604 | { |
| 605 | rtc_regs.time &= 0xfffffff0; |
| 606 | rtc_regs.time += 0x00000010; |
| 607 | if((rtc_regs.time & 0x000000ff) == 0x00000060) |
| 608 | { |
| 609 | rtc_regs.time &= 0xffffff00; |
| 610 | } |
| 611 | } |
| 612 | break; |
| 613 | case 1: // Minutes |
| 614 | rtc_regs.time += 0x00000100; |
| 615 | if((rtc_regs.time & 0x00000f00) == 0x00000a00) |
| 616 | { |
| 617 | rtc_regs.time &= 0xfffff0ff; |
| 618 | rtc_regs.time += 0x00001000; |
| 619 | if((rtc_regs.time & 0x0000ff00) == 0x00006000) |
| 620 | { |
| 621 | rtc_regs.time &= 0xffff00ff; |
| 622 | } |
| 623 | } |
| 624 | break; |
| 625 | case 2: // Hours |
| 626 | rtc_regs.time += 0x00010000; |
| 627 | if((rtc_regs.time & 0x00ff0000) == 0x00240000) |
| 628 | { |
| 629 | rtc_regs.time &= 0xff00ffff; |
| 630 | } |
| 631 | else if((rtc_regs.time & 0x000f0000) == 0x000a0000) |
| 632 | { |
| 633 | rtc_regs.time &= 0xfff0ffff; |
| 634 | rtc_regs.time += 0x00100000; |
| 635 | } |
| 636 | break; |
| 637 | case 3: // Day of the week |
| 638 | rtc_regs.time += 0x01000000; |
| 639 | if((rtc_regs.time & 0x0f000000) == 0x08000000) |
| 640 | { |
| 641 | rtc_regs.time &= 0xf0ffffff; |
| 642 | rtc_regs.time |= 0x01000000; |
| 643 | } |
| 644 | break; |
| 645 | case 4: // Day |
| 646 | rtc_regs.date += 0x00000001; |
| 647 | if((rtc_regs.date & 0x000000ff) == 0x00000032) |
| 648 | { |
| 649 | rtc_regs.date &= 0xffffff00; |
| 650 | } |
| 651 | else if((rtc_regs.date & 0x0000000f) == 0x0000000a) |
| 652 | { |
| 653 | rtc_regs.date &= 0xfffffff0; |
| 654 | rtc_regs.date += 0x00000010; |
| 655 | } |
| 656 | break; |
| 657 | case 5: // Month |
| 658 | rtc_regs.date += 0x00000100; |
| 659 | if((rtc_regs.date & 0x0000ff00) == 0x00001300) |
| 660 | { |
| 661 | rtc_regs.date &= 0xffffff00; |
| 662 | rtc_regs.date |= 0x00000001; |
| 663 | } |
| 664 | else if((rtc_regs.date & 0x00000f00) == 0x00000a00) |
| 665 | { |
| 666 | rtc_regs.date &= 0xfffff0ff; |
| 667 | rtc_regs.date += 0x00001000; |
| 668 | } |
| 669 | break; |
| 670 | case 6: // Year (LSB) |
| 671 | rtc_regs.date += 0x00010000; |
| 672 | if((rtc_regs.date & 0x000f0000) == 0x000a0000) |
| 673 | { |
| 674 | rtc_regs.date &= 0xfff0ffff; |
| 675 | rtc_regs.date += 0x00100000; |
| 676 | if((rtc_regs.date & 0x00f00000) == 0x00a00000) |
| 677 | { |
| 678 | rtc_regs.date &= 0xff00ffff; |
| 679 | } |
| 680 | } |
| 681 | break; |
| 682 | case 7: // Year (MSB) |
| 683 | break; |
| 684 | } |
| 685 | rtc_regs.control = 0; |
| 686 | } |
| 687 | else if(rtc_regs.control == 0) |
| 688 | { |
| 689 | COMBINE_DATA(&rtc_regs.control); |
| 690 | } |
| 590 | 691 | break; |
| 591 | 692 | default: |
| 592 | 693 | verboselog(space->machine, 0, "ps_rtc_w: Unknown Register %08x = %08x & %08x\n", 0x0b800000 + (offset << 2), data, mem_mask ); |
| r6300 | r6301 | |
| 635 | 736 | ps_intc_set_interrupt_line(field->port->machine, PS_INT_BTN_UP, (buttons & 16) ? 1 : 0); |
| 636 | 737 | } |
| 637 | 738 | |
| 739 | static READ32_HANDLER(ps_rombank_r) |
| 740 | { |
| 741 | INT32 bank = (offset >> 11) & 0x0f; |
| 742 | int index = 0; |
| 743 | for(index = 0; index < 32; index++) |
| 744 | { |
| 745 | if(ftlb_regs.valid & (1 << index)) |
| 746 | { |
| 747 | if(ftlb_regs.entry[index] == bank) |
| 748 | { |
| 749 | //printf( "Address %08x is assigned to %08x in entry %d\n", 0x02000000 + (offset << 2), index * 0x2000 + ((offset << 2) & 0x1fff), index ); |
| 750 | return ((UINT32*)memory_region(space->machine, "flash"))[index * (0x2000/4) + (offset & (0x1fff/4))]; |
| 751 | } |
| 752 | } |
| 753 | } |
| 754 | return ((UINT32*)memory_region(space->machine, "flash"))[offset & 0x7fff]; |
| 755 | } |
| 756 | |
| 757 | static INT32 ps_flash_write_enable_count; |
| 758 | static INT32 ps_flash_write_count; |
| 759 | |
| 760 | // Horrible hack, probably wrong |
| 761 | static WRITE32_HANDLER(ps_flash_w) |
| 762 | { |
| 763 | if(offset == (0x55a8/4)) |
| 764 | { |
| 765 | ps_flash_write_enable_count++; |
| 766 | return; |
| 767 | } |
| 768 | if(offset == (0x2a54/4)) |
| 769 | { |
| 770 | ps_flash_write_enable_count++; |
| 771 | return; |
| 772 | } |
| 773 | if(ps_flash_write_enable_count == 3) |
| 774 | { |
| 775 | ps_flash_write_enable_count = 0; |
| 776 | ps_flash_write_count = 0x40; |
| 777 | return; |
| 778 | } |
| 779 | if(ps_flash_write_count) |
| 780 | { |
| 781 | ps_flash_write_count--; |
| 782 | COMBINE_DATA(&((UINT32*)memory_region(space->machine, "flash"))[offset]); |
| 783 | } |
| 784 | } |
| 785 | |
| 638 | 786 | static ADDRESS_MAP_START(pockstat_mem, ADDRESS_SPACE_PROGRAM, 32) |
| 639 | 787 | AM_RANGE(0x00000000, 0x000007ff) AM_RAM |
| 788 | AM_RANGE(0x02000000, 0x02ffffff) AM_READ(ps_rombank_r) |
| 640 | 789 | AM_RANGE(0x04000000, 0x04003fff) AM_ROM AM_REGION("maincpu", 0) |
| 641 | 790 | AM_RANGE(0x06000000, 0x06000307) AM_READWRITE(ps_ftlb_r, ps_ftlb_w) |
| 791 | AM_RANGE(0x08000000, 0x0801ffff) AM_ROM AM_WRITE(ps_flash_w) AM_REGION("flash", 0) |
| 642 | 792 | AM_RANGE(0x0a000000, 0x0a000013) AM_READWRITE(ps_intc_r, ps_intc_w) |
| 643 | 793 | AM_RANGE(0x0a800000, 0x0a80002b) AM_READWRITE(ps_timer_r, ps_timer_w) |
| 644 | 794 | AM_RANGE(0x0b000000, 0x0b000007) AM_READWRITE(ps_clock_r, ps_clock_w) |
| 645 | 795 | AM_RANGE(0x0b800000, 0x0b80000f) AM_READWRITE(ps_rtc_r, ps_rtc_w) |
| 646 | 796 | AM_RANGE(0x0d000000, 0x0d000003) AM_READWRITE(ps_lcd_r, ps_lcd_w) |
| 647 | 797 | AM_RANGE(0x0d000100, 0x0d00017f) AM_RAM AM_BASE(&lcd_buffer) |
| 648 | | /* AM_RANGE(0x02000000, 0x0201ffff) Flash ROM |
| 649 | | AM_RANGE(0x08000000, 0x0801ffff) Same as 0x02 above. Mirrors every 128KB. |
| 650 | | AM_RANGE(0x0b000000, 0x0b000003) Internal CPU Clock control |
| 651 | | AM_RANGE(0x0b800000, 0x0b800003) RTC control word |
| 652 | | AM_RANGE(0x0b800004, 0x0b800007) RTC Modify value (write only) |
| 653 | | AM_RANGE(0x0b800008, 0x0b80000b) RTC Time of day + day of week (read only) |
| 654 | | AM_RANGE(0x0b80000c, 0x0b80000f) RTC Date (read only) |
| 655 | | AM_RANGE(0x0d000000, 0x0b000003) LCD control word |
| 656 | | AM_RANGE(0x0d000100, 0x0b00017f) LCD buffer - 1 word per scanline */ |
| 657 | 798 | ADDRESS_MAP_END |
| 658 | 799 | |
| 659 | 800 | /* Input ports */ |
| r6300 | r6301 | |
| 681 | 822 | |
| 682 | 823 | rtc_regs.timer = timer_alloc(machine, rtc_tick, 0); |
| 683 | 824 | timer_adjust_oneshot(rtc_regs.timer, ATTOTIME_IN_HZ(1), index); |
| 825 | |
| 826 | state_save_register_global(machine, ftlb_regs.control); |
| 827 | state_save_register_global(machine, ftlb_regs.stat); |
| 828 | state_save_register_global(machine, ftlb_regs.valid); |
| 829 | state_save_register_global(machine, ftlb_regs.wait1); |
| 830 | state_save_register_global(machine, ftlb_regs.wait2); |
| 831 | state_save_register_global_array(machine, ftlb_regs.entry); |
| 832 | |
| 833 | state_save_register_global(machine, intc_regs.hold); |
| 834 | state_save_register_global(machine, intc_regs.status); |
| 835 | state_save_register_global(machine, intc_regs.enable); |
| 836 | state_save_register_global(machine, intc_regs.mask); |
| 837 | |
| 838 | state_save_register_global(machine, timer_regs.timer[0].period); |
| 839 | state_save_register_global(machine, timer_regs.timer[0].count); |
| 840 | state_save_register_global(machine, timer_regs.timer[0].control); |
| 841 | state_save_register_global(machine, timer_regs.timer[1].period); |
| 842 | state_save_register_global(machine, timer_regs.timer[1].count); |
| 843 | state_save_register_global(machine, timer_regs.timer[1].control); |
| 844 | state_save_register_global(machine, timer_regs.timer[2].period); |
| 845 | state_save_register_global(machine, timer_regs.timer[2].count); |
| 846 | state_save_register_global(machine, timer_regs.timer[2].control); |
| 847 | |
| 848 | state_save_register_global(machine, clock_regs.mode); |
| 849 | state_save_register_global(machine, clock_regs.control); |
| 850 | |
| 851 | state_save_register_global(machine, rtc_regs.mode); |
| 852 | state_save_register_global(machine, rtc_regs.control); |
| 853 | state_save_register_global(machine, rtc_regs.time); |
| 854 | state_save_register_global(machine, rtc_regs.date); |
| 855 | |
| 856 | state_save_register_global(machine, ps_flash_write_enable_count); |
| 857 | state_save_register_global(machine, ps_flash_write_count); |
| 684 | 858 | } |
| 685 | 859 | |
| 686 | 860 | static MACHINE_RESET( pockstat ) |
| 687 | 861 | { |
| 688 | 862 | cpu_set_reg(cputag_get_cpu(machine, "maincpu"), REG_GENPC, 0x4000000); |
| 863 | |
| 864 | ps_flash_write_enable_count = 0; |
| 865 | ps_flash_write_count = 0; |
| 689 | 866 | } |
| 690 | 867 | |
| 691 | 868 | static VIDEO_UPDATE( pockstat ) |
| r6300 | r6301 | |
| 697 | 874 | UINT32 *scanline = BITMAP_ADDR32(bitmap, y, 0); |
| 698 | 875 | for(x = 0; x < 32; x++) |
| 699 | 876 | { |
| 700 | | if(lcd_buffer[y] & (1 << x)) |
| 877 | if(lcd_control != 0) // Hack |
| 701 | 878 | { |
| 702 | | scanline[x] = 0x00000000; |
| 879 | if(lcd_buffer[y] & (1 << x)) |
| 880 | { |
| 881 | scanline[x] = 0x00000000; |
| 882 | } |
| 883 | else |
| 884 | { |
| 885 | scanline[x] = 0x00ffffff; |
| 886 | } |
| 703 | 887 | } |
| 704 | 888 | else |
| 705 | 889 | { |
| r6300 | r6301 | |
| 710 | 894 | return 0; |
| 711 | 895 | } |
| 712 | 896 | |
| 897 | static DEVICE_IMAGE_LOAD( pockstat_flash) |
| 898 | { |
| 899 | int i, length; |
| 900 | UINT8 *cart = memory_region(image->machine, "flash"); |
| 901 | static const char *gme_id = "123-456-STD"; |
| 902 | |
| 903 | length = image_fread(image, cart, 0x20f40); |
| 904 | |
| 905 | if(length != 0x20f40) |
| 906 | { |
| 907 | return INIT_FAIL; |
| 908 | } |
| 909 | |
| 910 | for(i = 0; i < strlen(gme_id); i++) |
| 911 | { |
| 912 | if(cart[i] != gme_id[i]) |
| 913 | { |
| 914 | return INIT_FAIL; |
| 915 | } |
| 916 | } |
| 917 | |
| 918 | memcpy(cart, cart + 0xf40, 0x20000); |
| 919 | |
| 920 | return INIT_PASS; |
| 921 | } |
| 922 | |
| 713 | 923 | static MACHINE_DRIVER_START( pockstat ) |
| 714 | 924 | /* basic machine hardware */ |
| 715 | 925 | MDRV_CPU_ADD("maincpu", ARM7, DEFAULT_CLOCK) |
| r6300 | r6301 | |
| 730 | 940 | |
| 731 | 941 | MDRV_VIDEO_START(generic_bitmapped) |
| 732 | 942 | MDRV_VIDEO_UPDATE(pockstat) |
| 943 | |
| 944 | MDRV_SPEAKER_STANDARD_MONO("mono") |
| 945 | MDRV_SOUND_ADD("dac", DAC, 0) |
| 946 | MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) |
| 947 | |
| 948 | /* cartridge */ |
| 949 | MDRV_CARTSLOT_ADD("cart") |
| 950 | MDRV_CARTSLOT_EXTENSION_LIST("gme") |
| 951 | MDRV_CARTSLOT_NOT_MANDATORY |
| 952 | MDRV_CARTSLOT_LOAD(pockstat_flash) |
| 733 | 953 | MACHINE_DRIVER_END |
| 734 | 954 | |
| 735 | 955 | /* ROM definition */ |
| 736 | 956 | ROM_START( pockstat ) |
| 737 | 957 | ROM_REGION( 0x4000, "maincpu", 0 ) |
| 738 | 958 | ROM_LOAD( "kernel.bin", 0x0000, 0x4000, CRC(5fb47dd8) SHA1(6ae880493ddde880827d1e9f08e9cb2c38f9f2ec) ) |
| 959 | |
| 960 | ROM_REGION( 0x20f40, "flash", ROMREGION_ERASEFF ) |
| 739 | 961 | ROM_END |
| 740 | 962 | |
| 741 | 963 | /* Driver */ |
| 742 | 964 | |
| 743 | 965 | /* YEAR NAME PARENT COMPAT MACHINE INPUT INIT CONFIG COMPANY FULLNAME FLAGS */ |
| 744 | | CONS( 1999, pockstat, 0, 0, pockstat, pockstat, 0, 0, "Sony Computer Entertainment Inc.", "Sony PocketStation", GAME_NOT_WORKING ) |
| 966 | CONS( 1999, pockstat, 0, 0, pockstat, pockstat, 0, 0, "Sony Computer Entertainment Inc.", "Sony PocketStation", GAME_NO_SOUND | GAME_SUPPORTS_SAVE ) |