src/musashi/example/sim.c

Tue, 15 Nov 2011 10:12:37 +0000

author
Philip Pemberton <philpem@philpem.me.uk>
date
Tue, 15 Nov 2011 10:12:37 +0000
changeset 109
2f8afb9e5baa
parent 0
8bf1bf91a36d
permissions
-rw-r--r--

[musashi] Fix handling of bus errors

Patch-Author: Andrew Warkentin <andreww591!gmail>
Patch-MessageID: <4EC200CE.2020304@gmail.com>

I have fixed the first page fault test failure in FreeBee (the page fault test now hangs rather than errors out, because it is trying to read from the hard drive to test DMA page faults).

There were actually two bugs (the first bug was masking the second one).

First, the ancient version of Musashi that you used is unable to properly resume from bus errors that happen in the middle of certain instructions (some instructions are fetched in stages, with the PC being advanced to each part of the instruction, so basically what happens is the CPU core attempts to read the memory location referenced by the first operand, the bus error occurs, causing the PC to jump to the exception vector, but the faulting instruction is still in the middle of being fetched, so the PC is then advanced past the beginning of the exception handler). I fixed this by delaying the jump to the bus error vector until after the faulting instruction finishes.

The second bug is simpler - you had the UDS and LDS bits in BSR0 inverted (they are supposed to be active low).

     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 }