src/main.c

Wed, 01 Dec 2010 21:29:44 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 01 Dec 2010 21:29:44 +0000
changeset 20
bea459bc22a8
parent 18
320dc6206f52
child 21
e31d2ede6c6b
permissions
-rw-r--r--

add main emulation loop with preliminary timing

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <stdint.h>
     4 #include <stdbool.h>
     5 #include <malloc.h>
     6 #include <string.h>
     8 #include "SDL.h"
    10 #include "musashi/m68k.h"
    11 #include "version.h"
    12 #include "state.h"
    14 void FAIL(char *err)
    15 {
    16 	state_done();
    17 	fprintf(stderr, "ERROR: %s\nExiting...\n", err);
    18 	exit(EXIT_FAILURE);
    19 }
    21 // read m68k memory
    22 uint32_t m68k_read_memory_32(uint32_t address)
    23 {
    24 	uint32_t data = 0xFFFFFFFF;
    26 	printf("RD32 %08X %d", address, state.romlmap);
    28 	// If ROMLMAP is set, force system to access ROM
    29 	if (!state.romlmap)
    30 		address |= 0x800000;
    32 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
    33 		// ROM access
    34 		data = (((uint32_t)state.rom[(address + 0) & (ROM_SIZE - 1)] << 24) |
    35 				((uint32_t)state.rom[(address + 1) & (ROM_SIZE - 1)] << 16) |
    36 				((uint32_t)state.rom[(address + 2) & (ROM_SIZE - 1)] << 8)  |
    37 				((uint32_t)state.rom[(address + 3) & (ROM_SIZE - 1)]));
    38 	} else if (address < state.ram_size - 1) {
    39 		// RAM
    40 		data = (((uint32_t)state.ram[address + 0] << 24) |
    41 				((uint32_t)state.ram[address + 1] << 16) |
    42 				((uint32_t)state.ram[address + 2] << 8)  |
    43 				((uint32_t)state.ram[address + 3]));
    44 	}
    46 	printf(" ==> %08X\n", data);
    47 	return data;
    48 }
    50 uint32_t m68k_read_memory_16(uint32_t address)
    51 {
    52 	uint16_t data = 0xFFFF;
    54 	printf("RD16 %08X %d", address, state.romlmap);
    56 	// If ROMLMAP is set, force system to access ROM
    57 	if (!state.romlmap)
    58 		address |= 0x800000;
    60 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
    61 		// ROM access
    62 		data = ((state.rom[(address + 0) & (ROM_SIZE - 1)] << 8) |
    63 				(state.rom[(address + 1) & (ROM_SIZE - 1)]));
    64 	} else if (address < state.ram_size - 1) {
    65 		// RAM
    66 		data = ((state.ram[address + 0] << 8) |
    67 				(state.ram[address + 1]));
    68 	}
    70 	printf(" ==> %04X\n", data);
    71 	return data;
    72 }
    74 uint32_t m68k_read_memory_8(uint32_t address)
    75 {
    76 	uint8_t data = 0xFF;
    78 	printf("RD 8 %08X %d ", address, state.romlmap);
    80 	// If ROMLMAP is set, force system to access ROM
    81 	if (!state.romlmap)
    82 		address |= 0x800000;
    84 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
    85 		// ROM access
    86 		data = state.rom[(address + 0) & (ROM_SIZE - 1)];
    87 	} else if (address < state.ram_size) {
    88 		// RAM access
    89 		data = state.ram[address + 0];
    90 	}
    92 	printf("==> %02X\n", data);
    93 	return data;
    94 }
    96 // write m68k memory
    97 void m68k_write_memory_32(uint32_t address, uint32_t value)
    98 {
    99 	// If ROMLMAP is set, force system to access ROM
   100 	if (!state.romlmap)
   101 		address |= 0x800000;
   103 	printf("WR32 %08X %d %02X\n", address, state.romlmap, value);
   105 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   106 		// ROM access
   107 		// TODO: bus error here? can't write to rom!
   108 	} else if (address < state.ram_size) {
   109 		// RAM access
   110 		state.ram[address + 0] = (value >> 24) & 0xff;
   111 		state.ram[address + 1] = (value >> 16) & 0xff;
   112 		state.ram[address + 2] = (value >> 8)  & 0xff;
   113 		state.ram[address + 3] =  value        & 0xff;
   114 	} else {
   115 		switch (address) {
   116 			case 0xE43000:	state.romlmap = ((value & 0x8000) == 0x8000);
   117 		}
   118 	}
   119 }
   121 void m68k_write_memory_16(uint32_t address, uint32_t value)
   122 {
   123 	// If ROMLMAP is set, force system to access ROM
   124 	if (!state.romlmap)
   125 		address |= 0x800000;
   127 	printf("WR16 %08X %d %02X\n", address, state.romlmap, value);
   129 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   130 		// ROM access
   131 		// TODO: bus error here? can't write to rom!
   132 	} else if (address < state.ram_size) {
   133 		// RAM access
   134 		state.ram[address + 0] = (value >> 8)  & 0xff;
   135 		state.ram[address + 1] =  value        & 0xff;
   136 	} else {
   137 		switch (address) {
   138 			case 0xE43000:	state.romlmap = ((value & 0x8000) == 0x8000);
   139 		}
   140 	}
   141 }
   143 void m68k_write_memory_8(uint32_t address, uint32_t value)
   144 {
   145 	// If ROMLMAP is set, force system to access ROM
   146 	if (!state.romlmap)
   147 		address |= 0x800000;
   149 	printf("WR 8 %08X %d %02X\n", address, state.romlmap, value);
   151 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   152 		// ROM access
   153 		// TODO: bus error here? can't write to rom!
   154 	} else if (address < state.ram_size) {
   155 		state.ram[address] = value & 0xff;
   156 	} else {
   157 		switch (address) {
   158 			case 0xE43000:	state.romlmap = ((value & 0x80) == 0x80);
   159 		}
   160 	}
   161 }
   163 // for the disassembler
   164 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
   165 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
   166 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
   168 int main(void)
   169 {
   170 	// copyright banner
   171 	printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
   172 	printf("Copyright (C) 2010 P. A. Pemberton. All rights reserved.\nLicensed under the Apache License Version 2.0.\n");
   173 	printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
   174 	printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
   175 	printf("Compiler: %s\n", VER_COMPILER);
   176 	printf("CFLAGS: %s\n", VER_CFLAGS);
   177 	printf("\n");
   179 	// set up system state
   180 	// 512K of RAM
   181 	state_init(512*1024);
   183 	// set up musashi and reset the CPU
   184 	m68k_set_cpu_type(M68K_CPU_TYPE_68010);
   185 	m68k_pulse_reset();
   186 /*
   187 	size_t i = 0x80001a;
   188 	size_t len;
   189 	do {
   190 		char dasm[512];
   191 		len = m68k_disassemble(dasm, i, M68K_CPU_TYPE_68010);
   192 		printf("%06X: %s\n", i, dasm);
   193 		i += len;
   194 	} while (i < 0x8000ff);
   195 */
   197 	// set up SDL
   198 	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
   199 		printf("Could not initialise SDL: %s.\n", SDL_GetError());
   200 		return -1;
   201 	}
   203 	/***
   204 	 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at
   205 	 * around 60Hz (???), with a 60Hz periodic interrupt.
   206 	 */
   207 	const uint32_t TIMESLOT_FREQUENCY = 240;	// Hz
   208 	const uint32_t MILLISECS_PER_TIMESLOT = 1e3 / TIMESLOT_FREQUENCY;
   209 	const uint32_t CLOCKS_PER_60HZ = (10e6 / 60);
   210 	uint32_t next_timeslot = SDL_GetTicks() + MILLISECS_PER_TIMESLOT;
   211 	uint32_t clock_cycles = 0;
   212 	bool exitEmu = false;
   213 	for (;;) {
   214 		// Run the CPU for however many cycles we need to. CPU core clock is
   215 		// 10MHz, and we're running at 240Hz/timeslot. Thus: 10e6/240 or
   216 		// 41667 cycles per timeslot.
   217 		clock_cycles += m68k_execute(10e6/TIMESLOT_FREQUENCY);
   219 		// TODO: run DMA here
   221 		// Is it time to run the 60Hz periodic interrupt yet?
   222 		if (clock_cycles > CLOCKS_PER_60HZ) {
   223 			// TODO: refresh screen
   224 			// TODO: trigger periodic interrupt (if enabled)
   225 			// decrement clock cycle counter, we've handled the intr.
   226 			clock_cycles -= CLOCKS_PER_60HZ;
   227 		}
   229 		printf("timeslot\n");
   231 		// make sure frame rate is equal to real time
   232 		uint32_t now = SDL_GetTicks();
   233 		if (now < next_timeslot) {
   234 			// timeslot finished early -- eat up some time
   235 			SDL_Delay(next_timeslot - now);
   236 		} else {
   237 			// timeslot finished late -- skip ahead to gain time
   238 			// TODO: if this happens a lot, we should let the user know
   239 			// that their PC might not be fast enough...
   240 			next_timeslot = now;
   241 		}
   242 		// advance to the next timeslot
   243 		next_timeslot += MILLISECS_PER_TIMESLOT;
   245 		// if we've been asked to exit the emulator, then do so.
   246 		if (exitEmu) break;
   247 	}
   249 	// shut down and exit
   250 	SDL_Quit();
   252 	return 0;
   253 }