/* YAPE - Yet Another Plus/4 Emulator The program emulates the Commodore 264 family of 8 bit microcomputers This program is free software, you are welcome to distribute it, and/or modify it under certain conditions. For more information, read 'Copying'. (c) 2000, 2001, 2004 Attila Grósz */ #include "main.h" #include "interface.h" #include // SDL stuff static SDL_Event event; static SDL_Surface *screen, *image; static SDL_Palette palette; static SDL_Color *g_pal; static SDL_Rect dest; // class pointer for the user interface static UI *uinterface; // color static Uint8 p4col_calc[768]; /////////////////// // Screen variables static Uint8 *pixel; //////////////// // Supplementary static Uint32 g_TotFrames = 0; static Uint32 timeelapsed; static MEM *ted8360 = new MEM; static CPU *machine = new CPU(ted8360); static Uint32 i; static char textout[40]; static char inipath[512] = ""; static char inifile[512] = ""; static Uint8 *screenptr; static bool g_bActive = true; static bool g_inDebug = false; static bool g_FrameRate = true; static bool g_50Hz = true; static bool g_bSaveSettings = true; //----------------------------------------------------------------------------- // Name: ShowFrameRate() //----------------------------------------------------------------------------- inline static void ShowFrameRate() { static Uint32 fps = 50; static Uint32 g_TotElapsed = 0; g_TotFrames++; if (g_TotElapsed + 2000 < timeelapsed) { g_TotElapsed = timeelapsed; fps = g_TotFrames / 2; g_TotFrames = 0; } sprintf(textout, "%3i FPS", fps); ted8360->texttoscreen(324,40,textout); } //----------------------------------------------------------------------------- // Name: DebugInfo() //----------------------------------------------------------------------------- inline static void DebugInfo() { const Uint32 hpos = 36, vpos = 12; sprintf(textout,"OPCODE: %02x ",machine->getcins()); ted8360->texttoscreen(hpos,vpos,textout); ted8360->texttoscreen(hpos,vpos+8," PC SR AC XR YR SP"); sprintf(textout,";%04x %02x %02x %02x %02x %02x",machine->getPC(),machine->getST(),machine->getAC(),machine->getX(),machine->getY(), machine->getSP()); ted8360->texttoscreen(hpos,vpos+16,textout); sprintf(textout,"TAPE: %08d ",ted8360->tap->TapeSoFar); ted8360->texttoscreen(hpos,vpos+24,textout); } //----------------------------------------------------------------------------- // Name: load_file() // Desc: The Load File Procedure //----------------------------------------------------------------------------- bool load_file(char *fname) { Uint8 *lpBufPtr; Uint16 loadaddr; FILE *prg; Uint32 fsize; if ((prg = fopen(fname, "rb"))== NULL) { return false; } else { // load PRG file fseek(prg, 0L, SEEK_END); fsize=ftell(prg); fseek(prg, 0L, SEEK_SET); lpBufPtr=(Uint8 *) malloc(fsize); fread(lpBufPtr,fsize,1,prg); // copy to memory loadaddr=lpBufPtr[0]|(lpBufPtr[1]<<8); for (i=0;iwrt(loadaddr+i,lpBufPtr[2+i]); ted8360->wrt(0x2D,(loadaddr+fsize-2)&0xFF); ted8360->wrt(0x2E,(loadaddr+fsize-2)>>8); ted8360->wrt(0x2F,(loadaddr+fsize-2)&0xFF); ted8360->wrt(0x30,(loadaddr+fsize-2)>>8); ted8360->wrt(0x31,(loadaddr+fsize-2)&0xFF); ted8360->wrt(0x32,(loadaddr+fsize-2)>>8); ted8360->wrt(0x9D,(loadaddr+fsize-2)&0xFF); ted8360->wrt(0x9E,(loadaddr+fsize-2)>>8); fclose(prg); }; return true; } //----------------------------------------------------------------------------- // Name: StartFile( ) // Desc: The Load PRG File Dialog Box Procedure //----------------------------------------------------------------------------- bool StartFile() { ted8360->wrt(0xEF,4); ted8360->wrt(0x0527,82); ted8360->wrt(0x0528,85); ted8360->wrt(0x0529,78); ted8360->wrt(0x052A,13); return true; } //----------------------------------------------------------------------------- bool start_file(char *szFile ) { char fileext[4]; if (szFile[0]!='\0') { for (i=0;i<4;++i) fileext[i]=tolower(szFile[strlen(szFile)-3+i]); if (!strncmp(fileext,"d64",3)) { /*if (!LoadD64Image(szFile)) { return false; }*/ ted8360->wrt(0xEF,9); ted8360->wrt(0x0527,68); ted8360->wrt(0x0528,204); ted8360->wrt(0x0529,34); ted8360->wrt(0x052A,42); ted8360->wrt(0x052B,13); ted8360->wrt(0x052C,82); ted8360->wrt(0x052D,85); ted8360->wrt(0x052E,78); ted8360->wrt(0x052F,13); return true; } if (!strcmp(fileext,"prg")) { load_file( szFile ); StartFile(); return true; } if (!strcmp(fileext,"tap")) { /*ted8360->wrt(0xEF,3); ted8360->wrt(0x0527,76); ted8360->wrt(0x0528,207); ted8360->wrt(0x0529,13);*/ ted8360->tap->detach_tap(); strcpy(ted8360->tap->tapefilename, szFile); ted8360->tap->attach_tap(); /*ted8360->wrtDMA(0xFD10,ted8360->readDMA(0xFD10)&~0x04); ted8360->tapeload=true;*/ return true; } return false; } return false; } //----------------------------------------------------------------------------- void init_palette(void) { Uint32 colorindex; double Uc, Vc, Yc, PI = 3.14159265 ; double bsat = 45.0; /* Allocate 256 color palette */ int ncolors = 256; g_pal = (SDL_Color *)malloc(ncolors*sizeof(SDL_Color)); // calculate palette based on the HUE values memset(p4col_calc, 0, 768); for ( i=1; i<16; i++) for ( register int j = 0; j<8; j++) { Uint8 col; if (i == 1) Uc = Vc = 0; else { Uc = bsat * ((float) cos( HUE[i] * PI / 180.0 )); Vc = bsat * ((float) sin( HUE[i] * PI / 180.0 )); } Yc = (luma[j+1] - 2.0)* 255.0 / (5.0 - 2.0); // 5V is the base voltage // RED, GREEN and BLUE component colorindex = (j)*16*3 + i*3; col = (Uint8) fmax(fmin((Yc + 1.367 * Vc),255.0),0); p4col_calc[ colorindex ] = p4col_calc[ 384 + colorindex ] = col; col = (Uint8) fmax(fmin((Yc - 0.336 * Uc - 0.698 * Vc ),255.0),0); p4col_calc[ colorindex + 1] = p4col_calc[ 384 + colorindex + 1] = col; col = (Uint8) fmax(fmin((Yc + 1.732 * Uc),255.0),0); p4col_calc[ colorindex + 2] = p4col_calc[ 384 + colorindex + 2] = col; } for (i=0 ; i<256; ++i) { // Creating an 8 bit SDL_Color structure g_pal[i].b=p4col_calc[i*3+2]; g_pal[i].g=p4col_calc[i*3+1]; g_pal[i].r=p4col_calc[i*3]; g_pal[i].unused=0; } palette.ncolors = 256; palette.colors = g_pal; } inline void FrameUpdate(void) { SDL_Rect rc; rc.x = (456-384)/2; rc.y = (312-288)/2; rc.w = 384; rc.h = 288; //SDL_BlitSurface( image, &rc , screen, NULL); SDL_BlitSurface( image, &rc , screen, &rc); SDL_Flip ( screen ); } //----------------------------------------------------------------------------- // Name: SaveSettings //----------------------------------------------------------------------------- bool SaveSettings() { FILE *ini; unsigned int rammask; if (ini=fopen(inifile,"wt")) { fprintf(ini, "[Yape configuration file]\n"); //fprintf(ini,"Double sized window=%d\n",g_bDblSize); fprintf(ini,"Display frame rate=%d\n",g_FrameRate); fprintf(ini,"Display quick debug info=%d\n",g_inDebug); //fprintf(ini,"Use GDI for video=%d\n",g_UseGDI); //fprintf(ini,"Small border=%d\n",g_smallborder); fprintf(ini,"50 MHz timer=%d\n",g_50Hz); //fprintf(ini,"Relative speed index=%d\n",g_RelSpeedIndex); //fprintf(ini,"Sound=%d\n",g_bIsSound); fprintf(ini,"Joystick emulation=%d\n",ted8360->joyemu); fprintf(ini,"Active joystick=%d\n",ted8360->keys->activejoy); //fprintf(ini,"PC joystick=%d\n",PCjoyactive); rammask = ted8360->getRamMask(); fprintf(ini,"Ram mask=%x\n",rammask); fprintf(ini,"256KB RAM=%x\n",ted8360->bigram); fprintf(ini,"Save settings on exit=%x\n",g_bSaveSettings); //fprintf(ini,"Palette index=%d\n",g_scrpalindex); for (i = 0; i<4; i++) { fprintf(ini,"ROM C%d LOW=%s\n",i, ted8360->romlopath[i]); fprintf(ini,"ROM C%d HIGH=%s\n",i, ted8360->romhighpath[i]); } fclose(ini); return true; } return false; } bool LoadSettings() { FILE *ini; unsigned int rammask; bool tmpint; char first[6], fname[256]; //SDL_Event event; if (ini=fopen(inifile,"r")) { fscanf(ini,"%s configuration file]\n", first); if (strcmp(first, "[Yape")) return false; //fscanf(ini,"Double sized window=%d\n",&g_bDblSize); fscanf(ini,"Display frame rate=%d\n",&g_FrameRate); fscanf(ini,"Display quick debug info=%d\n",&g_inDebug); //fscanf(ini,"Use GDI for video=%d\n",&g_UseGDI); //fscanf(ini,"Small border=%d\n",&g_smallborder); fscanf(ini,"50 MHz timer=%d\n",&g_50Hz); //fscanf(ini,"Relative speed index=%d\n",&g_RelSpeedIndex); //fscanf(ini,"Sound=%d\n",&g_bIsSound); fscanf(ini,"Joystick emulation=%d\n",&tmpint); ted8360->joyemu = tmpint; fscanf(ini,"Active joystick=%d\n",&(ted8360->keys->activejoy)); tmpint ? ted8360->keys->joyinit() : ted8360->keys->releasejoy(); //fscanf(ini,"PC joystick=%d\n",&PCjoyactive); fscanf(ini,"Ram mask=%x\n",&rammask); ted8360->setRamMask( rammask ); fscanf(ini,"256KB RAM=%x\n",&tmpint); ted8360->bigram = tmpint; fscanf(ini,"Save settings on exit=%x\n",&g_bSaveSettings); //fscanf(ini,"Palette index=%d\n",&g_scrpalindex); /*g_bDblSize=!g_bDblSize; SendMessage(hWnd,WM_COMMAND,IDM_DBLSIZE,0L);*/ /*g_FrameRate=!g_FrameRate; event.key.type = SDL_KEYDOWN; event.key.state = SDL_RELEASED; SDL_PushEvent(&event); //SendMessage(hWnd,WM_COMMAND,IDM_FRAMERATE,0L); g_inDebug=!g_inDebug; /*SendMessage(hWnd,WM_COMMAND,IDM_DEBUG,0L); g_UseGDI=!g_UseGDI; SendMessage(hWnd,WM_COMMAND,IDM_GDI,0L); g_smallborder=!g_smallborder; SendMessage(hWnd,WM_COMMAND,IDM_SMALLBORDER,0L); SendMessage(hWnd,WM_COMMAND,g_SpeedMsg[g_RelSpeedIndex],0L); g_bIsSound=!g_bIsSound; SendMessage(hWnd,WM_COMMAND,IDM_SOUND,0L); ted8360->joyemu=!ted8360->joyemu; SendMessage(hWnd,WM_COMMAND,IDM_JOYEMU,0L); ted8360->keys->activejoy=!ted8360->keys->activejoy; SendMessage(hWnd,WM_COMMAND,IDM_SWAPJOY,0L); PCjoyactive=!PCjoyactive; SendMessage(hWnd,WM_COMMAND,IDM_PCJOY,0L); g_bSaveSettings=!g_bSaveSettings; SendMessage(hWnd,WM_COMMAND,IDM_SAVEONEXIT,0L); SendMessage(hWnd,WM_COMMAND,g_screenpalette[g_scrpalindex],0L);*/ for (i = 0; i<4; i++) { if (fscanf(ini,"ROM C%d LOW=%s\n", &tmpint, fname)) strcpy(ted8360->romlopath[tmpint], fname); else strcpy(ted8360->romlopath[tmpint], ""); if (fscanf(ini,"ROM C%d HIGH=%s\n", &tmpint, fname)) strcpy(ted8360->romhighpath[tmpint], fname); else strcpy(ted8360->romhighpath[tmpint], ""); } fclose(ini); return true; } return false; } inline void PopupMsg(char *msg) { Uint32 ix, len = strlen(msg); char dummy[40]; ix = len; while( ix-->0) dummy[ix] = 32; dummy[len] = '\0'; ted8360->texttoscreen(220-(len<<2),144,dummy); ted8360->texttoscreen(220-(len<<2),152,msg); ted8360->texttoscreen(220-(len<<2),160,dummy); FrameUpdate(); SDL_Delay(750); } //----------------------------------------------------------------------------- // Name: SaveBitmap() // Desc: Saves the SDL surface to Windows bitmap file named as yapeXXXX.bmp //----------------------------------------------------------------------------- int SaveBitmap( ) { bool success = true; char bmpname[16]; FILE *fp; int ix = 0; // finding the last yapeXXXX.bmp image while (success) { sprintf( bmpname, "yape%.4d.bmp", ix); fp=fopen( bmpname,"rb"); if (fp) fclose(fp); else success=false; ix++; }; //fprintf( stderr, "%s\n", bmpname); return SDL_SaveBMP( screen, bmpname); } //----------------------------------------------------------------------------- // Name: poll_events() // Desc: polls SDL events if there's any in the message queue //----------------------------------------------------------------------------- inline static void poll_events(void) { if ( SDL_PollEvent(&event) ) { switch (event.type) { case SDL_KEYDOWN: /*printf("The %d,%d,%s key was pressed!\n",event.key.keysym.sym,event.key.keysym.scancode, SDL_GetKeyName(event.key.keysym.sym));*/ if (event.key.keysym.mod & KMOD_LALT) { switch (event.key.keysym.sym) { case SDLK_j : ted8360->joyemu=!ted8360->joyemu; if (ted8360->joyemu) { sprintf(textout , " JOYSTICK EMULATION IS ON "); ted8360->keys->joyinit(); } else { sprintf(textout , " JOYSTICK EMULATION IS OFF "); ted8360->keys->releasejoy(); }; PopupMsg(textout); break; case SDLK_i : ted8360->keys->swapjoy(); sprintf(textout, "ACTIVE JOY IS : %d", ted8360->keys->activejoy); PopupMsg(textout); break; case SDLK_w : g_50Hz = ! g_50Hz ; if (g_50Hz) sprintf(textout , " 50 HZ TIMER IS ON "); else sprintf(textout , " 50 HZ TIMER IS OFF "); PopupMsg(textout); // restart counter g_TotFrames = 0; timeelapsed = SDL_GetTicks(); break; case SDLK_s : g_TotFrames = 0; g_FrameRate = !g_FrameRate; break; case SDLK_RETURN : SDL_WM_ToggleFullScreen( screen ); break; }; return; } switch (event.key.keysym.sym) { case SDLK_PAUSE : if (g_bActive) PopupMsg(" PAUSED "); g_bActive=!g_bActive; break; case SDLK_F5 : ted8360->wrtDMA(0xFD10,ted8360->readDMA(0xFD10)&~0x04); ted8360->wrtDMA(1,ted8360->readDMA(1)&0xF7); ted8360->tapeload=true; break; case SDLK_F6 : ted8360->wrtDMA(0xFD10,ted8360->readDMA(0xFD10)|0x04); ted8360->wrtDMA(1,ted8360->readDMA(1)|0x08); ted8360->tapeload=false; ted8360->tapesave=false; break; case SDLK_F7: //SDL_SaveBMP( screen , "yape.bmp"); if (!SaveBitmap( )) fprintf( stderr, "Screenshot saved.\n"); break; case SDLK_F8: uinterface = new UI(ted8360, screen, image, inipath); delete uinterface; break; case SDLK_F9 : g_inDebug=!g_inDebug; break; case SDLK_F10 : if (SaveSettings()) fprintf( stderr, "Settings saved to %s.\n", inifile); else fprintf( stderr, "Oops! Could not save settings... %s\n", inifile); break; case SDLK_F11 : g_bActive = false; break; case SDLK_F12 : case SDLK_ESCAPE : // Save settings if required if (g_bSaveSettings) SaveSettings(); close_audio(); exit(0); default : ted8360->keys->pushkey(event.key.keysym.sym&0x1FF); } break; case SDL_KEYUP: switch (event.key.keysym.sym) { case SDLK_F11 : g_bActive = true; switch (event.key.keysym.mod) { case KMOD_LSHIFT : case KMOD_RSHIFT : machine->reset(); break; case KMOD_LCTRL : case KMOD_RCTRL : machine->debugreset(); break; default : machine->softreset(); } break; default: ted8360->keys->releasekey(event.key.keysym.sym&0x1FF); } break; /*case SDL_VIDEORESIZE : resize_window(event.resize.w, event.resize.h); break;*/ case SDL_QUIT: // close audio close_audio(); // release the palette if (g_pal) free(g_pal); if (g_bSaveSettings) SaveSettings(); SDL_Quit(); exit(0); } } } static void app_initialise() { char drvnamebuf[16]; if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0 ) { // SDL_INIT_AUDIO| fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); exit(1); } atexit(SDL_Quit); // check the video driver we have SDL_VideoDriverName( drvnamebuf, 16); fprintf(stderr, "Using driver : %s\n", drvnamebuf); // set the window title and icon SDL_WM_SetCaption(NAME, "Yapelin"); SDL_WM_SetIcon(SDL_LoadBMP("Yapelin.bmp"), NULL); // set the appropriate video mode screen = SDL_SetVideoMode(456, 312, 8, //screen = SDL_SetVideoMode(384, 288, 8, /*SDL_RESIZABLE|*/SDL_HWPALETTE|SDL_SRCCOLORKEY|SDL_HWSURFACE|SDL_DOUBLEBUF ); // SDL_DOUBLEBUF|SDL_FULLSCREEN|SDL_RESIZABLE if ( screen == NULL) { fprintf(stderr, "Unable to set video mode\n"); exit(1); } event.type=SDL_VIDEORESIZE; event.resize.w=384; event.resize.h=288; SDL_PushEvent(&event); // set the window range to be updated dest.x = 0; dest.y = 0; dest.w = screen->w; dest.h = screen->h; // calculate and initialise palette init_palette(); init_audio(ted8360); // set colors to the screen buffer int SDLresult = SDL_SetColors(screen, g_pal, 0, 256); // set the backbuffer to the same format image = SDL_DisplayFormat(screen); // set the colors for the backbuffer too if (image->format->palette!= NULL ) { SDL_SetColors(screen, image->format->palette->colors, 0, image->format->palette->ncolors); } // change the pointer to the pixeldata of the backbuffer image->pixels = ted8360->screen; if (SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL)) fprintf(stderr,"Oops... could not set keyboard repeat rate.\n"); } inline Uint32 time_elapsed(void) { return SDL_GetTicks(); } // main program int main(int argc, char *argv[]) { // initialise SDL... app_initialise(); if (getenv("HOME")) { strcpy( inipath, getenv("HOME")); fprintf(stderr,"Home directory is %s\n",inipath); ad_makedirs( inipath ); } else { strcpy( inipath, ""); fprintf(stderr,"No home directory, using current directory\n"); } strcpy( inifile, ad_getinifilename( inipath ) ); if (LoadSettings()) { fprintf(stderr,"Settings loaded successfully.\n"); machine->reset(); } else fprintf(stderr,"Error loading settings or no .ini file present...\n"); //------------------------------------------------------------------------- // if we have a command line parameter if (argv[1]!='\0') { printf("Parameter 1 :%s\n", argv[1]); // do some frames while (g_TotFrames<6) { ted8360->ted_process(); FrameUpdate(); g_TotFrames++; } // and then try to load the parameter as file load_file(argv[1]); start_file(argv[1]); } //-------------------------------------------------------------- timeelapsed = time_elapsed(); ted8360->cpuptr = machine; for (;;) { // hook into the emulation loop if active if (g_bActive) { ted8360->ted_process(); poll_events(); if (g_inDebug) DebugInfo(); unsigned int time_limit = timeelapsed + 20; timeelapsed = time_elapsed(); if (g_50Hz) { if (time_limit>timeelapsed) { int nr10ms = ((time_limit-timeelapsed)/10) * 10; SDL_Delay(nr10ms); timeelapsed = time_elapsed(); while (time_limit>timeelapsed) { SDL_Delay(0); timeelapsed = time_elapsed(); } } } if (g_FrameRate) ShowFrameRate(); // frame update FrameUpdate(); } else { SDL_WaitEvent(NULL); poll_events(); } } return 0; }