]> git.sesse.net Git - pistorm/blob - emulator.c
change output for nmi slightly
[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       if (mouse_buttons & 0x02) {
590         return (unsigned int)(result ^ (0x2 << 9));
591       }
592       else
593           return (unsigned int)(result & 0xFFFD);
594     }
595   }
596
597   if (address & 0xFF000000)
598     return 0;
599
600   if (address & 0x01) {
601     return ((read8(address) << 8) | read8(address + 1));
602   }
603   return (unsigned int)read16((uint32_t)address);
604 }
605
606 unsigned int m68k_read_memory_32(unsigned int address) {
607   PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
608
609   /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
610     stop_cpu_emulation(1);
611   }*/
612
613   /*if (address >= 0xE90000 && address < 0xF00000) {
614     printf("LONGWORD read from DMAC @%.8X:", address);
615     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_LONGWORD);
616     printf("%.2X\n", v);
617     M68K_END_TIMESLICE;
618     cpu_emulation_running = 0;
619     return v;
620   }*/
621
622   if (address & 0xFF000000)
623     return 0;
624
625   if (address & 0x01) {
626     uint32_t c = read8(address);
627     c |= (be16toh(read16(address+1)) << 8);
628     c |= (read8(address + 3) << 24);
629     return htobe32(c);
630   }
631   uint16_t a = read16(address);
632   uint16_t b = read16(address + 2);
633   return (a << 16) | b;
634 }
635
636 #define PLATFORM_CHECK_WRITE(a) \
637   if (address >= cfg->custom_low && address < cfg->custom_high) { \
638     switch(cfg->platform->id) { \
639       case PLATFORM_AMIGA: { \
640         if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
641           handle_piscsi_write(address, value, a); \
642         } \
643         if (address >= PINET_OFFSET && address < PINET_UPPER) { \
644           handle_pinet_write(address, value, a); \
645         } \
646         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
647           rtg_write((address & 0x0FFFFFFF), value, a); \
648           return; \
649         } \
650         if (custom_write_amiga(cfg, address, value, a) != -1) { \
651           return; \
652         } \
653         break; \
654       } \
655       default: \
656         break; \
657     } \
658   } \
659   if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
660     if (handle_mapped_write(cfg, address, value, a) != -1) \
661       return; \
662   }
663
664 void m68k_write_memory_8(unsigned int address, unsigned int value) {
665   PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
666
667   /*if (address >= 0xE90000 && address < 0xF00000) {
668     printf("BYTE write to DMAC @%.8X: %.2X\n", address, value);
669     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_BYTE);
670     M68K_END_TIMESLICE;
671     cpu_emulation_running = 0;
672     return;
673   }*/
674
675   if (address == 0xbfe001) {
676     if (ovl != (value & (1 << 0))) {
677       ovl = (value & (1 << 0));
678       printf("OVL:%x\n", ovl);
679     }
680   }
681
682   if (address & 0xFF000000)
683     return;
684
685   write8((uint32_t)address, value);
686   return;
687 }
688
689 void m68k_write_memory_16(unsigned int address, unsigned int value) {
690   PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
691
692   /*if (address >= 0xE90000 && address < 0xF00000) {
693     printf("WORD write to DMAC @%.8X: %.4X\n", address, value);
694     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_WORD);
695     M68K_END_TIMESLICE;
696     cpu_emulation_running = 0;
697     return;
698   }*/
699
700   if (address == 0xDFF030) {
701     char *serdat = (char *)&value;
702     // SERDAT word. see amiga dev docs appendix a; upper byte is control codes, and bit 0 is always 1.
703     // ignore this upper byte as it's not viewable data, only display lower byte.
704     printf("%c", serdat[0]);
705   }
706   if (address == 0xDFF09A) {
707     if (!(value & 0x8000)) {
708       if (value & 0x04) {
709         int2_enabled = 0;
710       }
711     }
712     else if (value & 0x04) {
713       int2_enabled = 1;
714     }
715   }
716
717   if (address & 0xFF000000)
718     return;
719
720   if (address & 0x01)
721     printf("Unaligned WORD write!\n");
722
723   write16((uint32_t)address, value);
724   return;
725 }
726
727 void m68k_write_memory_32(unsigned int address, unsigned int value) {
728   PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
729
730   /*if (address >= 0xE90000 && address < 0xF00000) {
731     printf("LONGWORD write to DMAC @%.8X: %.8X\n", address, value);
732     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_LONGWORD);
733     M68K_END_TIMESLICE;
734     cpu_emulation_running = 0;
735     return;
736   }*/
737
738   if (address & 0xFF000000)
739     return;
740
741   if (address & 0x01)
742     printf("Unaligned LONGWORD write!\n");
743
744   write16(address, value >> 16);
745   write16(address + 2, value);
746   return;
747 }