src/main.c

Wed, 01 Dec 2010 22:15:41 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 01 Dec 2010 22:15:41 +0000
changeset 25
49526038b0fb
parent 24
724d2f6deb37
child 26
fef12817c5e8
permissions
-rw-r--r--

add LED decode [debug]

     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 	// If ROMLMAP is set, force system to access ROM
    27 	if (!state.romlmap)
    28 		address |= 0x800000;
    30 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
    31 		// ROM access
    32 		data = (((uint32_t)state.rom[(address + 0) & (ROM_SIZE - 1)] << 24) |
    33 				((uint32_t)state.rom[(address + 1) & (ROM_SIZE - 1)] << 16) |
    34 				((uint32_t)state.rom[(address + 2) & (ROM_SIZE - 1)] << 8)  |
    35 				((uint32_t)state.rom[(address + 3) & (ROM_SIZE - 1)]));
    36 	} else if (address < state.ram_size - 1) {
    37 		// RAM
    38 		data = (((uint32_t)state.ram[address + 0] << 24) |
    39 				((uint32_t)state.ram[address + 1] << 16) |
    40 				((uint32_t)state.ram[address + 2] << 8)  |
    41 				((uint32_t)state.ram[address + 3]));
    42 	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
    43 		// VRAM
    44 		data = (((uint32_t)state.vram[(address + 0) & 0x7fff] << 24) |
    45 				((uint32_t)state.vram[(address + 1) & 0x7fff] << 16) |
    46 				((uint32_t)state.vram[(address + 2) & 0x7fff] << 8)  |
    47 				((uint32_t)state.vram[(address + 3) & 0x7fff]));
    48 	} else {
    49 		// I/O register -- TODO
    50 		printf("RD32 0x%08X [unknown I/O register]\n", address);
    51 	}
    52 	return data;
    53 }
    55 uint32_t m68k_read_memory_16(uint32_t address)
    56 {
    57 	uint16_t data = 0xFFFF;
    59 	// If ROMLMAP is set, force system to access ROM
    60 	if (!state.romlmap)
    61 		address |= 0x800000;
    63 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
    64 		// ROM access
    65 		data = ((state.rom[(address + 0) & (ROM_SIZE - 1)] << 8) |
    66 				(state.rom[(address + 1) & (ROM_SIZE - 1)]));
    67 	} else if (address < state.ram_size - 1) {
    68 		// RAM
    69 		data = ((state.ram[address + 0] << 8) |
    70 				(state.ram[address + 1]));
    71 	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
    72 		// VRAM
    73 		data = (((uint16_t)state.vram[(address + 0) & 0x7fff] << 8)  |
    74 				((uint16_t)state.vram[(address + 1) & 0x7fff]));
    75 	} else {
    76 		// I/O register -- TODO
    77 		printf("RD16 0x%08X [unknown I/O register]\n", address);
    78 	}
    80 	return data;
    81 }
    83 uint32_t m68k_read_memory_8(uint32_t address)
    84 {
    85 	uint8_t data = 0xFF;
    87 	// If ROMLMAP is set, force system to access ROM
    88 	if (!state.romlmap)
    89 		address |= 0x800000;
    91 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
    92 		// ROM access
    93 		data = state.rom[(address + 0) & (ROM_SIZE - 1)];
    94 	} else if (address < state.ram_size) {
    95 		// RAM access
    96 		data = state.ram[address + 0];
    97 	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
    98 		// VRAM
    99 		data = state.vram[(address + 0) & 0x7fff];
   100 	} else {
   101 		// I/O register -- TODO
   102 		printf("RD08 0x%08X [unknown I/O register]\n", address);
   103 	}
   105 	return data;
   106 }
   108 // write m68k memory
   109 void m68k_write_memory_32(uint32_t address, uint32_t value)
   110 {
   111 	// If ROMLMAP is set, force system to access ROM
   112 	if (!state.romlmap)
   113 		address |= 0x800000;
   115 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   116 		// ROM access
   117 		// TODO: bus error here? can't write to rom!
   118 	} else if (address < state.ram_size) {
   119 		// RAM access
   120 		state.ram[address + 0] = (value >> 24) & 0xff;
   121 		state.ram[address + 1] = (value >> 16) & 0xff;
   122 		state.ram[address + 2] = (value >> 8)  & 0xff;
   123 		state.ram[address + 3] =  value        & 0xff;
   124 	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
   125 		// VRAM access
   126 		state.vram[(address + 0) & 0x7fff] = (value >> 24) & 0xff;
   127 		state.vram[(address + 1) & 0x7fff] = (value >> 16) & 0xff;
   128 		state.vram[(address + 2) & 0x7fff] = (value >> 8)  & 0xff;
   129 		state.vram[(address + 3) & 0x7fff] =  value        & 0xff;
   130 	} else {
   131 		switch (address) {
   132 			case 0xE43000:	state.romlmap = ((value & 0x8000) == 0x8000); break;	// GCR3: ROMLMAP
   133 			default:		printf("WR32 0x%08X ==> 0x%08X\n", address, value); break;
   134 		}
   135 	}
   136 }
   138 void m68k_write_memory_16(uint32_t address, uint32_t value)
   139 {
   140 	// If ROMLMAP is set, force system to access ROM
   141 	if (!state.romlmap)
   142 		address |= 0x800000;
   144 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   145 		// ROM access
   146 		// TODO: bus error here? can't write to rom!
   147 	} else if (address < state.ram_size) {
   148 		// RAM access
   149 		state.ram[address + 0] = (value >> 8)  & 0xff;
   150 		state.ram[address + 1] =  value        & 0xff;
   151 	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
   152 		// VRAM access
   153 		state.vram[(address + 0) & 0x7fff] = (value >> 8) & 0xff;
   154 		state.vram[(address + 1) & 0x7fff] =  value       & 0xff;
   155 	} else {
   156 		switch (address) {
   157 			case 0xE43000:	state.romlmap = ((value & 0x8000) == 0x8000); break;	// GCR3: ROMLMAP
   158 			default:		printf("WR16 0x%08X ==> 0x%04X\n", address, value); break;
   159 		}
   160 		if (address == 0x4A0000) {
   161 			printf("\tLED WRITE: %s %s %s %s\n",
   162 					value & 0x800 ? "-" : "R",
   163 					value & 0x400 ? "-" : "G",
   164 					value & 0x200 ? "-" : "Y",
   165 					value & 0x100 ? "-" : "R"
   166 					);
   167 		}
   168 	}
   169 }
   171 void m68k_write_memory_8(uint32_t address, uint32_t value)
   172 {
   173 	// If ROMLMAP is set, force system to access ROM
   174 	if (!state.romlmap)
   175 		address |= 0x800000;
   177 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   178 		// ROM access
   179 		// TODO: bus error here? can't write to rom!
   180 	} else if (address < state.ram_size) {
   181 		state.ram[address] = value & 0xff;
   182 	} else if ((address >= 0x420000) && (address <= 0x427FFF)) {
   183 		// VRAM access
   184 		state.vram[address & 0x7fff] = value;
   185 	} else {
   186 		switch (address) {
   187 			case 0xE43000:	state.romlmap = ((value & 0x80) == 0x80); break;	// GCR3: ROMLMAP
   188 			default:		printf("WR08 0x%08X ==> 0x%02X\n", address, value); break;
   189 		}
   190 	}
   191 }
   193 // for the disassembler
   194 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
   195 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
   196 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
   198 int main(void)
   199 {
   200 	// copyright banner
   201 	printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
   202 	printf("Copyright (C) 2010 P. A. Pemberton. All rights reserved.\nLicensed under the Apache License Version 2.0.\n");
   203 	printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
   204 	printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
   205 	printf("Compiler: %s\n", VER_COMPILER);
   206 	printf("CFLAGS: %s\n", VER_CFLAGS);
   207 	printf("\n");
   209 	// set up system state
   210 	// 512K of RAM
   211 	state_init(512*1024);
   213 	// set up musashi and reset the CPU
   214 	m68k_set_cpu_type(M68K_CPU_TYPE_68010);
   215 	m68k_pulse_reset();
   216 /*
   217 	size_t i = 0x80001a;
   218 	size_t len;
   219 	do {
   220 		char dasm[512];
   221 		len = m68k_disassemble(dasm, i, M68K_CPU_TYPE_68010);
   222 		printf("%06X: %s\n", i, dasm);
   223 		i += len;
   224 	} while (i < 0x8000ff);
   225 */
   227 	// set up SDL
   228 	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
   229 		printf("Could not initialise SDL: %s.\n", SDL_GetError());
   230 		return -1;
   231 	}
   233 	/***
   234 	 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at
   235 	 * around 60Hz (???), with a 60Hz periodic interrupt.
   236 	 */
   237 	const uint32_t TIMESLOT_FREQUENCY = 240;	// Hz
   238 	const uint32_t MILLISECS_PER_TIMESLOT = 1e3 / TIMESLOT_FREQUENCY;
   239 	const uint32_t CLOCKS_PER_60HZ = (10e6 / 60);
   240 	uint32_t next_timeslot = SDL_GetTicks() + MILLISECS_PER_TIMESLOT;
   241 	uint32_t clock_cycles = 0;
   242 	bool exitEmu = false;
   243 	for (;;) {
   244 		// Run the CPU for however many cycles we need to. CPU core clock is
   245 		// 10MHz, and we're running at 240Hz/timeslot. Thus: 10e6/240 or
   246 		// 41667 cycles per timeslot.
   247 		clock_cycles += m68k_execute(10e6/TIMESLOT_FREQUENCY);
   249 		// TODO: run DMA here
   251 		// Is it time to run the 60Hz periodic interrupt yet?
   252 		if (clock_cycles > CLOCKS_PER_60HZ) {
   253 			// TODO: refresh screen
   254 			// TODO: trigger periodic interrupt (if enabled)
   255 			// decrement clock cycle counter, we've handled the intr.
   256 			clock_cycles -= CLOCKS_PER_60HZ;
   257 		}
   259 		// make sure frame rate is equal to real time
   260 		uint32_t now = SDL_GetTicks();
   261 		if (now < next_timeslot) {
   262 			// timeslot finished early -- eat up some time
   263 			SDL_Delay(next_timeslot - now);
   264 		} else {
   265 			// timeslot finished late -- skip ahead to gain time
   266 			// TODO: if this happens a lot, we should let the user know
   267 			// that their PC might not be fast enough...
   268 			next_timeslot = now;
   269 		}
   270 		// advance to the next timeslot
   271 		next_timeslot += MILLISECS_PER_TIMESLOT;
   273 		// if we've been asked to exit the emulator, then do so.
   274 		if (exitEmu) break;
   275 	}
   277 	// shut down and exit
   278 	SDL_Quit();
   280 	return 0;
   281 }