* gdbtk.tcl (files_command): Correctly insert list of files into
[deliverable/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 2 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, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21
22 #ifndef _HW_NVRAM_C_
23 #define _HW_NVRAM_C_
24
25 #ifndef STATIC_INLINE_HW_NVRAM
26 #define STATIC_INLINE_HW_NVRAM STATIC_INLINE
27 #endif
28
29 #include "device_table.h"
30
31 #ifdef HAVE_TIME_H
32 #include <time.h>
33 #endif
34
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #else
38 #ifdef HAVE_STRINGS_H
39 #include <strings.h>
40 #endif
41 #endif
42
43 /* NVRAM - non-volatile memory with optional clock.
44
45 Description:
46
47 This device implements a small byte addressable non-volatile memory
48 component. The component may include an optional real-time clock
49 at its upper addresses.
50
51 Properties:
52
53 reg = <address> <size>. Determine where the device lives in the
54 parents address space.
55
56 timezone = <integer>. Adjustment to current host's GMT (in secons)
57 that should be applied when updating the NVRAM's clock. */
58
59 typedef struct _hw_nvram_device {
60 unsigned8 *memory;
61 unsigned sizeof_memory;
62 #ifdef HAVE_TIME_H
63 time_t host_time;
64 #else
65 long host_time;
66 #endif
67 unsigned timezone;
68 /* useful */
69 unsigned addr_year;
70 unsigned addr_month;
71 unsigned addr_date;
72 unsigned addr_day;
73 unsigned addr_hour;
74 unsigned addr_minutes;
75 unsigned addr_seconds;
76 unsigned addr_control;
77 } hw_nvram_device;
78
79 static void *
80 hw_nvram_create(const char *name,
81 const device_unit *unit_address,
82 const char *args,
83 device *parent)
84 {
85 hw_nvram_device *hw_nvram = ZALLOC(hw_nvram_device);
86 return hw_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 *hw_nvram = (hw_nvram_device*)device_data(me);
98 const device_property *reg = device_find_array_property(me, "reg");
99 const hw_nvram_reg_spec *spec = reg->array;
100 int nr_entries = reg->sizeof_array / sizeof(*spec);
101
102 if ((reg->sizeof_array % sizeof(*spec)) != 0)
103 error("devices/%s reg property of incorrect size\n", device_name(me));
104 if (nr_entries > 1)
105 error("devices/%s reg property contains multiple specs\n",
106 device_name(me));
107
108 /* initialize the hw_nvram */
109 if (hw_nvram->memory == NULL) {
110 hw_nvram->sizeof_memory = BE2H_4(spec->size);
111 hw_nvram->memory = zalloc(hw_nvram->sizeof_memory);
112 }
113 else
114 memset(hw_nvram->memory, hw_nvram->sizeof_memory, 0);
115
116 hw_nvram->timezone = device_find_integer_property(me, "timezone");
117
118 hw_nvram->addr_year = hw_nvram->sizeof_memory - 1;
119 hw_nvram->addr_month = hw_nvram->sizeof_memory - 2;
120 hw_nvram->addr_date = hw_nvram->sizeof_memory - 3;
121 hw_nvram->addr_day = hw_nvram->sizeof_memory - 4;
122 hw_nvram->addr_hour = hw_nvram->sizeof_memory - 5;
123 hw_nvram->addr_minutes = hw_nvram->sizeof_memory - 6;
124 hw_nvram->addr_seconds = hw_nvram->sizeof_memory - 7;
125 hw_nvram->addr_control = hw_nvram->sizeof_memory - 8;
126
127 device_attach_address(device_parent(me),
128 device_name(me),
129 attach_callback,
130 0 /*address space*/,
131 BE2H_4(spec->base),
132 hw_nvram->sizeof_memory,
133 access_read_write_exec,
134 me);
135 }
136
137 static int
138 hw_nvram_bcd(int val)
139 {
140 return ((val / 10) << 4) + (val % 10);
141 }
142
143 /* If reached an update interval and allowed, update the clock within
144 the hw_nvram. While this function could be implemented using events
145 it isn't on the assumption that the HW_NVRAM will hardly ever be
146 referenced and hence there is little need in keeping the clock
147 continually up-to-date */
148 static void
149 hw_nvram_update_clock(hw_nvram_device *hw_nvram, cpu *processor)
150 {
151 #ifdef HAVE_TIME_H
152 if (!(hw_nvram->memory[hw_nvram->addr_control] & 0xc0)) {
153 time_t host_time = time(NULL);
154 if (hw_nvram->host_time != host_time) {
155 time_t nvtime = hw_nvram->host_time + hw_nvram->timezone;
156 struct tm *clock = gmtime(&nvtime);
157 hw_nvram->host_time = host_time;
158 hw_nvram->memory[hw_nvram->addr_year] = hw_nvram_bcd(clock->tm_year);
159 hw_nvram->memory[hw_nvram->addr_month] = hw_nvram_bcd(clock->tm_mon + 1);
160 hw_nvram->memory[hw_nvram->addr_date] = hw_nvram_bcd(clock->tm_mday);
161 hw_nvram->memory[hw_nvram->addr_day] = hw_nvram_bcd(clock->tm_wday + 1);
162 hw_nvram->memory[hw_nvram->addr_hour] = hw_nvram_bcd(clock->tm_hour);
163 hw_nvram->memory[hw_nvram->addr_minutes] = hw_nvram_bcd(clock->tm_min);
164 hw_nvram->memory[hw_nvram->addr_seconds] = hw_nvram_bcd(clock->tm_sec);
165 }
166 }
167 #else
168 error("fixme - where do I find out GMT\n");
169 #endif
170 }
171
172 static void
173 hw_nvram_set_clock(hw_nvram_device *hw_nvram, cpu *processor)
174 {
175 error ("fixme - how do I set the localtime\n");
176 }
177
178 static unsigned
179 hw_nvram_io_read_buffer(device *me,
180 void *dest,
181 int space,
182 unsigned_word addr,
183 unsigned nr_bytes,
184 cpu *processor,
185 unsigned_word cia)
186 {
187 int i;
188 hw_nvram_device *hw_nvram = (hw_nvram_device*)device_data(me);
189 for (i = 0; i < nr_bytes; i++) {
190 unsigned address = (addr + i) % hw_nvram->sizeof_memory;
191 unsigned8 data = hw_nvram->memory[address];
192 hw_nvram_update_clock(hw_nvram, processor);
193 ((unsigned8*)dest)[i] = data;
194 }
195 return nr_bytes;
196 }
197
198 static unsigned
199 hw_nvram_io_write_buffer(device *me,
200 const void *source,
201 int space,
202 unsigned_word addr,
203 unsigned nr_bytes,
204 cpu *processor,
205 unsigned_word cia)
206 {
207 int i;
208 hw_nvram_device *hw_nvram = (hw_nvram_device*)device_data(me);
209 for (i = 0; i < nr_bytes; i++) {
210 unsigned address = (addr + i) % hw_nvram->sizeof_memory;
211 unsigned8 data = ((unsigned8*)source)[i];
212 if (address == hw_nvram->addr_control
213 && (data & 0x80) == 0
214 && (hw_nvram->memory[address] & 0x80) == 0x80)
215 hw_nvram_set_clock(hw_nvram, processor);
216 else
217 hw_nvram_update_clock(hw_nvram, processor);
218 hw_nvram->memory[address] = data;
219 }
220 return nr_bytes;
221 }
222
223 static device_callbacks const hw_nvram_callbacks = {
224 { hw_nvram_init_address, },
225 { NULL, }, /* address */
226 { hw_nvram_io_read_buffer, hw_nvram_io_write_buffer }, /* IO */
227 };
228
229 const device_descriptor hw_nvram_device_descriptor[] = {
230 { "nvram", hw_nvram_create, &hw_nvram_callbacks },
231 { NULL },
232 };
233
234 #endif /* _HW_NVRAM_C_ */
This page took 0.033747 seconds and 4 git commands to generate.