[PATCH 37/57][Arm][OBJDUMP] Add framework for MVE instructions
[binutils-gdb.git] / sim / ppc / hw_nvram.c
blobf8caaa8edd293909af1da57345e47a33d598b5bb
1 /* This file is part of the program psim.
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
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.
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.
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/>.
21 #ifndef _HW_NVRAM_C_
22 #define _HW_NVRAM_C_
24 #ifndef STATIC_INLINE_HW_NVRAM
25 #define STATIC_INLINE_HW_NVRAM STATIC_INLINE
26 #endif
28 #include "device_table.h"
30 #ifdef HAVE_TIME_H
31 #include <time.h>
32 #endif
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #else
37 #ifdef HAVE_STRINGS_H
38 #include <strings.h>
39 #endif
40 #endif
42 /* DEVICE
45 nvram - non-volatile memory with clock
48 DESCRIPTION
51 This device implements a small byte addressable non-volatile
52 memory. The top 8 bytes of this memory include a real-time clock.
55 PROPERTIES
58 reg = <address> <size> (required)
60 Specify the address/size of this device within its parents address
61 space.
64 timezone = <integer> (optional)
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.
73 typedef 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;
93 static void *
94 hw_nvram_create(const char *name,
95 const device_unit *unit_address,
96 const char *args)
98 hw_nvram_device *nvram = ZALLOC(hw_nvram_device);
99 return nvram;
102 typedef struct _hw_nvram_reg_spec {
103 unsigned32 base;
104 unsigned32 size;
105 } hw_nvram_reg_spec;
107 static void
108 hw_nvram_init_address(device *me)
110 hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
112 /* use the generic init code to attach this device to its parent bus */
113 generic_device_init_address(me);
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;
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");
137 /* initialize the hw_nvram */
138 if (nvram->memory == NULL) {
139 nvram->memory = zalloc(nvram->sizeof_memory);
141 else
142 memset(nvram->memory, 0, nvram->sizeof_memory);
144 if (device_find_property(me, "timezone") == NULL)
145 nvram->timezone = 0;
146 else
147 nvram->timezone = device_find_integer_property(me, "timezone");
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;
160 static int
161 hw_nvram_bcd(int val)
163 val = val % 100;
164 if (val < 0)
165 val += 100;
166 return ((val / 10) << 4) + (val % 10);
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 */
176 static void
177 hw_nvram_update_clock(hw_nvram_device *nvram,
178 cpu *processor)
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);
196 #else
197 error("fixme - where do I find out GMT\n");
198 #endif
201 static void
202 hw_nvram_set_clock(hw_nvram_device *nvram, cpu *processor)
204 error ("fixme - how do I set the localtime\n");
207 static unsigned
208 hw_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)
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;
224 return nr_bytes;
227 static unsigned
228 hw_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)
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;
249 return nr_bytes;
252 static 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 */
258 const device_descriptor hw_nvram_device_descriptor[] = {
259 { "nvram", hw_nvram_create, &hw_nvram_callbacks },
260 { NULL },
263 #endif /* _HW_NVRAM_C_ */