]> git.sesse.net Git - pistorm/blob - platforms/amiga/Gayle.c
Add Meson build files.
[pistorm] / platforms / amiga / Gayle.c
1 // SPDX-License-Identifier: MIT
2
3 //
4 //  Gayle.c
5 //  Originally based on Omega's Gayle emulation,
6 //  created by Matt Parsons on 06/03/2019.
7 //  Copyright © 2019 Matt Parsons. All rights reserved.
8 //
9
10 #include "Gayle.h"
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <time.h>
17 #include <endian.h>
18
19 #include "platforms/shared/rtc.h"
20 #include "config_file/config_file.h"
21
22 #include "amiga-registers.h"
23
24 //#define DEBUG_GAYLE
25 #ifdef DEBUG_GAYLE
26 #define DEBUG printf
27 #else
28 #define DEBUG(...)
29 #endif
30
31 #define IDE_DUMMY
32
33 #ifdef IDE_DUMMY
34 uint8_t *ide0 = NULL;
35
36 uint8_t ide_feature_w = 0, ide_command_w = 0, ide_sec_count = 0, ide_sec_num = 0, idewrite8 = 0, ide_cyl_hi = 0, ide_dev_head = 0;
37 uint8_t ide_devctrl_w = 0, ide_cyl_low = 0, ide_error_r = 0, ide_status_r = 0, ide_altst_r = 0, ide_data = 0;
38
39 uint8_t ide_read8(uint8_t *dummy, uint8_t ide_action) { if (dummy || ide_action) {}; return 0; }
40 uint16_t ide_read16(uint8_t *dummy, uint8_t ide_action) { if (dummy || ide_action) {}; return 0; }
41
42 void ide_write8(uint8_t *dummy, uint8_t ide_action, uint8_t value) { if (dummy || ide_action || value) {}; }
43 void ide_write16(uint8_t *dummy, uint8_t ide_action, uint16_t value) { if (dummy || ide_action || value) {}; }
44 void ide_reset_begin(uint8_t *dummy) { if (dummy) {}; }
45
46 uint8_t *ide_allocate(const char *name) { if (name) {}; return NULL; }
47
48 void ide_attach_hdf(uint8_t *dummy, uint32_t idx, uint32_t fd) {
49   if (dummy || idx || fd) {};
50   printf("[!!!IDE] No IDE emulation layer available, HDF image not attached.\n");
51   return;
52 }
53
54 void ide_attach(uint8_t *dummy, uint32_t idx, uint32_t fd) {
55   if (dummy || idx || fd) {};
56   printf("[!!!IDE] No IDE emulation layer available, image not mounted.\n");
57   return;
58 }
59 #else
60 static struct ide_controller *ide0 = NULL;
61 #endif
62
63 uint8_t gary_cfg[8];
64
65 uint8_t ramsey_cfg = 0x08;
66 static uint8_t ramsey_id = RAMSEY_REV7;
67
68 int counter;
69 static uint8_t gayle_irq, gayle_cs, gayle_cs_mask, gayle_cfg;
70 int fd;
71
72 uint8_t rtc_type = RTC_TYPE_RICOH;
73
74 char *hdd_image_file[GAYLE_MAX_HARDFILES];
75
76 uint8_t cdtv_mode = 0;
77 unsigned char cdtv_sram[32 * SIZE_KILO];
78
79 uint8_t gayle_a4k = 0xA0;
80 uint16_t gayle_a4k_irq = 0;
81 uint8_t gayle_a4k_int = 0;
82 uint8_t gayle_int = 0;
83
84 uint32_t gayle_ide_mask = ~GDATA;
85 uint32_t gayle_ide_base = GDATA;
86 uint8_t gayle_ide_enabled = 1;
87 uint8_t gayle_emulation_enabled = 1;
88 uint8_t gayle_ide_adj = 0;
89
90 void adjust_gayle_4000() {
91   gayle_ide_base = GAYLE_IDE_BASE_A4000;
92   gayle_ide_adj = 2;
93   gayle_a4k_int = 1;
94 }
95
96 void adjust_gayle_1200() {
97 }
98
99 void set_hard_drive_image_file_amiga(uint8_t index, char *filename) {
100   if (hdd_image_file[index] != NULL)
101     free(hdd_image_file[index]);
102   hdd_image_file[index] = calloc(1, strlen(filename) + 1);
103   strcpy(hdd_image_file[index], filename);
104 }
105
106 void InitGayle(void) {
107   uint8_t num_ide_drives = 0;
108
109   for (int i = 0; i < GAYLE_MAX_HARDFILES; i++) {
110     if (hdd_image_file[i]) {
111       fd = open(hdd_image_file[i], O_RDWR);
112       if (fd != -1) {
113         if (!ide0)
114             ide0 = ide_allocate("cf");
115       }
116
117       if (fd == -1) {
118         printf("[HDD%d] HDD Image %s failed open\n", i, hdd_image_file[i]);
119       } else {
120         printf("[HDD%d] Attaching HDD image %s.\n", i, hdd_image_file[i]);
121         if (strcmp(hdd_image_file[i] + (strlen(hdd_image_file[i]) - 3), "img") != 0) {
122           printf("No header present on HDD image %s.\n", hdd_image_file[i]);
123           ide_attach_hdf(ide0, i, fd);
124           num_ide_drives++;
125         }
126         else {
127           printf("Attaching HDD image with header.\n");
128           ide_attach(ide0, i, fd);
129           num_ide_drives++;
130         }
131         printf("[HDD%d] HDD Image %s attached\n", i, hdd_image_file[i]);
132       }
133     }
134   }
135   if (ide0)
136     ide_reset_begin(ide0);
137
138   if (num_ide_drives == 0) {
139     // No IDE drives mounted, disable IDE component of Gayle
140     printf("No IDE drives mounted, disabling Gayle IDE component.\n");
141     gayle_ide_enabled = 0;
142   }
143 }
144
145 static uint8_t ide_action = 0;
146
147 void writeGayleB(unsigned int address, unsigned int value) {
148   if (ide0) {
149     if (address >= gayle_ide_base) {
150       switch ((address - gayle_ide_base) - gayle_ide_adj) {
151         case GFEAT_OFFSET:
152           //printf("Write to GFEAT: %.2X.\n", value);
153           ide_action = ide_feature_w;
154           goto idewrite8;
155         case GCMD_OFFSET:
156           //printf("Write to GCMD: %.2X.\n", value);
157           ide_action = ide_command_w;
158           goto idewrite8;
159         case GSECTCOUNT_OFFSET:
160           ide_action = ide_sec_count;
161           goto idewrite8;
162         case GSECTNUM_OFFSET:
163           ide_action = ide_sec_num;
164           goto idewrite8;
165         case GCYLLOW_OFFSET:
166           ide_action = ide_cyl_low;
167           goto idewrite8;
168         case GCYLHIGH_OFFSET:
169           ide_action = ide_cyl_hi;
170           goto idewrite8;
171         case GDEVHEAD_OFFSET:
172           //printf("Write to GDEVHEAD: %.2X.\n", value);
173           ide_action = ide_dev_head;
174           goto idewrite8;
175         case GCTRL_OFFSET:
176           //printf("Write to GCTRL: %.2X.\n", value);
177           ide_action = ide_devctrl_w;
178           goto idewrite8;
179         case GIRQ_4000_OFFSET:
180           gayle_a4k_irq = value;
181           // Fallthrough
182         case GIRQ_OFFSET:
183           gayle_irq = (gayle_irq & value) | (value & (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR));
184           return;
185       }
186       goto skip_idewrite8;
187 idewrite8:;
188       ide_write8(ide0, ide_action, value);
189       return;
190 skip_idewrite8:;
191     }
192   }
193
194   switch (address) {
195     /*case 0xDD203A:
196       printf("Write bye to A4000 Gayle: %.2X\n", value);
197       gayle_a4k = value;
198       return;*/
199     case GIDENT:
200       //printf("Write to GIDENT: %d\n", value);
201       counter = 0;
202       return;
203     case GCONF:
204       //printf("Write to GCONF: %d\n", gayle_cfg);
205       gayle_cfg = value;
206       return;
207     case RAMSEY_REG:
208       ramsey_cfg = value & 0x0F;
209       return;
210     case GINT:
211       gayle_int = value;
212       return;
213     case GCS:
214       gayle_cs_mask = value & ~3;
215       gayle_cs &= ~3;
216       gayle_cs |= value & 3;
217       printf("Write to GCS: %d\n", gayle_cs);
218       //ide0->selected = gayle_cs;
219       return;
220   }
221
222   if ((address & GAYLEMASK) == CLOCKBASE) {
223     if ((address & CLOCKMASK) >= 0x8000) {
224       if (cdtv_mode) {
225         //printf("[CDTV] BYTE write to SRAM @%.8X (%.8X): %.2X\n", (address & CLOCKMASK) - 0x8000, address, value);
226         cdtv_sram[(address & CLOCKMASK) - 0x8000] = value;
227       }
228       return;
229     }
230     //printf("Byte write to RTC.\n");
231     put_rtc_byte(address, value, rtc_type);
232     return;
233   }
234
235   DEBUG("Write Byte to Gayle Space 0x%06x (0x%06x)\n", address, value);
236 }
237
238 void writeGayle(unsigned int address, unsigned int value) {
239   if (ide0) {
240     if (address - gayle_ide_base == GDATA_OFFSET) {
241       ide_write16(ide0, ide_data, value);
242       return;
243     }
244
245     if (address == GIRQ_A4000) {
246       gayle_a4k_irq = value;
247       return;
248     }
249   }
250
251   if ((address & GAYLEMASK) == CLOCKBASE) {
252     if ((address & CLOCKMASK) >= 0x8000) {
253       if (cdtv_mode) {
254         //printf("[CDTV] WORD write to SRAM @%.8X (%.8X): %.4X\n", (address & CLOCKMASK) - 0x8000, address, htobe16(value));
255         ((short *) ((size_t)(cdtv_sram + (address & CLOCKMASK) - 0x8000)))[0] = htobe16(value);
256       }
257       return;
258     }
259     //printf("Word write to RTC.\n");
260     put_rtc_byte(address + 1, (value & 0xFF), rtc_type);
261     put_rtc_byte(address, (value >> 8), rtc_type);
262     return;
263   }
264
265   DEBUG("Write Word to Gayle Space 0x%06x (0x%06x)\n", address, value);
266 }
267
268 void writeGayleL(unsigned int address, unsigned int value) {
269   if ((address & GAYLEMASK) == CLOCKBASE) {
270     if ((address & CLOCKMASK) >= 0x8000) {
271       if (cdtv_mode) {
272         //printf("[CDTV] LONGWORD write to SRAM @%.8X (%.8X): %.8X\n", (address & CLOCKMASK) - 0x8000, address, htobe32(value));
273         ((int *) (size_t)(cdtv_sram + (address & CLOCKMASK) - 0x8000))[0] = htobe32(value);
274       }
275       return;
276     }
277     //printf("Longword write to RTC.\n");
278     put_rtc_byte(address + 3, (value & 0xFF), rtc_type);
279     put_rtc_byte(address + 2, ((value & 0x0000FF00) >> 8), rtc_type);
280     put_rtc_byte(address + 1, ((value & 0x00FF0000) >> 16), rtc_type);
281     put_rtc_byte(address, (value >> 24), rtc_type);
282     return;
283   }
284
285   DEBUG("Write Long to Gayle Space 0x%06x (0x%06x)\n", address, value);
286 }
287
288 uint8_t readGayleB(unsigned int address) {
289   if (ide0) {
290     uint8_t ide_action = 0, ide_val = 0;
291
292     if (address >= gayle_ide_base) {
293       switch ((address - gayle_ide_base) - gayle_ide_adj) {
294         case GERROR_OFFSET:
295           ide_action = ide_error_r;
296           goto ideread8;
297         case GSTATUS_OFFSET:
298           ide_action = ide_status_r;
299           goto ideread8;
300         case GSECTCOUNT_OFFSET:
301           ide_action = ide_sec_count;
302           goto ideread8;
303         case GSECTNUM_OFFSET:
304           ide_action = ide_sec_num;
305           goto ideread8;
306         case GCYLLOW_OFFSET:
307           ide_action = ide_cyl_low;
308           goto ideread8;
309         case GCYLHIGH_OFFSET:
310           ide_action = ide_cyl_hi;
311           goto ideread8;
312         case GDEVHEAD_OFFSET:
313           ide_action = ide_dev_head;
314           goto ideread8;
315         case GCTRL_OFFSET:
316           ide_action = ide_altst_r;
317           goto ideread8;
318         case GIRQ_4000_OFFSET:
319         case GIRQ_OFFSET:
320           return 0x80;
321           //gayle_irq = (gayle_irq & value) | (value & (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR));
322       }
323       goto skip_ideread8;
324 ideread8:;
325       ide_val = ide_read8(ide0, ide_action);
326       return ide_val;
327 skip_ideread8:;
328     }
329
330     switch (address) {
331       case GIDENT: {
332         uint8_t val;
333         if (counter == 0 || counter == 1 || counter == 3) {
334           val = 0x80;  // 80; to enable gayle
335         } else {
336           val = 0x00;
337         }
338         counter++;
339         //printf("Read from GIDENT: %.2X.\n", val);
340         return val;
341       }
342       case GINT:
343         return gayle_int;
344       case GCONF:
345         //printf("Read from GCONF: %d\n", gayle_cfg & 0x0F);
346         return gayle_cfg & 0x0f;
347       case GCS: {
348         uint8_t v;
349         v = gayle_cs_mask | gayle_cs;
350         printf("Read from GCS: %d\n", v);
351         return v;
352       }
353       // This seems incorrect, GARY_REG3 is the same as GIDENT, and the A4000
354       // service manual says that Gary is accessible in the address range $DFC000 to $DFFFFF.
355       case GARY_REG0:
356       case GARY_REG1:
357       case GARY_REG2:
358         return gary_cfg[address - GARY_REG0];
359         break;
360       //case GARY_REG3:
361       case GARY_REG4:
362       //case GARY_REG5:
363         return gary_cfg[address - GARY_REG4];
364       case RAMSEY_ID:
365         return ramsey_id;
366       case RAMSEY_REG:
367         return ramsey_cfg;
368       case GARY_REG5: { // This makes no sense.
369         uint8_t val;
370         if (counter == 0 || counter == 1 || counter == 3) {
371           val = 0x80;  // 80; to enable GARY
372         } else {
373           val = 0x00;
374         }
375         counter++;
376         return val;
377       }
378       //case 0xDD203A:
379         // This can't be correct, as this is the same address as GDEVHEAD on the A4000 Gayle.
380         //printf("Read Byte from Gayle A4k: %.2X\n", gayle_a4k);
381         //return gayle_a4k;
382     }
383   }
384
385   if ((address & GAYLEMASK) == CLOCKBASE) {
386     if ((address & CLOCKMASK) >= 0x8000) {
387       if (cdtv_mode) {
388         //printf("[CDTV] BYTE read from SRAM @%.8X (%.8X): %.2X\n", (address & CLOCKMASK) - 0x8000, address, cdtv_sram[(address & CLOCKMASK) - 0x8000]);
389         return cdtv_sram[(address & CLOCKMASK) - 0x8000];
390       }
391       return 0;
392     }
393     //printf("Byte read from RTC.\n");
394     return get_rtc_byte(address, rtc_type);
395   }
396
397   DEBUG("Read Byte From Gayle Space 0x%06x\n", address);
398   return 0xFF;
399 }
400
401 uint16_t readGayle(unsigned int address) {
402   if (ide0) {
403     if (address - gayle_ide_base == GDATA_OFFSET) {
404       uint16_t value;
405       value = ide_read16(ide0, ide_data);
406       //        value = (value << 8) | (value >> 8);
407       return value;
408     }
409
410     if (address == GIRQ_A4000) {
411       gayle_a4k_irq = 0x8000;
412       return 0x8000;
413     }
414   }
415
416   if ((address & GAYLEMASK) == CLOCKBASE) {
417     if ((address & CLOCKMASK) >= 0x8000) {
418       if (cdtv_mode) {
419         //printf("[CDTV] WORD read from SRAM @%.8X (%.8X): %.4X\n", (address & CLOCKMASK) - 0x8000, address, be16toh( (( unsigned short *) (size_t)(cdtv_sram + (address & CLOCKMASK) - 0x8000))[0]));
420         return be16toh( (( unsigned short *) (size_t)(cdtv_sram + (address & CLOCKMASK) - 0x8000))[0]);
421       }
422       return 0;
423     }
424     //printf("Word read from RTC.\n");
425     return ((get_rtc_byte(address, rtc_type) << 8) | (get_rtc_byte(address + 1, rtc_type)));
426   }
427
428   DEBUG("Read Word From Gayle Space 0x%06x\n", address);
429   return 0x8000;
430 }
431
432 uint32_t readGayleL(unsigned int address) {
433   if ((address & GAYLEMASK) == CLOCKBASE) {
434     if ((address & CLOCKMASK) >= 0x8000) {
435       if (cdtv_mode) {
436         //printf("[CDTV] LONGWORD read from SRAM @%.8X (%.8X): %.8X\n", (address & CLOCKMASK) - 0x8000, address, be32toh( (( unsigned short *) (size_t)(cdtv_sram + (address & CLOCKMASK) - 0x8000))[0]));
437         return be32toh( (( unsigned int *) (size_t)(cdtv_sram + (address & CLOCKMASK) - 0x8000))[0]);
438       }
439       return 0;
440     }
441     //printf("Longword read from RTC.\n");
442     return ((get_rtc_byte(address, rtc_type) << 24) | (get_rtc_byte(address + 1, rtc_type) << 16) | (get_rtc_byte(address + 2, rtc_type) << 8) | (get_rtc_byte(address + 3, rtc_type)));
443   }
444
445   DEBUG("Read Long From Gayle Space 0x%06x\n", address);
446   return 0x8000;
447 }