/* * SYSTEM 16 ARCADE EMULATOR SOURCE CODE * * Copyright 1996/97 Thierry Lescot */ #include "cpudefs.h" #include #include #include "shinobi.h" unsigned int resultat=0; extern char game, game_basename[9], game_name[20]; extern char joy; int joy_count=1, old_joy=0; unsigned char *TilesROM1, *TilesROM2, *TilesROM3, *GameROM, *SpritesROM; extern UBYTE ext_bank, vid_bank, txt_bank, ctr_bank, pal_bank; extern int sortie, strace, sx, sy; extern long int total_render; extern unsigned int *PaletteShinobi; extern unsigned char number_of_new_colors; extern long valeur_controle; extern char sync; int areg_byteinc[] = {1,1,1,1,1,1,1,2}; int imm8_table[] = {8,1,2,3,4,5,6,7}; int keydef[40] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_0, KEY_CONTROL, KEY_ALT, KEY_SPACE, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, 127, 127, 127, 127, 127, 127, 127, KEY_Q, KEY_W, KEY_E, KEY_U, KEY_J, KEY_H, KEY_L, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, }; char joydef[4] = { 1, 2, 3, 4 }; UBYTE spr_tab[16]; UBYTE spr_tab_all[16*LAST_GAME] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, /* Shinobi */ 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, /* Altered Beast */ 0x08, 0x00, 0x0A, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x0A, 0x10, 0x12, 0x00, 0x00, /* Golden Axe */ 0x04, 0x06, 0x0C, 0x0E, 0x14, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, /* Time Scanner */ 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Quartet II */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* Shadow Dancer */ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E }; RGB pal; UBYTE shinobi_ds1[10] = {0,0,0,0,0,0,0,0,0,0}; UBYTE shinobi_ds2[10] = {0,0,0,0,0,0,0,0,0,0}; #ifdef SON_SIMULE SAMPLE *Sons[0x100]; #endif #ifdef MAX_MEM_TEST UWORD MaximumR[0x100], MaximumW[0x100]; #endif /* POINTEURS */ ULONG ptr_text_video; ULONG base_scr_hor_fg, base_scr_hor_bg, base_scr_ver_fg, base_scr_ver_bg; ULONG base_scr_pag_fg, base_scr_pag_bg; ULONG base_spr_regist; ULONG base_brq_page; UWORD reg_scr_active; UBYTE fake_page=0x01; void *bank_ff_base, *sprites_base_data, *bank_44_base; void *display_base, *text_base, *tiles_base; void *foreground_base, *background_base; void *display_bottom, *vga_pointer; ULONG vscreen_base, vscreen_base_spr; extern BITMAP *vscreen, *vscreen_sub; extern UBYTE *TimerA, *TimerB; #ifndef RELEASE_BETA extern TraceOn(); #endif #ifdef SEARCH void m68k_dumpstate() { int i; CPTR nextpc; for(i = 0; i < 8; i++){ printf("D%d: %08lx ", i, regs.d[i]); if ((i & 3) == 3) printf("\n"); } for(i = 0; i < 8; i++){ printf("A%d: %08lx ", i, regs.a[i]); if ((i & 3) == 3) printf("\n"); } if (regs.s == 0) regs.usp = regs.a[7]; if (regs.s && regs.m) regs.msp = regs.a[7]; if (regs.s && regs.m == 0) regs.isp = regs.a[7]; printf("USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx SR=%08x\n", regs.usp,regs.isp,regs.msp,regs.vbr,regs.sr); printf ("T=%d%d S=%d M=%d N=%d Z=%d V=%d C=%d IMASK=%d\n", regs.t1, regs.t0, regs.s, regs.m, NFLG, ZFLG, VFLG, CFLG, regs.intmask); for(i = 0; i < 8; i++){ printf("FP%d: %g ", i, regs.fp[i]); if ((i & 3) == 3) printf("\n"); } printf("N=%d Z=%d I=%d NAN=%d\n", (regs.fpsr & 0x8000000) != 0, (regs.fpsr & 0x4000000) != 0, (regs.fpsr & 0x2000000) != 0, (regs.fpsr & 0x1000000) != 0); MC68000_disasm(m68k_getpc(), &nextpc, 1); printf("Next PC = 0x%0x\n", nextpc); } #endif void WAccessCtr(UWORD r, UBYTE v) { } UWORD CheckInput(UWORD r) { UBYTE rt=0, update=1; if (game==3) RAM[0xFF][0xEC96]=0xFF; switch (r) { case 0x0001: case 0x1003: // 1P CONTROL if (joy==1) { poll_joystick(); if (joy_b[joydef[0]]) rt|=0x02; if (joy_b[joydef[1]]) rt|=0x04; if (joy_b[joydef[2]]) rt|=0x01; if (joy_left) rt|=0x80; else if (joy_right) rt|=0x40; if (joy_down) rt|=0x10; else if (joy_up) rt|=0x20; } if (key[keydef[6]]) rt|=0x02; // ATTACK, PUNCH, LEFT FLIPPER if (key[keydef[7]]) rt|=0x04; // JUMP, KICK, RIGHT FLIPPER if (key[keydef[8]]) rt|=0x01; // MAGIC, JUMP, NOT USED if (key[keydef[9]]) rt|=0x20; // UP, UP, PUSH SWITCH else if (key[keydef[10]]) rt|=0x10;// DOWN, DOWN, NOT USED if (key[keydef[11]]) rt|=0x80;// LEFT, LEFT, LEFT SWITCH else if (key[keydef[12]]) rt|=0x40;// RIGHT, RIGHT, RIGHT SWITCH break; case 0x1007: // 2P CONTROL if (joy==2) { poll_joystick(); if (joy_b[joydef[0]]) rt|=0x02; if (joy_b[joydef[1]]) rt|=0x04; if (joy_b[joydef[2]]) rt|=0x01; if (joy_left) rt|=0x80; else if (joy_right) rt|=0x40; if (joy_down) rt|=0x10; else if (joy_up) rt|=0x20; } if (key[keydef[20]]) rt|=0x02; // ATTACK if (key[keydef[21]]) rt|=0x04; // JUMP if (key[keydef[22]]) rt|=0x01; // MAGIC if (key[keydef[23]]) rt|=0x20; // UP if (key[keydef[24]]) rt|=0x10; // DOWN if (key[keydef[25]]) rt|=0x80; // LEFT if (key[keydef[26]]) rt|=0x40; // RIGHT break; case 0x0009: case 0x1001: if (key[keydef[0]]) rt|=0x10; // 1P START if (key[keydef[1]]) rt|=0x20; // 2P START if (key[keydef[5]]) rt|=0x04; // TEST SWITCH if (key[keydef[2]]) rt|=0x02; // COIN SWITCH 2 if (key[keydef[3]]) rt|=0x01; // COIN SWITCH 1 if (key[keydef[4]]) rt|=0x08; // SERVICE SWITCH // RAM[0xFF][0xEC96]=~rt; break; case 0x000B: case 0x2001: // DIP SWITCH 2 rt=shinobi_ds2[game]; break; case 0x1005: // DIP SWICTH 1 rt=shinobi_ds1[game]; break; default: update=0; break; } if (update) RAM[ctr_bank][r]=~rt; return(r); } UBYTE RAccessCtr(UWORD r) { UBYTE rt=0; switch (r) { case 0x0001: case 0x1003: // 1P CONTROL if (key[keydef[8]]) rt|=0x01; // MAGIC if (key[keydef[6]]) rt|=0x02; // ATTACK if (key[keydef[7]]) rt|=0x04; // JUMP if (key[keydef[10]]) rt|=0x10;// DOWN if (key[keydef[9]]) rt|=0x20; // UP if (key[keydef[12]]) rt|=0x40;// RIGHT if (key[keydef[11]]) rt|=0x80;// LEFT break; case 0x1007: // 2P CONTROL if (key[keydef[24]]) rt|=0x01; // MAGIC if (key[keydef[25]]) rt|=0x02; // ATTACK if (key[keydef[26]]) rt|=0x04; // JUMP if (key[keydef[21]]) rt|=0x10; if (key[keydef[20]]) rt|=0x20; if (key[keydef[23]]) rt|=0x40; if (key[keydef[22]]) rt|=0x80; break; case 0x0009: case 0x1001: if (key[keydef[0]]) rt|=0x10; // 1P if (key[keydef[1]]) rt|=0x20; // 2P if (key[keydef[5]]) rt|=0x04; // TEST if (key[keydef[2]]) rt|=0x02; // COIN SWITCH 2 if (key[keydef[3]]) rt|=0x01; // COIN SWITCH 1 if (key[keydef[4]]) rt|=0x08; // SERVICE break; case 0x000B: case 0x2001: // DIP SWITCH 2 rt=shinobi_ds2[game]; break; case 0x2003: // DIP SWICTH 1 rt=shinobi_ds1[game]; break; default: rt=(0x00); break; } return(~rt); } #ifdef MAX_MEM_TEST void TestMemAccessW(LONG p) { int s=(p&0xFF0000)>>16; int o=(p&0x00FFFF); if (o>MaximumW[s]) MaximumW[s]=o; } void TestMemAccessR(LONG p) { int s=(p&0xFF0000)>>16; int o=(p&0x00FFFF); if (o>MaximumR[s]) MaximumR[s]=o; } #endif // Proc‚dures d'acc‚s … la m‚moire // UBYTE ReadMEM(LONG p) { UBYTE bank = ((p&0xFF0000)>>16); #ifdef MAX_MEM_TEST TestMemAccessR(p); #endif switch (bank) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x40: case 0x41: case 0x43: case 0x84: case 0x10: case 0x11: case 0x14: case 0x3F: case 0x7F: case 0x1F: case 0xC0: case 0x44: case 0x20: case 0xFE: case 0x1E: case 0xFF: return(RAM[bank][p&0x0000FFFF]); break; case 0xE4: case 0xC4: return(RAccessCtr(p&0x0000FFFF)); break; #ifndef RELEASE_BETA default: { TraceOn(); printf("Tentative d'accŠs en lecture … une zone m‚moire non ‚mul‚e !\n"); printf("PC=0x%0x, zone lue=0x%0x (0x%0x)\n", m68k_getpc(), p, bank); m68k_dumpstate(); } #endif } } #ifdef SON_SIMULE void Load_Samples() { int i; char fn[30], bn[6]; switch (game) { case 1: strcpy(bn, "SHINO"); break; case 2: strcpy(bn, "ALTER"); break; } printf("Loading samples...\n"); for (i=0;i!=255;i++) { sprintf(fn, "samples\\%s_%02x.WAV", bn, i); if (file_exists(fn, 0, NULL)) { printf("%s\n", fn); Sons[i]=load_sample(fn); } else Sons[i]=NULL; } printf("Son charg‚s!\n"); } #endif void SoundRequest(int son) { #ifdef SON_SIMULE RGB pal; char status[40]; RAM[0xFE][0x0007]=0x00; if ((son>=0x40)&&(son<0x90)) last_voice=((last_voice<<8)|son); else if ((son>=0x90)&&(son<0xA0)) last_bgm=((last_bgm<<8)|son); else if ((son>=0xA0)&&(son<0xC0)) last_sfx=((last_sfx<<8)|son); /* 90-9A = BGM , A0-BD = SFX , 41-4F = VOICE */ pal.r=pal.g=pal.b=63; set_color(255, (RGB *)&pal); sprintf(status, "B:%08x S:%08x V:%08x", last_bgm, last_sfx, last_voice); textout(screen, font, status, 8, 232, 255); if (Sons[son]!=NULL) play_sample(Sons[son], 200, 100, 400, 0); #endif } void WriteMEM(LONG p, UBYTE v) { UBYTE bank = ((p&0xFF0000)>>16); #ifdef MAX_MEM_TEST TestMemAccessW(p); #endif /* if ((p==0xFFFFD780)&&(v==0x00)) { TraceOn(); printf("$D780 = $00!\n"); }*/ p&=0x0000FFFF; switch (bank) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: RAM[bank][p]=v; break; case 0xFE: if ((p&0xFFFF)==7) SoundRequest(v); break; case 0xFF: case 0x44: case 0x20: case 0x40: case 0x43: case 0x41: case 0x84: case 0x10: case 0x11: case 0x14: case 0x3F: case 0x7F: case 0x1F: case 0x1E: case 0xC0: RAM[bank][p]=v; break; case 0xE4: case 0xC4: WAccessCtr(p&0x0000FFFF, v); break; #ifndef RELEASE_BETA default: { TraceOn(); printf("Tentative d'accŠs en ‚criture … une zone m‚moire non ‚mul‚e !\n"); printf("PC=0x%0x, zone acc‚d‚e=0x%0x (0x%0x)\n", m68k_getpc(), p, bank); m68k_dumpstate(); sortie=0; } #endif } } #ifdef ASM_MEMORY UBYTE get_byte(LONG a); void put_byte(LONG a, UBYTE b); void put_word(LONG a, UWORD b); UWORD get_word(LONG a); void put_long(LONG a, ULONG b); ULONG get_long(LONG a); #else UBYTE get_byte(LONG a) { // if (((a&0xC40000)>>16)==0xC4) CheckInput(a&0xFFFF); return(ReadMEM(a)); } void put_byte(LONG a, UBYTE b) { WriteMEM(a, b); } void put_word(LONG a, UWORD b) { WriteMEM(a, (UBYTE)((b&0xFF00)>>8)); WriteMEM(a+1, (UBYTE)(b&0x00FF)); } UWORD get_word(LONG a) { return(((ULONG)ReadMEM(a)<<8)+(ULONG)ReadMEM(a+1)); } void put_long(LONG a, ULONG b) { WriteMEM(a, (UBYTE)((b&0xFF000000)>>24)); WriteMEM(a+1, (UBYTE)((b&0x00FF0000)>>16)); WriteMEM(a+2, (UBYTE)((b&0x0000FF00)>>8)); WriteMEM(a+3, (UBYTE)(b&0x000000FF)); } ULONG get_long(LONG a) { return( (((ULONG)ReadMEM(a))<<24)+ (((ULONG)ReadMEM(a+1))<<16)+ (((ULONG)ReadMEM(a+2))<<8)+ ((ULONG)ReadMEM(a+3)) ); } #endif void Setup_Asm() { ULONG ptr, ptr2; int i; vscreen_base_spr=vscreen_base=(ULONG)vscreen->line[0]; bank_ff_base=RAM[0xFF]; bank_44_base=RAM[0x44]; sprites_base_data=SpritesROM; display_base=&(vscreen->line[88][88]); display_bottom=vscreen->line[312]; text_base=&RAM[txt_bank][0x002E]; tiles_base=TilesROM1; foreground_base=RAM[vid_bank]; background_base=RAM[vid_bank]; for (i=0;i!=16;i++) spr_tab[i]=spr_tab_all[(16*(game-1))+i]; ptr=(ULONG)RAM[0xFF]; ptr2=(ULONG)RAM[0x41]; switch (game) { case 2: /* Altered Beast */ base_spr_regist=(ULONG)RAM[0x44]; base_scr_hor_fg=ptr2+0x0E98; base_scr_hor_bg=ptr2+0x0E9A; base_scr_ver_fg=ptr2+0x0E91; base_scr_ver_bg=ptr2+0x0E93; base_scr_pag_fg=ptr2+0x0E81; base_scr_pag_bg=ptr2+0x0E83; base_brq_page=ptr+0xF095; reg_scr_active=0xF018; TimerA=&RAM[0xFF][0xF01C]; TimerB=&RAM[0xFF][0xF01E]; break; case 3: /* Golden Axe */ ptr2=(ULONG)RAM[0x11]; base_spr_regist=(ULONG)RAM[0x20]; base_scr_hor_fg=ptr2+0x0E98; base_scr_hor_bg=ptr2+0x0E9A; base_scr_ver_fg=ptr2+0x0E91; base_scr_ver_bg=ptr2+0x0E93; base_scr_pag_fg=ptr2+0x0E81; base_scr_pag_bg=ptr2+0x0E83; reg_scr_active=0xF018; base_brq_page=(ULONG)&RAM[0x1F][0x2003]; break; case 5: base_spr_regist=(ULONG)RAM[0x44]; base_scr_hor_fg=ptr+0xCD14; base_scr_hor_bg=ptr+0xCD18; base_scr_ver_fg=ptr+0xFFF0; base_scr_ver_bg=ptr+0xFFF0; base_scr_pag_fg=ptr+0xCD1D; base_scr_pag_bg=ptr+0xCD1F; TimerA=&RAM[0xFF][0xC800]; break; case 6: base_spr_regist=(ULONG)RAM[0x44]; ptr_text_video=(ULONG)RAM[0x41]; /* foreground */ base_scr_hor_fg=ptr2+0x0E98; base_scr_ver_fg=ptr2+0x0E91; base_scr_pag_fg=ptr2+0x0E81;//E81 /* background */ base_scr_hor_bg=ptr2+0x0E9E;//E9A//E9E base_scr_ver_bg=ptr2+0x0E97;//E93//E97 base_scr_pag_bg=ptr2+0x0E87;//E83//E87 // base_brq_page=(ULONG)&fake_page; base_brq_page=(ULONG)&RAM[0xC0][0x0001]; break; case 4: reg_scr_active=0xC010; base_spr_regist=(ULONG)RAM[0x44]; base_scr_hor_fg=ptr2+0x0E98; base_scr_hor_bg=ptr2+0x0E9A; base_scr_ver_fg=ptr2+0x0E91; base_scr_ver_bg=ptr2+0x0E93; base_scr_pag_fg=ptr2+0x0E81; base_scr_pag_bg=ptr2+0x0E83; base_brq_page=(ULONG)&fake_page; break; default: /* Shinobi */ base_spr_regist=ptr+0xF800; base_scr_hor_fg=ptr2+0x0E98; base_scr_hor_bg=ptr2+0x0E9A; base_scr_ver_fg=ptr2+0x0E91; base_scr_ver_bg=ptr2+0x0E93; base_scr_pag_fg=ptr2+0x0E81; base_scr_pag_bg=ptr2+0x0E83; base_brq_page=(ULONG)&fake_page; TimerA=&RAM[0xFF][0xF01C]; TimerB=&RAM[0xFF][0xF01E]; reg_scr_active=0xF018; break; } } void RenderScreen() { char status[40]; RGB pal; #ifdef SEARCH pal.r=pal.g=pal.b=63; set_color(255,(RGB *)&pal); sprintf(status, " [%08x]=[%04x]", valeur_controle, get_word(valeur_controle)); /* sprintf(status ,"BASE=%03x, P=%04x, V=%04x, H=%04x", valeur_controle&0xFFF, get_word(valeur_controle), get_word(valeur_controle+16), get_word(valeur_controle+24));*/ textout(screen, font, status, 0, 0, 255); #endif if (game<3) { if (RAM[0xFF][reg_scr_active]&0x20) asm_render_screen(); } else asm_render_screen(); #ifdef SEARCH sprintf(status, "R=[%04x]", resultat); textout(screen, font, status, 160, 232, 255); #endif if (number_of_new_colors) Update_Palette(); if (sync) { // while ((inportb(0x3DA)&0x08)!=0); while ((inportb(0x3DA)&0x08)==0); } blit(vscreen, screen, 104, 88, sx, sy, 312, 224); total_render++; } void Save_SRAM() { PACKFILE *f; char fn[15]; sprintf(fn, "%s.ram", game_basename); f=pack_fopen(fn, F_WRITE_PACKED); if (f!=NULL) { pack_fwrite(&RAM[0xFF][0xF000], 0x1000, f); pack_fclose(f); } } void Load_SRAM() { PACKFILE *f; char fn[15]; sprintf(fn, "%s.ram", game_basename); f=pack_fopen(fn, F_READ_PACKED); if (f!=NULL) { pack_fread(&RAM[0xFF][0xF000], 0x1000, f); pack_fclose(f); } } /* UWORD get_word(LONG a) { UBYTE bank=(a&0xFF0000)>>16; UWORD offs=(a&0xFFFF); if (bank==0xC4) CheckInput(offs); return((RAM[bank][offs]*256)+RAM[bank][offs+1]); } */