]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
October 11th changes from Andrew
authorMichael Meissner <gnu@the-meissners.org>
Wed, 11 Oct 1995 20:17:49 +0000 (20:17 +0000)
committerMichael Meissner <gnu@the-meissners.org>
Wed, 11 Oct 1995 20:17:49 +0000 (20:17 +0000)
16 files changed:
sim/ppc/.Sanitize
sim/ppc/README.psim
sim/ppc/core.c
sim/ppc/core.h
sim/ppc/core_n.h [new file with mode: 0644]
sim/ppc/device_tree.c
sim/ppc/device_tree.h
sim/ppc/devices.c
sim/ppc/devices.h
sim/ppc/gen.c
sim/ppc/idecode_insn.h [deleted file]
sim/ppc/memory_map.c [deleted file]
sim/ppc/memory_map.h [deleted file]
sim/ppc/ppc-endian.h
sim/ppc/system.c
sim/ppc/system.h

index e99ca8a0fb56e6f0f47cb3d9356d3b4d69d3f242..c25d589d4cfc86bafda3a16108a68b10cdc60603 100644 (file)
@@ -36,6 +36,7 @@ configure
 configure.in
 core.c
 core.h
+core_n.h
 cpu.c
 cpu.h
 debug.c
@@ -52,14 +53,11 @@ gen.c
 idecode_branch.h
 idecode_expression.h
 idecode_fields.h
-idecode_insn.h
 inline.c
 inline.h
 interrupts.c
 interrupts.h
 main.c
-memory_map.c
-memory_map.h
 ppc-endian.c
 ppc-endian.h
 ppc-instructions
@@ -76,6 +74,7 @@ system.c
 system.h
 vm.c
 vm.h
+vm_n.h
 words.h
 
 Things-to-lose:
index c76c023bc21d8235c0b36620e192af844dccc4ff..f9a14866a27397478984b6eefdc6045c1425ffeb 100644 (file)
@@ -4,63 +4,47 @@
 Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
 
 This directory contains the program PSIM that models the PowerPC
-architecture.  It can either be run stand alone (psim) or linked with
-GDB.
+architecture.  It can either be run stand alone (psim or run) or used
+as part of GDB.
 
 
-CONTENTS:
+SOURCE:
 
-    psim-*.tar:        
+       PSIM is now part of the Cygnus GDB source tree (hopefully it
+       will in turn become part of the next FSF release of GDB).
 
-       psim-sim-*.tar.gz       simulator source code
+       If you're looking for a more `cutting' edge version of this
+       program then it can be found in:
 
-       psim-test-*.tar.gz      test directory for simulator
+               ftp.ci.com.au:pub/clayton/psim-sim-*.tar.gz
 
-       psim-gdb-*.diff.gz      patches to integrated psim
-                               into gdb
+       This contains a replacement for the directory sim/ppc.  As
+       these releases prove stable they are merged back into the GDB
+       source tree.
 
-    gnu-*.tar:
+       If you find bugs or experience problems, please e-mail them to
+       the alias:
 
-       gnu-gdb-*.diff.gz       patches to gdb that may have
-                               already been merged into the
-                               GDB source tree.
+               powerpc-psim@ci.com.au
 
-       gnu-*-*.diff.gz         Other noise
+       It's a majordomo mailing list.
 
 
 BUILDING:
 
-       o Install flex, bison, gnu-make, native gcc and probably also byacc.
+       o At present PSIM can only be built using the compiler GCC
+         (yes that is bug).  This is because, among other things the
+         code exploits GCC's suport of long ongs.
 
+       o I also suggest that you install: flex, bision, gnu-make and
+         byacc.  Doing this just makes builds easier.
 
-       o First you will need a fairly current copy of GDB (try the ftp site
-         ftp.cygnus.com:pub).  I've built it with a beta version of gdb-4.15.
+       o Configure almost as per normal, specifing the special target
+         eabisim vis:
 
-         Unpack gdb vis:
-
-               $ gunzip < gdb-4.15.tar.gz | tar xf -
-
-
-       o Apply any patches that haven't yet been merged into the GDB source
-         tree.
-
-               $ cd gdb-4.15
-               $ gunzip < ../psim-gdb-*.diff.gz | patch -p1
-               $ gunzip < ../gnu-gdb-*.diff.gz | patch -p1
-
-
-       o Unpack the psim source code (and optionally the test directory)
-
-               $ cd gdb-4.15
-               $ gunzip < ../psim-sim-*.tar.gz | tar xvf -
-               $ gunzip < ../psim-test-*.tar.gz | tar xvf -
-
-
-       o Configure gdb as per normal.  I use something along the lines of:
-
-               $ cd gdb-4.15
-               $ CC=gcc ./configure --target=powerpcle-unknown-eabi
+               $ CC=gcc ./configure --target=powerpcle-unknown-eabisim
 
+         by default (because of its dependency on GCC).
 
        o Build your entire gdb tree as per normal.  Something along the
          lines of:
@@ -78,15 +62,17 @@ BUILDING:
                $ cd gdb-4.15
                $ make CC=gcc install
 
-         The program sim/ppc/psim is not installed.
-
 
 RUNNING:
 
        PSIM can either be run as a stand alone program or as part
