]> git.sesse.net Git - pistorm/blob - Gayle.c
Fix a bunch of stuff, add working RICOH RTC emulation.
[pistorm] / 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 #include "ide.h"
22 #include "config_file/config_file.h"
23 #include "platforms/amiga/amiga-registers.h"
24
25 //#define GSTATUS 0xda201c
26 //#define GCLOW   0xda2010
27 //#define GDH   0xda2018
28
29 // Gayle Addresses
30
31 // Gayle IDE Reads
32 #define GERROR 0xda2004   // Error
33 #define GSTATUS 0xda201c  // Status
34 // Gayle IDE Writes
35 #define GFEAT 0xda2004  // Write : Feature
36 #define GCMD 0xda201c   // Write : Command
37 // Gayle IDE RW
38 #define GDATA 0xda2000     // Data
39 #define GSECTCNT 0xda2008  // SectorCount
40 #define GSECTNUM 0xda200c  // SectorNumber
41 #define GCYLLOW 0xda2010   // CylinderLow
42 #define GCYLHIGH 0xda2014  // CylinderHigh
43 #define GDEVHEAD 0xda2018  // Device/Head
44 #define GCTRL 0xda3018     // Control
45 // Gayle Ident
46 #define GIDENT 0xDE1000
47
48 // Gayle IRQ/CC
49 #define GCS 0xDA8000   // Card Control
50 #define GIRQ 0xDA9000  // IRQ
51 #define GINT 0xDAA000  // Int enable
52 #define GCONF 0xDAB000  // Gayle Config
53
54 /* DA8000 */
55 #define GAYLE_CS_IDE 0x80   /* IDE int status */
56 #define GAYLE_CS_CCDET 0x40 /* credit card detect */
57 #define GAYLE_CS_BVD1 0x20  /* battery voltage detect 1 */
58 #define GAYLE_CS_SC 0x20    /* credit card status change */
59 #define GAYLE_CS_BVD2 0x10  /* battery voltage detect 2 */
60 #define GAYLE_CS_DA 0x10    /* digital audio */
61 #define GAYLE_CS_WR 0x08    /* write enable (1 == enabled) */
62 #define GAYLE_CS_BSY 0x04   /* credit card busy */
63 #define GAYLE_CS_IRQ 0x04   /* interrupt request */
64 #define GAYLE_CS_DAEN 0x02  /* enable digital audio */
65 #define GAYLE_CS_DIS 0x01   /* disable PCMCIA slot */
66
67 /* DA9000 */
68 #define GAYLE_IRQ_IDE 0x80
69 #define GAYLE_IRQ_CCDET 0x40 /* credit card detect */
70 #define GAYLE_IRQ_BVD1 0x20  /* battery voltage detect 1 */
71 #define GAYLE_IRQ_SC 0x20    /* credit card status change */
72 #define GAYLE_IRQ_BVD2 0x10  /* battery voltage detect 2 */
73 #define GAYLE_IRQ_DA 0x10    /* digital audio */
74 #define GAYLE_IRQ_WR 0x08    /* write enable (1 == enabled) */
75 #define GAYLE_IRQ_BSY 0x04   /* credit card busy */
76 #define GAYLE_IRQ_IRQ 0x04   /* interrupt request */
77 #define GAYLE_IRQ_RESET 0x02 /* reset machine after CCDET change */
78 #define GAYLE_IRQ_BERR 0x01  /* generate bus error after CCDET change */
79
80 /* DAA000 */
81 #define GAYLE_INT_IDE 0x80     /* IDE interrupt enable */
82 #define GAYLE_INT_CCDET 0x40   /* credit card detect change enable */
83 #define GAYLE_INT_BVD1 0x20    /* battery voltage detect 1 change enable */
84 #define GAYLE_INT_SC 0x20      /* credit card status change enable */
85 #define GAYLE_INT_BVD2 0x10    /* battery voltage detect 2 change enable */
86 #define GAYLE_INT_DA 0x10      /* digital audio change enable */
87 #define GAYLE_INT_WR 0x08      /* write enable change enabled */
88 #define GAYLE_INT_BSY 0x04     /* credit card busy */
89 #define GAYLE_INT_IRQ 0x04     /* credit card interrupt request */
90 #define GAYLE_INT_BVD_LEV 0x02 /* BVD int level, 0=lev2,1=lev6 */
91 #define GAYLE_INT_BSY_LEV 0x01 /* BSY int level, 0=lev2,1=lev6 */
92
93 #define GAYLE_MAX_HARDFILES 8
94
95 int counter;
96 static uint8_t gayle_irq, gayle_int, gayle_cs, gayle_cs_mask, gayle_cfg;
97 static struct ide_controller *ide0;
98 int fd;
99
100 uint8_t rtc_type = RTC_TYPE_RICOH;
101
102 char *hdd_image_file[GAYLE_MAX_HARDFILES];
103
104 void set_hard_drive_image_file_amiga(uint8_t index, char *filename) {
105   if (hdd_image_file[index] != NULL)
106     free(hdd_image_file[index]);
107   hdd_image_file[index] = calloc(1, strlen(filename) + 1);
108   strcpy(hdd_image_file[index], filename);
109 }
110
111 void InitGayle(void) {
112   if (!hdd_image_file[0]) {
113     hdd_image_file[0] = calloc(1, 64);
114     sprintf(hdd_image_file[0], "hd0.img");
115   }
116
117   ide0 = ide_allocate("cf");
118   fd = open(hdd_image_file[0], O_RDWR);
119   if (fd == -1) {
120     printf("HDD Image %s failed open\n", hdd_image_file[0]);
121   } else {
122     ide_attach(ide0, 0, fd);
123     ide_reset_begin(ide0);
124     printf("HDD Image %s attached\n", hdd_image_file[0]);
125   }
126 }
127
128 uint8_t CheckIrq(void) {
129   uint8_t irq;
130
131   if (gayle_int & (1 << 7)) {
132     irq = ide0->drive->intrq;
133     //  if (irq==0)
134     //  printf("IDE IRQ: %x\n",irq);
135     return irq;
136   };
137   return 0;
138 }
139
140 void writeGayleB(unsigned int address, unsigned int value) {
141   if (address == GFEAT) {
142     ide_write8(ide0, ide_feature_w, value);
143     return;
144   }
145   if (address == GCMD) {
146     ide_write8(ide0, ide_command_w, value);
147     return;
148   }
149   if (address == GSECTCNT) {
150     ide_write8(ide0, ide_sec_count, value);
151     return;
152   }
153   if (address == GSECTNUM) {
154     ide_write8(ide0, ide_sec_num, value);
155     return;
156   }
157   if (address == GCYLLOW) {
158     ide_write8(ide0, ide_cyl_low, value);
159     return;
160   }
161   if (address == GCYLHIGH) {
162     ide_write8(ide0, ide_cyl_hi, value);
163     return;
164   }
165   if (address == GDEVHEAD) {
166     ide_write8(ide0, ide_dev_head, value);
167     return;
168   }
169   if (address == GCTRL) {
170     ide_write8(ide0, ide_devctrl_w, value);
171     return;
172   }
173
174   if (address == GIDENT) {
175     counter = 0;
176     // printf("Write Byte to Gayle Ident 0x%06x (0x%06x)\n",address,value);
177     return;
178   }
179
180   if (address == GIRQ) {
181     //   printf("Write Byte to Gayle GIRQ 0x%06x (0x%06x)\n",address,value);
182     gayle_irq = (gayle_irq & value) | (value & (GAYLE_IRQ_RESET | GAYLE_IRQ_BERR));
183
184     return;
185   }
186
187   if (address == GCS) {
188     printf("Write Byte to Gayle GCS 0x%06x (0x%06x)\n", address, value);
189     gayle_cs_mask = value & ~3;
190     gayle_cs &= ~3;
191     gayle_cs |= value & 3;
192     return;
193   }
194
195   if (address == GINT) {
196     printf("Write Byte to Gayle GINT 0x%06x (0x%06x)\n", address, value);
197     gayle_int = value;
198     return;
199   }
200
201   if (address == GCONF) {
202     printf("Write Byte to Gayle GCONF 0x%06x (0x%06x)\n", address, value);
203     gayle_cfg = value;
204     return;
205   }
206
207   if ((address & GAYLEMASK) == CLOCKBASE) {
208     if ((address & CLOCKMASK) >= 0x8000) {
209       printf("Byte write to CDTV SRAM?\n");
210       return;
211     }
212     put_rtc_byte(address, value, rtc_type);
213     return;
214   }
215
216   printf("Write Byte to Gayle Space 0x%06x (0x%06x)\n", address, value);
217 }
218
219 void writeGayle(unsigned int address, unsigned int value) {
220   if (address == GDATA) {
221     ide_write16(ide0, ide_data, value);
222     return;
223   }
224
225   if ((address & GAYLEMASK) == CLOCKBASE) {
226     if ((address & CLOCKMASK) >= 0x8000) {
227       printf("Word write to CDTV SRAM?\n");
228       return;
229     }
230     printf("Word write to RTC.\n");
231     put_rtc_byte(address, (value & 0xFF), rtc_type);
232     put_rtc_byte(address + 1, (value >> 8), rtc_type);
233     return;
234   }
235
236   printf("Write Word to Gayle Space 0x%06x (0x%06x)\n", address, value);
237 }
238
239 void writeGayleL(unsigned int address, unsigned int value) {
240   if ((address & GAYLEMASK) == CLOCKBASE) {
241     if ((address & CLOCKMASK) >= 0x8000) {
242       printf("Longword write to CDTV SRAM?\n");
243       return;
244     }
245     printf("Longword write to RTC.\n");
246     put_rtc_byte(address, (value & 0xFF), rtc_type);
247     put_rtc_byte(address + 1, ((value & 0x0000FF00) >> 8), rtc_type);
248     put_rtc_byte(address + 2, ((value & 0x00FF0000) >> 16), rtc_type);
249     put_rtc_byte(address + 3, (value >> 24), rtc_type);
250     return;
251   }
252
253   printf("Write Long to Gayle Space 0x%06x (0x%06x)\n", address, value);
254 }
255
256 static unsigned char rtc_mystery_reg[3];
257
258 void put_rtc_byte(uint32_t address_, uint8_t value, uint8_t rtc_type) {
259   uint32_t address = address_ & 0x3F;
260   address >>= 2;
261   if (rtc_type == RTC_TYPE_MSM) {
262     switch(address) {
263       case 0x0D:
264         rtc_mystery_reg[address - 0x0D] = value & (0x01 | 0x08);
265         break;
266       case 0x0E:
267       case 0x0F:
268         rtc_mystery_reg[address - 0x0D] = value;
269         break;
270       default:
271         return;
272     }
273   }
274   else {
275     int rtc_bank = (rtc_mystery_reg[0] & 0x03);
276     if ((rtc_bank & 0x02) && address < 0x0D) {
277       // RTC memory access?
278       printf("Write to Ricoh RTC memory.\n");
279       return;
280     }
281     else if ((rtc_bank & 0x01) && address < 0x0D) {
282       // RTC alarm access?
283       printf("Write to Ricoh RTC alarm.\n");
284       return;
285     }
286     else if (address >= 0x0D) {
287       rtc_mystery_reg[address - 0x0D] = value;
288       return;
289     }
290   }
291 }
292
293 uint8_t get_rtc_byte(uint32_t address_, uint8_t rtc_type) {
294   uint32_t address = address_;
295   address >>= 2;
296   time_t t;
297   time(&t);
298   struct tm *rtc_time = localtime(&t);
299
300   if (rtc_type == RTC_TYPE_RICOH) {
301     int rtc_bank = (rtc_mystery_reg[0] & 0x03);
302     if ((rtc_bank & 0x02) && address < 0x0D) {
303       // RTC memory access?
304       printf("Read from Ricoh RTC memory.\n");
305       return 0;
306     }
307     else if ((rtc_bank & 0x01) && address < 0x0D) {
308       // RTC alarm access?
309       printf("Read from Ricoh RTC alarm.\n");
310       return 0;
311     }
312   }
313
314   switch (address) {
315     case 0x00: // Seconds low?
316       return rtc_time->tm_sec % 10;
317     case 0x01: // Seconds high?
318       return rtc_time->tm_sec / 10;
319     case 0x02: // Minutes low?
320       return rtc_time->tm_min % 10;
321     case 0x03: // Minutes high?
322       return rtc_time->tm_min / 10;
323     case 0x04: // Hours low?
324       return rtc_time->tm_hour % 10;
325     case 0x05: // Hours high?
326       if (rtc_type == RTC_TYPE_MSM) {
327         if (rtc_mystery_reg[2] & 4) {
328           return ((rtc_time->tm_hour / 10) | (rtc_time->tm_hour > 12) ? 0x04 : 0x00);
329         }
330         else
331           return rtc_time->tm_hour / 10;
332       }
333       else {
334         break;
335       }
336     case 0x06: // Day low?
337       if (rtc_type == RTC_TYPE_MSM)
338         return rtc_time->tm_mday % 10;
339       else
340         return rtc_time->tm_wday;
341     case 0x07: // Day high?
342       if (rtc_type == RTC_TYPE_MSM)
343         return rtc_time->tm_mday / 10;
344       else
345         return rtc_time->tm_mday % 10;
346     case 0x08: // Month low?
347       if (rtc_type == RTC_TYPE_MSM)
348         return (rtc_time->tm_mon + 1) % 10;
349       else
350         return rtc_time->tm_mday / 10;
351     case 0x09: // Month high?
352       if (rtc_type == RTC_TYPE_MSM)
353         return (rtc_time->tm_mon + 1) / 10;
354       else
355         return (rtc_time->tm_mon + 1) % 10;
356     case 0x0A: // Year low?
357       if (rtc_type == RTC_TYPE_MSM)
358         return rtc_time->tm_year % 10;
359       else
360         return (rtc_time->tm_mon + 1) / 10;
361     case 0x0B: // Year high?
362       if (rtc_type == RTC_TYPE_MSM)
363         return rtc_time->tm_year / 10;
364       else
365         return rtc_time->tm_year % 10;
366     case 0x0C: // Day of week?
367       if (rtc_type == RTC_TYPE_MSM)
368         return rtc_time->tm_wday;
369       else
370         return rtc_time->tm_year / 10;
371     case 0x0D: // Mystery register D-F?
372       return rtc_mystery_reg[address - 0x0D];
373     case 0x0E:
374     case 0x0F:
375       return 0;
376     default:
377       break;
378   }
379
380   return 0x00;
381 }
382
383 uint8_t readGayleB(unsigned int address) {
384   if (address == GERROR) {
385     return ide_read8(ide0, ide_error_r);
386   }
387   if (address == GSTATUS) {
388     return ide_read8(ide0, ide_status_r);
389   }
390
391   if (address == GSECTCNT) {
392     return ide_read8(ide0, ide_sec_count);
393   }
394
395   if (address == GSECTNUM) {
396     return ide_read8(ide0, ide_sec_num);
397   }
398
399   if (address == GCYLLOW) {
400     return ide_read8(ide0, ide_cyl_low);
401   }
402
403   if (address == GCYLHIGH) {
404     return ide_read8(ide0, ide_cyl_hi);
405   }
406
407   if (address == GDEVHEAD) {
408     return ide_read8(ide0, ide_dev_head);
409   }
410
411   if (address == GCTRL) {
412     return ide_read8(ide0, ide_altst_r);
413   }
414
415   if ((address & GAYLEMASK) == CLOCKBASE) {
416     if ((address & CLOCKMASK) >= 0x8000) {
417       printf("Byte read from CDTV SRAM?\n");
418       return 0;
419     }
420     return get_rtc_byte((address & 0x3F), rtc_type);
421   }
422
423   if (address == GIDENT) {
424     uint8_t val;
425     // printf("Read Byte from Gayle Ident 0x%06x (0x%06x)\n",address,counter);
426     if (counter == 0 || counter == 1 || counter == 3) {
427       val = 0x80;  // 80; to enable gayle
428     } else {
429       val = 0x00;
430     }
431     counter++;
432     return val;
433   }
434
435   if (address == GIRQ) {
436     //  printf("Read Byte From GIRQ Space 0x%06x\n",gayle_irq);
437
438     return 0x80;//gayle_irq;
439 /*
440     uint8_t irq;
441     irq = ide0->drive->intrq;
442
443     if (irq == 1) {
444       // printf("IDE IRQ: %x\n",irq);
445       return 0x80;  // gayle_irq;
446     }
447
448     return 0;
449 */ 
450  }
451
452   if (address == GCS) {
453     printf("Read Byte From GCS Space 0x%06x\n", 0x1234);
454     uint8_t v;
455     v = gayle_cs_mask | gayle_cs;
456     return v;
457   }
458
459   if (address == GINT) {
460     //  printf("Read Byte From GINT Space 0x%06x\n",gayle_int);
461     return gayle_int;
462   }
463
464   if (address == GCONF) {
465     printf("Read Byte From GCONF Space 0x%06x\n", gayle_cfg & 0x0f);
466     return gayle_cfg & 0x0f;
467   }
468
469   printf("Read Byte From Gayle Space 0x%06x\n", address);
470   return 0xFF;
471 }
472
473 uint16_t readGayle(unsigned int address) {
474   if (address == GDATA) {
475     uint16_t value;
476     value = ide_read16(ide0, ide_data);
477     //  value = (value << 8) | (value >> 8);
478     return value;
479   }
480
481   if ((address & GAYLEMASK) == CLOCKBASE) {
482     if ((address & CLOCKMASK) >= 0x8000) {
483       printf("Word read from CDTV SRAM?\n");
484       return 0;
485     }
486     return ((get_rtc_byte((address & 0x3F), rtc_type) << 8) | (get_rtc_byte(((address + 1) & 0x3F), rtc_type)));
487   }
488
489   printf("Read Word From Gayle Space 0x%06x\n", address);
490   return 0x8000;
491 }
492
493 uint32_t readGayleL(unsigned int address) {
494   if ((address & GAYLEMASK) == CLOCKBASE) {
495     if ((address & CLOCKMASK) >= 0x8000) {
496       printf("Longword read from CDTV SRAM?\n");
497       return 0;
498     }
499     return ((get_rtc_byte((address & 0x3F), rtc_type) << 24) | (get_rtc_byte(((address + 1) & 0x3F), rtc_type) << 16) | (get_rtc_byte(((address + 2) & 0x3F), rtc_type) << 8) | (get_rtc_byte(((address + 3) & 0x3F), rtc_type)));
500   }
501
502   printf("Read Long From Gayle Space 0x%06x\n", address);
503   return 0x8000;
504 }