Remove circular dependencies between libs, use callback function pointers instead
authorAndreas Eversberg <jolly@eversberg.eu>
Wed, 7 Mar 2018 17:55:57 +0000 (18:55 +0100)
committerAndreas Eversberg <jolly@eversberg.eu>
Wed, 7 Mar 2018 18:27:53 +0000 (19:27 +0100)
src/libcpu/execute.c
src/libcpu/execute.h
src/libdisk/disk.c
src/libdisk/disk.h
src/libsdl/sdl.c
src/libsdl/sdl.h
src/mercenary/main.c

index cb97845..0b53f23 100644 (file)
 static uint8_t *memory = NULL;
 static uint32_t memory_size = 0;
 static uint16_t *chipreg = NULL;
+static uint16_t (*io_read)(uint32_t address) = NULL;
+static void (*io_write)(uint32_t address, uint16_t value) = NULL;
 
-static uint16_t read_io(unsigned int address)
+
+static uint16_t read_io_16(unsigned int address)
 {
 #ifdef DEBUG_CPU
        printf("Chip read from 0x%08x\n", address);
 #endif
-       return emulate_io_read(address);
+       return io_read(address);
 }
 
-static void write_io(unsigned int address, uint16_t value)
+static void write_io_16(unsigned int address, uint16_t value)
 {
 #ifdef DEBUG_CPU
        printf("Chip write to 0x%08x\n", address);
 #endif
        if ((address & IOMASK) == IOBASE)
                chipreg[address & ~IOMASK] = value;
-       emulate_io_write(address, value);
+       io_write(address, value);
 }
 
 unsigned int m68k_read_memory_8(unsigned int address)
@@ -56,10 +59,10 @@ unsigned int m68k_read_memory_8(unsigned int address)
        if (address > memory_size - 1) {
                if ((address & 1)) {
                        /* read lower (right) byte */
-                       return read_io(address & ~1);
+                       return read_io_16(address & ~1);
                } else {
                        /* read upper (left) byte */
-                       return read_io(address) >> 8;
+                       return read_io_16(address) >> 8;
                }
        }
        return *((uint8_t *)(memory + address));
