src/musashi/example/sim.c

changeset 0
8bf1bf91a36d
     1.1 diff -r 000000000000 -r 8bf1bf91a36d src/musashi/example/sim.c
     1.2 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 +++ b/src/musashi/example/sim.c	Sat Nov 27 01:13:12 2010 +0000
     1.4 @@ -0,0 +1,478 @@
     1.5 +#include <stdio.h>
     1.6 +#include <stdlib.h>
     1.7 +#include <stdarg.h>
     1.8 +#include <time.h>
     1.9 +#include "sim.h"
    1.10 +#include "m68k.h"
    1.11 +
    1.12 +/* Memory-mapped IO ports */
    1.13 +#define INPUT_ADDRESS 0x800000
    1.14 +#define OUTPUT_ADDRESS 0x400000
    1.15 +
    1.16 +/* IRQ connections */
    1.17 +#define IRQ_NMI_DEVICE 7
    1.18 +#define IRQ_INPUT_DEVICE 2
    1.19 +#define IRQ_OUTPUT_DEVICE 1
    1.20 +
    1.21 +/* Time between characters sent to output device (seconds) */
    1.22 +#define OUTPUT_DEVICE_PERIOD 1
    1.23 +
    1.24 +/* ROM and RAM sizes */
    1.25 +#define MAX_ROM 0xfff
    1.26 +#define MAX_RAM 0xff
    1.27 +
    1.28 +
    1.29 +/* Read/write macros */
    1.30 +#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
    1.31 +#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) |			\
    1.32 +							  (BASE)[(ADDR)+1])
    1.33 +#define READ_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) |			\
    1.34 +							  ((BASE)[(ADDR)+1]<<16) |		\
    1.35 +							  ((BASE)[(ADDR)+2]<<8) |		\
    1.36 +							  (BASE)[(ADDR)+3])
    1.37 +
    1.38 +#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)%0xff
    1.39 +#define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff;		\
    1.40 +									(BASE)[(ADDR)+1] = (VAL)&0xff
    1.41 +#define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>24) & 0xff;		\
    1.42 +									(BASE)[(ADDR)+1] = ((VAL)>>16)&0xff;	\
    1.43 +									(BASE)[(ADDR)+2] = ((VAL)>>8)&0xff;		\
    1.44 +									(BASE)[(ADDR)+3] = (VAL)&0xff
    1.45 +
    1.46 +
    1.47 +/* Prototypes */
    1.48 +void exit_error(char* fmt, ...);
    1.49 +int osd_get_char(void);
    1.50 +
    1.51 +unsigned int m68k_read_memory_8(unsigned int address);
    1.52 +unsigned int m68k_read_memory_16(unsigned int address);
    1.53 +unsigned int m68k_read_memory_32(unsigned int address);
    1.54 +void m68k_write_memory_8(unsigned int address, unsigned int value);
    1.55 +void m68k_write_memory_16(unsigned int address, unsigned int value);
    1.56 +void m68k_write_memory_32(unsigned int address, unsigned int value);
    1.57 +void cpu_pulse_reset(void);
    1.58 +void cpu_set_fc(unsigned int fc);
    1.59 +int cpu_irq_ack(int level);
    1.60 +
    1.61 +void nmi_device_reset(void);
    1.62 +void nmi_device_update(void);
    1.63 +int nmi_device_ack(void);
    1.64 +
    1.65 +void input_device_reset(void);
    1.66 +void input_device_update(void);
    1.67 +int input_device_ack(void);
    1.68 +unsigned int input_device_read(void);
    1.69 +void input_device_write(unsigned int value);
    1.70 +
    1.71 +void output_device_reset(void);
    1.72 +void output_device_update(void);
    1.73 +int output_device_ack(void);
    1.74 +unsigned int output_device_read(void);
    1.75 +void output_device_write(unsigned int value);
    1.76 +
    1.77 +void int_controller_set(unsigned int value);
    1.78 +void int_controller_clear(unsigned int value);
    1.79 +
    1.80 +void get_user_input(void);
    1.81 +
    1.82 +
    1.83 +/* Data */
    1.84 +unsigned int g_quit = 0;						/* 1 if we want to quit */
    1.85 +unsigned int g_nmi = 0;							/* 1 if nmi pending */
    1.86 +
    1.87 +int g_input_device_value = -1;					/* Current value in input device */
    1.88 +
    1.89 +unsigned int g_output_device_ready = 0;			/* 1 if output device is ready */
    1.90 +time_t g_output_device_last_output;				/* Time of last char output */
    1.91 +
    1.92 +unsigned int g_int_controller_pending = 0;		/* list of pending interrupts */
    1.93 +unsigned int g_int_controller_highest_int = 0;	/* Highest pending interrupt */
    1.94 +
    1.95 +unsigned char g_rom[MAX_ROM+1];					/* ROM */
    1.96 +unsigned char g_ram[MAX_RAM+1];					/* RAM */
    1.97 +unsigned int g_fc;								/* Current function code from CPU */
    1.98 +
    1.99 +
   1.100 +/* Exit with an error message.  Use printf syntax. */
   1.101 +void exit_error(char* fmt, ...)
   1.102 +{
   1.103 +	va_list args;
   1.104 +	va_start(args, fmt);
   1.105 +	vfprintf(stderr, fmt, args);
   1.106 +	va_end(args);
   1.107 +	fprintf(stderr, "\n");
   1.108 +
   1.109 +	exit(EXIT_FAILURE);
   1.110 +}
   1.111 +
   1.112 +/* OS-dependant code to get a character from the user.
   1.113 + * This function must not block, and must either return an ASCII code or -1.
   1.114 + */
   1.115 +//#include <conio.h>
   1.116 +int osd_get_char(void)
   1.117 +{
   1.118 +	int ch = -1;
   1.119 +/*	if(kbhit())
   1.120 +	{
   1.121 +		while(kbhit())
   1.122 +			ch = getch();
   1.123 +	}
   1.124 +*/	return ch;
   1.125 +}
   1.126 +
   1.127 +
   1.128 +/* Read data from RAM, ROM, or a device */
   1.129 +unsigned int m68k_read_memory_8(unsigned int address)
   1.130 +{
   1.131 +	if(g_fc & 2)	/* Program */
   1.132 +	{
   1.133 +		if(address > MAX_ROM)
   1.134 +			exit_error("Attempted to read byte from ROM address %08x", address);
   1.135 +		return READ_BYTE(g_rom, address);
   1.136 +	}
   1.137 +
   1.138 +	/* Otherwise it's data space */
   1.139 +	switch(address)
   1.140 +	{
   1.141 +		case INPUT_ADDRESS:
   1.142 +			return input_device_read();
   1.143 +		case OUTPUT_ADDRESS:
   1.144 +			return output_device_read();
   1.145 +		default:
   1.146 +			break;
   1.147 +	}
   1.148 +	if(address > MAX_RAM)
   1.149 +		exit_error("Attempted to read byte from RAM address %08x", address);
   1.150 +		return READ_BYTE(g_ram, address);
   1.151 +}
   1.152 +
   1.153 +unsigned int m68k_read_memory_16(unsigned int address)
   1.154 +{
   1.155 +	if(g_fc & 2)	/* Program */
   1.156 +	{
   1.157 +		if(address > MAX_ROM)
   1.158 +			exit_error("Attempted to read word from ROM address %08x", address);
   1.159 +		return READ_WORD(g_rom, address);
   1.160 +	}
   1.161 +
   1.162 +	/* Otherwise it's data space */
   1.163 +	switch(address)
   1.164 +	{
   1.165 +		case INPUT_ADDRESS:
   1.166 +			return input_device_read();
   1.167 +		case OUTPUT_ADDRESS:
   1.168 +			return output_device_read();
   1.169 +		default:
   1.170 +			break;
   1.171 +	}
   1.172 +	if(address > MAX_RAM)
   1.173 +		exit_error("Attempted to read word from RAM address %08x", address);
   1.174 +		return READ_WORD(g_ram, address);
   1.175 +}
   1.176 +
   1.177 +unsigned int m68k_read_memory_32(unsigned int address)
   1.178 +{
   1.179 +	if(g_fc & 2)	/* Program */
   1.180 +	{
   1.181 +		if(address > MAX_ROM)
   1.182 +			exit_error("Attempted to read long from ROM address %08x", address);
   1.183 +		return READ_LONG(g_rom, address);
   1.184 +	}
   1.185 +
   1.186 +	/* Otherwise it's data space */
   1.187 +	switch(address)
   1.188 +	{
   1.189 +		case INPUT_ADDRESS:
   1.190 +			return input_device_read();
   1.191 +		case OUTPUT_ADDRESS:
   1.192 +			return output_device_read();
   1.193 +		default:
   1.194 +			break;
   1.195 +	}
   1.196 +	if(address > MAX_RAM)
   1.197 +		exit_error("Attempted to read long from RAM address %08x", address);
   1.198 +		return READ_LONG(g_ram, address);
   1.199 +}
   1.200 +
   1.201 +
   1.202 +/* Write data to RAM or a device */
   1.203 +void m68k_write_memory_8(unsigned int address, unsigned int value)
   1.204 +{
   1.205 +	if(g_fc & 2)	/* Program */
   1.206 +		exit_error("Attempted to write %02x to ROM address %08x", value&0xff, address);
   1.207 +
   1.208 +	/* Otherwise it's data space */
   1.209 +	switch(address)
   1.210 +	{
   1.211 +		case INPUT_ADDRESS:
   1.212 +			input_device_write(value&0xff);
   1.213 +			return;
   1.214 +		case OUTPUT_ADDRESS:
   1.215 +			output_device_write(value&0xff);
   1.216 +			return;
   1.217 +		default:
   1.218 +			break;
   1.219 +	}
   1.220 +	if(address > MAX_RAM)
   1.221 +		exit_error("Attempted to write %02x to RAM address %08x", value&0xff, address);
   1.222 +	WRITE_BYTE(g_ram, address, value);
   1.223 +}
   1.224 +
   1.225 +void m68k_write_memory_16(unsigned int address, unsigned int value)
   1.226 +{
   1.227 +	if(g_fc & 2)	/* Program */
   1.228 +		exit_error("Attempted to write %04x to ROM address %08x", value&0xffff, address);
   1.229 +
   1.230 +	/* Otherwise it's data space */
   1.231 +	switch(address)
   1.232 +	{
   1.233 +		case INPUT_ADDRESS:
   1.234 +			input_device_write(value&0xffff);
   1.235 +			return;
   1.236 +		case OUTPUT_ADDRESS:
   1.237 +			output_device_write(value&0xffff);
   1.238 +			return;
   1.239 +		default:
   1.240 +			break;
   1.241 +	}
   1.242 +	if(address > MAX_RAM)
   1.243 +		exit_error("Attempted to write %04x to RAM address %08x", value&0xffff, address);
   1.244 +	WRITE_WORD(g_ram, address, value);
   1.245 +}
   1.246 +
   1.247 +void m68k_write_memory_32(unsigned int address, unsigned int value)
   1.248 +{
   1.249 +	if(g_fc & 2)	/* Program */
   1.250 +		exit_error("Attempted to write %08x to ROM address %08x", value, address);
   1.251 +
   1.252 +	/* Otherwise it's data space */
   1.253 +	switch(address)
   1.254 +	{
   1.255 +		case INPUT_ADDRESS:
   1.256 +			input_device_write(value);
   1.257 +			return;
   1.258 +		case OUTPUT_ADDRESS:
   1.259 +			output_device_write(value);
   1.260 +			return;
   1.261 +		default:
   1.262 +			break;
   1.263 +	}
   1.264 +	if(address > MAX_RAM)
   1.265 +		exit_error("Attempted to write %08x to RAM address %08x", value, address);
   1.266 +	WRITE_LONG(g_ram, address, value);
   1.267 +}
   1.268 +
   1.269 +/* Called when the CPU pulses the RESET line */
   1.270 +void cpu_pulse_reset(void)
   1.271 +{
   1.272 +	nmi_device_reset();
   1.273 +	output_device_reset();
   1.274 +	input_device_reset();
   1.275 +}
   1.276 +
   1.277 +/* Called when the CPU changes the function code pins */
   1.278 +void cpu_set_fc(unsigned int fc)
   1.279 +{
   1.280 +	g_fc = fc;
   1.281 +}
   1.282 +
   1.283 +/* Called when the CPU acknowledges an interrupt */
   1.284 +int cpu_irq_ack(int level)
   1.285 +{
   1.286 +	switch(level)
   1.287 +	{
   1.288 +		case IRQ_NMI_DEVICE:
   1.289 +			return nmi_device_ack();
   1.290 +		case IRQ_INPUT_DEVICE:
   1.291 +			return input_device_ack();
   1.292 +		case IRQ_OUTPUT_DEVICE:
   1.293 +			return output_device_ack();
   1.294 +	}
   1.295 +	return M68K_INT_ACK_SPURIOUS;
   1.296 +}
   1.297 +
   1.298 +
   1.299 +
   1.300 +
   1.301 +/* Implementation for the NMI device */
   1.302 +void nmi_device_reset(void)
   1.303 +{
   1.304 +	g_nmi = 0;
   1.305 +}
   1.306 +
   1.307 +void nmi_device_update(void)
   1.308 +{
   1.309 +	if(g_nmi)
   1.310 +	{
   1.311 +		g_nmi = 0;
   1.312 +		int_controller_set(IRQ_NMI_DEVICE);
   1.313 +	}
   1.314 +}
   1.315 +
   1.316 +int nmi_device_ack(void)
   1.317 +{
   1.318 +	printf("\nNMI\n");fflush(stdout);
   1.319 +	int_controller_clear(IRQ_NMI_DEVICE);
   1.320 +	return M68K_INT_ACK_AUTOVECTOR;
   1.321 +}
   1.322 +
   1.323 +
   1.324 +/* Implementation for the input device */
   1.325 +void input_device_reset(void)
   1.326 +{
   1.327 +	g_input_device_value = -1;
   1.328 +	int_controller_clear(IRQ_INPUT_DEVICE);
   1.329 +}
   1.330 +
   1.331 +void input_device_update(void)
   1.332 +{
   1.333 +	if(g_input_device_value >= 0)
   1.334 +		int_controller_set(IRQ_INPUT_DEVICE);
   1.335 +}
   1.336 +
   1.337 +int input_device_ack(void)
   1.338 +{
   1.339 +	return M68K_INT_ACK_AUTOVECTOR;
   1.340 +}
   1.341 +
   1.342 +unsigned int input_device_read(void)
   1.343 +{
   1.344 +	int value = g_input_device_value > 0 ? g_input_device_value : 0;
   1.345 +	int_controller_clear(IRQ_INPUT_DEVICE);
   1.346 +	g_input_device_value = -1;
   1.347 +	return value;
   1.348 +}
   1.349 +
   1.350 +void input_device_write(unsigned int value)
   1.351 +{
   1.352 +}
   1.353 +
   1.354 +
   1.355 +/* Implementation for the output device */
   1.356 +void output_device_reset(void)
   1.357 +{
   1.358 +	g_output_device_last_output = time(NULL);
   1.359 +	g_output_device_ready = 0;
   1.360 +	int_controller_clear(IRQ_OUTPUT_DEVICE);
   1.361 +}
   1.362 +
   1.363 +void output_device_update(void)
   1.364 +{
   1.365 +	if(!g_output_device_ready)
   1.366 +	{
   1.367 +		if((time(NULL) - g_output_device_last_output) >= OUTPUT_DEVICE_PERIOD)
   1.368 +		{
   1.369 +			g_output_device_ready = 1;
   1.370 +			int_controller_set(IRQ_OUTPUT_DEVICE);
   1.371 +		}
   1.372 +	}
   1.373 +}
   1.374 +
   1.375 +int output_device_ack(void)
   1.376 +{
   1.377 +	return M68K_INT_ACK_AUTOVECTOR;
   1.378 +}
   1.379 +
   1.380 +unsigned int output_device_read(void)
   1.381 +{
   1.382 +	int_controller_clear(IRQ_OUTPUT_DEVICE);
   1.383 +	return 0;
   1.384 +}
   1.385 +
   1.386 +void output_device_write(unsigned int value)
   1.387 +{
   1.388 +	char ch;
   1.389 +	if(g_output_device_ready)
   1.390 +	{
   1.391 +		ch = value & 0xff;
   1.392 +		printf("%c", ch);
   1.393 +		g_output_device_last_output = time(NULL);
   1.394 +		g_output_device_ready = 0;
   1.395 +		int_controller_clear(IRQ_OUTPUT_DEVICE);
   1.396 +	}
   1.397 +}
   1.398 +
   1.399 +
   1.400 +/* Implementation for the interrupt controller */
   1.401 +void int_controller_set(unsigned int value)
   1.402 +{
   1.403 +	unsigned int old_pending = g_int_controller_pending;
   1.404 +
   1.405 +	g_int_controller_pending |= (1<<value);
   1.406 +
   1.407 +	if(old_pending != g_int_controller_pending && value > g_int_controller_highest_int)
   1.408 +	{
   1.409 +		g_int_controller_highest_int = value;
   1.410 +		m68k_set_irq(g_int_controller_highest_int);
   1.411 +	}
   1.412 +}
   1.413 +
   1.414 +void int_controller_clear(unsigned int value)
   1.415 +{
   1.416 +	g_int_controller_pending &= ~(1<<value);
   1.417 +
   1.418 +	for(g_int_controller_highest_int = 7;g_int_controller_highest_int > 0;g_int_controller_highest_int--)
   1.419 +		if(g_int_controller_pending & (1<<g_int_controller_highest_int))
   1.420 +			break;
   1.421 +
   1.422 +	m68k_set_irq(g_int_controller_highest_int);
   1.423 +}
   1.424 +
   1.425 +
   1.426 +/* Parse user input and update any devices that need user input */
   1.427 +void get_user_input(void)
   1.428 +{
   1.429 +	static int last_ch = -1;
   1.430 +	int ch = osd_get_char();
   1.431 +
   1.432 +	if(ch >= 0)
   1.433 +	{
   1.434 +		switch(ch)
   1.435 +		{
   1.436 +			case 0x1b:
   1.437 +				g_quit = 1;
   1.438 +				break;
   1.439 +			case '~':
   1.440 +				if(last_ch != ch)
   1.441 +					g_nmi = 1;
   1.442 +				break;
   1.443 +			default:
   1.444 +				g_input_device_value = ch;
   1.445 +		}
   1.446 +	}
   1.447 +	last_ch = ch;
   1.448 +}
   1.449 +
   1.450 +
   1.451 +/* The main loop */
   1.452 +int main(int argc, char* argv[])
   1.453 +{
   1.454 +	FILE* fhandle;
   1.455 +
   1.456 +	if(argc != 2)
   1.457 +		exit_error("Usage: sim <program file>");
   1.458 +
   1.459 +	if((fhandle = fopen(argv[1], "rb")) == NULL)
   1.460 +		exit_error("Unable to open %s", argv[1]);
   1.461 +
   1.462 +	if(fread(g_rom, 1, MAX_ROM+1, fhandle) <= 0)
   1.463 +		exit_error("Error reading %s", argv[1]);
   1.464 +
   1.465 +
   1.466 +	m68k_pulse_reset();
   1.467 +	input_device_reset();
   1.468 +	output_device_reset();
   1.469 +	nmi_device_reset();
   1.470 +
   1.471 +	g_quit = 0;
   1.472 +	while(!g_quit)
   1.473 +	{
   1.474 +		get_user_input();
   1.475 +		/* Note that I am not emulating the correct clock speed! */
   1.476 +		m68k_execute(1000);
   1.477 +		output_device_update();
   1.478 +		input_device_update();
   1.479 +		nmi_device_update();
   1.480 +	}
   1.481 +	return 0;
   1.482 +}