]> git.sesse.net Git - pistorm/blob - emulator.c
Creepy CDTV experiments
[pistorm] / emulator.c
1 #include <assert.h>
2 #include <dirent.h>
3 #include <endian.h>
4 #include <fcntl.h>
5 #include <pthread.h>
6 #include <sched.h>
7 #include <signal.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <unistd.h>
16 #include <sys/ioctl.h>
17 #include "m68k.h"
18 #include "main.h"
19 #include "platforms/platforms.h"
20 #include "input/input.h"
21
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 "gpio/gpio.h"
27
28 unsigned char read_ranges;
29 unsigned int read_addr[8];
30 unsigned int read_upper[8];
31 unsigned char *read_data[8];
32 unsigned char write_ranges;
33 unsigned int write_addr[8];
34 unsigned int write_upper[8];
35 unsigned char *write_data[8];
36
37 int kb_hook_enabled = 0;
38 int mouse_hook_enabled = 0;
39 int cpu_emulation_running = 1;
40
41 char mouse_dx = 0, mouse_dy = 0;
42 char mouse_buttons = 0;
43
44 extern volatile unsigned int *gpio;
45 extern volatile uint16_t srdata;
46 extern uint8_t realtime_graphics_debug;
47 uint8_t realtime_disassembly;
48
49 char disasm_buf[4096];
50
51 #define KICKBASE 0xF80000
52 #define KICKSIZE 0x7FFFF
53
54 int mem_fd, mouse_fd = -1, keyboard_fd = -1;
55 int mem_fd_gpclk;
56 int gayle_emulation_enabled = 1;
57 int irq;
58 int gayleirq;
59
60 void *iplThread(void *args) {
61   printf("IPL thread running\n");
62
63   while (1) {
64     if (!gpio_get_irq()) {
65       irq = 1;
66       m68k_end_timeslice();
67     }
68     else
69       irq = 0;
70
71     if (gayle_emulation_enabled) {
72       if (((gayle_int & 0x80) || gayle_a4k_int) && (get_ide(0)->drive[0].intrq || get_ide(0)->drive[1].intrq)) {
73         //get_ide(0)->drive[0].intrq = 0;
74         gayleirq = 1;
75         m68k_end_timeslice();
76       }
77       else
78         gayleirq = 0;
79     }
80     usleep(0);
81   }
82   return args;
83 }
84
85
86 // Configurable emulator options
87 unsigned int cpu_type = M68K_CPU_TYPE_68000;
88 unsigned int loop_cycles = 300;
89 struct emulator_config *cfg = NULL;
90 char keyboard_file[256] = "/dev/input/event1";
91
92 //unsigned char g_kick[524288];
93 //unsigned char g_ram[FASTSIZE + 1]; /* RAM */
94 int ovl;
95 static volatile unsigned char maprom;
96
97 void sigint_handler(int sig_num) {
98   //if (sig_num) { }
99   //cpu_emulation_running = 0;
100
101   //return;
102   printf("Received sigint %d, exiting.\n", sig_num);
103   if (mouse_fd != -1)
104     close(mouse_fd);
105   if (mem_fd)
106     close(mem_fd);
107
108   if (cfg->platform->shutdown) {
109     cfg->platform->shutdown(cfg);
110   }
111
112   exit(0);
113 }
114
115 int main(int argc, char *argv[]) {
116   int g;
117   const struct sched_param priority = {99};
118
119   // Some command line switch stuffles
120   for (g = 1; g < argc; g++) {
121     if (strcmp(argv[g], "--disable-gayle") == 0) {
122       gayle_emulation_enabled = 0;
123     }
124     else if (strcmp(argv[g], "--cpu_type") == 0 || strcmp(argv[g], "--cpu") == 0) {
125       if (g + 1 >= argc) {
126         printf("%s switch found, but no CPU type specified.\n", argv[g]);
127       } else {
128         g++;
129         cpu_type = get_m68k_cpu_type(argv[g]);
130       }
131     }
132     else if (strcmp(argv[g], "--config-file") == 0 || strcmp(argv[g], "--config") == 0) {
133       if (g + 1 >= argc) {
134         printf("%s switch found, but no config filename specified.\n", argv[g]);
135       } else {
136         g++;
137         cfg = load_config_file(argv[g]);
138       }
139     }
140     else if (strcmp(argv[g], "--keyboard-file") == 0 || strcmp(argv[g], "--kbfile") == 0) {
141       if (g + 1 >= argc) {
142         printf("%s switch found, but no keyboard device path specified.\n", argv[g]);
143       } else {
144         g++;
145         strcpy(keyboard_file, argv[g]);
146       }
147     }
148   }
149
150   if (!cfg) {
151     printf("No config file specified. Trying to load default.cfg...\n");
152     cfg = load_config_file("default.cfg");
153     if (!cfg) {
154       printf("Couldn't load default.cfg, empty emulator config will be used.\n");
155       cfg = (struct emulator_config *)calloc(1, sizeof(struct emulator_config));
156       if (!cfg) {
157         printf("Failed to allocate memory for emulator config!\n");
158         return 1;
159       }
160       memset(cfg, 0x00, sizeof(struct emulator_config));
161     }
162   }
163
164   if (cfg) {
165     if (cfg->cpu_type) cpu_type = cfg->cpu_type;
166     if (cfg->loop_cycles) loop_cycles = cfg->loop_cycles;
167
168     if (!cfg->platform)
169       cfg->platform = make_platform_config("none", "generic");
170     cfg->platform->platform_initial_setup(cfg);
171   }
172
173   if (cfg->mouse_enabled) {
174     mouse_fd = open(cfg->mouse_file, O_RDONLY | O_NONBLOCK);
175     if (mouse_fd == -1) {
176       printf("Failed to open %s, can't enable mouse hook.\n", cfg->mouse_file);
177       cfg->mouse_enabled = 0;
178     }
179   }
180
181   keyboard_fd = open(keyboard_file, O_RDONLY | O_NONBLOCK);
182   if (keyboard_fd == -1) {
183     printf("Failed to open keyboard event source.\n");
184   }
185
186   InitGayle();
187
188   signal(SIGINT, sigint_handler);
189   setup_io();
190
191   //goto skip_everything;
192
193   // Enable 200MHz CLK output on GPIO4, adjust divider and pll source depending
194   // on pi model
195   printf("Enable 200MHz GPCLK0 on GPIO4\n");
196   gpio_enable_200mhz();
197
198   // reset cpld statemachine first
199
200   write_reg(0x01);
201   usleep(100);
202   usleep(1500);
203   write_reg(0x00);
204   usleep(100);
205
206   // reset amiga and statemachine
207   skip_everything:;
208
209   usleep(1500);
210
211   m68k_init();
212   printf("Setting CPU type to %d.\n", cpu_type);
213   m68k_set_cpu_type(cpu_type);
214   cpu_pulse_reset();
215
216   if (maprom == 1) {
217     m68k_set_reg(M68K_REG_PC, 0xF80002);
218   } else {
219     m68k_set_reg(M68K_REG_PC, 0x0);
220   }
221
222   char c = 0, c_code = 0, c_type = 0;
223
224   pthread_t id;
225   int err;
226   err = pthread_create(&id, NULL, &iplThread, NULL);
227   if (err != 0)
228     printf("can't create IPL thread :[%s]", strerror(err));
229   else
230     printf("IPL Thread created successfully\n");
231
232   m68k_pulse_reset();
233   while (42) {
234     if (mouse_hook_enabled) {
235       get_mouse_status(&mouse_dx, &mouse_dy, &mouse_buttons);
236     }
237
238     if (cpu_emulation_running)
239       m68k_execute(loop_cycles);
240
241 disasm_run:;
242     if (realtime_disassembly) {
243       m68k_execute(1);
244       m68k_disassemble(disasm_buf, m68k_get_reg(NULL, M68K_REG_PC), cpu_type);
245       printf("%.8X (%.8X)]] %s\n", m68k_get_reg(NULL, M68K_REG_PC), (m68k_get_reg(NULL, M68K_REG_PC) & 0xFFFFFF), disasm_buf);
246     }
247     
248     if (irq) {
249       unsigned int status = read_reg();
250       m68k_set_irq((status & 0xe000) >> 13);
251     }
252     else if (gayleirq) {
253       write16(0xdff09c, 0x8000 | (1 << 3));
254       //PAULA_SET_IRQ(3); // IRQ 3 = INT2
255       m68k_set_irq(2);
256     }
257     else {
258         m68k_set_irq(0);
259     }
260
261     while (get_key_char(&c, &c_code, &c_type)) {
262       if (c && c == cfg->keyboard_toggle_key && !kb_hook_enabled) {
263         kb_hook_enabled = 1;
264         printf("Keyboard hook enabled.\n");
265       }
266       else if (kb_hook_enabled) {
267         if (c == 0x1B && c_type) {
268           kb_hook_enabled = 0;
269           printf("Keyboard hook disabled.\n");
270         }
271         else {
272           /*printf("Key code: %.2X - ", c_code);
273           switch (c_type) {
274             case 0:
275               printf("released.\n");
276               break;
277             case 1:
278               printf("pressed.\n");
279               break;
280             case 2:
281               printf("repeat.\n");
282               break;
283             default:
284               printf("unknown.\n");
285               break;
286           }*/
287           if (queue_keypress(c_code, c_type, cfg->platform->id)) {
288             m68k_set_irq(2);
289           }
290         }
291       }
292
293       if (!kb_hook_enabled && c_type) {
294         if (c && c == cfg->mouse_toggle_key) {
295           mouse_hook_enabled ^= 1;
296           printf("Mouse hook %s.\n", mouse_hook_enabled ? "enabled" : "disabled");
297           mouse_dx = mouse_dy = mouse_buttons = 0;
298         }
299         if (c == 'r') {
300           cpu_emulation_running ^= 1;
301           printf("CPU emulation is now %s\n", cpu_emulation_running ? "running" : "stopped");
302         }
303         if (c == 'g') {
304           realtime_graphics_debug ^= 1;
305           printf("Real time graphics debug is now %s\n", realtime_graphics_debug ? "on" : "off");
306         }
307         if (c == 'R') {
308           cpu_pulse_reset();
309           //m68k_pulse_reset();
310           printf("CPU emulation reset.\n");
311         }
312         if (c == 'q') {
313           printf("Quitting and exiting emulator.\n");
314           goto stop_cpu_emulation;
315         }
316         if (c == 'd') {
317           realtime_disassembly ^= 1;
318           printf("Real time disassembly is now %s\n", realtime_disassembly ? "on" : "off");
319         }
320       }
321     }
322
323     if (realtime_disassembly)
324       goto disasm_run;
325
326     //gpio_handle_irq();
327     //GPIO_HANDLE_IRQ;
328   }
329
330   stop_cpu_emulation:;
331
332   if (mouse_fd != -1)
333     close(mouse_fd);
334   if (mem_fd)
335     close(mem_fd);
336
337   return 0;
338 }
339
340 void cpu_pulse_reset(void) {
341   write_reg(0x00);
342   // printf("Status Reg%x\n",read_reg());
343   usleep(100000);
344   write_reg(0x02);
345   // printf("Status Reg%x\n",read_reg());
346
347   ovl = 1;
348   m68k_write_memory_8(0xbfe201, 0x0001);  // AMIGA OVL
349   m68k_write_memory_8(0xbfe001, 0x0001);  // AMIGA OVL high (ROM@0x0)
350
351   m68k_pulse_reset();
352 }
353
354 int cpu_irq_ack(int level) {
355   printf("cpu irq ack\n");
356   return level;
357 }
358
359 static unsigned int target = 0;
360 static uint8_t send_keypress = 0;
361
362 uint8_t cdtv_dmac_reg_idx_read();
363 void cdtv_dmac_reg_idx_write(uint8_t value);
364 uint32_t cdtv_dmac_read(uint32_t address, uint8_t type);
365 void cdtv_dmac_write(uint32_t address, uint32_t value, uint8_t type);
366
367 #define PLATFORM_CHECK_READ(a) \
368   if (address >= cfg->custom_low && address < cfg->custom_high) { \
369     unsigned int target = 0; \
370     switch(cfg->platform->id) { \
371       case PLATFORM_AMIGA: { \
372         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
373           return rtg_read((address & 0x0FFFFFFF), a); \
374         } \
375         if (custom_read_amiga(cfg, address, &target, a) != -1) { \
376           return target; \
377         } \
378         break; \
379       } \
380       default: \
381         break; \
382     } \
383   } \
384   if (ovl || (address >= cfg->mapped_low && address < cfg->mapped_high)) { \
385     if (handle_mapped_read(cfg, address, &target, a) != -1) \
386       return target; \
387   }
388
389 unsigned int m68k_read_memory_8(unsigned int address) {
390   PLATFORM_CHECK_READ(OP_TYPE_BYTE);
391
392   if (address >= 0xE90000 && address < 0xF00000) {
393     printf("BYTE read from DMAC @%.8X:", address);
394     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_BYTE);
395     printf("%.2X\n", v);
396     m68k_end_timeslice();
397     cpu_emulation_running = 0;
398     return v;
399   }
400
401   if (mouse_hook_enabled) {
402     if (address == CIAAPRA) {
403       unsigned char result = (unsigned int)read8((uint32_t)address);
404       if (mouse_buttons & 0x01) {
405         //mouse_buttons -= 1;
406         return (unsigned int)(result ^ 0x40);
407       }
408       else
409           return (unsigned int)result;
410     }
411   }
412   if (kb_hook_enabled) {
413     unsigned char result = (unsigned int)read8((uint32_t)address);
414     if (address == CIAAICR) {
415       if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
416         result |= 0x08;
417         if (!send_keypress)
418           send_keypress = 1;
419       }
420       if (send_keypress == 2) {
421         result |= 0x02;
422         send_keypress = 0;
423       }
424       return result;
425     }
426     if (address == CIAADAT) {
427       if (send_keypress) {
428         uint8_t c = 0, t = 0;
429         pop_queued_key(&c, &t);
430         t ^= 0x01;
431         result = ((c << 1) | t) ^ 0xFF;
432         send_keypress = 2;
433       }
434       return result;
435     }
436   }
437
438   if (address & 0xFF000000)
439     return 0;
440
441   return read8((uint32_t)address);
442 }
443
444 unsigned int m68k_read_memory_16(unsigned int address) {
445   PLATFORM_CHECK_READ(OP_TYPE_WORD);
446
447   if (address >= 0xE90000 && address < 0xF00000) {
448     printf("WORD read from DMAC @%.8X:", address);
449     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_WORD);
450     printf("%.2X\n", v);
451     m68k_end_timeslice();
452     cpu_emulation_running = 0;
453     return v;
454   }
455
456   if (mouse_hook_enabled) {
457     if (address == JOY0DAT) {
458       // Forward mouse valueses to Amyga.
459       unsigned short result = (mouse_dy << 8) | (mouse_dx);
460       return (unsigned int)result;
461     }
462     /*if (address == CIAAPRA) {
463       unsigned short result = (unsigned int)read16((uint32_t)address);
464       if (mouse_buttons & 0x01) {
465         return (unsigned int)(result | 0x40);
466       }
467       else
468           return (unsigned int)result;
469     }*/
470     if (address == POTGOR) {
471       unsigned short result = (unsigned int)read16((uint32_t)address);
472       if (mouse_buttons & 0x02) {
473         return (unsigned int)(result ^ (0x2 << 9));
474       }
475       else
476           return (unsigned int)(result & 0xFFFD);
477     }
478   }
479
480   if (address & 0xFF000000)
481     return 0;
482
483   if (address & 0x01) {
484     return ((read8(address) << 8) | read8(address + 1));
485   }
486   return (unsigned int)read16((uint32_t)address);
487 }
488
489 unsigned int m68k_read_memory_32(unsigned int address) {
490   PLATFORM_CHECK_READ(OP_TYPE_LONGWORD);
491
492   if (address >= 0xE90000 && address < 0xF00000) {
493     printf("LONGWORD read from DMAC @%.8X:", address);
494     uint32_t v = cdtv_dmac_read(address & 0xFFFF, OP_TYPE_LONGWORD);
495     printf("%.2X\n", v);
496     m68k_end_timeslice();
497     cpu_emulation_running = 0;
498     return v;
499   }
500
501   if (address & 0xFF000000)
502     return 0;
503
504   if (address & 0x01) {
505     uint32_t c = read8(address);
506     c |= (be16toh(read16(address+1)) << 8);
507     c |= (read8(address + 3) << 24);
508     return htobe32(c);
509   }
510   uint16_t a = read16(address);
511   uint16_t b = read16(address + 2);
512   return (a << 16) | b;
513 }
514
515 #define PLATFORM_CHECK_WRITE(a) \
516   if (address >= cfg->custom_low && address < cfg->custom_high) { \
517     switch(cfg->platform->id) { \
518       case PLATFORM_AMIGA: { \
519         if (address >= PIGFX_RTG_BASE && address < PIGFX_UPPER) { \
520           rtg_write((address & 0x0FFFFFFF), value, a); \
521           return; \
522         } \
523         if (custom_write_amiga(cfg, address, value, a) != -1) { \
524           return; \
525         } \
526         break; \
527       } \
528       default: \
529         break; \
530     } \
531   } \
532   if (address >= cfg->mapped_low && address < cfg->mapped_high) { \
533     if (handle_mapped_write(cfg, address, value, a) != -1) \
534       return; \
535   }
536
537 void m68k_write_memory_8(unsigned int address, unsigned int value) {
538   PLATFORM_CHECK_WRITE(OP_TYPE_BYTE);
539
540   if (address >= 0xE90000 && address < 0xF00000) {
541     printf("BYTE write to DMAC @%.8X: %.2X\n", address, value);
542     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_BYTE);
543     m68k_end_timeslice();
544     cpu_emulation_running = 0;
545     return;
546   }
547
548   if (address == 0xbfe001) {
549     if (ovl != (value & (1 << 0))) {
550       ovl = (value & (1 << 0));
551       printf("OVL:%x\n", ovl);
552     }
553   }
554
555   if (address & 0xFF000000)
556     return;
557
558   write8((uint32_t)address, value);
559   return;
560 }
561
562 void m68k_write_memory_16(unsigned int address, unsigned int value) {
563   PLATFORM_CHECK_WRITE(OP_TYPE_WORD);
564
565   if (address >= 0xE90000 && address < 0xF00000) {
566     printf("WORD write to DMAC @%.8X: %.4X\n", address, value);
567     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_WORD);
568     m68k_end_timeslice();
569     cpu_emulation_running = 0;
570     return;
571   }
572
573   if (address & 0xFF000000)
574     return;
575
576   if (address & 0x01)
577     printf("Unaligned WORD write!\n");
578
579   write16((uint32_t)address, value);
580   return;
581 }
582
583 void m68k_write_memory_32(unsigned int address, unsigned int value) {
584   PLATFORM_CHECK_WRITE(OP_TYPE_LONGWORD);
585
586   if (address >= 0xE90000 && address < 0xF00000) {
587     printf("LONGWORD write to DMAC @%.8X: %.8X\n", address, value);
588     cdtv_dmac_write(address & 0xFFFF, value, OP_TYPE_LONGWORD);
589     m68k_end_timeslice();
590     cpu_emulation_running = 0;
591     return;
592   }
593
594   if (address & 0xFF000000)
595     return;
596
597   if (address & 0x01)
598     printf("Unaligned LONGWORD write!\n");
599
600   write16(address, value >> 16);
601   write16(address + 2, value);
602   return;
603 }