/* DJ Boy (c)1989 Kanako Hardware has many similarities to Airbusters. Self Test has two parts: 1) color test : press button#3 to advance past color pattern 2) i/o and sound test: use buttons 1,2,3 to select and play sound/music - CPU0 manages sprites, which are also used to display text irq (0x10) - timing/watchdog irq (0x30) - processes sprites nmi: wakes up this cpu - CPU1 manages the protection device, palette, and tilemap(s) nmi: resets this cpu irq: game update - CPU2 manages sound chips irq: update music nmi: handle sound command - The "BEAST" protection device has access to dipswitches and player inputs. Genre: Scrolling Fighter Orientation: Horizontal Type: Raster: Standard Resolution CRT: Color Conversion Class: JAMMA Number of Simultaneous Players: 2 Maximum number of Players: 2 Gameplay: Joint Control Panel Layout: Multiple Player Joystick: 8-way Buttons: 3 - Punch, Kick, Jump Sound: Amplified Mono (one channel) - Stereo sound is available through a 4-pin header (voice of Wolfman Jack!!) DJ Boy 1990, Kaneko / American Sammy Corp. PCB Layout ---------- BS |----------------------------------------------| | 6264 BS15 6116 | | BS-101 6116 | | BS-005 780C-2 | | BS-004 DSW1 DSW2 | | 6264 IO-JAMMA| | 16MHz PAL1|----------| | | 12MHz | BEAST | J| | |----------| A| | BS-003 * M| | 6116 BS-203 6295 YM2203 M| | BS-000 YM3014 A| | |-------| 6295 324 4558 | | BS-001 |KANEKO | 780C-2 324 | | |PANDORA| VOL JP| | BS-002 | | BS-100 PAL2 324 | | |-------| 6264 VOL CN1| | BS07 4464 4464 BS19 BS-200 LA4460 | | 4464 4464 PAL3 D780C-2 LA4460 | |----------------------------------------------| Notes: D780C-2 - Z80 CPU. clock 6.000MHz [12/2] (for all 3 Z80 CPUs) BEAST - DIP40 Microcontroller, 8xxx series (8041/8042/8751 etc). Clock 6.000MHz on pins 18 & 19 chip is stamped 'KANEKO Beast (C)Intel '80 (C)KANEKO 1988' YM2203 - Yamaha YM2203, clock 3.000MHz [12/4] 6295 - OKI M6295, clock 1.500MHz [12/8]. Sample rate (Hz) = 12000000 / 8 / 165 PANDORA - Custom Kaneko graphics generator chip stamped 'PX79C480FP-3 PANDORA-CHIP' (QFP160) 4464 - 64k x4 DRAM (DIP18) 6116 - 2k x8 SRAM (DIP24) 6264 - 8k x8 SRAM (DIP28) VSync - 57.5Hz HSync - 15.68kHz JP - 3 pin jumper to set mono/stereo sound output CN1 - 4 pin connector for speakers when jumper is set for stereo sound output PAL1 - PAL16L8 stamped 'BS-501' PAL2 - PAL16L8 stamped 'BS-502' PAL3 - PAL16L8 stamped 'BS-500' IO-JAMMA- Custom Kaneko ceramic I/O input resistor pack stamped 'I/O JAMMA MC-8282837' LA4460 - Sanyo 12W Power Amplifier (SIL10) * - Unpopulated DIP32 position ROMs - BS15.6Y 27C512 EPROM (DIP28) \ There is an alt. set of labels used for these ROMs with an 'S' BS07.1B 27C512 EPROM (DIP28) | added to the name (i.e. 'BS15S'), but the actual ROM contents is identical BS19.4B 27C1001 EPROM (DIP32) / to the regular set (both sets dumped / verified) BS-000.1H 4M MASKROM (DIP32) {sprite} BS-001.1F 4M MASKROM (DIP32) {sprite} BS-002.1D 4M MASKROM (DIP32) {sprite} BS-003.1K 4M MASKROM (DIP32) {sprite} BS-004.1S 4M MASKROM (DIP32) {tile} BS-005.1U 4M MASKROM (DIP32) {tile} BS-100.4D 1M MASKROM (DIP28) {z80} BS-101.6W 1M MASKROM (DIP28) {z80 data} BS-200.8C 1M MASKROM (DIP28) {z80} BS-203.5J 2M MASKROM (DIP32) {oki-m6295 samples} DIPs - SW1 |--------------------------------------------| | 1 2 3 4 5 6 7 8 | |--------------------------------------------| |SCREEN NORMAL OFF | | FLIP ON | |--------------------------------------------| |GAME NORMAL OFF | |MODE TEST ON | |--------------------------------------------| |COIN1 1C/1P OFF OFF | | 1C/2P ON OFF | | 2C/1P OFF ON | | 2C/3P ON ON | | | |COIN2 1C/1P OFF OFF| | 1C/2P ON OFF| | 2C/1P OFF ON | | 2C/3P ON ON | |--------------------------------------------| |SW1 & SW4 NOT USED ALWAYS OFF | |--------------------------------------------| SW2 |--------------------------------------------| | 1 2 3 4 5 6 7 8 | |--------------------------------------------| |DIFFICULTY | |NORMAL OFF OFF | |EASY ON OFF | |HARD OFF ON | |HARDEST ON ON | |--------------------------------------------| |BONUS | |10,30,50,70,90 OFF OFF | |10,20,30,40,50, | |60,70,80,90 ON OFF | |20,50 OFF ON | |NONE ON ON | |--------------------------------------------| |LIVES 5 OFF OFF | | 3 ON OFF | | 7 OFF ON | | 9 ON ON | |--------------------------------------------| |DEMO SOUND YES OFF | | NO ON | |--------------------------------------------| |SPEAKER STEREO OFF| |OUTPUT MONO ON| |--------------------------------------------| */ #include "driver.h" #include "deprecat.h" #include "cpu/z80/z80.h" #include "sound/2203intf.h" #include "sound/okim6295.h" #include "video/kan_pand.h" /* public functions from video/djboy.h */ extern void djboy_set_videoreg( UINT8 data ); extern WRITE8_HANDLER( djboy_scrollx_w ); extern WRITE8_HANDLER( djboy_scrolly_w ); extern WRITE8_HANDLER( djboy_videoram_w ); extern WRITE8_HANDLER( djboy_paletteram_w ); extern VIDEO_START( djboy ); extern VIDEO_UPDATE( djboy ); extern VIDEO_EOF( djboy ); static UINT8 *sharedram; static READ8_HANDLER( sharedram_r ) { return sharedram[offset]; } static WRITE8_HANDLER( sharedram_w ) { sharedram[offset] = data; } /******************************************************************************/ /* KANEKO BEAST state */ static int prot_busy_count; #define PROT_OUTPUT_BUFFER_SIZE 8 static UINT8 prot_output_buffer[PROT_OUTPUT_BUFFER_SIZE]; static int prot_available_data_count; static int prot_offs; /* internal state */ static UINT8 prot_ram[0x80]; /* internal RAM */ static UINT8 prot_param[8]; static int coin; static int complete; static int lives[2]; static enum { eDJBOY_ATTRACT_HIGHSCORE, eDJBOY_ATTRACT_TITLE, eDJBOY_ATTRACT_GAMEPLAY, eDJBOY_PRESS_P1_START, eDJBOY_PRESS_P1_OR_P2_START, eDJBOY_ACTIVE_GAMEPLAY } mDjBoyState; static enum { ePROT_NORMAL, ePROT_WRITE_BYTES, ePROT_WRITE_BYTE, ePROT_READ_BYTES, ePROT_WAIT_DSW1_WRITEBACK, ePROT_WAIT_DSW2_WRITEBACK, ePROT_STORE_PARAM } prot_mode; static void ProtectionOut( int i, UINT8 data ) { if( prot_available_data_count == i ) { prot_output_buffer[prot_available_data_count++] = data; } else { logerror( "prot_output_buffer overflow!\n" ); exit(1); } } /* ProtectionOut */ static int GetLives( running_machine *machine ) { int dsw = input_port_read(machine, "DSW2"); switch( dsw&0x30 ) { case 0x10: return 3; case 0x00: return 5; case 0x20: return 7; case 0x30: return 9; } return 0; } /* GetLives */ static WRITE8_HANDLER( coinplus_w ) { int dsw = input_port_read(machine, "DSW1"); coin_counter_w( 0, data&1 ); coin_counter_w( 1, data&2 ); if( data&1 ) { /* TODO: coinage adjustments */ logerror( "COIN A+\n" ); switch( (dsw&0x30)>>4 ) { case 0: coin += 4; break; /* 1 coin, 1 credit */ case 1: coin += 8; break; /* 1 coin, 2 credits */ case 2: coin += 2; break; /* 2 coins, 1 credit */ case 3: coin += 6; break; /* 2 coins, 3 credits */ } } if( data&2 ) { logerror( "COIN B+\n" ); switch( (dsw&0xc0)>>6 ) { case 0: coin += 4; break; /* 1 coin, 1 credit */ case 1: coin += 8; break; /* 1 coin, 2 credits */ case 2: coin += 2; break; /* 2 coins, 1 credit */ case 3: coin += 6; break; /* 2 coins, 3 credits */ } } } /* coinplus_w */ static void OutputProtectionState( running_machine *machine, int i, int type ) { int io = ~input_port_read(machine, "IN0"); int dat = 0x00; switch( mDjBoyState ) { case eDJBOY_ATTRACT_HIGHSCORE: if( coin>=4 ) { dat = 0x01; mDjBoyState = eDJBOY_PRESS_P1_START; logerror( "COIN UP\n" ); } else if( complete ) { dat = 0x06; mDjBoyState = eDJBOY_ATTRACT_TITLE; } break; case eDJBOY_ATTRACT_TITLE: if( coin>=4 ) { dat = 0x01; mDjBoyState = eDJBOY_PRESS_P1_START; logerror( "COIN UP\n" ); } else if( complete ) { dat = 0x15; mDjBoyState = eDJBOY_ATTRACT_GAMEPLAY; } break; case eDJBOY_ATTRACT_GAMEPLAY: if( coin>=4 ) { dat = 0x01; mDjBoyState = eDJBOY_PRESS_P1_START; logerror( "COIN UP\n" ); } else if( complete ) { dat = 0x0b; mDjBoyState = eDJBOY_ATTRACT_HIGHSCORE; } break; case eDJBOY_PRESS_P1_START: if( io&1 ) { /* p1 start */ dat = 0x16; mDjBoyState = eDJBOY_ACTIVE_GAMEPLAY; logerror( "P1 START\n" ); } else if( coin>=8 ) { dat = 0x05; mDjBoyState = eDJBOY_PRESS_P1_OR_P2_START; logerror( "COIN2 UP\n" ); } break; case eDJBOY_PRESS_P1_OR_P2_START: if( io&1 ) { /* p1 start */ dat = 0x16; mDjBoyState = eDJBOY_ACTIVE_GAMEPLAY; lives[0] = GetLives(machine); logerror( "P1 START!\n" ); coin-=4; } else if( io&2 ) { /* p2 start */ dat = 0x0a; mDjBoyState = eDJBOY_ACTIVE_GAMEPLAY; lives[0] = GetLives(machine); lives[1] = GetLives(machine); logerror( "P2 START!\n" ); coin-=8; } break; case eDJBOY_ACTIVE_GAMEPLAY: if( lives[0]==0 && lives[1]==0 && complete ) { /* continue countdown complete */ dat = 0x0f; logerror( "countdown complete!\n" ); mDjBoyState = eDJBOY_ATTRACT_HIGHSCORE; } else if( coin>=4 ) { if( (io&1) && lives[0]==0 ) { dat = 0x12; /* continue (P1) */ lives[0] = GetLives(machine); mDjBoyState = eDJBOY_ACTIVE_GAMEPLAY; coin-=4; logerror( "P1 CONTINUE!\n" ); } else if( (io&2) && lives[1]==0 ) { dat = 0x08; /* continue (P2) */ lives[1] = GetLives(machine); mDjBoyState = eDJBOY_ACTIVE_GAMEPLAY; coin-=4; logerror( "P2 CONTINUE!\n" ); } } break; } complete = 0; ProtectionOut( i, dat ); } /* OutputProtectionState */ static void CommonProt( running_machine *machine, int i, int type ) { int displayedCredits = coin/4; if( displayedCredits>9 ) { displayedCredits = 9; } ProtectionOut( i++, displayedCredits ); ProtectionOut( i++, input_port_read(machine, "IN0") ); /* COIN/START */ OutputProtectionState( machine, i, type ); } /* CommonProt */ static WRITE8_HANDLER( beast_data_w ) { prot_busy_count = 1; logerror( "0x%04x: prot_w(0x%02x)\n", activecpu_get_pc(), data ); watchdog_reset_w(machine,0,0); if( prot_mode == ePROT_WAIT_DSW1_WRITEBACK ) { logerror( "[DSW1_WRITEBACK]\n" ); ProtectionOut( 0, input_port_read(machine, "DSW2") ); /* DSW2 */ prot_mode = ePROT_WAIT_DSW2_WRITEBACK; } else if( prot_mode == ePROT_WAIT_DSW2_WRITEBACK ) { logerror( "[DSW2_WRITEBACK]\n" ); prot_mode = ePROT_STORE_PARAM; prot_offs = 0; } else if( prot_mode == ePROT_STORE_PARAM ) { logerror( "prot param[%d]: 0x%02x\n", prot_offs, data ); if( prot_offs<8 ) { prot_param[prot_offs++] = data; } if( prot_offs == 8 ) { prot_mode = ePROT_NORMAL; } } else if( prot_mode == ePROT_WRITE_BYTE ) { /* pc == 0x79cd */ prot_ram[(prot_offs++)&0x7f] = data; prot_mode = ePROT_WRITE_BYTES; } else { switch( data ) { case 0x00: if( prot_mode == ePROT_WRITE_BYTES ) { /* next byte is data to write to internal prot RAM */ prot_mode = ePROT_WRITE_BYTE; } else if( prot_mode == ePROT_READ_BYTES ) { /* request next byte of internal prot RAM */ ProtectionOut( 0, prot_ram[(prot_offs++)&0x7f] ); } else { logerror( "UNEXPECTED PREFIX!\n" ); } break; case 0x01: // pc=7389 OutputProtectionState( machine, 0, 0x01 ); break; case 0x02: CommonProt( machine,0,0x02 ); break; case 0x03: /* prepare for memory write to protection device ram (pc == 0x7987) */ // -> 0x02 logerror( "[WRITE BYTES]\n" ); prot_mode = ePROT_WRITE_BYTES; prot_offs = 0; break; case 0x04: ProtectionOut( 0,0 ); // ? ProtectionOut( 1,0 ); // ? ProtectionOut( 2,0 ); // ? ProtectionOut( 3,0 ); // ? CommonProt( machine, 4,0x04 ); break; case 0x05: /* 0x71f4 */ ProtectionOut( 0,input_port_read(machine, "IN1") ); // to $42 ProtectionOut( 1,0 ); // ? ProtectionOut( 2,input_port_read(machine, "IN2") ); // to $43 ProtectionOut( 3,0 ); // ? ProtectionOut( 4,0 ); // ? CommonProt( machine, 5,0x05 ); break; case 0x07: CommonProt( machine, 0,0x07 ); break; case 0x08: /* pc == 0x727a */ ProtectionOut( 0,input_port_read(machine, "IN0") ); /* COIN/START */ ProtectionOut( 1,input_port_read(machine, "IN1") ); /* JOY1 */ ProtectionOut( 2,input_port_read(machine, "IN2") ); /* JOY2 */ ProtectionOut( 3,input_port_read(machine, "DSW1") ); /* DSW1 */ ProtectionOut( 4,input_port_read(machine, "DSW2") ); /* DSW2 */ CommonProt( machine, 5, 0x08 ); break; case 0x09: ProtectionOut( 0,0 ); // ? ProtectionOut( 1,0 ); // ? ProtectionOut( 2,0 ); // ? CommonProt( machine, 3, 0x09 ); break; case 0x0a: CommonProt( machine,0,0x0a ); break; case 0x0c: CommonProt( machine,1,0x0c ); break; case 0x0d: CommonProt( machine,2,0x0d ); break; case 0xfe: /* prepare for memory read from protection device ram (pc == 0x79ee, 0x7a3f) */ if( prot_mode == ePROT_WRITE_BYTES ) { prot_mode = ePROT_READ_BYTES; logerror( "[READ BYTES]\n" ); } else { prot_mode = ePROT_WRITE_BYTES; logerror( "[WRITE BYTES*]\n" ); } prot_offs = 0; break; case 0xff: /* read DSW (pc == 0x714d) */ ProtectionOut( 0,input_port_read(machine, "DSW1") ); /* DSW1 */ prot_mode = ePROT_WAIT_DSW1_WRITEBACK; break; case 0xa9: /* 1-player game: P1 dies 2-player game: P2 dies */ if( lives[0]>0 && lives[1]>0 ) { lives[1]--; logerror( "%02x P2 DIE(%d)\n", data, lives[1] ); } else if( lives[0]>0 ) { lives[0]--; logerror( "%02x P1 DIE(%d)\n", data, lives[0] ); } else { logerror( "%02x COMPLETE.\n", data ); complete = 0xa9; } break; case 0x92: /* p2 lost life; in 2-p game, P1 died */ if( lives[0]>0 && lives[1]>0 ) { lives[0]--; logerror( "%02x P1 DIE(%d)\n", data, lives[0] ); } else if( lives[1]>0 ) { lives[1]--; logerror( "%02x P2 DIE (%d)\n", data, lives[1] ); } else { logerror( "%02x COMPLETE.\n", data ); complete = 0x92; } break; case 0xa3: /* p2 bonus life */ lives[1]++; logerror( "%02x P2 BONUS(%d)\n", data, lives[1] ); break; case 0xa5: /* p1 bonus life */ lives[0]++; logerror( "%02x P1 BONUS(%d)\n", data, lives[0] ); break; case 0xad: /* 1p game start ack */ logerror( "%02x 1P GAME START\n", data ); break; case 0xb0: /* 1p+2p game start ack */ logerror( "%02x 1P+2P GAME START\n", data ); break; case 0xb3: /* 1p continue ack */ logerror( "%02x 1P CONTINUE\n", data ); break; case 0xb7: /* 2p continue ack */ logerror( "%02x 2P CONTINUE\n", data ); break; default: case 0x97: case 0x9a: logerror( "!!0x%04x: prot_w(0x%02x)\n", activecpu_get_pc(), data ); break; } } } /* beast_data_w */ static READ8_HANDLER( beast_data_r ) { /* port#4 */ UINT8 data = 0x00; if( prot_available_data_count ) { int i; data = prot_output_buffer[0]; prot_available_data_count--; for( i=0; i