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