]> git.sesse.net Git - pistorm/blob - platforms/shared/rtc.c
Fix some RTC and CDTV NVRAM stuff
[pistorm] / platforms / shared / rtc.c
1 #include <time.h>
2 #include <stdio.h>
3 #include <stdint.h>
4 #include "rtc.h"
5
6 static unsigned char rtc_mystery_reg[3];
7 unsigned char ricoh_memory[0x0F];
8 unsigned char ricoh_alarm[0x0F];
9
10 void put_rtc_byte(uint32_t address_, uint8_t value_, uint8_t rtc_type) {
11   uint32_t address = address_ & 0x3F;
12   uint8_t value = (value_ & 0x0F);
13
14   address >>= 2;
15
16   //printf("Wrote byte %.2X.\n", address);
17
18   if (rtc_type == RTC_TYPE_MSM) {
19     switch(address) {
20       case 0x0D:
21         rtc_mystery_reg[address - 0x0D] = value & (0x01 | 0x08);
22         break;
23       case 0x0E:
24       case 0x0F:
25         rtc_mystery_reg[address - 0x0D] = value;
26         break;
27       default:
28         return;
29     }
30   }
31   else {
32     int rtc_bank = (rtc_mystery_reg[0] & 0x03);
33     if ((rtc_bank & 0x02) && address < 0x0D) {
34       if (rtc_bank & 0x01) {
35         // Low nibble of value -> high nibble in RTC memory
36         ricoh_memory[address] &= 0x0F;
37         ricoh_memory[address] |= ((value & 0x0F) << 4);
38       }
39       else {
40         // Low nibble of value -> low nibble in RTC memory
41         ricoh_memory[address] &= 0xF0;
42         ricoh_memory[address] |= (value & 0x0F);
43       }
44       return;
45     }
46     else if ((rtc_bank & 0x01) && address < 0x0D) {
47       // RTC alarm stuff, no idea what this is supposed to be for.
48       switch(address) {
49         case 0x00:
50         case 0x01:
51         case 0x09:
52         case 0x0C:
53           ricoh_alarm[address] = 0;
54           break;
55         case 0x03:
56         case 0x06:
57           ricoh_alarm[address] &= (value & (0x08 ^ 0xFF));
58           break;
59         case 0x05:
60         case 0x08:
61         case 0x0B:
62           ricoh_alarm[address] = (value & (0x0C ^ 0xFF));
63           break;
64         case 0x0A:
65           ricoh_alarm[address] = (value & (0x0E ^ 0xFF));
66           break;
67         default:
68           ricoh_alarm[address] = value;
69           break;
70       }
71       //printf("Write to Ricoh alarm @%.2X: %.2X -> %.2X\n", address, value, ricoh_alarm[address]);
72       return;
73     }
74     else if (address >= 0x0D) {
75       rtc_mystery_reg[address - 0x0D] = value;
76       return;
77     }
78   }
79 }
80
81 uint8_t get_rtc_byte(uint32_t address_, uint8_t rtc_type) {
82   uint32_t address = address_ & 0x3F;
83
84         if ((address & 3) == 2 || (address & 3) == 0) {
85     //printf("Garbage byte read.\n");
86                 return 0;
87         }
88
89   address >>= 2;
90   time_t t;
91   time(&t);
92   struct tm *rtc_time = localtime(&t);
93
94   if (rtc_type == RTC_TYPE_RICOH) {
95     int rtc_bank = (rtc_mystery_reg[0] & 0x03);
96     if ((rtc_bank & 0x02) && address < 0x0D) {
97       // Get low/high nibble from memory (bank 2/3)
98       return ((ricoh_memory[address] >> (rtc_bank & 0x01) ? 4 : 0) & 0x0F);
99     }
100     else if ((rtc_bank & 0x01) && address < 0x0D) {
101       // Get byte from alarm
102       return ricoh_alarm[address];
103     }
104   }
105
106   //printf("Read byte %.2X.\n", address);
107
108   switch (address) {
109     case 0x00: // Seconds low?
110       return rtc_time->tm_sec % 10;
111     case 0x01: // Seconds high?
112       return rtc_time->tm_sec / 10;
113     case 0x02: // Minutes low?
114       return rtc_time->tm_min % 10;
115     case 0x03: // Minutes high?
116       return rtc_time->tm_min / 10;
117     case 0x04: // Hours low?
118       return rtc_time->tm_hour % 10;
119     case 0x05: // Hours high?
120       if (rtc_type == RTC_TYPE_MSM) {
121         if (rtc_mystery_reg[2] & 4) {
122           return (((rtc_time->tm_hour % 12) / 10) | (rtc_time->tm_hour >= 12) ? 0x04 : 0x00);
123         }
124         else
125           return rtc_time->tm_hour / 10;
126       }
127       else {
128         if (ricoh_alarm[10] & 0x01) {
129           return rtc_time->tm_hour / 10;
130         }
131         else {
132           return (((rtc_time->tm_hour % 12) / 10) | (rtc_time->tm_hour >= 12) ? 0x02 : 0x00);
133         }
134         break;
135       }
136     case 0x06: // Day low?
137       if (rtc_type == RTC_TYPE_MSM)
138         return rtc_time->tm_mday % 10;
139       else
140         return rtc_time->tm_wday;
141     case 0x07: // Day high?
142       if (rtc_type == RTC_TYPE_MSM)
143         return rtc_time->tm_mday / 10;
144       else
145         return rtc_time->tm_mday % 10;
146     case 0x08: // Month low?
147       if (rtc_type == RTC_TYPE_MSM)
148         return (rtc_time->tm_mon + 1) % 10;
149       else
150         return rtc_time->tm_mday / 10;
151     case 0x09: // Month high?
152       if (rtc_type == RTC_TYPE_MSM)
153         return (rtc_time->tm_mon + 1) / 10;
154       else
155         return (rtc_time->tm_mon + 1) % 10;
156     case 0x0A: // Year low?
157       if (rtc_type == RTC_TYPE_MSM)
158         return rtc_time->tm_year % 10;
159       else
160         return (rtc_time->tm_mon + 1) / 10;
161     case 0x0B: // Year high?
162       if (rtc_type == RTC_TYPE_MSM)
163         return rtc_time->tm_year / 10;
164       else
165         return rtc_time->tm_year % 10;
166     case 0x0C: // Day of week?
167       if (rtc_type == RTC_TYPE_MSM)
168         return rtc_time->tm_wday;
169       else
170         return rtc_time->tm_year / 10;
171     case 0x0D: // Mystery register D-F?
172     case 0x0E:
173     case 0x0F:
174       if (rtc_type == RTC_TYPE_MSM) {
175         return rtc_mystery_reg[address - 0x0D];
176       }
177       else {
178         if (address == 0x0D) return rtc_mystery_reg[address - 0x0D];
179         return 0;
180       }
181     default:
182       break;
183   }
184
185   return 0x00;
186 }