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 // pause pressed; trigger nmi (int level 7)
376 if (c == 0x01 && c_type) {
377 printf("[INT] Sending NMI\n");
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;
389 cpu_emulation_running ^= 1;
390 printf("CPU emulation is now %s\n", cpu_emulation_running ? "running" : "stopped");
393 realtime_graphics_debug ^= 1;
394 printf("Real time graphics debug is now %s\n", realtime_graphics_debug ? "on" : "off");
398 //m68k_pulse_reset();
399 printf("CPU emulation reset.\n");
402 printf("Quitting and exiting emulator.\n");
403 goto stop_cpu_emulation;
406 realtime_disassembly ^= 1;
408 printf("Real time disassembly is now %s\n", realtime_disassembly ? "on" : "off");
411 int r = get_mapped_item_by_address(cfg, 0x08000000);
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);
419 if (c == 's' && realtime_disassembly) {
422 if (c == 'S' && realtime_disassembly) {
439 void cpu_pulse_reset(void) {
442 // printf("Status Reg%x\n",read_reg());
445 // printf("Status Reg%x\n",read_reg());
446 if (cfg->platform->handle_reset)
447 cfg->platform->handle_reset(cfg);
450 m68k_write_memory_8(0xbfe201, 0x0001); // AMIGA OVL
451 m68k_write_memory_8(0xbfe001, 0x0001); // AMIGA OVL high (ROM@0x0)
456 int cpu_irq_ack(int level) {
457 printf("cpu irq ack\n");
461 static unsigned int target = 0;
462 static uint8_t send_keypress = 0;
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);
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); \
477 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
478 return handle_pinet_read(address, a); \
480 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
481 return rtg_read((address & 0x0FFFFFFF), a); \
483 if (custom_read_amiga(cfg, address, &target, a) != -1) { \
492 if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
493 if (handle_mapped_read(cfg, address, &target, a) != -1) \
497 unsigned int m68k_read_memory_8(unsigned int address) {
498 PLATFORM_CHECK_READ(OP_TYPE_BYTE);
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);
505 cpu_emulation_running = 0;
509 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
510 stop_cpu_emulation(1);
514 if (address & 0xFF000000)
517 unsigned char result = (unsigned int)read8((uint32_t)address);
519 if (mouse_hook_enabled) {
520 if (address == CIAAPRA) {
521 if (mouse_buttons & 0x01) {
522 //mouse_buttons -= 1;
523 return (unsigned int)(result ^ 0x40);
526 return (unsigned int)result;
529 if (kb_hook_enabled) {
530 if (address == CIAAICR) {
531 if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
536 if (send_keypress == 2) {
542 if (address == CIAADAT) {
544 uint8_t c = 0, t = 0;
545 pop_queued_key(&c, &t);
547 result = ((c << 1) | t) ^ 0xFF;
557 unsigned int m68k_read_memory_16(unsigned int address) {
558 PLATFORM_CHECK_READ(OP_TYPE_WORD);
560 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
561 stop_cpu_emulation(1);
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);
569 cpu_emulation_running = 0;
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;
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);
585 return (unsigned int)result;
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
594 return (unsigned int)(result & 0xfffd);
598 if (address & 0xFF000000)
601 if (address & 0x01) {
602 return ((read8(address) << 8) | read8(address + 1));
604 return (unsigned int)read16((uint32_t)address);
607 unsigned int m68k_read_memory_32(unsigned int address) {
608 PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
610 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
611 stop_cpu_emulation(1);
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);
619 cpu_emulation_running = 0;
623 if (address & 0xFF000000)
626 if (address & 0x01) {
627 uint32_t c = read8(address);
628 c |= (be16toh(read16(address+1)) << 8);
629 c |= (read8(address + 3) << 24);
632 uint16_t a = read16(address);
633 uint16_t b = read16(address + 2);
634 return (a << 16) | b;
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); \
644 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
645 handle_pinet_write(address, value, a); \
647 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
648 rtg_write((address & 0x0FFFFFFF), value, a); \
651 if (custom_write_amiga(cfg, address, value, a) != -1) { \
660 if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
661 if (handle_mapped_write(cfg, address, value, a) != -1) \
665 void m68k_write_memory_8(unsigned int address, unsigned int value) {
666 PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
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);
672 cpu_emulation_running = 0;
676 if (address == 0xbfe001) {
677 if (ovl != (value & (1 << 0))) {
678 ovl = (value & (1 << 0));
679 printf("OVL:%x\n", ovl);
683 if (address & 0xFF000000)
686 write8((uint32_t)address, value);
690 void m68k_write_memory_16(unsigned int address, unsigned int value) {
691 PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
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);
697 cpu_emulation_running = 0;
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]);
707 if (address == 0xDFF09A) {
708 if (!(value & 0x8000)) {
713 else if (value & 0x04) {
718 if (address & 0xFF000000)
722 printf("Unaligned WORD write!\n");
724 write16((uint32_t)address, value);
728 void m68k_write_memory_32(unsigned int address, unsigned int value) {
729 PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
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);
735 cpu_emulation_running = 0;
739 if (address & 0xFF000000)
743 printf("Unaligned LONGWORD write!\n");
745 write16(address, value >> 16);
746 write16(address + 2, value);