]> git.sesse.net Git - pistorm/blob - emulator.c
send middle mouse button to amiga
[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       // pause pressed; trigger nmi (int level 7)
376       if (c == 0x01 && c_type) {
377         printf("[INT] Sending NMI\n");
378         last_irq = 7;
379         M68K_SET_IRQ(7);
380       }
381
382       if (!kb_hook_enabled && c_type) {
383         if (c && c == cfg->mouse_toggle_key) {
384           mouse_hook_enabled ^= 1;
385           printf("Mouse hook %s.\n", mouse_hook_enabled ? "enabled" : "disabled");
386           mouse_dx = mouse_dy = mouse_buttons = 0;
387         }
388         if (c == 'r') {
389           cpu_emulation_running ^= 1;
390           printf("CPU emulation is now %s\n", cpu_emulation_running ? "running" : "stopped");
391         }
392         if (c == 'g') {
393           realtime_graphics_debug ^= 1;
394           printf("Real time graphics debug is now %s\n", realtime_graphics_debug ? "on" : "off");
395         }
396         if (c == 'R') {
397           cpu_pulse_reset();
398           //m68k_pulse_reset();
399           printf("CPU emulation reset.\n");
400         }
401         if (c == 'q') {
402           printf("Quitting and exiting emulator.\n");
403           goto stop_cpu_emulation;
404         }
405         if (c == 'd') {
406           realtime_disassembly ^= 1;
407           do_disasm = 1;
408           printf("Real time disassembly is now %s\n", realtime_disassembly ? "on" : "off");
409         }
410         if (c == 'D') {
411           int r = get_mapped_item_by_address(cfg, 0x08000000);
412           if (r != -1) {
413             printf("Dumping first 16MB of mapped range %d.\n", r);
414             FILE *dmp = fopen("./memdmp.bin", "wb+");
415             fwrite(cfg->map_data[r], 16 * SIZE_MEGA, 1, dmp);
416             fclose(dmp);
417           }
418         }
419         if (c == 's' && realtime_disassembly) {
420           do_disasm = 1;
421         }
422         if (c == 'S' && realtime_disassembly) {
423           do_disasm = 128;
424         }
425       }
426     }
427   }
428
429   stop_cpu_emulation:;
430
431   if (mouse_fd != -1)
432     close(mouse_fd);
433   if (mem_fd)
434     close(mem_fd);
435
436   return 0;
437 }
438
439 void cpu_pulse_reset(void) {
440   ps_pulse_reset();
441   //write_reg(0x00);
442   // printf("Status Reg%x\n",read_reg());
443   //usleep(100000);
444   //write_reg(0x02);
445   // printf("Status Reg%x\n",read_reg());
446   if (cfg->platform->handle_reset)
447     cfg->platform->handle_reset(cfg);
448
449   ovl = 1;
450   m68k_write_memory_8(0xbfe201, 0x0001);  // AMIGA OVL
451   m68k_write_memory_8(0xbfe001, 0x0001);  // AMIGA OVL high (ROM@0x0)
452
453   m68k_pulse_reset();
454 }
455
456 int cpu_irq_ack(int level) {
457   printf("cpu irq ack\n");
458   return level;
459 }
460
461 static unsigned int target = 0;
462 static uint8_t send_keypress = 0;
463
464 uint8_t cdtv_dmac_reg_idx_read();
465 void cdtv_dmac_reg_idx_write(uint8_t value);
466 uint32_t cdtv_dmac_read(uint32_t address, uint8_t type);
467 void cdtv_dmac_write(uint32_t address, uint32_t value, uint8_t type);
468
469 #define PLATFORM_CHECK_READ(a) \
470   if (address >= cfg->custom_low && address < cfg->custom_high) { \
471     unsigned int target = 0; \
472     switch(cfg->platform->id) { \
473       case PLATFORM_AMIGA: { \
474         if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
475           return handle_piscsi_read(address, a); \
476         } \
477         if (address >= PINET_OFFSET && address < PINET_UPPER) { \
478           return handle_pinet_read(address, a); \
479         } \
480         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
481           return rtg_read((address & 0x0FFFFFFF), a); \
482         } \
483         if (custom_read_amiga(cfg, address, &target, a) != -1) { \
484           return target; \
485         } \
486         break; \
487       } \
488       default: \
489         break; \
490     } \
491   } \
492   if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
493     if (handle_mapped_read(cfg, address, &target, a) != -1) \
494       return target; \
495   }
496
497 unsigned int m68k_read_memory_8(unsigned int address) {
498   PLATFORM_CHECK_READ(OP_TYPE_BYTE);
499
500   /*if (address >= 0xE90000 && address < 0xF00000) {
501     printf("BYTE read from DMAC @%.8X:", address);
502     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_BYTE);
503     printf("%.2X\n", v);
504     M68K_END_TIMESLICE;
505     cpu_emulation_running = 0;
506     return v;
507   }*/
508
509   /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
510     stop_cpu_emulation(1);
511   }*/
512
513
514   if (address & 0xFF000000)
515     return 0;
516
517   unsigned char result = (unsigned int)read8((uint32_t)address);
518
519   if (mouse_hook_enabled) {
520     if (address == CIAAPRA) {
521       if (mouse_buttons & 0x01) {
522         //mouse_buttons -= 1;
523         return (unsigned int)(result ^ 0x40);
524       }
525       else
526           return (unsigned int)result;
527     }
528   }
529   if (kb_hook_enabled) {
530     if (address == CIAAICR) {
531       if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
532         result |= 0x08;
533         if (!send_keypress)
534           send_keypress = 1;
535       }
536       if (send_keypress == 2) {
537         result |= 0x02;
538         send_keypress = 0;
539       }
540       return result;
541     }
542     if (address == CIAADAT) {
543       if (send_keypress) {
544         uint8_t c = 0, t = 0;
545         pop_queued_key(&c, &t);
546         t ^= 0x01;
547         result = ((c << 1) | t) ^ 0xFF;
548         send_keypress = 2;
549       }
550       return result;
551     }
552   }
553
554   return result;
555 }
556
557 unsigned int m68k_read_memory_16(unsigned int address) {
558   PLATFORM_CHECK_READ(OP_TYPE_WORD);
559
560   /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
561     stop_cpu_emulation(1);
562   }*/
563
564   /*if (address >= 0xE90000 && address < 0xF00000) {
565     printf("WORD read from DMAC @%.8X:", address);
566     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_WORD);
567     printf("%.2X\n", v);
568     M68K_END_TIMESLICE;
569     cpu_emulation_running = 0;
570     return v;
571   }*/
572
573   if (mouse_hook_enabled) {
574     if (address == JOY0DAT) {
575       // Forward mouse valueses to Amyga.
576       unsigned short result = (mouse_dy << 8) | (mouse_dx);
577       return (unsigned int)result;
578     }
579     /*if (address == CIAAPRA) {
580       unsigned short result = (unsigned int)read16((uint32_t)address);
581       if (mouse_buttons & 0x01) {
582         return (unsigned int)(result | 0x40);
583       }
584       else
585           return (unsigned int)result;
586     }*/
587     if (address == POTGOR) {
588       unsigned short result = (unsigned int)read16((uint32_t)address);
589       // bit 1 rmb, bit 2 mmb
590       if (mouse_buttons & 0x06) {
591         return (unsigned int)((result ^ ((mouse_buttons & 0x02) << 9))   // move rmb to bit 10
592                             & (result ^ ((mouse_buttons & 0x04) << 6))); // move mmb to bit 8
593       }
594       return (unsigned int)(result & 0xfffd);
595     }
596   }
597
598   if (address & 0xFF000000)
599     return 0;
600
601   if (address & 0x01) {
602     return ((read8(address) << 8) | read8(address + 1));
603   }
604   return (unsigned int)read16((uint32_t)address);
605 }
606
607 unsigned int m68k_read_memory_32(unsigned int address) {
608   PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
609
610   /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
611     stop_cpu_emulation(1);
612   }*/
613
614   /*if (address >= 0xE90000 && address < 0xF00000) {
615     printf("LONGWORD read from DMAC @%.8X:", address);
616     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_LONGWORD);
617     printf("%.2X\n", v);
618     M68K_END_TIMESLICE;
619     cpu_emulation_running = 0;
620     return v;
621   }*/
622
623   if (address & 0xFF000000)
624     return 0;
625
626   if (address & 0x01) {
627     uint32_t c = read8(address);
628     c |= (be16toh(read16(address+1)) << 8);
629     c |= (read8(address + 3) << 24);
630     return htobe32(c);
631   }
632   uint16_t a = read16(address);
633   uint16_t b = read16(address + 2);
634   return (a << 16) | b;
635 }
636
637 #define PLATFORM_CHECK_WRITE(a) \
638   if (address >= cfg->custom_low && address < cfg->custom_high) { \
639     switch(cfg->platform->id) { \
640       case PLATFORM_AMIGA: { \
641         if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
642           handle_piscsi_write(address, value, a); \
643         } \
644         if (address >= PINET_OFFSET && address < PINET_UPPER) { \
645           handle_pinet_write(address, value, a); \
646         } \
647         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
648           rtg_write((address & 0x0FFFFFFF), value, a); \
649           return; \
650         } \
651         if (custom_write_amiga(cfg, address, value, a) != -1) { \
652           return; \
653         } \
654         break; \
655       } \
656       default: \
657         break; \
658     } \
659   } \
660   if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
661     if (handle_mapped_write(cfg, address, value, a) != -1) \
662       return; \
663   }
664
665 void m68k_write_memory_8(unsigned int address, unsigned int value) {
666   PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
667
668   /*if (address >= 0xE90000 && address < 0xF00000) {
669     printf("BYTE write to DMAC @%.8X: %.2X\n", address, value);
670     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_BYTE);
671     M68K_END_TIMESLICE;
672     cpu_emulation_running = 0;
673     return;
674   }*/
675
676   if (address == 0xbfe001) {
677     if (ovl != (value & (1 << 0))) {
678       ovl = (value & (1 << 0));
679       printf("OVL:%x\n", ovl);
680     }
681   }
682
683   if (address & 0xFF000000)
684     return;
685
686   write8((uint32_t)address, value);
687   return;
688 }
689
690 void m68k_write_memory_16(unsigned int address, unsigned int value) {
691   PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
692
693   /*if (address >= 0xE90000 && address < 0xF00000) {
694     printf("WORD write to DMAC @%.8X: %.4X\n", address, value);
695     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_WORD);
696     M68K_END_TIMESLICE;
697     cpu_emulation_running = 0;
698     return;
699   }*/
700
701   if (address == 0xDFF030) {
702     char *serdat = (char *)&value;
703     // SERDAT word. see amiga dev docs appendix a; upper byte is control codes, and bit 0 is always 1.
704     // ignore this upper byte as it's not viewable data, only display lower byte.
705     printf("%c", serdat[0]);
706   }
707   if (address == 0xDFF09A) {
708     if (!(value & 0x8000)) {
709       if (value & 0x04) {
710         int2_enabled = 0;
711       }
712     }
713     else if (value & 0x04) {
714       int2_enabled = 1;
715     }
716   }
717
718   if (address & 0xFF000000)
719     return;
720
721   if (address & 0x01)
722     printf("Unaligned WORD write!\n");
723
724   write16((uint32_t)address, value);
725   return;
726 }
727
728 void m68k_write_memory_32(unsigned int address, unsigned int value) {
729   PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
730
731   /*if (address >= 0xE90000 && address < 0xF00000) {
732     printf("LONGWORD write to DMAC @%.8X: %.8X\n", address, value);
733     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_LONGWORD);
734     M68K_END_TIMESLICE;
735     cpu_emulation_running = 0;
736     return;
737   }*/
738
739   if (address & 0xFF000000)
740     return;
741
742   if (address & 0x01)
743     printf("Unaligned LONGWORD write!\n");
744
745   write16(address, value >> 16);
746   write16(address + 2, value);
747   return;
748 }