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