14 #include <sys/types.h>
16 #include <sys/ioctl.h>
19 #include "platforms/platforms.h"
20 #include "input/input.h"
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"
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];
42 int kb_hook_enabled = 0;
43 int mouse_hook_enabled = 0;
44 int cpu_emulation_running = 1;
46 char mouse_dx = 0, mouse_dy = 0;
47 char mouse_buttons = 0;
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;
59 char disasm_buf[4096];
61 #define KICKBASE 0xF80000
62 #define KICKSIZE 0x7FFFF
64 int mem_fd, mouse_fd = -1, keyboard_fd = -1;
73 extern m68ki_cpu_core m68ki_cpu;
74 extern int m68ki_initial_cycles;
75 extern int m68ki_remaining_cycles;
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(); \
84 #define M68K_SET_IRQ m68k_set_irq
85 #define M68K_END_TIMESLICE m68k_end_timeslice()
88 #define NOP asm("nop"); asm("nop"); asm("nop"); asm("nop");
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";
96 uint64_t trig_irq = 0, serv_irq = 0;
98 void *iplThread(void *args) {
99 printf("IPL thread running\n");
102 if (!gpio_get_irq()) {
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;
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
136 void stop_cpu_emulation(uint8_t 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;
148 cpu_emulation_running = 0;
153 static volatile unsigned char maprom;
155 void sigint_handler(int sig_num) {
157 //cpu_emulation_running = 0;
160 printf("Received sigint %d, exiting.\n", sig_num);
166 if (cfg->platform->shutdown) {
167 cfg->platform->shutdown(cfg);
170 printf("IRQs triggered: %lld\n", trig_irq);
171 printf("IRQs serviced: %lld\n", serv_irq);
176 int main(int argc, char *argv[]) {
178 //const struct sched_param priority = {99};
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) {
184 printf("%s switch found, but no CPU type specified.\n", argv[g]);
187 cpu_type = get_m68k_cpu_type(argv[g]);
190 else if (strcmp(argv[g], "--config-file") == 0 || strcmp(argv[g], "--config") == 0) {
192 printf("%s switch found, but no config filename specified.\n", argv[g]);
195 cfg = load_config_file(argv[g]);
198 else if (strcmp(argv[g], "--keyboard-file") == 0 || strcmp(argv[g], "--kbfile") == 0) {
200 printf("%s switch found, but no keyboard device path specified.\n", argv[g]);
203 strcpy(keyboard_file, argv[g]);
209 printf("No config file specified. Trying to load default.cfg...\n");
210 cfg = load_config_file("default.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));
215 printf("Failed to allocate memory for emulator config!\n");
218 memset(cfg, 0x00, sizeof(struct emulator_config));
223 if (cfg->cpu_type) cpu_type = cfg->cpu_type;
224 if (cfg->loop_cycles) loop_cycles = cfg->loop_cycles;
227 cfg->platform = make_platform_config("none", "generic");
228 cfg->platform->platform_initial_setup(cfg);
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;
239 keyboard_fd = open(keyboard_file, O_RDONLY | O_NONBLOCK);
240 if (keyboard_fd == -1) {
241 printf("Failed to open keyboard event source.\n");
246 signal(SIGINT, sigint_handler);
249 //goto skip_everything;
251 // Enable 200MHz CLK output on GPIO4, adjust divider and pll source depending
253 printf("Enable 200MHz GPCLK0 on GPIO4\n");
254 gpio_enable_200mhz();
256 // reset cpld statemachine first
264 // reset amiga and statemachine
270 printf("Setting CPU type to %d.\n", cpu_type);
271 m68k_set_cpu_type(cpu_type);
275 m68k_set_reg(M68K_REG_PC, 0xF80002);
277 m68k_set_reg(M68K_REG_PC, 0x0);
280 ps_reset_state_machine();
285 printf("Setting CPU type to %d.\n", cpu_type);
286 m68k_set_cpu_type(cpu_type);
289 char c = 0, c_code = 0, c_type = 0;
290 uint32_t last_irq = 0;
294 err = pthread_create(&id, NULL, &iplThread, NULL);
296 printf("can't create IPL thread :[%s]", strerror(err));
298 printf("IPL Thread created successfully\n");
302 if (mouse_hook_enabled) {
303 get_mouse_status(&mouse_dx, &mouse_dy, &mouse_buttons);
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);
318 if (cpu_emulation_running)
319 m68k_execute(loop_cycles);
323 unsigned int status = read_reg();
324 if (((status & 0xe000) >> 13) != last_irq) {
325 last_irq = ((status & 0xe000) >> 13);
327 M68K_SET_IRQ(last_irq);
330 else if (gayleirq && int2_enabled) {
331 write16(0xdff09c, 0x8000 | (1 << 3));
342 while (get_key_char(&c, &c_code, &c_type)) {
343 if (c && c == cfg->keyboard_toggle_key && !kb_hook_enabled) {
345 printf("Keyboard hook enabled.\n");
347 else if (kb_hook_enabled) {
348 if (c == 0x1B && c_type) {
350 printf("Keyboard hook disabled.\n");
353 /*printf("Key code: %.2X - ", c_code);
356 printf("released.\n");
359 printf("pressed.\n");
365 printf("unknown.\n");
368 if (queue_keypress(c_code, c_type, cfg->platform->id) && int2_enabled) {
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;
382 cpu_emulation_running ^= 1;
383 printf("CPU emulation is now %s\n", cpu_emulation_running ? "running" : "stopped");
386 realtime_graphics_debug ^= 1;
387 printf("Real time graphics debug is now %s\n", realtime_graphics_debug ? "on" : "off");
391 //m68k_pulse_reset();
392 printf("CPU emulation reset.\n");
395 printf("Quitting and exiting emulator.\n");
396 goto stop_cpu_emulation;
399 realtime_disassembly ^= 1;
401 printf("Real time disassembly is now %s\n", realtime_disassembly ? "on" : "off");
404 int r = get_mapped_item_by_address(cfg, 0x08000000);
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);
412 if (c == 's' && realtime_disassembly) {
415 if (c == 'S' && realtime_disassembly) {
419 // pause pressed; trigger nmi (int level 7)
437 void cpu_pulse_reset(void) {
440 // printf("Status Reg%x\n",read_reg());
443 // printf("Status Reg%x\n",read_reg());
444 if (cfg->platform->handle_reset)
445 cfg->platform->handle_reset(cfg);
448 m68k_write_memory_8(0xbfe201, 0x0001); // AMIGA OVL
449 m68k_write_memory_8(0xbfe001, 0x0001); // AMIGA OVL high (ROM@0x0)
454 int cpu_irq_ack(int level) {
455 printf("cpu irq ack\n");
459 static unsigned int target = 0;
460 static uint8_t send_keypress = 0;
462 uint8_t cdtv_dmac_reg_idx_read();
463 void cdtv_dmac_reg_idx_write(uint8_t value);
464 uint32_t cdtv_dmac_read(uint32_t address, uint8_t type);
465 void cdtv_dmac_write(uint32_t address, uint32_t value, uint8_t type);
467 #define PLATFORM_CHECK_READ(a) \
468 if (address >= cfg->custom_low && address < cfg->custom_high) { \
469 unsigned int target = 0; \
470 switch(cfg->platform->id) { \
471 case PLATFORM_AMIGA: { \
472 if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
473 return handle_piscsi_read(address, a); \
475 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
476 return handle_pinet_read(address, a); \
478 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
479 return rtg_read((address & 0x0FFFFFFF), a); \
481 if (custom_read_amiga(cfg, address, &target, a) != -1) { \
490 if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
491 if (handle_mapped_read(cfg, address, &target, a) != -1) \
495 unsigned int m68k_read_memory_8(unsigned int address) {
496 PLATFORM_CHECK_READ(OP_TYPE_BYTE);
498 /*if (address >= 0xE90000 && address < 0xF00000) {
499 printf("BYTE read from DMAC @%.8X:", address);
500 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_BYTE);
503 cpu_emulation_running = 0;
507 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
508 stop_cpu_emulation(1);
512 if (address & 0xFF000000)
515 unsigned char result = (unsigned int)read8((uint32_t)address);
517 if (mouse_hook_enabled) {
518 if (address == CIAAPRA) {
519 if (mouse_buttons & 0x01) {
520 //mouse_buttons -= 1;
521 return (unsigned int)(result ^ 0x40);
524 return (unsigned int)result;
527 if (kb_hook_enabled) {
528 if (address == CIAAICR) {
529 if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
534 if (send_keypress == 2) {
540 if (address == CIAADAT) {
542 uint8_t c = 0, t = 0;
543 pop_queued_key(&c, &t);
545 result = ((c << 1) | t) ^ 0xFF;
555 unsigned int m68k_read_memory_16(unsigned int address) {
556 PLATFORM_CHECK_READ(OP_TYPE_WORD);
558 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
559 stop_cpu_emulation(1);
562 /*if (address >= 0xE90000 && address < 0xF00000) {
563 printf("WORD read from DMAC @%.8X:", address);
564 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_WORD);
567 cpu_emulation_running = 0;
571 if (mouse_hook_enabled) {
572 if (address == JOY0DAT) {
573 // Forward mouse valueses to Amyga.
574 unsigned short result = (mouse_dy << 8) | (mouse_dx);
575 return (unsigned int)result;
577 /*if (address == CIAAPRA) {
578 unsigned short result = (unsigned int)read16((uint32_t)address);
579 if (mouse_buttons & 0x01) {
580 return (unsigned int)(result | 0x40);
583 return (unsigned int)result;
585 if (address == POTGOR) {
586 unsigned short result = (unsigned int)read16((uint32_t)address);
587 if (mouse_buttons & 0x02) {
588 return (unsigned int)(result ^ (0x2 << 9));
591 return (unsigned int)(result & 0xFFFD);
595 if (address & 0xFF000000)
598 if (address & 0x01) {
599 return ((read8(address) << 8) | read8(address + 1));
601 return (unsigned int)read16((uint32_t)address);
604 unsigned int m68k_read_memory_32(unsigned int address) {
605 PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
607 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
608 stop_cpu_emulation(1);
611 /*if (address >= 0xE90000 && address < 0xF00000) {
612 printf("LONGWORD read from DMAC @%.8X:", address);
613 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_LONGWORD);
616 cpu_emulation_running = 0;
620 if (address & 0xFF000000)
623 if (address & 0x01) {
624 uint32_t c = read8(address);
625 c |= (be16toh(read16(address+1)) << 8);
626 c |= (read8(address + 3) << 24);
629 uint16_t a = read16(address);
630 uint16_t b = read16(address + 2);
631 return (a << 16) | b;
634 #define PLATFORM_CHECK_WRITE(a) \
635 if (address >= cfg->custom_low && address < cfg->custom_high) { \
636 switch(cfg->platform->id) { \
637 case PLATFORM_AMIGA: { \
638 if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
639 handle_piscsi_write(address, value, a); \
641 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
642 handle_pinet_write(address, value, a); \
644 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
645 rtg_write((address & 0x0FFFFFFF), value, a); \
648 if (custom_write_amiga(cfg, address, value, a) != -1) { \
657 if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
658 if (handle_mapped_write(cfg, address, value, a) != -1) \
662 void m68k_write_memory_8(unsigned int address, unsigned int value) {
663 PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
665 /*if (address >= 0xE90000 && address < 0xF00000) {
666 printf("BYTE write to DMAC @%.8X: %.2X\n", address, value);
667 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_BYTE);
669 cpu_emulation_running = 0;
673 if (address == 0xbfe001) {
674 if (ovl != (value & (1 << 0))) {
675 ovl = (value & (1 << 0));
676 printf("OVL:%x\n", ovl);
680 if (address & 0xFF000000)
683 write8((uint32_t)address, value);
687 void m68k_write_memory_16(unsigned int address, unsigned int value) {
688 PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
690 /*if (address >= 0xE90000 && address < 0xF00000) {
691 printf("WORD write to DMAC @%.8X: %.4X\n", address, value);
692 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_WORD);
694 cpu_emulation_running = 0;
698 if (address == 0xDFF030) {
699 char *serdat = (char *)&value;
700 // SERDAT word. see amiga dev docs appendix a; upper byte is control codes, and bit 0 is always 1.
701 // ignore this upper byte as it's not viewable data, only display lower byte.
702 printf("%c", serdat[0]);
704 if (address == 0xDFF09A) {
705 if (!(value & 0x8000)) {
710 else if (value & 0x04) {
715 if (address & 0xFF000000)
719 printf("Unaligned WORD write!\n");
721 write16((uint32_t)address, value);
725 void m68k_write_memory_32(unsigned int address, unsigned int value) {
726 PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
728 /*if (address >= 0xE90000 && address < 0xF00000) {
729 printf("LONGWORD write to DMAC @%.8X: %.8X\n", address, value);
730 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_LONGWORD);
732 cpu_emulation_running = 0;
736 if (address & 0xFF000000)
740 printf("Unaligned LONGWORD write!\n");
742 write16(address, value >> 16);
743 write16(address + 2, value);