aboutsummaryrefslogtreecommitdiff
path: root/sim/common/sim-core.c
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>1997-03-14 15:13:58 +0000
committerAndrew Cagney <cagney@redhat.com>1997-03-14 15:13:58 +0000
commitf2de7dfd8cf1ffd6edc7ed650e709c7fa4488da1 (patch)
tree45023095bbd84ccadf676659aa9cc9220536793f /sim/common/sim-core.c
parent35a78bd09b847d649fd42802049b5160ea1cea4a (diff)
downloadbinutils-f2de7dfd8cf1ffd6edc7ed650e709c7fa4488da1.zip
binutils-f2de7dfd8cf1ffd6edc7ed650e709c7fa4488da1.tar.gz
binutils-f2de7dfd8cf1ffd6edc7ed650e709c7fa4488da1.tar.bz2
Add a number of per-simulator options: hostendian, endian, inline, warnings.
Rename *-n.h files to be dos compatible
Diffstat (limited to 'sim/common/sim-core.c')
-rw-r--r--sim/common/sim-core.c375
1 files changed, 375 insertions, 0 deletions
diff --git a/sim/common/sim-core.c b/sim/common/sim-core.c
new file mode 100644
index 0000000..f822dad
--- /dev/null
+++ b/sim/common/sim-core.c
@@ -0,0 +1,375 @@
+/* This file is part of the program psim.
+
+ Copyright (C) 1994-1997, 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 _SIM_CORE_C_
+#define _SIM_CORE_C_
+
+#include "engine.h"
+
+
+INLINE_SIM_CORE\
+(void)
+core_init(engine *system)
+{
+ core *memory = &system->memory;
+ core_maps map;
+ for (map = 0;
+ map < nr_core_maps;
+ map++) {
+ /* blow away old mappings */
+ core_mapping *curr = memory->map[map].first;
+ while (curr != NULL) {
+ core_mapping *tbd = curr;
+ curr = curr->next;
+ if (tbd->free_buffer) {
+ ASSERT(tbd->buffer != NULL);
+ zfree(tbd->buffer);
+ }
+ zfree(tbd);
+ }
+ memory->map[map].first = NULL;
+ }
+}
+
+
+
+STATIC_INLINE_SIM_CORE\
+(core_mapping *)
+new_core_mapping(engine *system,
+ attach_type attach,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ device *device,
+ void *buffer,
+ int free_buffer)
+{
+ core_mapping *new_mapping = ZALLOC(core_mapping);
+ /* common */
+ new_mapping->level = attach;
+ new_mapping->space = space;
+ new_mapping->base = addr;
+ new_mapping->nr_bytes = nr_bytes;
+ new_mapping->bound = addr + (nr_bytes - 1);
+ if (attach == attach_raw_memory) {
+ new_mapping->buffer = buffer;
+ new_mapping->free_buffer = free_buffer;
+ }
+ else if (attach >= attach_callback) {
+ new_mapping->device = device;
+ }
+ else {
+ engine_error(system, "new_core_mapping - internal error - unknown attach type %d\n",
+ attach);
+ }
+ return new_mapping;
+}
+
+
+STATIC_INLINE_SIM_CORE\
+(void)
+core_map_attach(engine *system,
+ core_map *access_map,
+ attach_type attach,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes, /* host limited */
+ device *client, /*callback/default*/
+ void *buffer, /*raw_memory*/
+ int free_buffer) /*raw_memory*/
+{
+ /* find the insertion point for this additional mapping and then
+ insert */
+ core_mapping *next_mapping;
+ core_mapping **last_mapping;
+
+ ASSERT((attach >= attach_callback && client != NULL && buffer == NULL && !free_buffer)
+ || (attach == attach_raw_memory && client == NULL && buffer != NULL));
+
+ /* actually do occasionally get a zero size map */
+ if (nr_bytes == 0) {
+#if (WITH_DEVICES)
+ device_error(client, "called on core_map_attach with size zero");
+#else
+ engine_error(system, "called on core_map_attach with size zero");
+#endif
+ }
+
+ /* find the insertion point (between last/next) */
+ next_mapping = access_map->first;
+ last_mapping = &access_map->first;
+ while(next_mapping != NULL
+ && (next_mapping->level < attach
+ || (next_mapping->level == attach
+ && next_mapping->bound < addr))) {
+ /* provided levels are the same */
+ /* assert: next_mapping->base > all bases before next_mapping */
+ /* assert: next_mapping->bound >= all bounds before next_mapping */
+ last_mapping = &next_mapping->next;
+ next_mapping = next_mapping->next;
+ }
+
+ /* check insertion point correct */
+ ASSERT(next_mapping == NULL || next_mapping->level >= attach);
+ if (next_mapping != NULL && next_mapping->level == attach
+ && next_mapping->base < (addr + (nr_bytes - 1))) {
+#if (WITH_DEVICES)
+ device_error(client, "map overlap when attaching %d:0x%lx (%ld)",
+ space, (long)addr, (long)nr_bytes);
+#else
+ engine_error(system, "map overlap when attaching %d:0x%lx (%ld)",
+ space, (long)addr, (long)nr_bytes);
+#endif
+ }
+
+ /* create/insert the new mapping */
+ *last_mapping = new_core_mapping(system,
+ attach,
+ space, addr, nr_bytes,
+ client, buffer, free_buffer);
+ (*last_mapping)->next = next_mapping;
+}
+
+
+INLINE_SIM_CORE\
+(void)
+core_attach(engine *system,
+ attach_type attach,
+ access_type access,
+ int space,
+ unsigned_word addr,
+ unsigned nr_bytes, /* host limited */
+ device *client,
+ void *optional_buffer)
+{
+ core *memory = &system->memory;
+ core_maps map;
+ void *buffer;
+ int buffer_freed;
+ if ((access & access_read_write_exec) == 0
+ || (access & ~access_read_write_exec) != 0) {
+#if (WITH_DEVICES)
+ device_error(client, "invalid access for core attach");
+#else
+ engine_error(system, "invalid access for core attach");
+#endif
+ }
+ /* verify the attach type */
+ if (attach == attach_raw_memory) {
+ if (optional_buffer == NULL) {
+ buffer = zalloc(nr_bytes);
+ buffer_freed = 0;
+ }
+ else {
+ buffer = optional_buffer;
+ buffer_freed = 1;
+ }
+ }
+ else if (attach >= attach_callback) {
+ buffer = NULL;
+ buffer_freed = 1;
+ }
+ else {
+#if (WITH_DEVICES)
+ device_error(client, "core_attach - conflicting buffer and attach arguments");
+#else
+ engine_error(system, "core_attach - conflicting buffer and attach arguments");
+#endif
+ buffer = NULL;
+ buffer_freed = 1;
+ }
+ /* attach the region to all applicable access maps */
+ for (map = 0;
+ map < nr_core_maps;
+ map++) {
+ switch (map) {
+ case core_read_map:
+ if (access & access_read)
+ core_map_attach(system, &memory->map[map],
+ attach,
+ space, addr, nr_bytes,
+ client, buffer, !buffer_freed);
+ buffer_freed ++;
+ break;
+ case core_write_map:
+ if (access & access_write)
+ core_map_attach(system, &memory->map[map],
+ attach,
+ space, addr, nr_bytes,
+ client, buffer, !buffer_freed);
+ buffer_freed ++;
+ break;
+ case core_execute_map:
+ if (access & access_exec)
+ core_map_attach(system, &memory->map[map],
+ attach,
+ space, addr, nr_bytes,
+ client, buffer, !buffer_freed);
+ buffer_freed ++;
+ break;
+ case nr_core_maps:
+ engine_error(system, "core_attach - internal error - bad switch");
+ break;
+ }
+ }
+}
+
+
+STATIC_INLINE_SIM_CORE\
+(core_mapping *)
+core_map_find_mapping(engine *system,
+ core_maps map,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int abort) /*either 0 or 1 - helps inline */
+{
+ core_mapping *mapping = system->memory.map[map].first;
+ ASSERT((addr & (nr_bytes - 1)) == 0); /* must be aligned */
+ ASSERT((addr + (nr_bytes - 1)) >= addr); /* must not wrap */
+ while (mapping != NULL) {
+ if (addr >= mapping->base
+ && (addr + (nr_bytes - 1)) <= mapping->bound)
+ return mapping;
+ mapping = mapping->next;
+ }
+ if (abort)
+ engine_error(system, "access to unmaped address 0x%x (%d bytes)\n",
+ addr, nr_bytes);
+ return NULL;
+}
+
+
+STATIC_INLINE_SIM_CORE\
+(void *)
+core_translate(core_mapping *mapping,
+ unsigned_word addr)
+{
+ return (void *)(((char *)mapping->buffer) + addr - mapping->base);
+}
+
+
+INLINE_SIM_CORE\
+(unsigned)
+core_map_read_buffer(engine *system,
+ core_maps map,
+ void *buffer,
+ unsigned_word addr,
+ unsigned len)
+{
+ unsigned count = 0;
+ while (count < len) {
+ unsigned_word raddr = addr + count;
+ core_mapping *mapping =
+ core_map_find_mapping(system, map,
+ raddr, 1,
+ 0); /*dont-abort*/
+ if (mapping == NULL)
+ break;
+#if (WITH_DEVICES)
+ if (mapping->device != NULL) {
+ int nr_bytes = len - count;
+ if (raddr + nr_bytes - 1> mapping->bound)
+ nr_bytes = mapping->bound - raddr + 1;
+ if (device_io_read_buffer(mapping->device,
+ (unsigned_1*)buffer + count,
+ mapping->space,
+ raddr,
+ nr_bytes) != nr_bytes)
+ break;
+ count += nr_bytes;
+ }
+ else
+#endif
+ {
+ ((unsigned_1*)buffer)[count] =
+ *(unsigned_1*)core_translate(mapping, raddr);
+ count += 1;
+ }
+ }
+ return count;
+}
+
+
+INLINE_SIM_CORE\
+(unsigned)
+core_map_write_buffer(engine *system,
+ core_maps map,
+ const void *buffer,
+ unsigned_word addr,
+ unsigned len)
+{
+ unsigned count = 0;
+ while (count < len) {
+ unsigned_word raddr = addr + count;
+ core_mapping *mapping = core_map_find_mapping(system, map,
+ raddr, 1,
+ 0); /*dont-abort*/
+ if (mapping == NULL)
+ break;
+#if (WITH_DEVICES)
+ if (WITH_CALLBACK_MEMORY
+ && mapping->device != NULL) {
+ int nr_bytes = len - count;
+ if (raddr + nr_bytes - 1 > mapping->bound)
+ nr_bytes = mapping->bound - raddr + 1;
+ if (device_io_write_buffer(mapping->device,
+ (unsigned_1*)buffer + count,
+ mapping->space,
+ raddr,
+ nr_bytes) != nr_bytes)
+ break;
+ count += nr_bytes;
+ }
+ else
+#endif
+ {
+ *(unsigned_1*)core_translate(mapping, raddr) =
+ ((unsigned_1*)buffer)[count];
+ count += 1;
+ }
+ }
+ return count;
+}
+
+
+/* define the read/write 1/2/4/8/word functions */
+
+#define N 1
+#include "sim-n-core.h"
+#undef N
+
+#define N 2
+#include "sim-n-core.h"
+#undef N
+
+#define N 4
+#include "sim-n-core.h"
+#undef N
+
+#define N 8
+#include "sim-n-core.h"
+#undef N
+
+#define N word
+#include "sim-n-core.h"
+#undef N
+
+#endif