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