src/musashi/example/sim.c

Sat, 19 Apr 2014 02:19:39 -0600

author
andrew@localhost
date
Sat, 19 Apr 2014 02:19:39 -0600
changeset 152
d61e13d6e2a5
parent 0
8bf1bf91a36d
permissions
-rw-r--r--

fixed timing on OSes that set a minimum time for sleeps (previously the main loop code assumed no minimum sleep time; the new version uses longer sleeps less frequently)

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <stdarg.h>
     4 #include <time.h>
     5 #include "sim.h"
     6 #include "m68k.h"
     8 /* Memory-mapped IO ports */
     9 #define INPUT_ADDRESS 0x800000
    10 #define OUTPUT_ADDRESS 0x400000
    12 /* IRQ connections */
    13 #define IRQ_NMI_DEVICE 7
    14 #define IRQ_INPUT_DEVICE 2
    15 #define IRQ_OUTPUT_DEVICE 1
    17 /* Time between characters sent to output device (seconds) */
    18 #define OUTPUT_DEVICE_PERIOD 1
    20 /* ROM and RAM sizes */
    21 #define MAX_ROM 0xfff
    22 #define MAX_RAM 0xff
    25 /* Read/write macros */
    26 #define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
    27 #define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) |			\
    28 							  (BASE)[(ADDR)+1])
    29 #define READ_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) |			\
    30 							  ((BASE)[(ADDR)+1]<<16) |		\
    31 							  ((BASE)[(ADDR)+2]<<8) |		\
    32 							  (BASE)[(ADDR)+3])
    34 #define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)%0xff
    35 #define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff;		\
    36 									(BASE)[(ADDR)+1] = (VAL)&0xff
    37 #define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>24) & 0xff;		\
    38 									(BASE)[(ADDR)+1] = ((VAL)>>16)&0xff;	\
    39 									(BASE)[(ADDR)+2] = ((VAL)>>8)&0xff;		\
    40 									(BASE)[(ADDR)+3] = (VAL)&0xff
    43 /* Prototypes */
    44 void exit_error(char* fmt, ...);
    45 int osd_get_char(void);
    47 unsigned int m68k_read_memory_8(unsigned int address);
    48 unsigned int m68k_read_memory_16(unsigned int address);
    49 unsigned int m68k_read_memory_32(unsigned int address);
    50 void m68k_write_memory_8(unsigned int address, unsigned int value);
    51 void m68k_write_memory_16(unsigned int address, unsigned int value);
    52 void m68k_write_memory_32(unsigned int address, unsigned int value);
    53 void cpu_pulse_reset(void);
    54 void cpu_set_fc(unsigned int fc);
    55 int cpu_irq_ack(int level);
    57 void nmi_device_reset(void);
    58 void nmi_device_update(void);
    59 int nmi_device_ack(void);
    61 void input_device_reset(void);
    62 void input_device_update(void);
    63 int input_device_ack(void);
    64 unsigned int input_device_read(void);
    65 void input_device_write(unsigned int value);
    67 void output_device_reset(void);
    68 void output_device_update(void);
    69 int output_device_ack(void);
    70 unsigned int output_device_read(void);
    71 void output_device_write(unsigned int value);
    73 void int_controller_set(unsigned int value);
    74 void int_controller_clear(unsigned int value);
    76 void get_user_input(void);
    79 /* Data */
    80 unsigned int g_quit = 0;						/* 1 if we want to quit */
    81 unsigned int g_nmi = 0;							/* 1 if nmi pending */
    83 int g_input_device_value = -1;					/* Current value in input device */
    85 unsigned int g_output_device_ready = 0;			/* 1 if output device is ready */
    86 time_t g_output_device_last_output;				/* Time of last char output */
    88 unsigned int g_int_controller_pending = 0;		/* list of pending interrupts */
    89 unsigned int g_int_controller_highest_int = 0;	/* Highest pending interrupt */
    91 unsigned char g_rom[MAX_ROM+1];					/* ROM */
    92 unsigned char g_ram[MAX_RAM+1];					/* RAM */
    93 unsigned int g_fc;								/* Current function code from CPU */
    96 /* Exit with an error message.  Use printf syntax. */
    97 void exit_error(char* fmt, ...)
    98 {
    99 	va_list args;
   100 	va_start(args, fmt);
   101 	vfprintf(stderr, fmt, args);
   102 	va_end(args);
   103 	fprintf(stderr, "\n");
   105 	exit(EXIT_FAILURE);
   106 }
   108 /* OS-dependant code to get a character from the user.
   109  * This function must not block, and must either return an ASCII code or -1.
   110  */
   111 //#include <conio.h>
   112 int osd_get_char(void)
   113 {
   114 	int ch = -1;
   115 /*	if(kbhit())
   116 	{
   117 		while(kbhit())
   118 			ch = getch();
   119 	}
   120 */	return ch;
   121 }
   124 /* Read data from RAM, ROM, or a device */
   125 unsigned int m68k_read_memory_8(unsigned int address)
   126 {
   127 	if(g_fc & 2)	/* Program */
   128 	{
   129 		if(address > MAX_ROM)
   130 			exit_error("Attempted to read byte from ROM address %08x", address);
   131 		return READ_BYTE(g_rom, address);
   132 	}
   134 	/* Otherwise it's data space */
   135 	switch(address)
   136 	{
   137 		case INPUT_ADDRESS:
   138 			return input_device_read();
   139 		case OUTPUT_ADDRESS:
   140 			return output_device_read();
   141 		default:
   142 			break;
   143 	}
   144 	if(address > MAX_RAM)
   145 		exit_error("Attempted to read byte from RAM address %08x", address);
   146 		return READ_BYTE(g_ram, address);
   147 }
   149 unsigned int m68k_read_memory_16(unsigned int address)
   150 {
   151 	if(g_fc & 2)	/* Program */
   152 	{
   153 		if(address > MAX_ROM)
   154 			exit_error("Attempted to read word from ROM address %08x", address);
   155 		return READ_WORD(g_rom, address);
   156 	}
   158 	/* Otherwise it's data space */
   159 	switch(address)
   160 	{
   161 		case INPUT_ADDRESS:
   162 			return input_device_read();
   163 		case OUTPUT_ADDRESS:
   164 			return output_device_read();
   165 		default:
   166 			break;
   167 	}
   168 	if(address > MAX_RAM)
   169 		exit_error("Attempted to read word from RAM address %08x", address);
   170 		return READ_WORD(g_ram, address);
   171 }
   173 unsigned int m68k_read_memory_32(unsigned int address)
   174 {
   175 	if(g_fc & 2)	/* Program */
   176 	{
   177 		if(address > MAX_ROM)
   178 			exit_error("Attempted to read long from ROM address %08x", address);
   179 		return READ_LONG(g_rom, address);
   180 	}
   182 	/* Otherwise it's data space */
   183 	switch(address)
   184 	{
   185 		case INPUT_ADDRESS:
   186 			return input_device_read();
   187 		case OUTPUT_ADDRESS:
   188 			return output_device_read();
   189 		default:
   190 			break;
   191 	}
   192 	if(address > MAX_RAM)
   193 		exit_error("Attempted to read long from RAM address %08x", address);
   194 		return READ_LONG(g_ram, address);
   195 }
   198 /* Write data to RAM or a device */
   199 void m68k_write_memory_8(unsigned int address, unsigned int value)
   200 {
   201 	if(g_fc & 2)	/* Program */
   202 		exit_error("Attempted to write %02x to ROM address %08x", value&0xff, address);
   204 	/* Otherwise it's data space */
   205 	switch(address)
   206 	{
   207 		case INPUT_ADDRESS:
   208 			input_device_write(value&0xff);
   209 			return;
   210 		case OUTPUT_ADDRESS:
   211 			output_device_write(value&0xff);
   212 			return;
   213 		default:
   214 			break;
   215 	}
   216 	if(address > MAX_RAM)
   217 		exit_error("Attempted to write %02x to RAM address %08x", value&0xff, address);
   218 	WRITE_BYTE(g_ram, address, value);
   219 }
   221 void m68k_write_memory_16(unsigned int address, unsigned int value)
   222 {
   223 	if(g_fc & 2)	/* Program */
   224 		exit_error("Attempted to write %04x to ROM address %08x", value&0xffff, address);
   226 	/* Otherwise it's data space */
   227 	switch(address)
   228 	{
   229 		case INPUT_ADDRESS:
   230 			input_device_write(value&0xffff);
   231 			return;
   232 		case OUTPUT_ADDRESS:
   233 			output_device_write(value&0xffff);
   234 			return;
   235 		default:
   236 			break;
   237 	}
   238 	if(address > MAX_RAM)
   239 		exit_error("Attempted to write %04x to RAM address %08x", value&0xffff, address);
   240 	WRITE_WORD(g_ram, address, value);
   241 }
   243 void m68k_write_memory_32(unsigned int address, unsigned int value)
   244 {
   245 	if(g_fc & 2)	/* Program */
   246 		exit_error("Attempted to write %08x to ROM address %08x", value, address);
   248 	/* Otherwise it's data space */
   249 	switch(address)
   250 	{
   251 		case INPUT_ADDRESS:
   252 			input_device_write(value);
   253 			return;
   254 		case OUTPUT_ADDRESS:
   255 			output_device_write(value);
   256 			return;
   257 		default:
   258 			break;
   259 	}
   260 	if(address > MAX_RAM)
   261 		exit_error("Attempted to write %08x to RAM address %08x", value, address);
   262 	WRITE_LONG(g_ram, address, value);
   263 }
   265 /* Called when the CPU pulses the RESET line */
   266 void cpu_pulse_reset(void)
   267 {
   268 	nmi_device_reset();
   269 	output_device_reset();
   270 	input_device_reset();
   271 }
   273 /* Called when the CPU changes the function code pins */
   274 void cpu_set_fc(unsigned int fc)
   275 {
   276 	g_fc = fc;
   277 }
   279 /* Called when the CPU acknowledges an interrupt */
   280 int cpu_irq_ack(int level)
   281 {
   282 	switch(level)
   283 	{
   284 		case IRQ_NMI_DEVICE:
   285 			return nmi_device_ack();
   286 		case IRQ_INPUT_DEVICE:
   287 			return input_device_ack();
   288 		case IRQ_OUTPUT_DEVICE:
   289 			return output_device_ack();
   290 	}
   291 	return M68K_INT_ACK_SPURIOUS;
   292 }
   297 /* Implementation for the NMI device */
   298 void nmi_device_reset(void)
   299 {
   300 	g_nmi = 0;
   301 }
   303 void nmi_device_update(void)
   304 {
   305 	if(g_nmi)
   306 	{
   307 		g_nmi = 0;
   308 		int_controller_set(IRQ_NMI_DEVICE);
   309 	}
   310 }
   312 int nmi_device_ack(void)
   313 {
   314 	printf("\nNMI\n");fflush(stdout);
   315 	int_controller_clear(IRQ_NMI_DEVICE);
   316 	return M68K_INT_ACK_AUTOVECTOR;
   317 }
   320 /* Implementation for the input device */
   321 void input_device_reset(void)
   322 {
   323 	g_input_device_value = -1;
   324 	int_controller_clear(IRQ_INPUT_DEVICE);
   325 }
   327 void input_device_update(void)
   328 {
   329 	if(g_input_device_value >= 0)
   330 		int_controller_set(IRQ_INPUT_DEVICE);
   331 }
   333 int input_device_ack(void)
   334 {
   335 	return M68K_INT_ACK_AUTOVECTOR;
   336 }
   338 unsigned int input_device_read(void)
   339 {
   340 	int value = g_input_device_value > 0 ? g_input_device_value : 0;
   341 	int_controller_clear(IRQ_INPUT_DEVICE);
   342 	g_input_device_value = -1;
   343 	return value;
   344 }
   346 void input_device_write(unsigned int value)
   347 {
   348 }
   351 /* Implementation for the output device */
   352 void output_device_reset(void)
   353 {
   354 	g_output_device_last_output = time(NULL);
   355 	g_output_device_ready = 0;
   356 	int_controller_clear(IRQ_OUTPUT_DEVICE);
   357 }
   359 void output_device_update(void)
   360 {
   361 	if(!g_output_device_ready)
   362 	{
   363 		if((time(NULL) - g_output_device_last_output) >= OUTPUT_DEVICE_PERIOD)
   364 		{
   365 			g_output_device_ready = 1;
   366 			int_controller_set(IRQ_OUTPUT_DEVICE);
   367 		}
   368 	}
   369 }
   371 int output_device_ack(void)
   372 {
   373 	return M68K_INT_ACK_AUTOVECTOR;
   374 }
   376 unsigned int output_device_read(void)
   377 {
   378 	int_controller_clear(IRQ_OUTPUT_DEVICE);
   379 	return 0;
   380 }
   382 void output_device_write(unsigned int value)
   383 {
   384 	char ch;
   385 	if(g_output_device_ready)
   386 	{
   387 		ch = value & 0xff;
   388 		printf("%c", ch);
   389 		g_output_device_last_output = time(NULL);
   390 		g_output_device_ready = 0;
   391 		int_controller_clear(IRQ_OUTPUT_DEVICE);
   392 	}
   393 }
   396 /* Implementation for the interrupt controller */
   397 void int_controller_set(unsigned int value)
   398 {
   399 	unsigned int old_pending = g_int_controller_pending;
   401 	g_int_controller_pending |= (1<<value);
   403 	if(old_pending != g_int_controller_pending && value > g_int_controller_highest_int)
   404 	{
   405 		g_int_controller_highest_int = value;
   406 		m68k_set_irq(g_int_controller_highest_int);
   407 	}
   408 }
   410 void int_controller_clear(unsigned int value)
   411 {
   412 	g_int_controller_pending &= ~(1<<value);
   414 	for(g_int_controller_highest_int = 7;g_int_controller_highest_int > 0;g_int_controller_highest_int--)
   415 		if(g_int_controller_pending & (1<<g_int_controller_highest_int))
   416 			break;
   418 	m68k_set_irq(g_int_controller_highest_int);
   419 }
   422 /* Parse user input and update any devices that need user input */
   423 void get_user_input(void)
   424 {
   425 	static int last_ch = -1;
   426 	int ch = osd_get_char();
   428 	if(ch >= 0)
   429 	{
   430 		switch(ch)
   431 		{
   432 			case 0x1b:
   433 				g_quit = 1;
   434 				break;
   435 			case '~':
   436 				if(last_ch != ch)
   437 					g_nmi = 1;
   438 				break;
   439 			default:
   440 				g_input_device_value = ch;
   441 		}
   442 	}
   443 	last_ch = ch;
   444 }
   447 /* The main loop */
   448 int main(int argc, char* argv[])
   449 {
   450 	FILE* fhandle;
   452 	if(argc != 2)
   453 		exit_error("Usage: sim <program file>");
   455 	if((fhandle = fopen(argv[1], "rb")) == NULL)
   456 		exit_error("Unable to open %s", argv[1]);
   458 	if(fread(g_rom, 1, MAX_ROM+1, fhandle) <= 0)
   459 		exit_error("Error reading %s", argv[1]);
   462 	m68k_pulse_reset();
   463 	input_device_reset();
   464 	output_device_reset();
   465 	nmi_device_reset();
   467 	g_quit = 0;
   468 	while(!g_quit)
   469 	{
   470 		get_user_input();
   471 		/* Note that I am not emulating the correct clock speed! */
   472 		m68k_execute(1000);
   473 		output_device_update();
   474 		input_device_update();
   475 		nmi_device_update();
   476 	}
   477 	return 0;
   478 }