1 /*
2 * rtc.cpp - Atari NVRAM emulation code
3 *
4 * Copyright (c) 2001-2006 Petr Stehlik of ARAnyM dev team (see AUTHORS)
5 *
6 * This file is part of the ARAnyM project which builds a new and powerful
7 * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
8 *
9 * ARAnyM is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * ARAnyM is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ARAnyM; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "sysdeps.h"
25 #include "hardware.h"
26 #include "cpu_emulation.h"
27 #include "memory-uae.h"
28 #include "rtc.h"
29 #include "parameters.h"
30
31 #define DEBUG 0
32 #include "debug.h"
33
34 #define CKS_RANGE_START 14
35 #define CKS_RANGE_END (14+47)
36 #define CKS_RANGE_LEN (CKS_RANGE_END-CKS_RANGE_START+1)
37 #define CKS_LOC (14+48)
38
39 uint8 nvram[64]={48,255,21,255,23,255,1,25,3,33,42,14,112,128,
40 0,0,0,0,0,0,0,0,17,46,32,1,255,0,0,56,135,0,0,0,0,0,0,0,
41 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,31};
42
43 #define NVRAM_SYSTEM_LANGUAGE 20
44 #define NVRAM_KEYBOARD_LAYOUT 21
45
46 /*
47 int byte15th = (colors & 7) | (80:40) << 3 | (VGA : TV) << 4 | (PAL : NTSC) << 5| overscan << 6 | STcompatible << 7);
48 int byte14th = VGA:TV ? line doubling : half screen;
49 */
50
RTC(memptr addr,uint32 size)51 RTC::RTC(memptr addr, uint32 size) : BASE_IO(addr, size)
52 {
53 init();
54 reset();
55 }
56
reset()57 void RTC::reset()
58 {
59 patch();
60 index = 0;
61 }
62
~RTC()63 RTC::~RTC()
64 {
65 save(); // save NVRAM file upon exit automatically (should be conditionalized)
66 }
67
init()68 void RTC::init()
69 {
70 // set up the nvram filename
71 getConfFilename(ARANYMNVRAM, nvram_filename, sizeof(nvram_filename));
72
73 load(); // load NVRAM file automatically
74
75 }
76
patch()77 void RTC::patch()
78 {
79 if (bx_options.video.monitor != -1) {
80 if (bx_options.video.monitor == 0) // VGA
81 nvram[29] |= 0x10; // the monitor type should be set on a working copy only
82 else
83 nvram[29] &= ~0x10;
84 }
85 if (bx_options.video.boot_color_depth != -1) {
86 int res = nvram[29] & 0x07;
87 switch(bx_options.video.boot_color_depth) {
88 case 1: res = 0; break;
89 case 2: res = 1; break;
90 case 4: res = 2; break;
91 case 8: res = 3; break;
92 case 16: res = 4; break;
93 }
94 nvram[29] &= ~0x07;
95 nvram[29] |= res; // the booting resolution should be set on a working copy only
96 }
97
98 if (bx_options.tos.cookie_akp != -1) {
99 nvram[NVRAM_SYSTEM_LANGUAGE] = bx_options.tos.cookie_akp & 0xff;
100 nvram[NVRAM_KEYBOARD_LAYOUT] = (bx_options.tos.cookie_akp >> 8) & 0xff;
101 }
102
103 setChecksum();
104 }
105
load()106 bool RTC::load()
107 {
108 bool ret = false;
109 FILE *f = fopen(nvram_filename, "rb");
110 if (f != NULL) {
111 uint8 fnvram[CKS_RANGE_LEN];
112 if (fread(fnvram, 1, CKS_RANGE_LEN, f) == CKS_RANGE_LEN) {
113 memcpy(nvram+CKS_RANGE_START, fnvram, CKS_RANGE_LEN);
114 ret = true;
115 }
116 fclose(f);
117 if (false /*verbose*/) infoprint("NVRAM loaded from '%s'", nvram_filename);
118 }
119 else {
120 panicbug("NVRAM not found at '%s'", nvram_filename);
121 }
122
123 return ret;
124 }
125
save()126 bool RTC::save()
127 {
128 bool ret = false;
129 FILE *f = fopen(nvram_filename, "wb");
130 if (f != NULL) {
131 if (fwrite(nvram+CKS_RANGE_START, 1, CKS_RANGE_LEN, f) == CKS_RANGE_LEN) {
132 ret = true;
133 }
134 fclose(f);
135 }
136 else {
137 panicbug("ERROR: cannot store NVRAM to '%s'", nvram_filename);
138 }
139
140 return ret;
141 }
142
handleRead(memptr addr)143 uint8 RTC::handleRead(memptr addr)
144 {
145 addr -= getHWoffset();
146 if (addr > getHWsize())
147 return 0;
148
149 switch(addr) {
150 case 1: return index;
151 case 3: return getData();
152 }
153
154 return 0;
155 }
156
handleWrite(memptr addr,uint8 value)157 void RTC::handleWrite(memptr addr, uint8 value)
158 {
159 addr -= getHWoffset();
160 if (addr > getHWsize())
161 return;
162
163 switch(addr) {
164 case 1: setAddr(value); break;
165 case 3: setData(value); break;
166 }
167 }
168
setAddr(uint8 value)169 void RTC::setAddr(uint8 value)
170 {
171 if (value < sizeof(nvram)) {
172 index = value;
173 }
174 else {
175 D(bug("NVRAM: trying to set out-of-bound position (%d)", value));
176 }
177 }
178
freezeTime(void)179 void RTC::freezeTime(void)
180 {
181 time_t tim = time(NULL);
182 frozen_time = *(bx_options.gmtime ? gmtime(&tim) : localtime(&tim));
183 }
184
getFrozenTime(void)185 struct tm RTC::getFrozenTime(void)
186 {
187 if (!(nvram[11] & 0x80))
188 freezeTime();
189 return frozen_time;
190 }
191
getData()192 uint8 RTC::getData()
193 {
194 uint8 value;
195
196 #define BIN_TO_BCD() \
197 if (!(nvram[11] & 0x04)) \
198 value = ((value / 10) << 4) | (value % 10)
199
200 switch(index) {
201 case 0:
202 value = getFrozenTime().tm_sec;
203 BIN_TO_BCD();
204 break;
205 case 2:
206 value = getFrozenTime().tm_min;
207 BIN_TO_BCD();
208 break;
209 case 4:
210 value = getFrozenTime().tm_hour;
211 if (!(nvram[11] & 0x02))
212 {
213 uint8 pmflag = (value == 0 || value >= 13) ? 0x80 : 0;
214 value = value % 12;
215 if (value == 0)
216 value = 12;
217 BIN_TO_BCD();
218 value |= pmflag;
219 } else
220 {
221 BIN_TO_BCD();
222 }
223 break;
224 case 6:
225 value = getFrozenTime().tm_wday + 1;
226 BIN_TO_BCD();
227 break;
228 case 7:
229 value = getFrozenTime().tm_mday;
230 BIN_TO_BCD();
231 break;
232 case 8:
233 value = getFrozenTime().tm_mon+1;
234 BIN_TO_BCD();
235 break;
236 case 9:
237 value = getFrozenTime().tm_year - 68;
238 BIN_TO_BCD();
239 break;
240 case 1: /* alarm seconds */
241 case 3: /* alarm minutes */
242 case 5: /* alarm hour */
243 value = nvram[index];
244 BIN_TO_BCD();
245 break;
246 case 10:
247 nvram[index] ^= 0x80; // toggle UIP bit
248 value = nvram[index];
249 break;
250 default:
251 value = nvram[index];
252 break;
253 }
254 D(bug("Reading NVRAM data at %d = %d ($%02x) at %06x", index, value, value, showPC()));
255 return value;
256 }
257
setData(uint8 value)258 void RTC::setData(uint8 value)
259 {
260 D(bug("Writing NVRAM data at %d = %d ($%02x) at %06x", index, value, value, showPC()));
261 switch (index)
262 {
263 case 11:
264 if (value & 0x80)
265 freezeTime();
266 break;
267 }
268 nvram[index] = value;
269 }
270
getNvramKeyboard()271 nvram_t RTC::getNvramKeyboard()
272 {
273 /* Return keyboard language setting */
274 return (nvram_t) nvram[NVRAM_KEYBOARD_LAYOUT];
275 }
276
277 /* the checksum is over all bytes except the checksum bytes
278 * themselves; these are at the very end */
setChecksum()279 void RTC::setChecksum()
280 {
281 int i;
282 unsigned char sum = 0;
283
284 for(i = CKS_RANGE_START; i <= CKS_RANGE_END; ++i)
285 sum += nvram[i];
286 nvram[CKS_LOC] = ~sum;
287 nvram[CKS_LOC+1] = sum;
288 }
289
290 /*
291 vim:ts=4:sw=4:
292 */
293