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