diff options
author | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
commit | c906108c21474dfb4ed285bcc0ac6fe02cd400cc (patch) | |
tree | a0015aa5cedc19ccbab307251353a41722a3ae13 /sim/ppc/hw_nvram.c | |
parent | cd946cff9ede3f30935803403f06f6ed30cad136 (diff) | |
download | gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.zip gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.gz gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.bz2 |
Initial creation of sourceware repositorygdb-4_18-branchpoint
Diffstat (limited to 'sim/ppc/hw_nvram.c')
-rw-r--r-- | sim/ppc/hw_nvram.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/sim/ppc/hw_nvram.c b/sim/ppc/hw_nvram.c new file mode 100644 index 0000000..4c87d05 --- /dev/null +++ b/sim/ppc/hw_nvram.c @@ -0,0 +1,264 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _HW_NVRAM_C_ +#define _HW_NVRAM_C_ + +#ifndef STATIC_INLINE_HW_NVRAM +#define STATIC_INLINE_HW_NVRAM STATIC_INLINE +#endif + +#include "device_table.h" + +#ifdef HAVE_TIME_H +#include <time.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#else +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif +#endif + +/* DEVICE + + + nvram - non-volatile memory with clock + + + DESCRIPTION + + + This device implements a small byte addressable non-volatile + memory. The top 8 bytes of this memory include a real-time clock. + + + PROPERTIES + + + reg = <address> <size> (required) + + Specify the address/size of this device within its parents address + space. + + + timezone = <integer> (optional) + + Adjustment to the hosts current GMT (in seconds) that should be + applied when updating the NVRAM's clock. If no timezone is + specified, zero (GMT or UCT) is assumed. + + + */ + +typedef struct _hw_nvram_device { + unsigned8 *memory; + unsigned sizeof_memory; +#ifdef HAVE_TIME_H + time_t host_time; +#else + long host_time; +#endif + unsigned timezone; + /* useful */ + unsigned addr_year; + unsigned addr_month; + unsigned addr_date; + unsigned addr_day; + unsigned addr_hour; + unsigned addr_minutes; + unsigned addr_seconds; + unsigned addr_control; +} hw_nvram_device; + +static void * +hw_nvram_create(const char *name, + const device_unit *unit_address, + const char *args) +{ + hw_nvram_device *nvram = ZALLOC(hw_nvram_device); + return nvram; +} + +typedef struct _hw_nvram_reg_spec { + unsigned32 base; + unsigned32 size; +} hw_nvram_reg_spec; + +static void +hw_nvram_init_address(device *me) +{ + hw_nvram_device *nvram = (hw_nvram_device*)device_data(me); + + /* use the generic init code to attach this device to its parent bus */ + generic_device_init_address(me); + + /* find the first non zero reg property and use that as the device + size */ + if (nvram->sizeof_memory == 0) { + reg_property_spec reg; + int reg_nr; + for (reg_nr = 0; + device_find_reg_array_property(me, "reg", reg_nr, ®); + reg_nr++) { + unsigned attach_size; + if (device_size_to_attach_size(device_parent(me), + ®.size, &attach_size, + me)) { + nvram->sizeof_memory = attach_size; + break; + } + } + if (nvram->sizeof_memory == 0) + device_error(me, "reg property must contain a non-zero phys-addr:size tupple"); + if (nvram->sizeof_memory < 8) + device_error(me, "NVRAM must be at least 8 bytes in size"); + } + + /* initialize the hw_nvram */ + if (nvram->memory == NULL) { + nvram->memory = zalloc(nvram->sizeof_memory); + } + else + memset(nvram->memory, nvram->sizeof_memory, 0); + + if (device_find_property(me, "timezone") == NULL) + nvram->timezone = 0; + else + nvram->timezone = device_find_integer_property(me, "timezone"); + + nvram->addr_year = nvram->sizeof_memory - 1; + nvram->addr_month = nvram->sizeof_memory - 2; + nvram->addr_date = nvram->sizeof_memory - 3; + nvram->addr_day = nvram->sizeof_memory - 4; + nvram->addr_hour = nvram->sizeof_memory - 5; + nvram->addr_minutes = nvram->sizeof_memory - 6; + nvram->addr_seconds = nvram->sizeof_memory - 7; + nvram->addr_control = nvram->sizeof_memory - 8; + +} + +static int +hw_nvram_bcd(int val) +{ + val = val % 100; + if (val < 0) + val += 100; + return ((val / 10) << 4) + (val % 10); +} + + +/* If reached an update interval and allowed, update the clock within + the hw_nvram. While this function could be implemented using events + it isn't on the assumption that the HW_NVRAM will hardly ever be + referenced and hence there is little need in keeping the clock + continually up-to-date */ + +static void +hw_nvram_update_clock(hw_nvram_device *nvram, + cpu *processor) +{ +#ifdef HAVE_TIME_H + if (!(nvram->memory[nvram->addr_control] & 0xc0)) { + time_t host_time = time(NULL); + if (nvram->host_time != host_time) { + time_t nvtime = host_time + nvram->timezone; + struct tm *clock = gmtime(&nvtime); + nvram->host_time = host_time; + nvram->memory[nvram->addr_year] = hw_nvram_bcd(clock->tm_year); + nvram->memory[nvram->addr_month] = hw_nvram_bcd(clock->tm_mon + 1); + nvram->memory[nvram->addr_date] = hw_nvram_bcd(clock->tm_mday); + nvram->memory[nvram->addr_day] = hw_nvram_bcd(clock->tm_wday + 1); + nvram->memory[nvram->addr_hour] = hw_nvram_bcd(clock->tm_hour); + nvram->memory[nvram->addr_minutes] = hw_nvram_bcd(clock->tm_min); + nvram->memory[nvram->addr_seconds] = hw_nvram_bcd(clock->tm_sec); + } + } +#else + error("fixme - where do I find out GMT\n"); +#endif +} + +static void +hw_nvram_set_clock(hw_nvram_device *nvram, cpu *processor) +{ + error ("fixme - how do I set the localtime\n"); +} + +static unsigned +hw_nvram_io_read_buffer(device *me, + void *dest, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia) +{ + int i; + hw_nvram_device *nvram = (hw_nvram_device*)device_data(me); + for (i = 0; i < nr_bytes; i++) { + unsigned address = (addr + i) % nvram->sizeof_memory; + unsigned8 data = nvram->memory[address]; + hw_nvram_update_clock(nvram, processor); + ((unsigned8*)dest)[i] = data; + } + return nr_bytes; +} + +static unsigned +hw_nvram_io_write_buffer(device *me, + const void *source, + int space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia) +{ + int i; + hw_nvram_device *nvram = (hw_nvram_device*)device_data(me); + for (i = 0; i < nr_bytes; i++) { + unsigned address = (addr + i) % nvram->sizeof_memory; + unsigned8 data = ((unsigned8*)source)[i]; + if (address == nvram->addr_control + && (data & 0x80) == 0 + && (nvram->memory[address] & 0x80) == 0x80) + hw_nvram_set_clock(nvram, processor); + else + hw_nvram_update_clock(nvram, processor); + nvram->memory[address] = data; + } + return nr_bytes; +} + +static device_callbacks const hw_nvram_callbacks = { + { hw_nvram_init_address, }, + { NULL, }, /* address */ + { hw_nvram_io_read_buffer, hw_nvram_io_write_buffer }, /* IO */ +}; + +const device_descriptor hw_nvram_device_descriptor[] = { + { "nvram", hw_nvram_create, &hw_nvram_callbacks }, + { NULL }, +}; + +#endif /* _HW_NVRAM_C_ */ |