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