gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / sim / ppc / hw_nvram.c
CommitLineData
c906108c
SS
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
3fd725ef 7 the Free Software Foundation; either version 3 of the License, or
c906108c
SS
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
51b318de 16 along with this program; if not, see <http://www.gnu.org/licenses/>.
c906108c
SS
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#ifdef HAVE_TIME_H
31#include <time.h>
32#endif
33
34#ifdef HAVE_STRING_H
35#include <string.h>
36#else
37#ifdef HAVE_STRINGS_H
38#include <strings.h>
39#endif
40#endif
41
42/* DEVICE
43
44
45 nvram - non-volatile memory with clock
46
47
48 DESCRIPTION
49
50
51 This device implements a small byte addressable non-volatile
52 memory. The top 8 bytes of this memory include a real-time clock.
53
54
55 PROPERTIES
56
57
58 reg = <address> <size> (required)
59
60 Specify the address/size of this device within its parents address
61 space.
62
63
64 timezone = <integer> (optional)
65
66 Adjustment to the hosts current GMT (in seconds) that should be
67 applied when updating the NVRAM's clock. If no timezone is
68 specified, zero (GMT or UCT) is assumed.
69
70
71 */
72
73typedef struct _hw_nvram_device {
74 unsigned8 *memory;
75 unsigned sizeof_memory;
76#ifdef HAVE_TIME_H
77 time_t host_time;
78#else
79 long host_time;
80#endif
81 unsigned timezone;
82 /* useful */
83 unsigned addr_year;
84 unsigned addr_month;
85 unsigned addr_date;
86 unsigned addr_day;
87 unsigned addr_hour;
88 unsigned addr_minutes;
89 unsigned addr_seconds;
90 unsigned addr_control;
91} hw_nvram_device;
92
93static void *
94hw_nvram_create(const char *name,
95 const device_unit *unit_address,
96 const char *args)
97{
98 hw_nvram_device *nvram = ZALLOC(hw_nvram_device);
99 return nvram;
100}
101
102typedef struct _hw_nvram_reg_spec {
103 unsigned32 base;
104 unsigned32 size;
105} hw_nvram_reg_spec;
106
107static void
108hw_nvram_init_address(device *me)
109{
110 hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
111
112 /* use the generic init code to attach this device to its parent bus */
113 generic_device_init_address(me);
114
115 /* find the first non zero reg property and use that as the device
116 size */
117 if (nvram->sizeof_memory == 0) {
118 reg_property_spec reg;
119 int reg_nr;
120 for (reg_nr = 0;
121 device_find_reg_array_property(me, "reg", reg_nr, &reg);
122 reg_nr++) {
123 unsigned attach_size;
124 if (device_size_to_attach_size(device_parent(me),
125 &reg.size, &attach_size,
126 me)) {
127 nvram->sizeof_memory = attach_size;
128 break;
129 }
130 }
131 if (nvram->sizeof_memory == 0)
132 device_error(me, "reg property must contain a non-zero phys-addr:size tupple");
133 if (nvram->sizeof_memory < 8)
134 device_error(me, "NVRAM must be at least 8 bytes in size");
135 }
136
137 /* initialize the hw_nvram */
138 if (nvram->memory == NULL) {
139 nvram->memory = zalloc(nvram->sizeof_memory);
140 }
141 else
0f2f1341 142 memset(nvram->memory, 0, nvram->sizeof_memory);
c906108c
SS
143
144 if (device_find_property(me, "timezone") == NULL)
145 nvram->timezone = 0;
146 else
147 nvram->timezone = device_find_integer_property(me, "timezone");
148
149 nvram->addr_year = nvram->sizeof_memory - 1;
150 nvram->addr_month = nvram->sizeof_memory - 2;
151 nvram->addr_date = nvram->sizeof_memory - 3;
152 nvram->addr_day = nvram->sizeof_memory - 4;
153 nvram->addr_hour = nvram->sizeof_memory - 5;
154 nvram->addr_minutes = nvram->sizeof_memory - 6;
155 nvram->addr_seconds = nvram->sizeof_memory - 7;
156 nvram->addr_control = nvram->sizeof_memory - 8;
157
158}
159
160static int
161hw_nvram_bcd(int val)
162{
163 val = val % 100;
164 if (val < 0)
165 val += 100;
166 return ((val / 10) << 4) + (val % 10);
167}
168
169
170/* If reached an update interval and allowed, update the clock within
171 the hw_nvram. While this function could be implemented using events
172 it isn't on the assumption that the HW_NVRAM will hardly ever be
173 referenced and hence there is little need in keeping the clock
174 continually up-to-date */
175
176static void
177hw_nvram_update_clock(hw_nvram_device *nvram,
178 cpu *processor)
179{
180#ifdef HAVE_TIME_H
181 if (!(nvram->memory[nvram->addr_control] & 0xc0)) {
182 time_t host_time = time(NULL);
183 if (nvram->host_time != host_time) {
184 time_t nvtime = host_time + nvram->timezone;
185 struct tm *clock = gmtime(&nvtime);
186 nvram->host_time = host_time;
187 nvram->memory[nvram->addr_year] = hw_nvram_bcd(clock->tm_year);
188 nvram->memory[nvram->addr_month] = hw_nvram_bcd(clock->tm_mon + 1);
189 nvram->memory[nvram->addr_date] = hw_nvram_bcd(clock->tm_mday);
190 nvram->memory[nvram->addr_day] = hw_nvram_bcd(clock->tm_wday + 1);
191 nvram->memory[nvram->addr_hour] = hw_nvram_bcd(clock->tm_hour);
192 nvram->memory[nvram->addr_minutes] = hw_nvram_bcd(clock->tm_min);
193 nvram->memory[nvram->addr_seconds] = hw_nvram_bcd(clock->tm_sec);
194 }
195 }
196#else
197 error("fixme - where do I find out GMT\n");
198#endif
199}
200
201static void
202hw_nvram_set_clock(hw_nvram_device *nvram, cpu *processor)
203{
204 error ("fixme - how do I set the localtime\n");
205}
206
207static unsigned
208hw_nvram_io_read_buffer(device *me,
209 void *dest,
210 int space,
211 unsigned_word addr,
212 unsigned nr_bytes,
213 cpu *processor,
214 unsigned_word cia)
215{
216 int i;
217 hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
218 for (i = 0; i < nr_bytes; i++) {
219 unsigned address = (addr + i) % nvram->sizeof_memory;
220 unsigned8 data = nvram->memory[address];
221 hw_nvram_update_clock(nvram, processor);
222 ((unsigned8*)dest)[i] = data;
223 }
224 return nr_bytes;
225}
226
227static unsigned
228hw_nvram_io_write_buffer(device *me,
229 const void *source,
230 int space,
231 unsigned_word addr,
232 unsigned nr_bytes,
233 cpu *processor,
234 unsigned_word cia)
235{
236 int i;
237 hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
238 for (i = 0; i < nr_bytes; i++) {
239 unsigned address = (addr + i) % nvram->sizeof_memory;
240 unsigned8 data = ((unsigned8*)source)[i];
241 if (address == nvram->addr_control
242 && (data & 0x80) == 0
243 && (nvram->memory[address] & 0x80) == 0x80)
244 hw_nvram_set_clock(nvram, processor);
245 else
246 hw_nvram_update_clock(nvram, processor);
247 nvram->memory[address] = data;
248 }
249 return nr_bytes;
250}
251
252static device_callbacks const hw_nvram_callbacks = {
253 { hw_nvram_init_address, },
254 { NULL, }, /* address */
255 { hw_nvram_io_read_buffer, hw_nvram_io_write_buffer }, /* IO */
256};
257
258const device_descriptor hw_nvram_device_descriptor[] = {
259 { "nvram", hw_nvram_create, &hw_nvram_callbacks },
260 { NULL },
261};
262
263#endif /* _HW_NVRAM_C_ */
This page took 1.284217 seconds and 4 git commands to generate.