]> git.sesse.net Git - pistorm/blob - emulator.c
IDE updates, fix mouse hook hotkey
[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[0].intrq || get_ide(0)->drive[1].intrq)) {
73         //get_ide(0)->drive[0].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     while (get_key_char(&c, &c_code, &c_type)) {
262       if (c && c == cfg->keyboard_toggle_key && !kb_hook_enabled) {
263         kb_hook_enabled = 1;
264         printf("Keyboard hook enabled.\n");
265       }
266       else if (kb_hook_enabled) {
267         if (c == 0x1B && c_type) {
268           kb_hook_enabled = 0;
269           printf("Keyboard hook disabled.\n");
270         }
271         else {
272           /*printf("Key code: %.2X - ", c_code);
273           switch (c_type) {
274             case 0:
275               printf("released.\n");
276               break;
277             case 1:
278               printf("pressed.\n");
279               break;
280             case 2:
281               printf("repeat.\n");
282               break;
283             default:
284               printf("unknown.\n");
285               break;
286           }*/
287           if (queue_keypress(c_code, c_type, cfg->platform->id)) {
288             m68k_set_irq(2);
289           }
290         }
291       }
292
293       if (!kb_hook_enabled && c_type) {
294         if (c && c == cfg->mouse_toggle_key) {
295           mouse_hook_enabled ^= 1;
296           printf("Mouse hook %s.\n", mouse_hook_enabled ? "enabled" : "disabled");
297           mouse_dx = mouse_dy = mouse_buttons = 0;
298         }
299         if (c == 'r') {
300           cpu_emulation_running ^= 1;
301           printf("CPU emulation is now %s\n", cpu_emulation_running ? "running" : "stopped");
302         }
303         if (c == 'g') {
304           realtime_graphics_debug ^= 1;
305           printf("Real time graphics debug is now %s\n", realtime_graphics_debug ? "on" : "off");
306         }
307         if (c == 'R') {
308           cpu_pulse_reset();
309           //m68k_pulse_reset();
310           printf("CPU emulation reset.\n");
311         }
312         if (c == 'q') {
313           printf("Quitting and exiting emulator.\n");
314           goto stop_cpu_emulation;
315         }
316         if (c == 'd') {
317           realtime_disassembly ^= 1;
318           printf("Real time disassembly is now %s\n", realtime_disassembly ? "on" : "off");
319         }
320       }
321     }
322
323     if (realtime_disassembly)
324       goto disasm_run;
325
326     //gpio_handle_irq();
327     //GPIO_HANDLE_IRQ;
328   }
329
330   stop_cpu_emulation:;
331
332   if (mouse_fd != -1)
333     close(mouse_fd);
334   if (mem_fd)
335     close(mem_fd);
336
337   return 0;
338 }
339
340 void cpu_pulse_reset(void) {
341   write_reg(0x00);
342   // printf("Status Reg%x\n",read_reg());
343   usleep(100000);
344   write_reg(0x02);
345   // printf("Status Reg%x\n",read_reg());
346
347   ovl = 1;
348   m68k_write_memory_8(0xbfe201, 0x0001);  // AMIGA OVL
349   m68k_write_memory_8(0xbfe001, 0x0001);  // AMIGA OVL high (ROM@0x0)
350
351   m68k_pulse_reset();
352 }
353
354 int cpu_irq_ack(int level) {
355   printf("cpu irq ack\n");
356   return level;
357 }
358
359 static unsigned int target = 0;
360 static uint8_t send_keypress = 0;
361
362 #define PLATFORM_CHECK_READ(a) \
363   if (address >= cfg->custom_low && address < cfg->custom_high) { \
364     unsigned int target = 0; \
365     switch(cfg->platform->id) { \
366       case PLATFORM_AMIGA: { \
367         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
368           return rtg_read((address & 0x0FFFFFFF), a); \
369         } \
370         if (custom_read_amiga(cfg, address, &target, a) != -1) { \
371           return target; \
372         } \
373         break; \
374       } \
375       default: \
376         break; \
377     } \
378   } \
379   if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
380     if (handle_mapped_read(cfg, address, &target, a) != -1) \
381       return target; \
382   }
383
384 unsigned int m68k_read_memory_8(unsigned int address) {
385   PLATFORM_CHECK_READ(OP_TYPE_BYTE);
386
387   if (mouse_hook_enabled) {
388     if (address == CIAAPRA) {
389       unsigned char result = (unsigned int)read8((uint32_t)address);
390       if (mouse_buttons & 0x01) {
391         //mouse_buttons -= 1;
392         return (unsigned int)(result ^ 0x40);
393       }
394       else
395           return (unsigned int)result;
396     }
397   }
398   if (kb_hook_enabled) {
399     unsigned char result = (unsigned int)read8((uint32_t)address);
400     if (address == CIAAICR) {
401       if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
402         result |= 0x08;
403         if (!send_keypress)
404           send_keypress = 1;
405       }
406       if (send_keypress == 2) {
407         result |= 0x02;
408         send_keypress = 0;
409       }
410       return result;
411     }
412     if (address == CIAADAT) {
413       if (send_keypress) {
414         uint8_t c = 0, t = 0;
415         pop_queued_key(&c, &t);
416         t ^= 0x01;
417         result = ((c << 1) | t) ^ 0xFF;
418         send_keypress = 2;
419       }
420       return result;
421     }
422   }
423
424   address &=0xFFFFFF;
425   return read8((uint32_t)address);
426 }
427
428 unsigned int m68k_read_memory_16(unsigned int address) {
429   PLATFORM_CHECK_READ(OP_TYPE_WORD);
430
431   if (mouse_hook_enabled) {
432     if (address == JOY0DAT) {
433       // Forward mouse valueses to Amyga.
434       unsigned short result = (mouse_dy << 8) | (mouse_dx);
435       return (unsigned int)result;
436     }
437     /*if (address == CIAAPRA) {
438       unsigned short result = (unsigned int)read16((uint32_t)address);
439       if (mouse_buttons & 0x01) {
440         return (unsigned int)(result | 0x40);
441       }
442       else
443           return (unsigned int)result;
444     }*/
445     if (address == POTGOR) {
446       unsigned short result = (unsigned int)read16((uint32_t)address);
447       if (mouse_buttons & 0x02) {
448         return (unsigned int)(result ^ (0x2 << 9));
449       }
450       else
451           return (unsigned int)(result & 0xFFFD);
452     }
453   }
454
455   address &=0xFFFFFF;
456   if (address & 0x01) {
457     return ((read8(address) << 8) | read8(address + 1));
458   }
459   return (unsigned int)read16((uint32_t)address);
460 }
461
462 unsigned int m68k_read_memory_32(unsigned int address) {
463   PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
464
465   address &=0xFFFFFF;
466   if (address & 0x01) {
467     uint32_t c = read8(address);
468     c |= (be16toh(read16(address+1)) << 8);
469     c |= (read8(address + 3) << 24);
470     return htobe32(c);
471   }
472   uint16_t a = read16(address);
473   uint16_t b = read16(address + 2);
474   return (a << 16) | b;
475 }
476
477 #define PLATFORM_CHECK_WRITE(a) \
478   if (address >= cfg->custom_low && address < cfg->custom_high) { \
479     switch(cfg->platform->id) { \
480       case PLATFORM_AMIGA: { \
481         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
482           rtg_write((address & 0x0FFFFFFF), value, a); \
483           return; \
484         } \
485         if (custom_write_amiga(cfg, address, value, a) != -1) { \
486           return; \
487         } \
488         break; \
489       } \
490       default: \
491         break; \
492     } \
493   } \
494   if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
495     if (handle_mapped_write(cfg, address, value, a) != -1) \
496       return; \
497   }
498
499 void m68k_write_memory_8(unsigned int address, unsigned int value) {
500   PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
501
502   if (address == 0xbfe001) {
503     if (ovl != (value & (1 << 0))) {
504       ovl = (value & (1 << 0));
505       printf("OVL:%x\n", ovl);
506     }
507   }
508
509   address &=0xFFFFFF;
510   write8((uint32_t)address, value);
511   return;
512 }
513
514 void m68k_write_memory_16(unsigned int address, unsigned int value) {
515   PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
516
517   address &=0xFFFFFF;
518   write16((uint32_t)address, value);
519   return;
520 }
521
522 void m68k_write_memory_32(unsigned int address, unsigned int value) {
523   PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
524
525   address &=0xFFFFFF;
526   write16(address, value >> 16);
527   write16(address + 2, value);
528   return;
529 }