Mon, 06 Dec 2010 01:43:04 +0000
fix side-select bug in WDC FDC driver, was causing all reads to occur on side0... now the Loader boots!
Loader will boot, but immediately gives up on the floppy drive... Not sure why.
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 }