OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [branches/] [oc/] [gdb-5.0/] [sim/] [ppc/] [hw_nvram.c] - Blame information for rev 1771

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.