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 +}