]> git.sesse.net Git - pistorm/blob - emulator.c
Fix A4000 Gayle
[pistorm] / emulator.c
1 #include <assert.h>
2 #include <dirent.h>
3 #include <endian.h>
4 #include <fcntl.h>
5 #include <pthread.h>
6 #include <sched.h>
7 #include <signal.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 #include <sys/ioctl.h>
17 #include "m68k.h"
18 #include "main.h"
19 #include "platforms/platforms.h"
20 #include "input/input.h"
21
22 #include "platforms/amiga/Gayle.h"
23 #include "platforms/amiga/gayle-ide/ide.h"
24 #include "platforms/amiga/amiga-registers.h"
25 #include "platforms/amiga/rtg/rtg.h"
26 #include "gpio/gpio.h"
27
28 unsigned char read_ranges;
29 unsigned int read_addr[8];
30 unsigned int read_upper[8];
31 unsigned char *read_data[8];
32 unsigned char write_ranges;
33 unsigned int write_addr[8];
34 unsigned int write_upper[8];
35 unsigned char *write_data[8];
36
37 int kb_hook_enabled = 0;
38 int mouse_hook_enabled = 0;
39 int cpu_emulation_running = 1;
40
41 char mouse_dx = 0, mouse_dy = 0;
42 char mouse_buttons = 0;
43
44 extern volatile unsigned int *gpio;
45 extern volatile uint16_t srdata;
46 extern uint8_t realtime_graphics_debug;
47 uint8_t realtime_disassembly;
48
49 char disasm_buf[4096];
50
51 #define KICKBASE 0xF80000
52 #define KICKSIZE 0x7FFFF
53
54 int mem_fd, mouse_fd = -1, keyboard_fd = -1;
55 int mem_fd_gpclk;
56 int gayle_emulation_enabled = 1;
57 int irq;
58 int gayleirq;
59
60 void *iplThread(void *args) {
61   printf("IPL thread running\n");
62
63   while (1) {
64     if (!gpio_get_irq()) {
65       irq = 1;
66       m68k_end_timeslice();
67     }
68     else
69       irq = 0;
70
71     if (gayle_emulation_enabled) {
72       if (((gayle_int & 0x80) || gayle_a4k_int) && get_ide(0)->drive->intrq) {
73         get_ide(0)->drive->intrq = 0;
74         gayleirq = 1;
75         m68k_end_timeslice();
76       }
77       else
78         gayleirq = 0;
79     }
80     usleep(0);
81   }
82   return args;
83 }
84
85
86 // Configurable emulator options
87 unsigned int cpu_type = M68K_CPU_TYPE_68000;
88 unsigned int loop_cycles = 300;
89 struct emulator_config *cfg = NULL;
90 char keyboard_file[256] = "/dev/input/event1";
91
92 //unsigned char g_kick[524288];
93 //unsigned char g_ram[FASTSIZE + 1]; /* RAM */
94 int ovl;
95 static volatile unsigned char maprom;
96
97 void sigint_handler(int sig_num) {
98   //if (sig_num) { }
99   //cpu_emulation_running = 0;
100
101   //return;
102   printf("Received sigint %d, exiting.\n", sig_num);
103   if (mouse_fd != -1)
104     close(mouse_fd);
105   if (mem_fd)
106     close(mem_fd);
107
108   if (cfg->platform->shutdown) {
109     cfg->platform->shutdown(cfg);
110   }
111
112   exit(0);
113 }
114
115 int main(int argc, char *argv[]) {
116   int g;
117   const struct sched_param priority = {99};
118
119   // Some command line switch stuffles
120   for (g = 1; g < argc; g++) {
121     if (strcmp(argv[g], "--disable-gayle") == 0) {
122       gayle_emulation_enabled = 0;
123     }
124     else if (strcmp(argv[g], "--cpu_type") == 0 || strcmp(argv[g], "--cpu") == 0) {
125       if (g + 1 >= argc) {
126         printf("%s switch found, but no CPU type specified.\n", argv[g]);
127       } else {
128         g++;
129         cpu_type = get_m68k_cpu_type(argv[g]);
130       }
131     }
132     else if (strcmp(argv[g], "--config-file") == 0 || strcmp(argv[g], "--config") == 0) {
133       if (g + 1 >= argc) {
134         printf("%s switch found, but no config filename specified.\n", argv[g]);
135       } else {
136         g++;
137         cfg = load_config_file(argv[g]);
138       }
139     }
140     else if (strcmp(argv[g], "--keyboard-file") == 0 || strcmp(argv[g], "--kbfile") == 0) {
141       if (g + 1 >= argc) {
142         printf("%s switch found, but no keyboard device path specified.\n", argv[g]);
143       } else {
144         g++;
145         strcpy(keyboard_file, argv[g]);
146       }
147     }
148   }
149
150   if (!cfg) {
151     printf("No config file specified. Trying to load default.cfg...\n");
152     cfg = load_config_file("default.cfg");
153     if (!cfg) {
154       printf("Couldn't load default.cfg, empty emulator config will be used.\n");
155       cfg = (struct emulator_config *)calloc(1, sizeof(struct emulator_config));
156       if (!cfg) {
157         printf("Failed to allocate memory for emulator config!\n");
158         return 1;
159       }
160       memset(cfg, 0x00, sizeof(struct emulator_config));
161     }
162   }
163
164   if (cfg) {
165     if (cfg->cpu_type) cpu_type = cfg->cpu_type;
166     if (cfg->loop_cycles) loop_cycles = cfg->loop_cycles;
167
168     if (!cfg->platform)
169       cfg->platform = make_platform_config("none", "generic");
170     cfg->platform->platform_initial_setup(cfg);
171   }
172
173   if (cfg->mouse_enabled) {
174     mouse_fd = open(cfg->mouse_file, O_RDONLY | O_NONBLOCK);
175     if (mouse_fd == -1) {
176       printf("Failed to open %s, can't enable mouse hook.\n", cfg->mouse_file);
177       cfg->mouse_enabled = 0;
178     }
179   }
180
181   keyboard_fd = open(keyboard_file, O_RDONLY | O_NONBLOCK);
182   if (keyboard_fd == -1) {
183     printf("Failed to open keyboard event source.\n");
184   }
185
186   InitGayle();
187
188   signal(SIGINT, sigint_handler);
189   setup_io();
190
191   //goto skip_everything;
192
193   // Enable 200MHz CLK output on GPIO4, adjust divider and pll source depending
194   // on pi model
195   printf("Enable 200MHz GPCLK0 on GPIO4\n");
196   gpio_enable_200mhz();
197
198   // reset cpld statemachine first
199
200   write_reg(0x01);
201   usleep(100);
202   usleep(1500);
203   write_reg(0x00);
204   usleep(100);
205
206   // reset amiga and statemachine
207   skip_everything:;
208
209   usleep(1500);
210
211   m68k_init();
212   printf("Setting CPU type to %d.\n", cpu_type);
213   m68k_set_cpu_type(cpu_type);
214   cpu_pulse_reset();
215
216   if (maprom == 1) {
217     m68k_set_reg(M68K_REG_PC, 0xF80002);
218   } else {
219     m68k_set_reg(M68K_REG_PC, 0x0);
220   }
221
222   char c = 0, c_code = 0, c_type = 0;
223
224   pthread_t id;
225   int err;
226   err = pthread_create(&id, NULL, &iplThread, NULL);
227   if (err != 0)
228     printf("can't create IPL thread :[%s]", strerror(err));
229   else
230     printf("IPL Thread created successfully\n");
231
232   m68k_pulse_reset();
233   while (42) {
234     if (mouse_hook_enabled) {
235       get_mouse_status(&mouse_dx, &mouse_dy, &mouse_buttons);
236     }
237
238     if (cpu_emulation_running)
239       m68k_execute(loop_cycles);
240
241 disasm_run:;
242     if (realtime_disassembly) {
243       m68k_execute(1);
244       m68k_disassemble(disasm_buf, m68k_get_reg(NULL, M68K_REG_PC), cpu_type);
245       printf("%.8X (%.8X)]] %s\n", m68k_get_reg(NULL, M68K_REG_PC), (m68k_get_reg(NULL, M68K_REG_PC) & 0xFFFFFF), disasm_buf);
246     }
247     
248     if (irq) {
249       unsigned int status = read_reg();
250       m68k_set_irq((status & 0xe000) >> 13);
251     }
252     else if (gayleirq) {
253       write16(0xdff09c, 0x8000 | (1 << 3));
254       //PAULA_SET_IRQ(3); // IRQ 3 = INT2
255       m68k_set_irq(2);
256     }
257     else {
258         m68k_set_irq(0);
259     }
260
261   //usleep(0);
262     // FIXME: Rework this to use keyboard events instead.
263     while (get_key_char(&c, &c_code, &c_type)) {
264
265       if (c == cfg->keyboard_toggle_key && !kb_hook_enabled) {
266         kb_hook_enabled = 1;
267         printf("Keyboard hook enabled.\n");
268       }
269       else if (kb_hook_enabled) {
270         if (c == 0x1B && c_type) {
271           kb_hook_enabled = 0;
272           printf("Keyboard hook disabled.\n");
273         }
274         else {
275           /*printf("Key code: %.2X - ", c_code);
276           switch (c_type) {
277             case 0:
278               printf("released.\n");
279               break;
280             case 1:
281               printf("pressed.\n");
282               break;
283             case 2:
284               printf("repeat.\n");
285               break;
286             default:
287               printf("unknown.\n");
288               break;
289           }*/
290           if (queue_keypress(c_code, c_type, cfg->platform->id)) {
291             m68k_set_irq(2);
292           }
293         }
294       }
295
296       if (!kb_hook_enabled && c_type) {
297         if (c == cfg->mouse_toggle_key) {
298           mouse_hook_enabled ^= 1;
299           printf("Mouse hook %s.\n", mouse_hook_enabled ? "enabled" : "disabled");
300           mouse_dx = mouse_dy = mouse_buttons = 0;
301         }
302         if (c == 'r') {
303           cpu_emulation_running ^= 1;
304           printf("CPU emulation is now %s\n", cpu_emulation_running ? "running" : "stopped");
305         }
306         if (c == 'g') {
307           realtime_graphics_debug ^= 1;
308           printf("Real time graphics debug is now %s\n", realtime_graphics_debug ? "on" : "off");
309         }
310         if (c == 'R') {
311           cpu_pulse_reset();
312           //m68k_pulse_reset();
313           printf("CPU emulation reset.\n");
314         }
315         if (c == 'q') {
316           printf("Quitting and exiting emulator.\n");
317           goto stop_cpu_emulation;
318         }
319         if (c == 'd') {
320           realtime_disassembly ^= 1;
321           printf("Real time disassembly is now %s\n", realtime_disassembly ? "on" : "off");
322         }
323       }
324     }
325
326     if (realtime_disassembly)
327       goto disasm_run;
328
329     //gpio_handle_irq();
330     //GPIO_HANDLE_IRQ;
331   }
332
333   stop_cpu_emulation:;
334
335   if (mouse_fd != -1)
336     close(mouse_fd);
337   if (mem_fd)
338     close(mem_fd);
339
340   return 0;
341 }
342
343 void cpu_pulse_reset(void) {
344   write_reg(0x00);
345   // printf("Status Reg%x\n",read_reg());
346   usleep(100000);
347   write_reg(0x02);
348   // printf("Status Reg%x\n",read_reg());
349
350   ovl = 1;
351   m68k_write_memory_8(0xbfe201, 0x0001);  // AMIGA OVL
352   m68k_write_memory_8(0xbfe001, 0x0001);  // AMIGA OVL high (ROM@0x0)
353
354   m68k_pulse_reset();
355 }
356
357 int cpu_irq_ack(int level) {
358   printf("cpu irq ack\n");
359   return level;
360 }
361
362 static unsigned int target = 0;
363 static uint8_t send_keypress = 0;
364
365 #define PLATFORM_CHECK_READ(a) \
366   if (address >= cfg->custom_low && address < cfg->custom_high) { \
367     unsigned int target = 0; \
368     switch(cfg->platform->id) { \
369       case PLATFORM_AMIGA: { \
370         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
371           return rtg_read((address & 0x0FFFFFFF), a); \
372         } \
373         if (custom_read_amiga(cfg, address, &target, a) != -1) { \
374           return target; \
375         } \
376         break; \
377       } \
378       default: \
379         break; \
380     } \
381   } \
382   if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
383     if (handle_mapped_read(cfg, address, &target, a) != -1) \
384       return target; \
385   }
386
387 unsigned int m68k_read_memory_8(unsigned int address) {
388   PLATFORM_CHECK_READ(OP_TYPE_BYTE);
389
390   if (mouse_hook_enabled) {
391     if (address == CIAAPRA) {
392       unsigned char result = (unsigned int)read8((uint32_t)address);
393       if (mouse_buttons & 0x01) {
394         //mouse_buttons -= 1;
395         return (unsigned int)(result ^ 0x40);
396       }
397       else
398           return (unsigned int)result;
399     }
400   }
401   if (kb_hook_enabled) {
402     unsigned char result = (unsigned int)read8((uint32_t)address);
403     if (address == CIAAICR) {
404       if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
405         result |= 0x08;
406         if (!send_keypress)
407           send_keypress = 1;
408       }
409       if (send_keypress == 2) {
410         result |= 0x02;
411         send_keypress = 0;
412       }
413       return result;
414     }
415     if (address == CIAADAT) {
416       if (send_keypress) {
417         uint8_t c = 0, t = 0;
418         pop_queued_key(&c, &t);
419         t ^= 0x01;
420         result = ((c << 1) | t) ^ 0xFF;
421         send_keypress = 2;
422       }
423       return result;
424     }
425   }
426
427   address &=0xFFFFFF;
428   return read8((uint32_t)address);
429 }
430
431 unsigned int m68k_read_memory_16(unsigned int address) {
432   PLATFORM_CHECK_READ(OP_TYPE_WORD);
433
434   if (mouse_hook_enabled) {
435     if (address == JOY0DAT) {
436       // Forward mouse valueses to Amyga.
437       unsigned short result = (mouse_dy << 8) | (mouse_dx);
438       return (unsigned int)result;
439     }
440     /*if (address == CIAAPRA) {
441       unsigned short result = (unsigned int)read16((uint32_t)address);
442       if (mouse_buttons & 0x01) {
443         return (unsigned int)(result | 0x40);
444       }
445       else
446           return (unsigned int)result;
447     }*/
448     if (address == POTGOR) {
449       unsigned short result = (unsigned int)read16((uint32_t)address);
450       if (mouse_buttons & 0x02) {
451         return (unsigned int)(result ^ (0x2 << 9));
452       }
453       else
454           return (unsigned int)(result & 0xFFFD);
455     }
456   }
457
458   address &=0xFFFFFF;
459   if (address & 0x01) {
460     return ((read8(address) << 8) | read8(address + 1));
461   }
462   return (unsigned int)read16((uint32_t)address);
463 }
464
465 unsigned int m68k_read_memory_32(unsigned int address) {
466   PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
467
468   address &=0xFFFFFF;
469   if (address & 0x01) {
470     uint32_t c = read8(address);
471     c |= (be16toh(read16(address+1)) << 8);
472     c |= (read8(address + 3) << 24);
473     return htobe32(c);
474   }
475   uint16_t a = read16(address);
476   uint16_t b = read16(address + 2);
477   return (a << 16) | b;
478 }
479
480 #define PLATFORM_CHECK_WRITE(a) \
481   if (address >= cfg->custom_low && address < cfg->custom_high) { \
482     switch(cfg->platform->id) { \
483       case PLATFORM_AMIGA: { \
484         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
485           rtg_write((address & 0x0FFFFFFF), value, a); \
486           return; \
487         } \
488         if (custom_write_amiga(cfg, address, value, a) != -1) { \
489           return; \
490         } \
491         break; \
492       } \
493       default: \
494         break; \
495     } \
496   } \
497   if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
498     if (handle_mapped_write(cfg, address, value, a) != -1) \
499       return; \
500   }
501
502 void m68k_write_memory_8(unsigned int address, unsigned int value) {
503   PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
504
505   if (address == 0xbfe001) {
506     if (ovl != (value & (1 << 0))) {
507       ovl = (value & (1 << 0));
508       printf("OVL:%x\n", ovl);
509     }
510   }
511
512   address &=0xFFFFFF;
513   write8((uint32_t)address, value);
514   return;
515 }
516
517 void m68k_write_memory_16(unsigned int address, unsigned int value) {
518   PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
519
520   address &=0xFFFFFF;
521   write16((uint32_t)address, value);
522   return;
523 }
524
525 void m68k_write_memory_32(unsigned int address, unsigned int value) {
526   PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
527
528   address &=0xFFFFFF;
529   write16(address, value >> 16);
530   write16(address + 2, value);
531   return;
532 }