src/mess/machine/gb.c
| r6001 | r6002 | |
| 68 | 68 | #define MAX_ROMBANK 512 |
| 69 | 69 | #define MAX_RAMBANK 256 |
| 70 | 70 | |
| 71 | | #define JOYPAD gb_io[0x00] /* Joystick: 1.1.P15.P14.P13.P12.P11.P10 */ |
| 72 | | #define SIODATA gb_io[0x01] /* Serial IO data buffer */ |
| 73 | | #define SIOCONT gb_io[0x02] /* Serial IO control register */ |
| 74 | | #define DIVREG gb_io[0x04] /* Divider register (???) */ |
| 75 | | #define TIMECNT gb_io[0x05] /* Timer counter. Gen. int. when it overflows */ |
| 76 | | #define TIMEMOD gb_io[0x06] /* New value of TimeCount after it overflows */ |
| 77 | | #define TIMEFRQ gb_io[0x07] /* Timer frequency and start/stop switch */ |
| 71 | #define JOYPAD gb_driver_data.gb_io[0x00] /* Joystick: 1.1.P15.P14.P13.P12.P11.P10 */ |
| 72 | #define SIODATA gb_driver_data.gb_io[0x01] /* Serial IO data buffer */ |
| 73 | #define SIOCONT gb_driver_data.gb_io[0x02] /* Serial IO control register */ |
| 74 | #define DIVREG gb_driver_data.gb_io[0x04] /* Divider register (???) */ |
| 75 | #define TIMECNT gb_driver_data.gb_io[0x05] /* Timer counter. Gen. int. when it overflows */ |
| 76 | #define TIMEMOD gb_driver_data.gb_io[0x06] /* New value of TimeCount after it overflows */ |
| 77 | #define TIMEFRQ gb_driver_data.gb_io[0x07] /* Timer frequency and start/stop switch */ |
| 78 | 78 | |
| 79 | 79 | static UINT16 MBCType; /* MBC type: 0 for none */ |
| 80 | 80 | static UINT8 CartType; /* Cart Type (battery, ram, timer etc) */ |
| r6001 | r6002 | |
| 104 | 104 | |
| 105 | 105 | static UINT8 *gb_cart = NULL; |
| 106 | 106 | static UINT8 *gb_cart_ram = NULL; |
| 107 | | static UINT8 gb_io[0x10]; |
| 108 | 107 | static UINT8 *gb_dummy_rom_bank = NULL; |
| 109 | 108 | static UINT8 *gb_dummy_ram_bank = NULL; |
| 110 | 109 | /* TAMA5 related global variables */ |
| r6001 | r6002 | |
| 112 | 111 | static UINT8 gbTama5Byte; |
| 113 | 112 | static UINT8 gbTama5Address; |
| 114 | 113 | static UINT8 gbLastTama5Command; |
| 115 | | /* Timer related globals */ |
| 116 | | static struct gb_timer_struct { |
| 117 | | UINT16 divcount; |
| 118 | | UINT8 shift; |
| 119 | | UINT16 shift_cycles; |
| 120 | | UINT8 triggering_irq; |
| 121 | | UINT8 reloading; |
| 122 | | } gb_timer; |
| 123 | | /* Serial I/O related */ |
| 124 | | static UINT32 SIOCount; /* Serial I/O counter */ |
| 125 | | static emu_timer *gb_serial_timer = NULL; |
| 126 | 114 | |
| 115 | typedef struct _gb_state gb_state; |
| 116 | struct _gb_state { |
| 117 | UINT8 gb_io[0x10]; |
| 118 | |
| 119 | /* Timer related */ |
| 120 | UINT16 divcount; |
| 121 | UINT8 shift; |
| 122 | UINT16 shift_cycles; |
| 123 | UINT8 triggering_irq; |
| 124 | UINT8 reloading; |
| 125 | |
| 126 | /* Serial I/O related */ |
| 127 | UINT32 SIOCount; /* Serial I/O counter */ |
| 128 | emu_timer *gb_serial_timer; |
| 129 | }; |
| 130 | |
| 131 | static gb_state gb_driver_data; |
| 132 | |
| 127 | 133 | /* |
| 128 | 134 | Prototypes |
| 129 | 135 | */ |
| r6001 | r6002 | |
| 283 | 289 | gb_sound_w(devtag_get_device(space->machine, "custom"), 0x16, 0x00 ); /* Initialize sound hardware */ |
| 284 | 290 | |
| 285 | 291 | /* Allocate the serial timer, and disable it */ |
| 286 | | gb_serial_timer = timer_alloc(machine, gb_serial_timer_proc , NULL); |
| 287 | | timer_enable( gb_serial_timer, 0 ); |
| 292 | gb_driver_data.gb_serial_timer = timer_alloc(machine, gb_serial_timer_proc , NULL); |
| 293 | timer_enable( gb_driver_data.gb_serial_timer, 0 ); |
| 288 | 294 | |
| 289 | | gb_timer.divcount = 0; |
| 290 | | gb_timer.triggering_irq = 0; |
| 291 | | gb_io[0x07] = 0xF8; /* Upper bits of TIMEFRQ register are set to 1 */ |
| 295 | gb_driver_data.divcount = 0; |
| 296 | gb_driver_data.triggering_irq = 0; |
| 297 | gb_driver_data.gb_io[0x07] = 0xF8; /* Upper bits of TIMEFRQ register are set to 1 */ |
| 292 | 298 | } |
| 293 | 299 | |
| 294 | 300 | MACHINE_START( gb ) |
| r6001 | r6002 | |
| 307 | 313 | /* Enable BIOS rom */ |
| 308 | 314 | memory_set_bankptr(machine, 5, memory_region(machine, "maincpu") ); |
| 309 | 315 | |
| 310 | | gb_timer.divcount = 0x0004; |
| 316 | gb_driver_data.divcount = 0x0004; |
| 311 | 317 | } |
| 312 | 318 | |
| 313 | 319 | MACHINE_RESET( sgb ) |
| r6001 | r6002 | |
| 348 | 354 | sgb_hack = 1; |
| 349 | 355 | } |
| 350 | 356 | |
| 351 | | gb_timer.divcount = 0x0004; //0xABC8; // needs to be fixed for bootrom, probably should be 0x0004 like dmg |
| 357 | gb_driver_data.divcount = 0x0004; |
| 352 | 358 | } |
| 353 | 359 | |
| 354 | 360 | MACHINE_RESET( gbpocket ) |
| r6001 | r6002 | |
| 367 | 373 | /* Enable BIOS rom if we have one */ |
| 368 | 374 | gb_rom16_0000( machine, ROMMap[ROMBank00] ? ROMMap[ROMBank00] : gb_dummy_rom_bank ); |
| 369 | 375 | |
| 370 | | gb_timer.divcount = 0xABC8; |
| 376 | gb_driver_data.divcount = 0xABC8; |
| 371 | 377 | } |
| 372 | 378 | |
| 373 | 379 | MACHINE_RESET( gbc ) |
| r6001 | r6002 | |
| 814 | 820 | case 0x00: |
| 815 | 821 | case 0x01: |
| 816 | 822 | case 0x80: /* enabled & external clock */ |
| 817 | | SIOCount = 0; |
| 823 | gb_driver_data.SIOCount = 0; |
| 818 | 824 | break; |
| 819 | 825 | case 0x81: /* enabled & internal clock */ |
| 820 | 826 | SIODATA = 0xFF; |
| 821 | | SIOCount = 8; |
| 822 | | timer_adjust_periodic(gb_serial_timer, cputag_clocks_to_attotime(space->machine, "maincpu", 512), 0, cputag_clocks_to_attotime(space->machine, "maincpu", 512)); |
| 823 | | timer_enable( gb_serial_timer, 1 ); |
| 827 | gb_driver_data.SIOCount = 8; |
| 828 | timer_adjust_periodic(gb_driver_data.gb_serial_timer, cputag_clocks_to_attotime(space->machine, "maincpu", 512), 0, cputag_clocks_to_attotime(space->machine, "maincpu", 512)); |
| 829 | timer_enable( gb_driver_data.gb_serial_timer, 1 ); |
| 824 | 830 | break; |
| 825 | 831 | } |
| 826 | 832 | break; |
| 827 | 833 | case 0x04: /* DIV - Divider register */ |
| 828 | 834 | /* Force increment of TIMECNT register */ |
| 829 | | if ( gb_timer.divcount >= 16 ) |
| 835 | if ( gb_driver_data.divcount >= 16 ) |
| 830 | 836 | gb_timer_increment(space->machine); |
| 831 | | gb_timer.divcount = 0; |
| 837 | gb_driver_data.divcount = 0; |
| 832 | 838 | return; |
| 833 | 839 | case 0x05: /* TIMA - Timer counter */ |
| 834 | 840 | /* Check if the counter is being reloaded in this cycle */ |
| 835 | | if ( gb_timer.reloading && ( gb_timer.divcount & ( gb_timer.shift_cycles - 1 ) ) == 4 ) |
| 841 | if ( gb_driver_data.reloading && ( gb_driver_data.divcount & ( gb_driver_data.shift_cycles - 1 ) ) == 4 ) |
| 836 | 842 | { |
| 837 | 843 | data = TIMECNT; |
| 838 | 844 | } |
| 839 | 845 | break; |
| 840 | 846 | case 0x06: /* TMA - Timer module */ |
| 841 | 847 | /* Check if the counter is being reloaded in this cycle */ |
| 842 | | if ( gb_timer.reloading && ( gb_timer.divcount & ( gb_timer.shift_cycles - 1 ) ) == 4 ) |
| 848 | if ( gb_driver_data.reloading && ( gb_driver_data.divcount & ( gb_driver_data.shift_cycles - 1 ) ) == 4 ) |
| 843 | 849 | { |
| 844 | 850 | TIMECNT = data; |
| 845 | 851 | } |
| r6001 | r6002 | |
| 850 | 856 | if ( ( ! ( data & 0x04 ) && ( TIMEFRQ & 0x04 ) ) || ( ( data & 0x04 ) && ( TIMEFRQ & 0x04 ) && ( data & 0x03 ) != ( TIMEFRQ & 0x03 ) ) ) |
| 851 | 857 | { |
| 852 | 858 | /* Check if TIMECNT should be incremented */ |
| 853 | | if ( ( gb_timer.divcount & ( gb_timer.shift_cycles - 1 ) ) >= ( gb_timer.shift_cycles >> 1 ) ) |
| 859 | if ( ( gb_driver_data.divcount & ( gb_driver_data.shift_cycles - 1 ) ) >= ( gb_driver_data.shift_cycles >> 1 ) ) |
| 854 | 860 | { |
| 855 | 861 | gb_timer_increment(space->machine); |
| 856 | 862 | } |
| 857 | 863 | } |
| 858 | | gb_timer.shift = timer_shifts[data & 0x03]; |
| 859 | | gb_timer.shift_cycles = 1 << gb_timer.shift; |
| 864 | gb_driver_data.shift = timer_shifts[data & 0x03]; |
| 865 | gb_driver_data.shift_cycles = 1 << gb_driver_data.shift; |
| 860 | 866 | break; |
| 861 | 867 | case 0x0F: /* IF - Interrupt flag */ |
| 862 | 868 | data &= 0x1F; |
| r6001 | r6002 | |
| 864 | 870 | break; |
| 865 | 871 | } |
| 866 | 872 | |
| 867 | | gb_io[offset] = data; |
| 873 | gb_driver_data.gb_io[offset] = data; |
| 868 | 874 | } |
| 869 | 875 | |
| 870 | 876 | WRITE8_HANDLER ( gb_io2_w ) |
| r6001 | r6002 | |
| 1405 | 1411 | return; |
| 1406 | 1412 | } |
| 1407 | 1413 | |
| 1408 | | gb_io[offset] = data; |
| 1414 | gb_driver_data.gb_io[offset] = data; |
| 1409 | 1415 | } |
| 1410 | 1416 | |
| 1411 | 1417 | /* Interrupt Enable register */ |
| r6001 | r6002 | |
| 1425 | 1431 | switch(offset) |
| 1426 | 1432 | { |
| 1427 | 1433 | case 0x04: |
| 1428 | | return ( gb_timer.divcount >> 8 ) & 0xFF; |
| 1434 | return ( gb_driver_data.divcount >> 8 ) & 0xFF; |
| 1429 | 1435 | case 0x00: |
| 1430 | 1436 | case 0x01: |
| 1431 | 1437 | case 0x02: |
| r6001 | r6002 | |
| 1433 | 1439 | case 0x05: |
| 1434 | 1440 | case 0x06: |
| 1435 | 1441 | case 0x07: |
| 1436 | | return gb_io[offset]; |
| 1442 | return gb_driver_data.gb_io[offset]; |
| 1437 | 1443 | case 0x0F: |
| 1438 | 1444 | /* Make sure the internal states are up to date */ |
| 1439 | 1445 | return 0xE0 | cpu_get_reg( cputag_get_cpu(space->machine, "maincpu"), LR35902_IF ); |
| r6001 | r6002 | |
| 1907 | 1913 | /* Shift in a received bit */ |
| 1908 | 1914 | SIODATA = (SIODATA << 1) | 0x01; |
| 1909 | 1915 | /* Decrement number of handled bits */ |
| 1910 | | SIOCount--; |
| 1916 | gb_driver_data.SIOCount--; |
| 1911 | 1917 | /* If all bits done, stop timer and trigger interrupt */ |
| 1912 | | if ( ! SIOCount ) |
| 1918 | if ( ! gb_driver_data.SIOCount ) |
| 1913 | 1919 | { |
| 1914 | 1920 | SIOCONT &= 0x7F; |
| 1915 | | timer_enable( gb_serial_timer, 0 ); |
| 1921 | timer_enable( gb_driver_data.gb_serial_timer, 0 ); |
| 1916 | 1922 | cputag_set_input_line(machine, "maincpu", SIO_INT, ASSERT_LINE); |
| 1917 | 1923 | } |
| 1918 | 1924 | } |
| 1919 | 1925 | |
| 1920 | 1926 | INLINE void gb_timer_check_irq( running_machine *machine ) |
| 1921 | 1927 | { |
| 1922 | | gb_timer.reloading = 0; |
| 1923 | | if ( gb_timer.triggering_irq ) |
| 1928 | gb_driver_data.reloading = 0; |
| 1929 | if ( gb_driver_data.triggering_irq ) |
| 1924 | 1930 | { |
| 1925 | | gb_timer.triggering_irq = 0; |
| 1931 | gb_driver_data.triggering_irq = 0; |
| 1926 | 1932 | if ( TIMECNT == 0 ) |
| 1927 | 1933 | { |
| 1928 | 1934 | TIMECNT = TIMEMOD; |
| 1929 | 1935 | cputag_set_input_line(machine, "maincpu", TIM_INT, ASSERT_LINE ); |
| 1930 | | gb_timer.reloading = 1; |
| 1936 | gb_driver_data.reloading = 1; |
| 1931 | 1937 | } |
| 1932 | 1938 | } |
| 1933 | 1939 | } |
| r6001 | r6002 | |
| 1939 | 1945 | TIMECNT += 1; |
| 1940 | 1946 | if ( TIMECNT == 0 ) |
| 1941 | 1947 | { |
| 1942 | | gb_timer.triggering_irq = 1; |
| 1948 | gb_driver_data.triggering_irq = 1; |
| 1943 | 1949 | } |
| 1944 | 1950 | } |
| 1945 | 1951 | |
| 1946 | 1952 | void gb_timer_callback(const device_config *device, int cycles) |
| 1947 | 1953 | { |
| 1948 | | UINT16 old_gb_divcount = gb_timer.divcount; |
| 1949 | | gb_timer.divcount += cycles; |
| 1954 | UINT16 old_gb_divcount = gb_driver_data.divcount; |
| 1955 | gb_driver_data.divcount += cycles; |
| 1950 | 1956 | |
| 1951 | 1957 | gb_timer_check_irq(device->machine); |
| 1952 | 1958 | |
| 1953 | 1959 | if ( TIMEFRQ & 0x04 ) |
| 1954 | 1960 | { |
| 1955 | | UINT16 old_count = old_gb_divcount >> gb_timer.shift; |
| 1956 | | UINT16 new_count = gb_timer.divcount >> gb_timer.shift; |
| 1957 | | if ( cycles > gb_timer.shift_cycles ) |
| 1961 | UINT16 old_count = old_gb_divcount >> gb_driver_data.shift; |
| 1962 | UINT16 new_count = gb_driver_data.divcount >> gb_driver_data.shift; |
| 1963 | if ( cycles > gb_driver_data.shift_cycles ) |
| 1958 | 1964 | { |
| 1959 | 1965 | gb_timer_increment(device->machine); |
| 1960 | 1966 | old_count++; |
| r6001 | r6002 | |
| 1963 | 1969 | { |
| 1964 | 1970 | gb_timer_increment(device->machine); |
| 1965 | 1971 | } |
| 1966 | | if ( new_count << gb_timer.shift < gb_timer.divcount ) |
| 1972 | if ( new_count << gb_driver_data.shift < gb_driver_data.divcount ) |
| 1967 | 1973 | { |
| 1968 | 1974 | gb_timer_check_irq(device->machine); |
| 1969 | 1975 | } |