#include "driver.h" #include "includes/gamecom.h" #include "cpu/sm8500/sm8500.h" #include "image.h" typedef struct { int enabled; int transfer_mode; int decrement_y; int decrement_x; int overwrite_mode; int width_x; int width_y; int width_x_count; int width_y_count; int source_x; int source_x_current; int source_y; int source_width; int dest_x; int dest_x_current; int dest_y; int dest_width; int state_count; int state_pixel; int state_limit; UINT8 palette[4]; UINT8 *source_bank; unsigned int source_current; unsigned int source_line; unsigned int source_mask; UINT8 *dest_bank; unsigned int dest_current; unsigned int dest_line; unsigned int dest_mask; } GAMECOM_DMA; typedef struct { int enabled; int state_count; int state_limit; int counter; int check_value; } GAMECOM_TIMER; UINT8 *internal_ram; UINT8 internal_registers[0x80]; UINT8 gamecom_vram[16*1024]; UINT8 *cartridge1 = NULL; UINT8 *cartridge2 = NULL; UINT8 *cartridge = NULL; UINT8 *dummy_bank = NULL; static mame_timer *gamecom_clock_timer = NULL; GAMECOM_DMA gamecom_dma; GAMECOM_TIMER gamecom_timer[2]; //int gamecom_timer_limit[8] = { 2/2, 1024/2, 2048/2, 4096/2, 8192/2, 16384/2, 32768/2, 65536/2 }; int gamecom_timer_limit[8] = { 2, 1024, 2048, 4096, 8192, 16384, 32768, 65536 }; void gamecom_dma_init(void); static TIMER_CALLBACK(gamecom_clock_timer_callback) { UINT8 val = ( ( internal_registers[SM8521_CLKT] & 0x3F ) + 1 ) & 0x3F; internal_registers[SM8521_CLKT] = ( internal_registers[SM8521_CLKT] & 0xC0 ) | val; cpunum_set_input_line( 0, CK_INT, HOLD_LINE ); } MACHINE_RESET( gamecom ) { memory_set_bankptr( 1, memory_region(REGION_USER1) ); memory_set_bankptr( 2, memory_region(REGION_USER1) ); memory_set_bankptr( 3, memory_region(REGION_USER1) ); memory_set_bankptr( 4, memory_region(REGION_USER1) ); /* should possibly go in a DRIVER_INIT piece? */ if ( gamecom_clock_timer == NULL ) { gamecom_clock_timer = mame_timer_alloc( gamecom_clock_timer_callback ); } /* intialize the empty dummy bank */ if ( dummy_bank == NULL ) { dummy_bank = auto_malloc( 8 * 1024 ); } memset( dummy_bank, 0xff, sizeof( dummy_bank ) ); cartridge = NULL; /* disable DMA and timer */ gamecom_dma.enabled = 0; memset( internal_registers, 0x00, sizeof(internal_registers) ); gamecom_internal_w( SM8521_URTT, 0xFF ); gamecom_internal_w( SM8521_URTS, 0x42 ); gamecom_internal_w( SM8521_WDTC, 0x38 ); } static void gamecom_set_mmu( int mmu, UINT8 data ) { if ( data < 32 ) { /* select internal ROM bank */ memory_set_bankptr( mmu, memory_region(REGION_USER1) + (data << 13) ); } else { /* select cartridge bank */ if ( cartridge == NULL ) { memory_set_bankptr( mmu, dummy_bank ); } else { memory_set_bankptr( mmu, cartridge + ( data << 13 ) ); } } } static void handle_stylus_press( UINT8 column ) { static const UINT16 row_data[10] = { 0x3FE, 0x3FD, 0x3FB, 0x3F7, 0x3EF, 0x3DF, 0x3BF, 0x37F, 0x2FF, 0x1FF }; static UINT32 stylus_x; static UINT32 stylus_y; if ( column == 0 ) { if ( ! ( readinputport(2) & 0x04 ) ) { stylus_x = readinputport( 3 ) >> 4; stylus_y = readinputport( 4 ) >> 4; } else { stylus_x = 16; stylus_y = 16; } } if ( stylus_x == column ) { cpunum_set_reg( 0, SM8500_P0, row_data[stylus_y] & 0xFF ); cpunum_set_reg( 0, SM8500_P1, ( cpunum_get_reg( 0, SM8500_P1 ) & 0xFC ) | ( ( row_data[stylus_y] >> 8 ) & 0x03 ) ); } else { cpunum_set_reg( 0, SM8500_P0, 0xFF ); cpunum_set_reg( 0, SM8500_P1, ( cpunum_get_reg( 0, SM8500_P1 ) & 0xFC ) | 0x03 ); } } WRITE8_HANDLER( gamecom_internal_w ) { if ( offset >= 0x80 ) { internal_ram[offset] = data; return; } switch( offset ) { case SM8521_IE0: cpunum_set_reg( 0, SM8500_IE0, data ); return; case SM8521_IE1: cpunum_set_reg( 0, SM8500_IE1, data ); return; case SM8521_IR0: cpunum_set_reg( 0, SM8500_IR0, data ); return; case SM8521_IR1: cpunum_set_reg( 0, SM8500_IR1, data ); return; case SM8521_P0: cpunum_set_reg( 0, SM8500_P0, data ); return; case SM8521_P1: cpunum_set_reg( 0, SM8500_P1, data ); return; case SM8521_P2: cpunum_set_reg( 0, SM8500_P2, data ); switch( ( cpunum_get_reg( 0, SM8500_P1 ) << 8 ) | data ) { case 0xFBFF: /* column #0 */ /* P0 bit 0 cleared => 01 */ /* P0 bit 1 cleared => 0E */ /* P0 bit 2 cleared => 1B */ /* P0 bit 3 cleared => etc */ /* P0 bit 4 cleared => */ /* P0 bit 5 cleared => */ /* P0 bit 6 cleared => */ /* P0 bit 7 cleared => */ /* P1 bit 0 cleared => */ /* P1 bit 1 cleared => */ handle_stylus_press( 0 ); break; case 0xF7FF: /* column #1 */ handle_stylus_press( 1 ); break; case 0xEFFF: /* column #2 */ handle_stylus_press( 2 ); break; case 0xDFFF: /* column #3 */ handle_stylus_press( 3 ); break; case 0xBFFF: /* column #4 */ handle_stylus_press( 4 ); break; case 0x7FFF: /* column #5 */ handle_stylus_press( 5 ); break; case 0xFFFE: /* column #6 */ handle_stylus_press( 6 ); break; case 0xFFFD: /* column #7 */ handle_stylus_press( 7 ); break; case 0xFFFB: /* column #8 */ handle_stylus_press( 8 ); break; case 0xFFF7: /* column #9 */ handle_stylus_press( 9 ); break; case 0xFFEF: /* column #10 */ handle_stylus_press( 10 ); break; case 0xFFDF: /* column #11 */ handle_stylus_press( 11 ); break; case 0xFFBF: /* column #12 */ handle_stylus_press( 12 ); break; case 0xFF7F: /* keys #1 */ /* P0 bit 0 cleared => 83 (up) */ /* P0 bit 1 cleared => 84 (down) */ /* P0 bit 2 cleared => 85 (left) */ /* P0 bit 3 cleared => 86 (right) */ /* P0 bit 4 cleared => 87 (menu) */ /* P0 bit 5 cleared => 8A (pause) */ /* P0 bit 6 cleared => 89 (sound) */ /* P0 bit 7 cleared => 8B (button A) */ /* P1 bit 0 cleared => 8C (button B) */ /* P1 bit 1 cleared => 8D (button C) */ cpunum_set_reg( 0, SM8500_P0, readinputport(0) ); cpunum_set_reg( 0, SM8500_P1, ( cpunum_get_reg( 0, SM8500_P1 ) & 0xFC ) | ( readinputport(1) & 0x03 ) ); break; case 0xFFFF: /* keys #2 */ /* P0 bit 0 cleared => 88 (power) */ /* P0 bit 1 cleared => 8E (button D) */ /* P0 bit 2 cleared => A0 */ /* P0 bit 3 cleared => A0 */ /* P0 bit 4 cleared => A0 */ /* P0 bit 5 cleared => A0 */ /* P0 bit 6 cleared => A0 */ /* P0 bit 7 cleared => A0 */ /* P1 bit 0 cleared => A0 */ /* P1 bit 1 cleared => A0 */ cpunum_set_reg( 0, SM8500_P0, ( cpunum_get_reg( 0, SM8500_P0 ) & 0xFC ) | ( readinputport(2) & 0x03 ) ); cpunum_set_reg( 0, SM8500_P1, 0xFF ); break; } return; case SM8521_P3: /* P3 bit7 clear, bit6 set -> enable cartridge port #0? */ /* P3 bit6 clear, bit7 set -> enable cartridge port #1? */ cpunum_set_reg( 0, SM8500_P3, data ); switch( data & 0xc0 ) { case 0x40: cartridge = cartridge1; break; case 0x80: cartridge = cartridge2; break; default: cartridge = NULL; break; } /* update banks to reflect possible change of cartridge slot */ gamecom_set_mmu( 1, internal_registers[SM8521_MMU1] ); gamecom_set_mmu( 2, internal_registers[SM8521_MMU2] ); gamecom_set_mmu( 3, internal_registers[SM8521_MMU3] ); gamecom_set_mmu( 4, internal_registers[SM8521_MMU4] ); return; case SM8521_SYS: cpunum_set_reg( 0, SM8500_SYS, data ); return; case SM8521_CKC: cpunum_set_reg( 0, SM8500_CKC, data ); return; case SM8521_SPH: cpunum_set_reg( 0, SM8500_SPH, data ); return; case SM8521_SPL: cpunum_set_reg( 0, SM8500_SPL, data ); return; case SM8521_PS0: cpunum_set_reg( 0, SM8500_PS0, data ); return; case SM8521_PS1: cpunum_set_reg( 0, SM8500_PS1, data ); return; case SM8521_P0C: cpunum_set_reg( 0, SM8500_P0C, data ); return; case SM8521_P1C: cpunum_set_reg( 0, SM8500_P1C, data ); return; case SM8521_P2C: cpunum_set_reg( 0, SM8500_P2C, data ); return; case SM8521_P3C: cpunum_set_reg( 0, SM8500_P3C, data ); return; case SM8521_MMU0: /* disable bootstrap ROM? most likely not written to on game.com */ logerror( "Write to MMU0\n" ); break; case SM8521_MMU1: gamecom_set_mmu( 1, data ); break; case SM8521_MMU2: gamecom_set_mmu( 2, data ); break; case SM8521_MMU3: gamecom_set_mmu( 3, data ); break; case SM8521_MMU4: gamecom_set_mmu( 4, data ); break; /* Video hardware and DMA */ case SM8521_LCDC: // logerror( "%X: Setting LCDC to %X\n", activecpu_get_pc(), data ); break; case SM8521_LCH: break; case SM8521_LCV: break; case SM8521_DMC: gamecom_dma.overwrite_mode = data & 0x01; gamecom_dma.transfer_mode = data & 0x06; gamecom_dma.decrement_x = data & 0x08; gamecom_dma.decrement_y = data & 0x10; gamecom_dma.enabled = data & 0x80; if ( gamecom_dma.enabled ) { gamecom_dma_init(); } break; case SM8521_DMX1: break; case SM8521_DMY1: break; case SM8521_DMDX: break; case SM8521_DMDY: break; case SM8521_DMX2: break; case SM8521_DMY2: break; case SM8521_DMPL: break; case SM8521_DMBR: break; case SM8521_DMVP: break; case SM8521_TM0D: gamecom_timer[0].check_value = data; break; case SM8521_TM0C: gamecom_timer[0].enabled = data & 0x80; gamecom_timer[0].state_limit = gamecom_timer_limit[data & 0x07]; gamecom_timer[0].state_count = 0; gamecom_timer[0].counter = 0; break; case SM8521_TM1D: gamecom_timer[1].check_value = data; break; case SM8521_TM1C: gamecom_timer[1].enabled = data & 0x80; gamecom_timer[1].state_limit = gamecom_timer_limit[data & 0x07]; gamecom_timer[1].state_count = 0; gamecom_timer[1].counter = 0; break; case SM8521_CLKT: /* bit 6-7 */ if ( data & 0x80 ) { /* timer run */ if ( data & 0x40 ) { /* timer resolution 1 minute */ mame_timer_adjust( gamecom_clock_timer, MAME_TIME_IN_SEC(1), 0, MAME_TIME_IN_SEC(60) ); } else { /* TImer resolution 1 second */ mame_timer_adjust( gamecom_clock_timer, MAME_TIME_IN_SEC(1), 0, MAME_TIME_IN_SEC(1) ); } } else { /* disable timer reset */ mame_timer_enable( gamecom_clock_timer, 0 ); data &= 0xC0; } break; /* Reserved addresses */ case SM8521_18: case SM8521_1B: case SM8521_29: case SM8521_2A: case SM8521_2F: case SM8521_33: case SM8521_3E: case SM8521_3F: case SM8521_41: case SM8521_43: case SM8521_45: case SM8521_4B: case SM8521_4F: case SM8521_55: case SM8521_56: case SM8521_57: case SM8521_58: case SM8521_59: case SM8521_5A: case SM8521_5B: case SM8521_5C: case SM8521_5D: logerror( "%X: Write to reserved address (0x%02X). Value written: 0x%02X\n", activecpu_get_pc(), offset, data ); break; } internal_registers[offset] = data; } READ8_HANDLER( gamecom_internal_r ) { if ( offset >= 0x80 ) { return internal_ram[offset]; } switch( offset ) { case SM8521_R0: case SM8521_R1: case SM8521_R2: case SM8521_R3: case SM8521_R4: case SM8521_R5: case SM8521_R6: case SM8521_R7: case SM8521_R8: case SM8521_R9: case SM8521_R10: case SM8521_R11: case SM8521_R12: case SM8521_R13: case SM8521_R14: case SM8521_R15: return sm85cpu_mem_readbyte( offset ); case SM8521_IE0: return cpunum_get_reg( 0, SM8500_IE0 ); case SM8521_IE1: return cpunum_get_reg( 0, SM8500_IE1 ); case SM8521_IR0: return cpunum_get_reg( 0, SM8500_IR0 ); case SM8521_IR1: return cpunum_get_reg( 0, SM8500_IR1 ); case SM8521_P0: /* logerror( "%X: Read from P0\n", activecpu_get_pc() ); */ return cpunum_get_reg( 0, SM8500_P0 ); case SM8521_P1: /* logerror( "%X: Read from P1\n", activecpu_get_pc() ); */ return cpunum_get_reg( 0, SM8500_P1 ); case SM8521_P2: /* logerror( "%X: Read from P2\n", activecpu_get_pc() ); */ return cpunum_get_reg( 0, SM8500_P2 ); case SM8521_P3: return cpunum_get_reg( 0, SM8500_P3 ); case SM8521_SYS: return cpunum_get_reg( 0, SM8500_SYS ); case SM8521_CKC: return cpunum_get_reg( 0, SM8500_CKC ); case SM8521_SPH: return cpunum_get_reg( 0, SM8500_SPH ); case SM8521_SPL: return cpunum_get_reg( 0, SM8500_SPL ); case SM8521_PS0: return cpunum_get_reg( 0, SM8500_PS0 ); case SM8521_PS1: return cpunum_get_reg( 0, SM8500_PS1 ); case SM8521_P0C: return cpunum_get_reg( 0, SM8500_P0C ); case SM8521_P1C: return cpunum_get_reg( 0, SM8500_P1C ); case SM8521_P2C: return cpunum_get_reg( 0, SM8500_P2C ); case SM8521_P3C: return cpunum_get_reg( 0, SM8500_P3C ); case SM8521_TM0D: return gamecom_timer[0].counter; case SM8521_TM1D: return gamecom_timer[1].counter; // case SM8521_CLKT: /* bit 0-5 read only, 6-7 read/write */ // return ( internal_registers[offset] & 0xC0 ) | ( clock_timer_val & 0x3F ); /* Reserved addresses */ case SM8521_18: case SM8521_1B: case SM8521_29: case SM8521_2A: case SM8521_2F: case SM8521_33: case SM8521_3E: case SM8521_3F: case SM8521_41: case SM8521_43: case SM8521_45: case SM8521_4B: case SM8521_4F: case SM8521_55: case SM8521_56: case SM8521_57: case SM8521_58: case SM8521_59: case SM8521_5A: case SM8521_5B: case SM8521_5C: case SM8521_5D: // logerror( "%X: Read from reserved address (0x%02X)\n", activecpu_get_pc(), offset ); break; } return internal_registers[offset]; } /* The manual is not conclusive as to which bit of the DMVP register (offset 0x3D) determines which page for source or destination is used */ void gamecom_dma_init(void) { if ( gamecom_dma.decrement_x || gamecom_dma.decrement_y ) { logerror( "TODO: Decrement-x and decrement-y are not supported yet\n" ); } gamecom_dma.width_x = internal_registers[SM8521_DMDX]; gamecom_dma.width_x_count = 0; gamecom_dma.width_y = internal_registers[SM8521_DMDY]; gamecom_dma.width_y_count = 0; gamecom_dma.source_x = internal_registers[SM8521_DMX1]; gamecom_dma.source_x_current = gamecom_dma.source_x; gamecom_dma.source_y = internal_registers[SM8521_DMY1]; gamecom_dma.source_width = ( internal_registers[SM8521_LCH] & 0x20 ) ? 50 : 40; gamecom_dma.dest_x = internal_registers[SM8521_DMX2]; gamecom_dma.dest_x_current = gamecom_dma.dest_x; gamecom_dma.dest_y = internal_registers[SM8521_DMY2]; gamecom_dma.dest_width = ( internal_registers[SM8521_LCH] & 0x20 ) ? 50 : 40; gamecom_dma.palette[0] = ( internal_registers[SM8521_DMPL] & 0x03 ); gamecom_dma.palette[1] = ( internal_registers[SM8521_DMPL] & 0x0C ) >> 2; gamecom_dma.palette[2] = ( internal_registers[SM8521_DMPL] & 0x30 ) >> 4; gamecom_dma.palette[3] = ( internal_registers[SM8521_DMPL] & 0xC0 ) >> 6; gamecom_dma.source_mask = 0x1FFF; gamecom_dma.dest_mask = 0x1FFF; // logerror("DMA: width %Xx%X, source (%X,%X), dest (%X,%X), transfer_mode %X, banks %X \n", gamecom_dma.width_x, gamecom_dma.width_y, gamecom_dma.source_x, gamecom_dma.source_y, gamecom_dma.dest_x, gamecom_dma.dest_y, gamecom_dma.transfer_mode, internal_registers[SM8521_DMVP] ); // logerror( " Palette: %d, %d, %d, %d\n", gamecom_dma.palette[0], gamecom_dma.palette[1], gamecom_dma.palette[2], gamecom_dma.palette[3] ); switch( gamecom_dma.transfer_mode ) { case 0x00: /* VRAM->VRAM */ gamecom_dma.source_bank = &gamecom_vram[(internal_registers[SM8521_DMVP] & 0x01) ? 0x2000 : 0x0000]; gamecom_dma.dest_bank = &gamecom_vram[(internal_registers[SM8521_DMVP] & 0x02) ? 0x2000 : 0x0000]; break; case 0x02: /* ROM->VRAM */ // logerror( "DMA DMBR = %X\n", internal_registers[SM8521_DMBR] ); gamecom_dma.source_width = 64; if ( internal_registers[SM8521_DMBR] < 16 ) { gamecom_dma.source_bank = memory_region(REGION_USER1) + (internal_registers[SM8521_DMBR] << 14); gamecom_dma.source_mask = 0x3FFF; } else { logerror( "TODO: Reading from external ROMs not supported yet\n" ); gamecom_dma.source_bank = memory_region(REGION_USER1); } gamecom_dma.dest_bank = &gamecom_vram[(internal_registers[SM8521_DMVP] & 0x02) ? 0x2000 : 0x0000]; break; case 0x04: /* Extend RAM->VRAM */ gamecom_dma.source_width = 64; gamecom_dma.source_bank = memory_get_read_ptr(0, ADDRESS_SPACE_PROGRAM, 0xE000 ); gamecom_dma.dest_bank = &gamecom_vram[(internal_registers[SM8521_DMVP] & 0x02) ? 0x2000 : 0x0000]; break; case 0x06: /* VRAM->Extend RAM */ gamecom_dma.source_bank = &gamecom_vram[(internal_registers[SM8521_DMVP] & 0x01) ? 0x2000 : 0x0000]; gamecom_dma.dest_width = 64; gamecom_dma.dest_bank = memory_get_read_ptr(0, ADDRESS_SPACE_PROGRAM, 0xE000 ); break; } gamecom_dma.source_current = gamecom_dma.source_width * gamecom_dma.source_y; gamecom_dma.source_current += gamecom_dma.source_x >> 2; gamecom_dma.dest_current = gamecom_dma.dest_width * gamecom_dma.dest_y; gamecom_dma.dest_current += gamecom_dma.dest_x >> 2; gamecom_dma.source_line = gamecom_dma.source_current; gamecom_dma.dest_line = gamecom_dma.dest_current; gamecom_dma.state_count = 0; } /* For now the increment/decrement-x and increment/decrement-y parts are NOT supported. Their usage is also not explained properly in the manuals. Guess we'll have to wait for them to show up in some rom images... */ void gamecom_handle_dma( int cycles ) { unsigned y_count, x_count; /* If not enabled, ignore */ if ( ! gamecom_dma.enabled ) { return; } for( y_count = 0; y_count <= gamecom_dma.width_y; y_count++ ) { for( x_count = 0; x_count <= gamecom_dma.width_x; x_count++ ) { int source_pixel = 0; int dest_pixel = 0; int src_addr = gamecom_dma.source_current & gamecom_dma.source_mask; int dest_addr = gamecom_dma.dest_current & gamecom_dma.dest_mask; /* handle DMA for 1 pixel */ /* Read pixel data */ switch ( gamecom_dma.source_x_current & 0x03 ) { case 0x00: source_pixel = ( gamecom_dma.source_bank[src_addr] & 0xC0 ) >> 6; break; case 0x01: source_pixel = ( gamecom_dma.source_bank[src_addr] & 0x30 ) >> 4; break; case 0x02: source_pixel = ( gamecom_dma.source_bank[src_addr] & 0x0C ) >> 2; break; case 0x03: source_pixel = ( gamecom_dma.source_bank[src_addr] & 0x03 ); break; } if ( !gamecom_dma.overwrite_mode && source_pixel == 0 ) { switch ( gamecom_dma.dest_x_current & 0x03 ) { case 0x00: dest_pixel = ( gamecom_dma.dest_bank[dest_addr] & 0xC0 ) >> 6; break; case 0x01: dest_pixel = ( gamecom_dma.dest_bank[dest_addr] & 0x30 ) >> 4; break; case 0x02: dest_pixel = ( gamecom_dma.dest_bank[dest_addr] & 0x0C ) >> 2; break; case 0x03: dest_pixel = ( gamecom_dma.dest_bank[dest_addr] & 0x03 ); break; } source_pixel = dest_pixel; } /* Translate pixel data using DMA palette. */ /* Not sure if this should be done before the compound stuff - WP */ source_pixel = gamecom_dma.palette[ source_pixel ]; /* Write pixel data */ switch( gamecom_dma.dest_x_current & 0x03 ) { case 0x00: gamecom_dma.dest_bank[dest_addr] = ( gamecom_dma.dest_bank[dest_addr] & 0x3F ) | ( source_pixel << 6 ); break; case 0x01: gamecom_dma.dest_bank[dest_addr] = ( gamecom_dma.dest_bank[dest_addr] & 0xCF ) | ( source_pixel << 4 ); break; case 0x02: gamecom_dma.dest_bank[dest_addr] = ( gamecom_dma.dest_bank[dest_addr] & 0xF3 ) | ( source_pixel << 2 ); break; case 0x03: gamecom_dma.dest_bank[dest_addr] = ( gamecom_dma.dest_bank[dest_addr] & 0xFC ) | source_pixel; break; } /* Advance a pixel */ if ( gamecom_dma.decrement_x ) { gamecom_dma.source_x_current--; if ( ( gamecom_dma.source_x_current & 0x03 ) == 0x03 ) { gamecom_dma.source_current--; } } else { gamecom_dma.source_x_current++; if ( ( gamecom_dma.source_x_current & 0x03 ) == 0x00 ) { gamecom_dma.source_current++; } } gamecom_dma.dest_x_current++; if ( ( gamecom_dma.dest_x_current & 0x03 ) == 0x00 ) { gamecom_dma.dest_current++; } } /* Advance a line */ gamecom_dma.source_x_current = gamecom_dma.source_x; gamecom_dma.dest_x_current = gamecom_dma.dest_x; gamecom_dma.source_line += gamecom_dma.source_width; gamecom_dma.source_current = gamecom_dma.source_line; gamecom_dma.dest_line += gamecom_dma.dest_width; gamecom_dma.dest_current = gamecom_dma.dest_line; } gamecom_dma.enabled = 0; cpunum_set_input_line( 0, DMA_INT, HOLD_LINE ); } void gamecom_update_timers( int cycles ) { if ( gamecom_timer[0].enabled ) { gamecom_timer[0].state_count += cycles; while ( gamecom_timer[0].state_count >= gamecom_timer[0].state_limit ) { gamecom_timer[0].state_count -= gamecom_timer[0].state_limit; gamecom_timer[0].counter++; if ( gamecom_timer[0].counter == gamecom_timer[0].check_value ) { gamecom_timer[0].counter = 0; cpunum_set_input_line( 0, TIM0_INT, HOLD_LINE ); } } } if ( gamecom_timer[1].enabled ) { gamecom_timer[1].state_count += cycles; while ( gamecom_timer[1].state_count >= gamecom_timer[1].state_limit ) { gamecom_timer[1].state_count -= gamecom_timer[1].state_limit; gamecom_timer[1].counter++; if ( gamecom_timer[1].counter == gamecom_timer[1].check_value ) { gamecom_timer[1].counter = 0; cpunum_set_input_line( 0, TIM1_INT, HOLD_LINE ); } } } } WRITE8_HANDLER( gamecom_vram_w ) { gamecom_vram[offset] = data; } READ8_HANDLER( gamecom_vram_r ) { return gamecom_vram[offset]; } DEVICE_INIT( gamecom_cart ) { internal_ram = sm8500_internal_ram(); return INIT_PASS; } DEVICE_LOAD( gamecom_cart ) { int filesize; int load_offset = 0; /* allocate memory on first load of a cartridge */ if ( cartridge1 == NULL ) { cartridge1 = auto_malloc( 2048 * 1024 ); } filesize = image_length( image ); switch( filesize ) { case 0x008000: load_offset = 0; break; /* 32 KB */ case 0x040000: load_offset = 0; break; /* 256KB */ case 0x080000: load_offset = 0; break; /* 512KB */ case 0x100000: load_offset = 0; break; /* 1 MB */ case 0x1c0000: load_offset = 0x040000; break; /* 1.8MB */ case 0x200000: load_offset = 0; break; /* 2 MB */ default: /* otherwise */ logerror( "Error loading cartridge: Invalid file size.\n" ); return INIT_FAIL; } if ( image_fread( image, cartridge1 + load_offset, filesize ) != filesize ) { logerror( "Error loading cartridge: Unable to read from file: %s.\n", image_filename(image) ); return INIT_FAIL; } if ( filesize < 0x010000 ) { memcpy( cartridge1 + 0x008000, cartridge1, 0x008000 ); } /* ->64KB */ if ( filesize < 0x020000 ) { memcpy( cartridge1 + 0x010000, cartridge1, 0x010000 ); } /* ->128KB */ if ( filesize < 0x040000 ) { memcpy( cartridge1 + 0x020000, cartridge1, 0x020000 ); } /* ->256KB */ if ( filesize < 0x080000 ) { memcpy( cartridge1 + 0x040000, cartridge1, 0x040000 ); } /* ->512KB */ if ( filesize < 0x100000 ) { memcpy( cartridge1 + 0x080000, cartridge1, 0x080000 ); } /* ->1MB */ if ( filesize < 0x1c0000 ) { memcpy( cartridge1 + 0x100000, cartridge1, 0x100000 ); } /* -> >=1.8MB */ return INIT_PASS; }