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