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) {
400 void cpu_pulse_reset(void) {
403 // printf("Status Reg%x\n",read_reg());
406 // printf("Status Reg%x\n",read_reg());
407 if (cfg->platform->handle_reset)
408 cfg->platform->handle_reset(cfg);
411 m68k_write_memory_8(0xbfe201, 0x0001); // AMIGA OVL
412 m68k_write_memory_8(0xbfe001, 0x0001); // AMIGA OVL high (ROM@0x0)
417 int cpu_irq_ack(int level) {
418 printf("cpu irq ack\n");
422 static unsigned int target = 0;
423 static uint8_t send_keypress = 0;
425 uint8_t cdtv_dmac_reg_idx_read();
426 void cdtv_dmac_reg_idx_write(uint8_t value);
427 uint32_t cdtv_dmac_read(uint32_t address, uint8_t type);
428 void cdtv_dmac_write(uint32_t address, uint32_t value, uint8_t type);
430 #define PLATFORM_CHECK_READ(a) \
431 if (address >= cfg->custom_low && address < cfg->custom_high) { \
432 unsigned int target = 0; \
433 switch(cfg->platform->id) { \
434 case PLATFORM_AMIGA: { \
435 if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
436 return handle_piscsi_read(address, a); \
438 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
439 return handle_pinet_read(address, a); \
441 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
442 return rtg_read((address & 0x0FFFFFFF), a); \
444 if (custom_read_amiga(cfg, address, &target, a) != -1) { \
453 if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
454 if (handle_mapped_read(cfg, address, &target, a) != -1) \
458 unsigned int m68k_read_memory_8(unsigned int address) {
459 PLATFORM_CHECK_READ(OP_TYPE_BYTE);
461 /*if (address >= 0xE90000 && address < 0xF00000) {
462 printf("BYTE read from DMAC @%.8X:", address);
463 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_BYTE);
465 m68k_end_timeslice();
466 cpu_emulation_running = 0;
470 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
471 stop_cpu_emulation(1);
475 if (address & 0xFF000000)
478 unsigned char result = (unsigned int)read8((uint32_t)address);
480 if (mouse_hook_enabled) {
481 if (address == CIAAPRA) {
482 if (mouse_buttons & 0x01) {
483 //mouse_buttons -= 1;
484 return (unsigned int)(result ^ 0x40);
487 return (unsigned int)result;
490 if (kb_hook_enabled) {
491 if (address == CIAAICR) {
492 if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
497 if (send_keypress == 2) {
503 if (address == CIAADAT) {
505 uint8_t c = 0, t = 0;
506 pop_queued_key(&c, &t);
508 result = ((c << 1) | t) ^ 0xFF;
518 unsigned int m68k_read_memory_16(unsigned int address) {
519 PLATFORM_CHECK_READ(OP_TYPE_WORD);
521 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
522 stop_cpu_emulation(1);
525 /*if (address >= 0xE90000 && address < 0xF00000) {
526 printf("WORD read from DMAC @%.8X:", address);
527 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_WORD);
529 m68k_end_timeslice();
530 cpu_emulation_running = 0;
534 if (mouse_hook_enabled) {
535 if (address == JOY0DAT) {
536 // Forward mouse valueses to Amyga.
537 unsigned short result = (mouse_dy << 8) | (mouse_dx);
538 return (unsigned int)result;
540 /*if (address == CIAAPRA) {
541 unsigned short result = (unsigned int)read16((uint32_t)address);
542 if (mouse_buttons & 0x01) {
543 return (unsigned int)(result | 0x40);
546 return (unsigned int)result;
548 if (address == POTGOR) {
549 unsigned short result = (unsigned int)read16((uint32_t)address);
550 if (mouse_buttons & 0x02) {
551 return (unsigned int)(result ^ (0x2 << 9));
554 return (unsigned int)(result & 0xFFFD);
558 if (address & 0xFF000000)
561 if (address & 0x01) {
562 return ((read8(address) << 8) | read8(address + 1));
564 return (unsigned int)read16((uint32_t)address);
567 unsigned int m68k_read_memory_32(unsigned int address) {
568 PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
570 /*if (m68k_get_reg(NULL, M68K_REG_PC) >= 0x080032F0 && m68k_get_reg(NULL, M68K_REG_PC) <= 0x080032F0 + 0x4000) {
571 stop_cpu_emulation(1);
574 /*if (address >= 0xE90000 && address < 0xF00000) {
575 printf("LONGWORD read from DMAC @%.8X:", address);
576 uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_LONGWORD);
578 m68k_end_timeslice();
579 cpu_emulation_running = 0;
583 if (address & 0xFF000000)
586 if (address & 0x01) {
587 uint32_t c = read8(address);
588 c |= (be16toh(read16(address+1)) << 8);
589 c |= (read8(address + 3) << 24);
592 uint16_t a = read16(address);
593 uint16_t b = read16(address + 2);
594 return (a << 16) | b;
597 #define PLATFORM_CHECK_WRITE(a) \
598 if (address >= cfg->custom_low && address < cfg->custom_high) { \
599 switch(cfg->platform->id) { \
600 case PLATFORM_AMIGA: { \
601 if (address >= PISCSI_OFFSET && address < PISCSI_UPPER) { \
602 handle_piscsi_write(address, value, a); \
604 if (address >= PINET_OFFSET && address < PINET_UPPER) { \
605 handle_pinet_write(address, value, a); \
607 if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
608 rtg_write((address & 0x0FFFFFFF), value, a); \
611 if (custom_write_amiga(cfg, address, value, a) != -1) { \
620 if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
621 if (handle_mapped_write(cfg, address, value, a) != -1) \
625 void m68k_write_memory_8(unsigned int address, unsigned int value) {
626 PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
628 /*if (address >= 0xE90000 && address < 0xF00000) {
629 printf("BYTE write to DMAC @%.8X: %.2X\n", address, value);
630 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_BYTE);
631 m68k_end_timeslice();
632 cpu_emulation_running = 0;
636 if (address == 0xbfe001) {
637 if (ovl != (value & (1 << 0))) {
638 ovl = (value & (1 << 0));
639 printf("OVL:%x\n", ovl);
643 if (address & 0xFF000000)
646 write8((uint32_t)address, value);
650 void m68k_write_memory_16(unsigned int address, unsigned int value) {
651 PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
653 /*if (address >= 0xE90000 && address < 0xF00000) {
654 printf("WORD write to DMAC @%.8X: %.4X\n", address, value);
655 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_WORD);
656 m68k_end_timeslice();
657 cpu_emulation_running = 0;
661 if (address == 0xDFF030) {
662 char *beb = (char *)&value;
663 printf("%c%c", beb[1], beb[0]);
665 if (address == 0xDFF09A) {
666 if (!(value & 0x8000)) {
671 else if (value & 0x04) {
676 if (address & 0xFF000000)
680 printf("Unaligned WORD write!\n");
682 write16((uint32_t)address, value);
686 void m68k_write_memory_32(unsigned int address, unsigned int value) {
687 PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
689 /*if (address >= 0xE90000 && address < 0xF00000) {
690 printf("LONGWORD write to DMAC @%.8X: %.8X\n", address, value);
691 cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_LONGWORD);
692 m68k_end_timeslice();
693 cpu_emulation_running = 0;
697 if (address & 0xFF000000)
701 printf("Unaligned LONGWORD write!\n");
703 write16(address, value >> 16);
704 write16(address + 2, value);