src/main.c

Sun, 28 Nov 2010 23:08:06 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 28 Nov 2010 23:08:06 +0000
changeset 16
6773a87e27b1
parent 12
0c5bddf0289e
child 17
138cb2576dbc
permissions
-rw-r--r--

add preliminary main loop

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <stdint.h>
     4 #include <stdbool.h>
     5 #include <malloc.h>
     6 #include <string.h>
     7 #include "musashi/m68k.h"
     8 #include "version.h"
    10 void state_done(void);
    12 void FAIL(char *err)
    13 {
    14 	state_done();
    15 	fprintf(stderr, "ERROR: %s\nExiting...\n", err);
    16 	exit(EXIT_FAILURE);
    17 }
    19 // Maximum size of the Boot PROMs. Must be a binary power of two.
    20 #define ROM_SIZE 32768
    22 struct {
    23 	// Boot PROM can be up to 32Kbytes total size
    24 	uint8_t		rom[ROM_SIZE];
    26 	// Main system RAM
    27 	uint8_t		*ram;
    28 	size_t		ram_size;			// number of RAM bytes allocated
    30 	// GENERAL CONTROL REGISTER
    31 	bool		romlmap;
    32 } state;
    34 int state_init()
    35 {
    36 	// Free RAM if it's allocated
    37 	if (state.ram != NULL)
    38 		free(state.ram);
    40 	// Initialise hardware registers
    41 	state.romlmap = false;
    43 	// Allocate RAM, making sure the user has specified a valid RAM amount first
    44 	// Basically: 512KiB minimum, 4MiB maximum, in increments of 512KiB.
    45 	if ((state.ram_size < 512*1024) || ((state.ram_size % (512*1024)) != 0))
    46 		return -1;
    47 	state.ram = malloc(state.ram_size);
    48 	if (state.ram == NULL)
    49 		return -2;
    51 	// Load ROMs
    52 	FILE *r14c, *r15c;
    53 	r14c = fopen("roms/14c.bin", "rb");
    54 	if (r14c == NULL) FAIL("unable to open roms/14c.bin");
    55 	r15c = fopen("roms/15c.bin", "rb");
    56 	if (r15c == NULL) FAIL("unable to open roms/15c.bin");
    58 	// get ROM file size
    59 	fseek(r14c, 0, SEEK_END);
    60 	size_t romlen = ftell(r14c);
    61 	fseek(r14c, 0, SEEK_SET);
    62 	fseek(r15c, 0, SEEK_END);
    63 	size_t romlen2 = ftell(r15c);
    64 	fseek(r15c, 0, SEEK_SET);
    65 	if (romlen2 != romlen) FAIL("ROMs are not the same size!");
    66 	if ((romlen + romlen2) > ROM_SIZE) FAIL("ROMs are too large to fit in memory!");
    68 	// sanity checks completed; load the ROMs!
    69 	uint8_t *romdat1, *romdat2;
    70 	romdat1 = malloc(romlen);
    71 	romdat2 = malloc(romlen2);
    72 	fread(romdat1, 1, romlen, r15c);
    73 	fread(romdat2, 1, romlen2, r14c);
    75 	// convert the ROM data
    76 	for (size_t i=0; i<(romlen + romlen2); i+=2) {
    77 		state.rom[i+0] = romdat1[i/2];
    78 		state.rom[i+1] = romdat2[i/2];
    79 	}
    81 	// TODO: if ROM buffer not filled, repeat the ROM data we read until it is (wraparound emulation)
    83 	// free the data arrays and close the files
    84 	free(romdat1);
    85 	free(romdat2);
    86 	fclose(r14c);
    87 	fclose(r15c);
    89 	return 0;
    90 }
    92 void state_done()
    93 {
    94 	if (state.ram != NULL)
    95 		free(state.ram);
    96 }
    98 // read m68k memory
    99 uint32_t m68k_read_memory_32(uint32_t address)
   100 {
   101 	uint32_t data = 0xFFFFFFFF;
   103 	printf("RD32 %08X %d", address, state.romlmap);
   105 	// If ROMLMAP is set, force system to access ROM
   106 	if (!state.romlmap)
   107 		address |= 0x800000;
   109 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   110 		// ROM access
   111 		data = (((uint32_t)state.rom[(address + 0) & (ROM_SIZE - 1)] << 24) |
   112 				((uint32_t)state.rom[(address + 1) & (ROM_SIZE - 1)] << 16) |
   113 				((uint32_t)state.rom[(address + 2) & (ROM_SIZE - 1)] << 8)  |
   114 				((uint32_t)state.rom[(address + 3) & (ROM_SIZE - 1)]));
   115 	} else if (address < state.ram_size - 1) {
   116 		// RAM
   117 		data = (((uint32_t)state.ram[address + 0] << 24) |
   118 				((uint32_t)state.ram[address + 1] << 16) |
   119 				((uint32_t)state.ram[address + 2] << 8)  |
   120 				((uint32_t)state.ram[address + 3]));
   121 	}
   123 	printf(" ==> %08X\n", data);
   124 	return data;
   125 }
   127 uint32_t m68k_read_memory_16(uint32_t address)
   128 {
   129 	uint16_t data = 0xFFFF;
   131 	printf("RD16 %08X %d", address, state.romlmap);
   133 	// If ROMLMAP is set, force system to access ROM
   134 	if (!state.romlmap)
   135 		address |= 0x800000;
   137 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   138 		// ROM access
   139 		data = ((state.rom[(address + 0) & (ROM_SIZE - 1)] << 8) |
   140 				(state.rom[(address + 1) & (ROM_SIZE - 1)]));
   141 	} else if (address < state.ram_size - 1) {
   142 		// RAM
   143 		data = ((state.ram[address + 0] << 8) |
   144 				(state.ram[address + 1]));
   145 	}
   147 	printf(" ==> %04X\n", data);
   148 	return data;
   149 }
   151 uint32_t m68k_read_memory_8(uint32_t address)
   152 {
   153 	uint8_t data = 0xFF;
   155 	printf("RD 8 %08X %d ", address, state.romlmap);
   157 	// If ROMLMAP is set, force system to access ROM
   158 	if (!state.romlmap)
   159 		address |= 0x800000;
   161 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   162 		// ROM access
   163 		data = state.rom[(address + 0) & (ROM_SIZE - 1)];
   164 	} else if (address < state.ram_size) {
   165 		// RAM access
   166 		data = state.ram[address + 0];
   167 	}
   169 	printf("==> %02X\n", data);
   170 	return data;
   171 }
   173 // write m68k memory
   174 void m68k_write_memory_32(uint32_t address, uint32_t value)
   175 {
   176 	// If ROMLMAP is set, force system to access ROM
   177 	if (!state.romlmap)
   178 		address |= 0x800000;
   180 	printf("WR32 %08X %d %02X\n", address, state.romlmap, value);
   182 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   183 		// ROM access
   184 		// TODO: bus error here? can't write to rom!
   185 	} else if (address < state.ram_size) {
   186 		// RAM access
   187 		state.ram[address + 0] = (value >> 24) & 0xff;
   188 		state.ram[address + 1] = (value >> 16) & 0xff;
   189 		state.ram[address + 2] = (value >> 8)  & 0xff;
   190 		state.ram[address + 3] =  value        & 0xff;
   191 	} else {
   192 		switch (address) {
   193 			case 0xE43000:	state.romlmap = ((value & 0x8000) == 0x8000);
   194 		}
   195 	}
   196 }
   198 void m68k_write_memory_16(uint32_t address, uint32_t value)
   199 {
   200 	// If ROMLMAP is set, force system to access ROM
   201 	if (!state.romlmap)
   202 		address |= 0x800000;
   204 	printf("WR16 %08X %d %02X\n", address, state.romlmap, value);
   206 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   207 		// ROM access
   208 		// TODO: bus error here? can't write to rom!
   209 	} else if (address < state.ram_size) {
   210 		// RAM access
   211 		state.ram[address + 0] = (value >> 8)  & 0xff;
   212 		state.ram[address + 1] =  value        & 0xff;
   213 	} else {
   214 		switch (address) {
   215 			case 0xE43000:	state.romlmap = ((value & 0x8000) == 0x8000);
   216 		}
   217 	}
   218 }
   220 void m68k_write_memory_8(uint32_t address, uint32_t value)
   221 {
   222 	// If ROMLMAP is set, force system to access ROM
   223 	if (!state.romlmap)
   224 		address |= 0x800000;
   226 	printf("WR 8 %08X %d %02X\n", address, state.romlmap, value);
   228 	if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   229 		// ROM access
   230 		// TODO: bus error here? can't write to rom!
   231 	} else if (address < state.ram_size) {
   232 		state.ram[address] = value & 0xff;
   233 	} else {
   234 		switch (address) {
   235 			case 0xE43000:	state.romlmap = ((value & 0x80) == 0x80);
   236 		}
   237 	}
   238 }
   240 // for the disassembler
   241 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
   242 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
   243 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
   245 int main(void)
   246 {
   247 	// copyright banner
   248 	printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
   249 	printf("Copyright (C) 2010 P. A. Pemberton.\n");
   250 	printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
   251 	printf("Compiler: %s\n", VER_COMPILER);
   252 	printf("CFLAGS: %s\n", VER_CFLAGS);
   253 	printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
   255 	// set up system state
   256 	// 512K of RAM
   257 	state.ram_size = 512*1024;
   258 	state_init();
   260 	// set up musashi
   261 	m68k_set_cpu_type(M68K_CPU_TYPE_68010);
   262 	m68k_pulse_reset();
   264 	char dasm[512];
   265 	m68k_disassemble(dasm, 0x80001a, M68K_CPU_TYPE_68010);
   266 	printf("%s\n", dasm);
   268 	// set up SDL
   270 	// emulation loop!
   271 	// repeat:
   272 	// 		m68k_execute()
   273 	// 		m68k_set_irq() every 60ms
   274 	int32_t dwTimerTickCounter, dwCpuCycles;
   275 	const int32_t CLOCKS_PER_TIMER_TICK = 10e6/60;		//< number of clocks per 60Hz timer tick
   277 	// initialise emulation variables
   278 	dwTimerTickCounter = CLOCKS_PER_TIMER_TICK;
   279 	bool exitEmu = false;
   280 	for (;;) {
   281 		dwCpuCycles = m68k_execute(10e6/60);
   282 		dwTimerTickCounter -= dwCpuCycles;
   284 		// check for timer tick expiry
   285 		if (dwTimerTickCounter <= 0) {
   286 			// TODO: Timer Tick IRQ
   288 		}
   290 		if (exitEmu) break;
   291 	}
   293 	// shut down and exit
   295 	return 0;
   296 }