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)
421 printf("[*] Sending NMI\n");
438 void cpu_pulse_reset(void) {
441 // printf("Status Reg%x\n",read_reg());
444 // printf("Status Reg%x\n",read_reg());
445 if (cfg->platform->handle_reset)
446 cfg->platform->handle_reset(cfg);
449 m68k_write_memory_8(0xbfe201, 0x0001); // AMIGA OVL
450 m68k_write_memory_8(0xbfe001, 0x0001); // AMIGA OVL high (ROM@0x0)
455 int cpu_irq_ack(int level) {
456 printf("cpu irq ack\n");
460 static unsigned int target = 0;
461 static uint8_t send_keypress = 0;
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);
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); \
476 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
477 return handle_pinet_read(address, a); \
479 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
480 return rtg_read((address & 0x0FFFFFFF), a); \
482 if (custom_read_amiga(cfg, address, &target, a) != -1) { \
491 if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
492 if (handle_mapped_read(cfg, address, &target, a) != -1) \
496 unsigned int m68k_read_memory_8(unsigned int address) {
497 PLATFORM_CHECK_READ(OP_TYPE_BYTE);
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);
504 cpu_emulation_running = 0;
508 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
509 stop_cpu_emulation(1);
513 if (address & 0xFF000000)
516 unsigned char result = (unsigned int)read8((uint32_t)address);
518 if (mouse_hook_enabled) {
519 if (address == CIAAPRA) {
520 if (mouse_buttons & 0x01) {
521 //mouse_buttons -= 1;
522 return (unsigned int)(result ^ 0x40);
525 return (unsigned int)result;
528 if (kb_hook_enabled) {
529 if (address == CIAAICR) {
530 if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
535 if (send_keypress == 2) {
541 if (address == CIAADAT) {
543 uint8_t c = 0, t = 0;
544 pop_queued_key(&c, &t);
546 result = ((c << 1) | t) ^ 0xFF;
556 unsigned int m68k_read_memory_16(unsigned int address) {
557 PLATFORM_CHECK_READ(OP_TYPE_WORD);
559 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
560 stop_cpu_emulation(1);
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);
568 cpu_emulation_running = 0;
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;
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);
584 return (unsigned int)result;
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));
592 return (unsigned int)(result & 0xFFFD);
596 if (address & 0xFF000000)
599 if (address & 0x01) {
600 return ((read8(address) << 8) | read8(address + 1));
602 return (unsigned int)read16((uint32_t)address);
605 unsigned int m68k_read_memory_32(unsigned int address) {
606 PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
608 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
609 stop_cpu_emulation(1);
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);
617 cpu_emulation_running = 0;
621 if (address & 0xFF000000)
624 if (address & 0x01) {
625 uint32_t c = read8(address);
626 c |= (be16toh(read16(address+1)) << 8);
627 c |= (read8(address + 3) << 24);
630 uint16_t a = read16(address);
631 uint16_t b = read16(address + 2);
632 return (a << 16) | b;
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); \
642 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
643 handle_pinet_write(address, value, a); \
645 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
646 rtg_write((address & 0x0FFFFFFF), value, a); \
649 if (custom_write_amiga(cfg, address, value, a) != -1) { \
658 if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
659 if (handle_mapped_write(cfg, address, value, a) != -1) \
663 void m68k_write_memory_8(unsigned int address, unsigned int value) {
664 PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
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);
670 cpu_emulation_running = 0;
674 if (address == 0xbfe001) {
675 if (ovl != (value & (1 << 0))) {
676 ovl = (value & (1 << 0));
677 printf("OVL:%x\n", ovl);
681 if (address & 0xFF000000)
684 write8((uint32_t)address, value);
688 void m68k_write_memory_16(unsigned int address, unsigned int value) {
689 PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
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);
695 cpu_emulation_running = 0;
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]);
705 if (address == 0xDFF09A) {
706 if (!(value & 0x8000)) {
711 else if (value & 0x04) {
716 if (address & 0xFF000000)
720 printf("Unaligned WORD write!\n");
722 write16((uint32_t)address, value);
726 void m68k_write_memory_32(unsigned int address, unsigned int value) {
727 PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
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);
733 cpu_emulation_running = 0;
737 if (address & 0xFF000000)
741 printf("Unaligned LONGWORD write!\n");
743 write16(address, value >> 16);
744 write16(address + 2, value);