set up ROM loader and state storage, add basic emulator core

Sun, 28 Nov 2010 19:53:53 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Sun, 28 Nov 2010 19:53:53 +0000
changeset 7
7b98c7665aae
parent 6
5dc2f3565377
child 8
e2dcbabc7e1c

set up ROM loader and state storage, add basic emulator core

src/main.c file | annotate | diff | revisions
     1.1 --- a/src/main.c	Sun Nov 28 19:53:14 2010 +0000
     1.2 +++ b/src/main.c	Sun Nov 28 19:53:53 2010 +0000
     1.3 @@ -1,45 +1,253 @@
     1.4  #include <stdio.h>
     1.5 +#include <stdlib.h>
     1.6  #include <stdint.h>
     1.7 +#include <stdbool.h>
     1.8 +#include <malloc.h>
     1.9 +#include <string.h>
    1.10  #include "musashi/m68k.h"
    1.11 +#include "version.h"
    1.12 +
    1.13 +#define ROM_SIZE (32768/4)
    1.14 +
    1.15 +void state_done(void);
    1.16 +
    1.17 +void FAIL(char *err)
    1.18 +{
    1.19 +	state_done();
    1.20 +	fprintf(stderr, "ERROR: %s\nExiting...\n", err);
    1.21 +	exit(EXIT_FAILURE);
    1.22 +}
    1.23 +
    1.24 +
    1.25 +struct {
    1.26 +	// Boot PROM can be up to 32Kbytes total size
    1.27 +	uint32_t	rom[ROM_SIZE];
    1.28 +
    1.29 +	// Main system RAM
    1.30 +	uint32_t	*ram;
    1.31 +	size_t		ram_size;			// number of RAM bytes allocated
    1.32 +	uint32_t	ram_addr_mask;		// address mask
    1.33 +
    1.34 +	// GENERAL CONTROL REGISTER
    1.35 +	bool		romlmap;
    1.36 +} state;
    1.37 +
    1.38 +int state_init()
    1.39 +{
    1.40 +	// Free RAM if it's allocated
    1.41 +	if (state.ram != NULL)
    1.42 +		free(state.ram);
    1.43 +
    1.44 +	// Initialise hardware registers
    1.45 +	state.romlmap = false;
    1.46 +
    1.47 +	// Allocate RAM
    1.48 +	// TODO: make sure ram size selection is valid!
    1.49 +	state.ram = malloc(state.ram_size);
    1.50 +	if (state.ram == NULL)
    1.51 +		return -1;
    1.52 +	state.ram_addr_mask = state.ram_size - 1;
    1.53  
    1.54 -// m68k memory
    1.55 -//uint32_t rom[32768/4];
    1.56 -uint32_t ram[512*1024/4];
    1.57 +	// Load ROMs
    1.58 +	FILE *r14c, *r15c;
    1.59 +	r14c = fopen("roms/14c.bin", "rb");
    1.60 +	if (r14c == NULL) FAIL("unable to open roms/14c.bin");
    1.61 +	r15c = fopen("roms/15c.bin", "rb");
    1.62 +	if (r15c == NULL) FAIL("unable to open roms/15c.bin");
    1.63 +
    1.64 +	// get ROM file size
    1.65 +	fseek(r14c, 0, SEEK_END);
    1.66 +	size_t romlen = ftell(r14c);
    1.67 +	fseek(r14c, 0, SEEK_SET);
    1.68 +	fseek(r15c, 0, SEEK_END);
    1.69 +	size_t romlen2 = ftell(r15c);
    1.70 +	fseek(r15c, 0, SEEK_SET);
    1.71 +	if (romlen2 != romlen) FAIL("ROMs are not the same size!");
    1.72 +	if ((romlen / 4) > (ROM_SIZE / 2)) FAIL("ROM 14C is too big!");
    1.73 +	if ((romlen2 / 4) > (ROM_SIZE / 2)) FAIL("ROM 15C is too big!");
    1.74 +
    1.75 +	// sanity checks completed; load the ROMs!
    1.76 +	uint8_t *romdat1, *romdat2;
    1.77 +	romdat1 = malloc(romlen);
    1.78 +	romdat2 = malloc(romlen2);
    1.79 +	fread(romdat1, 1, romlen, r15c);
    1.80 +	fread(romdat2, 1, romlen2, r14c);
    1.81 +
    1.82 +	// convert the ROM data
    1.83 +	for (size_t i=0; i<romlen; i+=2) {
    1.84 +		state.rom[i/2] = (
    1.85 +				(romdat1[i+0] << 24) |
    1.86 +				(romdat2[i+0] << 16) |
    1.87 +				(romdat1[i+1] << 8)  |
    1.88 +				(romdat2[i+1]));
    1.89 +	}
    1.90 +
    1.91 +	for (int i=0; i<8; i++)
    1.92 +		printf("%02X %02X ", romdat1[i], romdat2[i]);
    1.93 +	printf("\n%08X %08X\n", state.rom[0], state.rom[1]);
    1.94 +
    1.95 +	// free the data arrays and close the files
    1.96 +	free(romdat1);
    1.97 +	free(romdat2);
    1.98 +	fclose(r14c);
    1.99 +	fclose(r15c);
   1.100 +
   1.101 +	return 0;
   1.102 +}
   1.103 +
   1.104 +void state_done()
   1.105 +{
   1.106 +	if (state.ram != NULL)
   1.107 +		free(state.ram);
   1.108 +}
   1.109  
   1.110  // read m68k memory
   1.111 +// TODO: refactor musashi to use stdint, and properly sized integers!
   1.112 +// TODO: find a way to make musashi use function pointers instead of hard coded callbacks, maybe use a context struct too
   1.113  uint32_t m68k_read_memory_32(uint32_t address)
   1.114  {
   1.115 -	return ram[address];
   1.116 +	// If ROMLMAP is set, force system to access ROM
   1.117 +	if (!state.romlmap)
   1.118 +		address |= 0x800000;
   1.119 +
   1.120 +	if (address >= 0xC00000) {
   1.121 +		// I/O Registers B
   1.122 +		// TODO
   1.123 +	} else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.124 +		// ROM access
   1.125 +		printf("%08X\n", state.rom[(address & (ROM_SIZE-1)) / 4]);
   1.126 +		return state.rom[(address & (ROM_SIZE-1)) / 4];
   1.127 +	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   1.128 +		// I/O Registers A
   1.129 +		// TODO
   1.130 +	} else if (address <= 0x3FFFFF) {
   1.131 +		// RAM
   1.132 +		return state.ram[(address & state.ram_addr_mask) / 4];
   1.133 +	}
   1.134 +	return 0xffffffff;
   1.135  }
   1.136  
   1.137  uint32_t m68k_read_memory_16(uint32_t address)
   1.138  {
   1.139 -	return ram[address] & 0xFFFF;
   1.140 +	if (address & 2) {
   1.141 +		return m68k_read_memory_32(address) & 0xFFFF;
   1.142 +	} else {
   1.143 +		return (m68k_read_memory_32(address) >> 16) & 0xFFFF;
   1.144 +	}
   1.145  }
   1.146  
   1.147  uint32_t m68k_read_memory_8(uint32_t address)
   1.148  {
   1.149 -	return ram[address] & 0xFF;
   1.150 +	// If ROMLMAP is set, force system to access ROM
   1.151 +	if (!state.romlmap)
   1.152 +		address |= 0x800000;
   1.153 +
   1.154 +	switch (address & 3) {
   1.155 +		case 3:		return m68k_read_memory_32(address)			& 0xFF;
   1.156 +		case 2:		return (m68k_read_memory_32(address) >> 8)	& 0xFF;
   1.157 +		case 1:		return (m68k_read_memory_32(address) >> 16)	& 0xFF;
   1.158 +		case 0:		return (m68k_read_memory_32(address) >> 24)	& 0xFF;
   1.159 +	}
   1.160 +	return 0xffffffff;
   1.161  }
   1.162  
   1.163  // write m68k memory
   1.164  void m68k_write_memory_32(uint32_t address, uint32_t value)
   1.165  {
   1.166 -	ram[address] = value;
   1.167 +	// If ROMLMAP is set, force system to access ROM
   1.168 +	if (!state.romlmap)
   1.169 +		address |= 0x800000;
   1.170 +
   1.171 +	if (address >= 0xC00000) {
   1.172 +		// I/O Registers B
   1.173 +		// TODO
   1.174 +	} else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.175 +		// ROM access
   1.176 +		// TODO: bus error here? can't write to rom!
   1.177 +	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   1.178 +		// I/O Registers A
   1.179 +		// TODO
   1.180 +	} else if (address <= 0x3FFFFF) {
   1.181 +		// RAM
   1.182 +		state.ram[(address & state.ram_addr_mask) / 4] = value;
   1.183 +	}
   1.184  }
   1.185  
   1.186  void m68k_write_memory_16(uint32_t address, uint32_t value)
   1.187  {
   1.188 -	ram[address] = (ram[address] & 0xFFFF0000) | (value & 0xFFFF);
   1.189 +	// If ROMLMAP is set, force system to access ROM
   1.190 +	if (!state.romlmap)
   1.191 +		address |= 0x800000;
   1.192 +
   1.193 +	if (address >= 0xC00000) {
   1.194 +		// I/O Registers B
   1.195 +		// TODO
   1.196 +	} else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.197 +		// ROM access
   1.198 +		// TODO: bus error here? can't write to rom!
   1.199 +	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   1.200 +		// I/O Registers A
   1.201 +		// TODO
   1.202 +	} else if (address <= 0x3FFFFF) {
   1.203 +		// RAM
   1.204 +		if (address & 2)
   1.205 +			state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFFFF0000) | (value & 0xFFFF);
   1.206 +		else
   1.207 +			state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0x0000FFFF) | ((value & 0xFFFF) << 16);
   1.208 +	}
   1.209  }
   1.210  
   1.211  void m68k_write_memory_8(uint32_t address, uint32_t value)
   1.212  {
   1.213 -	ram[address] = (ram[address] & 0xFFFFFF00) | (value & 0xFF);
   1.214 +	// If ROMLMAP is set, force system to access ROM
   1.215 +	if (!state.romlmap)
   1.216 +		address |= 0x800000;
   1.217 +
   1.218 +	if (address >= 0xC00000) {
   1.219 +		// I/O Registers B
   1.220 +		// TODO
   1.221 +	} else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
   1.222 +		// ROM access
   1.223 +		// TODO: bus error here? can't write to rom!
   1.224 +	} else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
   1.225 +		// I/O Registers A
   1.226 +		// TODO
   1.227 +	} else if (address <= 0x3FFFFF) {
   1.228 +		// RAM
   1.229 +		switch (address & 3) {
   1.230 +			case 3:		state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFFFFFF00) | (value & 0xFF);
   1.231 +			case 2:		state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFFFF00FF) | ((value & 0xFF) << 8);
   1.232 +			case 1:		state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFF00FFFF) | ((value & 0xFF) << 16);
   1.233 +			case 0:		state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0x00FFFFFF) | ((value & 0xFF) << 24);
   1.234 +		}
   1.235 +	}
   1.236  }
   1.237  
   1.238 -
   1.239  int main(void)
   1.240  {
   1.241 +	// copyright banner
   1.242 +	printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator\n");
   1.243 +	printf("Copyright (C) 2010 P. A. Pemberton.\n");
   1.244 +	printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
   1.245 +
   1.246 +	// set up system state
   1.247 +	// 512K of RAM
   1.248 +	state.ram_size = 512*1024;
   1.249 +	state_init();
   1.250 +
   1.251 +	// set up musashi
   1.252 +	m68k_set_cpu_type(M68K_CPU_TYPE_68010);
   1.253 +	m68k_pulse_reset();
   1.254 +
   1.255 +	// set up SDL
   1.256 +
   1.257 +	// emulation loop!
   1.258 +	// repeat:
   1.259 +	// 		m68k_execute()
   1.260 +	// 		m68k_set_irq() every 60ms
   1.261 +	m68k_execute(100000);
   1.262 +
   1.263 +	// shut down and exit
   1.264 +
   1.265  	return 0;
   1.266  }