@@ -68,7 +71,7 @@ unsigned int m68k_read_memory_8(unsigned int address)
 unsigned int m68k_read_memory_16(unsigned int address)
 {
        if (address > memory_size - 2) {
-               return read_io(address);
+               return read_io_16(address);
        }
        return  (memory[address] << 8) |
                 memory[address + 1];
@@ -78,8 +81,8 @@ unsigned int m68k_read_memory_32(unsigned int address)
 {
        if (address > memory_size - 4) {
                int32_t value;
-               value = read_io(address) << 16;
-               value |= read_io(address + 2);
+               value = read_io_16(address) << 16;
+               value |= read_io_16(address + 2);
                return value;
        }
        return  (memory[address] << 24)|
@@ -93,10 +96,10 @@ void m68k_write_memory_8(unsigned int address, unsigned int value)
        if (address > memory_size - 1) {
                if ((address & 1)) {
                        /* write lower (right) byte */
-                       write_io(address & ~1, 0xff00 | value);
+                       write_io_16(address & ~1, 0xff00 | value);
                } else {
                        /* write upper (left) byte */
-                       write_io(address, 0x00ff | (value << 8));
+                       write_io_16(address, 0x00ff | (value << 8));
                }
                return;
        }
@@ -106,7 +109,7 @@ void m68k_write_memory_8(unsigned int address, unsigned int value)
 void m68k_write_memory_16(unsigned int address, unsigned int value)
 {
        if (address > memory_size - 2) {
-               write_io(address, value);
+               write_io_16(address, value);
                return;
        }
        memory[address] = value >> 8;
@@ -116,8 +119,8 @@ void m68k_write_memory_16(unsigned int address, unsigned int value)
 void m68k_write_memory_32(unsigned int address, unsigned int value)
 {
        if (address > memory_size - 4) {
-               write_io(address, value >> 16);
-               write_io(address + 2, value);
+               write_io_16(address, value >> 16);
+               write_io_16(address + 2, value);
                return;
        }
        memory[address] = value >> 24;
@@ -126,11 +129,13 @@ void m68k_write_memory_32(unsigned int address, unsigned int value)
        memory[address + 3] = value;
 }
 
-void execute_init(int32_t _memory_size, uint8_t *_memory, uint16_t *_chipreg)
+void execute_init(int32_t _memory_size, uint8_t *_memory, uint16_t *_chipreg, uint16_t (*_io_read)(uint32_t address), void (*_io_write)(uint32_t address, uint16_t value))
 {
        memory_size = _memory_size;
        memory = _memory;
        chipreg = _chipreg;
+       io_read = _io_read;
+       io_write = _io_write;
 
        /* init CPU */
        m68k_init();
index 64ef160..2b84421 100644 (file)
@@ -4,9 +4,7 @@ struct cpu_stop {
        int             event;
 };
 
-void execute_init(int32_t _memory_size, uint8_t *_memory, uint16_t *_chipreg);
+void execute_init(int32_t _memory_size, uint8_t *_memory, uint16_t *_chipreg, uint16_t (*io_read)(uint32_t address), void (*io_write)(uint32_t address, uint16_t value));
 void reset_cpu(void);
 int execute_cpu(int irq, const struct cpu_stop stop_at[], int *event);
-uint16_t emulate_io_read(uint32_t address);
-void emulate_io_write(uint32_t address, uint16_t value);
 
index e9126d4..ba34192 100644 (file)
@@ -35,9 +35,17 @@ static uint16_t ciabprb = 0xffff;
 static int track = 0;
 static uint32_t dskptr = 0;
 static uint16_t dsklen = 0;
+static void (*disk_read)(int track, int side, uint32_t data, uint16_t length) = NULL;
+static void (*disk_write)(int track, int side, uint32_t data, uint16_t length) = NULL;
 
 /* NOTE: all CIA access is WORD access, so we use bits 8..15 for CIA-B */
 
+void disk_init(void (*_disk_read)(int track, int side, uint32_t data, uint16_t length), void (*_disk_write)(int track, int side, uint32_t data, uint16_t length))
+{
+       disk_read = _disk_read;
+       disk_write = _disk_write;
+}
+
 uint16_t emulate_disk_read(uint32_t address)
 {
        uint16_t value = 0xffff;
index 76361f2..0d517fe 100644 (file)
@@ -1,7 +1,6 @@
 
+void disk_init(void (*disk_read)(int track, int side, uint32_t data, uint16_t length), void (*disk_write)(int track, int side, uint32_t data, uint16_t length));
 uint16_t emulate_disk_read(uint32_t address);
 void emulate_disk_write(uint32_t address, uint16_t value);
 int get_disk_track(void);
-void disk_read(int track, int side, uint32_t data, uint16_t length);
-void disk_write(int track, int side, uint32_t data, uint16_t length);
 
index ad57dad..99178db 100644 (file)
@@ -30,6 +30,8 @@ static int sdl_initialized = 0;
 static int audio_initialized = 0;
 static SDL_Window *gl_window = NULL;
 static SDL_GLContext gl_context = NULL;
+static void (*keyboard_sdl)(int down, SDL_Keycode sym) = NULL;
+static void (*audio_sdl)(float *data, int len) = NULL;
 
 static void audio_cb(void __attribute__((unused)) *userdata, Uint8 *stream, int len)
 {
@@ -40,10 +42,13 @@ static void audio_cb(void __attribute__((unused)) *userdata, Uint8 *stream, int
        SDL_MixAudio(stream, (Uint8 *)audio_data, len, SDL_MIX_MAXVOLUME);
 }
 
-int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk)
+int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk, void (*keyboard)(int down, SDL_Keycode sym), void (*audio)(float *data, int len))
 {
        int rc;
 
+       keyboard_sdl = keyboard;
+       audio_sdl = audio;
+
        /* init SDL library */
        rc = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
        if (rc < 0) {
index dab62c2..08eb7fc 100644 (file)
@@ -1,9 +1,7 @@
 #include <SDL2/SDL.h>
 
-int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk);
+int init_sdl(const char *progname, int width, int height, int sound_samplerate, int sound_chunk, void (*keyboard)(int down, SDL_Keycode sym), void (*audio)(float *data, int len));
 int event_sdl(void);
 void swap_sdl(void);
 void exit_sdl(void);
-void audio_sdl(float *data, int len);
-void keyboard_sdl(int down, SDL_Keycode sym);
 
index b4c7735..62f92ed 100644 (file)
@@ -251,143 +251,121 @@ static void main_loop(void)
        }
 }
 
-int main(int argc, char *argv[])
+static uint16_t io_read(uint32_t address)
 {
-       int rc;
-       int sdl_sound_chunk;
-
-       home_dir = getenv("HOME");
-       if (!home_dir)
-               home_dir = "";
-
-       rc = parse_args(argc, argv);
-       if (rc)
-               return 0;
+       uint16_t value = 0xffff;
 
-       /* allocate image */
-       image = calloc(IMAGE_WIDTH * IMAGE_HEIGHT * ((double_size) ? 4 : 1), 3);
-       if (!image) {
-               fprintf(stderr, "Failed to allocate image buffer\n");
-               goto done;
-       }
+       /* joystick and fire button */
+       if (address == 0xbfe000 || address == 0xdff00c)
+               value &= emulate_joystick_read(address);
+       /* keyboard */
+       if (address == 0xbfec00 || address == 0xbfed00 || address == 0xbfee00)
+               value &= emulate_keyboard_read(address);
+       /* diskette */
+       if (address == 0xbfd100 || address == 0xbfe000 || address == 0xdff01a || address == 0xdff01e)
+               value &= emulate_disk_read(address);
 
-       if ((SOUND_SAMPLERATE % IRQ_RATE)) {
-               fprintf(stderr, "Sample rate must be a multiple of IRQ rate, please fix!\n");
-               goto done;
-       }
-       if ((1000 % IRQ_RATE)) {
-               fprintf(stderr, "1000 (Ticks per second) rate must be a multiple of IRQ rate, please fix!\n");
-               goto done;
-       }
+       return value;
+}
 
-       /* calculate SDL chunk size for audio
-        * it must be a power of two, but not more than the chunk size for each IRQ!
-        */
-       for (sdl_sound_chunk = 2; sdl_sound_chunk <= (SOUND_SAMPLERATE / IRQ_RATE); sdl_sound_chunk <<= 1)
-               ;
-       sdl_sound_chunk >>= 1;
-//     printf("samples per IRQ = %d, samples per SDL audio = %d\n", SOUND_SAMPLERATE / IRQ_RATE, sdl_sound_chunk); exit(0);
+static void io_write(uint32_t address, uint16_t value)
+{
+       /* dmacon and sound registers */
+       if (address == 0xdff096 || (address >= 0xdff0a0 && address <= 0xdff0df))
+               emulate_sound_write(address, value, SOUND_SAMPLERATE);
+       if (address == 0xbfd100 || (address >= 0xdff020 && address <= 0xdff024))
+               emulate_disk_write(address, value);
+}
 
-       /* allocate sound buffers */
-       sound_buffer_size = SOUND_SAMPLERATE / IRQ_RATE * SOUND_CHUNKS;
-       sound_buffer = calloc(sound_buffer_size, sizeof(*sound_buffer));
-       if (!sound_buffer) {
-               fprintf(stderr, "Failed to allocate image buffer\n");
-               goto done;
-       }
+/* two tracks with 0x1820 words of length */
+static uint8_t game_save[2][0x1820 << 1];
+static int last_track = 0;
 
-       /* allocate memory */
-       memory = calloc(MEMORY_SIZE, 1);
-       if (!memory) {
-               fprintf(stderr, "Failed to allocate cpu's memory\n");
-               goto done;
-       }
-       chipreg = calloc(IOSIZE, 1);
-       if (!chipreg) {
-               fprintf(stderr, "Failed to allocate chip register\n");
-               goto done;
+/* game reads track with saved game */
+static void disk_read(int track, int __attribute__((unused)) side, uint32_t data, uint16_t length)
+{
+       if (length > sizeof(game_save[0])) {
+               fprintf(stderr, "loading game state failed, because length exceeds game save data size, please fix!\n");
+               return;
        }
 
-       /* init cpu code */
-       execute_init(MEMORY_SIZE, memory, chipreg);
-
-       /* load binary */
-       mercenary_load();
-
-       /* patch some stuff */
-       mercenary_patch();
-
-       /* init SDL and OpenGL */
-       rc = init_sdl(argv[0], SCREEN_WIDTH, SCREEN_HEIGHT, SOUND_SAMPLERATE, sdl_sound_chunk);
-       if (rc < 0)
-               goto done;
-       rc = init_opengl((double_size) ? IMAGE_WIDTH * 2 : IMAGE_WIDTH, (double_size) ? IMAGE_HEIGHT * 2 : IMAGE_HEIGHT);
-       if (rc < 0)
-               goto done;
-       resize_opengl(SCREEN_WIDTH, SCREEN_HEIGHT);
-
-       /* init audio filter */
-       sound_init_filter(SOUND_SAMPLERATE);
+       /* if even track is selected, load game */
+       if (!(track & 1)) {
+               char filename[256];
+               int gamesave_num = (track - 2) >> 1;
+               int got;
+               FILE *fp;
 
-       /* start cpu */
-       reset_cpu();
+               memset(game_save, 0, sizeof(game_save)); /* clear so make the game fail, if we fail */
+               sprintf(filename, "%s/%s/%d.gamesave", home_dir, config_gamesave_dir, gamesave_num);
+               fp = fopen(filename, "r");
+               if (!fp) {
+fail:
+                       fprintf(stderr, "failed to load game from '%s'\n", filename);
+                       goto copy;
+               }
+               got = fread(game_save, sizeof(game_save[0]), 2, fp);
+               fclose(fp);
+               if (got != 2)
+                       goto fail;
+       }
 
-       printf("**********************************\n");
-       printf("* Welcome to Mercenary Reloaded! *\n");
-       printf("**********************************\n\n");
-       printf("Press CTRL + cursor keys to select inventory or pickup/drop item.\n");
-       printf("Press CTRL + f to toggle full screen.\n");
-       printf("Press CTRL + s to toggle rendering speed.\n");
-       printf("Press CTRL + v to toggle video filter.\n");
-       printf("Press CTRL + a to toggle audio filter.\n");
-       printf("Press CTRL + c to exit game.\n\n");
-       printf("Use '--help' as command line option for configuration settings.\n\n");
+copy:
+       /* copy track */
+       memcpy(memory + data, game_save[track & 1], length /* sizeof(game_save[0])*/);
+}
 
-       /* run game */
-       main_loop();
+/* game writes track with saved game */
+static void disk_write(int track, int __attribute__((unused)) side, uint32_t data, uint16_t length)
+{
+       /* skip sync info that is provided by game and only relevant for a real disk track */
+       data += 0x200;
+       length -= 0x200;
 
-done:
-       exit_opengl();
-       exit_sdl();
+       if (length != sizeof(game_save[0])) {
+               fprintf(stderr, "saving game state failed, because length of data does not match, please fix!\n");
+               return;
+       }
 
-       if (chipreg)
-               free(chipreg);
-       if (memory)
-               free(memory);
-       if (sound_buffer)
-               free(sound_buffer);
-       if (image)
-               free(image);
+       /* don't save if last track is the same, because disk is written on both sides with the same data */
+       if (track == last_track) {
+               if (memcmp(memory + data, game_save[track & 1], length)) {
+                       fprintf(stderr, "saving game data on other side of the disk is different, please fix!\n");
+               }
+               return;
+       }
+       last_track = track;
 
-       return 0;
-}
+       /* save game data */
+       memcpy(game_save[track & 1], memory + data, length);
 
-void audio_sdl(float *data, int length)
-{
-       int fill, s;
+       /* if done with saving */
+       if ((track & 1)) {
+               char filename[256];
+               int gamesave_num = (track - 2) >> 1;
+               int wrote;
+               FILE *fp;
 
-       /* read sound from sound buffer
-        * buffer pointer read and write is atomic, so no locking required!
-        */
-       fill = (sound_buffer_writep - sound_buffer_readp + sound_buffer_size) % sound_buffer_size;
-       if (fill < length) {
-#ifdef DEBUG_SOUND_BUFFERING
-               fprintf(stderr, "sound buffer underrun\n");
-#endif
-               /* correct read pointer as if the buffer would have 'length' of samples stored inside */
-               sound_buffer_readp = (sound_buffer_readp + fill - length + sound_buffer_size) % sound_buffer_size;
+               sprintf(filename, "%s/%s", home_dir, config_gamesave_dir);
+               mkdir(filename, 0777);
+               sprintf(filename + strlen(filename), "/%d.gamesave", gamesave_num);
+               fp = fopen(filename, "w");
+               if (!fp) {
+fail:
+                       fprintf(stderr, "failed to save game to '%s'\n", filename);
+                       return;
+               }
+               printf("Game state saved to '%s'\n", filename);
+               wrote = fwrite(game_save, sizeof(game_save[0]), 2, fp);
+               fclose(fp);
+               if (wrote != 2)
+                       goto fail;
        }
-       for (s = 0; s < length; s++)
-               *data++ = sound_buffer[(sound_buffer_readp + s) % sound_buffer_size];
-#ifdef DEBUG_SOUND_BUFFERING
-       printf("fill %d = %.4f\n", length, sound_buffer[sound_buffer_readp]);
-#endif
-       sound_buffer_readp =(sound_buffer_readp + length) % sound_buffer_size;
 }
 
 static int shift = 0, ctrl = 0;
 
-void keyboard_sdl(int down, SDL_Keycode sym)
+static void keyboard_sdl(int down, SDL_Keycode sym)
 {
        switch (sym) {
        case SDLK_LCTRL:
@@ -545,114 +523,140 @@ void keyboard_sdl(int down, SDL_Keycode sym)
        }
 }
 
-uint16_t emulate_io_read(uint32_t address)
+void audio_sdl(float *data, int length)
 {
-       uint16_t value = 0xffff;
-
-       /* joystick and fire button */
-       if (address == 0xbfe000 || address == 0xdff00c)
-               value &= emulate_joystick_read(address);
-       /* keyboard */
-       if (address == 0xbfec00 || address == 0xbfed00 || address == 0xbfee00)
-               value &= emulate_keyboard_read(address);
-       /* diskette */
-       if (address == 0xbfd100 || address == 0xbfe000 || address == 0xdff01a || address == 0xdff01e)
-               value &= emulate_disk_read(address);
+       int fill, s;
 
-       return value;
+       /* read sound from sound buffer
+        * buffer pointer read and write is atomic, so no locking required!
+        */
+       fill = (sound_buffer_writep - sound_buffer_readp + sound_buffer_size) % sound_buffer_size;
+       if (fill < length) {
+#ifdef DEBUG_SOUND_BUFFERING
+               fprintf(stderr, "sound buffer underrun\n");
+#endif
+               /* correct read pointer as if the buffer would have 'length' of samples stored inside */
+               sound_buffer_readp = (sound_buffer_readp + fill - length + sound_buffer_size) % sound_buffer_size;
+       }
+       for (s = 0; s < length; s++)
+               *data++ = sound_buffer[(sound_buffer_readp + s) % sound_buffer_size];
+#ifdef DEBUG_SOUND_BUFFERING
+       printf("fill %d = %.4f\n", length, sound_buffer[sound_buffer_readp]);
+#endif
+       sound_buffer_readp =(sound_buffer_readp + length) % sound_buffer_size;
 }
 
-void emulate_io_write(uint32_t address, uint16_t value)
+int main(int argc, char *argv[])
 {
-       /* dmacon and sound registers */
-       if (address == 0xdff096 || (address >= 0xdff0a0 && address <= 0xdff0df))
-               emulate_sound_write(address, value, SOUND_SAMPLERATE);
-       if (address == 0xbfd100 || (address >= 0xdff020 && address <= 0xdff024))
-               emulate_disk_write(address, value);
-}
-
-/* two tracks with 0x1820 words of length */
-static uint8_t game_save[2][0x1820 << 1];
-static int last_track = 0;
+       int rc;
+       int sdl_sound_chunk;
 
-/* game reads track with saved game */
-void disk_read(int track, int __attribute__((unused)) side, uint32_t data, uint16_t length)
-{
-       if (length > sizeof(game_save[0])) {
-               fprintf(stderr, "loading game state failed, because length exceeds game save data size, please fix!\n");
-               return;
-       }
+       home_dir = getenv("HOME");
+       if (!home_dir)
+               home_dir = "";
 
-       /* if even track is selected, load game */
-       if (!(track & 1)) {
-               char filename[256];
-               int gamesave_num = (track - 2) >> 1;
-               int got;
-               FILE *fp;
+       rc = parse_args(argc, argv);
+       if (rc)
+               return 0;
 
-               memset(game_save, 0, sizeof(game_save)); /* clear so make the game fail, if we fail */
-               sprintf(filename, "%s/%s/%d.gamesave", home_dir, config_gamesave_dir, gamesave_num);
-               fp = fopen(filename, "r");
-               if (!fp) {
-fail:
-                       fprintf(stderr, "failed to load game from '%s'\n", filename);
-                       goto copy;
-               }
-               got = fread(game_save, sizeof(game_save[0]), 2, fp);
-               fclose(fp);
-               if (got != 2)
-                       goto fail;
+       /* allocate image */
+       image = calloc(IMAGE_WIDTH * IMAGE_HEIGHT * ((double_size) ? 4 : 1), 3);
+       if (!image) {
+               fprintf(stderr, "Failed to allocate image buffer\n");
+               goto done;
        }
 
-copy:
-       /* copy track */
-       memcpy(memory + data, game_save[track & 1], length /* sizeof(game_save[0])*/);
-}
+       if ((SOUND_SAMPLERATE % IRQ_RATE)) {
+               fprintf(stderr, "Sample rate must be a multiple of IRQ rate, please fix!\n");
+               goto done;
+       }
+       if ((1000 % IRQ_RATE)) {
+               fprintf(stderr, "1000 (Ticks per second) rate must be a multiple of IRQ rate, please fix!\n");
+               goto done;
+       }
 
-/* game writes track with saved game */
-void disk_write(int track, int __attribute__((unused)) side, uint32_t data, uint16_t length)
-{
-       /* skip sync info that is provided by game and only relevant for a real disk track */
-       data += 0x200;
-       length -= 0x200;
+       /* calculate SDL chunk size for audio
+        * it must be a power of two, but not more than the chunk size for each IRQ!
+        */
+       for (sdl_sound_chunk = 2; sdl_sound_chunk <= (SOUND_SAMPLERATE / IRQ_RATE); sdl_sound_chunk <<= 1)
+               ;
+       sdl_sound_chunk >>= 1;
+//     printf("samples per IRQ = %d, samples per SDL audio = %d\n", SOUND_SAMPLERATE / IRQ_RATE, sdl_sound_chunk); exit(0);
 
-       if (length != sizeof(game_save[0])) {
-               fprintf(stderr, "saving game state failed, because length of data does not match, please fix!\n");
-               return;
+       /* allocate sound buffers */
+       sound_buffer_size = SOUND_SAMPLERATE / IRQ_RATE * SOUND_CHUNKS;
+       sound_buffer = calloc(sound_buffer_size, sizeof(*sound_buffer));
+       if (!sound_buffer) {
+               fprintf(stderr, "Failed to allocate image buffer\n");
+               goto done;
        }
 
-       /* don't save if last track is the same, because disk is written on both sides with the same data */
-       if (track == last_track) {
-               if (memcmp(memory + data, game_save[track & 1], length)) {
-                       fprintf(stderr, "saving game data on other side of the disk is different, please fix!\n");
-               }
-               return;
+       /* allocate memory */
+       memory = calloc(MEMORY_SIZE, 1);
+       if (!memory) {
+               fprintf(stderr, "Failed to allocate cpu's memory\n");
+               goto done;
+       }
+       chipreg = calloc(IOSIZE, 1);
+       if (!chipreg) {
+               fprintf(stderr, "Failed to allocate chip register\n");
+               goto done;
        }
-       last_track = track;
 
-       /* save game data */
-       memcpy(game_save[track & 1], memory + data, length);
+       /* init cpu code */
+       execute_init(MEMORY_SIZE, memory, chipreg, io_read, io_write);
 
-       /* if done with saving */
-       if ((track & 1)) {
-               char filename[256];
-               int gamesave_num = (track - 2) >> 1;
-               int wrote;
-               FILE *fp;
+       /* init disk emulation */
+       disk_init(disk_read, disk_write);
 
-               sprintf(filename, "%s/%s", home_dir, config_gamesave_dir);
-               mkdir(filename, 0777);
-               sprintf(filename + strlen(filename), "/%d.gamesave", gamesave_num);
-               fp = fopen(filename, "w");
-               if (!fp) {
-fail:
-                       fprintf(stderr, "failed to save game to '%s'\n", filename);
-                       return;
-               }
-               printf("Game state saved to '%s'\n", filename);
-               wrote = fwrite(game_save, sizeof(game_save[0]), 2, fp);
-               fclose(fp);
-               if (wrote != 2)
-                       goto fail;
-       }
+       /* load binary */
+       mercenary_load();
+
+       /* patch some stuff */
+       mercenary_patch();
+
+       /* init SDL and OpenGL */
+       rc = init_sdl(argv[0], SCREEN_WIDTH, SCREEN_HEIGHT, SOUND_SAMPLERATE, sdl_sound_chunk, keyboard_sdl, audio_sdl);
+       if (rc < 0)
+               goto done;
+       rc = init_opengl((double_size) ? IMAGE_WIDTH * 2 : IMAGE_WIDTH, (double_size) ? IMAGE_HEIGHT * 2 : IMAGE_HEIGHT);
+       if (rc < 0)
+               goto done;
+       resize_opengl(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+       /* init audio filter */
+       sound_init_filter(SOUND_SAMPLERATE);
+
+       /* start cpu */
+       reset_cpu();
+
+       printf("**********************************\n");
+       printf("* Welcome to Mercenary Reloaded! *\n");
+       printf("**********************************\n\n");
+       printf("Press CTRL + cursor keys to select inventory or pickup/drop item.\n");
+       printf("Press CTRL + f to toggle full screen.\n");
+       printf("Press CTRL + s to toggle rendering speed.\n");
+       printf("Press CTRL + v to toggle video filter.\n");
+       printf("Press CTRL + a to toggle audio filter.\n");
+       printf("Press CTRL + c to exit game.\n\n");
+       printf("Use '--help' as command line option for configuration settings.\n\n");
+
+       /* run game */
+       main_loop();
+
+done:
+       exit_opengl();
+       exit_sdl();
+
+       if (chipreg)
+               free(chipreg);
+       if (memory)
+               free(memory);
+       if (sound_buffer)
+               free(sound_buffer);
+       if (image)
+               free(image);
+
+       return 0;
 }
+