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)
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));
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];
{
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)|
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;
}
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;
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;
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();
}
}
-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:
}
}
-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;
}
+