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