]> git.sesse.net Git - pistorm/blob - emulator.c
mark when an nmi is sent in the output
[pistorm] / emulator.c
1 #include <assert.h>
2 #include <dirent.h>
3 #include <endian.h>
4 #include <fcntl.h>
5 #include <pthread.h>
6 #include <sched.h>
7 #include <signal.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 #include <sys/ioctl.h>
17 #include "m68k.h"
18 #include "main.h"
19 #include "platforms/platforms.h"
20 #include "input/input.h"
21
22 #include "platforms/amiga/Gayle.h"
23 #include "platforms/amiga/gayle-ide/ide.h"
24 #include "platforms/amiga/amiga-registers.h"
25 #include "platforms/amiga/rtg/rtg.h"
26 #include "platforms/amiga/hunk-reloc.h"
27 #include "platforms/amiga/piscsi/piscsi.h"
28 #include "platforms/amiga/piscsi/piscsi-enums.h"
29 #include "platforms/amiga/net/pi-net.h"
30 #include "platforms/amiga/net/pi-net-enums.h"
31 #include "gpio/ps_protocol.h"
32
33 unsigned char read_ranges;
34 unsigned int read_addr[8];
35 unsigned int read_upper[8];
36 unsigned char *read_data[8];
37 unsigned char write_ranges;
38 unsigned int write_addr[8];
39 unsigned int write_upper[8];
40 unsigned char *write_data[8];
41
42 int kb_hook_enabled = 0;
43 int mouse_hook_enabled = 0;
44 int cpu_emulation_running = 1;
45
46 char mouse_dx = 0, mouse_dy = 0;
47 char mouse_buttons = 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;
56 uint8_t realtime_disassembly, int2_enabled = 0;
57 uint32_t do_disasm = 0, old_level;
58
59 char disasm_buf[4096];
60
61 #define KICKBASE 0xF80000
62 #define KICKSIZE 0x7FFFF
63
64 int mem_fd, mouse_fd = -1, keyboard_fd = -1;
65 int mem_fd_gpclk;
66 int irq;
67 int gayleirq;
68
69 //#define MUSASHI_HAX
70
71 #ifdef MUSASHI_HAX
72 #include "m68kcpu.h"
73 extern m68ki_cpu_core m68ki_cpu;
74 extern int m68ki_initial_cycles;
75 extern int m68ki_remaining_cycles;
76
77 #define M68K_SET_IRQ(i) old_level = CPU_INT_LEVEL; \
78         CPU_INT_LEVEL = (i << 8); \
79         if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700) \
80                 m68ki_cpu.nmi_pending = TRUE;
81 #define M68K_END_TIMESLICE      m68ki_initial_cycles = GET_CYCLES(); \
82         SET_CYCLES(0);
83 #else
84 #define M68K_SET_IRQ m68k_set_irq
85 #define M68K_END_TIMESLICE m68k_end_timeslice()
86 #endif
87
88 #define NOP asm("nop"); asm("nop"); asm("nop"); asm("nop");
89
90 // Configurable emulator options
91 unsigned int cpu_type = M68K_CPU_TYPE_68000;
92 unsigned int loop_cycles = 300, irq_status = 0;
93 struct emulator_config *cfg = NULL;
94 char keyboard_file[256] = "/dev/input/event1";
95
96 uint64_t trig_irq = 0, serv_irq = 0;
97
98 void *iplThread(void *args) {
99   printf("IPL thread running\n");
100
101   while (1) {
102     if (!gpio_get_irq()) {
103       irq = 1;
104       M68K_END_TIMESLICE;
105     }
106     else {
107       irq = 0;
108     }
109
110     if (gayle_ide_enabled) {
111       if (((gayle_int & 0x80) || gayle_a4k_int) && (get_ide(0)->drive[0].intrq || get_ide(0)->drive[1].intrq)) {
112         //get_ide(0)->drive[0].intrq = 0;
113         gayleirq = 1;
114         M68K_END_TIMESLICE;
115       }
116       else
117         gayleirq = 0;
118     }
119     //usleep(0);
120     NOP NOP NOP NOP NOP NOP
121     NOP NOP NOP NOP NOP NOP
122     NOP NOP NOP NOP NOP NOP
123     NOP NOP NOP NOP NOP NOP
124     NOP NOP NOP NOP NOP NOP
125     NOP NOP NOP NOP NOP NOP
126     NOP NOP NOP NOP NOP NOP
127     NOP NOP NOP NOP NOP NOP
128     NOP NOP NOP NOP NOP NOP
129     NOP NOP NOP NOP NOP NOP
130     NOP NOP NOP NOP NOP NOP
131     NOP NOP NOP NOP NOP NOP
132   }
133   return args;
134 }
135
136 void stop_cpu_emulation(uint8_t disasm_cur) {
137   M68K_END_TIMESLICE;
138   if (disasm_cur) {
139     m68k_disassemble(disasm_buf, m68k_get_reg(NULL, M68K_REG_PC), cpu_type);
140     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), \
141             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));
142     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), \
143             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));
144     printf("%.8X (%.8X)]] %s\n", m68k_get_reg(NULL, M68K_REG_PC), (m68k_get_reg(NULL, M68K_REG_PC) & 0xFFFFFF), disasm_buf);
145     realtime_disassembly = 1;
146   }
147
148   cpu_emulation_running = 0;
149   do_disasm = 0;
150 }
151
152 unsigned int ovl;
153 static volatile unsigned char maprom;
154
155 void sigint_handler(int sig_num) {
156   //if (sig_num) { }
157   //cpu_emulation_running = 0;
158
159   //return;
160   printf("Received sigint %d, exiting.\n", sig_num);
161   if (mouse_fd != -1)
162     close(mouse_fd);
163   if (mem_fd)
164     close(mem_fd);
165
166   if (cfg->platform->shutdown) {
167     cfg->platform->shutdown(cfg);
168   }
169
170   printf("IRQs triggered: %lld\n", trig_irq);
171   printf("IRQs serviced: %lld\n", serv_irq);
172
173   exit(0);
174 }
175
176 int main(int argc, char *argv[]) {
177   int g;
178   //const struct sched_param priority = {99};
179
180   // Some command line switch stuffles
181   for (g = 1; g < argc; g++) {
182     if (strcmp(argv[g], "--cpu_type") == 0 || strcmp(argv[g], "--cpu") == 0) {
183       if (g + 1 >= argc) {
184         printf("%s switch found, but no CPU type specified.\n", argv[g]);
185       } else {
186         g++;
187         cpu_type = get_m68k_cpu_type(argv[g]);
188       }
189     }
190     else if (strcmp(argv[g], "--config-file") == 0 || strcmp(argv[g], "--config") == 0) {
191       if (g + 1 >= argc) {
192         printf("%s switch found, but no config filename specified.\n", argv[g]);
193       } else {
194         g++;
195         cfg = load_config_file(argv[g]);
196       }
197     }
198     else if (strcmp(argv[g], "--keyboard-file") == 0 || strcmp(argv[g], "--kbfile") == 0) {
199       if (g + 1 >= argc) {
200         printf("%s switch found, but no keyboard device path specified.\n", argv[g]);
201       } else {
202         g++;
203         strcpy(keyboard_file, argv[g]);
204       }
205     }
206   }
207
208   if (!cfg) {
209     printf("No config file specified. Trying to load default.cfg...\n");
210     cfg = load_config_file("default.cfg");
211     if (!cfg) {
212       printf("Couldn't load default.cfg, empty emulator config will be used.\n");
213       cfg = (struct emulator_config *)calloc(1, sizeof(struct emulator_config));
214       if (!cfg) {
215         printf("Failed to allocate memory for emulator config!\n");
216         return 1;
217       }
218       memset(cfg, 0x00, sizeof(struct emulator_config));
219     }
220   }
221
222   if (cfg) {
223     if (cfg->cpu_type) cpu_type = cfg->cpu_type;
224     if (cfg->loop_cycles) loop_cycles = cfg->loop_cycles;
225
226     if (!cfg->platform)
227       cfg->platform = make_platform_config("none", "generic");
228     cfg->platform->platform_initial_setup(cfg);
229   }
230
231   if (cfg->mouse_enabled) {
232     mouse_fd = open(cfg->mouse_file, O_RDONLY | O_NONBLOCK);
233     if (mouse_fd == -1) {
234       printf("Failed to open %s, can't enable mouse hook.\n", cfg->mouse_file);
235       cfg->mouse_enabled = 0;
236     }
237   }
238
239   keyboard_fd = open(keyboard_file, O_RDONLY | O_NONBLOCK);
240   if (keyboard_fd == -1) {
241     printf("Failed to open keyboard event source.\n");
242   }
243
244   InitGayle();
245
246   signal(SIGINT, sigint_handler);
247   /*setup_io();
248
249   //goto skip_everything;
250
251   // Enable 200MHz CLK output on GPIO4, adjust divider and pll source depending
252   // on pi model
253   printf("Enable 200MHz GPCLK0 on GPIO4\n");
254   gpio_enable_200mhz();
255
256   // reset cpld statemachine first
257
258   write_reg(0x01);
259   usleep(100);
260   usleep(1500);
261   write_reg(0x00);
262   usleep(100);
263
264   // reset amiga and statemachine
265   skip_everything:;
266
267   usleep(1500);
268
269   m68k_init();
270   printf("Setting CPU type to %d.\n", cpu_type);
271   m68k_set_cpu_type(cpu_type);
272   cpu_pulse_reset();
273
274   if (maprom == 1) {
275     m68k_set_reg(M68K_REG_PC, 0xF80002);
276   } else {
277     m68k_set_reg(M68K_REG_PC, 0x0);
278   }*/
279   ps_setup_protocol();
280   ps_reset_state_machine();
281   ps_pulse_reset();
282
283   usleep(1500);
284   m68k_init();
285   printf("Setting CPU type to %d.\n", cpu_type);
286   m68k_set_cpu_type(cpu_type);
287   cpu_pulse_reset();
288
289   char c = 0, c_code = 0, c_type = 0;
290   uint32_t last_irq = 0;
291
292   pthread_t id;
293   int err;
294   err = pthread_create(&id, NULL, &iplThread, NULL);
295   if (err != 0)
296     printf("can't create IPL thread :[%s]", strerror(err));
297   else
298     printf("IPL Thread created successfully\n");
299
300   m68k_pulse_reset();
301   while (42) {
302     if (mouse_hook_enabled) {
303       get_mouse_status(&mouse_dx, &mouse_dy, &mouse_buttons);
304     }
305
306     if (realtime_disassembly && (do_disasm || cpu_emulation_running)) {
307       m68k_disassemble(disasm_buf, m68k_get_reg(NULL, M68K_REG_PC), cpu_type);
308       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), \
309               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));
310       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), \
311               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));
312       printf("%.8X (%.8X)]] %s\n", m68k_get_reg(NULL, M68K_REG_PC), (m68k_get_reg(NULL, M68K_REG_PC) & 0xFFFFFF), disasm_buf);
313       if (do_disasm)
314         do_disasm--;
315       m68k_execute(1);
316     }
317     else {
318       if (cpu_emulation_running)
319         m68k_execute(loop_cycles);
320     }
321
322     if (irq) {
323       unsigned int status = read_reg();
324       if (((status & 0xe000) >> 13) != last_irq) {
325         last_irq = ((status & 0xe000) >> 13);
326         serv_irq++;
327         M68K_SET_IRQ(last_irq);
328       }
329     }
330     else if (gayleirq && int2_enabled) {
331       write16(0xdff09c, 0x8000 | (1 << 3));
332       last_irq = 2;
333       M68K_SET_IRQ(2);
334     }
335     else {
336       if (last_irq != 0) {
337         last_irq = 0;
338         M68K_SET_IRQ(0);
339       }
340     }
341
342     while (get_key_char(&c, &c_code, &c_type)) {
343       if (c && c == cfg->keyboard_toggle_key && !kb_hook_enabled) {
344         kb_hook_enabled = 1;
345         printf("Keyboard hook enabled.\n");
346       }
347       else if (kb_hook_enabled) {
348         if (c == 0x1B && c_type) {
349           kb_hook_enabled = 0;
350           printf("Keyboard hook disabled.\n");
351         }
352         else {
353           /*printf("Key code: %.2X - ", c_code);
354           switch (c_type) {
355             case 0:
356               printf("released.\n");
357               break;
358             case 1:
359               printf("pressed.\n");
360               break;
361             case 2:
362               printf("repeat.\n");
363               break;
364             default:
365               printf("unknown.\n");
366               break;
367           }*/
368           if (queue_keypress(c_code, c_type, cfg->platform->id) && int2_enabled) {
369             last_irq = 2;
370             M68K_SET_IRQ(2);
371           }
372         }
373       }
374
375       if (!kb_hook_enabled && c_type) {
376         if (c && c == cfg->mouse_toggle_key) {
377           mouse_hook_enabled ^= 1;
378           printf("Mouse hook %s.\n", mouse_hook_enabled ? "enabled" : "disabled");
379           mouse_dx = mouse_dy = mouse_buttons = 0;
380         }
381         if (c == 'r') {
382           cpu_emulation_running ^= 1;
383           printf("CPU emulation is now %s\n", cpu_emulation_running ? "running" : "stopped");
384         }
385         if (c == 'g') {
386           realtime_graphics_debug ^= 1;
387           printf("Real time graphics debug is now %s\n", realtime_graphics_debug ? "on" : "off");
388         }
389         if (c == 'R') {
390           cpu_pulse_reset();
391           //m68k_pulse_reset();
392           printf("CPU emulation reset.\n");
393         }
394         if (c == 'q') {
395           printf("Quitting and exiting emulator.\n");
396           goto stop_cpu_emulation;
397         }
398         if (c == 'd') {
399           realtime_disassembly ^= 1;
400           do_disasm = 1;
401           printf("Real time disassembly is now %s\n", realtime_disassembly ? "on" : "off");
402         }
403         if (c == 'D') {
404           int r = get_mapped_item_by_address(cfg, 0x08000000);
405           if (r != -1) {
406             printf("Dumping first 16MB of mapped range %d.\n", r);
407             FILE *dmp = fopen("./memdmp.bin", "wb+");
408             fwrite(cfg->map_data[r], 16 * SIZE_MEGA, 1, dmp);
409             fclose(dmp);
410           }
411         }
412         if (c == 's' && realtime_disassembly) {
413           do_disasm = 1;
414         }
415         if (c == 'S' && realtime_disassembly) {
416           do_disasm = 128;
417         }
418
419         // pause pressed; trigger nmi (int level 7)
420         if (c == 0x01) {
421           printf("[*] Sending NMI\n");
422           m68k_set_irq(7);
423         }
424       }
425     }
426   }
427
428   stop_cpu_emulation:;
429
430   if (mouse_fd != -1)
431     close(mouse_fd);
432   if (mem_fd)
433     close(mem_fd);
434
435   return 0;
436 }
437
438 void cpu_pulse_reset(void) {
439   ps_pulse_reset();
440   //write_reg(0x00);
441   // printf("Status Reg%x\n",read_reg());
442   //usleep(100000);
443   //write_reg(0x02);
444   // printf("Status Reg%x\n",read_reg());
445   if (cfg->platform->handle_reset)
446     cfg->platform->handle_reset(cfg);
447
448   ovl = 1;
449   m68k_write_memory_8(0xbfe201, 0x0001);  // AMIGA OVL
450   m68k_write_memory_8(0xbfe001, 0x0001);  // AMIGA OVL high (ROM@0x0)
451
452   m68k_pulse_reset();
453 }
454
455 int cpu_irq_ack(int level) {
456   printf("cpu irq ack\n");
457   return level;
458 }
459
460 static unsigned int target = 0;
461 static uint8_t send_keypress = 0;
462
463 uint8_t cdtv_dmac_reg_idx_read();
464 void cdtv_dmac_reg_idx_write(uint8_t value);
465 uint32_t cdtv_dmac_read(uint32_t address, uint8_t type);
466 void cdtv_dmac_write(uint32_t address, uint32_t value, uint8_t type);
467
468 #define PLATFORM_CHECK_READ(a) \
469   if (address >= cfg->custom_low && address < cfg->custom_high) { \
470     unsigned int target = 0; \
471     switch(cfg->platform->id) { \
472       case PLATFORM_AMIGA: { \
473         if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
474           return handle_piscsi_read(address, a); \
475         } \
476         if (address >= PINET_OFFSET && address < PINET_UPPER) { \
477           return handle_pinet_read(address, a); \
478         } \
479         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
480           return rtg_read((address & 0x0FFFFFFF), a); \
481         } \
482         if (custom_read_amiga(cfg, address, &target, a) != -1) { \
483           return target; \
484         } \
485         break; \
486       } \
487       default: \
488         break; \
489     } \
490   } \
491   if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
492     if (handle_mapped_read(cfg, address, &target, a) != -1) \
493       return target; \
494   }
495
496 unsigned int m68k_read_memory_8(unsigned int address) {
497   PLATFORM_CHECK_READ(OP_TYPE_BYTE);
498
499   /*if (address >= 0xE90000 && address < 0xF00000) {
500     printf("BYTE read from DMAC @%.8X:", address);
501     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_BYTE);
502     printf("%.2X\n", v);
503     M68K_END_TIMESLICE;
504     cpu_emulation_running = 0;
505     return v;
506   }*/
507
508   /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
509     stop_cpu_emulation(1);
510   }*/
511
512
513   if (address & 0xFF000000)
514     return 0;
515
516   unsigned char result = (unsigned int)read8((uint32_t)address);
517
518   if (mouse_hook_enabled) {
519     if (address == CIAAPRA) {
520       if (mouse_buttons & 0x01) {
521         //mouse_buttons -= 1;
522         return (unsigned int)(result ^ 0x40);
523       }
524       else
525           return (unsigned int)result;
526     }
527   }
528   if (kb_hook_enabled) {
529     if (address == CIAAICR) {
530       if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
531         result |= 0x08;
532         if (!send_keypress)
533           send_keypress = 1;
534       }
535       if (send_keypress == 2) {
536         result |= 0x02;
537         send_keypress = 0;
538       }
539       return result;
540     }
541     if (address == CIAADAT) {
542       if (send_keypress) {
543         uint8_t c = 0, t = 0;
544         pop_queued_key(&c, &t);
545         t ^= 0x01;
546         result = ((c << 1) | t) ^ 0xFF;
547         send_keypress = 2;
548       }
549       return result;
550     }
551   }
552
553   return result;
554 }
555
556 unsigned int m68k_read_memory_16(unsigned int address) {
557   PLATFORM_CHECK_READ(OP_TYPE_WORD);
558
559   /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
560     stop_cpu_emulation(1);
561   }*/
562
563   /*if (address >= 0xE90000 && address < 0xF00000) {
564     printf("WORD read from DMAC @%.8X:", address);
565     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_WORD);
566     printf("%.2X\n", v);
567     M68K_END_TIMESLICE;
568     cpu_emulation_running = 0;
569     return v;
570   }*/
571
572   if (mouse_hook_enabled) {
573     if (address == JOY0DAT) {
574       // Forward mouse valueses to Amyga.
575       unsigned short result = (mouse_dy << 8) | (mouse_dx);
576       return (unsigned int)result;
577     }
578     /*if (address == CIAAPRA) {
579       unsigned short result = (unsigned int)read16((uint32_t)address);
580       if (mouse_buttons & 0x01) {
581         return (unsigned int)(result | 0x40);
582       }
583       else
584           return (unsigned int)result;
585     }*/
586     if (address == POTGOR) {
587       unsigned short result = (unsigned int)read16((uint32_t)address);
588       if (mouse_buttons & 0x02) {
589         return (unsigned int)(result ^ (0x2 << 9));
590       }
591       else
592           return (unsigned int)(result & 0xFFFD);
593     }
594   }
595
596   if (address & 0xFF000000)
597     return 0;
598
599   if (address & 0x01) {
600     return ((read8(address) << 8) | read8(address + 1));
601   }
602   return (unsigned int)read16((uint32_t)address);
603 }
604
605 unsigned int m68k_read_memory_32(unsigned int address) {
606   PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
607
608   /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
609     stop_cpu_emulation(1);
610   }*/
611
612   /*if (address >= 0xE90000 && address < 0xF00000) {
613     printf("LONGWORD read from DMAC @%.8X:", address);
614     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_LONGWORD);
615     printf("%.2X\n", v);
616     M68K_END_TIMESLICE;
617     cpu_emulation_running = 0;
618     return v;
619   }*/
620
621   if (address & 0xFF000000)
622     return 0;
623
624   if (address & 0x01) {
625     uint32_t c = read8(address);
626     c |= (be16toh(read16(address+1)) << 8);
627     c |= (read8(address + 3) << 24);
628     return htobe32(c);
629   }
630   uint16_t a = read16(address);
631   uint16_t b = read16(address + 2);
632   return (a << 16) | b;
633 }
634
635 #define PLATFORM_CHECK_WRITE(a) \
636   if (address >= cfg->custom_low && address < cfg->custom_high) { \
637     switch(cfg->platform->id) { \
638       case PLATFORM_AMIGA: { \
639         if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
640           handle_piscsi_write(address, value, a); \
641         } \
642         if (address >= PINET_OFFSET && address < PINET_UPPER) { \
643           handle_pinet_write(address, value, a); \
644         } \
645         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
646           rtg_write((address & 0x0FFFFFFF), value, a); \
647           return; \
648         } \
649         if (custom_write_amiga(cfg, address, value, a) != -1) { \
650           return; \
651         } \
652         break; \
653       } \
654       default: \
655         break; \
656     } \
657   } \
658   if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
659     if (handle_mapped_write(cfg, address, value, a) != -1) \
660       return; \
661   }
662
663 void m68k_write_memory_8(unsigned int address, unsigned int value) {
664   PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
665
666   /*if (address >= 0xE90000 && address < 0xF00000) {
667     printf("BYTE write to DMAC @%.8X: %.2X\n", address, value);
668     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_BYTE);
669     M68K_END_TIMESLICE;
670     cpu_emulation_running = 0;
671     return;
672   }*/
673
674   if (address == 0xbfe001) {
675     if (ovl != (value & (1 << 0))) {
676       ovl = (value & (1 << 0));
677       printf("OVL:%x\n", ovl);
678     }
679   }
680
681   if (address & 0xFF000000)
682     return;
683
684   write8((uint32_t)address, value);
685   return;
686 }
687
688 void m68k_write_memory_16(unsigned int address, unsigned int value) {
689   PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
690
691   /*if (address >= 0xE90000 && address < 0xF00000) {
692     printf("WORD write to DMAC @%.8X: %.4X\n", address, value);
693     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_WORD);
694     M68K_END_TIMESLICE;
695     cpu_emulation_running = 0;
696     return;
697   }*/
698
699   if (address == 0xDFF030) {
700     char *serdat = (char *)&value;
701     // SERDAT word. see amiga dev docs appendix a; upper byte is control codes, and bit 0 is always 1.
702     // ignore this upper byte as it's not viewable data, only display lower byte.
703     printf("%c", serdat[0]);
704   }
705   if (address == 0xDFF09A) {
706     if (!(value & 0x8000)) {
707       if (value & 0x04) {
708         int2_enabled = 0;
709       }
710     }
711     else if (value & 0x04) {
712       int2_enabled = 1;
713     }
714   }
715
716   if (address & 0xFF000000)
717     return;
718
719   if (address & 0x01)
720     printf("Unaligned WORD write!\n");
721
722   write16((uint32_t)address, value);
723   return;
724 }
725
726 void m68k_write_memory_32(unsigned int address, unsigned int value) {
727   PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
728
729   /*if (address >= 0xE90000 && address < 0xF00000) {
730     printf("LONGWORD write to DMAC @%.8X: %.8X\n", address, value);
731     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_LONGWORD);
732     M68K_END_TIMESLICE;
733     cpu_emulation_running = 0;
734     return;
735   }*/
736
737   if (address & 0xFF000000)
738     return;
739
740   if (address & 0x01)
741     printf("Unaligned LONGWORD write!\n");
742
743   write16(address, value >> 16);
744   write16(address + 2, value);
745   return;
746 }