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;
59 char disasm_buf[4096];
61 #define KICKBASE 0xF80000
62 #define KICKSIZE 0x7FFFF
64 int mem_fd, mouse_fd = -1, keyboard_fd = -1;
69 #define NOP asm("nop"); asm("nop"); asm("nop"); asm("nop");
71 // Configurable emulator options
72 unsigned int cpu_type = M68K_CPU_TYPE_68000;
73 unsigned int loop_cycles = 300;
74 struct emulator_config *cfg = NULL;
75 char keyboard_file[256] = "/dev/input/event1";
77 void *iplThread(void *args) {
78 printf("IPL thread running\n");
81 if (!gpio_get_irq()) {
89 if (gayle_ide_enabled) {
90 if (((gayle_int & 0x80) || gayle_a4k_int) && (get_ide(0)->drive[0].intrq || get_ide(0)->drive[1].intrq)) {
91 //get_ide(0)->drive[0].intrq = 0;
99 NOP NOP NOP NOP NOP NOP
100 NOP NOP NOP NOP NOP NOP
101 NOP NOP NOP NOP NOP NOP
102 NOP NOP NOP NOP NOP NOP
103 NOP NOP NOP NOP NOP NOP
104 NOP NOP NOP NOP NOP NOP
105 NOP NOP NOP NOP NOP NOP
106 NOP NOP NOP NOP NOP NOP
107 NOP NOP NOP NOP NOP NOP
108 NOP NOP NOP NOP NOP NOP
109 NOP NOP NOP NOP NOP NOP
110 NOP NOP NOP NOP NOP NOP
115 void stop_cpu_emulation(uint8_t disasm_cur) {
116 m68k_end_timeslice();
118 m68k_disassemble(disasm_buf, m68k_get_reg(NULL, M68K_REG_PC), cpu_type);
119 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), \
120 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));
121 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), \
122 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));
123 printf("%.8X (%.8X)]] %s\n", m68k_get_reg(NULL, M68K_REG_PC), (m68k_get_reg(NULL, M68K_REG_PC) & 0xFFFFFF), disasm_buf);
124 realtime_disassembly = 1;
127 cpu_emulation_running = 0;
132 static volatile unsigned char maprom;
134 void sigint_handler(int sig_num) {
136 //cpu_emulation_running = 0;
139 printf("Received sigint %d, exiting.\n", sig_num);
145 if (cfg->platform->shutdown) {
146 cfg->platform->shutdown(cfg);
152 int main(int argc, char *argv[]) {
154 //const struct sched_param priority = {99};
156 // Some command line switch stuffles
157 for (g = 1; g < argc; g++) {
158 if (strcmp(argv[g], "--cpu_type") == 0 || strcmp(argv[g], "--cpu") == 0) {
160 printf("%s switch found, but no CPU type specified.\n", argv[g]);
163 cpu_type = get_m68k_cpu_type(argv[g]);
166 else if (strcmp(argv[g], "--config-file") == 0 || strcmp(argv[g], "--config") == 0) {
168 printf("%s switch found, but no config filename specified.\n", argv[g]);
171 cfg = load_config_file(argv[g]);
174 else if (strcmp(argv[g], "--keyboard-file") == 0 || strcmp(argv[g], "--kbfile") == 0) {
176 printf("%s switch found, but no keyboard device path specified.\n", argv[g]);
179 strcpy(keyboard_file, argv[g]);
185 printf("No config file specified. Trying to load default.cfg...\n");
186 cfg = load_config_file("default.cfg");
188 printf("Couldn't load default.cfg, empty emulator config will be used.\n");
189 cfg = (struct emulator_config *)calloc(1, sizeof(struct emulator_config));
191 printf("Failed to allocate memory for emulator config!\n");
194 memset(cfg, 0x00, sizeof(struct emulator_config));
199 if (cfg->cpu_type) cpu_type = cfg->cpu_type;
200 if (cfg->loop_cycles) loop_cycles = cfg->loop_cycles;
203 cfg->platform = make_platform_config("none", "generic");
204 cfg->platform->platform_initial_setup(cfg);
207 if (cfg->mouse_enabled) {
208 mouse_fd = open(cfg->mouse_file, O_RDONLY | O_NONBLOCK);
209 if (mouse_fd == -1) {
210 printf("Failed to open %s, can't enable mouse hook.\n", cfg->mouse_file);
211 cfg->mouse_enabled = 0;
215 keyboard_fd = open(keyboard_file, O_RDONLY | O_NONBLOCK);
216 if (keyboard_fd == -1) {
217 printf("Failed to open keyboard event source.\n");
222 signal(SIGINT, sigint_handler);
225 //goto skip_everything;
227 // Enable 200MHz CLK output on GPIO4, adjust divider and pll source depending
229 printf("Enable 200MHz GPCLK0 on GPIO4\n");
230 gpio_enable_200mhz();
232 // reset cpld statemachine first
240 // reset amiga and statemachine
246 printf("Setting CPU type to %d.\n", cpu_type);
247 m68k_set_cpu_type(cpu_type);
251 m68k_set_reg(M68K_REG_PC, 0xF80002);
253 m68k_set_reg(M68K_REG_PC, 0x0);
256 ps_reset_state_machine();
261 printf("Setting CPU type to %d.\n", cpu_type);
262 m68k_set_cpu_type(cpu_type);
265 char c = 0, c_code = 0, c_type = 0;
269 err = pthread_create(&id, NULL, &iplThread, NULL);
271 printf("can't create IPL thread :[%s]", strerror(err));
273 printf("IPL Thread created successfully\n");
277 if (mouse_hook_enabled) {
278 get_mouse_status(&mouse_dx, &mouse_dy, &mouse_buttons);
281 if (realtime_disassembly && (do_disasm || cpu_emulation_running)) {
282 m68k_disassemble(disasm_buf, m68k_get_reg(NULL, M68K_REG_PC), cpu_type);
283 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), \
284 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));
285 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), \
286 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));
287 printf("%.8X (%.8X)]] %s\n", m68k_get_reg(NULL, M68K_REG_PC), (m68k_get_reg(NULL, M68K_REG_PC) & 0xFFFFFF), disasm_buf);
293 if (cpu_emulation_running)
294 m68k_execute(loop_cycles);
298 unsigned int status = read_reg();
299 m68k_set_irq((status & 0xe000) >> 13);
302 else if (gayleirq && int2_enabled) {
303 write16(0xdff09c, 0x8000 | (1 << 3));
311 while (get_key_char(&c, &c_code, &c_type)) {
312 if (c && c == cfg->keyboard_toggle_key && !kb_hook_enabled) {
314 printf("Keyboard hook enabled.\n");
316 else if (kb_hook_enabled) {
317 if (c == 0x1B && c_type) {
319 printf("Keyboard hook disabled.\n");
322 /*printf("Key code: %.2X - ", c_code);
325 printf("released.\n");
328 printf("pressed.\n");
334 printf("unknown.\n");
337 if (queue_keypress(c_code, c_type, cfg->platform->id) && int2_enabled) {
343 if (!kb_hook_enabled && c_type) {
344 if (c && c == cfg->mouse_toggle_key) {
345 mouse_hook_enabled ^= 1;
346 printf("Mouse hook %s.\n", mouse_hook_enabled ? "enabled" : "disabled");
347 mouse_dx = mouse_dy = mouse_buttons = 0;
350 cpu_emulation_running ^= 1;
351 printf("CPU emulation is now %s\n", cpu_emulation_running ? "running" : "stopped");
354 realtime_graphics_debug ^= 1;
355 printf("Real time graphics debug is now %s\n", realtime_graphics_debug ? "on" : "off");
359 //m68k_pulse_reset();
360 printf("CPU emulation reset.\n");
363 printf("Quitting and exiting emulator.\n");
364 goto stop_cpu_emulation;
367 realtime_disassembly ^= 1;
369 printf("Real time disassembly is now %s\n", realtime_disassembly ? "on" : "off");
372 int r = get_mapped_item_by_address(cfg, 0x08000000);
374 printf("Dumping first 16MB of mapped range %d.\n", r);
375 FILE *dmp = fopen("./memdmp.bin", "wb+");
376 fwrite(cfg->map_data[r], 16 * SIZE_MEGA, 1, dmp);
380 if (c == 's' && realtime_disassembly) {
383 if (c == 'S' && realtime_disassembly) {
387 // pause pressed; trigger nmi (int level 7)
405 void cpu_pulse_reset(void) {
408 // printf("Status Reg%x\n",read_reg());
411 // printf("Status Reg%x\n",read_reg());
412 if (cfg->platform->handle_reset)
413 cfg->platform->handle_reset(cfg);
416 m68k_write_memory_8(0xbfe201, 0x0001); // AMIGA OVL
417 m68k_write_memory_8(0xbfe001, 0x0001); // AMIGA OVL high (ROM@0x0)
422 int cpu_irq_ack(int level) {
423 printf("cpu irq ack\n");
427 static unsigned int target = 0;
428 static uint8_t send_keypress = 0;
430 uint8_t cdtv_dmac_reg_idx_read();
431 void cdtv_dmac_reg_idx_write(uint8_t value);
432 uint32_t cdtv_dmac_read(uint32_t address, uint8_t type);
433 void cdtv_dmac_write(uint32_t address, uint32_t value, uint8_t type);
435 #define PLATFORM_CHECK_READ(a) \
436 if (address >= cfg->custom_low && address < cfg->custom_high) { \
437 unsigned int target = 0; \
438 switch(cfg->platform->id) { \
439 case PLATFORM_AMIGA: { \
440 if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
441 return handle_piscsi_read(address, a); \
443 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
444 return handle_pinet_read(address, a); \
446 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
447 return rtg_read((address & 0x0FFFFFFF), a); \
449 if (custom_read_amiga(cfg, address, &target, a) != -1) { \
458 if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
459 if (handle_mapped_read(cfg, address, &target, a) != -1) \
463 unsigned int m68k_read_memory_8(unsigned int address) {
464 PLATFORM_CHECK_READ(OP_TYPE_BYTE);
466 /*if (address >= 0xE90000 && address < 0xF00000) {
467 printf("BYTE read from DMAC @%.8X:", address);
468 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_BYTE);
470 m68k_end_timeslice();
471 cpu_emulation_running = 0;
475 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
476 stop_cpu_emulation(1);
480 if (address & 0xFF000000)
483 unsigned char result = (unsigned int)read8((uint32_t)address);
485 if (mouse_hook_enabled) {
486 if (address == CIAAPRA) {
487 if (mouse_buttons & 0x01) {
488 //mouse_buttons -= 1;
489 return (unsigned int)(result ^ 0x40);
492 return (unsigned int)result;
495 if (kb_hook_enabled) {
496 if (address == CIAAICR) {
497 if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
502 if (send_keypress == 2) {
508 if (address == CIAADAT) {
510 uint8_t c = 0, t = 0;
511 pop_queued_key(&c, &t);
513 result = ((c << 1) | t) ^ 0xFF;
523 unsigned int m68k_read_memory_16(unsigned int address) {
524 PLATFORM_CHECK_READ(OP_TYPE_WORD);
526 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
527 stop_cpu_emulation(1);
530 /*if (address >= 0xE90000 && address < 0xF00000) {
531 printf("WORD read from DMAC @%.8X:", address);
532 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_WORD);
534 m68k_end_timeslice();
535 cpu_emulation_running = 0;
539 if (mouse_hook_enabled) {
540 if (address == JOY0DAT) {
541 // Forward mouse valueses to Amyga.
542 unsigned short result = (mouse_dy << 8) | (mouse_dx);
543 return (unsigned int)result;
545 /*if (address == CIAAPRA) {
546 unsigned short result = (unsigned int)read16((uint32_t)address);
547 if (mouse_buttons & 0x01) {
548 return (unsigned int)(result | 0x40);
551 return (unsigned int)result;
553 if (address == POTGOR) {
554 unsigned short result = (unsigned int)read16((uint32_t)address);
555 if (mouse_buttons & 0x02) {
556 return (unsigned int)(result ^ (0x2 << 9));
559 return (unsigned int)(result & 0xFFFD);
563 if (address & 0xFF000000)
566 if (address & 0x01) {
567 return ((read8(address) << 8) | read8(address + 1));
569 return (unsigned int)read16((uint32_t)address);
572 unsigned int m68k_read_memory_32(unsigned int address) {
573 PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
575 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
576 stop_cpu_emulation(1);
579 /*if (address >= 0xE90000 && address < 0xF00000) {
580 printf("LONGWORD read from DMAC @%.8X:", address);
581 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_LONGWORD);
583 m68k_end_timeslice();
584 cpu_emulation_running = 0;
588 if (address & 0xFF000000)
591 if (address & 0x01) {
592 uint32_t c = read8(address);
593 c |= (be16toh(read16(address+1)) << 8);
594 c |= (read8(address + 3) << 24);
597 uint16_t a = read16(address);
598 uint16_t b = read16(address + 2);
599 return (a << 16) | b;
602 #define PLATFORM_CHECK_WRITE(a) \
603 if (address >= cfg->custom_low && address < cfg->custom_high) { \
604 switch(cfg->platform->id) { \
605 case PLATFORM_AMIGA: { \
606 if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
607 handle_piscsi_write(address, value, a); \
609 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
610 handle_pinet_write(address, value, a); \
612 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
613 rtg_write((address & 0x0FFFFFFF), value, a); \
616 if (custom_write_amiga(cfg, address, value, a) != -1) { \
625 if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
626 if (handle_mapped_write(cfg, address, value, a) != -1) \
630 void m68k_write_memory_8(unsigned int address, unsigned int value) {
631 PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
633 /*if (address >= 0xE90000 && address < 0xF00000) {
634 printf("BYTE write to DMAC @%.8X: %.2X\n", address, value);
635 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_BYTE);
636 m68k_end_timeslice();
637 cpu_emulation_running = 0;
641 if (address == 0xbfe001) {
642 if (ovl != (value & (1 << 0))) {
643 ovl = (value & (1 << 0));
644 printf("OVL:%x\n", ovl);
648 if (address & 0xFF000000)
651 write8((uint32_t)address, value);
655 void m68k_write_memory_16(unsigned int address, unsigned int value) {
656 PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
658 /*if (address >= 0xE90000 && address < 0xF00000) {
659 printf("WORD write to DMAC @%.8X: %.4X\n", address, value);
660 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_WORD);
661 m68k_end_timeslice();
662 cpu_emulation_running = 0;
666 if (address == 0xDFF030) {
667 char *serdat = (char *)&value;
668 // SERDAT word. see amiga dev docs appendix a; upper byte is control codes, and bit 0 is always 1.
669 // ignore this upper byte as it's not viewable data, only display lower byte.
670 printf("%c", serdat[0]);
672 if (address == 0xDFF09A) {
673 if (!(value & 0x8000)) {
678 else if (value & 0x04) {
683 if (address & 0xFF000000)
687 printf("Unaligned WORD write!\n");
689 write16((uint32_t)address, value);
693 void m68k_write_memory_32(unsigned int address, unsigned int value) {
694 PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
696 /*if (address >= 0xE90000 && address < 0xF00000) {
697 printf("LONGWORD write to DMAC @%.8X: %.8X\n", address, value);
698 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_LONGWORD);
699 m68k_end_timeslice();
700 cpu_emulation_running = 0;
704 if (address & 0xFF000000)
708 printf("Unaligned LONGWORD write!\n");
710 write16(address, value >> 16);
711 write16(address + 2, value);