#include "emul.h" #include #include void emul_init( emul_t *emul, cpu_6502_t *cpu, bus_t *bus, int width, int height ) { emul->cpu = cpu; emul->bus = bus; emul->gui = false; emul->width = width; emul->height = height; emul->debug = false; emul->paused = false; emul->speed = CPU_FREQUENCY; } void emul_start( emul_t *emul ) { if( emul->gui ) { #ifdef WITH_GUI int rt = SDL_Init( SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO ); if( rt < 0 ) { fprintf( stderr, "ERROR: SDL_Init failed: %s\n", SDL_GetError( ) ); exit( EXIT_FAILURE ); } atexit( SDL_Quit ); SDL_ShowCursor( SDL_ENABLE ); int display = -1; for( int i = 0; i < SDL_GetNumVideoDisplays( ); i++ ) { SDL_Rect rect; if( SDL_GetDisplayBounds( i, &rect ) == 0 ) { fprintf( stderr, "INFO: display %d has dimensions %dx%d\n", i, rect.w, rect.h ); display = i; } else { fprintf( stderr, "ERROR: SDL_GetDisplayBounds failed: %s\n", SDL_GetError( ) ); exit( EXIT_FAILURE ); } } if( display < 0 ) { fprintf( stderr, "ERROR: no video display found\n" ); exit( EXIT_FAILURE ); } emul->window = SDL_CreateWindow( "6502 emu", SDL_WINDOWPOS_UNDEFINED_DISPLAY( display ), SDL_WINDOWPOS_UNDEFINED_DISPLAY( display ), emul->width, emul->height, 0 ); if( emul->window == NULL ) { fprintf( stderr, "ERROR: SDL_CreateWindow failed: %s\n", SDL_GetError( ) ); exit( EXIT_FAILURE ); } emul->renderer = SDL_CreateRenderer( emul->window, -1, 0 ); if( emul->renderer == NULL ) { fprintf( stderr, "ERROR: SDL_Renderer failed: %s\n", SDL_GetError( ) ); exit( EXIT_FAILURE ); } SDL_ShowWindow( emul->window ); SDL_SetRenderDrawColor( emul->renderer, 0, 0, 0, 255 ); SDL_RenderClear( emul->renderer ); emul->background_image = SDL_LoadBMP( "../other/breadboard.bmp" ); emul->background_texture = SDL_CreateTextureFromSurface( emul->renderer, emul->background_image ); SDL_RenderCopy( emul->renderer, emul->background_texture, NULL, NULL ); SDL_RenderPresent( emul->renderer ); #else fprintf( stderr, "WARN: gui enabled and not compiled with WITH_GUI (SDL2)\n" ); #endif } } static void print_help( void ) { fprintf( stderr, "CPU is paused, press\n" "(s) for single step\n" "(f) fini (continue to next rts)\n" "(c) for continue running\n" "(b) break to single stepping\n" "(+) speed up\n" "(-) speed down\n" "(q) or (ESC) for shutting down\n" ); } void emul_run( emul_t *emul, int nof_steps ) { #ifdef WITH_GUI if( emul->gui ) { SDL_Event event; bool done = false; if( emul->paused ) { print_help( ); } while( !done && emul->cpu->error_state == ERROR_STATE_OK ) { uint32_t frame_start = SDL_GetTicks( ); SDL_PollEvent( &event ); switch( event.type ) { case SDL_KEYDOWN: switch( event.key.keysym.sym ) { case SDLK_ESCAPE: case SDLK_q: done = true; break; case SDLK_c: fprintf( stderr, "continuing at normal speed %1.6f MHz\n", ( (double)emul->speed / 1000000 ) ); emul->paused = false; break; case SDLK_b: fprintf( stderr, "CPU paused (in single step mode)\n" ); emul->paused = true; break; case SDLK_s: cpu_6502_run_steps( emul->cpu, 1 ); break; case SDLK_EQUALS: case SDLK_KP_EQUALS: case SDLK_PLUS: case SDLK_KP_PLUS: emul->speed *= 10; if( emul->speed > CPU_FREQUENCY ) { emul->speed = CPU_FREQUENCY; } fprintf( stderr, "CPU speed is %1.6f MHz now\n", ( (double)emul->speed / 1000000 ) ); break; case SDLK_MINUS: case SDLK_KP_MINUS: emul->speed /= 10; if( emul->speed < 25 ) { emul->speed = 25; } fprintf( stderr, "CPU speed is %1.6f MHz now\n", ( (double)emul->speed / 1000000 ) ); break; } break; case SDL_QUIT: done = true; break; } if( !emul->paused ) { cpu_6502_run_cycles( emul->cpu, emul->speed / DISPLAY_FPS ); } SDL_RenderCopy( emul->renderer, emul->background_texture, NULL, NULL ); emul->bus->base.vtable->draw( emul->bus, emul->renderer ); //~ for( int i = 0; i < emul->bus->nof_devices; i++ ) { //~ device_t *device = emul->bus->devices[i].device; //~ device->vtable->draw( device, emul->renderer ); //~ } SDL_RenderPresent( emul->renderer ); uint32_t frame_end = SDL_GetTicks( ); int delay = frame_start + 1000 / DISPLAY_FPS - frame_end; if( delay > 0 ) { SDL_Delay( delay ); } if( nof_steps != -1 && emul->cpu->steps > nof_steps ) { fprintf( stderr, "INFO: final number of steps reached (%d), terminating now\n", emul->cpu->steps ); done = true; } } } else { cpu_6502_run_steps( emul->cpu, nof_steps ); } #else cpu_6502_run( emul->cpu, nof_steps ); #endif } void emul_free( emul_t *emul ) { #ifdef WITH_GUI if( emul->gui ) { SDL_DestroyTexture( emul->background_texture ); SDL_FreeSurface( emul->background_image ); SDL_DestroyRenderer( emul->renderer ); SDL_DestroyWindow( emul->window ); } #endif }