-       of gdb.  The psim-test archive contains pre-compiled and
-       linked programs that can be run on PSIM.  The notes below
-       assume that you have unpacked that tar archive.
+       of gdb.  The psim-test archive (found in:
+
+               ftp.ci.com.au:pub/clayton
+
+       contains pre-compiled and linked programs that can be run on
+       PSIM.  The notes below assume that you have unpacked that tar
+       archive.
 
        To rebuild the archive you will need to obtain a working
        version of an ELF compiler/linker for the PowerPC.
@@ -135,68 +121,105 @@ RUNNING:
                        .
 
 
-CONFIGURATION: Making it go faster
+CONFIGURATION:
+
+       Making it go faster
 
-       See the file sim/ppc/config.h (a.k.a. sim/ppc/data/ppc-config)
-       for notes.
+       See the file sim/ppc/config.h (which is copied from
+       sim/ppc/std-config.h) for further information.
 
 
 KNOWN FEATURES
 
-       SMP, dual-endian, VEA and OEA models, hardware devices
-       (console, icu, reset) ...
+       SMP: A Symetric Multi-Processor configuration is suported.
+       This includes a model of the PowerPC load word and reserve
+       et.al. instructions (if intending to use this feature you are
+       well advised to read the the source code for the reservation
+       instructions so that you are aware of any potential
+       limitations in the model).
+
+       DUAL-ENDIAN: Both little and big endian modes are suported.
+       Switching between the two modes at run time, however, is not.
+
+       UIEA, VEA and OEA: The PowerPC architecture defines three
+       levels of the PowerPC architecture.  This simulator, to a
+       reasonable degree, is capable of modeling all three of them.
+       That is the User Instruction Set Architecture, the Virtual
+       Environment Architecture and finally the Operating Environment
+       Architecture.
+
+       HARDWARE DEVICES: The OEA model includes facilities that allow
+       a programmer to (I won't say easily) extend this simulator so
+       that a program can interact with models of real devices.
+       Illustrating this is the phony machine clayton that includes
+       console, interrupt control unit and reset register devices.
+
+       PEDANTIC VEA MEMORY MODEL: User programs can not assume that
+       they can stray off the end of valid memory areas.  This model
+       defines valid memory addresses in strict accordance to the
+       executable and does not page allign their values.  At first
+       this was a bug but since then has turned up several bugs in
+       peoples code so I've renamed it `a feature' :-)
+
+       RUNTIME CONFIG OF HARDWARE: In addition to the three builtin
+       models of hardware - VEA, OEA/Hardware and (the start of) OpenBoot,
+       it is possible to load a file containing a specification of a
+       custom device tree.
 
 
 KNOWN PROBLEMS:
 
-       Configuration could be better.
+       FLOATING POINT: Need to add suport for non IEEE float
+       machines.  Need to more fully handle exceptions (eg things
+       like divide by zero).
 
-       HTAB (page) code for OEA model untested.  Some of the vm code
-       instructions unimplemented.
+       DEVICE TREE DOC: How to create and use the device tree is not
+       documented at all.
 
-       Doesn't detect/handle changing endian bits.  In fact they are
-       ignored.
+       INITIALIZATION: When running from gdb, things are not
+       re-initialzied very well e.g. registers are not rezeroed.
 
-       Return from interrupt instruction unimplemented.
+       HTAB (page) code for OEA model untested.  Some of the vm code
+       instructions unimplemented.
 
        Flush instruction cache instructions do nothing.  Perhaphs they
        should (if there is an instruction cache) flush it.
 
-       PowerOpen VEA model (a.k.a XCOFF a.k.a AIX) broken.  It was
-       working but that is before I changed the create stack frame
-       code into an ELF version.
+       Lacks PowerOpen (a.k.a. XCOFF a.k.a. AIX) and NT startups.
+       The PowerOpen worked until I added the ELF one.
 
        OpenBoot and PR*P interfaces missing.  Open boot could be
        implemented by putting special instructions at the address
        of the OpenBoot callback functions.  Those instructions
        could than emulate OpenBoot behavour.
 
-       VEA memory read/write performance could be improved by merging
-       the data sections.
-
-       When reading in a VEA executable, the binaries text and data
-       sections are not made page aligned.
+       Missing VEA system calls.
 
        Missing or commented out instructions.
 
-       Lack of floating point support.
-       [workaround: build everything using -msoft-float]
+       Only basic (hackish) floating point implemented, I would not
+       trust it and it is going to change.
+
+       64bit target untested.
 
-       64bit untested.
+       64bit host broken.  For instance use of scanf "%x", &long long.
 
-       Event code for pending events from signal handlers not
+       Event code for pending events from within signal handlers not
        finished/tested.
 
        Better and more devices.
 
-       Only two device trees VEA and OEA (clayton) and those hard coded.
-       Should be possible to specify a file containing a device tree
-       description as the program to run.  At present it a device tree
-       file is detected causing psim to abort.
-
-       I wonder if I've got my ppc.instructions copyright
-       notice correct.
+       PORTABILITY (Notes taken from Michael Meissner): Heavy use of
+       the ## operator - fix using the clasic X/**/Y hack; Use of the
+       signed keyword.  In particular, signed char has no analogue in
+       classic C (though most implementations of classic C use signed
+       chars); Use of long long which restricts the target compiler
+       to be GCC.
 
+       OPTIONS/FLAGS: Need a function that can parse command line
+       options so that both psim and sim_{load,open,command} can all
+       call it.  Options should be extended to allow the setting of
+       things like floating point support.
 
 THANKS:
 
@@ -251,3 +274,7 @@ i486DX2/66
        1/270/316 - switch=2/2,expand=0,inline=1,nia=0
        1/271/281 - switch=1/1,expand=0,inline=1,nia=1
        1/267/274 - switch=2/1,expand=0,inline=1,nia=1
+
+----
+
+CFLAGS = -g -Wall -Wno-unused -Wmissing-prototypes -Werror
index 9c47a6ce8a0889cb2a3a33878c2ea65fca0d35d1..a40128e981fee680ef49e79fa267e81f053469c7 100644 (file)
 #define STATIC_INLINE_CORE STATIC_INLINE
 #endif
 
+
 #include "basics.h"
 #include "device_tree.h"
-#include "memory_map.h"
 #include "core.h"
 
 
+typedef struct _core_mapping core_mapping;
+struct _core_mapping {
+  /* ram map */
+  int free_buffer;
+  void *buffer;
+  /* device map */
+  const device *device;
+  device_io_read_buffer_callback *reader;
+  device_io_write_buffer_callback *writer;
+  /* common */
+  int address_space;
+  unsigned_word base;
+  unsigned_word bound;
+  unsigned nr_bytes;
+  core_mapping *next;
+};
+
+struct _core_map {
+  core_mapping *first;
+  core_mapping *default_map;
+};
+
+typedef enum {
+  core_read_map,
+  core_write_map,
+  core_execute_map,
+  nr_core_map_types,
+} core_map_types;
+
 struct _core {
-  /* attached devices */
-  device_node *device_tree;
-  /* different memory maps */
-  memory_map *readable; /* really everything */
-  memory_map *writeable;
-  memory_map *executable;
-  /* VEA model requires additional memory information */
-  unsigned_word data_upper_bound;
-  unsigned_word data_high_water;
-  unsigned_word stack_upper_bound;
-  unsigned_word stack_lower_bound;
-  unsigned_word stack_low_water;
-  /* misc */
-  int trace;
+  core_map map[nr_core_map_types];
 };
 
 
+INLINE_CORE core *
+core_create(void)
+{
+  core *new_core = ZALLOC(core);
+  return new_core;
+}
+
+
 STATIC_INLINE_CORE void
-create_core_from_addresses(device_node *device,
-                          void *data)
+core_init(core *memory)
 {
-  core *memory = (core*)data;
-  device_address *address;
-  for (address = device->addresses;
-       address != NULL;
-       address = address->next_address) {
-    switch (device->type) {
-    case memory_device:
-      {
-       void *ram = zalloc(address->size);
-       TRACE(trace_core,
-             ("create_core_from_addresses() adding memory at 0x%.8x-0x%.8x, size %8d\n",
-              address->lower_bound, address->lower_bound + address->size - 1, address->size));
-       core_add_raw_memory(memory,
-                           ram,
-                           address->lower_bound,
-                           address->size,
-                           address->access);
+  core_map_types access_type;
+  for (access_type = 0;
+       access_type < nr_core_map_types;
+       access_type++) {
+    core_map *map = memory->map + access_type;
+    /* blow away old mappings */
+    core_mapping *curr = map->first;
+    while (curr != NULL) {
+      core_mapping *tbd = curr;
+      curr = curr->next;
+      if (tbd->free_buffer) {
+       ASSERT(tbd->buffer != NULL);
+       zfree(tbd->buffer);
       }
-      break;
-    case sequential_device:
-    case block_device:
-    case bus_device:
-    case other_device:
-      {
-       TRACE(trace_core,
-             ("create_core_from_addresses() adding device at 0x%.8x-0x%.8x, size %8d\n",
-              address->lower_bound, address->lower_bound + address->size - 1, address->size));
-       ASSERT(device->callbacks != NULL);
-       core_add_callback_memory(memory,
-                                device,
-                                device->callbacks->read_callback,
-                                device->callbacks->write_callback,
-                                address->lower_bound,
-                                address->size,
-                                address->access);
-      }
-      break;
-    default:
-      TRACE(trace_core,
-           ("create_core_from_addresses() unknown type %d\n", (int)device->type));
-      break;
-      /* nothing happens here */
+      zfree(tbd);
+    }
+    map->first = NULL;
+    /* blow away the default */
+    if (map->default_map != NULL) {
+      ASSERT(map->default_map->buffer == NULL);
+      zfree(map->default_map);
     }
+    map->default_map = NULL;
   }
 }
 
 
-INLINE_CORE core *
-core_create(device_node *root,
-           int trace)
+
+/* the core has three sub mappings that the more efficient
+   read/write fixed quantity functions use */
+
+INLINE_CORE core_map *
+core_readable(core *memory)
 {
-  core *memory;
-
-  /* Initialize things */
-  memory = ZALLOC(core);
-  memory->trace = trace;
-  memory->device_tree = root;
-
-  /* allocate space for the separate virtual to physical maps */
-  memory->executable = new_memory_map();
-  memory->readable = new_memory_map();
-  memory->writeable = new_memory_map();
-
-  /* initial values for the water marks */
-  memory->data_high_water = 0;
-  memory->stack_low_water = memory->data_high_water - sizeof(unsigned_word);
-
-  /* go over the device tree looking for address ranges to add to
-     memory */
-  device_tree_traverse(root,
-                      create_core_from_addresses,
-                      NULL,
-                      memory);
-
-  /* return the created core object */
-  return memory;
+  return memory->map + core_read_map;
 }
 
+INLINE_CORE core_map *
+core_writeable(core *memory)
+{
+  return memory->map + core_write_map;
+}
 
-STATIC_INLINE_CORE void
-zero_core_from_addresses(device_node *device,
-                        void *data)
+INLINE_CORE core_map *
+core_executable(core *memory)
 {
-  core *memory = (core*)data;
-  device_address *address;
-
-  /* for memory nodes, copy or zero any data */
-  if (device->type == memory_device) {
-    for (address = device->addresses;
-        address != NULL;
-        address = address->next_address) {
-      if (memory_map_zero(memory->readable,
-                         address->lower_bound,
-                         address->size) != address->size)
-       error("init_core_from_addresses() - zero failed\n");
-      /* adjust high water mark (sbrk) */
-      if (memory->data_upper_bound < address->upper_bound)
-       memory->data_upper_bound = address->upper_bound;
-    }
-  }
+  return memory->map + core_execute_map;
 }
 
-STATIC_INLINE_CORE void
-load_core_from_addresses(device_node *device,
-                        void *data)
+
+
+STATIC_INLINE_CORE core_mapping *
+new_core_mapping(attach_type attach,
+                  int address_space,
+                  unsigned_word addr,
+                  unsigned nr_bytes,
+                  const device *device,
+                  void *buffer,
+                  int free_buffer)
 {
-  core *memory = (core*)data;
-  device_address *address;
-
-  /* initialize the address range with the value attached to the
-     address.  Even works for devices! */
-  for (address = device->addresses;
-       address != NULL;
-       address = address->next_address) {
-    /* (re)init the address range.  I don't want to think about what
-       this is doing to callback devices! */
-    if (address->init) {
-      if (memory_map_write_buffer(memory->readable,
-                                 address->init,
-                                 address->lower_bound,
-                                 address->size,
-                                 raw_transfer) != address->size)
-       error("init_core_from_addresses() - write failed\n");
-    }
+  core_mapping *new_mapping = ZALLOC(core_mapping);
+  switch (attach) {
+  case attach_default:
+  case attach_callback:
+    new_mapping->device = device;
+    new_mapping->reader = device->callback->io_read_buffer;
+    new_mapping->writer = device->callback->io_write_buffer;
+    break;
+  case attach_raw_memory:
+    new_mapping->buffer = buffer;
+    new_mapping->free_buffer = free_buffer;
+    break;
+  default:
+    error("new_core_mapping() - internal error - unknown attach type %d\n",
+         attach);
   }
+  /* common */
+  new_mapping->address_space = address_space;
+  new_mapping->base = addr;
+  new_mapping->nr_bytes = nr_bytes;
+  new_mapping->bound = addr + (nr_bytes - 1);
+  return new_mapping;
 }
 
-INLINE_CORE void
-core_init(core *memory)
+
+STATIC_INLINE_CORE void
+core_map_attach(core_map *access_map,
+                        attach_type attach,
+                        int address_space,
+                        unsigned_word addr,
+                        unsigned nr_bytes, /* host limited */
+                        const device *device, /*callback/default*/
+                        void *buffer, /*raw_memory*/
+                        int free_buffer) /*raw_memory*/
 {
-  unsigned nr_cleared;
-  unsigned_word clear_base;
-  unsigned_word clear_bound;
-
-  /* for vea, several memory break points */
-  memory->data_upper_bound = 0;
-  memory->stack_upper_bound = device_tree_find_int(memory->device_tree,
-                                                  "/options/stack-pointer");;
-  memory->stack_lower_bound = memory->stack_upper_bound;
-
-  /* (re) clear all of memory that is specified by memory-address
-     entries.  While we're at it determine the upper bound for memory
-     areas */
-  device_tree_traverse(memory->device_tree,
-                      NULL,
-                      zero_core_from_addresses,
-                      memory);
-
-  /* May have grown the data sectioin (vea model), zero that too if
-     present */
-  clear_base = memory->data_upper_bound;
-  clear_bound = memory->data_high_water;
-  if (clear_bound > clear_base) {
-    while ((nr_cleared = memory_map_zero(memory->readable,
-                                        clear_base,
-                                        clear_bound - clear_base)) > 0) {
-      clear_base += nr_cleared;
-    }
+  if (attach == attach_default) {
+    if (access_map->default_map != NULL)
+      error("core_map_attach() default mapping already in place\n");
+    ASSERT(buffer == NULL);
+    access_map->default_map = new_core_mapping(attach, 
+                                                address_space, addr, nr_bytes,
+                                                device, buffer, free_buffer);
   }
-
-  /* clear any part of the stack that was dynamically allocated */
-  clear_base = memory->stack_low_water;
-  clear_bound = memory->stack_upper_bound;
-  if (clear_bound > clear_base) {
-    while ((nr_cleared = memory_map_zero(memory->readable,
-                                        clear_base,
-                                        clear_bound - clear_base)) > 0) {
-      clear_base += nr_cleared;
+  else {
+    /* find the insertion point for this additional mapping and insert */
+    core_mapping *next_mapping;
+    core_mapping **last_mapping;
+
+    /* actually do occasionally get a zero size map */
+    if (nr_bytes == 0)
+      error("core_map_attach() size == 0\n");
+
+    /* find the insertion point (between last/next) */
+    next_mapping = access_map->first;
+    last_mapping = &access_map->first;
+    while(next_mapping != NULL && next_mapping->bound < addr) {
+      /* 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;
     }
-  }
 
-  /* with everything zero'ed, now (re) load any data sections */
-  device_tree_traverse(memory->device_tree,
-                      NULL,
-                      load_core_from_addresses,
-                      memory);
+    /* check insertion point correct */
+    if (next_mapping != NULL && next_mapping->base < (addr + (nr_bytes - 1))) {
+      error("core_map_attach() map overlap\n");
+    }
 
+    /* create/insert the new mapping */
+    *last_mapping = new_core_mapping(attach,
+                                      address_space, addr, nr_bytes,
+                                      device, buffer, free_buffer);
+    (*last_mapping)->next = next_mapping;
+  }
 }
 
 
-
 INLINE_CORE void
-core_add_raw_memory(core *memory,
-                   void *buffer,
-                   unsigned_word base,
-                   unsigned size,
-                   device_access access)
+core_attach(core *memory,
+           attach_type attach,
+           int address_space,
+           access_type access,
+           unsigned_word addr,
+           unsigned nr_bytes, /* host limited */
+           const device *device) /*callback/default*/
 {
-  if (access & device_is_readable)
-    memory_map_add_raw_memory(memory->readable,
-                             buffer, base, size);
-  if (access & device_is_writeable)
-    memory_map_add_raw_memory(memory->writeable,
-                             buffer, base, size);
-  if (access & device_is_executable)
-    memory_map_add_raw_memory(memory->executable,
-                             buffer, base, size);
+  core_map_types access_map;
+  int free_buffer = 0;
+  void *buffer = NULL;
+  ASSERT(attach == attach_default || nr_bytes > 0);
+  if (attach == attach_raw_memory)
+    buffer = zalloc(nr_bytes);
+  for (access_map = 0; 
+       access_map < nr_core_map_types;
+       access_map++) {
+    switch (access_map) {
+    case core_read_map:
+      if (access & access_read)
+       core_map_attach(memory->map + access_map,
+                       attach,
+                       address_space, addr, nr_bytes,
+                       device, buffer, !free_buffer);
+      free_buffer ++;
+      break;
+    case core_write_map:
+      if (access & access_write)
+       core_map_attach(memory->map + access_map,
+                       attach,
+                       address_space, addr, nr_bytes,
+                       device, buffer, !free_buffer);
+      free_buffer ++;
+      break;
+    case core_execute_map:
+      if (access & access_exec)
+       core_map_attach(memory->map + access_map,
+                       attach,
+                       address_space, addr, nr_bytes,
+                       device, buffer, !free_buffer);
+      free_buffer ++;
+      break;
+    default:
+      error("core_attach() internal error\n");
+      break;
+    }
+  }
+  ASSERT(free_buffer > 0); /* must attach to at least one thing */
 }
 
 
-INLINE_CORE void
-core_add_callback_memory(core *memory,
-                        device_node *device,
-                        device_reader_callback *reader,
-                        device_writer_callback *writer,
-                        unsigned_word base,
-                        unsigned size,
-                        device_access access)
+STATIC_INLINE_CORE core_mapping *
+core_map_find_mapping(core_map *map,
+                     unsigned_word addr,
+                     unsigned nr_bytes,
+                     cpu *processor,
+                     unsigned_word cia,
+                     int abort) /*either 0 or 1 - helps inline */
 {
-  if (access & device_is_readable)
-    memory_map_add_callback_memory(memory->readable,
-                                  device, reader, writer,
-                                  base, size);
-  if (access & device_is_writeable)
-    memory_map_add_callback_memory(memory->writeable,
-                                  device, reader, writer,
-                                  base, size);
-  if (access & device_is_executable)
-    memory_map_add_callback_memory(memory->executable,
-                                  device, reader, writer,
-                                  base, size);
+  core_mapping *mapping = 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 (map->default_map != NULL)
+    return map->default_map;
+  if (abort)
+    error("core_find_mapping() - access to unmaped address, attach a default map to handle this - addr=0x%x nr_bytes=0x%x processor=0x%x cia=0x%x\n",
+         addr, nr_bytes, processor, cia);
+  return NULL;
 }
 
 
-STATIC_INLINE_CORE void
-malloc_core_memory(core *memory,
-                  unsigned_word base,
-                  unsigned size,
-                  device_access access)
+STATIC_INLINE_CORE void *
+core_translate(core_mapping *mapping,
+                    unsigned_word addr)
 {
-  void *buffer = (void*)zalloc(size);
-  core_add_raw_memory(memory, buffer, base, size, access);
+  return mapping->buffer + addr - mapping->base;
 }
 
-INLINE_CORE unsigned_word
-core_data_upper_bound(core *memory)
+
+INLINE_CORE unsigned
+core_map_read_buffer(core_map *map,
+                    void *buffer,
+                    unsigned_word addr,
+                    unsigned len)
 {
-  return memory->data_upper_bound;
+  unsigned count;
+  unsigned_1 byte;
+  for (count = 0; count < len; count++) {
+    unsigned_word raddr = addr + count;
+    core_mapping *mapping =
+      core_map_find_mapping(map,
+                           raddr, 1,
+                           NULL, /*processor*/
+                           0, /*cia*/
+                           0); /*dont-abort*/
+    if (mapping == NULL)
+      break;
+    if (mapping->reader != NULL) {
+      if (mapping->reader(mapping->device,
+                         &byte,
+                         mapping->address_space,
+                         raddr - mapping->base,
+                         1, /* nr_bytes */
+                         0, /*processor*/
+                         0 /*cpu*/) != 1)
+       break;
+    }
+    else
+      byte = *(unsigned_1*)core_translate(mapping,
+                                               raddr);
+    ((unsigned_1*)buffer)[count] = T2H_1(byte);
+  }
+  return count;
 }
 
 
-INLINE_CORE unsigned_word
-core_stack_lower_bound(core *memory)
+INLINE_CORE unsigned
+core_map_write_buffer(core_map *map,
+                     const void *buffer,
+                     unsigned_word addr,
+                     unsigned len)
 {
-  return memory->stack_lower_bound;
+  unsigned count;
+  unsigned_1 byte;
+  for (count = 0; count < len; count++) {
+    unsigned_word raddr = addr + count;
+    core_mapping *mapping = core_map_find_mapping(map,
+                                                 raddr, 1,
+                                                 NULL, /*processor*/
+                                                 0, /*cia*/
+                                                 0); /*dont-abort*/
+    if (mapping == NULL)
+      break;
+    byte = H2T_1(((unsigned_1*)buffer)[count]);
+    if (mapping->writer != NULL) {
+      if (mapping->writer(mapping->device,
+                         &byte,
+                         mapping->address_space,
+                         raddr - mapping->base,
+                         1, /*nr_bytes*/
+                         0, /*processor*/
+                         0 /*cpu*/) != 1)
+       break;
+    }
+    else
+      *(unsigned_1*)core_translate(mapping, raddr) = byte;
+  }
+  return count;
 }
 
-INLINE_CORE unsigned_word
-core_stack_size(core *memory)
-{
-  return (memory->stack_upper_bound - memory->stack_lower_bound);
-}
 
 
+/* Top level core(root) device: core@garbage
+
+   The core device captures incomming dma requests and changes them to
+   outgoing io requests. */
 
-INLINE_CORE void 
-core_add_data(core *memory, unsigned_word incr)
+STATIC_INLINE_CORE void
+core_init_callback(const device *me,
+                  psim *system)
 {
-  unsigned_word new_upper_bound = memory->data_upper_bound + incr;
-  if (new_upper_bound > memory->data_high_water) {
-    if (memory->data_upper_bound >= memory->data_high_water)
-      /* all the memory is new */
-      malloc_core_memory(memory,
-                        memory->data_upper_bound,
-                        incr,
-                        device_is_readable | device_is_writeable);
-    else
-      /* some of the memory was already allocated, only need to add
-         missing bit */
-      malloc_core_memory(memory,
-                        memory->data_high_water,
-                        new_upper_bound - memory->data_high_water,
-                        device_is_readable | device_is_writeable);
-    memory->data_high_water = new_upper_bound;
-  }
-  memory->data_upper_bound = new_upper_bound;
+  core *memory = (core*)me->data;
+  core_init(memory);
 }
 
 
-INLINE_CORE void 
-core_add_stack(core *memory, unsigned_word incr)
+STATIC_INLINE_CORE void
+core_attach_address_callback(const device *me,
+                            const char *name,
+                            attach_type attach,
+                            int address_space,
+                            unsigned_word addr,
+                            unsigned nr_bytes,
+                            access_type access,
+                            const device *who) /*callback/default*/
 {
-  unsigned_word new_lower_bound = memory->stack_lower_bound - incr;
-  if (new_lower_bound < memory->stack_low_water) {
-    if (memory->stack_lower_bound <= memory->stack_low_water)
-      /* all the memory is new */
-      malloc_core_memory(memory,
-                        new_lower_bound,
-                        incr,
-                        device_is_readable | device_is_writeable);
-    else
-      /* allocate only the extra bit */
-      malloc_core_memory(memory,
-                        new_lower_bound, 
-                        memory->stack_low_water - new_lower_bound,
-                        device_is_readable | device_is_writeable);
-    memory->stack_low_water = new_lower_bound;
-  }
-  memory->stack_lower_bound = new_lower_bound;
+  core *memory = (core*)me->data;
+  unsigned_word device_address;
+  if (address_space != 0)
+    error("core_attach_address_callback() invalid address space\n");
+  core_attach(memory,
+             attach,
+             address_space,
+             access,
+             addr,
+             nr_bytes,
+             who);
 }
 
 
-INLINE_CORE memory_map *
-core_readable(core *core)
+STATIC_INLINE_CORE unsigned
+core_dma_read_buffer_callback(const device *me,
+                             void *target,
+                             int address_space,
+                             unsigned_word offset,
+                             unsigned nr_bytes)
 {
-  return core->readable;
+  core *memory = (core*)me->data;
+  return core_map_read_buffer(core_readable(memory),
+                             target,
+                             offset,
+                             nr_bytes);
 }
 
 
-INLINE_CORE memory_map *
-core_writeable(core *core)
+STATIC_INLINE_CORE unsigned
+core_dma_write_buffer_callback(const device *me,
+                              const void *source,
+                              int address_space,
+                              unsigned_word offset,
+                              unsigned nr_bytes,
+                              int violate_read_only_section)
 {
-  return core->writeable;
+  core *memory = (core*)me->data;
+  core_map *map = (violate_read_only_section
+                  ? core_readable(memory)
+                  : core_writeable(memory));
+  return core_map_write_buffer(map,
+                              source,
+                              offset,
+                              nr_bytes);
 }
 
 
-INLINE_CORE memory_map *
-core_executable(core *core)
+static device_callbacks const core_callbacks = {
+  core_init_callback,
+  core_attach_address_callback,
+  unimp_device_detach_address,
+  unimp_device_io_read_buffer,
+  unimp_device_io_write_buffer,
+  core_dma_read_buffer_callback,
+  core_dma_write_buffer_callback,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
+};
+
+
+INLINE_CORE const device *
+core_device_create(core *memory)
 {
-  return core->executable;
+  return device_create_from("core", memory, &core_callbacks, NULL);
 }
 
-#endif /* _CORE_ */
+
+
+/* define the read/write 1/2/4/8/word functions */
+
+#undef N
+#define N 1
+#include "core_n.h"
+
+#undef N
+#define N 2
+#include "core_n.h"
+
+#undef N
+#define N 4
+#include "core_n.h"
+
+#undef N
+#define N 8
+#include "core_n.h"
+
+#undef N
+#define N word
+#include "core_n.h"
+
+#endif /* _CORE_C_ */
index 5d7837adb18b6f2866e81a3497c69f7809acae9a..38871e67ccef59601ccd4d4fe0da3cdaf4176feb 100644 (file)
 #define INLINE_CORE
 #endif
 
-/* the base type */
+/* basic types */
 
 typedef struct _core core;
+typedef struct _core_map core_map;
 
+/* constructor */
 
-/* create the hardware's core (memory and devices) from the device
-   tree */
 INLINE_CORE core *core_create
-(device_node *root,
- int trace);
+(void);
 
+INLINE_CORE const device *core_device_create
+(core *);
 
-/* given a created core object, (re)initialize it from the
-   information provided in it's associated device tree */
-
-INLINE_CORE void core_init
-(core *memory);
 
 
-/* from this core extract out the three different types of memory -
-   executable, readable, writeable */
+/* the core has three sub mappings that the more efficient
+   read/write fixed quantity functions use */
 
-INLINE_CORE memory_map *core_readable
+INLINE_CORE core_map *core_readable
 (core *memory);
 
-INLINE_CORE memory_map *core_writeable
+INLINE_CORE core_map *core_writeable
 (core *memory);
 
-INLINE_CORE memory_map *core_executable
+INLINE_CORE core_map *core_executable
 (core *memory);
 
 
-/* operators to grow memory on the fly */
 
-INLINE_CORE void core_add_raw_memory
-(core *memory,
- void *buffer,
- unsigned_word base,
- unsigned size,
- device_access access);
+/* operators to add/remove a mapping in the core
 
-INLINE_CORE void core_add_callback_memory
-(core *memory,
- device_node *device,
- device_reader_callback *reader,
- device_writer_callback *writer,
- unsigned_word base,
- unsigned size,
- device_access access);
+   callback-memory:
 
+   All access are passed onto the specified devices callback routines
+   after being `translated'.  DEFAULT indicates that the specified
+   memory should be called if all other mappings fail.
+   
+   For callback-memory, the device must be specified.
 
-/* In the VEA model, memory grow's after it is created.  Operators
-   below grow memory as required.
+   raw-memory:
 
-   FIXME - should this be inside of vm? */
+   While RAM could be implemented using the callback interface
+   core instead treats it as the common case including the code
+   directly in the read/write operators.
 
-INLINE_CORE unsigned_word core_data_upper_bound
-(core *memory);
+   For raw-memory, the device is ignored and the core alloc's a
+   block to act as the memory.
 
-INLINE_CORE unsigned_word core_stack_lower_bound
-(core *memory);
+   default-memory:
 
-INLINE_CORE unsigned_word core_stack_size
-(core *memory);
+   Should, for the core, there be no defined mapping for a given
+   address then the default map (if present) is called.
 
-INLINE_CORE void core_add_data
-(core *memory,
- unsigned_word incr);
+   For default-memory, the device must be specified. */
 
-INLINE_CORE void core_add_stack
-(core *memory,
- unsigned_word incr);
+INLINE_CORE void core_attach
+(core *map,
+ attach_type attach,
+ int address_space,
+ access_type access,
+ unsigned_word addr,
+ unsigned nr_bytes, /* host limited */
+ const device *device); /*callback/default*/
 
+INLINE_CORE void core_detach
+(core *map,
+ attach_type attach,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes, /* host limited */
+ access_type access,
+ const device *device); /*callback/default*/
 
-#endif /* _CORE_ */
+
+/* Variable sized read/write:
+
+   Transfer (zero) a variable size block of data between the host and
+   target (possibly byte swapping it).  Should any problems occure,
+   the number of bytes actually transfered is returned. */
+
+INLINE_CORE unsigned core_map_read_buffer
+(core_map *map,
+ void *buffer,
+ unsigned_word addr,
+ unsigned nr_bytes);
+
+INLINE_CORE unsigned core_map_write_buffer
+(core_map *map,
+ const void *buffer,
+ unsigned_word addr,
+ unsigned nr_bytes);
+
+
+/* Fixed sized read/write:
+
+   Transfer a fixed amout of memory between the host and target.  The
+   memory always being translated and the operation always aborting
+   should a problem occure */
+
+#define DECLARE_CORE_WRITE_N(N) \
+INLINE_CORE void core_map_write_##N \
+(core_map *map, \
+ unsigned_word addr, \
+ unsigned_##N val, \
+ cpu *processor, \
+ unsigned_word cia);
+
+DECLARE_CORE_WRITE_N(1)
+DECLARE_CORE_WRITE_N(2)
+DECLARE_CORE_WRITE_N(4)
+DECLARE_CORE_WRITE_N(8)
+DECLARE_CORE_WRITE_N(word)
+
+#define DECLARE_CORE_READ_N(N) \
+INLINE_CORE unsigned_##N core_map_read_##N \
+(core_map *map, \
+ unsigned_word addr, \
+ cpu *processor, \
+ unsigned_word cia);
+
+DECLARE_CORE_READ_N(1)
+DECLARE_CORE_READ_N(2)
+DECLARE_CORE_READ_N(4)
+DECLARE_CORE_READ_N(8)
+DECLARE_CORE_READ_N(word)
+
+#endif
diff --git a/sim/ppc/core_n.h b/sim/ppc/core_n.h
new file mode 100644 (file)
index 0000000..d4c54bc
--- /dev/null
@@ -0,0 +1,91 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, 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 N
+#error "N must be #defined"
+#endif
+
+#undef unsigned_N
+#define unsigned_N XCONCAT2(unsigned_,N)
+#undef T2H_N
+#define T2H_N XCONCAT2(T2H_,N)
+#undef H2T_N
+#define H2T_N XCONCAT2(H2T_,N)
+
+
+INLINE_CORE unsigned_N
+XCONCAT2(core_map_read_,N)(core_map *map,
+                          unsigned_word addr,
+                          cpu *processor,
+                          unsigned_word cia)
+{
+  core_mapping *mapping = core_map_find_mapping(map,
+                                               addr,
+                                               sizeof(unsigned_N),
+                                               processor,
+                                               cia,
+                                               1); /*abort*/
+  if (WITH_CALLBACK_MEMORY && mapping->reader != NULL) {
+    unsigned_N data;
+    if (mapping->reader(mapping->device,
+                       &data,
+                        mapping->address_space,
+                        addr - mapping->base,
+                        sizeof(unsigned_N), /* nr_bytes */
+                        processor,
+                        cia) != sizeof(unsigned_N))
+      error("core_read_,N() reader should not fail\n");
+    return T2H_N(data);
+  }
+  else
+    return T2H_N(*(unsigned_N*)core_translate(mapping, addr));
+}
+
+
+
+INLINE_CORE void
+XCONCAT2(core_map_write_,N)(core_map *map,
+                           unsigned_word addr,
+                           unsigned_N val,
+                           cpu *processor,
+                           unsigned_word cia)
+{
+  core_mapping *mapping = core_map_find_mapping(map,
+                                               addr,
+                                               sizeof(unsigned_N),
+                                               processor,
+                                               cia,
+                                               1); /*abort*/
+  if (WITH_CALLBACK_MEMORY && mapping->writer != NULL) {
+    unsigned_N data = H2T_N(val);
+    if (mapping->writer(mapping->device,
+                       &data,
+                        mapping->address_space,
+                       addr - mapping->base,
+                       sizeof(unsigned_N), /* nr_bytes */
+                       processor,
+                       cia) != sizeof(unsigned_N))
+      error("core_read_,N() writer should not fail\n");
+  }
+  else
+    *(unsigned_N*)core_translate(mapping, addr) = H2T_N(val);
+}
+
index 3a0f60e26f64c7c4e1a4f4263710f464b85fa103..78b6e1b624590896631c28dab1dc9f261333e9a7 100644 (file)
 #endif
 
 #include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 #include "basics.h"
 #include "device_tree.h"
-#include "devices.h"
 
-#include "bfd.h"
-
-/* Any starting address less than this is assumed to be an OEA program
-   rather than VEA.  */
-#ifndef OEA_START_ADDRESS
-#define        OEA_START_ADDRESS 4096
-#endif
-
-#ifndef OEA_MEMORY_SIZE
-#define OEA_MEMORY_SIZE 0x100000
-#endif
-
-enum { clayton_memory_size = OEA_MEMORY_SIZE };
-
-/* insert the address into the device_nodes sorted list of addresses */
-INLINE_DEVICE_TREE void
-device_node_add_address(device_node *node,
-                       unsigned_word lower_bound,
-                       unsigned size,
-                       device_access access,
-                       void *init)
-{
-  unsigned_word upper_bound = lower_bound + size;
-  device_address *new_address;
-  device_address **current_address;
-
-  /* find the insertion point */
-  current_address = &node->addresses;
-  while (*current_address != NULL
-        && (*current_address)->upper_bound >= upper_bound) {
-    current_address = &(*current_address)->next_address;
-  }
-
-  /* insert */
-  new_address = ZALLOC(device_address);
-  new_address->lower_bound = lower_bound;
-  new_address->upper_bound = lower_bound + size;
-  new_address->size = size;
-  new_address->access = access;
-  new_address->init = init;
-  new_address->next_address = *current_address;
-  *current_address = new_address;
-}
-
-
-/* create a new device tree optionally making it a child of the parent
-   node */
-
-INLINE_DEVICE_TREE device_node *
-device_node_create(device_node *parent,
-                  char *name,
-                  device_type type,
-                  device_callbacks *callbacks,
-                  void *data)
+typedef enum {
+  node_any = 0,
+  node_device,
+  node_integer,
+  node_boolean,
+  node_string
+} node_type;
+
+
+struct _device_tree {
+  /* where i am */
+  device_tree *parent;
+  device_tree *children;
+  device_tree *sibling;
+  /* what i am */
+  node_type type;
+  const char *name;
+  /* the value */
+  const device *device;
+  int boolean;
+  const char *string;
+  signed_word integer;
+};
+
+
+STATIC_INLINE_DEVICE_TREE device_tree *
+new_device_tree(device_tree *parent,
+               const char *name,
+               node_type type)
 {
-  device_node *new_node;
-  new_node = ZALLOC(device_node);
+  device_tree *new_node;
+  new_node = ZALLOC(device_tree);
   new_node->parent = parent;
-  new_node->name = name;
+  new_node->name = strdup(name);
   new_node->type = type;
-  new_node->callbacks = callbacks;
-  new_node->data = data;
   if (parent != NULL) {
-    new_node->sibling = parent->children;
-    parent->children = new_node;
+    device_tree **sibling = &parent->children;
+    while ((*sibling) != NULL)
+      sibling = &(*sibling)->sibling;
+    *sibling = new_node;
   }
   return new_node;
 }
 
 
-/* Binary file:
+/* find/create a node in the device tree */
 
-   The specified file is a binary, assume VEA is required, construct a
-   fake device tree based on the addresses of the text / data segments
-   requested by the binary */
+typedef enum {
+  device_tree_grow = 1,
+  device_tree_return_null = 2,
+  device_tree_abort = 3,
+} device_tree_action;
 
-
-/* Update the fake device tree so that memory is allocated for this
-   section */
-STATIC_INLINE_DEVICE_TREE void
-update_memory_node_for_section(bfd *abfd,
-                              asection *the_section,
-                              PTR obj)
+STATIC_INLINE_DEVICE_TREE device_tree *
+device_tree_find_node(device_tree *root,
+                     const char *path,
+                     node_type type,
+                     device_tree_action action)
 {
-  unsigned_word section_vma;
-  unsigned_word section_size;
-  device_access section_access;
-  void *section_init;
-  device_node *memory = (device_node*)obj;
-
-  /* skip the section if no memory to allocate */
-  if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
-    return;
-
-  /* check/ignore any sections of size zero */
-  section_size = bfd_get_section_size_before_reloc(the_section);
-  if (section_size == 0)
-    return;
-
-  /* find where it is to go */
-  section_vma = bfd_get_section_vma(abfd, the_section);
-
-  TRACE(trace_device_tree,
-       ("name=%-7s, vma=0x%.8x, size=%6d, flags=%3x(%s%s%s%s )\n",
-        bfd_get_section_name(abfd, the_section),
-        section_vma, section_size,
-        bfd_get_section_flags(abfd, the_section),
-        bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
-        bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
-        bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
-        bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
-        bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
-       ));
-
-  if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
-    section_init = zalloc(section_size);
-    if (!bfd_get_section_contents(abfd,
-                                 the_section,
-                                 section_init, 0,
-                                 section_size)) {
-      bfd_perror("core:load_section()");
-      error("load of data failed");
-      return;
+  const char *chp;
+  int name_len;
+  device_tree *child;
+
+  /* strip off any leading `/', `../' or `./' */
+  while (1) {
+    if (strncmp(path, "/", strlen("/")) == 0) {
+      while (root != NULL && root->parent != NULL)
+       root = root->parent;
+      path += strlen("/");
+    }
+    else if (strncmp(path, "./", strlen("./")) == 0) {
+      root = root;
+      path += strlen("./");
+    }
+    else if (strncmp(path, "../", strlen("../")) == 0) {
+      if (root != NULL && root->parent != NULL)
+       root = root->parent;
+      path += strlen("../");
+    }
+    else {
+      break;
     }
   }
-  else {
-    section_init = NULL;
+
+  /* find the qualified (with @) and unqualified names in the path,
+     remembering to skip any "\/" */
+  chp = path;
+  do {
+    chp = strchr(chp+1, '/');
+  } while (chp != NULL && chp[-1] == '\\');
+  name_len = (chp == NULL
+             ? strlen(path)
+             : chp - path);
+
+  /* leaf? and growing? */
+  if (root != NULL) {
+    for (child = root->children;
+        child != NULL;
+        child = child->sibling) {
+      if (strncmp(path, child->name, name_len) == 0
+         && (strlen(child->name) == name_len
+             || (strchr(child->name, '@')
+                 == child->name + name_len))) {
+       if (path[name_len] == '\0') {
+         if (action == device_tree_grow)
+           error("device_tree_find_node() node %s already present\n",
+                 path);
+         if (type != node_any && child->type != type) {
+           if (action == device_tree_return_null)
+             return NULL;
+           else
+             error("device_tree_find_node() node %s does not match type %d\n",
+                   path, type);
+         }
+         else
+           return child;
+       }
+       else
+         return device_tree_find_node(child,
+                                      path + name_len + 1,
+                                      type,
+                                      action);
+      }
+    }
+  }
+
+  /* search failed, take default action */
+  switch (action) {
+  case device_tree_grow:
+    if (path[name_len] != '\0')
+      error("device_tree_find_node() not a leaf %s\n", path);
+    return new_device_tree(root, path, type);
+  case device_tree_return_null:
+    return NULL;
+  default:
+    error("device_tree_find_node() invalid default action %d\n", action);
+    return NULL;
   }
+}
 
-  /* determine the devices access */
-  if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
-    section_access = (device_is_readable | device_is_executable);
-  else if (bfd_get_section_flags(abfd, the_section) & SEC_READONLY)
-    section_access = device_is_readable;
-  else
-    section_access = (device_is_readable | device_is_writeable);
-
-  /* find our memory and add this section to its list of addresses */
-  device_node_add_address(memory,
-                         section_vma,
-                         section_size,
-                         section_access,
-                         section_init);
+
+/* grow the device tree */
+
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_passthrough(device_tree *root,
+                           const char *path)
+{
+  device_tree *new_node = device_tree_find_node(root,
+                                               path,
+                                               node_device,
+                                               device_tree_grow);
+  new_node->device = device_create_from(new_node->name,
+                                       NULL,
+                                       passthrough_device_callbacks(),
+                                       new_node->parent->device);
+  return new_node;
 }
 
 
-/* construct the device tree from the executable */
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_device(device_tree *root,
+                      const char *path,
+                      const device *dev)
+{
+  device_tree *new_node = device_tree_find_node(root,
+                                               path,
+                                               node_device,
+                                               device_tree_grow);
+  new_node->device = dev;
+  return new_node;
+}
 
-STATIC_INLINE_DEVICE_TREE device_node *
-create_option_device_node(device_node *root,
-                         bfd *image)
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_integer(device_tree *root,
+                       const char *path,
+                       signed_word integer)
 {
-  int oea = (bfd_get_start_address(image) < OEA_START_ADDRESS);
-  int elf = (image->xvec->flavour == bfd_target_elf_flavour);
-  device_node *option_node;
-  
-  /* the option node and than its members */
-  option_node = device_node_create(root, "options", options_device,
-                                  NULL, NULL);
-
-  /* which endian are we ? */
-  device_node_create(option_node,
-                    "little-endian?",
-                    boolean_type_device,
-                    NULL,
-                    (void*)(image->xvec->byteorder_big_p ? 0 : -1));
-
-  /* what is the initial entry point */
-  device_node_create(option_node,
-                    "program-counter",
-                    integer_type_device,
-                    NULL,
-                    (void*)(bfd_get_start_address(image)));
-
-  /* address of top of boot stack */
-  TRACE(trace_tbd, ("create_optioin_device_node() - TBD - NT/OpenBoot?\n"));
-  device_node_create(option_node,
-                    "stack-pointer",
-                    integer_type_device,
-                    NULL,
-                    (void *)((oea)
-                            ? clayton_memory_size /* OEA */
-                            : ((elf)
-                               ? 0xe0000000 /* elf */
-                               : 0x20000000 /* xcoff */)));
-
-  /* execution environment */
-  device_node_create(option_node,
-                    "vea?",
-                    boolean_type_device,
-                    NULL,
-                    (void *)((oea) ? 0 : -1));
-
-  /* what type of binary */
-  TRACE(trace_tbd, ("create_optioin_device_node() - TBD - NT/OpenBoot?\n"));
-  device_node_create(option_node,
-                    "elf?",
-                    boolean_type_device,
-                    NULL,
-                    (void *)((elf) ? -1 : 0));
-
-  /* must all memory transfers be naturally aligned? */
-  device_node_create(option_node,
-                    "aligned?",
-                    boolean_type_device,
-                    NULL,
-                    (void*)((WITH_ALIGNMENT == NONSTRICT_ALIGNMENT
-                             || image->xvec->byteorder_big_p
-                             || !oea)
-                            ? 0
-                            : -1));
-
-
-  return option_node;
+  device_tree *new_node = device_tree_find_node(root,
+                                               path,
+                                               node_integer,
+                                               device_tree_grow);
+  new_node->integer = integer;
+  return new_node;
 }
 
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_string(device_tree *root,
+                      const char *path,
+                      const char *string)
+{
+  device_tree *new_node = device_tree_find_node(root,
+                                               path,
+                                               node_string,
+                                               device_tree_grow);
+  new_node->string = string;
+  return new_node;
+}
 
-/* clatyon is a simple machine that does not require interrupts or any
-   thing else */
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_boolean(device_tree *root,
+                       const char *path,
+                       int boolean)
+{
+  device_tree *new_node = device_tree_find_node(root,
+                                               path,
+                                               node_boolean,
+                                               device_tree_grow);
+  new_node->boolean = boolean;
+  return new_node;
+}
 
-STATIC_INLINE_DEVICE_TREE device_node *
-create_clayton_device_tree(bfd *image)
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_found_device(device_tree *root,
+                            const char *path)
 {
-  device_node *root;
-  device_node *io_node;
-  device_node *data_node;
-  device_node *memory_node;
-
-  /* the root */
-  root = ZALLOC(device_node);
-
-  /* memory - clayton has 2mb of RAM at location 0 */
-  memory_node = device_node_create(root,
-                                  "memory",
-                                  memory_device,
-                                  NULL,
-                                  NULL);
-  device_node_add_address(memory_node, 0x0, clayton_memory_size,
-                         (device_is_readable
-                          | device_is_writeable
-                          | device_is_executable),
-                         NULL);
-
-  /* io address space */
-  io_node = device_node_create(root, "io", bus_device, NULL, NULL);
-
-  /* and IO devices */
-  find_device_descriptor("console")
-    ->creator(io_node, "console@0x400000,0");
-  find_device_descriptor("halt")
-    ->creator(io_node, "halt@0x500000,0");
-  find_device_descriptor("icu")
-    ->creator(io_node, "icu@0x600000,0");
-
-  /* data to load */
-  data_node = device_node_create(root, "image", data_device, NULL, NULL);
-  bfd_map_over_sections(image,
-                       update_memory_node_for_section,
-                       (PTR)data_node);
-
-  /* options */
-  create_option_device_node(root, image);
-
-  return root;
+  device_tree *new_node = device_tree_add_device(root, path, NULL);
+  new_node->device = device_create(new_node->name,
+                                  new_node->parent->device);
+  return new_node;
 }
 
 
-/* user mode executable build up a device tree that reflects this */
+/* look up the device tree */
 
-STATIC_INLINE_DEVICE_TREE device_node *
-create_vea_device_tree(bfd *image)
+INLINE_DEVICE_TREE const device *
+device_tree_find_device(device_tree *root,
+                       const char *path)
 {
-  device_node *root;
-  device_node *memory_node;
-  device_node *option_node;
-
-  /* the root */
-  root = ZALLOC(device_node);
-
-  /* memory */
-  memory_node = device_node_create(root, "memory", memory_device,
-                                  NULL, NULL);
-  bfd_map_over_sections(image,
-                       update_memory_node_for_section,
-                       (PTR)memory_node);
-  /* options - only endian so far */
-  option_node = create_option_device_node(root, image);
-
-  return root;
+  device_tree *node = device_tree_find_node(root,
+                                           path,
+                                           node_device,
+                                           device_tree_abort);
+  return node->device;
 }
 
+INLINE_DEVICE_TREE signed_word
+device_tree_find_integer(device_tree *root,
+                        const char *path)
+{
+  device_tree *node = device_tree_find_node(root,
+                                           path,
+                                           node_integer,
+                                           device_tree_abort);
+  return node->integer;
+}
 
-/* create a device tree from the specified file */
-INLINE_DEVICE_TREE device_node *
-device_tree_create(const char *file_name)
+INLINE_DEVICE_TREE const char *
+device_tree_find_string(device_tree *root,
+                       const char *path)
 {
-  bfd *image;
-  device_node *tree;
+  device_tree *node = device_tree_find_node(root,
+                                           path,
+                                           node_string,
+                                           device_tree_abort);
+  return node->string;
+}
 
-  bfd_init(); /* could be redundant but ... */
+INLINE_DEVICE_TREE int
+device_tree_find_boolean(device_tree *root,
+                        const char *path)
+{
+  device_tree *node = device_tree_find_node(root,
+                                           path,
+                                           node_boolean,
+                                           device_tree_abort);
+  return node->boolean;
+}
 
-  /* open the file */
-  image = bfd_openr(file_name, NULL);
-  if (image == NULL) {
-    bfd_perror("open failed:");
-    error("nothing loaded\n");
-    return NULL;
-  }
 
-  /* check it is valid */
-  if (!bfd_check_format(image, bfd_object)) {
-    printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
-    printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
-    bfd_close(image);
-    image = NULL;
-  }
+/* init all the devices */
 
-  /* depending on what was found about the file, load it */
-  if (image != NULL) {
-    if (bfd_get_start_address(image) == 0) {
-      TRACE(trace_device_tree, ("create_device_tree() - clayton image\n"));
-      tree = create_clayton_device_tree(image);
-    }
-    else if (bfd_get_start_address(image) > 0) {
-      TRACE(trace_device_tree, ("create_device_tree() - vea image\n"));
-      tree = create_vea_device_tree(image);
-    }
-    bfd_close(image);
-  }
-  else {
-    error("TBD - create_device_tree() text file defining device tree\n");
-    tree = NULL;
-  }
+STATIC_INLINE_DEVICE_TREE void
+device_tree_init_device(device_tree *root,
+                       void *data)
+{
+  psim *system = (psim*)data;
+  if (root->type == node_device)
+    root->device->callback->init(root->device, system);
+}
 
-  return tree;
+
+INLINE_DEVICE_TREE void
+device_tree_init(device_tree *root,
+                psim *system)
+{
+  device_tree_traverse(root, device_tree_init_device, NULL, system);
 }
 
 
 /* traverse a device tree applying prefix/postfix functions to it */
 
 INLINE_DEVICE_TREE void
-device_tree_traverse(device_node *root,
+device_tree_traverse(device_tree *root,
                     device_tree_traverse_function *prefix,
                     device_tree_traverse_function *postfix,
                     void *data)
 {
-  device_node *child;
+  device_tree *child;
   if (prefix != NULL)
     prefix(root, data);
   for (child = root->children; child != NULL; child = child->sibling) {
@@ -389,126 +341,312 @@ device_tree_traverse(device_node *root,
 }
 
 
-/* query the device tree */
+/* dump out a device node and addresses */
 
-INLINE_DEVICE_TREE device_node *
-device_tree_find_node(device_node *root,
-                     const char *path)
+INLINE_DEVICE_TREE void
+device_tree_dump(device_tree *device,
+                void *ignore_data_argument)
 {
-  char *chp;
-  int name_len;
-  device_node *child;
+  printf_filtered("(device_tree@0x%x\n", device);
+  printf_filtered(" (parent 0x%x)\n", device->parent);
+  printf_filtered(" (children 0x%x)\n", device->children);
+  printf_filtered(" (sibling 0x%x)\n", device->sibling);
+  printf_filtered(" (type %d)\n", device->type);
+  printf_filtered(" (name %s)\n", device->name);
+  printf_filtered(" (device 0x%x)\n", device->device);
+  printf_filtered(" (boolean %d)\n", device->boolean);
+  printf_filtered(" (string %s)\n", device->string);
+  printf_filtered(" (integer %d)\n", device->integer);
+  printf_filtered(")\n");
+}
 
-  /* strip off any leading `/', `../' or `./' */
-  while (1) {
-    if (strncmp(path, "/", strlen("/")) == 0) {
-      while (root->parent != NULL)
-       root = root->parent;
-      path += strlen("/");
-    }
-    else if (strncmp(path, "./", strlen("./")) == 0) {
-      root = root;
-      path += strlen("./");
-    }
-    else if (strncmp(path, "../", strlen("../")) == 0) {
-      if (root->parent != NULL)
-       root = root->parent;
-      path += strlen("../");
-    }
-    else {
-      break;
-    }
-  }
 
-  /* find the qualified (with @) and unqualified names in the path */
-  chp = strchr(path, '/');
-  name_len = (chp == NULL
-             ? strlen(path)
-             : chp - path);
+/* Parse a device name, various formats */
 
-  /* search through children for a match */
-  for (child = root->children;
-       child != NULL;
-       child = child->sibling) {
-    if (strncmp(path, child->name, name_len) == 0
-       && (strlen(child->name) == name_len
-           || strchr(child->name, '@') == child->name + name_len)) {
-      if (path[name_len] == '\0')
-       return child;
-      else
-       return device_tree_find_node(child, path + name_len + 1);
-    }
-  }
-  return NULL;
+#ifndef __NetBSD__
+#define strtouq strtoul
+#endif
+
+#define SCAN_INIT(START, END, COUNT, NAME) \
+  char *START = NULL; \
+  char *END = strchr(NAME, '@'); \
+  int COUNT = 0; \
+  if (END == NULL) \
+    return 0; \
+  START = END + 1
+
+#define SCAN_U(START, END, COUNT, U) \
+do { \
+  *U = strtouq(START, &END, 0); \
+  if (START == END) \
+    return COUNT; \
+  COUNT++; \
+  if (*END != ',') \
+    return COUNT; \
+  START = END + 1; \
+} while (0)
+
+#define SCAN_P(START, END, COUNT, P) \
+do { \
+  *P = (void*)(unsigned)strtouq(START, &END, 0); \
+  if (START == END) \
+    return COUNT; \
+  COUNT++; \
+  if (*END != ',') \
+    return COUNT; \
+  START = END + 1; \
+} while (0)
+
+#define SCAN_C(START, END, COUNT, C) \
+do { \
+  char *chp = C; \
+  END = START; \
+  while (*END != '\0' && *END != ',') { \
+    if (*END == '\\') \
+      END++; \
+    *chp = *END; \
+    chp += 1; \
+    END += 1; \
+  } \
+  *chp = '\0'; \
+  if (START == END) \
+    return COUNT; \
+  COUNT++; \
+  if (*END != ',') \
+    return COUNT; \
+  START = END + 1; \
+} while (0)
+
+INLINE_DEVICE_TREE int
+scand_uw(const char *name,
+        unsigned_word *uw1)
+{
+  SCAN_INIT(start, end, count, name);
+  SCAN_U(start, end, count, uw1);
+  return count;
 }
 
-INLINE_DEVICE_TREE device_node *device_tree_find_next_node
-(device_node *root,
- const char *path,
- device_node *last);
+INLINE_DEVICE_TREE int
+scand_uw_u(const char *name,
+          unsigned_word *uw1,
+          unsigned *u2)
+{
+  SCAN_INIT(start, end, count, name);
+  SCAN_U(start, end, count, uw1);
+  SCAN_U(start, end, count, u2);
+  return count;
+}
 
-INLINE_DEVICE_TREE signed_word
-device_tree_find_int(device_node *root,
-                    const char *path)
+INLINE_DEVICE_TREE int
+scand_uw_u_u(const char *name,
+            unsigned_word *uw1,
+            unsigned *u2,
+            unsigned *u3)
 {
-  device_node *int_node = device_tree_find_node(root, path);
-  if (int_node == NULL) {
-    error("device_tree_find_int() - node %s does not exist\n", path);
-    return 0;
-  }
-  else if (int_node->type != integer_type_device) {
-    error("device_tree_find_int() - node %s is not an int\n", path);
-    return 0;
-  }
-  else {
-    return (signed_word)(int_node->data);
-  }
+  SCAN_INIT(start, end, count, name);
+  SCAN_U(start, end, count, uw1);
+  SCAN_U(start, end, count, u2);
+  SCAN_U(start, end, count, u3);
+  return count;
 }
 
+INLINE_DEVICE_TREE int
+scand_uw_uw_u(const char *name,
+             unsigned_word *uw1,
+             unsigned_word *uw2,
+             unsigned *u3)
+{
+  SCAN_INIT(start, end, count, name);
+  SCAN_U(start, end, count, uw1);
+  SCAN_U(start, end, count, uw2);
+  SCAN_U(start, end, count, u3);
+  return count;
+}
 
-INLINE_DEVICE_TREE const char *device_tree_find_string
-(device_node *root,
- const char *path);
+INLINE_DEVICE_TREE int
+scand_c(const char *name,
+       char *c1)
+{
+  SCAN_INIT(start, end, count, name);
+  SCAN_C(start, end, count, c1);
+  return count;
+}
 
 INLINE_DEVICE_TREE int
-device_tree_find_boolean(device_node *root,
-                        const char *path)
+scand_c_uw_u(const char *name,
+            char *c1,
+            unsigned_word *uw2,
+            unsigned *u3)
 {
-  device_node *int_node = device_tree_find_node(root, path);
-  if (int_node == NULL) {
-    error("device_tree_find_boolean() - node %s does not exist\n", path);
-    return 0;
-  }
-  else if (int_node->type != boolean_type_device) {
-    error("device_tree_find_boolean() - node %s is not a boolean\n", path);
-    return 0;
+  SCAN_INIT(start, end, count, name);
+  SCAN_C(start, end, count, c1);
+  SCAN_U(start, end, count, uw2);
+  SCAN_U(start, end, count, u3);
+  return count;
+}
+
+
+STATIC_INLINE_DEVICE_TREE void
+u_strcat(char *buf,
+        unsigned_word uw)
+{
+  if (MASKED64(uw, 32, 63) == uw
+      || WITH_HOST_WORD_BITSIZE == 64) {
+    char *end = strchr(buf, '\0');
+    sprintf(end, "0x%x", (unsigned)uw);
   }
   else {
-    return (signed_word)(int_node->data);
+    char *end = strchr(buf, '\0');
+    sprintf(end, "0x%x%08x",
+           (unsigned)EXTRACTED64(uw, 0, 31),
+           (unsigned)EXTRACTED64(uw, 32, 63));
+  }
+}
+
+STATIC_INLINE_DEVICE_TREE void
+c_strcat(char *buf,
+       const char *c)
+{
+  char *end = strchr(buf, '\0');
+  while (*c) {
+    if (*c == '/' || *c == ',')
+      *end++ = '\\';
+    *end++ = *c++;
+  }
+  *end = '\0';
+}
+
+STATIC_INLINE_DEVICE_TREE int
+c_strlen(const char *c)
+{
+  int len = 0;
+  while (*c) {
+    if (*c == '/' || *c == ',')
+      len++;
+    len++;
+    c++;
   }
+  return len;
 }
 
+enum {
+  strlen_unsigned = 10,
+  strlen_unsigned_word = 18,
+};
 
-INLINE_DEVICE_TREE void *device_tree_find_bytes
-(device_node *root,
- const char *path);
+INLINE_DEVICE_TREE char *
+printd_uw_u(const char *name,
+           unsigned_word uw1,
+           unsigned u2)
+{
+  int sizeof_buf = (strlen(name)
+                   + strlen("@")
+                   + strlen_unsigned_word
+                   + strlen(",")
+                   + strlen_unsigned
+                   + 1);
+  char *buf = (char*)zalloc(sizeof_buf);
+  strcpy(buf, name);
+  strcat(buf, "@");
+  u_strcat(buf, uw1);
+  strcat(buf, ",");
+  u_strcat(buf, u2);
+  ASSERT(strlen(buf) < sizeof_buf);
+  return buf;
+}
 
-/* dump out a device node and addresses */
+INLINE_DEVICE_TREE char *
+printd_uw_u_u(const char *name,
+             unsigned_word uw1,
+             unsigned u2,
+             unsigned u3)
+{
+  int sizeof_buf = (strlen(name)
+                   + strlen("@")
+                   + strlen_unsigned_word
+                   + strlen(",")
+                   + strlen_unsigned
+                   + strlen(",")
+                   + strlen_unsigned
+                   + 1);
+  char *buf = (char*)zalloc(sizeof_buf);
+  strcpy(buf, name);
+  strcat(buf, "@");
+  u_strcat(buf, uw1);
+  strcat(buf, ",");
+  u_strcat(buf, u2);
+  strcat(buf, ",");
+  u_strcat(buf, u3);
+  ASSERT(strlen(buf) < sizeof_buf);
+  return buf;
+}
 
-INLINE_DEVICE_TREE void
-device_tree_dump(device_node *device,
-                void *ignore_data_argument)
+INLINE_DEVICE_TREE char *
+printd_uw_u_u_c(const char *name,
+               unsigned_word uw1,
+               unsigned u2,
+               unsigned u3,
+               const char *c4)
 {
-  printf_filtered("(device_node@0x%x\n", device);
-  printf_filtered(" (parent 0x%x)\n", device->parent);
-  printf_filtered(" (children 0x%x)\n", device->children);
-  printf_filtered(" (sibling 0x%x)\n", device->sibling);
-  printf_filtered(" (name %s)\n", device->name ? device->name : "(null)");
-  printf_filtered(" (type %d)\n", device->type);
-  printf_filtered(" (handlers 0x%x)\n", device->callbacks);
-  printf_filtered(" (addresses %d)\n", device->addresses);
-  printf_filtered(" (data %d)\n", device->data);
-  printf_filtered(")\n");
+  int sizeof_buf = (strlen(name)
+                   + strlen("@")
+                   + strlen_unsigned_word
+                   + strlen(",")
+                   + strlen_unsigned
+                   + strlen(",")
+                   + strlen_unsigned
+                   + strlen(",")
+                   + c_strlen(c4)
+                   + 1);
+  char *buf = (char*)zalloc(sizeof_buf);
+  strcpy(buf, name);
+  strcat(buf, "@");
+  u_strcat(buf, uw1);
+  strcat(buf, ",");
+  u_strcat(buf, u2);
+  strcat(buf, ",");
+  u_strcat(buf, u3);
+  strcat(buf, ",");
+  c_strcat(buf, c4);
+  ASSERT(strlen(buf) < sizeof_buf);
+  return buf;
+}
+
+INLINE_DEVICE_TREE char *
+printd_c(const char *name,
+        const char *c1)
+{
+  int sizeof_buf = (strlen(name)
+                   + strlen("@")
+                   + c_strlen(c1)
+                   + 1);
+  char *buf = (char*)zalloc(sizeof_buf);
+  strcpy(buf, name);
+  strcat(buf, "@");
+  c_strcat(buf, c1);
+  ASSERT(strlen(buf) < sizeof_buf);
+  return buf;
+}
+
+INLINE_DEVICE_TREE char *
+printd_c_uw(const char *name,
+           const char *c1,
+           unsigned_word uw2)
+{
+  int sizeof_buf = (strlen(name)
+                   + strlen("@")
+                   + c_strlen(c1)
+                   + strlen(",")
+                   + strlen_unsigned_word
+                   + 1);
+  char *buf = (char*)zalloc(sizeof_buf);
+  strcpy(buf, name);
+  strcat(buf, "@");
+  c_strcat(buf, c1);
+  strcat(buf, ",");
+  u_strcat(buf, uw2);
+  ASSERT(strlen(buf) < sizeof_buf);
+  return buf;
 }
 
 #endif /* _DEVICE_TREE_C_ */
index 59d764ec88f03b6f0ed44b1b182eec7f8a40dc6b..d8e54819d328a6b3f8cb7bcbed3f7236987d1e10 100644 (file)
 #endif
 
 
-/* forward declaration of types */
-
-typedef struct _device_node device_node;
-typedef struct _device_address device_address;
-typedef struct _device_callbacks device_callbacks;
-
-
-/* Device callbacks: */
-
-
-/* Memory operations: transfer data to/from a processor.
-
-   These callbacks pass/return data in *host* byte order.
-
-   Should a memory read/write operation cause an interrupt (external
-   exception) then a device would typically pass an interrupt message
-   to the devices parent.  Hopefully that is an interrupt controler
-   and will know what to do with it.
-
-   Devices normally never either restart a processor or issue an
-   interrupt directly.  The only exception I've thought of could be
-   machine check type event. */
-
-typedef unsigned64 (device_reader_callback)
-     (device_node *device,
-      unsigned_word base,
-      unsigned nr_bytes,
-      cpu *processor,
-      unsigned_word cia);
-
-typedef void (device_writer_callback)
-     (device_node *device,
-      unsigned_word base,
-      unsigned nr_bytes,
-      unsigned64 val,
-      cpu *processor,
-      unsigned_word cia);
-
-/* Interrupts:
-
-   A child device uses the below to pass on to its parent changes in
-   the state of a child devices interrupt lines.
-
-   Typically, the parent being an interrupt control device, would, in
-   responce, schedule an event at the start of the next clock cycle.
-   On this event, the state of any cpu could be changed.  Other
-   devices could either ignore or pass on the interrupt message */
-
-typedef void (device_interrupt_callback)
-     (device_node *me,
-      int interrupt_status,
-      device_node *device,
-      cpu *processor,
-      unsigned_word cia);
-
-/* Create:
-
-   DEVICE_CREATOR is called once, as part of building the device tree.
-   This function gives the device the chance to attach any additional
-   data to this particular device instance.
-
-   DEVICE_INIT_CALLBACK is (re)called when ever the system is
-   (re)initialised. */
-
-typedef device_node *(device_creator)
-     (device_node *parent,
-      char *name);
-
-typedef void (device_init_callback)
-     (device_node *device);
-
-
-
-/* constructs to describe the hardware's tree of devices */
-
-typedef enum _device_type {
-  /* default */
-  unknown_device,
-  /* typical devices */
-  memory_device,
-  sequential_device,
-  block_device,
-  bus_device,
-  other_device,
-  /* atypical devices, these are for data being loaded into ram/rom */
-  data_device,
-  options_device,
-  /* types of primative nodes containing just data */
-  boolean_type_device,
-  integer_type_device,
-  string_type_device,
-  byte_type_device,
-} device_type;
-
-typedef enum _device_access {
-  device_is_readable = 1,
-  device_is_writeable = 2,
-  device_is_read_write = 3,
-  device_is_executable = 4,
-  device_is_read_exec = 5,
-  device_is_write_exec = 6,
-  device_is_read_write_exec = 7,
-} device_access;
-
-struct _device_address {
-  unsigned_word lower_bound;
-  unsigned_word upper_bound;
-  unsigned size; /* host limited */
-  void *init; /* initial data */
-  device_access access;
-  device_address *next_address;
-};
-
-struct _device_callbacks {
-  device_reader_callback *read_callback;
-  device_writer_callback *write_callback;
-  device_interrupt_callback *interrupt_callback;
-  /* device_init_callback *init_callback; */
-  /* device_init_hander *post_init_handler; */
-};
-
-struct _device_node {
-  /* where i am */
-  device_node *parent;
-  device_node *children;
-  device_node *sibling;
-  /* what I am */
-  char *name; /* eg rom@0x1234,0x40 */
-  device_type type;
-  device_callbacks *callbacks;
-  device_address *addresses;
-  void *data;
-};
-
-
-/* given the image to run, return its device tree */
-
-INLINE_DEVICE_TREE device_node *device_tree_create
-(const char *hardware_description);
+#include "devices.h"
 
+typedef struct _device_tree device_tree;
 
-/* traverse the tree eiter pre or post fix */
 
-typedef void (device_tree_traverse_function)
-     (device_node *device,
-      void *data);
+/* extend the device tree, each function returns the address of the
+   new node */
 
-INLINE_DEVICE_TREE void device_tree_traverse
-(device_node *root,
- device_tree_traverse_function *prefix,
- device_tree_traverse_function *postfix,
- void *data);
+INLINE_DEVICE_TREE device_tree *device_tree_add_passthrough
+(device_tree *root,
+ const char *path);
 
+INLINE_DEVICE_TREE device_tree *device_tree_add_device
+(device_tree *root,
+ const char *path,
+ const device *dev);
+INLINE_DEVICE_TREE device_tree *device_tree_add_integer
+(device_tree *root,
+ const char *path,
+ signed_word integer);
 
-/* query the device tree */
+INLINE_DEVICE_TREE device_tree *device_tree_add_string
+(device_tree *root,
+ const char *path,
+ const char *string);
+
+INLINE_DEVICE_TREE device_tree *device_tree_add_boolean
+(device_tree *root,
+ const char *path,
+ int bool);
 
-INLINE_DEVICE_TREE device_node *device_tree_find_node
-(device_node *root,
+INLINE_DEVICE_TREE device_tree *device_tree_add_found_device
+(device_tree *root,
  const char *path);
 
-INLINE_DEVICE_TREE device_node *device_tree_find_next_node
-(device_node *root,
- const char *path,
- device_node *last);
+/* query the device tree */
+
+INLINE_DEVICE_TREE const device *device_tree_find_device
+(device_tree *root,
+ const char *path);
 
-INLINE_DEVICE_TREE signed_word device_tree_find_int
-(device_node *root,
+INLINE_DEVICE_TREE signed_word device_tree_find_integer
+(device_tree *root,
  const char *path);
 
 INLINE_DEVICE_TREE const char *device_tree_find_string
-(device_node *root,
+(device_tree *root,
  const char *path);
 
 INLINE_DEVICE_TREE int device_tree_find_boolean
-(device_node *root,
+(device_tree *root,
  const char *path);
 
-INLINE_DEVICE_TREE void *device_tree_find_bytes
-(device_node *root,
- const char *path);
 
-/* add to the device tree */
+/* initialize the entire tree */
+
+INLINE_DEVICE_TREE void device_tree_init
+(device_tree *root,
+ psim *system);
+
+
+/* traverse the tree eiter pre or post fix */
 
-INLINE_DEVICE_TREE device_node *device_node_create
-(device_node *parent,
- char *name,
- device_type type,
- device_callbacks *callbacks,
+typedef void (device_tree_traverse_function)
+     (device_tree *device,
+      void *data);
+
+INLINE_DEVICE_TREE void device_tree_traverse
+(device_tree *root,
+ device_tree_traverse_function *prefix,
+ device_tree_traverse_function *postfix,
  void *data);
 
-INLINE_DEVICE_TREE void device_node_add_address
-(device_node *node,
- unsigned_word lower_bound,
- unsigned size,
- device_access access,
- void *init);
 
-/* dump a node, pass this to the device_tree_traverse() function to
-   dump the tree */
+/* dump a node, this can be passed to the device_tree_traverse()
+   function to dump out the entire device tree */
 
 INLINE_DEVICE_TREE void device_tree_dump
-(device_node *device,
+(device_tree *device,
  void *ignore_data_argument);
 
+
+/* Parse a device name, various formats */
+
+INLINE_DEVICE_TREE int scand_uw
+(const char *name,
+ unsigned_word *uw1);
+INLINE_DEVICE_TREE int scand_uw_u
+(const char *name,
+ unsigned_word *uw1,
+ unsigned *u2);
+INLINE_DEVICE_TREE int scand_uw_u_u
+(const char *name,
+ unsigned_word *uw1,
+ unsigned *u2,
+ unsigned *u3);
+INLINE_DEVICE_TREE int scand_uw_uw_u
+(const char *name,
+ unsigned_word *uw1,
+ unsigned_word *uw2,
+ unsigned *u3);
+INLINE_DEVICE_TREE int scand_c
+(const char *name,
+ char *c1);
+
+INLINE_DEVICE_TREE int scand_c_uw_u
+(const char *name,
+ char *c1,
+ unsigned_word *uw2,
+ unsigned *u3);
+
+INLINE_DEVICE_TREE char *printd_uw_u
+(const char *name,
+ unsigned_word uw1,
+ unsigned u2);
+
+INLINE_DEVICE_TREE char *printd_uw_u_u
+(const char *name,
+ unsigned_word uw1,
+ unsigned u2,
+ unsigned u3);
+
+INLINE_DEVICE_TREE char *printd_uw_u_u_c
+(const char *name,
+ unsigned_word uw1,
+ unsigned u2,
+ unsigned u3,
+ const char *c4);
+
+INLINE_DEVICE_TREE char *printd_c
+(const char *name,
+ const char *c1);
+
+INLINE_DEVICE_TREE char *printd_c_uw
+(const char *name,
+ const char *c1,
+ unsigned_word uw2);
+
 #endif /* _DEVICE_TREE_H_ */
index 96b8109b326b70b493f366e37af54107b8af74ab..983b6934d82879a994c58d1533e5fcc186bc3506 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 #include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
 
 #include "basics.h"
-#include "device_tree.h"
 #include "devices.h"
 #include "events.h"
 
-#include "cpu.h" /* drats */
+#include "cpu.h"
+
+#include "bfd.h"
 
 /* Helper functions */
 
+/* Generic device init: Attaches the device of size <nr_bytes> (taken
+   from <name>@<int>,<nr_bytes>) to its parent at address zero and
+   with read/write access. */
+
 STATIC_INLINE_DEVICES void
-parse_device_address(char *name,
-                    unsigned *base,
-                    unsigned *flags)
+generic_init_callback(const device *me,
+                     psim *system)
 {
-  /* extract the two arguments */
-  name = strchr(name, '@');
-  if (name == NULL)
-    error("missing address for device %s\n", name);
-  name++;
-  *base = strtol(name, &name, 0);
-  *flags = (*name == ','
-           ? strtol(name+1, &name, 0)
-           : 0);
+  unsigned_word addr;
+  unsigned nr_bytes;
+  if (scand_uw_u(me->name, &addr, &nr_bytes) != 2)
+    error("generic_init_callback() invalid nr_bytes in %s\n", me->name);
+  me->parent->callback->attach_address(me->parent,
+                                      me->name,
+                                      attach_callback,
+                                      0 /*address_space*/,
+                                      addr,
+                                      nr_bytes,
+                                      access_read_write,
+                                      me);
 }
 
 
-/* Simple console device:
+\f
+/* inimplemented versions of each function */
 
-   Implements a simple text output device that is attached to stdout
-   of the process running the simulation.  The devices has four
-   word registers:
+INLINE_DEVICES void
+unimp_device_init(const device *me,
+                 psim *system)
+{
+  error("device_init_callback for %s not implemented\n", me->name);
+}
 
-   0: read
-   4: read-status
-   8: write
-   c: write-status
+INLINE_DEVICES void
+unimp_device_attach_address(const device *me,
+                           const char *name,
+                           attach_type type,
+                           int address_space,
+                           unsigned_word addr,
+                           unsigned nr_bytes,
+                           access_type access,
+                           const device *who) /*callback/default*/
+{
+  error("device_attach_address_callback for %s not implemented\n", me->name);
+}
 
-   Where a nonzero status register indicates that the device is ready
-   (input fifo contains a character or output fifo has space).
+INLINE_DEVICES void
+unimp_device_detach_address(const device *me,
+                           const char *name,
+                           attach_type type,
+                           int address_space,
+                           unsigned_word addr,
+                           unsigned nr_bytes,
+                           access_type access,
+                           const device *who) /*callback/default*/
+{
+  error("device_detach_address_callback for %s not implemented\n", me->name);
+}
 
-   Illustrates: Mapping read/write to device operations onto actual
-   registers.
+INLINE_DEVICES unsigned
+unimp_device_io_read_buffer(const device *me,
+                           void *dest,
+                           int address_space,
+                           unsigned_word addr,
+                           unsigned nr_bytes,
+                           cpu *processor,
+                           unsigned_word cia)
+{
+  error("device_io_read_buffer_callback for %s not implemented\n", me->name);
+  return 0;
+}
 
-   */
+INLINE_DEVICES unsigned
+unimp_device_io_write_buffer(const device *me,
+                            const void *source,
+                            int address_space,
+                            unsigned_word addr,
+                            unsigned nr_bytes,
+                            cpu *processor,
+                            unsigned_word cia)
+{
+  error("device_io_write_buffer_callback for %s not implemented\n", me->name);
+  return 0;
+}
+
+INLINE_DEVICES unsigned
+unimp_device_dma_read_buffer(const device *me,
+                            void *target,
+                            int address_space,
+                            unsigned_word addr,
+                            unsigned nr_bytes)
+{
+  error("device_dma_read_buffer_callback for %s not implemented\n", me->name);
+  return 0;
+}
+
+INLINE_DEVICES unsigned
+unimp_device_dma_write_buffer(const device *me,
+                             const void *source,
+                             int address_space,
+                             unsigned_word addr,
+                             unsigned nr_bytes,
+                             int violate_read_only_section)
+{
+  error("device_dma_write_buffer_callback for %s not implemented\n", me->name);
+  return 0;
+}
+
+INLINE_DEVICES void
+unimp_device_attach_interrupt(const device *me,
+                             const device *who,
+                             int interrupt_line,
+                             const char *name)
+{
+  error("device_attach_interrupt_callback for %s not implemented\n", me->name);
+}
+
+INLINE_DEVICES void
+unimp_device_detach_interrupt(const device *me,
+                             const device *who,
+                             int interrupt_line,
+                             const char *name)
+{
+  error("device_detach_interrupt_callback for %s not implemented\n", me->name);
+}
+
+INLINE_DEVICES void
+unimp_device_interrupt(const device *me,
+                      const device *who,
+                      int interrupt_line,
+                      int interrupt_status,
+                      cpu *processor,
+                      unsigned_word cia)
+{
+  error("device_interrupt_callback for %s not implemented\n", me->name);
+}
+
+INLINE_DEVICES void
+unimp_device_interrupt_ack(const device *me,
+                          int interrupt_line,
+                          int interrupt_status)
+{
+  error("device_interrupt_ack_callback for %s not implemented\n", me->name);
+}
+
+INLINE_DEVICES void
+unimp_device_ioctl(const device *me,
+                  psim *system,
+                  cpu *processor,
+                  unsigned_word cia,
+                  ...)
+{
+  error("device_ioctl_callback for %s not implemented\n", me->name);
+}
+
+
+\f
+/* ignore/passthrough versions of each function */
+
+INLINE_DEVICES void
+ignore_device_init(const device *me,
+                  psim *system)
+{
+  /*null*/
+}
+
+INLINE_DEVICES void
+pass_device_attach_address(const device *me,
+                          const char *name,
+                          attach_type type,
+                          int address_space,
+                          unsigned_word addr,
+                          unsigned nr_bytes,
+                          access_type access,
+                          const device *who) /*callback/default*/
+{
+  me->parent->callback->attach_address(me->parent, name, type,
+                                      address_space, addr, nr_bytes,
+                                      access,
+                                      who);
+}
+
+INLINE_DEVICES void
+pass_device_detach_address(const device *me,
+                          const char *name,
+                          attach_type type,
+                          int address_space,
+                          unsigned_word addr,
+                          unsigned nr_bytes,
+                          access_type access,
+                          const device *who) /*callback/default*/
+{
+  me->parent->callback->detach_address(me->parent, name, type,
+                                      address_space, addr, nr_bytes, access,
+                                      who);
+}
+
+INLINE_DEVICES unsigned
+pass_device_dma_read_buffer(const device *me,
+                           void *target,
+                           int address_space,
+                           unsigned_word addr,
+                           unsigned nr_bytes)
+{
+  return me->parent->callback->dma_read_buffer(me->parent, target,
+                                              address_space, addr, nr_bytes);
+}
+
+INLINE_DEVICES unsigned
+pass_device_dma_write_buffer(const device *me,
+                            const void *source,
+                            int address_space,
+                            unsigned_word addr,
+                            unsigned nr_bytes,
+                            int violate_read_only_section)
+{
+  return me->parent->callback->dma_write_buffer(me->parent, source,
+                                               address_space, addr,
+                                               nr_bytes,
+                                               violate_read_only_section);
+}
+
+INLINE_DEVICES void
+pass_device_attach_interrupt(const device *me,
+                            const device *who,
+                            int interrupt_line,
+                            const char *name)
+{
+  me->parent->callback->attach_interrupt(me->parent, who,
+                                        interrupt_line, name);
+}
+
+INLINE_DEVICES void
+pass_device_detach_interrupt(const device *me,
+                            const device *who,
+                            int interrupt_line,
+                            const char *name)
+{
+  me->parent->callback->detach_interrupt(me->parent, who,
+                                        interrupt_line, name);
+}
+
+
+INLINE_DEVICES void
+pass_device_interrupt(const device *me,
+                     const device *who,
+                     int interrupt_line,
+                     int interrupt_status,
+                     cpu *processor,
+                     unsigned_word cia)
+{
+  me->parent->callback->interrupt(me->parent, who,
+                                 interrupt_line, interrupt_status,
+                                 processor, cia);
+}
+
+
+\f
+/* Simple console device: console@)x<address>,16
+
+   Input characters are taken from the keyboard, output characters
+   sent to the terminal.  Echoing of characters is not disabled.
+
+   The device has four registers:
+
+   0x0: read
+   0x4: read-status
+   0x8: write
+   0xC: write-status
+
+   Where a nonzero status register indicates that the device is ready
+   (input fifo contains a character or output fifo has space). */
 
 typedef struct _console_buffer {
   char buffer;
@@ -84,8 +324,6 @@ typedef struct _console_buffer {
 } console_buffer;
 
 typedef struct _console_device {
-  unsigned_word my_base_address;
-  int interrupt_delay;
   console_buffer input;
   console_buffer output;
 } console_device;
@@ -100,24 +338,28 @@ typedef enum {
 } console_offsets;
 
 
-STATIC_INLINE_DEVICES unsigned64
-console_read_callback(device_node *device,
-                     unsigned_word base,
-                     unsigned nr_bytes,
-                     cpu *processor,
-                     unsigned_word cia)
+STATIC_INLINE_DEVICES unsigned
+console_io_read_buffer_callback(const device *me,
+                               void *dest,
+                               int address_space,
+                               unsigned_word addr,
+                               unsigned nr_bytes,
+                               cpu *processor,
+                               unsigned_word cia)
 {
-  console_device *con = (console_device*)device->data;
+  console_device *console = (console_device*)me->data;
+  unsigned_1 val;
   TRACE(trace_console_device,
-       ("device=0x%x, base=0x%x, nr_bytes=%d\n",
-        device, base, nr_bytes));
+       ("device=0x%x, addr=0x%x, nr_bytes=%d\n",
+        me, addr, nr_bytes));
 
-  /* handle the request */
+  /* determine what was read */
 
-  switch (base & console_offset_mask) {
+  switch (addr) {
 
   case console_read_buffer:
-    return con->input.buffer;
+    val = console->input.buffer;
+    break;
 
   case console_read_status:
     { /* check for input */
@@ -127,124 +369,130 @@ console_read_callback(device_node *device,
       flags = fcntl(0, F_GETFL, 0);
       if (flags == -1) {
        perror("console");
-       return 0;
+       val = 0;
+       break;
       }
       /* temp, disable blocking IO */
       status = fcntl(0, F_SETFL, flags | O_NDELAY);
       if (status == -1) {
        perror("console");
-       return 0;
+       val = 0;
+       break;
       }
       /* try for input */
-      status = read(0, &con->input.buffer, 1);
+      status = read(0, &console->input.buffer, 1);
       if (status == 1) {
-       con->input.status = 1;
+       console->input.status = 1;
       }
       else {
-       con->input.status = 0;
+       console->input.status = 0;
       }
       /* return to regular vewing */
       fcntl(0, F_SETFL, flags);
     }
-    return con->input.status;
+    val = console->input.status;
+    break;
 
   case console_write_buffer:
-    return con->output.buffer;
+    val = console->output.buffer;
+    break;
 
   case console_write_status:
-    return con->output.status;
+    val = console->output.status;
+    break;
 
   default:
     error("console_read_callback() internal error\n");
-    return 0;
+    val = 0;
+    break;
 
   }
 
+  bzero(dest, nr_bytes);
+  *(unsigned_1*)dest = val;
+  return nr_bytes;
 }
 
-STATIC_INLINE_DEVICES void
-console_write_callback(device_node *device,
-                      unsigned_word base,
-                      unsigned nr_bytes,
-                      unsigned64 val,
-                      cpu *processor,
-                      unsigned_word cia)
+STATIC_INLINE_DEVICES unsigned
+console_io_write_buffer_callback(const device *me,
+                                const void *source,
+                                int address_space,
+                                unsigned_word addr,
+                                unsigned nr_bytes,
+                                cpu *processor,
+                                unsigned_word cia)
 {
-  console_device *con = (console_device*)device->data;
+  console_device *console = (console_device*)me->data;
+  unsigned_1 val = *(unsigned8*)source;
 
   TRACE(trace_console_device,
-       ("device=0x%x, base=0x%x, nr_bytes=%d, val=0x%x\n",
-        device, base, nr_bytes, val));
+       ("device=0x%x, addr=0x%x, nr_bytes=%d, val=%d\n",
+        me, addr, nr_bytes, val));
 
-  /* check for bus error */
-  if (base & 0x3) {
-    error("%s - misaligned base address, base=0x%x, nr_bytes=%d\n",
-         "console_write_callback", base, nr_bytes);
-  }
-
-  switch (base & console_offset_mask) {
-  case console_read_buffer: con->input.buffer = val; break;
-  case console_read_status: con->input.status = val; break;
+  switch (addr) {
+  case console_read_buffer:
+    console->input.buffer = val;
+    break;
+  case console_read_status:
+    console->input.status = val;
+    break;
   case console_write_buffer:
     TRACE(trace_console_device,
          ("<%c:%d>", val, val));
-    printf_filtered("%c", val);
-    con->output.buffer = val;
-    con->output.status = 1;
+    printf_filtered("%c",val) ;
+    console->output.buffer = val;
+    console->output.status = 1;
     break;
   case console_write_status:
-    con->output.status = val;
+    console->output.status = val;
     break;
+  default:
+    error("console_write_callback() internal error\n");
   }
-
+        
+  return nr_bytes;
 }
 
-static device_callbacks console_callbacks = {
-  console_read_callback,
-  console_write_callback,
+
+static device_callbacks const console_callbacks = {
+  generic_init_callback,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  console_io_read_buffer_callback,
+  console_io_write_buffer_callback,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
 };
 
-STATIC_INLINE_DEVICES device_node *
-console_create(device_node *parent,
-              char *name)
-{
-  device_node *device;
-  unsigned address_base;
-  unsigned address_flags;
 
+STATIC_INLINE_DEVICES const device *
+console_create(const char *name,
+              const device *parent)
+{
   /* create the descriptor */
   console_device *console = ZALLOC(console_device);
 
-  /* extract the two arguments */
-  parse_device_address(name, &address_base, &address_flags);
-
   /* fill in the details */
-  console->my_base_address = address_base;
-  console->interrupt_delay = address_flags;
   console->output.status = 1;
   console->output.buffer = '\0';
   console->input.status = 0;
   console->input.buffer = '\0';
 
   /* insert into the device tree along with its address info */
-  device = device_node_create(parent, name, sequential_device,
-                             &console_callbacks, console);
-  device_node_add_address(device,
-                         address_base,
-                         console_size,
-                         device_is_read_write_exec,
-                         NULL);
-
-  return device;
+  return device_create_from(name,
+                           console, /* data */
+                           &console_callbacks,
+                           parent);
 }
 
-static device_descriptor console_descriptor = {
-  "console",
-  console_create,
-};
-
 
-/* ICU device:
+\f
+/* ICU device: icu@0x<address>,4
 
    Single 4 byte register.  Read returns processor number.  Write
    interrupts specified processor.
@@ -256,55 +504,513 @@ static device_descriptor console_descriptor = {
    device doesn't pass interrupt events to its parent.  Instead it
    passes them back to its self. */
 
-STATIC_INLINE_DEVICES unsigned64
-icu_read_callback(device_node *device,
-                 unsigned_word base,
-                 unsigned nr_bytes,
-                 cpu *processor,
-                 unsigned_word cia)
+STATIC_INLINE_DEVICES unsigned
+icu_io_read_buffer_callback(const device *me,
+                           void *dest,
+                           int address_space,
+                           unsigned_word base,
+                           unsigned nr_bytes,
+                           cpu *processor,
+                           unsigned_word cia)
 {
+  unsigned_1 val;
   TRACE(trace_icu_device,
        ("device=0x%x, base=0x%x, nr_bytes=%d\n",
-        device, base, nr_bytes));
-  return cpu_nr(processor);
+        me, base, nr_bytes));
+  val = cpu_nr(processor);
+  bzero(dest, nr_bytes);
+  *(unsigned_1*)dest = val;
+  return nr_bytes;
 }
 
-STATIC_INLINE_DEVICES void
-icu_write_callback(device_node *device,
-                  unsigned_word base,
-                  unsigned nr_bytes,
-                  unsigned64 val,
-                  cpu *processor,
-                  unsigned_word cia)
+
+STATIC_INLINE_DEVICES unsigned
+icu_io_write_buffer_callback(const device *me,
+                            const void *source,
+                            int address_space,
+                            unsigned_word base,
+                            unsigned nr_bytes,
+                            cpu *processor,
+                            unsigned_word cia)
 {
   psim *system = cpu_system(processor);
-  device_node *parent = device; /* NB: normally would be device->parent */
+  unsigned_1 val = H2T_1(*(unsigned_1*)source);
   TRACE(trace_icu_device,
        ("device=0x%x, base=0x%x, nr_bytes=%d, val=0x%x\n",
-        device, base, nr_bytes, val));
+        me, base, nr_bytes, val));
   /* tell the parent device that the interrupt lines have changed.
      For this fake ICU.  The interrupt lines just indicate the cpu to
      interrupt next */
-  parent->callbacks->interrupt_callback(parent, val, device, processor, cia);
+  me->parent->callback->interrupt(me->parent, me,
+                                 val, val,
+                                 processor, cia);
+  return nr_bytes;
 }
 
+
+static device_callbacks const icu_callbacks = {
+  generic_init_callback,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  icu_io_read_buffer_callback,
+  icu_io_write_buffer_callback,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
+};
+
+
+\f
+/* HALT device: halt@0x<address>,4
+
+   With real hardware, the processor operation is normally terminated
+   through a reset.  This device illustrates how a reset device could
+   be attached to an address */
+
+
+STATIC_INLINE_DEVICES unsigned
+halt_io_read_buffer_callback(const device *me,
+                            void *dest,
+                            int address_space,
+                            unsigned_word base,
+                            unsigned nr_bytes,
+                            cpu *processor,
+                            unsigned_word cia)
+{
+  cpu_halt(processor, cia, was_exited, 0);
+  return 0;
+}
+
+
+STATIC_INLINE_DEVICES unsigned
+halt_io_write_buffer_callback(const device *me,
+                             const void *source,
+                             int address_space,
+                             unsigned_word addr,
+                             unsigned nr_bytes,
+                             cpu *processor,
+                             unsigned_word cia)
+{
+  cpu_halt(processor, cia, was_exited, 0);
+  return 0;
+}
+
+
+static device_callbacks const halt_callbacks = {
+  generic_init_callback,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  halt_io_read_buffer_callback,
+  halt_io_write_buffer_callback,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
+};
+
+
+\f
+/* Register init device: register@<name>,0x<value>[,<processor>]
+
+   This strange device is used to initialize the processors registers
+   as part of the initialization. */
+
+STATIC_INLINE_DEVICES void
+register_init_callback(const device *me,
+                      psim *system)
+{
+  char name[100];
+  unsigned_word value;
+  unsigned which_cpu;
+  int status;
+  status = scand_c_uw_u(me->name, name, &value, &which_cpu);
+  switch (status) {
+  case 2: /* register@<name>,<value> */
+    psim_write_register(system, -1, &value, name, cooked_transfer);
+    break;
+  case 3: /* register@<name>,<value>,<processor> */
+    psim_write_register(system, which_cpu, &value, name, cooked_transfer);
+    break;
+  default:
+    error("register_init_callback() invalid register init %s\n", me->name);
+    break;
+  }
+}
+
+
+static device_callbacks const register_callbacks = {
+  register_init_callback,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  unimp_device_io_read_buffer,
+  unimp_device_io_write_buffer,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
+};
+
+
+\f
+/* VEA VM device: vm@0x<stack-base>,<nr_bytes>
+
+   A VEA mode device. This sets its self up as the default memory
+   device capturing all accesses (reads/writes) to currently unmapped
+   addresses.  If the unmaped access falls within unallocated stack or
+   heap address ranges then memory is allocated and the access is
+   allowed to continue.
+
+   During init phase, this device expects to receive `attach' requests
+   from its children for the text/data/bss memory areas.  Typically,
+   this would be done by the binary device.
+
+   STACK: The location of the stack in memory is specified as part of
+   the devices name.  Unmaped accesses that fall within the stack
+   space result in the allocated stack being grown downwards so that
+   it includes the page of the culprit access.
+
+   HEAP: During initialization, the vm device monitors all `attach'
+   operations from its children using this to determine the initial
+   location of the heap.  The heap is then extended by system calls
+   that frob the heap upper bound variable (see system.c). */
+
+
+typedef struct _vm_device {
+  /* area of memory valid for stack addresses */
+  unsigned_word stack_base; /* min possible stack value */
+  unsigned_word stack_bound;
+  unsigned_word stack_lower_limit;
+  /* area of memory valid for heap addresses */
+  unsigned_word heap_base;
+  unsigned_word heap_bound;
+  unsigned_word heap_upper_limit;
+} vm_device;
+
+
 STATIC_INLINE_DEVICES void
-icu_do_interrupt(event_queue *queue,
-                void *data)
+vm_init_callback(const device *me,
+                psim *system)
+{
+  vm_device *vm = (vm_device*)me->data;
+
+  /* revert the stack/heap variables to their defaults */
+  vm->stack_lower_limit = vm->stack_bound;
+  vm->heap_base = 0;
+  vm->heap_bound = 0;
+  vm->heap_upper_limit = 0;
+
+  /* establish this device as the default memory handler */
+  me->parent->callback->attach_address(me->parent,
+                                      me->name,
+                                      attach_default,
+                                      0 /*address space - ignore*/,
+                                      0 /*addr - ignore*/,
+                                      0 /*nr_bytes - ignore*/,
+                                      access_read_write /*access*/,
+                                      me);
+}
+
+
+STATIC_INLINE_DEVICES void
+vm_attach_address(const device *me,
+                 const char *name,
+                 attach_type type,
+                 int address_space,
+                 unsigned_word addr,
+                 unsigned nr_bytes,
+                 access_type access,
+                 const device *who) /*callback/default*/
+{
+  vm_device *vm = (vm_device*)me->data;
+  /* update end of bss if necessary */
+  if (vm->heap_base < addr + nr_bytes) {
+    vm->heap_base = addr + nr_bytes;
+    vm->heap_bound = addr + nr_bytes;
+    vm->heap_upper_limit = addr + nr_bytes;
+  }
+  me->parent->callback->attach_address(me->parent,
+                                      "vm@0x0,0", /* stop remap */
+                                      attach_raw_memory,
+                                      0 /*address space*/,
+                                      addr,
+                                      nr_bytes,
+                                      access,
+                                      me);
+}
+
+
+STATIC_INLINE_DEVICES unsigned
+add_vm_space(const device *me,
+            unsigned_word addr,
+            unsigned nr_bytes,
+            cpu *processor,
+            unsigned_word cia)
+{
+  vm_device *vm = (vm_device*)me->data;
+  unsigned_word block_addr;
+  unsigned block_nr_bytes;
+
+  /* an address in the stack area, allocate just down to the addressed
+     page */
+  if (addr >= vm->stack_base && addr < vm->stack_lower_limit) {
+    block_addr = FLOOR_PAGE(addr);
+    block_nr_bytes = vm->stack_lower_limit - block_addr;
+    vm->stack_lower_limit = block_addr;
+  }
+  /* an address in the heap area, allocate all of the required heap */
+  else if (addr >= vm->heap_upper_limit && addr < vm->heap_bound) {
+    block_addr = vm->heap_upper_limit;
+    block_nr_bytes = vm->heap_bound - vm->heap_upper_limit;
+    vm->heap_upper_limit = vm->heap_bound;
+  }
+  /* oops - an invalid address - abort the cpu */
+  else if (processor != NULL) {
+    cpu_halt(processor, cia, was_signalled, SIGSEGV);
+    return 0;
+  }
+  /* 2*oops - an invalid address and no processor */
+  else {
+    return 0;
+  }
+
+  /* got the parameters, allocate the space */
+  me->parent->callback->attach_address(me->parent,
+                                      "vm@0x0,0", /* stop remap */
+                                      attach_raw_memory,
+                                      0 /*address space*/,
+                                      block_addr,
+                                      block_nr_bytes,
+                                      access_read_write,
+                                      me);
+  return block_nr_bytes;
+}
+
+
+STATIC_INLINE_DEVICES unsigned
+vm_io_read_buffer_callback(const device *me,
+                          void *dest,
+                          int address_space,
+                          unsigned_word addr,
+                          unsigned nr_bytes,
+                          cpu *processor,
+                          unsigned_word cia)
+{
+  if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
+    bzero(dest, nr_bytes); /* always initialized to zero */
+    return nr_bytes;
+  }
+  else 
+    return 0;
+}
+
+
+STATIC_INLINE_DEVICES unsigned
+vm_io_write_buffer_callback(const device *me,
+                           const void *source,
+                           int address_space,
+                           unsigned_word addr,
+                           unsigned nr_bytes,
+                           cpu *processor,
+                           unsigned_word cia)
+{
+  if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
+    return me->parent->callback->dma_write_buffer(me->parent, source,
+                                                 address_space, addr,
+                                                 nr_bytes,
+                                                 0/*violate_read_only*/);
+  }
+  else
+    return 0;
+}
+
+
+STATIC_INLINE_DEVICES void
+vm_ioctl_callback(const device *me,
+                 psim *system,
+                 cpu *processor,
+                 unsigned_word cia,
+                 ...)
+{
+  /* While the caller is notified that the heap has grown by the
+     requested amount, the heap is infact extended out to a page
+     boundary. */
+  vm_device *vm = (vm_device*)me->data;
+  unsigned_word new_break = ALIGN_8(cpu_registers(processor)->gpr[3]);
+  unsigned_word old_break = vm->heap_bound;
+  signed_word delta = new_break - old_break;
+  if (delta > 0)
+    vm->heap_bound = ALIGN_PAGE(new_break);
+  cpu_registers(processor)->gpr[0] = 0;
+  cpu_registers(processor)->gpr[3] = new_break;
+}
+
+
+static device_callbacks const vm_callbacks = {
+  vm_init_callback,
+  vm_attach_address,
+  pass_device_detach_address,
+  vm_io_read_buffer_callback,
+  vm_io_write_buffer_callback,
+  unimp_device_dma_read_buffer,
+  pass_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  vm_ioctl_callback,
+};
+
+
+STATIC_INLINE_DEVICES const device *
+vea_vm_create(const char *name,
+            const device *parent)
+{
+  vm_device *vm = ZALLOC(vm_device);
+  unsigned_word addr;
+  unsigned nr_bytes;
+
+  /* extract out the stack parameters */
+  if (scand_uw_u(name, &addr, &nr_bytes) != 2)
+    error("vm_device_create() invalid vm device %s\n", name);
+  vm->stack_base = addr;
+  vm->stack_bound = addr + nr_bytes;
+
+  /* insert in the tree including the buffer */
+  return device_create_from(name,
+                           vm, /* data */
+                           &vm_callbacks,
+                           parent);
+}
+
+
+\f
+/* Memory init device: memory@0x<addr>,<size>,<access>
+
+   This strange device is used create sections of memory */
+
+STATIC_INLINE_DEVICES void
+memory_init_callback(const device *me,
+                    psim *system)
+{
+  unsigned_word addr;
+  unsigned nr_bytes;
+  unsigned access;
+
+  if (scand_uw_u_u(me->name, &addr, &nr_bytes, &access) != 3)
+    error("memory_init_callback() invalid memory device %s\n", me->name);
+
+  me->parent->callback->attach_address(me->parent,
+                                      me->name,
+                                      attach_raw_memory,
+                                      0 /*address space*/,
+                                      addr,
+                                      nr_bytes,
+                                      (access_type)access,
+                                      me);
+}
+
+
+static device_callbacks const memory_callbacks = {
+  memory_init_callback,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  unimp_device_io_read_buffer,
+  unimp_device_io_write_buffer,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
+};
+
+
+STATIC_INLINE_DEVICES const device *
+memory_create(const char *name,
+             const device *parent)
+{
+  void *buffer;
+  unsigned_word addr;
+  unsigned nr_bytes;
+  if (scand_uw_u(name, &addr, &nr_bytes) != 2)
+    error("memory_create() invalid memory device %s\n");
+
+  /* insert in the tree including the buffer */
+  return device_create_from(name,
+                           buffer, /* data */
+                           &memory_callbacks,
+                           parent);
+}
+
+
+\f
+/* IOBUS device: iobus@<address>
+
+   Simple bus on which some IO devices live */
+
+STATIC_INLINE_DEVICES void
+iobus_attach_address_callback(const device *me,
+                             const char *name,
+                             attach_type type,
+                             int address_space,
+                             unsigned_word addr,
+                             unsigned nr_bytes,
+                             access_type access,
+                             const device *who) /*callback/default*/
+{
+  unsigned_word iobus_addr;
+  /* sanity check */
+  if (type == attach_default)
+    error("iobus_attach_address_callback() no default for %s/%s\n",
+         me->name, name);
+  if (address_space != 0)
+    error("iobus_attach_address_callback() no address_space for %s/%s\n",
+         me->name, name);
+  /* get the bus address */
+  if (scand_uw(me->name, &iobus_addr) != 1)
+    error("iobus_attach_address_callback() invalid address for %s\n",
+         me->name);
+  me->parent->callback->attach_address(me->parent,
+                                      me->name,
+                                      type,
+                                      0 /*address_space*/,
+                                      iobus_addr + addr,
+                                      nr_bytes,
+                                      access,
+                                      who);
+}
+
+
+STATIC_INLINE_DEVICES void
+iobus_do_interrupt(event_queue *queue,
+                  void *data)
 {
   cpu *target = (cpu*)data;
   /* try to interrupt the processor.  If the attempt fails, try again
      on the next tick */
   if (!external_interrupt(target))
-    event_queue_schedule(queue, 1, icu_do_interrupt, target);
+    event_queue_schedule(queue, 1, iobus_do_interrupt, target);
 }
 
+
 STATIC_INLINE_DEVICES void
-icu_interrupt_callback(device_node *me,
-                      int interrupt_status,
-                      device_node *device,
-                      cpu *processor,
-                      unsigned_word cia)
+iobus_interrupt_callback(const device *me,
+                        const device *who,
+                        int interrupt_line,
+                        int interrupt_status,
+                        cpu *processor,
+                        unsigned_word cia)
 {
   /* the interrupt controler can't interrupt a cpu at any time.
      Rather it must synchronize with the system clock before
@@ -313,130 +1019,605 @@ icu_interrupt_callback(device_node *me,
   cpu *target = psim_cpu(system, interrupt_status);
   if (target != NULL) {
     event_queue *events = cpu_event_queue(target);
-    event_queue_schedule(events, 1, icu_do_interrupt, target);
+    event_queue_schedule(events, 1, iobus_do_interrupt, target);
   }
 }
 
-static device_callbacks icu_callbacks = {
-  icu_read_callback,
-  icu_write_callback,
-  icu_interrupt_callback,
+
+static device_callbacks const iobus_callbacks = {
+  ignore_device_init,
+  iobus_attach_address_callback,
+  unimp_device_detach_address,
+  unimp_device_io_read_buffer,
+  unimp_device_io_write_buffer,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  iobus_interrupt_callback,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
 };
 
-STATIC_INLINE_DEVICES device_node *
-icu_create(device_node *parent,
-              char *name)
+
+\f
+/* FILE device: file@0x<address>,<file-name>
+   (later - file@0x<address>,<size>,<file-offset>,<file-name>)
+
+   Specifies a file to read directly into memory starting at <address> */
+
+
+STATIC_INLINE_DEVICES void
+file_init_callback(const device *me,
+                  psim *system)
 {
-  device_node *device;
-  unsigned address_base;
-  unsigned address_flags;
+  unsigned_word addr;
+  char *file_name;
+  char buf;
+  FILE *image;
+
+  if ((file_name = strchr(me->name, ',')) == NULL
+      || scand_uw(me->name, &addr) != 1)
+    error("file_init_callback() invalid file device %s\n", me->name);
+
+  /* open the file to load */
+  file_name++; /* skip the `,' */
+  image = fopen(file_name, "r");
+  if (image == NULL)
+    error("file_init_callback() file open failed for %s\n", me->name);
+
+  /* read it in slowly */
+  while (fread(&buf, 1, 1, image) > 0) {
+    me->parent->callback->dma_write_buffer(me->parent,
+                                          &buf,
+                                          0 /*address-space*/,
+                                          addr,
+                                          1 /*nr-bytes*/,
+                                          1 /*violate ro*/);
+    addr++;
+  }
 
-  /* extract the two arguments */
-  parse_device_address(name, &address_base, &address_flags);
+  /* close down again */
+  fclose(image);
+}
 
-  /* insert into the device tree along with its address info */
-  device = device_node_create(parent, name, sequential_device,
-                             &icu_callbacks, 0);
-  device_node_add_address(device,
-                         address_base,
-                         4,
-                         device_is_read_write_exec,
-                         NULL);
 
-  return device;
+static device_callbacks const file_callbacks = {
+  file_init_callback,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  unimp_device_io_read_buffer,
+  unimp_device_io_write_buffer,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
+};
+
+
+\f
+/* HTAB: htab@0x<address>,<nr_bytes>
+   PTE: pte@0x<effective-address>,0x<real-address>,<nr_bytes>
+
+   HTAB defines the location (in physical memory) of a HASH table.
+   PTE (as a child of HTAB) defines a mapping that is to be entered
+   into that table.
+
+   NB: All the work in this device is done during init by the PTE.
+   The pte, looks up its parent to determine the address of the HTAB
+   and then uses DMA calls to establish the required mapping. */
+
+
+STATIC_INLINE_DEVICES void
+htab_init_callback(const device *me,
+                  psim *system)
+{
+  /* only the pte does work */
+  if (strncmp(me->name, "pte@", strlen("pte@")) == 0) {
+    unsigned_word htab_ra;
+    unsigned htab_nr_bytes;
+    unsigned_word pte_ea;
+    unsigned_word pte_ra;
+    unsigned pte_nr_bytes;
+    /* determine the location/size of the hash table */
+    if (scand_uw_u(me->parent->name, &htab_ra, &htab_nr_bytes) != 2)
+      error("htab_init_callback() htab entry %s invalid\n",
+           me->parent->name);
+    /* determine the location/size of the mapping */
+    if (scand_uw_uw_u(me->name, &pte_ea, &pte_ra, &pte_nr_bytes) != 3)
+      error("htab_init_callback() pte entry %s invalid\n", me->name);
+    error("Map ea=0x%x, ra=0x%x, nr_bytes=%d using htab=0x%x, nr_bytes=%d\n",
+         pte_ea, pte_ra, pte_nr_bytes, htab_ra, htab_nr_bytes);
+  }
 }
 
-static device_descriptor icu_descriptor = {
-  "icu",
-  icu_create,
+
+static device_callbacks const htab_callbacks = {
+  htab_init_callback,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  unimp_device_io_read_buffer,
+  unimp_device_io_write_buffer,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
 };
 
 
+\f
+/* Simulator device: sim@0x<address>,<nr_bytes>
+
+   Eventually gives access to the hardware configuration.  For
+   instance, it could allow the setting (on the fly) of variables such
+   as hardware floating-point or strict-alignment.
+
+   It's intended use is as part of testing the simulators
+   functionality */
+
+static device_callbacks const sim_callbacks = {
+  ignore_device_init,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  unimp_device_io_read_buffer,
+  unimp_device_io_write_buffer,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
+};
 
 
+\f
+/* Load device: *binary@<file-name>
 
-/* HALT device:
+   Assuming that <file-name> is an executable file understood by BFD,
+   this device loads or maps the relevant text/data segments into
+   memory using dma. */
 
-   With real hardware, the processor operation is normally terminated
-   through a reset.  This device illustrates how a reset device could
-   be attached to an address */
+/* create a device tree from the image */
 
-STATIC_INLINE_DEVICES unsigned64
-halt_read_callback(device_node *device,
-                  unsigned_word base,
-                  unsigned nr_bytes,
-                  cpu *processor,
-                  unsigned_word cia)
+STATIC_INLINE_DEVICES void
+update_device_tree_for_section(bfd *abfd,
+                              asection *the_section,
+                              PTR obj)
 {
-  cpu_halt(processor, cia, was_exited, 0);
-  return 0;
+  unsigned_word section_vma;
+  unsigned_word section_size;
+  access_type access;
+  device *me = (device*)obj;
+
+  /* skip the section if no memory to allocate */
+  if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
+    return;
+
+  /* check/ignore any sections of size zero */
+  section_size = bfd_get_section_size_before_reloc(the_section);
+  if (section_size == 0)
+    return;
+
+  /* find where it is to go */
+  section_vma = bfd_get_section_vma(abfd, the_section);
+
+  TRACE(trace_device_tree,
+       ("name=%-7s, vma=0x%.8x, size=%6d, flags=%3x(%s%s%s%s )\n",
+        bfd_get_section_name(abfd, the_section),
+        section_vma, section_size,
+        bfd_get_section_flags(abfd, the_section),
+        bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
+        bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
+        bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
+        bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
+        bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
+       ));
+
+  /* determine the devices access */
+  access = access_read;
+  if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
+    access |= access_exec;
+  if (!(bfd_get_section_flags(abfd, the_section) & SEC_READONLY))
+    access |= access_write;
+
+  /* if a map, pass up a request to create the memory in core */
+  if (strncmp(me->name, "map-binary@", strlen("map-binary@")) == 0)
+    me->parent->callback->attach_address(me->parent,
+                                        me->name,
+                                        attach_raw_memory,
+                                        0 /*address space*/,
+                                        section_vma,
+                                        section_size,
+                                        access,
+                                        me);
+
+  /* if a load dma in the required data */
+  if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
+    void *section_init = zalloc(section_size);
+    if (!bfd_get_section_contents(abfd,
+                                 the_section,
+                                 section_init, 0,
+                                 section_size)) {
+      bfd_perror("core:load_section()");
+      error("load of data failed");
+      return;
+    }
+    if (me->parent->callback->dma_write_buffer(me->parent,
+                                              section_init,
+                                              0 /*address_space*/,
+                                              section_vma,
+                                              section_size,
+                                              1 /*violate_read_only*/)
+       != section_size)
+      error("data_init_callback() broken transfer for %s\n", me->name);
+    zfree(section_init); /* only free if load */
+  }
 }
 
+
 STATIC_INLINE_DEVICES void
-halt_write_callback(device_node *device,
-                   unsigned_word base,
-                   unsigned nr_bytes,
-                   unsigned64 val,
-                   cpu *processor,
-                   unsigned_word cia)
+binary_init_callback(const device *me,
+                    psim *system)
 {
-  cpu_halt(processor, cia, was_exited, 0);
+  char file_name[100];
+  bfd *image;
+
+  /* get a file name */
+  if (scand_c(me->name, file_name) != 1)
+    error("load_binary_init_callback() invalid load-binary device %s\n",
+         me->name);
+
+  /* open the file */
+  image = bfd_openr(file_name, NULL);
+  if (image == NULL) {
+    bfd_perror("open failed:");
+    error("nothing loaded\n");
+  }
+
+  /* check it is valid */
+  if (!bfd_check_format(image, bfd_object)) {
+    printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
+    printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
+    bfd_close(image);
+    image = NULL;
+  }
+
+  /* and the data sections */
+  bfd_map_over_sections(image,
+                       update_device_tree_for_section,
+                       (PTR)me);
+
+  bfd_close(image);
 }
 
 
-static device_callbacks halt_callbacks = {
-  halt_read_callback,
-  halt_write_callback,
+static device_callbacks const binary_callbacks = {
+  binary_init_callback,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  unimp_device_io_read_buffer,
+  unimp_device_io_write_buffer,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  unimp_device_ioctl,
 };
 
-STATIC_INLINE_DEVICES device_node *
-halt_create(device_node *parent,
-           char *name)
+
+\f
+/* Stack device: stack@<type>
+
+   Has a single IOCTL to create a stack frame of the specified type.
+   If <type> is elf or xcoff then a corresponding stack is created.
+   Any other value of type is ignored.
+
+   The IOCTL takes the additional arguments:
+
+     unsigned_word stack_end -- where the stack should come down from
+     char **argv -- ...
+     char **envp -- ...
+
+   */
+
+STATIC_INLINE_DEVICES int
+sizeof_argument_strings(char **arg)
+{
+  int sizeof_strings = 0;
+
+  /* robust */
+  if (arg == NULL)
+    return 0;
+
+  /* add up all the string sizes (padding as we go) */
+  for (; *arg != NULL; arg++) {
+    int len = strlen(*arg) + 1;
+    sizeof_strings += ALIGN_8(len);
+  }
+
+  return sizeof_strings;
+}
+
+STATIC_INLINE_DEVICES int
+number_of_arguments(char **arg)
+{
+  int nr;
+  if (arg == NULL)
+    return 0;
+  for (nr = 0; *arg != NULL; arg++, nr++);
+  return nr;
+}
+
+STATIC_INLINE_DEVICES int
+sizeof_arguments(char **arg)
+{
+  return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
+}
+
+STATIC_INLINE_DEVICES void
+write_stack_arguments(psim *system,
+                     char **arg,
+                     unsigned_word start_block,
+                     unsigned_word end_block,
+                     unsigned_word start_arg,
+                     unsigned_word end_arg)
+{
+  TRACE(trace_create_stack,
+       ("write_stack_arguments() - %s=0x%x %s=0x%x %s=0x%x %s=0x%x\n",
+        "system", system, "arg", arg,
+        "start_block", start_block, "start_arg", start_arg));
+  if (arg == NULL)
+    error("write_arguments: character array NULL\n");
+  /* only copy in arguments, memory is already zero */
+  for (; *arg != NULL; arg++) {
+    int len = strlen(*arg)+1;
+    unsigned_word target_start_block;
+    TRACE(trace_create_stack,
+         ("write_stack_arguments - write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n",
+          "**arg", *arg, "start_block", start_block,
+          "len", len, "start_arg", start_arg));
+    if (psim_write_memory(system, 0, *arg,
+                         start_block, len,
+                         0/*violate_readonly*/) != len)
+      error("write_stack_arguments() - write of **arg (%s) at 0x%x failed\n",
+           *arg, start_block);
+    target_start_block = H2T_word(start_block);
+    if (psim_write_memory(system, 0, &target_start_block,
+                         start_arg, sizeof(target_start_block),
+                         0) != sizeof(target_start_block))
+      error("write_stack_arguments() - write of *arg failed\n");
+    start_block += ALIGN_8(len);
+    start_arg += sizeof(start_block);
+  }
+  start_arg += sizeof(start_block); /*the null at the end*/
+  if (start_block != end_block
+      || ALIGN_8(start_arg) != end_arg)
+    error("write_stack_arguments - possible corruption\n");
+}
+
+STATIC_INLINE_DEVICES void
+create_elf_stack_frame(psim *system,
+                      unsigned_word bottom_of_stack,
+                      char **argv,
+                      char **envp)
+{
+  /* fixme - this is over aligned */
+
+  /* information block */
+  const unsigned sizeof_envp_block = sizeof_argument_strings(envp);
+  const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block;
+  const unsigned sizeof_argv_block = sizeof_argument_strings(argv);
+  const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block;
+
+  /* auxiliary vector - contains only one entry */
+  const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */
+  const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry);
+
+  /* environment points (including null sentinal) */
+  const unsigned sizeof_envp = sizeof_arguments(envp);
+  const unsigned_word start_envp = start_aux - sizeof_envp;
+
+  /* argument pointers (including null sentinal) */
+  const int argc = number_of_arguments(argv);
+  const unsigned sizeof_argv = sizeof_arguments(argv);
+  const unsigned_word start_argv = start_envp - sizeof_argv;
+
+  /* link register save address - alligned to a 16byte boundary */
+  const unsigned_word top_of_stack = ((start_argv
+                                      - 2 * sizeof(unsigned_word))
+                                     & ~0xf);
+
+  /* install arguments on stack */
+  write_stack_arguments(system, envp,
+                       start_envp_block, bottom_of_stack,
+                       start_envp, start_aux);
+  write_stack_arguments(system, argv,
+                       start_argv_block, start_envp_block,
+                       start_argv, start_envp);
+
+  /* set up the registers */
+  psim_write_register(system, -1,
+                     &top_of_stack, "sp", cooked_transfer);
+  psim_write_register(system, -1,
+                     &argc, "r3", cooked_transfer);
+  psim_write_register(system, -1,
+                     &start_argv, "r4", cooked_transfer);
+  psim_write_register(system, -1,
+                     &start_envp, "r5", cooked_transfer);
+  psim_write_register(system, -1,
+                     &start_aux, "r6", cooked_transfer);
+}
+
+STATIC_INLINE_DEVICES void
+create_aix_stack_frame(psim *system,
+                      unsigned_word bottom_of_stack,
+                      char **argv,
+                      char **envp)
 {
-  device_node *device;
-  unsigned address_base;
-  unsigned address_flags;
+  unsigned_word core_envp;
+  unsigned_word core_argv;
+  unsigned_word core_argc;
+  unsigned_word core_aux;
+  unsigned_word top_of_stack;
+
+  /* cheat - create an elf stack frame */
+  create_elf_stack_frame(system, bottom_of_stack, argv, envp);
+  
+  /* extract argument addresses from registers */
+  psim_read_register(system, 0, &top_of_stack, "r1", cooked_transfer);
+  psim_read_register(system, 0, &core_argc, "r3", cooked_transfer);
+  psim_read_register(system, 0, &core_argv, "r4", cooked_transfer);
+  psim_read_register(system, 0, &core_envp, "r5", cooked_transfer);
+  psim_read_register(system, 0, &core_aux, "r6", cooked_transfer);
+
+  /* extract arguments from registers */
+  error("create_aix_stack_frame() - what happens next?\n");
+}
+
+
 
-  parse_device_address(name, &address_base, &address_flags);
-  device = device_node_create(parent, name, other_device,
-                             &halt_callbacks, NULL);
-  device_node_add_address(device,
-                         address_base,
-                         4,
-                         device_is_read_write_exec,
-                         NULL);
-  return device;
+STATIC_INLINE_DEVICES void
+stack_ioctl_callback(const device *me,
+                    psim *system,
+                    cpu *processor,
+                    unsigned_word cia,
+                    ...)
+{
+  va_list ap;
+  unsigned_word stack_pointer;
+  char **argv;
+  char **envp;
+  va_start(ap, cia);
+  stack_pointer = va_arg(ap, unsigned_word);
+  argv = va_arg(ap, char **);
+  envp = va_arg(ap, char **);
+  if (strcmp(me->name, "stack@elf") == 0)
+    create_elf_stack_frame(system, stack_pointer, argv, envp);
+  else if (strcmp(me->name, "stack@xcoff") == 0)
+    create_aix_stack_frame(system, stack_pointer, argv, envp);
 }
 
-static device_descriptor halt_descriptor = {
-  "halt",
-  halt_create,
+
+static device_callbacks const stack_callbacks = {
+  ignore_device_init,
+  unimp_device_attach_address,
+  unimp_device_detach_address,
+  unimp_device_io_read_buffer,
+  unimp_device_io_write_buffer,
+  unimp_device_dma_read_buffer,
+  unimp_device_dma_write_buffer,
+  unimp_device_attach_interrupt,
+  unimp_device_detach_interrupt,
+  unimp_device_interrupt,
+  unimp_device_interrupt_ack,
+  stack_ioctl_callback,
 };
 
 
-static device_descriptor *devices[] = {
-  &console_descriptor,
-  &halt_descriptor,
-  &icu_descriptor,
-  NULL,
+\f
+/* Table of all the devices and a function to lookup/create a device
+   from its name */
+
+typedef const device *(device_creator)
+     (const char *name,
+      const device *parent);
+
+typedef struct _device_descriptor device_descriptor;
+struct _device_descriptor {
+  const char *name;
+  device_creator *creator;
+  const device_callbacks *callbacks;
+};
+
+static device_descriptor devices[] = {
+  { "console", console_create, NULL },
+  { "memory", memory_create, NULL },
+  { "vm", vea_vm_create, NULL },
+  { "halt", NULL, &halt_callbacks },
+  { "icu", NULL, &icu_callbacks },
+  { "register", NULL, &register_callbacks },
+  { "iobus", NULL, &iobus_callbacks },
+  { "file", NULL, &file_callbacks },
+  { "htab", NULL, &htab_callbacks },
+  { "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
+  { "stack", NULL, &stack_callbacks },
+  { "sim", NULL, &sim_callbacks },
+  { "load-binary", NULL, &binary_callbacks },
+  { "map-binary", NULL, &binary_callbacks },
+  { NULL },
 };
 
 
-INLINE_DEVICES device_descriptor *
-find_device_descriptor(char *name)
+INLINE_DEVICES const device *
+device_create(const char *name,
+             const device *parent)
 {
-  device_descriptor **device;
+  device_descriptor *device;
   int name_len;
   char *chp;
   chp = strchr(name, '@');
   name_len = (chp == NULL ? strlen(name) : chp - name);
-  for (device = devices; *device != NULL; device++) {
-    if (strncmp(name, (*device)->name, name_len) == 0
-       && ((*device)->name[name_len] == '\0'
-           || (*device)->name[name_len] == '@'))
-      return *device;
+  for (device = devices; device->name != NULL; device++) {
+    if (strncmp(name, device->name, name_len) == 0
+       && (device->name[name_len] == '\0'
+           || device->name[name_len] == '@'))
+      if (device->creator != NULL)
+       return device->creator(name, parent);
+      else
+       return device_create_from(name,
+                                 NULL /* data */,
+                                 device->callbacks,
+                                 parent);
   }
+  error("device_create() unknown device %s\n", name);
   return NULL;
 }
 
+
+INLINE_DEVICES const device *
+device_create_from(const char *name,
+                  void *data,
+                  const device_callbacks *callback,
+                  const device *parent)
+{
+  device *me = ZALLOC(device);
+  me->name = strdup(name);
+  me->data = data;
+  me->callback = callback;
+  me->parent = parent;
+  return me;
+}
+
+
+INLINE_DEVICES const device_callbacks *
+passthrough_device_callbacks(void)
+{
+  static const device_callbacks callbacks = {
+    ignore_device_init,
+    pass_device_attach_address,
+    pass_device_detach_address,
+    unimp_device_io_read_buffer,
+    unimp_device_io_write_buffer,
+    pass_device_dma_read_buffer,
+    pass_device_dma_write_buffer,
+    pass_device_attach_interrupt,
+    pass_device_detach_interrupt,
+    pass_device_interrupt,
+    unimp_device_interrupt_ack,
+    unimp_device_ioctl,
+  };
+  return &callbacks;
+}
+
+
+
 #endif /* _DEVICES_C_ */
index e115779bda19815e9a7e5b30b2c87a365839c4cb..681992e1269f94d40f459f3761461356ef78c0ef 100644 (file)
 #define INLINE_DEVICES
 #endif
 
-#include "device_tree.h"
 
-/* table of all the configured devices */
+/* forward declaration of types */
+/* typedef struct _device device; -- in devices.h */
 
-typedef struct _device_descriptor device_descriptor;
-struct _device_descriptor {
-  char *name;
-  device_creator *creator;
+
+/* Address access attributes that can be attached to a devices address
+   range */
+typedef enum _access_type {
+  access_invalid = 0,
+  access_read = 1,
+  access_write = 2,
+  access_read_write = 3,
+  access_exec = 4,
+  access_read_exec = 5,
+  access_write_exec = 6,
+  access_read_write_exec = 7,
+} access_type;
+
+/* Address attachement types */
+typedef enum _attach_type {
+  attach_invalid,
+  attach_callback,
+  attach_default,
+  attach_raw_memory,
+} attach_type;
+
+
+/* Operators on devices: */
+
+
+/* Initialization:
+
+   A device is made fully functional in two stages.
+
+   1. It is created. A device is created _before_ it is entered into
+   the device tree.  During creation any permenant structures needed
+   by the device should be created/initialized.
+
+   2. It is initialized.  Before a simulation run, each device in the
+   device tree is initialized in prefix order.  As part of this
+   initialization, a device should (re)attach its self to its parent
+   as needed.
+
+   */
+
+typedef void (device_init_callback)
+     (const device *me,
+      psim *system);
+
+
+/* Data transfers:
+
+   A device may permit the reading/writing (IO) of its registers in
+   one or more address spaces.  For instance, a PCI device may have
+   config registers in its config space and control registers in both
+   the io and memory spaces of a PCI bus.
+
+   Similarly, a device may initiate a data transfer (DMA) by passing
+   such a request up to its parent.
+
+   Init:
+
+   As part of its initialization (not creation) and possibly also as a
+   consequence of IO a device may attach its self to one or more of
+   the address spaces of its parent device.
+
+   For instance, a PCI device, during initialization would attach its
+   config registers (space=0?, base=0, nr_bytes=64) to its parent PCI
+   bridge.  Later, due to a write to this config space, the same
+   device may in turn find it necessary to also attach its self to
+   it's parent's `memory' or `io' space.
+
+   To perform these operations, a device will call upon its parent
+   using either device_attach_address or device_detach_address.
+
+   * Any address specified is according to what the device expects to
+   see.
+
+   * Any detach operation must exactly match a previous attach.
+
+   * included with the attach or detach is the devices name, the
+   parent may use this as part of determining how to map map between a
+   child's address + space and its own.
+
+   * at any time, at most one device can have a default mapping
+   registered.
+
+
+   IO:
+
+   A device receives requests to perform reads/writes to its registers
+   or memory either A. from a processor or B. from a parent device.
+
+   The device may then in turn either A. resolve the IO request
+   locally by processing the data or trigering an exception or
+   B. re-mapping the access onto one of its local address spaces and
+   then in turn passing that on to one of its children.
+
+   * Any address passed is relative to the local device.  Eg for PCI
+   config registers, the address would (normally) be in the range of 0
+   to 63.
+
+   * Any exception situtation triggered by an IO operation (processor
+   != NULL) is handled in one of the following ways: 1. Machine check
+   (and similar): issued immediatly by restarting the cpu; 2. External
+   exception: issue delayed (using events.h) until the current
+   instruction execution cycle is completed; 3. Slave device (and
+   similar): the need for the interrupt is passed on to the devices
+   parent (which being an interrupt control unit will in turn take one
+   of the actions described here); 4. Forget it.
+
+   * Any exception situtation trigered by a non IO operation
+   (processor == NULL) is handled buy returning 0.
+
+   * Transfers of size <= 8 and of a power of 2 *must* be correctly
+   aligned and should be treated as a `single cycle' transfer.
+
+   DMA:
+
+   A device initiates a DMA transfer by calling its parent with the
+   request.  At the top level (if not done earlier) this is reflected
+   back down the tree as io read/writes to the target device.
+
+   This function is subject to change ...
+
+   */
+
+typedef void (device_config_address_callback)
+     (const device *me,
+      const char *name,
+      attach_type type,
+      int address_space,
+      unsigned_word addr,
+      unsigned nr_bytes,
+      access_type access,
+      const device *who); /*callback/default*/
+
+typedef unsigned (device_io_read_buffer_callback)
+     (const device *me,
+      void *dest,
+      int address_space,
+      unsigned_word addr,
+      unsigned nr_bytes,
+      cpu *processor,
+      unsigned_word cia);
+
+typedef unsigned (device_io_write_buffer_callback)
+     (const device *me,
+      const void *source,
+      int address_space,
+      unsigned_word addr,
+      unsigned nr_bytes,
+      cpu *processor,
+      unsigned_word cia);
+
+typedef unsigned (device_dma_read_buffer_callback)
+     (const device *me,
+      void *dest,
+      int address_space,
+      unsigned_word addr,
+      unsigned nr_bytes);
+
+typedef unsigned (device_dma_write_buffer_callback)
+     (const device *me,
+      const void *source,
+      int address_space,
+      unsigned_word addr,
+      unsigned nr_bytes,
+      int violate_read_only_section);
+
+
+/* Interrupts:
+
+   As mentioned above.  Instead of handling an interrupt directly, a
+   device may instead pass the need to interrupt on to its parent.
+
+   Init:
+
+   Before passing interrupts up to is parent, a device must first
+   attach its interrupt lines to the parent device.  To do this, the
+   device uses the parents attach/detach calls.
+  
+   Interrupts:
+
+   A child notifies a parent of a change in an interrupt lines status
+   using the interrupt call.  Similarly, a parent may notify a child
+   of any `interrupt ack' sequence using the interrupt_ack call.
+
+   */
+
+typedef void (device_config_interrupt_callback)
+     (const device *me,
+      const device *who,
+      int interrupt_line,
+      const char *name);
+
+typedef void (device_interrupt_ack_callback)
+     (const device *me,
+      int interrupt_line,
+      int interrupt_status);
+
+typedef void (device_interrupt_callback)
+     (const device *me,
+      const device *who,
+      int interrupt_line,
+      int interrupt_status,
+      cpu *processor,
+      unsigned_word cia);
+
+
+/* IOCTL:
+
+   Very simply, a catch all for any thing that turns up that until now
+   either hasn't been thought of or doesn't justify an extra function. */
+
+
+typedef void (device_ioctl_callback)
+     (const device *me,
+      psim *system,
+      cpu *processor,
+      unsigned_word cia,
+      ...);
+      
+
+
+/* the callbacks */
+
+typedef struct _device_callbacks {
+  /* initialization */
+  device_init_callback *init;
+  /* address/data config - from child */
+  device_config_address_callback *attach_address;
+  device_config_address_callback *detach_address;
+  /* address/data transfer - to child */
+  device_io_read_buffer_callback *io_read_buffer;
+  device_io_write_buffer_callback *io_write_buffer;
+  /* address/data transfer - from child */
+  device_dma_read_buffer_callback *dma_read_buffer;
+  device_dma_write_buffer_callback *dma_write_buffer;
+  /* interrupt config - from child */
+  device_config_interrupt_callback *attach_interrupt;
+  device_config_interrupt_callback *detach_interrupt;
+  /* interrupt transfer - from child */
+  device_interrupt_callback *interrupt;
+  /* interrupt transfer - to child */
+  device_interrupt_ack_callback *interrupt_ack;
+  /* back door to anything we've forgot */
+  device_ioctl_callback *ioctl;
+} device_callbacks;
+
+/* A device */
+struct _device {
+  const char *name; /* eg rom@0x1234, 0x400 */
+  void *data; /* device specific data */
+  const device_callbacks *callback;
+  const device *parent;
 };
 
 
-INLINE_DEVICES device_descriptor *find_device_descriptor(char *name);
+/* Create a new device, finding it in the builtin device table */
+
+INLINE_DEVICES const device *device_create
+(const char *name,
+ const device *parent);
+
+/* create a new device using the parameterized data */
+
+INLINE_DEVICES const device *device_create_from
+(const char *name,
+ void *data,
+ const device_callbacks *callback,
+ const device *parent);
+
+
+/* Unimplemented call back functions.  These abort the simulation */
+
+INLINE_DEVICES device_init_callback unimp_device_init;
+INLINE_DEVICES device_config_address_callback unimp_device_attach_address;
+INLINE_DEVICES device_config_address_callback unimp_device_detach_address;
+INLINE_DEVICES device_io_read_buffer_callback unimp_device_io_read_buffer;
+INLINE_DEVICES device_io_write_buffer_callback unimp_device_io_write_buffer;
+INLINE_DEVICES device_dma_read_buffer_callback unimp_device_dma_read_buffer;
+INLINE_DEVICES device_dma_write_buffer_callback unimp_device_dma_write_buffer;
+INLINE_DEVICES device_config_interrupt_callback unimp_device_attach_interrupt;
+INLINE_DEVICES device_config_interrupt_callback unimp_device_detach_interrupt;
+INLINE_DEVICES device_interrupt_callback unimp_device_interrupt;
+INLINE_DEVICES device_interrupt_ack_callback unimp_device_interrupt_ack;
+INLINE_DEVICES device_ioctl_callback unimp_device_ioctl;
+
+/* Pass through and ignore callback functions.  A call going towards
+   the root device are passed on up, local calls are ignored and call
+   downs abort */
+
+INLINE_DEVICES device_init_callback ignore_device_init;
+INLINE_DEVICES device_config_address_callback pass_device_attach_address;
+INLINE_DEVICES device_config_address_callback pass_device_detach_address;
+INLINE_DEVICES device_dma_read_buffer_callback pass_device_dma_read_buffer;
+INLINE_DEVICES device_dma_write_buffer_callback pass_device_dma_write_buffer;
+INLINE_DEVICES device_config_interrupt_callback pass_device_attach_interrupt;
+INLINE_DEVICES device_config_interrupt_callback pass_device_detach_interrupt;
+INLINE_DEVICES device_interrupt_callback pass_device_interrupt;
+
+INLINE_DEVICES const device_callbacks *passthrough_device_callbacks
+(void);
+
+
 
 #endif /* _DEVICES_H_ */
index cc46952d05548dfb1bfa01f9e53768f5897746f1..b9870ab65d7b74debba654510b5385eb1b758ef5 100644 (file)
 
    Instead of using/abusing macro's the semantic code should be parsed
    and each `cachable' expression replaced with the corresponding
-   value.
-
-   If not expanding fields, invalid_insn has call to its self this is
-   a little fatal when semantic_invalid() is being called because an
-   instruction is invalid */
+   value. */
 
 
 #include <sys/types.h>
@@ -52,7 +48,7 @@
 
 /****************************************************************/
 
-void
+static void
 error (char *msg, ...)
 {
   va_list ap;
@@ -62,7 +58,7 @@ error (char *msg, ...)
   exit (1);
 }
 
-void *
+static void *
 zmalloc(long size)
 {
   void *memory = malloc(size);
@@ -72,7 +68,7 @@ zmalloc(long size)
   return memory;
 }
 
-void
+static void
 dumpf (int indent, char *msg, ...)
 {
   va_list ap;
@@ -121,10 +117,11 @@ typedef struct _opcode_rules {
 /* FIXME - this should be loaded from a file */
 opcode_rules opcode_table[] = WITH_IDECODE_OPCODE_RULES;
 
+static void
 dump_opcode_rule(opcode_rules *rule,
                 int indent)
 {
-  printf("(opcode_rules*)0x%x\n", rule);
+  printf("(opcode_rules*)%p\n", rule);
   dumpf(indent, "(valid %d)\n", rule->valid);
   ASSERT(rule != NULL);
   if (rule->valid) {
@@ -158,7 +155,7 @@ char insn_local[] = "unsigned_word nia = cia + 4;";
 
 /****************************************************************/
 
-int
+static int
 bin2i(char *bin, int width)
 {
   int i = 0;
@@ -171,7 +168,7 @@ bin2i(char *bin, int width)
 }
 
 
-int
+static int
 it_is(char *flag,
       char *flags)
 {
@@ -203,13 +200,16 @@ struct _lf {
 };
 
 
-lf *
-lf_open(char *name)
+static lf *
+lf_open(char *name,
+       char *real_name)
 {
   /* create a file object */
   lf *new_lf = zmalloc(sizeof(lf));
   ASSERT(new_lf != NULL);
-  new_lf->file_name = name;
+  new_lf->file_name = (real_name == NULL
+                      ? name
+                      : real_name);
 
   /* attach to stdout if pipe */
   if (!strcmp(name, "-")) {
@@ -224,7 +224,7 @@ lf_open(char *name)
 }
 
 
-void
+static void
 lf_close(lf *file)
 {
   if (file->stream != stdout) {
@@ -237,7 +237,7 @@ lf_close(lf *file)
 }
 
 
-void
+static void
 lf_putchr(lf *file,
          const char chr)
 {
@@ -254,14 +254,14 @@ lf_putchr(lf *file,
   putc(chr, file->stream);
 }
 
-void
+static void
 lf_indent_suppress(lf *file)
 {
   file->line_blank = 0;
 }
 
 
-void
+static void
 lf_putstr(lf *file,
          const char *string)
 {
@@ -273,7 +273,7 @@ lf_putstr(lf *file,
   }
 }
 
-void
+static void
 do_lf_putunsigned(lf *file,
              unsigned u)
 {
@@ -284,7 +284,7 @@ do_lf_putunsigned(lf *file,
 }
 
 
-void
+static void
 lf_putint(lf *file,
          int decimal)
 {
@@ -301,7 +301,7 @@ lf_putint(lf *file,
     ASSERT(0);
 }
 
-void
+static void
 lf_printf(lf *file,
          const char *fmt,
          ...)
@@ -318,7 +318,7 @@ lf_printf(lf *file,
   va_end(ap);
 }
 
-void
+static void
 lf_print_file_line_nr(lf *file)
 {
 #if WITH_LINE_NUMBERS
@@ -331,6 +331,7 @@ lf_print_file_line_nr(lf *file)
 #endif
 }
 
+static void
 lf_indent(lf *file, int delta)
 {
   file->indent += delta;
@@ -363,7 +364,7 @@ struct _file_table_entry {
 };
 
 
-file_table *
+static file_table *
 file_table_open(char *file_name)
 {
   int fd;
@@ -411,7 +412,7 @@ file_table_open(char *file_name)
 }
 
 
-file_table_entry *
+static file_table_entry *
 file_table_read(file_table *file)
 {
   int field;
@@ -494,11 +495,11 @@ file_table_read(file_table *file)
 }
 
 
-void
+static void
 dump_file_table_entry(file_table_entry *entry,
                      int indent)
 {
-  printf("(file_table_entry*)0x%x\n", entry);
+  printf("(file_table_entry*)%p\n", entry);
 
   if (entry != NULL) {
     int field;
@@ -548,7 +549,7 @@ struct _insn_fields {
   unsigned value;
 };
 
-insn_field *
+static insn_field *
 insn_field_new()
 {
   insn_field *new_field = (insn_field*)zmalloc(sizeof(insn_field));
@@ -556,7 +557,7 @@ insn_field_new()
   return new_field;
 }
 
-insn_fields *
+static insn_fields *
 insn_fields_new()
 {
   insn_fields *new_fields = (insn_fields*)zmalloc(sizeof(insn_fields));
@@ -565,7 +566,7 @@ insn_fields_new()
 }
 
 
-insn_fields *
+static insn_fields *
 parse_insn_format(file_table_entry *entry,
                  char *format)
 {
@@ -600,9 +601,8 @@ parse_insn_format(file_table_entry *entry,
 
     /* sanity check */
     if (!isdigit(*chp)) {
-      fprintf(stderr, "%s:%d: missing position field at %s\n",
-             entry->file_name, entry->line_nr, chp);
-      break;
+      error("%s:%d: missing position field at `%s'\n",
+           entry->file_name, entry->line_nr, chp);
     }
 
     /* break out the bit position */
@@ -613,23 +613,23 @@ parse_insn_format(file_table_entry *entry,
     if (*chp == '.' && strlen_pos > 0)
       chp++;
     else {
-      fprintf(stderr, "%s:%d: missing field value at %s\n",
-             entry->file_name, entry->line_nr, chp);
+      error("%s:%d: missing field value at %s\n",
+           entry->file_name, entry->line_nr, chp);
       break;
     }
 
     /* break out the value */
     start_val = chp;
-    while (*start_val == '/' && *chp == '/'
-          || isdigit(*start_val) && isdigit(*chp)
-          || isalpha(*start_val) && (isalnum(*chp) || *chp == '_'))
+    while ((*start_val == '/' && *chp == '/')
+          || (isdigit(*start_val) && isdigit(*chp))
+          || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_')))
       chp++;
     strlen_val = chp - start_val;
     if (*chp == ',')
       chp++;
     else if (*chp != '\0' || strlen_val == 0) {
-      fprintf(stderr, "%s:%d: missing field terminator at %s\n",
-             entry->file_name, entry->line_nr, chp);
+      error("%s:%d: missing field terminator at %s\n",
+           entry->file_name, entry->line_nr, chp);
       break;
     }
 
@@ -706,7 +706,7 @@ typedef enum {
 } constant_field_types;
 
 
-int
+static int
 insn_field_is_constant(insn_field *field,
                       opcode_rules *rule)
 {
@@ -738,12 +738,12 @@ insn_field_is_constant(insn_field *field,
 }
 
 
-void
+static void
 dump_insn_field(insn_field *field,
                int indent)
 {
 
-  printf("(insn_field*)0x%x\n", field);
+  printf("(insn_field*)0x%x\n", (unsigned)field);
 
   dumpf(indent, "(first %d)\n", field->first);
 
@@ -767,14 +767,14 @@ dump_insn_field(insn_field *field,
 
 }
 
-void
+static void
 dump_insn_fields(insn_fields *fields,
                 int indent)
 {
   insn_field *field;
   int i;
 
-  printf("(insn_fields*)0x%x\n", fields);
+  printf("(insn_fields*)%p\n", fields);
 
   dumpf(indent, "(first 0x%x)\n", fields->first);
   dumpf(indent, "(last 0x%x)\n", fields->last);
@@ -800,7 +800,7 @@ struct _opcode_field {
   opcode_field *parent;
 };
 
-opcode_field *
+static opcode_field *
 opcode_field_new()
 {
   opcode_field *new_field = (opcode_field*)zmalloc(sizeof(opcode_field));
@@ -810,10 +810,10 @@ opcode_field_new()
   return new_field;
 }
 
-void
+static void
 dump_opcode_field(opcode_field *field, int indent, int levels)
 {
-  printf("(opcode_field*)0x%x\n", field);
+  printf("(opcode_field*)%p\n", field);
   if (levels && field != NULL) {
     dumpf(indent, "(first %d)\n", field->first);
     dumpf(indent, "(last %d)\n", field->last);
@@ -835,7 +835,7 @@ struct _insn_bits {
   insn_bits *last;
 };
 
-insn_bits *
+static insn_bits *
 insn_bits_new()
 {
   insn_bits *new_bits = (insn_bits*)zmalloc(sizeof(insn_bits));
@@ -844,10 +844,10 @@ insn_bits_new()
 }
 
 
-void
+static void
 dump_insn_bits(insn_bits *bits, int indent, int levels)
 {
-  printf("(insn_bits*)0x%x\n", bits);
+  printf("(insn_bits*)%p\n", bits);
 
   if (levels && bits != NULL) {
     dumpf(indent, "(value %d)\n", bits->value);
@@ -873,12 +873,19 @@ typedef enum {
   insn_nmemonic,
   insn_name,
   insn_comment,
-  nr_insn_table_fields = file_table_max_fields
+  nr_insn_table_fields = file_table_max_fields,
 } insn_table_fields;
 char *insn_field_name[] = {
   "format", "form", "flags", "nmemonic", "name", "comments"
 };
 
+typedef enum {
+  function_type = insn_format,
+  function_name = insn_name,
+  function_param = insn_comment,
+} function_table_fields;
+
+
 typedef struct _insn insn;
 struct _insn {
   file_table_entry *file_entry;
@@ -892,6 +899,7 @@ struct _insn_table {
   insn_bits *expanded_bits;
   int nr_insn;
   insn *insns;
+  insn *functions;
   opcode_rules *opcode_rule;
   opcode_field *opcode;
   int nr_entries;
@@ -902,7 +910,7 @@ struct _insn_table {
 
 
 
-insn *
+static insn *
 insn_new()
 {
   insn *new_entry = ((insn*) zmalloc(sizeof(insn)));
@@ -910,7 +918,7 @@ insn_new()
   return new_entry;
 }
 
-insn_table *
+static insn_table *
 insn_table_new()
 {
   insn_table *new_table = (insn_table*)zmalloc(sizeof(insn_table));
@@ -919,7 +927,25 @@ insn_table_new()
 }
 
 
-void
+static void
+insn_table_insert_function(insn_table *table,
+                          file_table_entry *file_entry)
+{
+  insn **ptr_to_cur_function = &table->functions;
+
+  /* create a new function */
+  insn *new_function = insn_new();
+  new_function->file_entry = file_entry;
+
+  /* append it to the end of the function list */
+  while (*ptr_to_cur_function != NULL) {
+    ptr_to_cur_function = &(*ptr_to_cur_function)->next;
+  }
+  *ptr_to_cur_function = new_function;
+}
+
+
+static void
 insn_table_insert_insn(insn_table *table,
                       file_table_entry *file_entry,
                       insn_fields *fields)
@@ -946,7 +972,7 @@ insn_table_insert_insn(insn_table *table,
 }
 
 
-opcode_field *
+static opcode_field *
 insn_table_find_opcode_field(insn *insns,
                             opcode_rules *rule,
                             int string_only)
@@ -1047,7 +1073,7 @@ insn_table_find_opcode_field(insn *insns,
 }
 
 
-void
+static void
 insn_table_insert_expanded(insn_table *table,
                           insn *old_insn,
                           int new_opcode_nr,
@@ -1081,7 +1107,7 @@ insn_table_insert_expanded(insn_table *table,
                         old_insn->fields);
 }
 
-void
+static void
 insn_table_expand_opcode(insn_table *table,
                         insn *instruction,
                         int field_nr,
@@ -1124,6 +1150,7 @@ insn_table_expand_opcode(insn_table *table,
   }
 }
 
+static void
 insn_table_insert_expanding(insn_table *table,
                            insn *entry)
 {
@@ -1135,7 +1162,7 @@ insn_table_insert_expanding(insn_table *table,
 }
 
 
-void
+static void
 insn_table_expand_insns(insn_table *table)
 {
 
@@ -1196,7 +1223,7 @@ insn_table_expand_insns(insn_table *table)
 
 
 
-insn_table *
+static insn_table *
 insn_table_load_insns(char *file_name)
 {
   file_table *file = file_table_open(file_name);
@@ -1204,25 +1231,33 @@ insn_table_load_insns(char *file_name)
   file_table_entry *file_entry;
   table->opcode_rule = opcode_table;
 
-  while (file_entry = file_table_read(file)) {
-    insn_fields *fields;
-    /* skip instructions that aren't relevant to the mode */
-    if (it_is("64", file_entry->fields[insn_flags]) && !WITH_64BIT_TARGET
-       || it_is("32", file_entry->fields[insn_flags]) && WITH_64BIT_TARGET)
-      continue;
-    /* create/insert the new instruction */
-    fields = parse_insn_format(file_entry, file_entry->fields[insn_format]);
-    insn_table_insert_insn(table, file_entry, fields);
+  while ((file_entry = file_table_read(file)) != NULL) {
+    if (it_is("function", file_entry->fields[insn_flags])) {
+      insn_table_insert_function(table, file_entry);
+    }
+    else {
+      insn_fields *fields;
+      /* skip instructions that aren't relevant to the mode */
+      if ((it_is("64", file_entry->fields[insn_flags])
+          && WITH_TARGET_WORD_BITSIZE != 64)
+         || (it_is("32", file_entry->fields[insn_flags])
+             && WITH_TARGET_WORD_BITSIZE != 32)
+         || (it_is("f", file_entry->fields[insn_flags])
+             && WITH_FLOATING_POINT == SOFT_FLOATING_POINT))
+       continue;
+      /* create/insert the new instruction */
+      fields = parse_insn_format(file_entry, file_entry->fields[insn_format]);
+      insn_table_insert_insn(table, file_entry, fields);
+    }
   }
-
   return table;
 }
 
 
-void
+static void
 dump_insn(insn *entry, int indent, int levels)
 {
-  printf("(insn*)0x%x\n", entry);
+  printf("(insn*)%p\n", entry);
 
   if (levels && entry != NULL) {
 
@@ -1243,12 +1278,12 @@ dump_insn(insn *entry, int indent, int levels)
 }
 
 
-void
+static void
 dump_insn_table(insn_table *table,
                int indent, int levels)
 {
 
-  printf("(insn_table*)0x%x\n", table);
+  printf("(insn_table*)%p\n", table);
 
   if (levels && table != NULL) {
     insn *entry;
@@ -1293,7 +1328,7 @@ dump_insn_table(insn_table *table,
 /****************************************************************/
 
 
-void
+static void
 lf_print_copyleft(lf *file)
 {
   lf_putstr(file, "\
@@ -1326,7 +1361,7 @@ lf_print_copyleft(lf *file)
 }
 
 
-void
+static void
 lf_print_c_line_nr(lf *file, file_table_entry *entry)
 {
 #if WITH_LINE_NUMBERS
@@ -1340,7 +1375,7 @@ lf_print_c_line_nr(lf *file, file_table_entry *entry)
 }
 
 
-void
+static void
 lf_print_c_code(lf *file, char *code)
 {
   char *chp = code;
@@ -1378,7 +1413,7 @@ lf_print_c_code(lf *file, char *code)
 }
 
 
-void
+static void
 lf_print_binary(lf *file, int decimal, int width)
 {
   int bit;
@@ -1394,7 +1429,7 @@ lf_print_binary(lf *file, int decimal, int width)
 }
 
 
-void
+static void
 lf_print_insn_bits(lf *file, insn_bits *bits)
 {
   if (bits == NULL)
@@ -1410,7 +1445,7 @@ lf_print_insn_bits(lf *file, insn_bits *bits)
   }
 }
 
-void
+static void
 lf_print_opcodes(lf *file,
                 insn_table *table)
 {
@@ -1426,7 +1461,7 @@ lf_print_opcodes(lf *file,
   }
 }
 
-void
+static void
 lf_print_table_name(lf *file,
                    insn_table *table)
 {
@@ -1442,12 +1477,13 @@ typedef enum {
   function_name_prefix_none
 } lf_function_name_prefixes;
 
-void
+static void
 lf_print_function_name(lf *file,
-                      insn *instruction,
+                      char *basename,
                       insn_bits *expanded_bits,
                       lf_function_name_prefixes prefix)
 {
+
   /* the prefix */
   switch (prefix) {
   case function_name_prefix_semantics:
@@ -1463,7 +1499,7 @@ lf_print_function_name(lf *file,
   /* the function name */
   {
     char *pos;
-    for (pos = instruction->file_entry->fields[insn_name];
+    for (pos = basename;
         *pos != '\0';
         pos++) {
       switch (*pos) {
@@ -1486,7 +1522,7 @@ lf_print_function_name(lf *file,
 }
 
 
-void
+static void
 lf_print_idecode_table(lf *file,
                       insn_table *entry)
 {
@@ -1574,7 +1610,7 @@ lf_print_idecode_table(lf *file,
 }
 
 
-void
+static void
 lf_print_my_prefix(lf *file,
                   file_table_entry *file_entry)
 {
@@ -1586,7 +1622,7 @@ lf_print_my_prefix(lf *file,
 }
 
 
-void
+static void
 lf_print_ptrace(lf *file)
 {
   lf_printf(file, "\n");
@@ -1607,7 +1643,7 @@ typedef void padding_handler
  int opcode_nr);
 
 
-void
+static void
 insn_table_traverse_tree(insn_table *table,
                         void *data,
                         int depth,
@@ -1657,12 +1693,31 @@ insn_table_traverse_tree(insn_table *table,
 }
 
 
+typedef void function_handler
+(insn_table *table,
+ void *data,
+ file_table_entry *function);
+
+static void
+insn_table_traverse_function(insn_table *table,
+                            void *data,
+                            function_handler *leaf)
+{
+  insn *function;
+  for (function = table->functions;
+       function != NULL;
+       function = function->next) {
+    leaf(table, data, function->file_entry);
+  }
+}
+
+
 typedef void insn_handler
 (insn_table *table,
  void *data,
  insn *instruction);
 
-void
+static void
 insn_table_traverse_insn(insn_table *table,
                         void *data,
                         insn_handler *leaf)
@@ -1676,7 +1731,7 @@ insn_table_traverse_insn(insn_table *table,
 }
 
 
-void
+static void
 update_depth(insn_table *entry,
             void *data,
             int depth)
@@ -1687,7 +1742,7 @@ update_depth(insn_table *entry,
 }
 
 
-int
+static int
 insn_table_depth(insn_table *table)
 {
   int depth = 0;
@@ -1704,7 +1759,7 @@ insn_table_depth(insn_table *table)
 
 /****************************************************************/
 
-void
+static void
 dump_traverse_start(insn_table *table,
                    void *data,
                    int depth)
@@ -1712,7 +1767,7 @@ dump_traverse_start(insn_table *table,
   dumpf(depth*2, "(%d\n", table->opcode_nr);
 }
 
-void
+static void
 dump_traverse_leaf(insn_table *entry,
                   void *data,
                   int depth)
@@ -1724,7 +1779,7 @@ dump_traverse_leaf(insn_table *entry,
        entry->insns->file_entry->fields[insn_format]);
 }
 
-void
+static void
 dump_traverse_end(insn_table *table,
                  void *data,
                  int depth)
@@ -1732,7 +1787,7 @@ dump_traverse_end(insn_table *table,
   dumpf(depth*2, ")\n");
 }
 
-void
+static void
 dump_traverse_padding(insn_table *table,
                      void *data,
                      int depth,
@@ -1742,7 +1797,7 @@ dump_traverse_padding(insn_table *table,
 }
 
 
-void
+static void
 dump_traverse(insn_table *table)
 {
   insn_table_traverse_tree(table, NULL, 1,
@@ -1756,15 +1811,15 @@ dump_traverse(insn_table *table)
 /****************************************************************/
 
 
-void
+static void
 semantics_h_print_function(lf *file,
-                          insn *instruction,
+                          char *basename,
                           insn_bits *expanded_bits)
 {
   lf_printf(file, "\n");
   lf_printf(file, "INLINE_SEMANTICS unsigned_word ");
   lf_print_function_name(file,
-                        instruction,
+                        basename,
                         expanded_bits,
                         function_name_prefix_semantics);
   lf_printf(file, "\n(%s);\n",
@@ -1772,27 +1827,52 @@ semantics_h_print_function(lf *file,
 }
 
 
-void
+static void
 semantics_h_leaf(insn_table *entry,
                 void *data,
                 int depth)
 {
   lf *file = (lf*)data;
   ASSERT(entry->nr_insn == 1);
-  semantics_h_print_function(file, entry->insns, entry->expanded_bits);
+  semantics_h_print_function(file,
+                            entry->insns->file_entry->fields[insn_name],
+                            entry->expanded_bits);
 }
 
-void
+static void
 semantics_h_insn(insn_table *entry,
                 void *data,
                 insn *instruction)
 {
   lf *file = (lf*)data;
-  semantics_h_print_function(file, instruction, NULL);
+  semantics_h_print_function(file,
+                            instruction->file_entry->fields[insn_name],
+                            NULL);
+}
+
+static void
+semantics_h_function(insn_table *entry,
+                    void *data,
+                    file_table_entry *function)
+{
+  lf *file = (lf*)data;
+  if (function->fields[function_type] == NULL
+      || function->fields[function_type][0] == '\0') {
+    semantics_h_print_function(file,
+                              function->fields[function_name],
+                              NULL);
+  }
+  else {
+    lf_printf(file, "\n");
+    lf_printf(file, "INLINE_SEMANTICS %s %s\n(%s);\n",
+             function->fields[function_type],
+             function->fields[function_name],
+             function->fields[function_param]);
+  }
 }
 
 
-void 
+static void 
 gen_semantics_h(insn_table *table, lf *file)
 {
 
@@ -1807,6 +1887,12 @@ gen_semantics_h(insn_table *table, lf *file)
   lf_printf(file, "\n");
   lf_printf(file, "\n");
 
+  /* output a declaration for all functions */
+  insn_table_traverse_function(table,
+                              file,
+                              semantics_h_function);
+
+  /* output a declaration for all instructions */
   if (idecode_expand_semantics)
     insn_table_traverse_tree(table,
                             file,
@@ -1834,7 +1920,7 @@ struct _icache_tree {
   icache_tree *children;
 };
 
-icache_tree *
+static icache_tree *
 icache_tree_new()
 {
   icache_tree *new_tree = (icache_tree*)zmalloc(sizeof(icache_tree));
@@ -1842,7 +1928,7 @@ icache_tree_new()
   return new_tree;
 }
 
-icache_tree *
+static icache_tree *
 icache_tree_insert(icache_tree *tree,
                   char *name)
 {
@@ -1872,7 +1958,7 @@ icache_tree_insert(icache_tree *tree,
 }
 
 
-icache_tree *
+static icache_tree *
 insn_table_cache_fields(insn_table *table)
 {
   icache_tree *tree = icache_tree_new();
@@ -1896,7 +1982,7 @@ insn_table_cache_fields(insn_table *table)
 
 
 
-void
+static void
 gen_icache_h(icache_tree *tree,
             lf *file)
 {
@@ -1976,7 +2062,7 @@ gen_icache_h(icache_tree *tree,
 /****************************************************************/
 
 
-void
+static void
 lf_print_c_extraction(lf *file,
                      insn *instruction,
                      char *field_name,
@@ -2030,7 +2116,7 @@ lf_print_c_extraction(lf *file,
 }
 
 
-void
+static void
 lf_print_c_extractions(lf *file,
                       insn *instruction,
                       insn_bits *expanded_bits,
@@ -2126,7 +2212,24 @@ lf_print_c_extractions(lf *file,
   lf_print_file_line_nr(file);
 }
 
-void
+
+static void
+lf_print_idecode_illegal(lf *file)
+{
+  switch (idecode_cache) {
+  case 0:
+    lf_printf(file, "return semantic_illegal(%s);\n", insn_actual);
+    break;
+  case 1:
+    lf_printf(file, "return semantic_illegal;\n");
+    break;
+  default:
+    lf_printf(file, "return idecode_illegal(%s);\n", cache_idecode_actual);
+  }
+}
+
+
+static void
 lf_print_c_validate(lf *file,
                    insn *instruction,
                    opcode_field *opcodes)
@@ -2161,30 +2264,21 @@ lf_print_c_validate(lf *file,
   }
 
   /* if any bits not checked by opcode tables, output code to check them */
-  if (!it_is("illegal", instruction->file_entry->fields[insn_flags])
-      && check_mask) {
+  if (check_mask) {
     lf_printf(file, "\n");
     lf_printf(file, "/* validate: %s */\n",
              instruction->file_entry->fields[insn_format]);
-    lf_printf(file, "if ((instruction & 0x%x) != 0x%x) {\n",
+    lf_printf(file, "if ((instruction & 0x%x) != 0x%x)\n",
              check_mask, check_val);
-    switch (idecode_cache) {
-    case 0:
-      lf_printf(file, "  return semantic_illegal(%s);\n", insn_actual);
-      break;
-    case 1:
-      lf_printf(file, "  return semantic_illegal;\n");
-      break;
-    default:
-      lf_printf(file, "  return idecode_illegal(%s);\n", cache_idecode_actual);
-    }
-    lf_printf(file, "}\n");
+    lf_indent(file, +2);
+    lf_print_idecode_illegal(file);
+    lf_indent(file, -2);
   }
 
 }
 
 
-void
+static void
 lf_print_c_cracker(lf *file,
                   insn *instruction,
                   insn_bits *expanded_bits,
@@ -2219,7 +2313,7 @@ lf_print_c_cracker(lf *file,
   lf_print_c_line_nr(file, instruction->file_entry);
   lf_printf(file, "return ");
   lf_print_function_name(file,
-                        instruction,
+                        instruction->file_entry->fields[insn_name],
                         expanded_bits,
                         function_name_prefix_semantics);
   lf_printf(file, ";\n");
@@ -2230,7 +2324,7 @@ lf_print_c_cracker(lf *file,
 }
 
 
-void
+static void
 lf_print_c_semantic(lf *file,
                    insn *instruction,
                    insn_bits *expanded_bits,
@@ -2258,12 +2352,21 @@ lf_print_c_semantic(lf *file,
   if (idecode_cache < 2)
     lf_print_c_validate(file, instruction, opcodes);
 
-  /* if OEA and a floating point generate a check that fp is enabled */
+  /* if floating-point generate checks that a. floating point hardware
+     exists and b. floating point is enabled */
   if (it_is("f", instruction->file_entry->fields[insn_flags])) {
     lf_printf(file, "\n");
-    lf_printf(file, "/* verify FP is enabled */\n");
+    lf_printf(file, "/* verify: FP hardware exists */\n");
+    lf_printf(file, "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT)\n");
+    lf_indent(file, +2);
+    lf_print_idecode_illegal(file);
+    lf_indent(file, -2);
+    lf_printf(file, "\n");
+    lf_printf(file, "/* verify: FP is enabled */\n");
     lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n");
-    lf_printf(file, "  floating_point_unavailable_interrupt(processor, cia);\n");
+    lf_indent(file, +2);
+    lf_printf(file, "floating_point_unavailable_interrupt(processor, cia);\n");
+    lf_indent(file, -2);
   }
 
   /* generate the code (or at least something */
@@ -2282,8 +2385,9 @@ lf_print_c_semantic(lf *file,
     lf_print_file_line_nr(file);
   }
   else if (it_is("f", instruction->file_entry->fields[insn_flags])) {
-    /* unimplemented floating point - call for assistance */
+    /* unimplemented floating point instruction - call for assistance */
     lf_printf(file, "\n");
+    lf_printf(file, "/* unimplemented floating point instruction - call for assistance */\n");
     lf_print_c_line_nr(file, instruction->file_entry);
     lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n");
     lf_print_file_line_nr(file);
@@ -2302,25 +2406,32 @@ lf_print_c_semantic(lf *file,
   lf_printf(file, "}\n");
 }
 
-void
-lf_print_c_semantic_function(lf *file,
-                            insn *instruction,
-                            insn_bits *expanded_bits,
-                            opcode_field *opcodes)
+static void
+lf_print_c_semantic_function_header(lf *file,
+                                   char *basename,
+                                   insn_bits *expanded_bits)
 {
-
-  /* build the semantic routine to execute the instruction */
-
-  /* function header */
   lf_printf(file, "\n");
   lf_printf(file, "INLINE_SEMANTICS unsigned_word\n");
   lf_print_function_name(file,
-                        instruction,
+                        basename,
                         expanded_bits,
                         function_name_prefix_semantics);
   lf_printf(file, "\n(%s)\n",
            idecode_cache > 1 ? cache_insn_formal : insn_formal);
+}
 
+static void
+lf_print_c_semantic_function(lf *file,
+                            insn *instruction,
+                            insn_bits *expanded_bits,
+                            opcode_field *opcodes)
+{
+
+  /* build the semantic routine to execute the instruction */
+  lf_print_c_semantic_function_header(file,
+                                     instruction->file_entry->fields[insn_name],
+                                     expanded_bits);
   lf_print_c_semantic(file,
                      instruction,
                      expanded_bits,
@@ -2329,7 +2440,7 @@ lf_print_c_semantic_function(lf *file,
 }
 
 
-void
+static void
 semantics_c_leaf(insn_table *entry,
                 void *data,
                 int depth)
@@ -2345,7 +2456,7 @@ semantics_c_leaf(insn_table *entry,
                               entry->parent->opcode);
 }
 
-void
+static void
 semantics_c_insn(insn_table *table,
                 void *data,
                 insn *instruction)
@@ -2355,9 +2466,37 @@ semantics_c_insn(insn_table *table,
                               NULL, NULL);
 }
 
+static void
+semantics_c_function(insn_table *table,
+                    void *data,
+                    file_table_entry *function)
+{
+  lf *file = (lf*)data;
+  if (function->fields[function_type] == NULL
+      || function->fields[function_type][0] == '\0') {
+    lf_print_c_semantic_function_header(file,
+                                       function->fields[function_name],
+                                       NULL);
+  }
+  else {
+    lf_printf(file, "\n");
+    lf_printf(file, "INLINE_SEMANTICS %s\n%s(%s)\n",
+             function->fields[function_type],
+             function->fields[function_name],
+             function->fields[function_param]);
+  }
+  lf_print_c_line_nr(file, function);
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+  lf_print_c_code(file, function->annex);
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+  lf_print_file_line_nr(file);
+}
+
 
 
-void 
+static void 
 gen_semantics_c(insn_table *table, lf *file)
 {
   lf_print_copyleft(file);
@@ -2374,6 +2513,12 @@ gen_semantics_c(insn_table *table, lf *file)
   lf_printf(file, "#include \"semantics.h\"\n");
   lf_printf(file, "\n");
 
+  /* output a definition (c-code) for all functions */
+  insn_table_traverse_function(table,
+                              file,
+                              semantics_c_function);
+
+  /* output a definition (c-code) for all instructions */
   if (idecode_expand_semantics)
     insn_table_traverse_tree(table,
                             file,
@@ -2394,7 +2539,7 @@ gen_semantics_c(insn_table *table, lf *file)
 
 /****************************************************************/
 
-void
+static void
 gen_idecode_h(insn_table *table, lf *file)
 {
   lf_print_copyleft(file);
@@ -2406,7 +2551,6 @@ gen_idecode_h(insn_table *table, lf *file)
   lf_printf(file, "#define INLINE_IDECODE\n");
   lf_printf(file, "#endif\n");
   lf_printf(file, "\n");
-  lf_printf(file, "#include \"idecode_insn.h\"\n");
   lf_printf(file, "#include \"idecode_expression.h\"\n");
   lf_printf(file, "#include \"idecode_fields.h\"\n");
   lf_printf(file, "#include \"idecode_branch.h\"\n");
@@ -2430,7 +2574,7 @@ gen_idecode_h(insn_table *table, lf *file)
 /****************************************************************/
 
 
-void
+static void
 idecode_table_start(insn_table *table,
                    void *data,
                    int depth)
@@ -2446,7 +2590,7 @@ idecode_table_start(insn_table *table,
   }
 }
 
-void
+static void
 idecode_table_leaf(insn_table *entry,
                   void *data,
                   int depth)
@@ -2461,7 +2605,7 @@ idecode_table_leaf(insn_table *entry,
       /* table leaf entry */
       lf_printf(file, "  /*%d*/ { 0, 0, ", entry->opcode_nr);
       lf_print_function_name(file,
-                            entry->insns,
+                            entry->insns->file_entry->fields[insn_name],
                             entry->expanded_bits,
                             (idecode_cache < 2
                              ? function_name_prefix_semantics
@@ -2491,7 +2635,7 @@ idecode_table_leaf(insn_table *entry,
   }
 }
 
-void
+static void
 idecode_table_end(insn_table *table,
                  void *data,
                  int depth)
@@ -2504,7 +2648,7 @@ idecode_table_end(insn_table *table,
   }
 }
 
-void
+static void
 idecode_table_padding(insn_table *table,
                      void *data,
                      int depth,
@@ -2528,7 +2672,7 @@ void lf_print_idecode_switch
  insn_table *table);
 
 
-void
+static void
 idecode_switch_start(insn_table *table,
                void *data,
                int depth)
@@ -2542,7 +2686,7 @@ idecode_switch_start(insn_table *table,
 }
 
 
-void
+static void
 idecode_switch_leaf(insn_table *entry,
                    void *data,
                    int depth)
@@ -2559,7 +2703,7 @@ idecode_switch_leaf(insn_table *entry,
       /* switch calling leaf */
       lf_printf(file, "return ");
       lf_print_function_name(file,
-                            entry->insns,
+                            entry->insns->file_entry->fields[insn_name],
                             entry->expanded_bits,
                             (idecode_cache < 2
                              ? function_name_prefix_semantics
@@ -2585,22 +2729,17 @@ idecode_switch_leaf(insn_table *entry,
   lf_indent(file, -2);
 }
 
+
+static void
 lf_print_idecode_switch_illegal(lf *file)
 {
-  switch (idecode_cache) {
-  case 0:
-    lf_printf(file, "  return semantic_illegal(%s);\n", insn_actual);
-    break;
-  case 1:
-    lf_printf(file, "  return semantic_illegal;\n");
-    break;
-  default:
-    lf_printf(file, "  return idecode_illegal(%s);\n", cache_idecode_actual);
-  }
-  lf_printf(file, "  break;\n");
+  lf_indent(file, +2);
+  lf_print_idecode_illegal(file);
+  lf_printf(file, "break;\n");
+  lf_indent(file, -2);
 }
 
-void
+static void
 idecode_switch_end(insn_table *table,
                   void *data,
                   int depth)
@@ -2616,7 +2755,7 @@ idecode_switch_end(insn_table *table,
   lf_printf(file, "}\n");
 }
 
-void
+static void
 idecode_switch_padding(insn_table *table,
                       void *data,
                       int depth,
@@ -2648,7 +2787,7 @@ lf_print_idecode_switch(lf *file,
 }
 
 
-void
+static void
 idecode_expand_if_switch(insn_table *table,
                         void *data,
                         int depth)
@@ -2674,6 +2813,7 @@ idecode_expand_if_switch(insn_table *table,
 }
 
 
+static void
 lf_print_c_cracker_function(lf *file,
                            insn *instruction,
                            insn_bits *expanded_bits,
@@ -2683,7 +2823,7 @@ lf_print_c_cracker_function(lf *file,
   lf_printf(file, "\n");
   lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n");
   lf_print_function_name(file,
-                        instruction,
+                        instruction->file_entry->fields[insn_name],
                         expanded_bits,
                         function_name_prefix_idecode);
   lf_printf(file, "\n(%s)\n", cache_idecode_formal);
@@ -2694,7 +2834,7 @@ lf_print_c_cracker_function(lf *file,
                     opcodes);
 }
 
-void
+static void
 idecode_crack_leaf(insn_table *entry,
                   void *data,
                   int depth)
@@ -2710,7 +2850,7 @@ idecode_crack_leaf(insn_table *entry,
                              entry->opcode);
 }
 
-void
+static void
 idecode_crack_insn(insn_table *entry,
                   void *data,
                   insn *instruction)
@@ -2724,6 +2864,7 @@ idecode_crack_insn(insn_table *entry,
 
 /****************************************************************/
 
+static void
 gen_idecode_c(insn_table *table, lf *file)
 {
   int depth;
@@ -2841,7 +2982,7 @@ struct _spreg_table {
   spreg_table_entry *sprs;
 };
 
-spreg_table_entry *
+static spreg_table_entry *
 spreg_table_entry_new()
 {
   spreg_table_entry *new_entry =
@@ -2850,7 +2991,7 @@ spreg_table_entry_new()
   return new_entry;
 }
 
-spreg_table *
+static spreg_table *
 spreg_table_new()
 {
   spreg_table *new_table = (spreg_table*)zmalloc(sizeof(spreg_table));
@@ -2858,7 +2999,7 @@ spreg_table_new()
   return new_table;
 }
 
-void
+static void
 spreg_table_insert(spreg_table *table, file_table_entry *entry)
 {
   /* create a new spr entry */
@@ -2898,7 +3039,7 @@ spreg_table_insert(spreg_table *table, file_table_entry *entry)
 }
 
 
-spreg_table *
+static spreg_table *
 spreg_table_load(char *file_name)
 {
   file_table *file = file_table_open(file_name);
@@ -2906,7 +3047,7 @@ spreg_table_load(char *file_name)
 
   {
     file_table_entry *entry;
-    while (entry = file_table_read(file)) {
+    while ((entry = file_table_read(file)) != NULL) {
       spreg_table_insert(table, entry);
     }
   }
@@ -2926,7 +3067,7 @@ char *spreg_attributes[] = {
   0
 };
 
-void
+static void
 gen_spreg_h(spreg_table *table, lf *file)
 {
   spreg_table_entry *entry;
@@ -2969,7 +3110,7 @@ gen_spreg_h(spreg_table *table, lf *file)
 }
 
 
-void
+static void
 gen_spreg_c(spreg_table *table, lf *file)
 {
   spreg_table_entry *entry;
@@ -3060,9 +3201,10 @@ main(int argc,
   insn_table *instructions = NULL;
   spreg_table *sprs = NULL;
   icache_tree *cache_fields = NULL;
+  char *real_file_name = NULL;
   int ch;
 
-  while ((ch = getopt(argc, argv, "i:I:r:S:s:D:d:P:p:C:")) != -1) {
+  while ((ch = getopt(argc, argv, "n:i:I:r:S:s:D:d:P:p:C:")) != -1) {
     fprintf(stderr, "\t-%c %s\n", ch, optarg);
     switch(ch) {
     case 'I':
@@ -3080,9 +3222,12 @@ main(int argc,
     case 'r':
       sprs = spreg_table_load(optarg);
       break;
+    case 'n':
+      real_file_name = strdup(optarg);
+      break;
     default:
       {
-       lf *file = lf_open(optarg);
+       lf *file = lf_open(optarg, real_file_name);
        switch (ch) {
        case 'S':
          gen_semantics_h(instructions, file);
@@ -3108,6 +3253,7 @@ main(int argc,
        }
        lf_close(file);
       }
+      real_file_name = NULL;
     }
   }
   return 0;
diff --git a/sim/ppc/idecode_insn.h b/sim/ppc/idecode_insn.h
deleted file mode 100644 (file)
index 4e56b78..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*  This file is part of the program psim.
-
-    Copyright (C) 1994-1995, 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.
-    */
-
-
-/*
- * Interface for the Instruction execution routines
- */
-
-/*
- * Macro's that define the parts of an instruction
- */
-
-#define FLOATING_POINT_ENABLED_PROGRAM_INTERRUPT \
-     program_interrupt(processor, \
-                      cia, \
-                      floating_point_enabled_program_interrupt)
-
-#define ILLEGAL_INSN_PROGRAM_INTERRUPT \
-     program_interrupt(processor, \
-                      cia, \
-                      illegal_instruction_program_interrupt)
-#define PRIVILEGED_INSN_PROGRAM_INTERRUPT \
-     program_interrupt(processor, \
-                      cia, \
-                      privileged_instruction_program_interrupt)
-
-#define TRAP_PROGRAM_INTERRUPT \
-     program_interrupt(processor, \
-                      cia, \
-                      trap_program_interrupt)
-
-#define FLOATING_POINT_UNAVAILABLE_INTERRUPT \
-     floating_point_unavailable_interrupt(processor, \
-                                         cia)
-
-#define FLOATING_POINT_ASSIST_INTERRUPT \
-     floating_point_assist_interrupt(processor, \
-                                    cia)
-
-#define BREAKPOINT \
-     do { \
-       ITRACE(trace_breakpoint, \
-             ("breakpoint - cia0x%x\n", \
-              cia)); \
-       cpu_halt(processor, cia, was_trap, 0); \
-     } while (0)
-
-#define SYSTEM_CALL_INTERRUPT \
-     system_call_interrupt(processor, \
-                          cia)
diff --git a/sim/ppc/memory_map.c b/sim/ppc/memory_map.c
deleted file mode 100644 (file)
index af97006..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-/*  This file is part of the program psim.
-
-    Copyright (C) 1994-1995, 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 _MEMORY_MAP_C_
-#define _MEMORY_MAP_C_
-
-#ifndef STATIC_INLINE_MEMORY_MAP
-#define STATIC_INLINE_MEMORY_MAP STATIC_INLINE
-#endif
-
-
-#include "basics.h"
-#include "device_tree.h"
-#include "memory_map.h"
-#include "interrupts.h"
-
-
-typedef struct _memory_mapping memory_mapping;
-struct _memory_mapping {
-  /* ram map */
-  void *buffer;
-  /* device map */
-  device_node *device;
-  device_reader_callback *reader;
-  device_writer_callback *writer;
-  /* common */
-  unsigned_word base;
-  unsigned_word bound;
-  unsigned_word size;
-  struct _memory_mapping *next;
-};
-
-struct _memory_map {
-  memory_mapping *first;
-};
-
-INLINE_MEMORY_MAP memory_map *
-new_memory_map(void)
-{
-  memory_map *new_map;
-  new_map = ZALLOC(memory_map);
-  return new_map;
-}
-
-STATIC_INLINE_MEMORY_MAP void
-memory_map_add_memory(memory_map *map,
-                     device_node *device,
-                     device_reader_callback *reader,
-                     device_writer_callback *writer,
-                     void *buffer,
-                     unsigned_word base,
-                     unsigned size)
-{
-  memory_mapping *new_mapping;
-  memory_mapping *next_mapping;
-  memory_mapping **last_mapping;
-
-  /* actually do occasionally get a zero size map */
-  if (size == 0)
-    return;
-
-  new_mapping = ZALLOC(memory_mapping);
-
-  /* ram */
-  new_mapping->buffer = buffer;
-  /* devices */
-  new_mapping->device = device;
-  new_mapping->reader = reader;
-  new_mapping->writer = writer;
-  /* common */
-  new_mapping->base = base;
-  new_mapping->size = size;
-  new_mapping->bound = base + size;
-
-  /* find the insertion point (between last/next) */
-  next_mapping = map->first;
-  last_mapping = &map->first;
-  while(next_mapping != NULL && next_mapping->bound <= new_mapping->base) {
-    /* assert: new_mapping->base > all bases before next_mapping */
-    /* assert: new_mapping->bound >= all bounds before next_mapping */
-    last_mapping = &next_mapping->next;
-    next_mapping = next_mapping->next;
-  }
-
-  /* check insertion point correct */
-  if (next_mapping != NULL && next_mapping->base < new_mapping->bound) {
-    error("memory_map_add_callback_memory() internal error - map overlap\n");
-  }
-
-  /* insert the new mapping */
-  *last_mapping = new_mapping;
-  new_mapping->next = next_mapping;
-
-}
-
-
-INLINE_MEMORY_MAP void
-memory_map_add_callback_memory(memory_map *map,
-                              device_node *device,
-                              device_reader_callback *reader,
-                              device_writer_callback *writer,
-                              unsigned_word base,
-                              unsigned size)
-{
-  memory_map_add_memory(map, device, reader, writer, NULL, base, size);
-}
-
-INLINE_MEMORY_MAP void
-memory_map_add_raw_memory(memory_map *map,
-                         void *buffer,
-                         unsigned_word base,
-                         unsigned size)
-{
-  memory_map_add_memory(map, NULL, NULL, NULL, buffer, base, size);
-}
-
-
-
-
-STATIC_INLINE_MEMORY_MAP memory_mapping *
-memory_map_find_mapping(memory_map *map,
-                       unsigned_word addr,
-                       unsigned nr_bytes,
-                       int abort,
-                       cpu *processor,
-                       unsigned_word cia)
-{
-  memory_mapping *mapping = map->first;
-  ASSERT((addr & (nr_bytes-1)) == 0);
-  while (1) {
-    if (addr >= mapping->base
-       && (addr + nr_bytes) <= mapping->bound)
-      break;
-    mapping = mapping->next;
-    if (mapping == NULL) {
-      if (abort) {
-       switch (CURRENT_ENVIRONMENT) {
-       case VIRTUAL_ENVIRONMENT:
-         data_storage_interrupt(processor,
-                                cia,
-                                addr,
-                                vea_storage_interrupt,
-                                0/* doesnt matter */);
-         break;
-       default:
-         error("memory_map_find_mapping() - %s%x%s%s%s%s%s",
-               "access to undefined address 0x", addr, "\n",
-               "this code should be passing back up the device tree an\n",
-               "abort event (with processor attached).  Somewhere in\n",
-               "the device tree this would be caught and either halt,\n",
-               "interrupt, or reset the processor\n");
-       }
-       return NULL;
-      }
-      else
-       return NULL;
-    }
-  }
-  return mapping;
-}
-
-
-STATIC_INLINE_MEMORY_MAP void *
-memory_map_translate(memory_mapping *mapping,
-                    unsigned_word addr)
-{
-  return mapping->buffer + addr - mapping->base;
-}
-
-
-INLINE_MEMORY_MAP unsigned
-memory_map_read_buffer(memory_map *map,
-                      void *buffer,
-                      unsigned_word addr,
-                      unsigned len,
-                      transfer_mode mode)
-{
-  unsigned count;
-  unsigned_1 byte;
-  for (count = 0; count < len; count++) {
-    unsigned pos = 0;
-    unsigned_word raddr = addr + count;
-    memory_mapping *mapping =
-      memory_map_find_mapping(map, raddr, 1,
-                             0/*abort*/,
-                             0, 0/*processor, cia*/);
-    if (mapping == NULL)
-      break;
-    if (mode == raw_transfer ||
-       CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER)
-      pos = count;
-    else if (mode == cooked_transfer)
-      pos = len-count-1;
-    else
-      error("memory_map_read_buffer() - transfer mode unknown\n");
-    if (mapping->reader != NULL)
-      /* hope it doesn't barf */
-      byte = mapping->reader(mapping->device,
-                            raddr - mapping->base,
-                            1,
-                            0, 0/*processor, cia*/);
-    else
-      byte = *(unsigned_1*)memory_map_translate(mapping,
-                                               raddr);
-    ((unsigned_1*)buffer)[pos] = T2H_1(byte);
-  }
-  return count;
-}
-
-
-INLINE_MEMORY_MAP unsigned
-memory_map_write_buffer(memory_map *map,
-                       const void *buffer,
-                       unsigned_word addr,
-                       unsigned len,
-                       transfer_mode mode)
-{
-  unsigned count;
-  unsigned_1 byte;
-  for (count = 0; count < len; count++) {
-    unsigned pos = 0;
-    unsigned_word raddr = addr + count;
-    memory_mapping *mapping =
-      memory_map_find_mapping(map, raddr, 1,
-                             0/*abort*/,
-                             0, 0/*processor, cia*/);
-    if (mapping == NULL)
-      break;
-    if (mode == raw_transfer || 
-       CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER)
-      pos = count;
-    else if (mode == cooked_transfer)
-      pos = len-count-1;
-    else
-      error("memory_map_write_buffer() - transfer mode unknown\n");
-    byte = H2T_1(((unsigned_1*)buffer)[pos]);
-    if (mapping->writer != NULL)
-      /* hope it doesn't barf */
-      mapping->writer(mapping->device,
-                     raddr - mapping->base,
-                     1,
-                     byte,
-                     0, 0/*processor, cia*/);
-    else
-      *(unsigned_1*)memory_map_translate(mapping, raddr) = byte;
-  }
-  return count;
-}
-
-
-INLINE_MEMORY_MAP unsigned
-memory_map_zero(memory_map *map,
-               unsigned_word addr,
-               unsigned len)
-{
-  unsigned pos;
-  for (pos = 0; pos < len; pos++) {
-    unsigned_word raddr = addr + pos;
-    memory_mapping *mapping =
-      memory_map_find_mapping(map, raddr, 1,
-                             0/*abort*/,
-                             0, 0/*processor, cia*/);
-    if (mapping == NULL)
-      break;
-    if (mapping->writer != NULL)
-      mapping->writer(mapping->device,
-                     raddr - mapping->base,
-                     1,
-                     0,
-                     0, 0/*processor, cia*/);
-    else
-      *(unsigned_1*)memory_map_translate(mapping, raddr) = 0;
-  }
-  return pos;
-}
-
-
-#define DEFINE_MEMORY_MAP_READ_N(N) \
-INLINE_MEMORY_MAP unsigned_##N \
-memory_map_read_##N(memory_map *map, \
-                   unsigned_word addr, \
-                   cpu *processor, \
-                   unsigned_word cia) \
-{ \
-  memory_mapping *mapping = memory_map_find_mapping(map, addr, \
-                                                   sizeof(unsigned_##N), \
-                                                   1, \
-                                                   processor, \
-                                                   cia); \
-  if (WITH_CALLBACK_MEMORY && mapping->reader != NULL) \
-    return ((unsigned_##N) \
-           mapping->reader(mapping->device, \
-                           addr - mapping->base, \
-                           sizeof(unsigned_##N), \
-                           processor, \
-                           cia)); \
-  else \
-    return T2H_##N(*(unsigned_##N*)memory_map_translate(mapping, addr)); \
-}
-
-DEFINE_MEMORY_MAP_READ_N(1)
-DEFINE_MEMORY_MAP_READ_N(2)
-DEFINE_MEMORY_MAP_READ_N(4)
-DEFINE_MEMORY_MAP_READ_N(8)
-DEFINE_MEMORY_MAP_READ_N(word)
-
-#define DEFINE_MEMORY_MAP_WRITE_N(N) \
-INLINE_MEMORY_MAP void \
-memory_map_write_##N(memory_map *map, \
-                    unsigned_word addr, \
-                    unsigned_##N val, \
-                    cpu *processor, \
-                    unsigned_word cia) \
-{ \
-  memory_mapping *mapping = memory_map_find_mapping(map, addr, \
-                                                   sizeof(unsigned_##N), \
-                                                   1, \
-                                                   processor, \
-                                                   cia); \
-  if (WITH_CALLBACK_MEMORY && mapping->writer != NULL) \
-    mapping->writer(mapping->device, \
-                   addr - mapping->base, \
-                   sizeof(unsigned_##N), \
-                   val, \
-                   processor, \
-                   cia); \
-  else \
-    *(unsigned_##N*)memory_map_translate(mapping, addr) = H2T_##N(val); \
-}
-
-DEFINE_MEMORY_MAP_WRITE_N(1)
-DEFINE_MEMORY_MAP_WRITE_N(2)
-DEFINE_MEMORY_MAP_WRITE_N(4)
-DEFINE_MEMORY_MAP_WRITE_N(8)
-DEFINE_MEMORY_MAP_WRITE_N(word)
-
-#endif /* _MEMORY_MAP_C_ */
diff --git a/sim/ppc/memory_map.h b/sim/ppc/memory_map.h
deleted file mode 100644 (file)
index c197f43..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*  This file is part of the program psim.
-
-    Copyright (C) 1994-1995, 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 _MEMORY_MAP_H_
-#define _MEMORY_MAP_H_
-
-#ifndef INLINE_MEMORY_MAP
-#define INLINE_MEMORY_MAP
-#endif
-
-/* basic types */
-
-typedef struct _memory_map memory_map;
-
-
-/* constructor */
-
-INLINE_MEMORY_MAP memory_map *new_memory_map
-(void);
-
-
-/* operators to add memory to a memory map
-
-   callback-memory:
-
-   includes a callback routine that is called upon for the data.
-   Useful when modeling memory mapped devices.
-
-   raw-memory:
-
-   normal base and bound memory map used to model ram or mapped memory
-   pages */
-
-INLINE_MEMORY_MAP void memory_map_add_callback_memory
-(memory_map *map,
- device_node *device,
- device_reader_callback *reader,
- device_writer_callback *writer,
- unsigned_word base,
- unsigned size); /* host limited */
-
-INLINE_MEMORY_MAP void memory_map_add_raw_memory
-(memory_map *map,
- void *buffer,
- unsigned_word base,
- unsigned size/*host limited*/);
-
-
-/* Variable sized read/write/zero:
-
-   Transfer (zero) a variable size block of data between the host and
-   target (possibly byte swapping it).  Should any problems occure,
-   the number of bytes actually transfered is returned. */
-
-INLINE_MEMORY_MAP unsigned memory_map_read_buffer
-(memory_map *map,
- void *buffer,
- unsigned_word addr,
- unsigned len,
- transfer_mode mode);
-
-INLINE_MEMORY_MAP unsigned memory_map_write_buffer
-(memory_map *map,
- const void *buffer,
- unsigned_word addr,
- unsigned len,
- transfer_mode mode);
-
-INLINE_MEMORY_MAP unsigned memory_map_zero
-(memory_map *map,
- unsigned_word addr,
- unsigned len);
-
-
-/* Fixed sized read/write:
-
-   Transfer a fixed amout of memory between the host and target.  The
-   memory always being translated and the operation always aborting
-   should a problem occure */
-
-#define DECLARE_MEMORY_MAP_WRITE_N(N) \
-INLINE_MEMORY_MAP void memory_map_write_##N \
-(memory_map *map, \
- unsigned_word addr, \
- unsigned_##N val, \
- cpu *processor, \
- unsigned_word cia);
-
-DECLARE_MEMORY_MAP_WRITE_N(1)
-DECLARE_MEMORY_MAP_WRITE_N(2)
-DECLARE_MEMORY_MAP_WRITE_N(4)
-DECLARE_MEMORY_MAP_WRITE_N(8)
-DECLARE_MEMORY_MAP_WRITE_N(word)
-
-#define DECLARE_MEMORY_MAP_READ_N(N) \
-INLINE_MEMORY_MAP unsigned_##N memory_map_read_##N \
-(memory_map *map, \
- unsigned_word addr, \
- cpu *processor, \
- unsigned_word cia);
-
-DECLARE_MEMORY_MAP_READ_N(1)
-DECLARE_MEMORY_MAP_READ_N(2)
-DECLARE_MEMORY_MAP_READ_N(4)
-DECLARE_MEMORY_MAP_READ_N(8)
-DECLARE_MEMORY_MAP_READ_N(word)
-
-#endif
index 6ac060194508ad0e6ad69a877476778a8a8f8890..496d36a5f89b9828784eb3c5e15c92aaf89387da 100644 (file)
@@ -184,10 +184,11 @@ do { \
 
    Byte swap a quantity the size of the targets word */
 
-#if WITH_64BIT_TARGET
+#if (WITH_TARGET_WORD_BITSIZE == 64)
 #define H2T_word(X) H2T_8(X)
 #define T2H_word(X) T2H_8(X)
-#else
+#endif
+#if (WITH_TARGET_WORD_BITSIZE == 32)
 #define H2T_word(X) H2T_4(X)
 #define T2H_word(X) T2H_4(X)
 #endif
index c032688bebad7412d91a989315f2a603612d8e24..25ea8eb3cecdcbfe01e75f02730d74bd20fcb61d 100644 (file)
@@ -30,6 +30,7 @@
 #include <signal.h>
 #include <sys/errno.h>
 #include <sys/param.h>
+#include <fcntl.h>
 
 #if (NetBSD >= 199306) /* here NetBSD as that is what we're emulating */
 #include <sys/syscall.h> /* FIXME - should not be including this one */
@@ -45,347 +46,675 @@ extern int errno;
 #include "system.h"
 
 
-void
-system_call(cpu *processor,
-           unsigned_word cia)
-{
-  switch (cpu_registers(processor)->gpr[0]) {
-    
-
-  case 1/*SYS_exit*/:
-#if (NetBSD >= 199306) && (SYS_exit != 1)
-#  error "SYS_exit"
+#ifndef STATIC_INLINE_SYSTEM
+#define STATIC_INLINE_SYSTEM STATIC_INLINE
 #endif
-    {
-      int status = (int)cpu_registers(processor)->gpr[3];
-      cpu_halt(processor, cia, was_exited, status);
-      break;
-    }
-    
 
-  case 3/*SYS_read*/:
-#if (NetBSD >= 199306) && (SYS_read != 3)
-#  error "SYS_read"
-#endif
-    {
-      void *scratch_buffer;
-      int d = (int)cpu_registers(processor)->gpr[3];
-      unsigned_word buf = cpu_registers(processor)->gpr[4];
-      int nbytes = cpu_registers(processor)->gpr[5];
-      int status;
-      int nr_moved;
-
-      /* get a tempoary bufer */
-      scratch_buffer = zalloc(cpu_registers(processor)->gpr[5]);
-
-      /* check if buffer exists by reading it */
-      nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
-                                        scratch_buffer,
-                                        buf,
-                                        nbytes,
-                                        raw_transfer);
-      if (nr_moved != nbytes)
-       error("system_call()read - check on buffer failed\n");
-      
-      /* read */
-      if (d == 0) {
-       status = fread (scratch_buffer, 1, nbytes, stdin);
-       if (status == 0 && ferror (stdin))
-         status = -1;
-      } else {
-       status = read (d, scratch_buffer, nbytes);
-      }
-
-      if (status == -1) {
-       cpu_registers(processor)->gpr[0] = errno;
-       break;
-      } else {
-       cpu_registers(processor)->gpr[0] = 0;
-       cpu_registers(processor)->gpr[3] = status;
-
-       if (status > 0) {
-         nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
-                                             scratch_buffer,
-                                             buf,
-                                             status,
-                                             raw_transfer,
-                                             0/*violate_ro*/);
-
-         if (nr_moved != nbytes)
-           error("system_call()read - write to buffer failed\n");
-       }
-      }
-      
-      zfree(scratch_buffer);
-      
-      break;
-    }
-    
 
-  case 4/*SYS_write*/:
-#if (NetBSD >= 199306) && (SYS_write != 4)
-#  error "SYS_write"
+#if (NetBSD >= 199306)
+#define SYS(X) ASSERT(call == (SYS_##X))
+#else
+#define SYS(X)
 #endif
-    {
-      void *scratch_buffer;
-      int nr_moved;
-      int d = (int)cpu_registers(processor)->gpr[3];
-      unsigned_word buf = cpu_registers(processor)->gpr[4];
-      int nbytes = cpu_registers(processor)->gpr[5];
-      int status;
-      
-      /* get a tempoary bufer */
-      scratch_buffer = zalloc(cpu_registers(processor)->gpr[5]);
-      
-      /* copy in */
-      nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
-                                        scratch_buffer,
-                                        buf,
-                                        nbytes,
-                                        raw_transfer);
-      if (nr_moved != nbytes) {
-       /* FIXME - should handle better */
-       error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n",
-             nr_moved, nbytes);
-      }
-      
-      /* write */
-      status = write(d, scratch_buffer, nbytes);
-      if (status == -1) {
-       cpu_registers(processor)->gpr[0] = errno;
-       break;
-      }
-      cpu_registers(processor)->gpr[0] = 0;
-      cpu_registers(processor)->gpr[3] = status;
-      
-      zfree(scratch_buffer);
-      
-      break;
-    }
-    
 
-  case 17/*SYS_break*/:
-#if (NetBSD >= 199306) && (SYS_break != 17)
-#  error "SYS_break"
+#if (NetBSD >= 199306 && PATH_MAX != 1024)
+#error "PATH_MAX not 1024"
+#elif !defined(PATH_MAX)
+#define PATH_MAX 1024
 #endif
-    {
-      /* pretend to extend the heap so that it reaches addresss
-         new_break while in truth, if growth is needed grow it by a
-         page aligned amount */
-      unsigned_word new_break = ALIGN_8(cpu_registers(processor)->gpr[3]);
-      unsigned_word old_break = core_data_upper_bound(cpu_core(processor));
-      signed_word delta = new_break - old_break;
-      if (delta > 0)
-       core_add_data(cpu_core(processor),
-                     ALIGN_PAGE(new_break) - old_break);
-      cpu_registers(processor)->gpr[0] = 0;
-      cpu_registers(processor)->gpr[3] = new_break;
-      break;
-    }
 
 
-  case 20/*SYS_getpid*/:
-#if (NetBSD >= 199306) && (SYS_getpid != 20)
-#  error "SYS_getpid"
-#endif
-    {
-      cpu_registers(processor)->gpr[3] = (int)getpid();
+STATIC_INLINE_SYSTEM char *
+read_string(cpu *processor,
+           char *dest,
+           unsigned_word addr,
+           unsigned nr_bytes)
+{
+  unsigned nr_moved = 0;
+  if (addr == 0)
+    return NULL;
+  while (1) {
+    if (vm_data_map_read_buffer(cpu_data_map(processor),
+                                &dest[nr_moved],
+                                addr + nr_moved,
+                                sizeof(dest[nr_moved]))
+       != sizeof(dest[nr_moved]))
+      return NULL;
+    if (dest[nr_moved] == '\0' || nr_moved >= nr_bytes)
       break;
-    }
-    
+    nr_moved++;
+  }
+  dest[nr_moved] = '\0';
+  return dest;
+}
 
-  case 37/*SYS_kill*/:
-#if (NetBSD >= 199306) && (SYS_kill != 37)
-#  error "SYS_kill"
-#endif
-    {
-      pid_t pid = cpu_registers(processor)->gpr[3];
-      int sig = cpu_registers(processor)->gpr[4];
-      TRACE(trace_tbd, ("SYS_kill - more to this than just a kill\n"));
-      cpu_halt(processor, cia, was_signalled, sig);
-      break;
-    }
-    
 
-  case 48/*SYS_sigprocmask*/:
-#if (NetBSD >= 199306) && (SYS_sigprocmask != 48)
-#  error "SYS_sigprocmask"
-#endif
-    {
-      natural_word how = cpu_registers(processor)->gpr[3];
-      unsigned_word set = cpu_registers(processor)->gpr[4];
-      unsigned_word oset = cpu_registers(processor)->gpr[5];
-      TRACE(trace_system, ("SYS_sigprocmask: how=%d, set=0x%x, oset=0x%x\n",
-                          how, set, oset));
-      cpu_registers(processor)->gpr[0] = 0;
-      cpu_registers(processor)->gpr[3] = 0;
-      cpu_registers(processor)->gpr[4] = set;
-      break;
-    }
+STATIC_INLINE_SYSTEM void
+write_status(cpu *processor,
+            int status)
+{
+  cpu_registers(processor)->gpr[3] = status;
+  if (status < 0)
+    cpu_registers(processor)->gpr[0] = errno;
+  else
+    cpu_registers(processor)->gpr[0] = 0;
+}
 
 
-  case 54/*SYS_ioctl*/:
-#if (NetBSD >= 199306) && (SYS_ioctl != 54)
-#  error "SYS_ioctl"
+STATIC_INLINE_SYSTEM void
+write_stat(cpu *processor,
+          unsigned_word addr,
+          struct stat buf)
+{
+  int nr_moved;
+  H2T(buf.st_dev);
+  H2T(buf.st_ino);
+  H2T(buf.st_mode);
+  H2T(buf.st_nlink);
+  H2T(buf.st_uid);
+  H2T(buf.st_gid);
+  H2T(buf.st_rdev);
+  H2T(buf.st_size);
+  H2T(buf.st_atime);
+  /* H2T(buf.st_spare1); */
+  H2T(buf.st_mtime);
+  /* H2T(buf.st_spare2); */
+  H2T(buf.st_ctime);
+  /* H2T(buf.st_spare3); */
+  H2T(buf.st_blksize);
+  H2T(buf.st_blocks);
+#if (NetBSD >= 199306)
+  H2T(buf.st_flags);
+  H2T(buf.st_gen);
 #endif
-    {
-      TRACE(trace_system, ("SYS_ioctl: d=%d, request=0x%x, argp=0x%x\n",
-                          cpu_registers(processor)->gpr[3], cpu_registers(processor)->gpr[4], cpu_registers(processor)->gpr[5]));
-      cpu_registers(processor)->gpr[0] = 0;
-      cpu_registers(processor)->gpr[3] = 0;
-      break;
-    }
+  nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
+                                     &buf,
+                                     addr,
+                                     sizeof(buf),
+                                     0/*violate_ro*/);
+  if (nr_moved != sizeof(buf))
+    error("write_stat() write failed\n");
+}
+
+  
+STATIC_INLINE_SYSTEM void
+do_exit(unsigned call,
+       cpu *processor,
+       unsigned_word cia)
+{
+  int status = (int)cpu_registers(processor)->gpr[3];
+  SYS(exit);
+  cpu_halt(processor, cia, was_exited, status);
+}
 
 
-  case 189/*SYS_fstat*/:
-#if (NetBSD >= 199306) && (SYS_fstat != 189)
-#  error "SYS_fstat"
-#endif
-    {
-      int fd = cpu_registers(processor)->gpr[3];
-      unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
-      struct stat buf;
-      int nr_moved;
-      int status;
-
-      /* check buffer all there, by reading it */
-      nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
-                                        &buf,
-                                        stat_buf_addr,
-                                        sizeof(buf),
-                                        raw_transfer);
-      if (nr_moved != sizeof(buf))
-       error("system_call()fstat - check on buffer failed\n");
-
-      /* do the fstat call */
-      status = fstat(fd, &buf);
-      if (status == -1) {
-       cpu_registers(processor)->gpr[0] = errno;
-       break;
-      }
-      cpu_registers(processor)->gpr[0] = 0;
-      cpu_registers(processor)->gpr[3] = 0;
-
-      H2T(buf.st_dev);
-      H2T(buf.st_ino);
-      H2T(buf.st_mode);
-      H2T(buf.st_nlink);
-      H2T(buf.st_uid);
-      H2T(buf.st_gid);
-      H2T(buf.st_rdev);
-      H2T(buf.st_size);
-      H2T(buf.st_atime);
-      /* H2T(buf.st_spare1); */
-      H2T(buf.st_mtime);
-      /* H2T(buf.st_spare2); */
-      H2T(buf.st_ctime);
-      /* H2T(buf.st_spare3); */
-      H2T(buf.st_blksize);
-      H2T(buf.st_blocks);
-#if (NetBSD >= 199306)
-      H2T(buf.st_flags);
-      H2T(buf.st_gen);
+STATIC_INLINE_SYSTEM void
+do_read(unsigned call,
+       cpu *processor,
+       unsigned_word cia)
+{
+  void *scratch_buffer;
+  int d = (int)cpu_registers(processor)->gpr[3];
+  unsigned_word buf = cpu_registers(processor)->gpr[4];
+  int nbytes = cpu_registers(processor)->gpr[5];
+  int status;
+  int nr_moved;
+  SYS(read);
+  
+  /* get a tempoary bufer */
+  scratch_buffer = zalloc(nbytes);
+  
+  /* check if buffer exists by reading it */
+  nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
+                                    scratch_buffer,
+                                    buf,
+                                    nbytes);
+  if (nr_moved != nbytes)
+    error("system_call()read - check on buffer failed\n");
+  
+  /* read */
+#if 0
+  if (d == 0) {
+    status = fread (scratch_buffer, 1, nbytes, stdin);
+    if (status == 0 && ferror (stdin))
+      status = -1;
+  }
 #endif
-      
+  status = read (d, scratch_buffer, nbytes);
+  
+  if (status == -1) {
+    cpu_registers(processor)->gpr[0] = errno;
+  } else {
+    cpu_registers(processor)->gpr[3] = status;
+    
+    if (status > 0) {
       nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
-                                         &buf,
-                                         stat_buf_addr,
-                                         sizeof(buf),
-                                         raw_transfer,
+                                         scratch_buffer,
+                                         buf,
+                                         status,
                                          0/*violate_ro*/);
-      break;
+      if (nr_moved != status)
+       error("system_call()read - write to buffer failed\n");
     }
+  }
+  
+  zfree(scratch_buffer);
+}
 
 
-  case 202/*SYS___sysctl*/:
-#if (NetBSD >= 199306) && (SYS___sysctl != 202)
-#  error "SYS__sysctl"
-#endif
-    {
-      /* call the arguments by their real name */
-      unsigned_word name = cpu_registers(processor)->gpr[3];
-      natural_word namelen = cpu_registers(processor)->gpr[4];
-      unsigned_word oldp = cpu_registers(processor)->gpr[5];
-      unsigned_word oldlenp = cpu_registers(processor)->gpr[6];
-      natural_word oldlen;
-      natural_word mib;
-      natural_word int_val;
-
-      /* pluck out the management information base id */
-      if (namelen < 1
-         || sizeof(mib) != vm_data_map_read_buffer(cpu_data_map(processor),
-                                                   &mib,
-                                                   name,
-                                                   sizeof(mib),
-                                                   cooked_transfer))
-       error("system_call()SYS___sysctl bad name[0]\n");
-      name += sizeof(mib);
-
-      /* see what to do with it ... */
-      switch (mib) {
-      case 6/*CTL_HW*/:
+STATIC_INLINE_SYSTEM void
+do_write(unsigned call,
+        cpu *processor,
+        unsigned_word cia)
+{
+  void *scratch_buffer = NULL;
+  int nr_moved;
+  int d = (int)cpu_registers(processor)->gpr[3];
+  unsigned_word buf = cpu_registers(processor)->gpr[4];
+  int nbytes = cpu_registers(processor)->gpr[5];
+  int status;
+  SYS(write);
+  
+  /* get a tempoary bufer */
+  scratch_buffer = zalloc(nbytes); /* FIXME - nbytes == 0 */
+  
+  /* copy in */
+  nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
+                                    scratch_buffer,
+                                    buf,
+                                    nbytes);
+  if (nr_moved != nbytes) {
+    /* FIXME - should handle better */
+    error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n",
+         nr_moved, nbytes);
+  }
+  
+  /* write */
+  status = write(d, scratch_buffer, nbytes);
+  if (status == -1) {
+    cpu_registers(processor)->gpr[0] = errno;
+  }
+  cpu_registers(processor)->gpr[3] = status;
+  
+  zfree(scratch_buffer);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_open(unsigned call,
+       cpu *processor,
+       unsigned_word cia)
+{
+  unsigned_word path_addr = cpu_registers(processor)->gpr[3];
+  char path_buf[PATH_MAX];
+  char *path = read_string(processor, path_buf, path_addr, PATH_MAX);
+  int flags = (int)cpu_registers(processor)->gpr[4];
+  int mode = (int)cpu_registers(processor)->gpr[4];
+  SYS(open);
+  write_status(processor, open(path, flags, mode));
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_close(unsigned call,
+        cpu *processor,
+        unsigned_word cia)
+{
+  int d = (int)cpu_registers(processor)->gpr[3];
+  SYS(close);
+  write_status(processor, close(d));
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_break(unsigned call,
+        cpu *processor,
+        unsigned_word cia)
+     /* just pass this onto the `vm' device */
+{
+  psim *system = cpu_system(processor);
+  const device *vm = psim_device(system, "/vm");
+  SYS(break);
+  vm->callback->ioctl(vm,
+                     system,
+                     processor,
+                     cia,
+                     0, /*ioctl*/
+                     NULL); /*ioctl-data*/
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_getpid(unsigned call,
+             cpu *processor,
+             unsigned_word cia)
+{
+  SYS(getpid);
+  cpu_registers(processor)->gpr[3] = (int)getpid();
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_getuid(unsigned call,
+         cpu *processor,
+         unsigned_word cia)
+{
+  SYS(getuid);
+  cpu_registers(processor)->gpr[3] = (int)getuid();
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_geteuid(unsigned call,
+          cpu *processor,
+          unsigned_word cia)
+{
+  SYS(geteuid);
+  cpu_registers(processor)->gpr[3] = (int)geteuid();
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_kill(unsigned call,
+       cpu *processor,
+       unsigned_word cia)
+{
+  pid_t pid = cpu_registers(processor)->gpr[3];
+  int sig = cpu_registers(processor)->gpr[4];
+  SYS(kill);
+  error("SYS_kill - more to this than just a kill\n");
+  cpu_halt(processor, cia, was_signalled, sig);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_sigprocmask(unsigned call,
+              cpu *processor,
+              unsigned_word cia)
+{
+  natural_word how = cpu_registers(processor)->gpr[3];
+  unsigned_word set = cpu_registers(processor)->gpr[4];
+  unsigned_word oset = cpu_registers(processor)->gpr[5];
+  SYS(sigprocmask);
+  TRACE(trace_system, ("SYS_sigprocmask: how=%d, set=0x%x, oset=0x%x\n",
+                      how, set, oset));
+  cpu_registers(processor)->gpr[3] = 0;
+  cpu_registers(processor)->gpr[4] = set;
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_ioctl(unsigned call,
+        cpu *processor,
+        unsigned_word cia)
+{
+  SYS(ioctl);
+  TRACE(trace_system, ("SYS_ioctl: d=%d, request=0x%x, argp=0x%x\n",
+                      cpu_registers(processor)->gpr[3], cpu_registers(processor)->gpr[4], cpu_registers(processor)->gpr[5]));
+  cpu_registers(processor)->gpr[3] = 0;
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_umask(unsigned call,
+        cpu *processor,
+        unsigned_word cia)
+{
+  SYS(umask);
+  cpu_registers(processor)->gpr[3] = umask(cpu_registers(processor)->gpr[3]);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_stat(unsigned call,
+       cpu *processor,
+       unsigned_word cia)
+{
+  char path_buf[PATH_MAX];
+  unsigned_word path_addr = cpu_registers(processor)->gpr[3];
+  unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
+  char *path = read_string(processor, path_buf, path_addr, PATH_MAX);
+  struct stat buf;
+  SYS(stat);
+  write_status(processor, stat(path, &buf));
+  write_stat(processor, stat_buf_addr, buf);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_fstat(unsigned call,
+        cpu *processor,
+        unsigned_word cia)
+{
+  int fd = cpu_registers(processor)->gpr[3];
+  unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
+  struct stat buf;
+  SYS(fstat);
+  write_status(processor, fstat(fd, &buf));
+  write_stat(processor, stat_buf_addr, buf);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_lstat(unsigned call,
+        cpu *processor,
+        unsigned_word cia)
+{
+  char path_buf[PATH_MAX];
+  unsigned_word path_addr = cpu_registers(processor)->gpr[3];
+  char *path = read_string(processor, path_buf, path_addr, PATH_MAX);
+  unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
+  struct stat buf;
+  SYS(lstat);
+  write_status(processor, stat(path, &buf));
+  write_stat(processor, stat_buf_addr, buf);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do___sysctl(unsigned call,
+          cpu *processor,
+          unsigned_word cia)
+{
+  /* call the arguments by their real name */
+  unsigned_word name = cpu_registers(processor)->gpr[3];
+  natural_word namelen = cpu_registers(processor)->gpr[4];
+  unsigned_word oldp = cpu_registers(processor)->gpr[5];
+  unsigned_word oldlenp = cpu_registers(processor)->gpr[6];
+  natural_word oldlen;
+  natural_word mib;
+  natural_word int_val;
+  SYS(__sysctl);
+
+  /* pluck out the management information base id */
+  if (namelen < 1)
+    error("system_call()SYS___sysctl bad name[0]\n");
+  mib = vm_data_map_read_word(cpu_data_map(processor),
+                             name,
+                             processor,
+                             cia);
+  name += sizeof(mib);
+  
+  /* see what to do with it ... */
+  switch (mib) {
+  case 6/*CTL_HW*/:
 #if (NetBSD >= 199306) && (CTL_HW != 6)
 #  error "CTL_HW"
 #endif
-       if (namelen < 2
-           || sizeof(mib) != vm_data_map_read_buffer(cpu_data_map(processor),
-                                                     &mib,
-                                                     name,
-                                                     sizeof(mib),
-                                                     cooked_transfer))
-         error("system_call()SYS___sysctl - CTL_HW - bad name[1]\n");
-       name += sizeof(mib);
-       switch (mib) {
-       case 7/*HW_PAGESIZE*/:
+    if (namelen < 2)
+      error("system_call()SYS___sysctl - CTL_HW - bad name[1]\n");
+    mib = vm_data_map_read_word(cpu_data_map(processor),
+                               name,
+                               processor,
+                               cia);
+    name += sizeof(mib);
+    switch (mib) {
+    case 7/*HW_PAGESIZE*/:
 #if (NetBSD >= 199306) && (HW_PAGESIZE != 7)
 #  error "HW_PAGESIZE"
 #endif
-         if (sizeof(oldlen) != vm_data_map_read_buffer(cpu_data_map(processor),
-                                                       &oldlen,
-                                                       oldlenp,
-                                                       sizeof(oldlen),
-                                                       cooked_transfer))
-           error("system_call()sysctl - CTL_HW.HW_PAGESIZE - oldlen read\n");
-         if (sizeof(natural_word) > oldlen)
-           error("system_call()sysctl - CTL_HW.HW_PAGESIZE - to small\n");
-         int_val = 8192;
-         oldlen = sizeof(int_val);
-         if (sizeof(int_val) != vm_data_map_write_buffer(cpu_data_map(processor),
-                                                         &int_val,
-                                                         oldp,
-                                                         sizeof(int_val),
-                                                         cooked_transfer,
-                                                         0/*violate_ro*/))
-           error("system_call()sysctl - CTL_HW.HW_PAGESIZE - int_val\n");
-         if (sizeof(oldlen) != vm_data_map_write_buffer(cpu_data_map(processor),
-                                                        &oldlen,
-                                                        oldlenp,
-                                                        sizeof(oldlen),
-                                                        cooked_transfer,
-                                                        0/*violate_ro*/))
-           error("system_call()sysctl - CTL_HW.HW_PAGESIZE - oldlen write\n");
-         break;
-       default:
-         error("sysctl() CTL_HW.%d unknown\n", mib);
-         break;
-       }
-       break;
-      default:
-       error("sysctl() name[0]=%s unknown\n", (int)mib);
-       break;
-      }
-      cpu_registers(processor)->gpr[0] = 0;
-      cpu_registers(processor)->gpr[3] = 0;
+      oldlen = vm_data_map_read_word(cpu_data_map(processor),
+                                    oldlenp,
+                                    processor,
+                                    cia);
+      if (sizeof(natural_word) > oldlen)
+       error("system_call()sysctl - CTL_HW.HW_PAGESIZE - to small\n");
+      int_val = 8192;
+      oldlen = sizeof(int_val);
+      vm_data_map_write_word(cpu_data_map(processor),
+                            oldp,
+                            int_val,
+                            processor,
+                            cia);
+      vm_data_map_write_word(cpu_data_map(processor),
+                            oldlenp,
+                            oldlen,
+                            processor,
+                            cia);
+      break;
+    default:
+      error("sysctl() CTL_HW.%d unknown\n", mib);
       break;
     }
-
-
+    break;
   default:
-    error("system_call() unimplemented system call %d, cia=0x%x, arg[0]=0x%x, lr=0x%x\n",
-         cpu_registers(processor)->gpr[0], cia, cpu_registers(processor)->gpr[3], LR);
+    error("sysctl() name[0]=%s unknown\n", (int)mib);
     break;
-    
   }
+  cpu_registers(processor)->gpr[3] = 0;
+}
+
+STATIC_INLINE_SYSTEM void
+unimp(unsigned call,
+      cpu *processor,
+      unsigned_word cia)
+{
+  error("unimplemented system call %d, cia=0x%x\n", call, cia);
+}
+
+
+typedef void (sys_handler)
+     (unsigned call,
+      cpu *processor,
+      unsigned_word cia);
+
+static sys_handler *(handlers[]) = {
+  unimp, /* SYS_syscall 0 */
+  do_exit, /* 1*/
+  unimp, /* SYS_fork 2 */
+  do_read, /* 3 */
+  do_write, /* 4 */
+  do_open, /* 5 */
+  do_close, /* 6 */
+  unimp, /* SYS_wait4  7 */
+  unimp, /* 8 is old creat */
+  unimp, /* SYS_link   9 */
+  unimp, /* SYS_unlink 10 */
+  unimp, /* 11 is obsolete execv */
+  unimp, /* SYS_chdir  12 */
+  unimp, /* SYS_fchdir 13 */
+  unimp, /* SYS_mknod  14 */
+  unimp, /* SYS_chmod  15 */
+  unimp, /* SYS_chown  16 */
+  do_break, /* 17 */
+  unimp, /* SYS_getfsstat      18 */
+  unimp, /* 19 is old lseek */
+  do_getpid, /* 20 */
+  unimp, /* SYS_mount  21 */
+  unimp, /* SYS_unmount        22 */
+  unimp, /* SYS_setuid 23 */
+  do_getuid, /* 24 */
+  do_geteuid, /* 25 */
+  unimp, /* SYS_ptrace 26 */
+  unimp, /* SYS_recvmsg        27 */
+  unimp, /* SYS_sendmsg        28 */
+  unimp, /* SYS_recvfrom       29 */
+  unimp, /* SYS_accept 30 */
+  unimp, /* SYS_getpeername    31 */
+  unimp, /* SYS_getsockname    32 */
+  unimp, /* SYS_access 33 */
+  unimp, /* SYS_chflags        34 */
+  unimp, /* SYS_fchflags       35 */
+  unimp, /* SYS_sync   36 */
+  do_kill, /* 37 */
+  unimp, /* 38 is old stat */
+  unimp, /* SYS_getppid        39 */
+  unimp, /* 40 is old lstat */
+  unimp, /* SYS_dup    41 */
+  unimp, /* SYS_pipe   42 */
+  unimp, /* SYS_getegid        43 */
+  unimp, /* SYS_profil 44 */
+  unimp, /* SYS_ktrace 45 */
+  unimp, /* SYS_sigaction      46 */
+  unimp, /* SYS_getgid 47 */
+  do_sigprocmask, /* 48 */
+  unimp, /* SYS_getlogin       49 */
+  unimp, /* SYS_setlogin       50 */
+  unimp, /* SYS_acct   51 */
+  unimp, /* SYS_sigpending     52 */
+  unimp, /* SYS_sigaltstack    53 */
+  do_ioctl, /* 54 */
+  unimp, /* SYS_reboot 55 */
+  unimp, /* SYS_revoke 56 */
+  unimp, /* SYS_symlink        57 */
+  unimp, /* SYS_readlink       58 */
+  unimp, /* SYS_execve 59 */
+  do_umask, /* 60 */
+  unimp, /* SYS_chroot 61 */
+  unimp, /* 62 is old fstat */
+  unimp, /* 63 is old getkerninfo */
+  unimp, /* 64 is old getpagesize */
+  unimp, /* SYS_msync  65 */
+  unimp, /* SYS_vfork  66 */
+  unimp, /* 67 is obsolete vread */
+  unimp, /* 68 is obsolete vwrite */
+  unimp, /* SYS_sbrk   69 */
+  unimp, /* SYS_sstk   70 */
+  unimp, /* 71 is old mmap */
+  unimp, /* SYS_vadvise        72 */
+  unimp, /* SYS_munmap 73 */
+  unimp, /* SYS_mprotect       74 */
+  unimp, /* SYS_madvise        75 */
+  unimp, /* 76 is obsolete vhangup */
+  unimp, /* 77 is obsolete vlimit */
+  unimp, /* SYS_mincore        78 */
+  unimp, /* SYS_getgroups      79 */
+  unimp, /* SYS_setgroups      80 */
+  unimp, /* SYS_getpgrp        81 */
+  unimp, /* SYS_setpgid        82 */
+  unimp, /* SYS_setitimer      83 */
+  unimp, /* 84 is old wait */
+  unimp, /* SYS_swapon 85 */
+  unimp, /* SYS_getitimer      86 */
+  unimp, /* 87 is old gethostname */
+  unimp, /* 88 is old sethostname */
+  unimp, /* 89 is old getdtablesize */
+  unimp, /* SYS_dup2   90 */
+  unimp, /* 91 */
+  unimp, /* SYS_fcntl  92 */
+  unimp, /* SYS_select 93 */
+  unimp, /* 94 */
+  unimp, /* SYS_fsync  95 */
+  unimp, /* SYS_setpriority    96 */
+  unimp, /* SYS_socket 97 */
+  unimp, /* SYS_connect        98 */
+  unimp, /* 99 is old accept */
+  unimp, /* SYS_getpriority    100 */
+  unimp, /* 101 is old send */
+  unimp, /* 102 is old recv */
+  unimp, /* SYS_sigreturn      103 */
+  unimp, /* SYS_bind   104 */
+  unimp, /* SYS_setsockopt     105 */
+  unimp, /* SYS_listen 106 */
+  unimp, /* 107 is obsolete vtimes */
+  unimp, /* 108 is old sigvec */
+  unimp, /* 109 is old sigblock */
+  unimp, /* 110 is old sigsetmask */
+  unimp, /* SYS_sigsuspend     111 */
+  unimp, /* 112 is old sigstack */
+  unimp, /* 113 is old recvmsg */
+  unimp, /* 114 is old sendmsg */
+  unimp, /* SYS_vtrace 115 - is obsolete vtrace */
+  unimp, /* SYS_gettimeofday   116 */
+  unimp, /* SYS_getrusage      117 */
+  unimp, /* SYS_getsockopt     118 */
+  unimp, /* SYS_resuba 119 */
+  unimp, /* SYS_readv  120 */
+  unimp, /* SYS_writev 121 */
+  unimp, /* SYS_settimeofday   122 */
+  unimp, /* SYS_fchown 123 */
+  unimp, /* SYS_fchmod 124 */
+  unimp, /* 125 is old recvfrom */
+  unimp, /* 126 is old setreuid */
+  unimp, /* 127 is old setregid */
+  unimp, /* SYS_rename 128 */
+  unimp, /* 129 is old truncate */
+  unimp, /* 130 is old ftruncate */
+  unimp, /* SYS_flock  131 */
+  unimp, /* SYS_mkfifo 132 */
+  unimp, /* SYS_sendto 133 */
+  unimp, /* SYS_shutdown       134 */
+  unimp, /* SYS_socketpair     135 */
+  unimp, /* SYS_mkdir  136 */
+  unimp, /* SYS_rmdir  137 */
+  unimp, /* SYS_utimes 138 */
+  unimp, /* 139 is obsolete 4.2 sigreturn */
+  unimp, /* SYS_adjtime        140 */
+  unimp, /* 141 is old getpeername */
+  unimp, /* 142 is old gethostid */
+  unimp, /* 143 is old sethostid */
+  unimp, /* 144 is old getrlimit */
+  unimp, /* 145 is old setrlimit */
+  unimp, /* 146 is old killpg */
+  unimp, /* SYS_setsid 147 */
+  unimp, /* SYS_quotactl       148 */
+  unimp, /* 149 is old quota */
+  unimp, /* 150 is old getsockname */
+  unimp, /* 151 */
+  unimp, /* 152 */
+  unimp, /* 153 */
+  unimp, /* 154 */
+  unimp, /* SYS_nfssvc 155 */
+  unimp, /* 156 is old getdirentries */
+  unimp, /* SYS_statfs 157 */
+  unimp, /* SYS_fstatfs        158 */
+  unimp, /* 159 */
+  unimp, /* 160 */
+  unimp, /* SYS_getfh  161 */
+  unimp, /* 162 is old getdomainname */
+  unimp, /* 163 is old setdomainname */
+  unimp, /* 164 is old uname */
+  unimp, /* SYS_sysarch        165 */
+  unimp, /* 166 */
+  unimp, /* 167 */
+  unimp, /* 168 */
+  unimp, /* SYS_semsys 169 */
+  unimp, /* SYS_msgsys 170 */
+  unimp, /* SYS_shmsys 171 */
+  unimp, /* 172 */
+  unimp, /* 173 */
+  unimp, /* 174 */
+  unimp, /* 175 */
+  unimp, /* 176 */
+  unimp, /* 177 */
+  unimp, /* 178 */
+  unimp, /* 179 */
+  unimp, /* 180 */
+  unimp, /* SYS_setgid 181 */
+  unimp, /* SYS_setegid        182 */
+  unimp, /* SYS_seteuid        183 */
+  unimp, /* SYS_lfs_bmapv      184 */
+  unimp, /* SYS_lfs_markv      185 */
+  unimp, /* SYS_lfs_segclean   186 */
+  unimp, /* SYS_lfs_segwait    187 */
+  do_stat, /* 188 */
+  do_fstat, /* 189 */
+  do_lstat, /* 190 */
+  unimp, /* SYS_pathconf       191 */
+  unimp, /* SYS_fpathconf      192 */
+  unimp, /* 193 */
+  unimp, /* SYS_getrlimit      194 */
+  unimp, /* SYS_setrlimit      195 */
+  unimp, /* SYS_getdirentries  196 */
+  unimp, /* SYS_mmap   197 */
+  unimp, /* SYS___syscall      198 */
+  unimp, /* SYS_lseek  199 */
+  unimp, /* SYS_truncate       200 */
+  unimp, /* SYS_ftruncate      201 */
+  do___sysctl, /* 202 */
+  unimp, /* SYS_mlock  203 */
+  unimp, /* SYS_munlock 204 */
+};
+    
+INLINE_SYSTEM void
+system_call(cpu *processor,
+           unsigned_word cia)
+{
+  unsigned call = cpu_registers(processor)->gpr[0];
+  if (call >= sizeof(handlers)/sizeof(handlers[0]))
+    error("system call %d out-of-range\n", call);
+  cpu_registers(processor)->gpr[0] = 0; /* default success */
+  handlers[call](call, processor, cia);
 }
 
 #endif /* _SYSTEM_C_ */
index 4a0df87123d05793f135afc54dd7e3680067ab99..709d5c5c17a844559f2f98170e0f072781cf36c6 100644 (file)
 #ifndef _SYSTEM_H_
 #define _SYSTEM_H_
 
-void system_call
+#ifndef INLINE_SYSTEM
+#define INLINE_SYSTEM
+#endif
+
+INLINE_SYSTEM void system_call
 (cpu *processor,
  unsigned_word cia);