]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/hw_nvram.c
sim: unify -Werror build settings
[thirdparty/binutils-gdb.git] / sim / ppc / hw_nvram.c
1 /* This file is part of the program psim.
2
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>.
17
18 */
19
20
21 #ifndef _HW_NVRAM_C_
22 #define _HW_NVRAM_C_
23
24 #ifndef STATIC_INLINE_HW_NVRAM
25 #define STATIC_INLINE_HW_NVRAM STATIC_INLINE
26 #endif
27
28 #include "device_table.h"
29
30 #include <time.h>
31 #include <string.h>
32
33 /* DEVICE
34
35
36 nvram - non-volatile memory with clock
37
38
39 DESCRIPTION
40
41
42 This device implements a small byte addressable non-volatile
43 memory. The top 8 bytes of this memory include a real-time clock.
44
45
46 PROPERTIES
47
48
49 reg = <address> <size> (required)
50
51 Specify the address/size of this device within its parents address
52 space.
53
54
55 timezone = <integer> (optional)
56
57 Adjustment to the hosts current GMT (in seconds) that should be
58 applied when updating the NVRAM's clock. If no timezone is
59 specified, zero (GMT or UCT) is assumed.
60
61
62 */
63
64 typedef struct _hw_nvram_device {
65 unsigned8 *memory;
66 unsigned sizeof_memory;
67 time_t host_time;
68 unsigned timezone;
69 /* useful */
70 unsigned addr_year;
71 unsigned addr_month;
72 unsigned addr_date;
73 unsigned addr_day;
74 unsigned addr_hour;
75 unsigned addr_minutes;
76 unsigned addr_seconds;
77 unsigned addr_control;
78 } hw_nvram_device;
79
80 static void *
81 hw_nvram_create(const char *name,
82 const device_unit *unit_address,
83 const char *args)
84 {
85 hw_nvram_device *nvram = ZALLOC(hw_nvram_device);
86 return nvram;
87 }
88
89 typedef struct _hw_nvram_reg_spec {
90 unsigned32 base;
91 unsigned32 size;
92 } hw_nvram_reg_spec;
93
94 static void
95 hw_nvram_init_address(device *me)
96 {
97 hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
98
99 /* use the generic init code to attach this device to its parent bus */
100 generic_device_init_address(me);
101
102 /* find the first non zero reg property and use that as the device
103 size */
104 if (nvram->sizeof_memory == 0) {
105 reg_property_spec reg;
106 int reg_nr;
107 for (reg_nr = 0;
108 device_find_reg_array_property(me, "reg", reg_nr, &reg);
109 reg_nr++) {
110 unsigned attach_size;
111 if (device_size_to_attach_size(device_parent(me),
112 &reg.size, &attach_size,
113 me)) {
114 nvram->sizeof_memory = attach_size;
115 break;
116 }
117 }
118 if (nvram->sizeof_memory == 0)
119 device_error(me, "reg property must contain a non-zero phys-addr:size tupple");
120 if (nvram->sizeof_memory < 8)
121 device_error(me, "NVRAM must be at least 8 bytes in size");
122 }
123
124 /* initialize the hw_nvram */
125 if (nvram->memory == NULL) {
126 nvram->memory = zalloc(nvram->sizeof_memory);
127 }
128 else
129 memset(nvram->memory, 0, nvram->sizeof_memory);
130
131 if (device_find_property(me, "timezone") == NULL)
132 nvram->timezone = 0;
133 else
134 nvram->timezone = device_find_integer_property(me, "timezone");
135
136 nvram->addr_year = nvram->sizeof_memory - 1;
137 nvram->addr_month = nvram->sizeof_memory - 2;
138 nvram->addr_date = nvram->sizeof_memory - 3;
139 nvram->addr_day = nvram->sizeof_memory - 4;
140 nvram->addr_hour = nvram->sizeof_memory - 5;
141 nvram->addr_minutes = nvram->sizeof_memory - 6;
142 nvram->addr_seconds = nvram->sizeof_memory - 7;
143 nvram->addr_control = nvram->sizeof_memory - 8;
144
145 }
146
147 static int
148 hw_nvram_bcd(int val)
149 {
150 val = val % 100;
151 if (val < 0)
152 val += 100;
153 return ((val / 10) << 4) + (val % 10);
154 }
155
156
157 /* If reached an update interval and allowed, update the clock within
158 the hw_nvram. While this function could be implemented using events
159 it isn't on the assumption that the HW_NVRAM will hardly ever be
160 referenced and hence there is little need in keeping the clock
161 continually up-to-date */
162
163 static void
164 hw_nvram_update_clock(hw_nvram_device *nvram,
165 cpu *processor)
166 {
167 if (!(nvram->memory[nvram->addr_control] & 0xc0)) {
168 time_t host_time = time(NULL);
169 if (nvram->host_time != host_time) {
170 time_t nvtime = host_time + nvram->timezone;
171 struct tm *clock = gmtime(&nvtime);
172 nvram->host_time = host_time;
173 nvram->memory[nvram->addr_year] = hw_nvram_bcd(clock->tm_year);
174 nvram->memory[nvram->addr_month] = hw_nvram_bcd(clock->tm_mon + 1);
175 nvram->memory[nvram->addr_date] = hw_nvram_bcd(clock->tm_mday);
176 nvram->memory[nvram->addr_day] = hw_nvram_bcd(clock->tm_wday + 1);
177 nvram->memory[nvram->addr_hour] = hw_nvram_bcd(clock->tm_hour);
178 nvram->memory[nvram->addr_minutes] = hw_nvram_bcd(clock->tm_min);
179 nvram->memory[nvram->addr_seconds] = hw_nvram_bcd(clock->tm_sec);
180 }
181 }
182 }
183
184 static void
185 hw_nvram_set_clock(hw_nvram_device *nvram, cpu *processor)
186 {
187 error ("fixme - how do I set the localtime\n");
188 }
189
190 static unsigned
191 hw_nvram_io_read_buffer(device *me,
192 void *dest,
193 int space,
194 unsigned_word addr,
195 unsigned nr_bytes,
196 cpu *processor,
197 unsigned_word cia)
198 {
199 int i;
200 hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
201 for (i = 0; i < nr_bytes; i++) {
202 unsigned address = (addr + i) % nvram->sizeof_memory;
203 unsigned8 data = nvram->memory[address];
204 hw_nvram_update_clock(nvram, processor);
205 ((unsigned8*)dest)[i] = data;
206 }
207 return nr_bytes;
208 }
209
210 static unsigned
211 hw_nvram_io_write_buffer(device *me,
212 const void *source,
213 int space,
214 unsigned_word addr,
215 unsigned nr_bytes,
216 cpu *processor,
217 unsigned_word cia)
218 {
219 int i;
220 hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
221 for (i = 0; i < nr_bytes; i++) {
222 unsigned address = (addr + i) % nvram->sizeof_memory;
223 unsigned8 data = ((unsigned8*)source)[i];
224 if (address == nvram->addr_control
225 && (data & 0x80) == 0
226 && (nvram->memory[address] & 0x80) == 0x80)
227 hw_nvram_set_clock(nvram, processor);
228 else
229 hw_nvram_update_clock(nvram, processor);
230 nvram->memory[address] = data;
231 }
232 return nr_bytes;
233 }
234
235 static device_callbacks const hw_nvram_callbacks = {
236 { hw_nvram_init_address, },
237 { NULL, }, /* address */
238 { hw_nvram_io_read_buffer, hw_nvram_io_write_buffer }, /* IO */
239 };
240
241 const device_descriptor hw_nvram_device_descriptor[] = {
242 { "nvram", hw_nvram_create, &hw_nvram_callbacks },
243 { NULL },
244 };
245
246 #endif /* _HW_NVRAM_C_ */