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