]> git.sesse.net Git - pistorm/blob - emulator.c
Disable mouse/kb hook on Amiga platform shutdown
[pistorm] / emulator.c
1 // SPDX-License-Identifier: MIT
2
3 #include "m68k.h"
4 #include "emulator.h"
5 #include "platforms/platforms.h"
6 #include "input/input.h"
7 #include "m68kcpu.h"
8
9 #include "platforms/amiga/Gayle.h"
10 #include "platforms/amiga/amiga-registers.h"
11 #include "platforms/amiga/rtg/rtg.h"
12 #include "platforms/amiga/hunk-reloc.h"
13 #include "platforms/amiga/piscsi/piscsi.h"
14 #include "platforms/amiga/piscsi/piscsi-enums.h"
15 #include "platforms/amiga/net/pi-net.h"
16 #include "platforms/amiga/net/pi-net-enums.h"
17 #include "platforms/amiga/pistorm-dev/pistorm-dev.h"
18 #include "platforms/amiga/pistorm-dev/pistorm-dev-enums.h"
19 #include "gpio/ps_protocol.h"
20
21 #include <assert.h>
22 #include <dirent.h>
23 #include <endian.h>
24 #include <fcntl.h>
25 #include <poll.h>
26 #include <pthread.h>
27 #include <sched.h>
28 #include <signal.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/ioctl.h>
34 #include <sys/mman.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38
39 #define KEY_POLL_INTERVAL_MSEC 5000
40
41 int kb_hook_enabled = 0;
42 int mouse_hook_enabled = 0;
43 int cpu_emulation_running = 1;
44
45 uint8_t mouse_dx = 0, mouse_dy = 0;
46 uint8_t mouse_buttons = 0;
47 uint8_t mouse_extra = 0;
48
49 extern uint8_t gayle_int;
50 extern uint8_t gayle_ide_enabled;
51 extern uint8_t gayle_emulation_enabled;
52 extern uint8_t gayle_a4k_int;
53 extern volatile unsigned int *gpio;
54 extern volatile uint16_t srdata;
55 extern uint8_t realtime_graphics_debug, emulator_exiting;
56 extern uint8_t rtg_on;
57 uint8_t realtime_disassembly, int2_enabled = 0;
58 uint32_t do_disasm = 0, old_level;
59 uint32_t last_irq = 8, last_last_irq = 8;
60
61 uint8_t end_signal = 0, load_new_config = 0;
62
63 char disasm_buf[4096];
64
65 #define KICKBASE 0xF80000
66 #define KICKSIZE 0x7FFFF
67
68 int mem_fd, mouse_fd = -1, keyboard_fd = -1;
69 int mem_fd_gpclk;
70 int irq;
71 int gayleirq;
72
73 #define MUSASHI_HAX
74
75 #ifdef MUSASHI_HAX
76 #include "m68kcpu.h"
77 extern m68ki_cpu_core m68ki_cpu;
78 extern int m68ki_initial_cycles;
79 extern int m68ki_remaining_cycles;
80
81 #define M68K_SET_IRQ(i) old_level = CPU_INT_LEVEL; \
82         CPU_INT_LEVEL = (i << 8); \
83         if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700) \
84                 m68ki_cpu.nmi_pending = TRUE;
85 #define M68K_END_TIMESLICE      m68ki_initial_cycles = GET_CYCLES(); \
86         SET_CYCLES(0);
87 #else
88 #define M68K_SET_IRQ m68k_set_irq
89 #define M68K_END_TIMESLICE m68k_end_timeslice()
90 #endif
91
92 #define NOP asm("nop"); asm("nop"); asm("nop"); asm("nop");
93
94 #define DEBUG_EMULATOR
95 #ifdef DEBUG_EMULATOR
96 #define DEBUG printf
97 #else
98 #define DEBUG(...)
99 #endif
100
101 // Configurable emulator options
102 unsigned int cpu_type = M68K_CPU_TYPE_68000;
103 unsigned int loop_cycles = 300, irq_status = 0;
104 struct emulator_config *cfg = NULL;
105 char keyboard_file[256] = "/dev/input/event1";
106
107 uint64_t trig_irq = 0, serv_irq = 0;
108 uint16_t irq_delay = 0;
109 unsigned int amiga_reset=0, amiga_reset_last=0;
110 unsigned int do_reset=0;
111
112 void *ipl_task(void *args) {
113   printf("IPL thread running\n");
114   uint16_t old_irq = 0;
115   uint32_t value;
116
117   while (1) {
118     value = *(gpio + 13);
119
120     if (!(value & (1 << PIN_IPL_ZERO))) {
121       old_irq = irq_delay;
122       //NOP
123       if (!irq) {
124         M68K_END_TIMESLICE;
125         NOP
126         irq = 1;
127       }
128       //usleep(0);
129     }
130     else {
131       if (irq) {
132         if (old_irq) {
133           old_irq--;
134         }
135         else {
136           irq = 0;
137         }
138         M68K_END_TIMESLICE;
139         NOP
140         //usleep(0);
141       }
142     }
143     if(do_reset==0)
144     {
145       amiga_reset=(value & (1 << PIN_RESET));
146       if(amiga_reset!=amiga_reset_last)
147       {
148         amiga_reset_last=amiga_reset;
149         if(amiga_reset==0)
150         {
151           printf("Amiga Reset is down...\n");
152           do_reset=1;
153           M68K_END_TIMESLICE;
154         }
155         else
156         {
157           printf("Amiga Reset is up...\n");
158         }
159       }
160     }
161
162     /*if (gayle_ide_enabled) {
163       if (((gayle_int & 0x80) || gayle_a4k_int) && (get_ide(0)->drive[0].intrq || get_ide(0)->drive[1].intrq)) {
164         //get_ide(0)->drive[0].intrq = 0;
165         gayleirq = 1;
166         M68K_END_TIMESLICE;
167       }
168       else
169         gayleirq = 0;
170     }*/
171     //usleep(0);
172     //NOP NOP
173     NOP NOP NOP NOP NOP NOP NOP NOP
174     //NOP NOP NOP NOP NOP NOP NOP NOP
175     //NOP NOP NOP NOP NOP NOP NOP NOP
176     /*NOP NOP NOP NOP NOP NOP NOP NOP
177     NOP NOP NOP NOP NOP NOP NOP NOP
178     NOP NOP NOP NOP NOP NOP NOP NOP*/
179   }
180   return args;
181 }
182
183 void *cpu_task() {
184   m68k_pulse_reset();
185
186 cpu_loop:
187   if (mouse_hook_enabled) {
188     get_mouse_status(&mouse_dx, &mouse_dy, &mouse_buttons, &mouse_extra);
189   }
190
191   if (realtime_disassembly && (do_disasm || cpu_emulation_running)) {
192     m68k_disassemble(disasm_buf, m68k_get_reg(NULL, M68K_REG_PC), cpu_type);
193     printf("REGA: 0:$%.8X 1:$%.8X 2:$%.8X 3:$%.8X 4:$%.8X 5:$%.8X 6:$%.8X 7:$%.8X\n", m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), m68k_get_reg(NULL, M68K_REG_A2), m68k_get_reg(NULL, M68K_REG_A3), \
194             m68k_get_reg(NULL, M68K_REG_A4), m68k_get_reg(NULL, M68K_REG_A5), m68k_get_reg(NULL, M68K_REG_A6), m68k_get_reg(NULL, M68K_REG_A7));
195     printf("REGD: 0:$%.8X 1:$%.8X 2:$%.8X 3:$%.8X 4:$%.8X 5:$%.8X 6:$%.8X 7:$%.8X\n", m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2), m68k_get_reg(NULL, M68K_REG_D3), \
196             m68k_get_reg(NULL, M68K_REG_D4), m68k_get_reg(NULL, M68K_REG_D5), m68k_get_reg(NULL, M68K_REG_D6), m68k_get_reg(NULL, M68K_REG_D7));
197     printf("%.8X (%.8X)]] %s\n", m68k_get_reg(NULL, M68K_REG_PC), (m68k_get_reg(NULL, M68K_REG_PC) & 0xFFFFFF), disasm_buf);
198     if (do_disasm)
199       do_disasm--;
200     m68k_execute(1);
201   }
202   else {
203     if (cpu_emulation_running)
204       m68k_execute(loop_cycles);
205   }
206
207   if (irq) {
208     while (irq) {
209       last_irq = ((read_reg() & 0xe000) >> 13);
210       if (last_irq != last_last_irq) {
211         last_last_irq = last_irq;
212         M68K_SET_IRQ(last_irq);
213       }
214       m68k_execute(5);
215     }
216     if (gayleirq && int2_enabled) {
217       write16(0xdff09c, 0x8000 | (1 << 3) && last_irq != 2);
218       last_last_irq = last_irq;
219       last_irq = 2;
220       M68K_SET_IRQ(2);
221     }
222     M68K_SET_IRQ(0);
223     last_last_irq = 0;
224     m68k_execute(5);
225   }
226   /*else {
227     if (last_irq != 0) {
228       M68K_SET_IRQ(0);
229       last_last_irq = last_irq;
230       last_irq = 0;
231     }
232   }*/
233   if (do_reset) {
234     cpu_pulse_reset();
235     do_reset=0;
236     usleep(1000000); // 1sec
237     rtg_on=0;
238 //    while(amiga_reset==0);
239 //    printf("CPU emulation reset.\n");
240   }
241
242   if (mouse_hook_enabled && (mouse_extra != 0x00)) {
243     // mouse wheel events have occurred; unlike l/m/r buttons, these are queued as keypresses, so add to end of buffer
244     switch (mouse_extra) {
245       case 0xff:
246         // wheel up
247         queue_keypress(0xfe, KEYPRESS_PRESS, PLATFORM_AMIGA);
248         break;
249       case 0x01:
250         // wheel down
251         queue_keypress(0xff, KEYPRESS_PRESS, PLATFORM_AMIGA);
252         break;
253     }
254
255     // dampen the scroll wheel until next while loop iteration
256     mouse_extra = 0x00;
257   }
258
259   if (load_new_config) {
260     printf("[CPU] Loading new config file.\n");
261     goto stop_cpu_emulation;
262   }
263
264   if (end_signal)
265           goto stop_cpu_emulation;
266
267   goto cpu_loop;
268
269 stop_cpu_emulation:
270   printf("[CPU] End of CPU thread\n");
271   return (void *)NULL;
272 }
273
274 void *keyboard_task() {
275   struct pollfd kbdpoll[1];
276   int kpollrc;
277   char c = 0, c_code = 0, c_type = 0;
278   char grab_message[] = "[KBD] Grabbing keyboard from input layer\n",
279        ungrab_message[] = "[KBD] Ungrabbing keyboard\n";
280
281   printf("[KBD] Keyboard thread started\n");
282
283   // because we permit the keyboard to be grabbed on startup, quickly check if we need to grab it
284   if (kb_hook_enabled && cfg->keyboard_grab) {
285     printf(grab_message);
286     grab_device(keyboard_fd);
287   }
288
289   kbdpoll[0].fd = keyboard_fd;
290   kbdpoll[0].events = POLLIN;
291
292 key_loop:
293   kpollrc = poll(kbdpoll, 1, KEY_POLL_INTERVAL_MSEC);
294   if ((kpollrc > 0) && (kbdpoll[0].revents & POLLHUP)) {
295     // in the event that a keyboard is unplugged, keyboard_task will whiz up to 100% utilisation
296     // this is undesired, so if the keyboard HUPs, end the thread without ending the emulation
297     printf("[KBD] Keyboard node returned HUP (unplugged?)\n");
298     goto key_end;
299   }
300
301   // if kpollrc > 0 then it contains number of events to pull, also check if POLLIN is set in revents
302   if ((kpollrc <= 0) || !(kbdpoll[0].revents & POLLIN)) {
303     goto key_loop;
304   }
305
306   while (get_key_char(&c, &c_code, &c_type)) {
307     if (c && c == cfg->keyboard_toggle_key && !kb_hook_enabled) {
308       kb_hook_enabled = 1;
309       printf("[KBD] Keyboard hook enabled.\n");
310       if (cfg->keyboard_grab) {
311         grab_device(keyboard_fd);
312         printf(grab_message);
313       }
314     } else if (kb_hook_enabled) {
315       if (c == 0x1B && c_type) {
316         kb_hook_enabled = 0;
317         printf("[KBD] Keyboard hook disabled.\n");
318         if (cfg->keyboard_grab) {
319           release_device(keyboard_fd);
320           printf(ungrab_message);
321         }
322       } else {
323         if (queue_keypress(c_code, c_type, cfg->platform->id) && int2_enabled && last_irq != 2) {
324           //last_irq = 0;
325           //M68K_SET_IRQ(2);
326         }
327       }
328     }
329
330     // pause pressed; trigger nmi (int level 7)
331     if (c == 0x01 && c_type) {
332       printf("[INT] Sending NMI\n");
333       M68K_SET_IRQ(7);
334     }
335
336     if (!kb_hook_enabled && c_type) {
337       if (c && c == cfg->mouse_toggle_key) {
338         mouse_hook_enabled ^= 1;
339         printf("Mouse hook %s.\n", mouse_hook_enabled ? "enabled" : "disabled");
340         mouse_dx = mouse_dy = mouse_buttons = mouse_extra = 0;
341       }
342       if (c == 'r') {
343         cpu_emulation_running ^= 1;
344         printf("CPU emulation is now %s\n", cpu_emulation_running ? "running" : "stopped");
345       }
346       if (c == 'g') {
347         realtime_graphics_debug ^= 1;
348         printf("Real time graphics debug is now %s\n", realtime_graphics_debug ? "on" : "off");
349       }
350       if (c == 'R') {
351         cpu_pulse_reset();
352         //m68k_pulse_reset();
353         printf("CPU emulation reset.\n");
354       }
355       if (c == 'q') {
356         printf("Quitting and exiting emulator.\n");
357               end_signal = 1;
358         goto key_end;
359       }
360       if (c == 'd') {
361         realtime_disassembly ^= 1;
362         do_disasm = 1;
363         printf("Real time disassembly is now %s\n", realtime_disassembly ? "on" : "off");
364       }
365       if (c == 'D') {
366         int r = get_mapped_item_by_address(cfg, 0x08000000);
367         if (r != -1) {
368           printf("Dumping first 16MB of mapped range %d.\n", r);
369           FILE *dmp = fopen("./memdmp.bin", "wb+");
370           fwrite(cfg->map_data[r], 16 * SIZE_MEGA, 1, dmp);
371           fclose(dmp);
372         }
373       }
374       if (c == 's' && realtime_disassembly) {
375         do_disasm = 1;
376       }
377       if (c == 'S' && realtime_disassembly) {
378         do_disasm = 128;
379       }
380     }
381   }
382
383   goto key_loop;
384
385 key_end:
386   printf("[KBD] Keyboard thread ending\n");
387   if (cfg->keyboard_grab) {
388     printf(ungrab_message);
389     release_device(keyboard_fd);
390   }
391   return (void*)NULL;
392 }
393
394 void stop_cpu_emulation(uint8_t disasm_cur) {
395   M68K_END_TIMESLICE;
396   if (disasm_cur) {
397     m68k_disassemble(disasm_buf, m68k_get_reg(NULL, M68K_REG_PC), cpu_type);
398     printf("REGA: 0:$%.8X 1:$%.8X 2:$%.8X 3:$%.8X 4:$%.8X 5:$%.8X 6:$%.8X 7:$%.8X\n", m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), m68k_get_reg(NULL, M68K_REG_A2), m68k_get_reg(NULL, M68K_REG_A3), \
399             m68k_get_reg(NULL, M68K_REG_A4), m68k_get_reg(NULL, M68K_REG_A5), m68k_get_reg(NULL, M68K_REG_A6), m68k_get_reg(NULL, M68K_REG_A7));
400     printf("REGD: 0:$%.8X 1:$%.8X 2:$%.8X 3:$%.8X 4:$%.8X 5:$%.8X 6:$%.8X 7:$%.8X\n", m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2), m68k_get_reg(NULL, M68K_REG_D3), \
401             m68k_get_reg(NULL, M68K_REG_D4), m68k_get_reg(NULL, M68K_REG_D5), m68k_get_reg(NULL, M68K_REG_D6), m68k_get_reg(NULL, M68K_REG_D7));
402     printf("%.8X (%.8X)]] %s\n", m68k_get_reg(NULL, M68K_REG_PC), (m68k_get_reg(NULL, M68K_REG_PC) & 0xFFFFFF), disasm_buf);
403     realtime_disassembly = 1;
404   }
405
406   cpu_emulation_running = 0;
407   do_disasm = 0;
408 }
409
410 unsigned int ovl;
411 static volatile unsigned char maprom;
412
413 void sigint_handler(int sig_num) {
414   //if (sig_num) { }
415   //cpu_emulation_running = 0;
416
417   //return;
418   printf("Received sigint %d, exiting.\n", sig_num);
419   if (mouse_fd != -1)
420     close(mouse_fd);
421   if (mem_fd)
422     close(mem_fd);
423
424   if (cfg->platform->shutdown) {
425     cfg->platform->shutdown(cfg);
426   }
427
428   while (!emulator_exiting) {
429     emulator_exiting = 1;
430     usleep(0);
431   }
432
433   printf("IRQs triggered: %lld\n", trig_irq);
434   printf("IRQs serviced: %lld\n", serv_irq);
435
436   exit(0);
437 }
438
439 int main(int argc, char *argv[]) {
440   int g;
441
442   ps_setup_protocol();
443
444   //const struct sched_param priority = {99};
445
446   // Some command line switch stuffles
447   for (g = 1; g < argc; g++) {
448     if (strcmp(argv[g], "--cpu_type") == 0 || strcmp(argv[g], "--cpu") == 0) {
449       if (g + 1 >= argc) {
450         printf("%s switch found, but no CPU type specified.\n", argv[g]);
451       } else {
452         g++;
453         cpu_type = get_m68k_cpu_type(argv[g]);
454       }
455     }
456     else if (strcmp(argv[g], "--config-file") == 0 || strcmp(argv[g], "--config") == 0) {
457       if (g + 1 >= argc) {
458         printf("%s switch found, but no config filename specified.\n", argv[g]);
459       } else {
460         g++;
461         FILE *chk = fopen(argv[g], "rb");
462         if (chk == NULL) {
463           printf("Config file %s does not exist, please check that you've specified the path correctly.\n", argv[g]);
464         } else {
465           fclose(chk);
466           load_new_config = 1;
467           set_pistorm_devcfg_filename(argv[g]);
468         }
469       }
470     }
471     else if (strcmp(argv[g], "--keyboard-file") == 0 || strcmp(argv[g], "--kbfile") == 0) {
472       if (g + 1 >= argc) {
473         printf("%s switch found, but no keyboard device path specified.\n", argv[g]);
474       } else {
475         g++;
476         strcpy(keyboard_file, argv[g]);
477       }
478     }
479   }
480
481 switch_config:
482   srand(clock());
483
484   ps_reset_state_machine();
485   ps_pulse_reset();
486   usleep(1500);
487
488   if (load_new_config != 0) {
489     uint8_t config_action = load_new_config - 1;
490     load_new_config = 0;
491     if (cfg) {
492       free_config_file(cfg);
493       free(cfg);
494       cfg = NULL;
495     }
496
497     switch(config_action) {
498       case PICFG_LOAD:
499       case PICFG_RELOAD:
500         cfg = load_config_file(get_pistorm_devcfg_filename());
501         break;
502       case PICFG_DEFAULT:
503         cfg = load_config_file("default.cfg");
504         break;
505     }
506   }
507
508   if (!cfg) {
509     printf("No config file specified. Trying to load default.cfg...\n");
510     cfg = load_config_file("default.cfg");
511     if (!cfg) {
512       printf("Couldn't load default.cfg, empty emulator config will be used.\n");
513       cfg = (struct emulator_config *)calloc(1, sizeof(struct emulator_config));
514       if (!cfg) {
515         printf("Failed to allocate memory for emulator config!\n");
516         return 1;
517       }
518       memset(cfg, 0x00, sizeof(struct emulator_config));
519     }
520   }
521
522   if (cfg) {
523     if (cfg->cpu_type) cpu_type = cfg->cpu_type;
524     if (cfg->loop_cycles) loop_cycles = cfg->loop_cycles;
525
526     if (!cfg->platform)
527       cfg->platform = make_platform_config("none", "generic");
528     cfg->platform->platform_initial_setup(cfg);
529   }
530
531   if (cfg->mouse_enabled) {
532     mouse_fd = open(cfg->mouse_file, O_RDWR | O_NONBLOCK);
533     if (mouse_fd == -1) {
534       printf("Failed to open %s, can't enable mouse hook.\n", cfg->mouse_file);
535       cfg->mouse_enabled = 0;
536     } else {
537       /**
538        * *-*-*-* magic numbers! *-*-*-*
539        * great, so waaaay back in the history of the pc, the ps/2 protocol set the standard for mice
540        * and in the process, the mouse sample rate was defined as a way of putting mice into vendor-specific modes.
541        * as the ancient gpm command explains, almost everything except incredibly old mice talk the IntelliMouse
542        * protocol, which reports four bytes. by default, every mouse starts in 3-byte mode (don't report wheel or
543        * additional buttons) until imps2 magic is sent. so, command $f3 is "set sample rate", followed by a byte.
544        */
545       uint8_t mouse_init[] = { 0xf4, 0xf3, 0x64 }; // enable, then set sample rate 100
546       uint8_t imps2_init[] = { 0xf3, 0xc8, 0xf3, 0x64, 0xf3, 0x50 }; // magic sequence; set sample 200, 100, 80
547       if (write(mouse_fd, mouse_init, sizeof(mouse_init)) != -1) {
548         if (write(mouse_fd, imps2_init, sizeof(imps2_init)) == -1)
549           printf("[MOUSE] Couldn't enable scroll wheel events; is this mouse from the 1980s?\n");
550       } else
551         printf("[MOUSE] Mouse didn't respond to normal PS/2 init; have you plugged a brick in by mistake?\n");
552     }
553   }
554
555   if (cfg->keyboard_file)
556     keyboard_fd = open(cfg->keyboard_file, O_RDONLY | O_NONBLOCK);
557   else
558     keyboard_fd = open(keyboard_file, O_RDONLY | O_NONBLOCK);
559
560   if (keyboard_fd == -1) {
561     printf("Failed to open keyboard event source.\n");
562   }
563
564   if (cfg->mouse_autoconnect)
565     mouse_hook_enabled = 1;
566
567   if (cfg->keyboard_autoconnect)
568     kb_hook_enabled = 1;
569
570   InitGayle();
571
572   signal(SIGINT, sigint_handler);
573
574   ps_reset_state_machine();
575   ps_pulse_reset();
576   usleep(1500);
577
578   m68k_init();
579   printf("Setting CPU type to %d.\n", cpu_type);
580   m68k_set_cpu_type(cpu_type);
581   cpu_pulse_reset();
582
583   pthread_t ipl_tid = 0, cpu_tid, kbd_tid;
584   int err;
585   if (ipl_tid == 0) {
586     err = pthread_create(&ipl_tid, NULL, &ipl_task, NULL);
587     if (err != 0)
588       printf("[ERROR] Cannot create IPL thread: [%s]", strerror(err));
589     else {
590       pthread_setname_np(ipl_tid, "pistorm: ipl");
591       printf("IPL thread created successfully\n");
592     }
593   }
594
595   // create keyboard task
596   err = pthread_create(&kbd_tid, NULL, &keyboard_task, NULL);
597   if (err != 0)
598     printf("[ERROR] Cannot create keyboard thread: [%s]", strerror(err));
599   else {
600     pthread_setname_np(kbd_tid, "pistorm: kbd");
601     printf("[MAIN] Keyboard thread created successfully\n");
602   }
603
604   // create cpu task
605   err = pthread_create(&cpu_tid, NULL, &cpu_task, NULL);
606   if (err != 0)
607     printf("[ERROR] Cannot create CPU thread: [%s]", strerror(err));
608   else {
609     pthread_setname_np(cpu_tid, "pistorm: cpu");
610     printf("[MAIN] CPU thread created successfully\n");
611   }
612
613   // wait for cpu task to end before closing up and finishing
614   pthread_join(cpu_tid, NULL);
615
616   while (!emulator_exiting) {
617     emulator_exiting = 1;
618     usleep(0);
619   }
620
621   if (load_new_config == 0)
622     printf("[MAIN] All threads appear to have concluded; ending process\n");
623
624   if (mouse_fd != -1)
625     close(mouse_fd);
626   if (mem_fd)
627     close(mem_fd);
628
629   if (load_new_config != 0)
630     goto switch_config;
631
632   if (cfg->platform->shutdown) {
633     cfg->platform->shutdown(cfg);
634   }
635
636   return 0;
637 }
638
639 void cpu_pulse_reset(void) {
640   ps_pulse_reset();
641   if (cfg->platform->handle_reset)
642     cfg->platform->handle_reset(cfg);
643
644   //m68k_write_memory_16(INTENA, 0x7FFF);
645   ovl = 1;
646   //m68k_write_memory_8(0xbfe201, 0x0001);  // AMIGA OVL
647   //m68k_write_memory_8(0xbfe001, 0x0001);  // AMIGA OVL high (ROM@0x0)
648
649   m68k_pulse_reset();
650 }
651
652 int cpu_irq_ack(int level) {
653   printf("cpu irq ack\n");
654   return level;
655 }
656
657 static unsigned int target = 0;
658 static uint8_t send_keypress = 0;
659 static uint32_t platform_res, rres;
660
661 uint8_t cdtv_dmac_reg_idx_read();
662 void cdtv_dmac_reg_idx_write(uint8_t value);
663 uint32_t cdtv_dmac_read(uint32_t address, uint8_t type);
664 void cdtv_dmac_write(uint32_t address, uint32_t value, uint8_t type);
665
666 static inline void inline_write_16(unsigned int address, unsigned int data) {
667   *(gpio + 0) = GPFSEL0_OUTPUT;
668   *(gpio + 1) = GPFSEL1_OUTPUT;
669   *(gpio + 2) = GPFSEL2_OUTPUT;
670
671   *(gpio + 7) = ((data & 0xffff) << 8) | (REG_DATA << PIN_A0);
672   *(gpio + 7) = 1 << PIN_WR;
673   *(gpio + 10) = 1 << PIN_WR;
674   *(gpio + 10) = 0xffffec;
675
676   *(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
677   *(gpio + 7) = 1 << PIN_WR;
678   *(gpio + 10) = 1 << PIN_WR;
679   *(gpio + 10) = 0xffffec;
680
681   *(gpio + 7) = ((0x0000 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
682   *(gpio + 7) = 1 << PIN_WR;
683   *(gpio + 10) = 1 << PIN_WR;
684   *(gpio + 10) = 0xffffec;
685
686   *(gpio + 0) = GPFSEL0_INPUT;
687   *(gpio + 1) = GPFSEL1_INPUT;
688   *(gpio + 2) = GPFSEL2_INPUT;
689
690   while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
691     ;
692 }
693
694 static inline void inline_write_8(unsigned int address, unsigned int data) {
695   if ((address & 1) == 0)
696     data = data + (data << 8);  // EVEN, A0=0,UDS
697   else
698     data = data & 0xff;  // ODD , A0=1,LDS
699
700   *(gpio + 0) = GPFSEL0_OUTPUT;
701   *(gpio + 1) = GPFSEL1_OUTPUT;
702   *(gpio + 2) = GPFSEL2_OUTPUT;
703
704   *(gpio + 7) = ((data & 0xffff) << 8) | (REG_DATA << PIN_A0);
705   *(gpio + 7) = 1 << PIN_WR;
706   *(gpio + 10) = 1 << PIN_WR;
707   *(gpio + 10) = 0xffffec;
708
709   *(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
710   *(gpio + 7) = 1 << PIN_WR;
711   *(gpio + 10) = 1 << PIN_WR;
712   *(gpio + 10) = 0xffffec;
713
714   *(gpio + 7) = ((0x0100 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
715   *(gpio + 7) = 1 << PIN_WR;
716   *(gpio + 10) = 1 << PIN_WR;
717   *(gpio + 10) = 0xffffec;
718
719   *(gpio + 0) = GPFSEL0_INPUT;
720   *(gpio + 1) = GPFSEL1_INPUT;
721   *(gpio + 2) = GPFSEL2_INPUT;
722
723   while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
724     ;
725 }
726
727 static inline void inline_write_32(unsigned int address, unsigned int value) {
728   inline_write_16(address, value >> 16);
729   inline_write_16(address + 2, value);
730 }
731
732 static inline unsigned int inline_read_16(unsigned int address) {
733   *(gpio + 0) = GPFSEL0_OUTPUT;
734   *(gpio + 1) = GPFSEL1_OUTPUT;
735   *(gpio + 2) = GPFSEL2_OUTPUT;
736
737   *(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
738   *(gpio + 7) = 1 << PIN_WR;
739   *(gpio + 10) = 1 << PIN_WR;
740   *(gpio + 10) = 0xffffec;
741
742   *(gpio + 7) = ((0x0200 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
743   *(gpio + 7) = 1 << PIN_WR;
744   *(gpio + 10) = 1 << PIN_WR;
745   *(gpio + 10) = 0xffffec;
746
747   *(gpio + 0) = GPFSEL0_INPUT;
748   *(gpio + 1) = GPFSEL1_INPUT;
749   *(gpio + 2) = GPFSEL2_INPUT;
750
751   *(gpio + 7) = (REG_DATA << PIN_A0);
752   *(gpio + 7) = 1 << PIN_RD;
753
754   unsigned int value = *(gpio + 13);
755   while ((value=*(gpio + 13)) & (1 << PIN_TXN_IN_PROGRESS))
756     ;
757
758   *(gpio + 10) = 0xffffec;
759
760   return (value >> 8) & 0xffff;
761 }
762
763 static inline unsigned int inline_read_8(unsigned int address) {
764   *(gpio + 0) = GPFSEL0_OUTPUT;
765   *(gpio + 1) = GPFSEL1_OUTPUT;
766   *(gpio + 2) = GPFSEL2_OUTPUT;
767
768   *(gpio + 7) = ((address & 0xffff) << 8) | (REG_ADDR_LO << PIN_A0);
769   *(gpio + 7) = 1 << PIN_WR;
770   *(gpio + 10) = 1 << PIN_WR;
771   *(gpio + 10) = 0xffffec;
772
773   *(gpio + 7) = ((0x0300 | (address >> 16)) << 8) | (REG_ADDR_HI << PIN_A0);
774   *(gpio + 7) = 1 << PIN_WR;
775   *(gpio + 10) = 1 << PIN_WR;
776   *(gpio + 10) = 0xffffec;
777
778   *(gpio + 0) = GPFSEL0_INPUT;
779   *(gpio + 1) = GPFSEL1_INPUT;
780   *(gpio + 2) = GPFSEL2_INPUT;
781
782   *(gpio + 7) = (REG_DATA << PIN_A0);
783   *(gpio + 7) = 1 << PIN_RD;
784
785   unsigned int value = *(gpio + 13);
786   while ((value=*(gpio + 13)) & (1 << PIN_TXN_IN_PROGRESS))
787     ;
788
789   *(gpio + 10) = 0xffffec;
790
791   value = (value >> 8) & 0xffff;
792
793   if ((address & 1) == 0)
794     return (value >> 8) & 0xff;  // EVEN, A0=0,UDS
795   else
796     return value & 0xff;  // ODD , A0=1,LDS
797 }
798
799 static inline unsigned int inline_read_32(unsigned int address) {
800   unsigned int a = inline_read_16(address);
801   unsigned int b = inline_read_16(address + 2);
802   return (a << 16) | b;
803 }
804
805 static inline uint32_t ps_read(uint8_t type, uint32_t addr) {
806   switch (type) {
807     case OP_TYPE_BYTE:
808       return inline_read_8(addr);
809     case OP_TYPE_WORD:
810       return inline_read_16(addr);
811     case OP_TYPE_LONGWORD:
812       return inline_read_32(addr);
813   }
814   // This shouldn't actually happen.
815   return 0;
816 }
817
818 static inline int32_t platform_read_check(uint8_t type, uint32_t addr, uint32_t *res) {
819   switch (cfg->platform->id) {
820     case PLATFORM_AMIGA:
821       switch (addr) {
822         case CIAAPRA:
823           if (mouse_hook_enabled && (mouse_buttons & 0x01)) {
824             rres = (uint32_t)ps_read(type, addr);
825             *res = (rres ^ 0x40);
826             return 1;
827           }
828           return 0;
829           break;
830         case CIAAICR:
831           if (kb_hook_enabled) {
832             rres = (uint32_t)ps_read(type, addr);
833             if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
834               rres |= 0x08;
835               if (!send_keypress)
836                 send_keypress = 1;
837             }
838             if (send_keypress == 2) {
839               send_keypress = 0;
840             }
841             *res = rres;
842             return 1;
843           }
844           return 0;
845           break;
846         case CIAADAT:
847           if (kb_hook_enabled) {
848             rres = (uint32_t)ps_read(type, addr);
849             uint8_t c = 0, t = 0;
850             pop_queued_key(&c, &t);
851             t ^= 0x01;
852             rres = ((c << 1) | t) ^ 0xFF;
853             send_keypress = 2;
854             *res = rres;
855             return 1;
856           }
857           return 0;
858           break;
859         case JOY0DAT:
860           if (mouse_hook_enabled) {
861             unsigned short result = (mouse_dy << 8) | (mouse_dx);
862             *res = (unsigned int)result;
863             return 1;
864           }
865           return 0;
866           break;
867         case POTGOR:
868           if (mouse_hook_enabled) {
869             unsigned short result = (unsigned short)ps_read(type, addr);
870             // bit 1 rmb, bit 2 mmb
871             if (mouse_buttons & 0x06) {
872               *res = (unsigned int)((result ^ ((mouse_buttons & 0x02) << 9))   // move rmb to bit 10
873                                   & (result ^ ((mouse_buttons & 0x04) << 6))); // move mmb to bit 8
874               return 1;
875             }
876             *res = (unsigned int)(result & 0xfffd);
877             return 1;
878           }
879           return 0;
880           break;
881         default:
882           break;
883       }
884
885       if (addr >= cfg->custom_low && addr < cfg->custom_high) {
886         if (addr >= PISCSI_OFFSET && addr < PISCSI_UPPER) {
887           *res = handle_piscsi_read(addr, type);
888           return 1;
889         }
890         if (addr >= PINET_OFFSET && addr < PINET_UPPER) {
891           *res = handle_pinet_read(addr, type);
892           return 1;
893         }
894         if (addr >= PIGFX_RTG_BASE && addr < PIGFX_UPPER) {
895           *res = rtg_read((addr & 0x0FFFFFFF), type);
896           return 1;
897         }
898         if (custom_read_amiga(cfg, addr, &target, type) != -1) {
899           *res = target;
900           return 1;
901         }
902       }
903       break;
904     default:
905       break;
906   }
907
908   if (ovl || (addr >= cfg->mapped_low && addr < cfg->mapped_high)) {
909     if (handle_mapped_read(cfg, addr, &target, type) != -1) {
910       *res = target;
911       return 1;
912     }
913   }
914
915   return 0;
916 }
917
918 unsigned int m68k_read_memory_8(unsigned int address) {
919   if (platform_read_check(OP_TYPE_BYTE, address, &platform_res)) {
920     return platform_res;
921   }
922
923   if (address & 0xFF000000)
924     return 0;
925
926   return (unsigned int)inline_read_8((uint32_t)address);
927 }
928
929 unsigned int m68k_read_memory_16(unsigned int address) {
930   if (platform_read_check(OP_TYPE_WORD, address, &platform_res)) {
931     return platform_res;
932   }
933
934   if (address & 0xFF000000)
935     return 0;
936
937   if (address & 0x01) {
938     return ((inline_read_8(address) << 8) | inline_read_8(address + 1));
939   }
940   return (unsigned int)inline_read_16((uint32_t)address);
941 }
942
943 unsigned int m68k_read_memory_32(unsigned int address) {
944   if (platform_read_check(OP_TYPE_LONGWORD, address, &platform_res)) {
945     return platform_res;
946   }
947
948   if (address & 0xFF000000)
949     return 0;
950
951   if (address & 0x01) {
952     uint32_t c = inline_read_8(address);
953     c |= (be16toh(inline_read_16(address+1)) << 8);
954     c |= (inline_read_8(address + 3) << 24);
955     return htobe32(c);
956   }
957   uint16_t a = inline_read_16(address);
958   uint16_t b = inline_read_16(address + 2);
959   return (a << 16) | b;
960 }
961
962 static inline int32_t platform_write_check(uint8_t type, uint32_t addr, uint32_t val) {
963   switch (cfg->platform->id) {
964     case PLATFORM_MAC:
965       switch (addr) {
966         case 0xEFFFFE: // VIA1?
967           if (val & 0x10 && !ovl) {
968               ovl = 1;
969               printf("[MAC] OVL on.\n");
970           } else if (ovl) {
971             ovl = 0;
972             printf("[MAC] OVL off.\n");
973           }
974           break;
975       }
976       break;
977     case PLATFORM_AMIGA:
978       switch (addr) {
979         case CIAAPRA:
980           if (ovl != (val & (1 << 0))) {
981             ovl = (val & (1 << 0));
982             printf("OVL:%x\n", ovl);
983           }
984           return 0;
985           break;
986         case SERDAT: {
987           char *serdat = (char *)&val;
988           // SERDAT word. see amiga dev docs appendix a; upper byte is control codes, and bit 0 is always 1.
989           // ignore this upper byte as it's not viewable data, only display lower byte.
990           printf("%c", serdat[0]);
991           return 0;
992           break;
993         }
994         case INTENA:
995           // This code is kind of strange and should probably be reworked/revoked.
996           if (!(val & 0x8000)) {
997             if (val & 0x04) {
998               int2_enabled = 0;
999             }
1000           }
1001           else if (val & 0x04) {
1002             int2_enabled = 1;
1003           }
1004           return 0;
1005           break;
1006         default:
1007           break;
1008       }
1009
1010       if (addr >= cfg->custom_low && addr < cfg->custom_high) {
1011         if (addr >= PISCSI_OFFSET && addr < PISCSI_UPPER) {
1012           handle_piscsi_write(addr, val, type);
1013           return 1;
1014         }
1015         if (addr >= PINET_OFFSET && addr < PINET_UPPER) {
1016           handle_pinet_write(addr, val, type);
1017           return 1;
1018         }
1019         if (addr >= PIGFX_RTG_BASE && addr < PIGFX_UPPER) {
1020           rtg_write((addr & 0x0FFFFFFF), val, type);
1021           return 1;
1022         }
1023         if (custom_write_amiga(cfg, addr, val, type) != -1) {
1024           return 1;
1025         }
1026       }
1027       break;
1028     default:
1029       break;
1030   }
1031
1032   if (ovl || (addr >= cfg->mapped_low && addr < cfg->mapped_high)) {
1033     if (handle_mapped_write(cfg, addr, val, type) != -1) {
1034       return 1;
1035     }
1036   }
1037
1038   return 0;
1039 }
1040
1041 void m68k_write_memory_8(unsigned int address, unsigned int value) {
1042   if (platform_write_check(OP_TYPE_BYTE, address, value))
1043     return;
1044
1045   if (address & 0xFF000000)
1046     return;
1047
1048   inline_write_8((uint32_t)address, value);
1049   return;
1050 }
1051
1052 void m68k_write_memory_16(unsigned int address, unsigned int value) {
1053   if (platform_write_check(OP_TYPE_WORD, address, value))
1054     return;
1055
1056   if (address & 0xFF000000)
1057     return;
1058
1059   if (address & 0x01) {
1060     inline_write_8(value & 0xFF, address);
1061     inline_write_8((value >> 8) & 0xFF, address + 1);
1062     return;
1063   }
1064
1065   inline_write_16((uint32_t)address, value);
1066   return;
1067 }
1068
1069 void m68k_write_memory_32(unsigned int address, unsigned int value) {
1070   if (platform_write_check(OP_TYPE_LONGWORD, address, value))
1071     return;
1072
1073   if (address & 0xFF000000)
1074     return;
1075
1076   if (address & 0x01) {
1077     inline_write_8(value & 0xFF, address);
1078     inline_write_16(htobe16(((value >> 8) & 0xFFFF)), address + 1);
1079     inline_write_8((value >> 24), address + 3);
1080     return;
1081   }
1082
1083   inline_write_16(address, value >> 16);
1084   inline_write_16(address + 2, value);
1085   return;
1086 }