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) {
432 void cpu_pulse_reset(void) {
435 // printf("Status Reg%x\n",read_reg());
438 // printf("Status Reg%x\n",read_reg());
439 if (cfg->platform->handle_reset)
440 cfg->platform->handle_reset(cfg);
443 m68k_write_memory_8(0xbfe201, 0x0001); // AMIGA OVL
444 m68k_write_memory_8(0xbfe001, 0x0001); // AMIGA OVL high (ROM@0x0)
449 int cpu_irq_ack(int level) {
450 printf("cpu irq ack\n");
454 static unsigned int target = 0;
455 static uint8_t send_keypress = 0;
457 uint8_t cdtv_dmac_reg_idx_read();
458 void cdtv_dmac_reg_idx_write(uint8_t value);
459 uint32_t cdtv_dmac_read(uint32_t address, uint8_t type);
460 void cdtv_dmac_write(uint32_t address, uint32_t value, uint8_t type);
462 #define PLATFORM_CHECK_READ(a) \
463 if (address >= cfg->custom_low && address < cfg->custom_high) { \
464 unsigned int target = 0; \
465 switch(cfg->platform->id) { \
466 case PLATFORM_AMIGA: { \
467 if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
468 return handle_piscsi_read(address, a); \
470 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
471 return handle_pinet_read(address, a); \
473 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
474 return rtg_read((address & 0x0FFFFFFF), a); \
476 if (custom_read_amiga(cfg, address, &target, a) != -1) { \
485 if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
486 if (handle_mapped_read(cfg, address, &target, a) != -1) \
490 unsigned int m68k_read_memory_8(unsigned int address) {
491 PLATFORM_CHECK_READ(OP_TYPE_BYTE);
493 /*if (address >= 0xE90000 && address < 0xF00000) {
494 printf("BYTE read from DMAC @%.8X:", address);
495 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_BYTE);
498 cpu_emulation_running = 0;
502 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
503 stop_cpu_emulation(1);
507 if (address & 0xFF000000)
510 unsigned char result = (unsigned int)read8((uint32_t)address);
512 if (mouse_hook_enabled) {
513 if (address == CIAAPRA) {
514 if (mouse_buttons & 0x01) {
515 //mouse_buttons -= 1;
516 return (unsigned int)(result ^ 0x40);
519 return (unsigned int)result;
522 if (kb_hook_enabled) {
523 if (address == CIAAICR) {
524 if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
529 if (send_keypress == 2) {
535 if (address == CIAADAT) {
537 uint8_t c = 0, t = 0;
538 pop_queued_key(&c, &t);
540 result = ((c << 1) | t) ^ 0xFF;
550 unsigned int m68k_read_memory_16(unsigned int address) {
551 PLATFORM_CHECK_READ(OP_TYPE_WORD);
553 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
554 stop_cpu_emulation(1);
557 /*if (address >= 0xE90000 && address < 0xF00000) {
558 printf("WORD read from DMAC @%.8X:", address);
559 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_WORD);
562 cpu_emulation_running = 0;
566 if (mouse_hook_enabled) {
567 if (address == JOY0DAT) {
568 // Forward mouse valueses to Amyga.
569 unsigned short result = (mouse_dy << 8) | (mouse_dx);
570 return (unsigned int)result;
572 /*if (address == CIAAPRA) {
573 unsigned short result = (unsigned int)read16((uint32_t)address);
574 if (mouse_buttons & 0x01) {
575 return (unsigned int)(result | 0x40);
578 return (unsigned int)result;
580 if (address == POTGOR) {
581 unsigned short result = (unsigned int)read16((uint32_t)address);
582 if (mouse_buttons & 0x02) {
583 return (unsigned int)(result ^ (0x2 << 9));
586 return (unsigned int)(result & 0xFFFD);
590 if (address & 0xFF000000)
593 if (address & 0x01) {
594 return ((read8(address) << 8) | read8(address + 1));
596 return (unsigned int)read16((uint32_t)address);
599 unsigned int m68k_read_memory_32(unsigned int address) {
600 PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
602 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
603 stop_cpu_emulation(1);
606 /*if (address >= 0xE90000 && address < 0xF00000) {
607 printf("LONGWORD read from DMAC @%.8X:", address);
608 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_LONGWORD);
611 cpu_emulation_running = 0;
615 if (address & 0xFF000000)
618 if (address & 0x01) {
619 uint32_t c = read8(address);
620 c |= (be16toh(read16(address+1)) << 8);
621 c |= (read8(address + 3) << 24);
624 uint16_t a = read16(address);
625 uint16_t b = read16(address + 2);
626 return (a << 16) | b;
629 #define PLATFORM_CHECK_WRITE(a) \
630 if (address >= cfg->custom_low && address < cfg->custom_high) { \
631 switch(cfg->platform->id) { \
632 case PLATFORM_AMIGA: { \
633 if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
634 handle_piscsi_write(address, value, a); \
636 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
637 handle_pinet_write(address, value, a); \
639 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
640 rtg_write((address & 0x0FFFFFFF), value, a); \
643 if (custom_write_amiga(cfg, address, value, a) != -1) { \
652 if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
653 if (handle_mapped_write(cfg, address, value, a) != -1) \
657 void m68k_write_memory_8(unsigned int address, unsigned int value) {
658 PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
660 /*if (address >= 0xE90000 && address < 0xF00000) {
661 printf("BYTE write to DMAC @%.8X: %.2X\n", address, value);
662 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_BYTE);
664 cpu_emulation_running = 0;
668 if (address == 0xbfe001) {
669 if (ovl != (value & (1 << 0))) {
670 ovl = (value & (1 << 0));
671 printf("OVL:%x\n", ovl);
675 if (address & 0xFF000000)
678 write8((uint32_t)address, value);
682 void m68k_write_memory_16(unsigned int address, unsigned int value) {
683 PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
685 /*if (address >= 0xE90000 && address < 0xF00000) {
686 printf("WORD write to DMAC @%.8X: %.4X\n", address, value);
687 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_WORD);
689 cpu_emulation_running = 0;
693 if (address == 0xDFF030) {
694 char *beb = (char *)&value;
695 printf("%c%c", beb[1], beb[0]);
697 if (address == 0xDFF09A) {
698 if (!(value & 0x8000)) {
703 else if (value & 0x04) {
708 if (address & 0xFF000000)
712 printf("Unaligned WORD write!\n");
714 write16((uint32_t)address, value);
718 void m68k_write_memory_32(unsigned int address, unsigned int value) {
719 PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
721 /*if (address >= 0xE90000 && address < 0xF00000) {
722 printf("LONGWORD write to DMAC @%.8X: %.8X\n", address, value);
723 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_LONGWORD);
725 cpu_emulation_running = 0;
729 if (address & 0xFF000000)
733 printf("Unaligned LONGWORD write!\n");
735 write16(address, value >> 16);
736 write16(address + 2, value);