Andrew's latest changes & print all instruction counts if -I
authorMichael Meissner <gnu@the-meissners.org>
Thu, 2 Nov 1995 14:27:18 +0000 (14:27 +0000)
committerMichael Meissner <gnu@the-meissners.org>
Thu, 2 Nov 1995 14:27:18 +0000 (14:27 +0000)
19 files changed:
sim/ppc/ChangeLog
sim/ppc/Makefile.in
sim/ppc/configure
sim/ppc/configure.in
sim/ppc/cpu.h
sim/ppc/debug.c [new file with mode: 0644]
sim/ppc/debug.h
sim/ppc/dgen.c [new file with mode: 0644]
sim/ppc/igen.c
sim/ppc/interrupts.c [new file with mode: 0644]
sim/ppc/main.c
sim/ppc/misc.c [new file with mode: 0644]
sim/ppc/mon.c [new file with mode: 0644]
sim/ppc/ppc-opcode-stupid [new file with mode: 0644]
sim/ppc/psim.c
sim/ppc/sim_calls.c
sim/ppc/std-config.h
sim/ppc/vm.c [new file with mode: 0644]
sim/ppc/vm_n.h [new file with mode: 0644]

index 66b2465..8094bdc 100644 (file)
@@ -1,3 +1,59 @@
+Thu Nov  2 08:54:04 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
+
+       * main.c (main): Call psim_print_info with verbose == 2.
+
+       * mon.c (mon_print_info): Align the cpu number and number of
+       instructions fields.  Do not print an instruction category if the
+       CPU did not execute any of those instructions.
+       
+       * configure.in: Add support for --enable-sim-opcode=stupid.
+       * configure: Regenerate.
+
+Wed Nov  1 23:46:59 1995  Andrew Cagney - aka Noid  <cagney@highland.com.au>
+
+       * std-config (INLINE_DEVICE_TREE): Don't inline either of
+        device_tree.c or devices.c.  There is no significant gain.
+
+       * configure.in, Makefile.in: add --enable-sim-icache=[0-9]* and
+       IGEN_ICACHE macro.
+       
+Wed Nov  1 23:46:59 1995  Andrew Cagney - aka Noid  <cagney@highland.com.au>
+
+       * igen.c (main), misc.h (target_a2i, i2target), misc.c: Add
+        functions to convert between target and igen internal bit numbers.
+        Make IO go through these functions. Add -b (bit size) and -h (high
+        bit nr) options to igen.  Typical usage would be: ./igen -b 16 -h
+        15 for a 16 bit instruction format with the msb given a number 15.
+
+Wed Nov  1 22:17:32 1995  Andrew Cagney - aka Noid  <cagney@highland.com.au>
+
+       * dgen.c (main): Was outputting optarg even when it was NULL.
+
+Tue Oct 31 23:48:33 1995  Andrew Cagney - aka Noid  <cagney@highland.com.au>
+
+       * vm_n.h (vm_data_map_load_N, vm_data_map_store_n), debug.h,
+        debug.c: Add tracing of load/store unit (virtual) with -t
+        load-store.
+
+Tue Oct 31 21:44:01 1995  Andrew Cagney - aka Noid  <cagney@highland.com.au>
+
+        * std-config.h (WITH_ENVIRONMENT): Add USER_ENVIRONMENT which does
+        not include things such as the time base and events.
+
+       * interrupt.c, sim_calls.c, cpu.h, vm.c, configure.in: Add UEA to
+       all environment switches for above.
+
+       * psim.c (psim_create): ditto - new device tree node name is
+        /options/environment-architecture with values user, virtual and
+        operating.
+
+Tue Oct 31 21:31:32 1995  Andrew Cagney - aka Noid  <cagney@highland.com.au>
+
+       * ppc-opcode-stupid: Third example of use of opcode table - this
+        one expands all mtspr/mfspr and branch instructions.  Appears to
+        give about a 10% gain in performance if everything enabled.  Also
+        takes about 150mb of swap to build.
+
 Wed Nov  1 10:49:48 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
 
        * emul_netbsd.c (do_exit): Print arguments and close parenthesis
index f2c7625..566d89e 100644 (file)
@@ -68,7 +68,7 @@ RANLIB = @RANLIB@
 
 HDEFINES = @HDEFINES@
 TDEFINES =
-IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER)
+IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER) $(IGEN_ICACHE)
 
 .NOEXPORT:
 MAKEOVERRIDES=
index 3b5059a..3d6b563 100755 (executable)
@@ -1057,7 +1057,7 @@ $srcdir/config.make Makefile CONFIG_FILE --enable-sim-config "$enable_sim_config
 
 $srcdir/config.make Makefile IGEN_OPCODE_RULES --enable-sim-opcode "$enable_sim_opcode" \
   "" "ppc-opcode-simple" "no" "ppc-opcode-simple" "yes" "ppc-opcode-simple" \
-  "complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" 1>&6
+  "complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" "stupid" "ppc-opcode-stupid" 1>&6
 
 $srcdir/config.make Makefile DGEN_FLAGS --enable-sim-switch "$enable_sim_switch" \
   "" "" "no" "" "yes" "-s" 1>&6
@@ -1068,6 +1068,9 @@ $srcdir/config.make Makefile IGEN_DUPLICATE --enable-sim-duplicate "$enable_sim_
 $srcdir/config.make Makefile IGEN_FILTER --enable-sim-filter "$enable_sim_filter" \
   "" "-f 64" "no" "" "yes" "-f 64" "*" "$enable_sim_filter" 1>&6
 
+$srcdir/config.make Makefile IGEN_ICACHE --enable-sim-icache "$enable_sim_icache" \
+  "" "" "no" "" "yes" "-r 1024" "*" "-r $enable_sim_icache" 1>&6
+
 flags=""
 if test x"$enable_sim_inline" != x""; then
   case "$enable_sim_inline" in
@@ -1126,7 +1129,9 @@ $srcdir/config.hdr config.h WITH_HOST_WORD_BITSIZE --enable-sim-hostbitsize "$en
 $srcdir/config.hdr config.h WITH_ENVIRONMENT --enable-sim-env "$enable_sim_env" \
   "yes" "0" \
   "operating" "OPERATING_ENVIRONMENT" "os" "OPERATING_ENVIRONMENT" "oea" "OPERATING_ENVIRONMENT" \
-  "virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" 1>&6
+  "virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" \
+  "user" "USER_ENVIRONMENT" "uea" "USER_ENVIRONMENT" \
+  1>&6
 
 $srcdir/config.hdr config.h WITH_TIME_BASE --enable-sim-timebase "$enable_sim_timebase" \
   "no" "0" "yes" "1" 1>&6
index 7b319f5..2f24d64 100644 (file)
@@ -48,7 +48,7 @@ $srcdir/config.make Makefile CONFIG_FILE --enable-sim-config "$enable_sim_config
 
 $srcdir/config.make Makefile IGEN_OPCODE_RULES --enable-sim-opcode "$enable_sim_opcode" \
   "" "ppc-opcode-simple" "no" "ppc-opcode-simple" "yes" "ppc-opcode-simple" \
-  "complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" 1>&6
+  "complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" "stupid" "ppc-opcode-stupid" 1>&6
 
 $srcdir/config.make Makefile DGEN_FLAGS --enable-sim-switch "$enable_sim_switch" \
   "" "" "no" "" "yes" "-s" 1>&6
@@ -59,6 +59,9 @@ $srcdir/config.make Makefile IGEN_DUPLICATE --enable-sim-duplicate "$enable_sim_
 $srcdir/config.make Makefile IGEN_FILTER --enable-sim-filter "$enable_sim_filter" \
   "" "-f 64" "no" "" "yes" "-f 64" "*" "$enable_sim_filter" 1>&6
 
+$srcdir/config.make Makefile IGEN_ICACHE --enable-sim-icache "$enable_sim_icache" \
+  "" "" "no" "" "yes" "-r 1024" "*" "-r $enable_sim_icache" 1>&6
+
 flags=""
 if test x"$enable_sim_inline" != x""; then
   case "$enable_sim_inline" in
@@ -117,7 +120,9 @@ $srcdir/config.hdr config.h WITH_HOST_WORD_BITSIZE --enable-sim-hostbitsize "$en
 $srcdir/config.hdr config.h WITH_ENVIRONMENT --enable-sim-env "$enable_sim_env" \
   "yes" "0" \
   "operating" "OPERATING_ENVIRONMENT" "os" "OPERATING_ENVIRONMENT" "oea" "OPERATING_ENVIRONMENT" \
-  "virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" 1>&6
+  "virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" \
+  "user" "USER_ENVIRONMENT" "uea" "USER_ENVIRONMENT" \
+  1>&6
 
 $srcdir/config.hdr config.h WITH_TIME_BASE --enable-sim-timebase "$enable_sim_timebase" \
   "no" "0" "yes" "1" 1>&6
index f9790e8..a4e4b02 100644 (file)
 #include "basics.h"
 #include "registers.h"
 #include "device_tree.h"
-#include "memory_map.h"
 #include "core.h"
 #include "vm.h"
 #include "events.h"
 #include "interrupts.h"
 #include "psim.h"
 #include "icache.h"
+#include "itable.h"
+#include "mon.h"
 
 
 /* typedef struct _cpu cpu;
@@ -50,14 +51,20 @@ INLINE_CPU cpu *cpu_create
 (psim *system,
  core *memory,
  event_queue *events,
+ cpu_mon *monitor,
  int cpu_nr);
 
+INLINE_CPU void cpu_init
+(cpu *processor);
 
 /* Find our way home */
 
 INLINE_CPU psim *cpu_system
 (cpu *processor);
 
+INLINE_CPU cpu_mon *cpu_monitor
+(cpu *processor);
+
 INLINE_CPU int cpu_nr
 (cpu *processor);
 
@@ -108,16 +115,21 @@ INLINE_CPU void cpu_halt
  int signal);
 
 
-#if WITH_IDECODE_CACHE
-/* gain acces to the processors instruction cracking cache
+#if WITH_IDECODE_CACHE_SIZE
+/* Return the cache entry that matches the given CIA.  No guarentee
+   that the cache entry actually contains the instruction for that
+   address */
 
-   Only useful (and visable) if we're cracking the cache */
-INLINE_CPU idecode_cache *cpu_icache
+INLINE_CPU idecode_cache *cpu_icache_entry
+(cpu *processor,
+ unsigned_word cia);
+
+INLINE_CPU void cpu_flush_icache
 (cpu *processor);
 #endif
 
 
-/* reveal the processor address maps
+/* reveal the processors VM:
 
    At first sight it may seem better to, instead of exposing the cpu's
    inner vm maps, to have the cpu its self provide memory manipulation
@@ -128,13 +140,10 @@ INLINE_CPU idecode_cache *cpu_icache
    the vm protection (eg store breakpoint instruction in the
    instruction map). */
 
-INLINE_CPU vm_instruction_map *cpu_instruction_map
-(cpu *processor);
-
 INLINE_CPU vm_data_map *cpu_data_map
 (cpu *processor);
 
-INLINE_CPU core *cpu_core
+INLINE_CPU vm_instruction_map *cpu_instruction_map
 (cpu *processor);
 
 
@@ -149,16 +158,11 @@ INLINE_CPU memory_reservation *cpu_reservation
 (cpu *processor);
 
 
-INLINE_CPU void cpu_increment_number_of_insns
-(cpu *processor);
-
-INLINE_CPU long cpu_get_number_of_insns
-(cpu *processor);
-
 INLINE_CPU void cpu_print_info
 (cpu *processor,
  int verbose);
 
+
 /* Registers:
 
    This model exploits the PowerPC's requirement for a synchronization
@@ -173,15 +177,20 @@ INLINE_CPU void cpu_synchronize_context
 (cpu *processor);
 
 #define IS_PROBLEM_STATE(PROCESSOR) \
-(CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT \
- || (cpu_registers(PROCESSOR)->msr & msr_problem_state))
+(CURRENT_ENVIRONMENT == OPERATING_ENVIRONMENT \
+ ? (cpu_registers(PROCESSOR)->msr & msr_problem_state) \
+ : 1)
 
 #define IS_64BIT_MODE(PROCESSOR) \
-((CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT && WITH_64BIT_TARGET) \
- || (cpu_registers(PROCESSOR)->msr & msr_64bit_mode))
+(WITH_TARGET_WORD_BITSIZE == 64 \
+ ? (CURRENT_ENVIRONMENT == OPERATING_ENVIRONMENT \
+    ? (cpu_registers(PROCESSOR)->msr & msr_64bit_mode) \
+    : 1) \
+ : 0)
 
 #define IS_FP_AVAILABLE(PROCESSOR) \
-(CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT \
- || (cpu_registers(PROCESSOR)->msr & msr_floating_point_available))
+(CURRENT_ENVIRONMENT == OPERATING_ENVIRONMENT \
+ ? (cpu_registers(PROCESSOR)->msr & msr_floating_point_available) \
+ : 1)
 
 #endif
diff --git a/sim/ppc/debug.c b/sim/ppc/debug.c
new file mode 100644 (file)
index 0000000..b23644c
--- /dev/null
@@ -0,0 +1,114 @@
+/*  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 _DEBUG_C_
+#define _DEBUG_C_
+
+#include "basics.h"
+#include <stdlib.h>
+
+int ppc_trace[nr_trace_options];
+int print_info;
+
+typedef struct _trace_option_descriptor {
+  trace_options option;
+  const char *name;
+  const char *description;
+} trace_option_descriptor;
+
+static trace_option_descriptor trace_description[] = {
+  { trace_gdb, "gdb", "calls made by gdb to the sim_calls.c file" },
+  { trace_os_emul, "os-emul", "VEA mode sytem calls - like strace/spy" },
+  /* decode/issue */
+  { trace_semantics, "semantics", "Instruction execution (issue)" },
+  { trace_idecode, "idecode", "instruction decode (when miss in cache)" },
+  { trace_alu, "alu", "results of integer ALU" },
+  { trace_load_store, "load-store", "transfers to from data registers" },
+  /* devices */
+  { trace_device_tree, "device-tree",  },
+  { trace_devices, "devices" },
+  { trace_pass_device, "pass-device" },
+  { trace_console_device, "console-device" },
+  { trace_icu_device, "icu-device" },
+  { trace_halt_device, "halt-device" },
+  { trace_register_device, "register-device" },
+  { trace_vm_device, "vm-device" },
+  { trace_memory_device, "memory-device" },
+  { trace_htab_device, "htab-device" },
+  { trace_pte_device, "pte-device" },
+  { trace_binary_device, "binary-device" },
+  { trace_file_device, "file-device" },
+  { trace_core_device, "core-device" },
+  { trace_stack_device, "stack-device" },
+  /* misc */
+  /* sentinal */
+  { nr_trace_options, NULL },
+};
+
+extern void
+trace_option(const char *option)
+{
+  int setting = 1;
+  if (option[0] == '!') {
+    setting = 0; /* clear it */
+    option += 1;
+  }
+  if (strcmp(option, "all") == 0) {
+    trace_options i;
+    for (i = 0; i < nr_trace_options; i++)
+      ppc_trace[i] = setting;
+  }
+  else {
+    int i = 0;
+    while (trace_description[i].option < nr_trace_options
+          && strcmp(option, trace_description[i].name) != 0)
+      i++;
+    if (trace_description[i].option < nr_trace_options)
+      ppc_trace[trace_description[i].option] = setting;
+    else {
+      i = strtoul(option, 0, 0);
+      if (i > 0 && i < nr_trace_options)
+       ppc_trace[i] = setting;
+      else
+       error("Unknown trace option: %s\n", option);
+    }
+      
+  }
+}
+
+
+extern void
+trace_usage(void)
+{
+  const char *format = "\t%-18s%s\n";
+  int i;
+  printf_filtered("Possible <trace-option>s are:\n");
+  printf_filtered(format, "!<trace-option>", "Disable the specified option");
+  printf_filtered(format, "all", "enable all the trace options");
+  for (i = 0; trace_description[i].option < nr_trace_options; i++)
+    printf_filtered(format,
+                   trace_description[i].name,
+                   (trace_description[i].description
+                    ? trace_description[i].description
+                    : ""));
+}
+
+#endif /* _DEBUG_C_ */
index b300add..e1cb053 100644 (file)
@@ -50,6 +50,7 @@ typedef enum {
   trace_semantics,
   trace_idecode,
   trace_alu,
+  trace_load_store,
   /**/
   trace_vm,
   trace_core,
diff --git a/sim/ppc/dgen.c b/sim/ppc/dgen.c
new file mode 100644 (file)
index 0000000..2d6d3a3
--- /dev/null
@@ -0,0 +1,319 @@
+/*  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.
+    */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "misc.h"
+#include "lf.h"
+#include "table.h"
+
+/****************************************************************/
+
+int spreg_lookup_table = 1;
+int number_lines = 1;
+enum {
+  nr_of_sprs = 1024,
+};
+
+/****************************************************************/
+
+
+typedef enum {
+  spreg_name,
+  spreg_reg_nr,
+  spreg_readonly,
+  spreg_length,
+  nr_spreg_fields,
+} spreg_fields;
+
+typedef struct _spreg_table_entry spreg_table_entry;
+struct _spreg_table_entry {
+  char *name;
+  int spreg_nr;
+  int is_readonly;
+  int length;
+  table_entry *entry;
+  spreg_table_entry *next;
+};
+
+typedef struct _spreg_table spreg_table;
+struct _spreg_table {
+  spreg_table_entry *sprs;
+};
+
+static void
+spreg_table_insert(spreg_table *table, table_entry *entry)
+{
+  /* create a new spr entry */
+  spreg_table_entry *new_spr = ZALLOC(spreg_table_entry);
+  new_spr->next = NULL;
+  new_spr->entry = entry;
+  new_spr->spreg_nr = atoi(entry->fields[spreg_reg_nr]);
+  new_spr->is_readonly = (entry->fields[spreg_readonly]
+                         ? atoi(entry->fields[spreg_readonly])
+                         : 0);
+  new_spr->length = atoi(entry->fields[spreg_length]);
+  new_spr->name = (char*)zalloc(strlen(entry->fields[spreg_name]) + 1);
+  ASSERT(new_spr->name != NULL);
+  {
+    int i;
+    for (i = 0; entry->fields[spreg_name][i] != '\0'; i++) {
+      if (isupper(entry->fields[spreg_name][i]))
+       new_spr->name[i] = tolower(entry->fields[spreg_name][i]);
+      else
+       new_spr->name[i] = entry->fields[spreg_name][i];
+    }
+  }
+
+  /* insert, by spreg_nr order */
+  {
+    spreg_table_entry **ptr_to_spreg_entry = &table->sprs;
+    spreg_table_entry *spreg_entry = *ptr_to_spreg_entry;
+    while (spreg_entry != NULL && spreg_entry->spreg_nr < new_spr->spreg_nr) {
+      ptr_to_spreg_entry = &spreg_entry->next;
+      spreg_entry = *ptr_to_spreg_entry;
+    }
+    ASSERT(spreg_entry == NULL || spreg_entry->spreg_nr != new_spr->spreg_nr);
+    *ptr_to_spreg_entry = new_spr;
+    new_spr->next = spreg_entry;
+  }
+
+}
+
+
+static spreg_table *
+spreg_table_load(char *file_name)
+{
+  table *file = table_open(file_name, nr_spreg_fields);
+  spreg_table *table = ZALLOC(spreg_table);
+
+  {
+    table_entry *entry;
+    while ((entry = table_entry_read(file)) != NULL) {
+      spreg_table_insert(table, entry);
+    }
+  }
+
+  return table;
+}
+
+
+/****************************************************************/
+
+char *spreg_attributes[] = {
+  "is_valid",
+  "is_readonly",
+  "name",
+  "index",
+  "length",
+  0
+};
+
+static void
+gen_spreg_h(spreg_table *table, lf *file)
+{
+  spreg_table_entry *entry;
+  char **attribute;
+
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _SPREG_H_\n");
+  lf_printf(file, "#define _SPREG_H_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef INLINE_SPREG\n");
+  lf_printf(file, "#define INLINE_SPREG\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef unsigned_word spreg;\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef enum {\n");
+
+  for (entry = table->sprs;
+       entry != NULL ;
+       entry = entry->next) {
+    lf_printf(file, "  spr_%s = %d,\n", entry->name, entry->spreg_nr);
+  }
+
+  lf_printf(file, "  nr_of_sprs = %d\n", nr_of_sprs);
+  lf_printf(file, "} sprs;\n");
+  lf_printf(file, "\n");
+  for (attribute = spreg_attributes;
+       *attribute != NULL;
+       attribute++) {
+    if (strcmp(*attribute, "name") == 0)
+      lf_printf(file, "INLINE_SPREG char *spr_%s(sprs spr);\n",
+               *attribute);
+    else
+      lf_printf(file, "INLINE_SPREG int spr_%s(sprs spr);\n",
+               *attribute);
+  }
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _SPREG_H_ */\n");
+}
+
+
+static void
+gen_spreg_c(spreg_table *table, lf *file)
+{
+  spreg_table_entry *entry;
+  char **attribute;
+  int spreg_nr;
+
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _SPREG_C_\n");
+  lf_printf(file, "#define _SPREG_C_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"words.h\"\n");
+  lf_printf(file, "#include \"spreg.h\"\n");
+
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef struct _spreg_info {\n");
+  lf_printf(file, "  char *name;\n");
+  lf_printf(file, "  int is_valid;\n");
+  lf_printf(file, "  int length;\n");
+  lf_printf(file, "  int is_readonly;\n");
+  lf_printf(file, "  int index;\n");
+  lf_printf(file, "} spreg_info;\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "static spreg_info spr_info[nr_of_sprs+1] = {\n");
+  entry = table->sprs;
+  for (spreg_nr = 0; spreg_nr < nr_of_sprs+1; spreg_nr++) {
+    if (entry == NULL || spreg_nr < entry->spreg_nr)
+      lf_printf(file, "  { 0, 0, 0, 0, %d},\n", spreg_nr);
+    else {
+      lf_printf(file, "  { \"%s\", %d, %d, %d, spr_%s /*%d*/ },\n",
+               entry->name, 1, entry->length, entry->is_readonly,
+               entry->name, entry->spreg_nr);
+      entry = entry->next;
+    }
+  }
+  lf_printf(file, "};\n");
+
+  for (attribute = spreg_attributes;
+       *attribute != NULL;
+       attribute++) {
+    lf_printf(file, "\n");
+    if (strcmp(*attribute, "name") == 0)
+      lf_printf(file, "INLINE_SPREG char *\n");
+    else
+      lf_printf(file, "INLINE_SPREG int\n");
+    lf_printf(file, "spr_%s(sprs spr)\n", *attribute);
+    lf_printf(file, "{\n");
+    if (spreg_lookup_table
+       || strcmp(*attribute, "name") == 0
+       || strcmp(*attribute, "index") == 0)
+      lf_printf(file, "  return spr_info[spr].%s;\n",
+               *attribute);
+    else {
+      spreg_table_entry *entry;
+      lf_printf(file, "  switch (spr) {\n");
+      for (entry = table->sprs; entry != NULL; entry = entry->next) {
+       lf_printf(file, "  case %d:\n", entry->spreg_nr);
+       if (strcmp(*attribute, "is_valid") == 0)
+         lf_printf(file, "    return 1;\n");
+       else if (strcmp(*attribute, "is_readonly") == 0)
+         lf_printf(file, "    return %d;\n", entry->is_readonly);
+       else if (strcmp(*attribute, "length") == 0)
+         lf_printf(file, "    return %d;\n", entry->length);
+       else
+         ASSERT(0);
+      }
+      lf_printf(file, "  default:\n");
+      lf_printf(file, "    return 0;\n");
+      lf_printf(file, "  }\n");
+    }
+    lf_printf(file, "}\n");
+  }
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _SPREG_C_ */\n");
+}
+
+
+
+/****************************************************************/
+
+
+int
+main(int argc,
+     char **argv,
+     char **envp)
+{
+  spreg_table *sprs = NULL;
+  char *real_file_name = NULL;
+  int ch;
+
+  if (argc <= 1) {
+    printf("Usage: dgen ...\n");
+    printf("-s  Use switch instead of table\n");
+    printf("-n  Use this as cpp line numbering name\n");
+    printf("-[Pp] <spreg>  Output spreg.h(P) or spreg.c(p)\n");
+    printf("-l  Suppress cpp line numbering in output files\n");
+  }
+
+
+  while ((ch = getopt(argc, argv, "lsn:r:P:p:")) != -1) {
+    fprintf(stderr, "\t-%c %s\n", ch, ( optarg ? optarg : ""));
+    switch(ch) {
+    case 'l':
+      number_lines = 0;
+      break;
+    case 's':
+      spreg_lookup_table = 0;
+      break;
+    case 'r':
+      sprs = spreg_table_load(optarg);
+      break;
+    case 'n':
+      real_file_name = strdup(optarg);
+      break;
+    case 'P':
+    case 'p':
+      {
+       lf *file = lf_open(optarg, real_file_name, number_lines);
+       switch (ch) {
+       case 'P':
+         gen_spreg_h(sprs, file);
+         break;
+       case 'p':
+         gen_spreg_c(sprs, file);
+         break;
+       }
+       lf_close(file);
+      }
+      real_file_name = NULL;
+      break;
+    default:
+      error("unknown option\n");
+    }
+  }
+  return 0;
+}
index 78c1494..cab46a0 100644 (file)
 /****************************************************************/
 
 enum {
-  insn_size = 32,
+  max_insn_size = 32,
 };
 
+int hi_bit_nr = 0;
+int insn_size = max_insn_size;
 int idecode_expand_semantics = 0;
 int idecode_cache = 0;
 int number_lines = 1;
@@ -51,7 +53,6 @@ char *cache_semantic_actual = "processor, entry, cia";
 char *semantic_formal = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia";
 char *semantic_actual = "processor, instruction, cia";
 
-char *semantic_local = "unsigned_word nia = cia + 4;";
 
 
 /****************************************************************/
@@ -98,7 +99,7 @@ load_cache_rules(char *file_name)
   cache_rules **curr_rule = &table;
   while ((entry = table_entry_read(file)) != NULL) {
     cache_rules *new_rule = ZALLOC(cache_rules);
-    new_rule->valid = a2i(entry->fields[ca_valid]);
+    new_rule->valid = target_a2i(hi_bit_nr, entry->fields[ca_valid]);
     new_rule->old_name = entry->fields[ca_old_name];
     new_rule->new_name = entry->fields[ca_new_name];
     new_rule->type = (strlen(entry->fields[ca_type])
@@ -184,10 +185,10 @@ load_opcode_rules(char *file_name)
   opcode_rules **curr_rule = &table;
   while ((entry = table_entry_read(file)) != NULL) {
     opcode_rules *new_rule = ZALLOC(opcode_rules);
-    new_rule->first = a2i(entry->fields[op_first]);
-    new_rule->last = a2i(entry->fields[op_last]);
-    new_rule->force_first = a2i(entry->fields[op_force_first]);
-    new_rule->force_last = a2i(entry->fields[op_force_last]);
+    new_rule->first = target_a2i(hi_bit_nr, entry->fields[op_first]);
+    new_rule->last = target_a2i(hi_bit_nr, entry->fields[op_last]);
+    new_rule->force_first = target_a2i(hi_bit_nr, entry->fields[op_force_first]);
+    new_rule->force_last = target_a2i(hi_bit_nr, entry->fields[op_force_last]);
     new_rule->force_slash = a2i(entry->fields[op_force_slash]);
     new_rule->force_expansion = entry->fields[op_force_expansion];
     new_rule->use_switch = a2i(entry->fields[op_use_switch]);
@@ -253,7 +254,7 @@ struct _insn_field {
 
 typedef struct _insn_fields insn_fields;
 struct _insn_fields {
-  insn_field *bits[insn_size];
+  insn_field *bits[max_insn_size];
   insn_field *first;
   insn_field *last;
   unsigned value;
@@ -350,7 +351,7 @@ parse_insn_format(table_entry *entry,
     /* the pos */
     new_field->pos_string = (char*)zalloc(strlen_pos+1);
     strncpy(new_field->pos_string, start_pos, strlen_pos);
-    new_field->first = a2i(new_field->pos_string);
+    new_field->first = target_a2i(hi_bit_nr, new_field->pos_string);
     new_field->last = new_field->next->first - 1; /* guess */
     new_field->width = new_field->last - new_field->first + 1; /* guess */
     new_field->prev->last = new_field->first-1; /*fix*/
@@ -1119,7 +1120,8 @@ lf_print_idecode_table(lf *file,
     lf_print_table_name(file, entry);
     lf_printf(file, ";\n");
     lf_printf(file, "int opcode = EXTRACTED32(instruction, %d, %d);\n",
-             entry->opcode->first, entry->opcode->last);
+             i2target(hi_bit_nr, entry->opcode->first),
+             i2target(hi_bit_nr, entry->opcode->last));
     lf_printf(file, "idecode_table_entry *table_entry = table + opcode;\n");
     lf_printf(file, "while (1) {\n");
     lf_indent(file, +2);
@@ -1660,7 +1662,8 @@ lf_print_c_extraction(lf *file,
     if (!get_value_from_cache) {
       if (strcmp(field_name, cur_field->val_string) == 0)
        lf_printf(file, "EXTRACTED32(instruction, %d, %d)",
-                 cur_field->first, cur_field->last);
+                 i2target(hi_bit_nr, cur_field->first),
+                 i2target(hi_bit_nr, cur_field->last));
       else if (field_expression != NULL)
        lf_printf(file, "%s", field_expression);
       else
@@ -1949,8 +1952,7 @@ lf_print_c_semantic(lf *file,
   lf_print_my_prefix(file,
                     instruction->file_entry,
                     0/*not putting value in cache*/);
-  lf_putstr(file, semantic_local);
-  lf_printf(file, "\n");
+  lf_printf(file, "unsigned_word nia = cia + %d;\n", insn_size / 8);
 
   lf_printf(file, "\n");
   lf_print_c_extractions(file,
@@ -2231,11 +2233,13 @@ idecode_table_leaf(insn_table *entry,
       lf_printf(file, "  /*%d*/ { ", entry->opcode_nr);
       if (entry->opcode->is_boolean)
        lf_printf(file, "MASK32(%d,%d), 0, ",
-                 entry->opcode->first, entry->opcode->last);
+                 i2target(hi_bit_nr, entry->opcode->first),
+                 i2target(hi_bit_nr, entry->opcode->last));
       else
        lf_printf(file, "%d, MASK32(%d,%d), ",
                  insn_size - entry->opcode->last - 1,
-                 entry->opcode->first, entry->opcode->last);
+                 i2target(hi_bit_nr, entry->opcode->first),
+                 i2target(hi_bit_nr, entry->opcode->last));
       lf_print_table_name(file, entry);
       lf_printf(file, " },\n");
     }
@@ -2289,7 +2293,8 @@ idecode_switch_start(insn_table *table,
   ASSERT(table->opcode_rule->use_switch);
 
   lf_printf(file, "switch (EXTRACTED32(instruction, %d, %d)) {\n",
-           table->opcode->first, table->opcode->last);
+           i2target(hi_bit_nr, table->opcode->first),
+           i2target(hi_bit_nr, table->opcode->last));
 }
 
 
@@ -2726,21 +2731,27 @@ main(int argc,
 
   if (argc == 1) {
     printf("Usage:\n");
-    printf("-f <filter-out-flag>  eg -f 64 to skip 64bit instructions\n");
-    printf("-[Ii] <instruction-table>  -I to dump internal table\n");
-    printf("-[Oo] <opcode-rules>\n");
-    printf("-[Kk] <cache-rules>\n");
-    printf("-[Ss] <schematic>  output schematic.h(S) schematic.c(s)\n");
-    printf("-[Dd] <schematic>  output idecode.h(S) idecode.c(s)\n");
-    printf("-[Tt] <table>      output itable.h(t) itable.c(t)\n");
-    printf("-[Cc] <schematic>  output icache.h(S) invalid(s)\n");
-    printf("-e  Expand (duplicate) semantic functions\n");
-    printf("-r <size>  Generate a cracking cache of <size>\n");
-    printf("-l  Supress includsion of CPP line numbering in output files\n");
+    printf("  igen <config-opts> ... <input-opts>... <output-opts>...\n");
+    printf("Config options:\n");
+    printf("  -f <filter-out-flag>  eg -f 64 to skip 64bit instructions\n");
+    printf("  -e    Expand (duplicate) semantic functions\n");
+    printf("  -r <icache-size>  Generate cracking cache version\n");
+    printf("  -l    Supress line numbering in output files\n");
+    printf("  -b <bit-size>  Set the number of bits in an instruction\n");
+    printf("  -h <high-bit>  Set the nr of the high (msb bit)\n");
+    printf("Input options (ucase version also dumps loaded table):\n");
+    printf("  -[Oo] <opcode-rules>\n");
+    printf("  -[Kk] <cache-rules>\n");
+    printf("  -[Ii] <instruction-table>\n");
+    printf("Output options:\n");
+    printf("  -[Cc] <output-file>  output icache.h(C) invalid(c)\n");
+    printf("  -[Dd] <output-file>  output idecode.h(D) idecode.c(d)\n");
+    printf("  -[Ss] <output-file>  output schematic.h(S) schematic.c(s)\n");
+    printf("  -[Tt] <table>      output itable.h(T) itable.c(t)\n");
   }
 
   while ((ch = getopt(argc, argv,
-                     "ler:f:I:i:O:o:K:k:n:S:s:D:d:T:t:C:")) != -1) {
+                     "leb:h:r:f:I:i:O:o:K:k:n:S:s:D:d:T:t:C:")) != -1) {
     fprintf(stderr, "\t-%c %s\n", ch, (optarg ? optarg : ""));
     switch(ch) {
     case 'l':
@@ -2752,6 +2763,15 @@ main(int argc,
     case 'r':
       idecode_cache = a2i(optarg);
       break;
+    case 'b':
+      insn_size = a2i(optarg);
+      ASSERT(insn_size > 0 && insn_size <= max_insn_size
+            && (hi_bit_nr == insn_size-1 || hi_bit_nr == 0));
+      break;
+    case 'h':
+      hi_bit_nr = a2i(optarg);
+      ASSERT(hi_bit_nr == insn_size-1 || hi_bit_nr == 0);
+      break;
     case 'f':
       {
        filter *new_filter = ZALLOC(filter);
diff --git a/sim/ppc/interrupts.c b/sim/ppc/interrupts.c
new file mode 100644 (file)
index 0000000..453ebdb
--- /dev/null
@@ -0,0 +1,413 @@
+/*  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 _INTERRUPTS_C_
+#define _INTERRUPTS_C_
+
+#ifndef STATIC_INLINE_INTERRUPTS
+#define STATIC_INLINE_INTERRUPTS STATIC_INLINE
+#endif
+
+#include <signal.h>
+
+#include "cpu.h"
+#include "idecode.h"
+#include "os_emul.h"
+
+
+/* Operating environment support code
+
+   Unlike the VEA, the OEA must fully model the effect an interrupt
+   has on the processors state.
+
+   Each function below return updated values for registers effected by
+   interrupts */
+
+
+STATIC_INLINE_INTERRUPTS msreg
+interrupt_msr(msreg old_msr,
+             msreg msr_clear,
+             msreg msr_set)
+{
+  msreg msr_set_to_0 = (msr_branch_trace_enable
+                       | msr_data_relocate
+                       | msr_external_interrupt_enable
+                       | msr_floating_point_exception_mode_0
+                       | msr_floating_point_exception_mode_1
+                       | msr_floating_point_available
+                       | msr_instruction_relocate
+                       | msr_power_management_enable
+                       | msr_problem_state
+                       | msr_recoverable_interrupt
+                       | msr_single_step_trace_enable);
+  /* remember, in 32bit mode msr_64bit_mode is zero */
+  msreg new_msr = ((((old_msr & ~msr_set_to_0)
+                    | msr_64bit_mode)
+                   & ~msr_clear)
+                  | msr_set);
+  return new_msr;
+}
+
+
+STATIC_INLINE_INTERRUPTS msreg
+interrupt_srr1(msreg old_msr,
+              msreg srr1_clear,
+              msreg srr1_set)
+{
+  spreg srr1_mask = (MASK(0,32)
+                      | MASK(37, 41)
+                      | MASK(48, 63));
+  spreg srr1 = (old_msr & srr1_mask & ~srr1_clear) | srr1_set;
+  return srr1;
+}
+
+
+STATIC_INLINE_INTERRUPTS unsigned_word
+interrupt_base_ea(msreg msr)
+{
+  if (msr & msr_interrupt_prefix)
+    return MASK(0, 43);
+  else
+    return 0;
+}
+
+
+/* finish off an interrupt for the OEA model, updating all registers
+   and forcing a restart of the processor */
+
+STATIC_INLINE_INTERRUPTS unsigned_word
+perform_oea_interrupt(cpu *processor,
+                     unsigned_word cia,
+                     unsigned_word vector_offset,
+                     msreg msr_clear,
+                     msreg msr_set,
+                     msreg srr1_clear,
+                     msreg srr1_set)
+{
+  msreg old_msr = MSR;
+  msreg new_msr = interrupt_msr(old_msr, msr_clear, msr_set);
+  unsigned_word nia;
+  if (!(old_msr & msr_recoverable_interrupt))
+    error("perform_oea_interrupt() recoverable_interrupt bit clear, cia=0x%x, msr=0x%x\n",
+         cia, old_msr);
+  SRR0 = (spreg)(cia);
+  SRR1 = interrupt_srr1(old_msr, srr1_clear, srr1_set);
+  MSR = new_msr;
+  nia = interrupt_base_ea(new_msr) + vector_offset;
+  cpu_synchronize_context(processor);
+  return nia;
+}
+
+
+INLINE_INTERRUPTS void machine_check_interrupt
+(cpu *processor,
+ unsigned_word cia)
+{
+  switch (CURRENT_ENVIRONMENT) {
+
+  case USER_ENVIRONMENT:
+  case VIRTUAL_ENVIRONMENT:
+    error("%s - cia=0x%x\n",
+         "machine_check_interrupt", cia);
+
+  case OPERATING_ENVIRONMENT:
+    cia = perform_oea_interrupt(processor, cia, 0x00200, 0, 0, 0, 0);
+    cpu_restart(processor, cia);
+
+  default:
+    error("machine_check_interrupt() - internal error\n");
+
+  }
+}
+
+
+INLINE_INTERRUPTS void
+data_storage_interrupt(cpu *processor,
+                      unsigned_word cia,
+                      unsigned_word ea,
+                      storage_interrupt_reasons reason,
+                      int is_store)
+{
+  switch (CURRENT_ENVIRONMENT) {
+
+  case USER_ENVIRONMENT:
+  case VIRTUAL_ENVIRONMENT:
+    error("data_storage_interrupt() should not be called in VEA mode\n");
+
+  case OPERATING_ENVIRONMENT:
+    {
+      spreg direction = (is_store ? dsisr_store_operation : 0);
+      switch (reason) {
+      case direct_store_storage_interrupt:
+       DSISR = dsisr_direct_store_error_exception | direction;
+       break;
+      case hash_table_miss_storage_interrupt:
+       DSISR = dsisr_hash_table_or_dbat_miss | direction;
+       break;
+      case protection_violation_storage_interrupt:
+       DSISR = dsisr_protection_violation | direction;
+       break;
+      case earwax_violation_storage_interrupt:
+       DSISR = dsisr_earwax_violation | direction;
+       break;
+      case segment_table_miss_storage_interrupt:
+       DSISR = dsisr_segment_table_miss | direction;
+       break;
+      case earwax_disabled_storage_interrupt:
+       DSISR = dsisr_earwax_disabled | direction;
+       break;
+      default:
+       error("data_storage_interrupt: unknown reason %d\n", reason);
+       break;
+      }
+      DAR = (spreg)ea;
+      cia = perform_oea_interrupt(processor, cia, 0x00300, 0, 0, 0, 0);
+      cpu_restart(processor, cia);
+    }
+
+  default:
+    error("data_storage_interrupt() - internal error\n");
+
+  }
+}
+
+
+INLINE_INTERRUPTS void
+instruction_storage_interrupt(cpu *processor,
+                             unsigned_word cia,
+                             storage_interrupt_reasons reason)
+{
+  switch (CURRENT_ENVIRONMENT) {
+
+  case USER_ENVIRONMENT:
+  case VIRTUAL_ENVIRONMENT:
+    error("instruction_storage_interrupt - cia=0x%x - not implemented\n",
+         cia);
+
+  case OPERATING_ENVIRONMENT:
+    {
+      unsigned_word nia;
+      msreg srr1_set;
+      switch(reason) {
+      case hash_table_miss_storage_interrupt:
+       srr1_set = srr1_hash_table_or_ibat_miss;
+       break;
+      case direct_store_storage_interrupt:
+       srr1_set = srr1_direct_store_error_exception;
+       break;
+      case protection_violation_storage_interrupt:
+       srr1_set = srr1_protection_violation;
+       break;
+      case segment_table_miss_storage_interrupt:
+       srr1_set = srr1_segment_table_miss;
+       break;
+      default:
+       srr1_set = 0;
+       error("instruction_storage_interrupt: unknown reason %d\n", reason);
+       break;
+      }
+      cia = perform_oea_interrupt(processor, cia, 0x00400, 0, 0, 0, srr1_set);
+      cpu_restart(processor, cia);
+    }
+
+  default:
+    error("instruction_storage_interrupt() - internal error\n");
+
+  }
+}
+
+
+
+INLINE_INTERRUPTS void alignment_interrupt
+(cpu *processor,
+ unsigned_word cia,
+ unsigned_word ra)
+{
+  switch (CURRENT_ENVIRONMENT) {
+
+  case USER_ENVIRONMENT:
+  case VIRTUAL_ENVIRONMENT:
+    error("%s - cia=0x%x, ra=0x%x\n",
+         "alignment_interrupt", cia, ra);
+    
+  case OPERATING_ENVIRONMENT:
+    DAR = (spreg)ra;
+    DSISR = 0; /* FIXME */
+    cia = perform_oea_interrupt(processor, cia, 0x00600, 0, 0, 0, 0);
+    cpu_restart(processor, cia);
+
+  default:
+    error("alignment_interrupt() - internal error\n");
+    
+  }
+}
+
+
+
+
+INLINE_INTERRUPTS void
+program_interrupt(cpu *processor,
+                 unsigned_word cia,
+                 program_interrupt_reasons reason)
+{
+  switch (CURRENT_ENVIRONMENT) {
+
+  case USER_ENVIRONMENT:
+  case VIRTUAL_ENVIRONMENT:
+    switch (reason) {
+    default:
+      error("%s - cia=0x%x, reason=%d - not implemented\n",
+           "program_interrupt", cia, reason);
+    }
+
+  case OPERATING_ENVIRONMENT:
+    {
+      msreg srr1_set;
+      switch (reason) {
+      case illegal_instruction_program_interrupt:
+       srr1_set = srr1_illegal_instruction;
+       break;
+      case privileged_instruction_program_interrupt:
+       srr1_set = srr1_priviliged_instruction;
+       break;
+      case trap_program_interrupt:
+       srr1_set = srr1_trap;
+       break;
+      default:
+       srr1_set = 0;
+       error("program_interrupt - cia=0x%x, reason=%d(%s) - not implemented\n",
+             cia, reason);
+      }
+      cia = perform_oea_interrupt(processor, cia, 0x00700, 0, 0, 0, srr1_set);
+      cpu_restart(processor, cia);
+    }
+
+  default:
+    error("program_interrupt() - internal error\n");
+
+  }
+}
+
+
+INLINE_INTERRUPTS void
+floating_point_unavailable_interrupt(cpu *processor,
+                                    unsigned_word cia)
+{
+  switch (CURRENT_ENVIRONMENT) {
+    
+  case USER_ENVIRONMENT:
+  case VIRTUAL_ENVIRONMENT:
+    error("%s - cia=0x%x - not implemented\n",
+         "floating_point_unavailable_interrupt", cia);
+
+  case OPERATING_ENVIRONMENT:
+    cia = perform_oea_interrupt(processor, cia, 0x00800, 0, 0, 0, 0);
+    cpu_restart(processor, cia);
+
+  default:
+    error("floating_point_unavailable_interrupt() - internal error\n");
+
+  }
+}
+
+
+INLINE_INTERRUPTS void
+system_call_interrupt(cpu *processor,
+                     unsigned_word cia)
+{
+  switch (CURRENT_ENVIRONMENT) {
+
+  case USER_ENVIRONMENT:
+  case VIRTUAL_ENVIRONMENT:
+    os_emul_call(processor, cia);
+    cpu_restart(processor, cia+4);
+
+  case OPERATING_ENVIRONMENT:
+    cia = perform_oea_interrupt(processor, cia+4, 0x00c00, 0, 0, 0, 0);
+    cpu_restart(processor, cia);
+
+  default:
+    error("system_call_interrupt() - internal error\n");
+
+  }
+}
+
+INLINE_INTERRUPTS void
+trace_interrupt(cpu *processor,
+               unsigned_word cia);
+
+INLINE_INTERRUPTS void
+floating_point_assist_interrupt(cpu *processor,
+                               unsigned_word cia)
+{
+  switch (CURRENT_ENVIRONMENT) {
+
+  case USER_ENVIRONMENT:
+  case VIRTUAL_ENVIRONMENT:
+    error("%s - cia=0x%x - not implemented\n",
+         "floating_point_assist_interrupt", cia);
+
+  case OPERATING_ENVIRONMENT:
+    cia = perform_oea_interrupt(processor, cia, 0x00e00, 0, 0, 0, 0);
+    cpu_restart(processor, cia);
+
+  default:
+    error("floating_point_assist_interrupt() - internal error\n");
+
+  }
+}
+
+
+
+/* handle an externally generated event */
+
+INLINE_INTERRUPTS int
+decrementer_interrupt(cpu *processor)
+{
+  if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
+    unsigned_word cia = cpu_get_program_counter(processor);
+    unsigned_word nia = perform_oea_interrupt(processor,
+                                             cia, 0x00900, 0, 0, 0, 0);
+    cpu_set_program_counter(processor, nia);
+    return 1;
+  }
+  else {
+    return 0;
+  }
+}
+
+INLINE_INTERRUPTS int
+external_interrupt(cpu *processor)
+{
+  if (cpu_registers(processor)->msr & msr_external_interrupt_enable) {
+    unsigned_word cia = cpu_get_program_counter(processor);
+    unsigned_word nia = perform_oea_interrupt(processor,
+                                             cia, 0x00500, 0, 0, 0, 0);
+    cpu_set_program_counter(processor, nia);
+    return 1;
+  }
+  else {
+    return 0; /* not delivered */
+  }
+}
+
+
+#endif /* _INTERRUPTS_C_ */
index 1227940..47f506d 100644 (file)
@@ -70,7 +70,9 @@ zfree(void *chunk)
 static void
 usage(void)
 {
-  error ("Usage: psim [ -a -p -c -C -s -i -I -t -g ] <image> [ <image-args> ... ]\n");
+  printf_filtered("Usage:\n\tpsim [ -t <trace-option> ] <image> [ <image-args> ... ]\n");
+  trace_usage();
+  error("");
 }
 
 int
@@ -87,37 +89,15 @@ main(int argc, char **argv)
 
   /* check for arguments -- note sim_calls.c also contains argument processing
      code for the simulator linked within gdb.  */
-  while ((letter = getopt (argc, argv, "acCiIpstg")) != EOF)
+  while ((letter = getopt (argc, argv, "It:")) != EOF)
     {
       switch (letter) {
-      case 'a':
-       for (i = 0; i < nr_trace; i++)
-         ppc_trace[i] = 1;
-       break;
-      case 'p':
-       ppc_trace[trace_cpu] = ppc_trace[trace_semantics] = 1;
-       break;
-      case 'c':
-       ppc_trace[trace_core] = 1;
-       break;
-      case 'C':
-       ppc_trace[trace_console_device] = 1;
-       break;
-      case 's':
-       ppc_trace[trace_create_stack] = 1;
-       break;
-      case 'i':
-       ppc_trace[trace_icu_device] = 1;
+      case 't':
+       trace_option(optarg);
        break;
       case 'I':
        print_info = 1;
        break;
-      case 't':
-       ppc_trace[trace_device_tree] = 1;
-       break;
-      case 'g':
-       ppc_trace[trace_gdb] = 1;
-       break;
       default:
        usage();
       }
@@ -127,7 +107,7 @@ main(int argc, char **argv)
   name_of_file = argv[optind];
 
   /* create the simulator */
-  system = psim_create(name_of_file, ((WITH_SMP > 0) ? WITH_SMP : 1));
+  system = psim_create(name_of_file);
 
   /* fudge the environment so that _=prog-name */
   arg_ = (char*)zalloc(strlen(argv[optind]) + strlen("_=") + 1);
@@ -143,7 +123,7 @@ main(int argc, char **argv)
 
   /* any final clean up */
   if (print_info)
-    psim_print_info (system, 1);
+    psim_print_info (system, 2);
 
   /* why did we stop */
   status = psim_get_status(system);
@@ -158,8 +138,8 @@ main(int argc, char **argv)
     return status.signal;
   case was_signalled:
     printf ("%s: Caught signal %d at address 0x%lx\n",
-           name_of_file, (int)status.signal,
-           (long)status.program_counter);
+           name_of_file, (int)status.signal,
+           (long)status.program_counter);
     return status.signal;
   default:
     error("unknown halt condition\n");
diff --git a/sim/ppc/misc.c b/sim/ppc/misc.c
new file mode 100644 (file)
index 0000000..8c62ad2
--- /dev/null
@@ -0,0 +1,107 @@
+/*  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.
+    */
+
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "misc.h"
+
+void
+error (char *msg, ...)
+{
+  va_list ap;
+  va_start(ap, msg);
+  vprintf(msg, ap);
+  va_end(ap);
+  exit (1);
+}
+
+void *
+zalloc(long size)
+{
+  void *memory = malloc(size);
+  if (memory == NULL)
+    error("zalloc failed\n");
+  bzero(memory, size);
+  return memory;
+}
+
+void
+dumpf (int indent, char *msg, ...)
+{
+  va_list ap;
+  for (; indent > 0; indent--)
+    printf(" ");
+  va_start(ap, msg);
+  vprintf(msg, ap);
+  va_end(ap);
+}
+
+
+int
+it_is(const char *flag,
+      const char *flags)
+{
+  int flag_len = strlen(flag);
+  while (*flags != '\0') {
+    if (!strncmp(flags, flag, flag_len)
+       && (flags[flag_len] == ',' || flags[flag_len] == '\0'))
+      return 1;
+    while (*flags != ',') {
+      if (*flags == '\0')
+       return 0;
+      flags++;
+    }
+    flags++;
+  }
+  return 0;
+}
+
+
+unsigned
+a2i(const char *a)
+{
+  return strtoul(a, 0, 0);
+}
+
+unsigned
+target_a2i(int ms_bit_nr,
+          const char *a)
+{
+  if (ms_bit_nr)
+    return (ms_bit_nr - strtoul(a, 0, 0));
+  else
+    return strtoul(a, 0, 0);
+}
+
+unsigned
+i2target(int ms_bit_nr,
+        unsigned bit)
+{
+  if (ms_bit_nr)
+    return ms_bit_nr - bit;
+  else
+    return bit;
+}
+
+
diff --git a/sim/ppc/mon.c b/sim/ppc/mon.c
new file mode 100644 (file)
index 0000000..60b6fdb
--- /dev/null
@@ -0,0 +1,189 @@
+/*  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 _MON_C_
+#define _MON_C_
+
+#ifndef STATIC_INLINE_MON
+#define STATIC_INLINE_MON STATIC_INLINE
+#endif
+
+#include <string.h>
+
+#include "basics.h"
+#include "cpu.h"
+#include "mon.h"
+
+struct _cpu_mon {
+  unsigned issue_count[nr_itable_entries];
+  unsigned read_count;
+  unsigned write_count;
+};
+
+struct _mon {
+  int nr_cpus;
+  cpu_mon cpu_monitor[MAX_NR_PROCESSORS];
+};
+
+
+INLINE_MON mon *
+mon_create(void)
+{
+  mon *monitor = ZALLOC(mon);
+  return monitor;
+}
+
+
+INLINE_MON cpu_mon *
+mon_cpu(mon *monitor,
+       int cpu_nr)
+{
+  if (cpu_nr < 0 || cpu_nr >= MAX_NR_PROCESSORS)
+    error("mon_cpu() - invalid cpu number\n");
+  return &monitor->cpu_monitor[cpu_nr];
+}
+
+
+INLINE_MON void
+mon_init(mon *monitor,
+        int nr_cpus)
+{
+  bzero(monitor, sizeof(*monitor));
+  monitor->nr_cpus = nr_cpus;
+}
+
+
+INLINE_MON void
+mon_issue(itable_index index,
+         cpu *processor, 
+         unsigned_word cia)
+{
+  cpu_mon *monitor = cpu_monitor(processor);
+  ASSERT(index <= nr_itable_entries);
+  monitor->issue_count[index] += 1;
+}
+
+
+INLINE_MON void
+mon_read(unsigned_word ea,
+        unsigned_word ra,
+        unsigned nr_bytes,
+        cpu *processor,
+        unsigned_word cia)
+{
+  cpu_mon *monitor = cpu_monitor(processor);
+  monitor->read_count += 1;
+}
+
+
+INLINE_MON void
+mon_write(unsigned_word ea,
+         unsigned_word ra,
+         unsigned nr_bytes,
+         cpu *processor,
+         unsigned_word cia)
+{
+  cpu_mon *monitor = cpu_monitor(processor);
+  monitor->write_count += 1;
+}
+
+
+STATIC_INLINE_MON unsigned
+mon_get_number_of_insns(cpu_mon *monitor)
+{
+  itable_index index;
+  unsigned total_insns = 0;
+  for (index = 0; index < nr_itable_entries; index++)
+    total_insns += monitor->issue_count[index];
+  return total_insns;
+}
+
+STATIC_INLINE_MON char *
+mon_add_commas(char *buf,
+              int sizeof_buf,
+              long value)
+{
+  int comma = 3;
+  char *endbuf = buf + sizeof_buf - 1;
+
+  *--endbuf = '\0';
+  do {
+    if (comma-- == 0)
+      {
+       *--endbuf = ',';
+       comma = 2;
+      }
+
+    *--endbuf = (value % 10) + '0';
+  } while ((value /= 10) != 0);
+
+  ASSERT(endbuf >= buf);
+  return endbuf;
+}
+
+
+INLINE_MON void
+mon_print_info(mon *monitor,
+              int verbose)
+{
+  char buffer[20];
+  int cpu_nr;
+  int len_cpu;
+  int len_num = 0;
+  int len;
+
+  for (cpu_nr = 0; cpu_nr < monitor->nr_cpus; cpu_nr++) {
+    len = strlen (mon_add_commas(buffer,
+                                sizeof(buffer),
+                                mon_get_number_of_insns(&monitor->cpu_monitor[cpu_nr])));
+    if (len_num < len)
+      len_num = len;
+  }
+  
+  sprintf (buffer, "%d", (int)monitor->nr_cpus + 1);
+  len_cpu = strlen (buffer);
+
+  for (cpu_nr = 0; cpu_nr < monitor->nr_cpus; cpu_nr++) {
+
+    if (verbose > 1) {
+      itable_index index;
+      for (index = 0; index < nr_itable_entries; index++) {
+       if (monitor->cpu_monitor[cpu_nr].issue_count[index])
+         printf_filtered("CPU #%*d executed %*s %s instruction%s.\n",
+                         len_cpu, cpu_nr+1,
+                         len_num, mon_add_commas(buffer,
+                                                 sizeof(buffer),
+                                                 monitor->cpu_monitor[cpu_nr].issue_count[index]),
+                         itable[index].name,
+                         (monitor->cpu_monitor[cpu_nr].issue_count[index] == 1) ? "" : "s");
+      }
+    }
+    
+    printf_filtered("CPU #%d executed %s instructions in total.\n",
+                   cpu_nr+1,
+                   mon_add_commas(buffer,
+                                  sizeof(buffer),
+                                  mon_get_number_of_insns(&monitor->cpu_monitor[cpu_nr])));
+
+  }
+}
+
+#endif /* _MON_C_ */
diff --git a/sim/ppc/ppc-opcode-stupid b/sim/ppc/ppc-opcode-stupid
new file mode 100644 (file)
index 0000000..39795c8
--- /dev/null
@@ -0,0 +1,96 @@
+#
+#   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.
+#
+#   Instruction decode:
+#
+#   The table that follows is used by gen to construct a decision tree
+#   that can identify each possible instruction.  Gen then outputs this
+#   decision tree as (according to config) a table or switch statement
+#   as the function idecode.
+#
+#   In parallel to this, as mentioned above, WITH_EXPANDED_SEMANTICS
+#   determines of the semantic functions themselves should be expanded
+#   in a similar way.
+#
+#   The table contains the following entries:
+#
+#   <valid>
+#
+#   Must be 1 for the entry to be considered.  The last entry must be
+#   zero.
+#      
+#   <first>
+#   <last>
+#
+#   Range of bits (within the instruction) that should be searched for
+#   an instruction field.  Within such ranges, gen looks for opcodes
+#   (constants), registers (strings) and reserved bits (slash) and
+#   according to the rules that follows includes or excludes them from
+#   a possible instruction field.
+#
+#   <force_first>
+#   <force_last>
+#
+#   If an instructioin field was found, enlarge the field size so that
+#   it is forced to at least include bits starting from <force_first>
+#   (<force_last>).  To stop this occuring, use <force_first> = <last>
+#   + 1 and <force_last> = <first> - 1.
+#
+#   <force_slash>
+#
+#   Treat `/' fields as a constant instead of variable when looking for
+#   an instruction field.
+#
+#   <force_expansion>
+#
+#   Treat any contained register (string) fields as constant when
+#   determining the instruction field.  For the instruction decode (and
+#   controled by IDECODE_EXPAND_SEMANTICS) this forces the expansion of
+#   what would otherwize be non constant bits of an instruction.
+#
+#   <use_switch>
+#
+#   Should this table be expanded using a switch statement (val 1) and
+#   if so, should it be padded with entries so as to force the compiler
+#   to generate a jump table (val 2).
+#
+#   <special_mask>
+#   <special_value>
+#   <special_rule>
+#
+#   Special rule to fine tune how specific (or groups) of instructions
+#   are expanded.  The applicability of the rule is determined by
+#
+#     <special_mask> != 0 && (instruction> & <special_mask>) == <special_value>
+#
+#   Where <instruction> is obtained by looking only at constant fields
+#   with in an instructions spec.  When determining an expansion, the
+#   rule is only considered when a node contains a single instruction.
+#   <special_rule> can be any of:
+#
+#        0: for this instruction, expand by earlier rules
+#      1: expand bits <force_low> .. <force_hi> only
+#      2: boolean expansion of only zero/non-zero cases
+#
+ 0: 5: 0: 5:0:0:             0:0x00000000:0x00000000:0
+21:31:32:-1:0:OE,LR,AA,Rc,LK:0:0x00000000:0x00000000:0
+ 6:15: 6:15:0:BO,BI:         0:0xfc000000:0x40000000:0
+11:15:11:15:0:RA:            0:0xfc000000:0x38000000:2
+11:15:11:15:0:RA:            0:0xfc000000:0x3c000000:2
+11:20:11:20:0:spr:           0:0xfc000000:0x7c000000:0
index 96b94e5..66c54ed 100644 (file)
 #ifndef _PSIM_C_
 #define _PSIM_C_
 
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
 #include "config.h"
 #include "ppc-config.h"
 #include "inline.h"
 #include "cpu.h" /* includes psim.h */
 #include "idecode.h"
 
+#include "bfd.h"
+
+
 #include "inline.c"
 
+/* 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
+
+/* Any starting address greater than this is assumed to be an OpenBoot
+   rather than VEA */
+#ifndef OPENBOOT_START_ADDRESS
+#define OPENBOOT_START_ADDRESS 0x80000000
+#endif
+
+#ifndef OEA_MEMORY_SIZE
+#define OEA_MEMORY_SIZE 0x100000
+#endif
+
 
 /* system structure, actual size of processor array determined at
    runtime */
 
 struct _psim {
   event_queue *events;
-  device_node *devices;
+  device_tree *devices;
+  mon *monitor;
   core *memory;
   /* escape routine for inner functions */
   void *path_to_halt;
@@ -54,7 +78,7 @@ struct _psim {
   /* the processes proper */
   int nr_cpus;
   int last_cpu; /* CPU that last (tried to) execute an instruction */
-  cpu *processors[0];
+  cpu *processors[MAX_NR_PROCESSORS];
 };
 
 
@@ -62,64 +86,348 @@ int current_target_byte_order;
 int current_host_byte_order;
 int current_environment;
 int current_alignment;
+int current_floating_point;
+
+
+/* create a device tree from the image */
+
+
+
+/* Raw hardware tree:
+
+   A small default set of devices are configured.  Each section of the
+   image is loaded directly into physical memory. */
+
+STATIC_INLINE_PSIM void
+create_hardware_device_tree(bfd *image,
+                           device_tree *root)
+{
+  char *name;
+  const memory_size = OEA_MEMORY_SIZE;
+
+  /* options */
+  device_tree_add_passthrough(root, "/options");
+  device_tree_add_integer(root, "/options/smp",
+                         MAX_NR_PROCESSORS);
+  device_tree_add_boolean(root, "/options/little-endian?",
+                         !image->xvec->byteorder_big_p);
+  device_tree_add_string(root, "/options/environment-architecture",
+                        "operating");
+  device_tree_add_boolean(root, "/options/strict-alignment?",
+                         (WITH_ALIGNMENT == STRICT_ALIGNMENT
+                          || !image->xvec->byteorder_big_p));
+  device_tree_add_boolean(root, "/options/floating-point?",
+                         WITH_FLOATING_POINT);
+
+  /* hardware */
+  name = printd_uw_u_u("/memory", 0, memory_size, access_read_write_exec);
+  device_tree_add_found_device(root, name);
+  zfree(name);
+  device_tree_add_found_device(root, "/iobus@0x400000");
+  device_tree_add_found_device(root, "/iobus/console@0x000000,16");
+  device_tree_add_found_device(root, "/iobus/halt@0x100000,4");
+  device_tree_add_found_device(root, "/iobus/icu@0x200000,4");
+
+  /* initialization */
+  device_tree_add_passthrough(root, "/init");
+  device_tree_add_found_device(root, "/init/register@pc,0x0");
+  name = printd_c_uw("/init/register", "sp", memory_size);
+  device_tree_add_found_device(root, name);
+  zfree(name);
+  name = printd_c_uw("/init/register", "msr",
+                    (image->xvec->byteorder_big_p
+                     ? 0
+                     : msr_little_endian_mode));
+  device_tree_add_found_device(root, name);
+  zfree(name);
+  /* AJC puts the PC at zero and wants a stack while MM puts it above
+     zero and doesn't. Really there should be no stack *but* this
+     makes testing easier */
+  device_tree_add_found_device(root,
+                              (bfd_get_start_address(image) == 0
+                               ? "/init/stack@elf"
+                               : "/init/stack@none"));
+  name = printd_c("/init/load-binary", bfd_get_filename(image));
+  device_tree_add_found_device(root, name);
+  zfree(name);
+}
+
+
+/* Openboot model (under development):
+
+   An extension of the hardware model.  The image is read into memory
+   as a single block.  Sections of the image are then mapped as
+   required using a HTAB. */
+
+STATIC_INLINE_PSIM void
+create_openboot_device_tree(bfd *image,
+                           device_tree *root)
+{
+  create_hardware_device_tree(image, root);
+}
+
+
+/* User mode model:
+
+   Image sections loaded into virtual addresses as specified.  A
+   (large) stack is reserved (but only allocated as needed). System
+   calls that include suport for heap growth are attached. */
+
+STATIC_INLINE_PSIM void
+create_vea_device_tree(bfd *image,
+                      device_tree *root)
+{
+  unsigned_word top_of_stack;
+  unsigned stack_size;
+  int elf_binary;
+  char *name;
+
+  /* establish a few defaults */
+  if (image->xvec->flavour == bfd_target_elf_flavour) {
+    elf_binary = 1;
+    top_of_stack = 0xe0000000;
+    stack_size =   0x00100000;
+  }
+  else {
+    elf_binary = 0;
+    top_of_stack = 0x20000000;
+    stack_size =   0x00100000;
+  }
+
+  /* options */
+  device_tree_add_passthrough(root, "/options");
+  device_tree_add_integer(root, "/options/smp", 1); /* always */
+  device_tree_add_boolean(root, "/options/little-endian?",
+                         !image->xvec->byteorder_big_p);
+  device_tree_add_string(root, "/options/environment-architecture",
+                        (WITH_ENVIRONMENT == USER_ENVIRONMENT
+                         ? "user" : "virtual"));
+  device_tree_add_boolean(root, "/options/strict-alignment?",
+                         (WITH_ALIGNMENT == STRICT_ALIGNMENT
+                           || !image->xvec->byteorder_big_p));
+  device_tree_add_boolean(root, "/options/floating-point?",
+                         WITH_FLOATING_POINT);
+
+  /* virtual memory - handles growth of stack/heap */
+  name = printd_uw_u("/vm", top_of_stack - stack_size, stack_size);
+  device_tree_add_found_device(root, name);
+  zfree(name);
+  name = printd_c("/vm/map-binary", bfd_get_filename(image));
+  device_tree_add_found_device(root, name);
+  zfree(name);
+
+  /* finish the init */
+  device_tree_add_passthrough(root, "/init");
+  name = printd_c_uw("/init/register", "pc", bfd_get_start_address(image));
+  device_tree_add_found_device(root, name); /*pc*/
+  zfree(name);
+  name = printd_c_uw("/init/register", "sp", top_of_stack);
+  device_tree_add_found_device(root, name);
+  zfree(name);
+  name = printd_c_uw("/init/register", "msr",
+                    (image->xvec->byteorder_big_p
+                     ? 0
+                     : msr_little_endian_mode));
+  device_tree_add_found_device(root, name);
+  zfree(name);
+  device_tree_add_found_device(root, (elf_binary
+                                     ? "/init/stack@elf"
+                                     : "/init/stack@xcoff"));
+}
+
+
+/* File device:
+
+   The file contains lines that specify the describe the device tree
+   to be created, read them in and load them into the tree */
+
+STATIC_INLINE_PSIM void
+create_filed_device_tree(const char *file_name,
+                        device_tree *root)
+{
+  FILE *description = fopen(file_name, "r");
+  int line_nr = 0;
+  char device_path[1000];
+  while (fgets(device_path, sizeof(device_path), description)) {
+    /* check all of line was read */
+    {
+      char *end = strchr(device_path, '\n');
+      if (end == NULL) {
+       fclose(description);
+       error("create_filed_device_tree() line %d to long: %s\n",
+             line_nr, device_path);
+      }
+      line_nr++;
+      *end = '\0';
+    }
+    /* check for leading comment */
+    if (device_path[0] != '/')
+      continue;
+    /* enter it in varying ways */
+    if (strchr(device_path, '@') != NULL) {
+      device_tree_add_found_device(root, device_path);
+    }
+    else {
+      char *space = strchr(device_path, ' ');
+      if (space == NULL) {
+       /* intermediate node */
+       device_tree_add_passthrough(root, device_path);
+      }
+      else if (space[-1] == '?') {
+       /* boolean */
+       *space = '\0';
+       device_tree_add_boolean(root, device_path, space[1] != '0');
+      }
+      else if (isdigit(space[1])) {
+       /* integer */
+       *space = '\0';
+       device_tree_add_integer(root, device_path, strtoul(space+1, 0, 0));
+      }
+      else if (space[1] == '"') {
+       /* quoted string */
+       char *end = strchr(space+2, '\0');
+       if (end[-1] == '"')
+         end[-1] = '\0';
+       *space = '\0';
+       device_tree_add_string(root, device_path, space + 2);
+      }
+      else {
+       /* any thing else */
+       space = '\0';
+       device_tree_add_string(root, device_path, space + 1);
+      }
+    }
+  }
+  fclose(description);
+}
+
+
+/* Given the file containing the `image', create a device tree that
+   defines the machine to be modeled */
+
+STATIC_INLINE_PSIM device_tree *
+create_device_tree(const char *file_name,
+                  core *memory)
+{
+  bfd *image;
+  const device *core_device = core_device_create(memory);
+  device_tree *root = device_tree_add_device(NULL, "/", core_device);
+
+  bfd_init(); /* could be redundant but ... */
+
+  /* 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;
+  }
+
+  /* depending on what was found about the file, load it */
+  if (image != NULL) {
+    if (bfd_get_start_address(image) < OEA_START_ADDRESS) {
+      TRACE(trace_device_tree, ("create_device_tree() - hardware image\n"));
+      create_hardware_device_tree(image, root);
+    }
+    else if (bfd_get_start_address(image) < OPENBOOT_START_ADDRESS) {
+      TRACE(trace_device_tree, ("create_device_tree() - vea image\n"));
+      create_vea_device_tree(image, root);
+    }
+    else {
+      TRACE(trace_device_tree, ("create_device_tree() - openboot? image\n"));
+      create_openboot_device_tree(image, root);
+    }
+    bfd_close(image);
+  }
+  else {
+    TRACE(trace_device_tree, ("create_device_tree() - text image\n"));
+    create_filed_device_tree(file_name, root);
+  }
+
+  return root;
+}
+
+
 
 INLINE_PSIM psim *
-psim_create(const char *file_name,
-           int nr_processors)
+psim_create(const char *file_name)
 {
   int cpu_nr;
+  const char *env;
   psim *system;
 
-  /* sanity check */
-  if (nr_processors <= 0
-      || (!WITH_SMP && nr_processors != 1))
-    error("psim_create() invalid number of cpus\n");
-
   /* create things */
-  system = (psim*)zalloc(sizeof(psim)
-                        + sizeof(cpu*) * (nr_processors + 1));
-  system->nr_cpus = nr_processors;
+  system = ZALLOC(psim);
   system->events = event_queue_create();
-  system->devices = device_tree_create(file_name);
-  system->memory = core_create(system->devices, 0);
-  for (cpu_nr = 0; cpu_nr < nr_processors; cpu_nr++) {
+  system->memory = core_create();
+  system->monitor = mon_create();
+  system->devices = create_device_tree(file_name, system->memory);
+  for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
     system->processors[cpu_nr] = cpu_create(system,
                                            system->memory,
                                            system->events,
+                                           mon_cpu(system->monitor,
+                                                   cpu_nr),
                                            cpu_nr);
   }
 
-  /* fill in the missing endian information */
-  current_target_byte_order
-    = (device_tree_find_boolean(system->devices, "/options/little-endian?")
-       ? LITTLE_ENDIAN
-       : BIG_ENDIAN);
-  if (WITH_TARGET_BYTE_ORDER
-      && WITH_TARGET_BYTE_ORDER != current_target_byte_order)
+  /* fill in the missing real number of CPU's */
+  system->nr_cpus = device_tree_find_integer(system->devices,
+                                            "/options/smp");
+
+  /* fill in the missing TARGET BYTE ORDER information */
+  current_target_byte_order = (device_tree_find_boolean(system->devices,
+                                                       "/options/little-endian?")
+                              ? LITTLE_ENDIAN
+                              : BIG_ENDIAN);
+  if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
     error("target byte order conflict\n");
 
-  current_host_byte_order = 1;
-  current_host_byte_order = (*(char*)(&current_host_byte_order)
-                            ? LITTLE_ENDIAN
-                            : BIG_ENDIAN);
-  if (WITH_HOST_BYTE_ORDER
-      && WITH_HOST_BYTE_ORDER != current_host_byte_order)
+  /* fill in the missing HOST BYTE ORDER information */
+  current_host_byte_order = (current_host_byte_order = 1,
+                            (*(char*)(&current_host_byte_order)
+                             ? LITTLE_ENDIAN
+                             : BIG_ENDIAN));
+  if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order)
     error("host byte order conflict\n");
 
   /* fill in the missing OEA/VEA information */
-  current_environment = (device_tree_find_boolean(system->devices,
-                                                 "/options/vea?")
+  env = device_tree_find_string(system->devices,
+                               "/options/environment-architecture");
+  current_environment = (strcmp(env, "user") == 0
+                        ? USER_ENVIRONMENT
+                        : strcmp(env, "virtual") == 0
                         ? VIRTUAL_ENVIRONMENT
-                        : OPERATING_ENVIRONMENT);
+                        : strcmp(env, "operating") == 0
+                        ? OPERATING_ENVIRONMENT
+                        : 0);
+  if (current_environment == 0)
+    error("unreconized /options/environment-architecture\n");
+  if (CURRENT_ENVIRONMENT != current_environment)
+    error("target environment conflict\n");
 
   /* fill in the missing ALLIGNMENT information */
   current_alignment = (device_tree_find_boolean(system->devices,
-                                               "/options/aligned?")
+                                               "/options/strict-alignment?")
                       ? STRICT_ALIGNMENT
                       : NONSTRICT_ALIGNMENT);
-  if (WITH_ALIGNMENT
-      && CURRENT_ALIGNMENT != WITH_ALIGNMENT)
-    error("target alignment support conflict\n");
+  if (CURRENT_ALIGNMENT != current_alignment)
+    error("target alignment conflict\n");
+
+  /* fill in the missing FLOATING POINT information */
+  current_floating_point = (device_tree_find_boolean(system->devices,
+                                                    "/options/floating-point?")
+                           ? HARD_FLOATING_POINT
+                           : SOFT_FLOATING_POINT);
+  if (CURRENT_FLOATING_POINT != current_floating_point)
+    error("target floating-point conflict\n");
 
   return system;
 }
@@ -185,207 +493,32 @@ psim_cpu(psim *system,
 }
 
 
-
-STATIC_INLINE_PSIM int
-sizeof_argument_strings(char **arg)
+const device *
+psim_device(psim *system,
+           const char *path)
 {
-  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;
+  return device_tree_find_device(system->devices, path);
 }
 
-STATIC_INLINE_PSIM int
-number_of_arguments(char **arg)
-{
-  int nr;
-  if (arg == NULL)
-    return 0;
-  for (nr = 0; *arg != NULL; arg++, nr++);
-  return nr;
-}
 
-STATIC_INLINE_PSIM int
-sizeof_arguments(char **arg)
-{
-  return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
-}
 
-STATIC_INLINE_PSIM void
-write_stack_arguments(psim *system,
-                     char **arg,
-                     unsigned_word start_block,
-                     unsigned_word start_arg)
-{
-  if (CURRENT_ENVIRONMENT != VIRTUAL_ENVIRONMENT)
-    {
-      TRACE(trace_create_stack, ("write_stack_arguments() - skipping, OEA program\n"));
-      return;
-    }
-
-  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;
-    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,
-                         raw_transfer, 0) != len)
-      error("write_arguments() - write of **arg (%s) at 0x%x failed\n",
-           *arg, start_block);
-    if (psim_write_memory(system, 0, &start_block,
-                         start_arg, sizeof(start_block),
-                         cooked_transfer, 0) != sizeof(start_block))
-      error("write_arguments() - write of *arg failed\n");
-    start_block += ALIGN_8(len);
-    start_arg += sizeof(start_block);
-  }
-}
-
-STATIC_INLINE_PSIM 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);
-
-  /* force some stack space */
-  if (CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT
-      && core_stack_lower_bound(system->memory) > top_of_stack) {
-    unsigned_word extra_stack_space = (core_stack_lower_bound(system->memory)
-                                      - FLOOR_PAGE(top_of_stack));
-    TRACE(trace_create_stack,
-         ("create_elf_stack_frame() - growing stack by 0x%x\n",
-          extra_stack_space));
-    core_add_stack(system->memory, extra_stack_space);
-  }
-
-  /* install arguments on stack */
-  write_stack_arguments(system, envp, start_envp_block, start_envp);
-  write_stack_arguments(system, argv, start_argv_block, start_argv);
-
-  /* set up the registers */
-  psim_write_register(system, -1,
-                     &top_of_stack, "r1", 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_PSIM void
-create_aix_stack_frame(psim *system,
-                      unsigned_word bottom_of_stack,
-                      char **argv,
-                      char **envp)
+INLINE_PSIM void
+psim_init(psim *system)
 {
-  unsigned_word core_envp;
-  unsigned_word core_argv;
-  unsigned_word core_argc;
-  unsigned_word core_aux;
-  unsigned_word top_of_stack;
+  int cpu_nr;
 
-  /* 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);
-
-  /* check stack fits at least this much */
-  if (CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT
-      && core_stack_lower_bound(system->memory) > top_of_stack) {
-    unsigned_word extra_stack_space = (core_stack_lower_bound(system->memory)
-                                      - FLOOR_PAGE(top_of_stack));
-    TRACE(trace_create_stack,
-         ("create_aix_stack_frame() - growing stack by 0x%x\n",
-          extra_stack_space));
-    core_add_stack(system->memory, extra_stack_space);
-  }
+  /* scrub the monitor */
+  mon_init(system->monitor, system->nr_cpus);
 
-  /* extract arguments from registers */
-  error("create_aix_stack_frame() - what happens next?\n");
-}
+  /* scrub all the cpus */
+  for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
+    cpu_init(system->processors[cpu_nr]);
 
+  /* init all the devices */
+  device_tree_init(system->devices, system);
 
-INLINE_PSIM void
-psim_load(psim *system)
-{
-  unsigned_word program_counter;
-  msreg msr;
-
-  /* load in core data */
-  core_init(system->memory);
-
-  /* set up all processor entry points (to same thing).  Maybe
-     someday, the device tree could include information specifying the
-     entry point for each processor, one day */
-  TRACE(trace_tbd,
-       ("TBD - device tree specifying entry point of each processor\n"));
-  program_counter = device_tree_find_int(system->devices,
-                                        "/options/program-counter");
-  psim_write_register(system, -1,
-                     &program_counter,
-                     "pc", cooked_transfer);
-  system->last_cpu = system->nr_cpus - 1; /* force loop to restart */
-
-  /* set up the MSR for at least be/le mode */
-  msr = (device_tree_find_boolean(system->devices,
-                                 "/options/little-endian?")
-        ? msr_little_endian_mode
-        : 0);
-  psim_write_register(system, -1,
-                     &msr,
-                     "msr", cooked_transfer);
+  /* force loop to restart */
+  system->last_cpu = system->nr_cpus - 1;
 }
 
 INLINE_PSIM void
@@ -393,13 +526,19 @@ psim_stack(psim *system,
           char **argv,
           char **envp)
 {
-  unsigned_word stack_pointer = device_tree_find_int(system->devices,
-                                                    "/options/stack-pointer");
-  if (device_tree_find_boolean(system->devices,
-                              "/options/elf?"))
-    create_elf_stack_frame(system, stack_pointer, argv, envp);
-  else
-    create_aix_stack_frame(system, stack_pointer, argv, envp);
+  /* pass the stack device the argv/envp and let it work out what to
+     do with it */
+  const device *stack_device = device_tree_find_device(system->devices,
+                                                      "/init/stack");
+  unsigned_word stack_pointer;
+  psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer);
+  stack_device->callback->ioctl(stack_device,
+                               system,
+                               NULL, /*cpu*/
+                               0, /*cia*/
+                               stack_pointer,
+                               argv,
+                               envp);
 }
 
 
@@ -416,8 +555,16 @@ STATIC_INLINE_PSIM void
 run_until_stop(psim *system,
               volatile int *keep_running)
 {
+  jmp_buf halt;
+  jmp_buf restart;
+  int cpu_nr;
+#if WITH_IDECODE_CACHE_SIZE
+  for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
+    cpu_flush_icache(system->processors[cpu_nr]);
+#endif
+  psim_set_halt_and_restart(system, &halt, &restart);
 
-#if (WITH_IDECODE_CACHE == 0 && WITH_SMP == 0)
+#if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
 
   /* CASE 1: No instruction cache and no SMP.
 
@@ -429,9 +576,6 @@ run_until_stop(psim *system,
      later functions always save the current cpu instruction
      address. */
 
-  jmp_buf halt;
-  jmp_buf restart;
-  psim_set_halt_and_restart(system, &halt, &restart);
   if (!setjmp(halt)) {
     do {
       if (!setjmp(restart)) {
@@ -456,11 +600,10 @@ run_until_stop(psim *system,
       }
     } while(keep_running == NULL || *keep_running);
   }
-  psim_clear_halt_and_restart(system);
 #endif
 
 
-#if (WITH_IDECODE_CACHE > 0 && WITH_SMP == 0)
+#if (WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
 
   /* CASE 2: Instruction case but no SMP
 
@@ -468,9 +611,6 @@ run_until_stop(psim *system,
      different cache implementations.  A simple function address cache
      or a full cracked instruction cache */
 
-  jmp_buf halt;
-  jmp_buf restart;
-  psim_set_halt_and_restart(system, &halt, &restart);
   if (!setjmp(halt)) {
     do {
       if (!setjmp(restart)) {
@@ -484,39 +624,24 @@ run_until_stop(psim *system,
              cia = cpu_get_program_counter(processor);
            }
          { 
-           idecode_cache *const cache_entry
-             = cpu_icache(processor) + (cia / 4 % IDECODE_CACHE_SIZE);
+           idecode_cache *const cache_entry = cpu_icache_entry(processor,
+                                                               cia);
            if (cache_entry->address == cia) {
              idecode_semantic *const semantic = cache_entry->semantic;
-#if WITH_IDECODE_CACHE == 1
-             cia = semantic(processor, cache_entry->instruction, cia);
-#else
              cia = semantic(processor, cache_entry, cia);
-#endif
            }
            else {
              instruction_word const instruction
                = vm_instruction_map_read(cpu_instruction_map(processor),
                                          processor,
                                          cia);
-#if WITH_IDECODE_CACHE == 1
-             idecode_semantic *const semantic = idecode(processor,
-                                                        instruction,
-                                                        cia);
-#else
              idecode_semantic *const semantic = idecode(processor,
                                                         instruction,
                                                         cia,
                                                         cache_entry);
-#endif
              cache_entry->address = cia;
              cache_entry->semantic = semantic;
-#if WITH_IDECODE_CACHE == 1
-             cache_entry->instruction = instruction;
-             cia = semantic(processor, instruction, cia);
-#else
              cia = semantic(processor, cache_entry, cia);
-#endif
            }
          }
        } while (keep_running == NULL || *keep_running);
@@ -524,11 +649,10 @@ run_until_stop(psim *system,
       }
     } while(keep_running == NULL || *keep_running);
   }
-  psim_clear_halt_and_restart(system);
 #endif
 
 
-#if (WITH_IDECODE_CACHE == 0 && WITH_SMP > 0)
+#if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
 
   /* CASE 3: No ICACHE but SMP
 
@@ -537,10 +661,6 @@ run_until_stop(psim *system,
      restart, the next cpu is still cpu1.  Cpu0 being restarted after
      all the other CPU's and the event queue have been processed */
 
-  jmp_buf halt;
-  jmp_buf restart;
-  psim_set_halt_and_restart(system, &halt, &restart);
-
   if (!setjmp(halt)) {
     int first_cpu = setjmp(restart);
     if (first_cpu == 0)
@@ -571,10 +691,9 @@ run_until_stop(psim *system,
       }
     } while (keep_running == NULL || *keep_running);
   }
-  psim_clear_halt_and_restart(system);
 #endif
 
-#if (WITH_IDECODE_CACHE > 0 && WITH_SMP > 0)
+#if (WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
 
   /* CASE 4: ICACHE and SMP ...
 
@@ -582,10 +701,6 @@ run_until_stop(psim *system,
      correctly, need to save the program counter and finally need to
      keep track of each processors current address! */
 
-  jmp_buf halt;
-  jmp_buf restart;
-  psim_set_halt_and_restart(system, &halt, &restart);
-
   if (!setjmp(halt)) {
     int first_cpu = setjmp(restart);
     if (!first_cpu)
@@ -602,47 +717,25 @@ run_until_stop(psim *system,
        else {
          cpu *processor = system->processors[current_cpu];
          unsigned_word const cia = cpu_get_program_counter(processor);
-         idecode_cache *cache_entry
-           = (cpu_icache(processor) + (cia / 4 % IDECODE_CACHE_SIZE));
+         idecode_cache *cache_entry = cpu_icache_entry(processor, cia);
          if (cache_entry->address == cia) {
            idecode_semantic *semantic = cache_entry->semantic;
-#if WITH_IDECODE_CACHE == 1
-           cpu_set_program_counter(processor,
-                                   semantic(processor,
-                                            cache_entry->instruction,
-                                            cia);
-#else
            cpu_set_program_counter(processor,
-                                   semantic(processor,
-                                            cache_entry,
-                                            cia);
-#endif
+                                   semantic(processor, cache_entry, cia));
          }
          else {
            instruction_word instruction =
              vm_instruction_map_read(cpu_instruction_map(processor),
                                      processor,
                                      cia);
-#if WITH_IDECODE_CACHE == 1
-           idecode_semantic *semantic = idecode(processor,
-                                                instruction,
-                                                cia);
-#else
            idecode_semantic *semantic = idecode(processor,
                                                 instruction,
                                                 cia,
                                                 cache_entry);
-#endif
            cache_entry->address = cia;
            cache_entry->semantic = semantic;
-#if WITH_IDECODE_CACHE == 1
-           cache_entry->instruction = instruction;
-           cpu_set_program_counter(processor,
-                                   semantic(processor, instruction, cia));
-#else
            cpu_set_program_counter(processor,
-                                   semantic(processor, cache_entry, cia);
-#endif
+                                   semantic(processor, cache_entry, cia));
          }
        }
        if (!(keep_running == NULL || *keep_running))
@@ -650,8 +743,9 @@ run_until_stop(psim *system,
       }
     } while (keep_running == NULL || *keep_running);
   }
-  psim_clear_halt_and_restart(system);
 #endif
+
+  psim_clear_halt_and_restart(system);
 }
 
 
@@ -662,7 +756,7 @@ INLINE_PSIM void
 psim_step(psim *system)
 {
   volatile int keep_running = 0;
-  psim_run_until_stop(system, &keep_running);
+  run_until_stop(system, &keep_running);
 }
 
 INLINE_PSIM void
@@ -694,10 +788,10 @@ psim_read_register(psim *system,
   cpu *processor;
 
   /* find our processor */
-  if (which_cpu < 0 || which_cpu > system->nr_cpus)
-    error("psim_read_register() - invalid processor %d\n", which_cpu);
-  if (which_cpu == system->nr_cpus)
+  if (which_cpu == MAX_NR_PROCESSORS)
     which_cpu = system->last_cpu;
+  if (which_cpu < 0 || which_cpu >= system->nr_cpus)
+    error("psim_read_register() - invalid processor %d\n", which_cpu);
   processor = system->processors[which_cpu];
 
   /* find the register description */
@@ -783,15 +877,14 @@ psim_write_register(psim *system,
   char cooked_buf[sizeof(natural_word)];
 
   /* find our processor */
+  if (which_cpu == MAX_NR_PROCESSORS)
+    which_cpu = system->last_cpu;
   if (which_cpu == -1) {
     int i;
     for (i = 0; i < system->nr_cpus; i++)
       psim_write_register(system, i, buf, reg, mode);
     return;
   }
-  else if (which_cpu == system->nr_cpus) {
-    which_cpu = system->last_cpu;
-  }
   else if (which_cpu < 0 || which_cpu >= system->nr_cpus) {
     error("psim_read_register() - invalid processor %d\n", which_cpu);
   }
@@ -873,17 +966,16 @@ psim_read_memory(psim *system,
                 int which_cpu,
                 void *buffer,
                 unsigned_word vaddr,
-                unsigned len,
-                transfer_mode mode)
+                unsigned nr_bytes)
 {
   cpu *processor;
-  if (which_cpu < 0 || which_cpu > system->nr_cpus)
-    error("psim_read_memory() invalid cpu\n");
-  if (which_cpu == system->nr_cpus)
+  if (which_cpu == MAX_NR_PROCESSORS)
     which_cpu = system->last_cpu;
+  if (which_cpu < 0 || which_cpu >= system->nr_cpus)
+    error("psim_read_memory() invalid cpu\n");
   processor = system->processors[which_cpu];
   return vm_data_map_read_buffer(cpu_data_map(processor),
-                                buffer, vaddr, len, mode);
+                                buffer, vaddr, nr_bytes);
 }
 
 
@@ -892,44 +984,26 @@ psim_write_memory(psim *system,
                  int which_cpu,
                  const void *buffer,
                  unsigned_word vaddr,
-                 unsigned len,
-                 transfer_mode mode,
+                 unsigned nr_bytes,
                  int violate_read_only_section)
 {
   cpu *processor;
-  if (which_cpu < 0 || which_cpu > system->nr_cpus)
-    error("psim_read_memory() invalid cpu\n");
-  if (which_cpu == system->nr_cpus)
+  if (which_cpu == MAX_NR_PROCESSORS)
     which_cpu = system->last_cpu;
+  if (which_cpu < 0 || which_cpu >= system->nr_cpus)
+    error("psim_read_memory() invalid cpu\n");
   processor = system->processors[which_cpu];
   return vm_data_map_write_buffer(cpu_data_map(processor),
-                                 buffer, vaddr, len, mode, 1);
+                                 buffer, vaddr, nr_bytes, 1);
 }
 
 
 INLINE_PSIM void
-psim_print_info(psim *system, int verbose)
+psim_print_info(psim *system,
+               int verbose)
 {
-  psim_status status;
-  int i;
-
-
-  status = psim_get_status(system);
-  switch (status.reason) {
-  default:
-    break;     /* our caller will print an appropriate error message */
-
-  case was_exited:
-    printf ("Exit status = %d\n", status.signal);
-    break;
-
-  case was_signalled:
-    printf ("Got signal %d\n", status.signal);
-    break;
-  }
-
-  for (i = 0; i < system->nr_cpus; i++)
-    cpu_print_info (system->processors[i], verbose);
+  mon_print_info(system->monitor, verbose);
 }
 
+
 #endif /* _PSIM_C_ */
index d3462b3..e262e05 100644 (file)
@@ -39,7 +39,6 @@
 /* Structures used by the simulator, for gdb just have static structures */
 
 static psim *simulator;
-static int nr_cpus;
 static char *register_names[] = REGISTER_NAMES;
 static int print_info = 0;
 
@@ -52,53 +51,39 @@ sim_open (char *args)
   TRACE(trace_gdb, ("sim_open(args=%s) called\n", args ? args : "(null)"));
 
   if (args) {
-    char *buf = (char *)alloca (strlen (args) + 1);
-    char *p;
-    strcpy (buf, args);
+    char **argv = buildargv(args);
+    int argp = 0;
+    int argc;
+    for (argc = 0; argv[argc]; argc++);
 
-    p = strtok (args, " \t");
-    while (p != (char *)0) {
-      if (*p != '-')
-       error ("Argument is not an option '%s'", p);
+    while (argp < argc) {
+      if (*argv[argp] != '-')
+       error ("Argument is not an option '%s'", argv[argp]);
 
       else {
        /* check arguments -- note, main.c also contains argument processing
           code for the standalone emulator.  */
-       while (*++p != '\0') {
+       char *p = argv[argp] + 1;
+       while (*p != '\0') {
          switch (*p) {
          default:
-           error ("Usage: target sim [ -a -p -c -C -s -i -I -t ]\n");
+           printf_filtered("Usage:\n\ttarget sim [ -t <trace-option> ]\n");
+           trace_usage();
+           error ("");
            break;
-         case 'a':
-           for (i = 0; i < nr_trace; i++)
-             trace[i] = 1;
-           break;
-         case 'p':
-           trace[trace_cpu] = trace[trace_semantics] = 1;
-           break;
-         case 'c':
-           trace[trace_core] = 1;
-           break;
-         case 'C':
-           trace[trace_console_device] = 1;
-           break;
-         case 's':
-           trace[trace_create_stack] = 1;
-           break;
-         case 'i':
-           trace[trace_icu_device] = 1;
+         case 't':
+           argp += 1;
+           if (argv[argp] == NULL)
+             error("Missing <trace> option for -t\n");
+           trace_option(argv[argp]); /* better fail if NULL */
            break;
          case 'I':
            print_info = 1;
            break;
-         case 't':
-           trace[trace_device_tree] = 1;
-           break;
          }
        }
       }
-
-      p = strtok ((char *)0, " \t");
+      argp += 1;
     }
   }
 
@@ -122,24 +107,26 @@ sim_close (int quitting)
 int
 sim_load (char *prog, int from_tty)
 {
+  char **argv;
   TRACE(trace_gdb, ("sim_load(prog=%s, from_tty=%d) called\n",
                    prog, from_tty));
+  ASSERT(prog != NULL);
 
-  /* sanity check */
-  if (prog == NULL) {
-    error ("sim_load() - TBD - read stan shebs e-mail about how to find the program name?\n");
-    return -1;
-  }
-  TRACE(trace_tbd, ("sim_load() - TBD - parse that prog stripping things like quotes\n"));
+  /* parse the arguments, assume that the file is argument 0 */
+  argv = buildargv(prog);
+  ASSERT(argv != NULL && argv[0] != NULL);
 
   /* create the simulator */
   TRACE(trace_gdb, ("sim_load() - first time, create the simulator\n"));
-  nr_cpus = (WITH_SMP ? WITH_SMP : 1);
-  simulator = psim_create(prog, nr_cpus);
+  simulator = psim_create(argv[0]);
 
   /* bring in all the data section */
-  psim_load(simulator);
+  psim_init(simulator);
 
+  /* release the arguments */
+  freeargv(argv);
+
+  /* `I did it my way' */
   return 0;
 }
 
@@ -155,16 +142,23 @@ sim_kill (void)
 int
 sim_read (SIM_ADDR mem, unsigned char *buf, int length)
 {
-  return psim_read_memory(simulator, nr_cpus, buf, mem, length,
-                         raw_transfer);
+  int result = psim_read_memory(simulator, MAX_NR_PROCESSORS,
+                               buf, mem, length);
+  TRACE(trace_gdb, ("sim_read(mem=0x%x, buf=0x%x, length=%d) = %d\n",
+                   mem, buf, length, result));
+  return result;
 }
 
 
 int
 sim_write (SIM_ADDR mem, unsigned char *buf, int length)
 {
-  return psim_write_memory(simulator, nr_cpus, buf, mem, length,
-                          raw_transfer, 1/*violate_ro*/);
+  int result = psim_write_memory(simulator, MAX_NR_PROCESSORS,
+                                buf, mem, length,
+                                1/*violate_ro*/);
+  TRACE(trace_gdb, ("sim_write(mem=0x%x, buf=0x%x, length=%d) = %d\n",
+                   mem, buf, length, result));
+  return result;
 }
 
 
@@ -174,8 +168,10 @@ sim_fetch_register (int regno, unsigned char *buf)
   if (simulator == NULL) {
     return;
   }
-
-  psim_read_register(simulator, nr_cpus, buf, register_names[regno],
+  TRACE(trace_gdb, ("sim_fetch_register(regno=%d(%s), buf=0x%x)\n",
+                   regno, register_names[regno], buf));
+  psim_read_register(simulator, MAX_NR_PROCESSORS,
+                    buf, register_names[regno],
                     raw_transfer);
 }
 
@@ -185,8 +181,10 @@ sim_store_register (int regno, unsigned char *buf)
 {
   if (simulator == NULL)
     return;
-
-  psim_write_register(simulator, nr_cpus, buf, register_names[regno],
+  TRACE(trace_gdb, ("sim_store_register(regno=%d(%s), buf=0x%x)\n",
+                   regno, register_names[regno], buf));
+  psim_write_register(simulator, MAX_NR_PROCESSORS,
+                     buf, register_names[regno],
                      raw_transfer);
 }
 
@@ -207,7 +205,7 @@ sim_create_inferior (SIM_ADDR start_address, char **argv, char **envp)
   TRACE(trace_gdb, ("sim_create_inferior(start_address=0x%x, ...)\n",
                    start_address));
 
-  psim_load(simulator);
+  psim_init(simulator);
   psim_stack(simulator, argv, envp);
 
   psim_write_register(simulator, -1 /* all start at same PC */,
@@ -224,6 +222,7 @@ sim_stop_reason (enum sim_stop *reason, int *sigrc)
 
   switch (CURRENT_ENVIRONMENT) {
 
+  case USER_ENVIRONMENT:
   case VIRTUAL_ENVIRONMENT:
     switch (status.reason) {
     case was_continuing:
@@ -257,6 +256,9 @@ sim_stop_reason (enum sim_stop *reason, int *sigrc)
     error("sim_stop_reason() - unknown environment\n");
   
   }
+
+  TRACE(trace_gdb, ("sim_stop_reason(reason=0x%x(%d), sigrc=0x%x(%d))\n",
+                   reason, *reason, sigrc, *sigrc));
 }
 
 
@@ -274,6 +276,9 @@ sim_resume (int step, int siggnal)
   void (*prev) ();
   unsigned_word program_counter;
 
+  TRACE(trace_gdb, ("sim_resume(step=%d, siggnal=%d)\n",
+                   step, siggnal));
+
   prev = signal(SIGINT, sim_ctrl_c);
   sim_should_run = 1;
 
index 868ab19..69359f4 100644 (file)
@@ -96,18 +96,19 @@ extern int current_target_byte_order;
 
 /* Program environment:
 
-   Two environments are available. VEA (or virtual environment
-   architecture) and OEA (or operating environment architecture).  The
-   former is the environment that a user program would see while the
-   latter is the environment as seen by an operating system.  By
+   Three environments are available - UEA (user), VEA (virtual) and
+   OEA (perating).  The former two are environment that users would
+   expect to see (VEA includes things like coherency and the time
+   base) while OEA is what an operating system expects to see.  By
    setting these to specific values, the build process is able to
    eliminate non relevent environment code
 
    CURRENT_ENVIRONMENT specifies which of vea or oea is required for
    the current runtime. */
 
-#define VIRTUAL_ENVIRONMENT            1
-#define OPERATING_ENVIRONMENT          2
+#define USER_ENVIRONMENT               1
+#define VIRTUAL_ENVIRONMENT            2
+#define OPERATING_ENVIRONMENT          3
 
 #ifndef WITH_ENVIRONMENT
 #define WITH_ENVIRONMENT               0
@@ -131,7 +132,7 @@ extern int current_environment;
    queue implements this.  Unfortunatly this adds the need to check
    for any events once each full instruction cycle. */
 
-#define WITH_EVENTS                     (WITH_ENVIRONMENT != VIRTUAL_ENVIRONMENT)
+#define WITH_EVENTS                     (WITH_ENVIRONMENT != USER_ENVIRONMENT)
 
 
 /* Time base:
@@ -141,7 +142,7 @@ extern int current_environment;
    of of some instruction cycles. */
 
 #ifndef WITH_TIME_BASE
-#define WITH_TIME_BASE                 1
+#define WITH_TIME_BASE                 (WITH_ENVIRONMENT != USER_ENVIRONMENT)
 #endif
 
 
@@ -374,7 +375,7 @@ extern int current_floating_point;
    not a leaf */
 
 #ifndef DEVICE_TREE_INLINE
-#define DEVICE_TREE_INLINE             DEFAULT_INLINE
+#define DEVICE_TREE_INLINE             0
 #endif
 
 #ifndef DEVICES_INLINE
diff --git a/sim/ppc/vm.c b/sim/ppc/vm.c
new file mode 100644 (file)
index 0000000..f15e0bf
--- /dev/null
@@ -0,0 +1,938 @@
+/*  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 _VM_C_
+#define _VM_C_
+
+#ifndef STATIC_INLINE_VM
+#define STATIC_INLINE_VM STATIC_INLINE
+#endif
+
+
+#include "basics.h"
+
+#include "registers.h"
+
+#include "device_tree.h"
+#include "core.h"
+
+#include "vm.h"
+
+#include "interrupts.h"
+
+#include "mon.h"
+
+/* OEA vs VEA
+
+   For the VEA model, the VM layer is almost transparent.  It's only
+   purpose is to maintain separate core_map's for the instruction
+   and data address spaces.  This being so that writes to instruction
+   space or execution of a data space is prevented.
+
+   For the OEA model things are more complex.  The reason for separate
+   instruction and data models becomes crucial.  The OEA model is
+   built out of three parts.  An instruction map, a data map and an
+   underlying structure that provides access to the VM data kept in
+   main memory. */
+
+
+/* OEA data structures:
+
+   The OEA model maintains internal data structures that shadow the
+   semantics of the various OEA VM registers (BAT, SR, etc).  This
+   allows a simple efficient model of the VM to be implemented.
+
+   Consistency between OEA registers and this model's internal data
+   structures is maintained by updating the structures at
+   `synchronization' points.  Of particular note is that (at the time
+   of writing) the memory data types for BAT registers are rebuilt
+   when ever the processor moves between problem and system states */
+
+
+/* Protection table:
+
+   Matrix of processor state, type of access and validity */
+
+typedef enum {
+  om_supervisor_state,
+  om_problem_state,
+  nr_om_modes
+} om_processor_modes;
+
+typedef enum {
+  om_data_read, om_data_write,
+  om_instruction_read, om_access_any,
+  nr_om_access_types
+} om_access_types;
+
+static int om_valid_access[2][4][nr_om_access_types] = {
+  /* read, write, instruction, any */
+  /* K bit == 0 */
+  { /*r  w  i  a       pp */
+    { 1, 1, 1, 1 }, /* 00 */
+    { 1, 1, 1, 1 }, /* 01 */
+    { 1, 1, 1, 1 }, /* 10 */
+    { 1, 0, 1, 1 }, /* 11 */
+  },
+  /* K bit == 1  or P bit valid */
+  { /*r  w  i  a       pp */
+    { 0, 0, 0, 0 }, /* 00 */
+    { 1, 0, 1, 1 }, /* 01 */
+    { 1, 1, 1, 1 }, /* 10 */
+    { 1, 0, 1, 1 }, /* 11 */
+  }
+};
+
+
+/* Bat translation:
+
+   The bat data structure only contains information on valid BAT
+   translations for the current processor mode and type of access. */
+
+typedef struct _om_bat {
+  unsigned_word block_effective_page_index;
+  unsigned_word block_effective_page_index_mask;
+  unsigned_word block_length_mask;
+  unsigned_word block_real_page_number;
+  int protection_bits;
+} om_bat;
+
+enum _nr_om_bat_registers {
+  nr_om_bat_registers = 4
+};
+
+typedef struct _om_bats {
+  int nr_valid_bat_registers;
+  om_bat bat[nr_om_bat_registers];
+} om_bats;
+
+
+/* Segment TLB:
+
+   In this model the 32 and 64 bit segment tables are treated in very
+   similar ways.  The 32bit segment registers are treated as a
+   simplification of the 64bit segment tlb */
+
+enum _om_segment_tlb_constants {
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+  sizeof_segment_table_entry_group = 128,
+  sizeof_segment_table_entry = 16,
+#endif
+  om_segment_tlb_index_start_bit = 32,
+  om_segment_tlb_index_stop_bit = 35,
+  nr_om_segment_tlb_entries = 16,
+  nr_om_segment_tlb_constants
+};
+
+typedef struct _om_segment_tlb_entry {
+  int key[nr_om_modes];
+  om_access_types invalid_access; /* set to instruction if no_execute bit */
+  unsigned_word masked_virtual_segment_id;
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+  int is_valid;
+  unsigned_word masked_effective_segment_id;
+#endif
+} om_segment_tlb_entry;
+
+typedef struct _om_segment_tlb {
+  om_segment_tlb_entry entry[nr_om_segment_tlb_entries];
+} om_segment_tlb;
+
+
+/* Page TLB:
+
+   This OEA model includes a small direct map Page TLB.  The tlb is to
+   cut down on the need for the OEA to perform walks of the page hash
+   table. */
+
+enum _om_page_tlb_constants {
+  om_page_tlb_index_start_bit = 46,
+  om_page_tlb_index_stop_bit = 51,
+  nr_om_page_tlb_entries = 64,
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+  sizeof_pte_group = 128,
+  sizeof_pte = 16,
+#endif
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+  sizeof_pte_group = 64,
+  sizeof_pte = 8,
+#endif
+  nr_om_page_tlb_constants
+};
+
+typedef struct _om_page_tlb_entry {
+  int valid;
+  int protection;
+  unsigned_word masked_virtual_segment_id;
+  unsigned_word masked_page;
+  unsigned_word masked_real_page_number;
+} om_page_tlb_entry;
+
+typedef struct _om_page_tlb {
+  om_page_tlb_entry entry[nr_om_page_tlb_entries];
+} om_page_tlb;
+
+
+/* memory translation:
+
+   OEA memory translation possibly involves BAT, SR, TLB and HTAB
+   information*/
+
+typedef struct _om_map {
+
+  /* local cache of register values */
+  int is_relocate;
+  int is_problem_state;
+
+  /* block address translation */
+  om_bats *bat_registers;
+
+  /* failing that, translate ea to va using segment tlb */
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+  unsigned_word real_address_of_segment_table;
+#endif
+  om_segment_tlb *segment_tlb;
+
+  /* then va to ra using hashed page table and tlb */
+  unsigned_word real_address_of_page_table;
+  unsigned_word page_table_hash_mask;
+  om_page_tlb *page_tlb;
+
+  /* physical memory for fetching page table entries */
+  core_map *physical;
+
+} om_map;
+
+
+/* VM objects:
+
+   External objects defined by vm.h */
+
+struct _vm_instruction_map {
+  /* real memory for last part */
+  core_map *code;
+  /* translate effective to real */
+  om_map translation;
+};
+
+struct _vm_data_map {
+  /* translate effective to real */
+  om_map translation;
+  /* real memory for translated address */
+  core_map *read;
+  core_map *write;
+};
+
+
+/* VM:
+
+   Underlying memory object.  For the VEA this is just the
+   core_map. For OEA it is the instruction and data memory
+   translation's */
+
+struct _vm {
+
+  /* OEA: base address registers */
+  om_bats ibats;
+  om_bats dbats;
+
+  /* OEA: segment registers */
+  om_segment_tlb segment_tlb;
+
+  /* OEA: translation lookaside buffers */
+  om_page_tlb instruction_tlb;
+  om_page_tlb data_tlb;
+
+  /* real memory */
+  core *physical;
+
+  /* memory maps */
+  vm_instruction_map instruction_map;
+  vm_data_map data_map;
+
+};
+
+
+/* OEA Support procedures */
+
+
+STATIC_INLINE_VM unsigned_word
+om_segment_tlb_index(unsigned_word ea)
+{
+  unsigned_word index = EXTRACTED(ea,
+                                 om_segment_tlb_index_start_bit,
+                                 om_segment_tlb_index_stop_bit);
+  return index;
+}
+
+STATIC_INLINE_VM unsigned_word
+om_page_tlb_index(unsigned_word ea)
+{
+  unsigned_word index = EXTRACTED(ea,
+                                 om_page_tlb_index_start_bit,
+                                 om_page_tlb_index_stop_bit);
+  return index;
+}
+
+STATIC_INLINE_VM unsigned_word
+om_masked_page(unsigned_word ea)
+{
+  unsigned_word masked_page = MASKED(ea, 36, 51);
+  return masked_page;
+}
+
+STATIC_INLINE_VM unsigned_word
+om_masked_byte(unsigned_word ea)
+{
+  unsigned_word masked_byte = MASKED(ea, 52, 63);
+  return masked_byte;
+}
+
+
+
+INLINE_VM vm *
+vm_create(core *physical)
+{
+  vm *virtual;
+
+  /* internal checks */
+  if (nr_om_segment_tlb_entries
+      != (1 << (om_segment_tlb_index_stop_bit
+               - om_segment_tlb_index_start_bit + 1)))
+    error("new_vm() - internal error with om_segment constants\n");
+  if (nr_om_page_tlb_entries
+      != (1 << (om_page_tlb_index_stop_bit
+               - om_page_tlb_index_start_bit + 1)))
+    error("new_vm() - internal error with om_page constants\n");
+
+  /* create the new vm register file */
+  virtual = ZALLOC(vm);
+
+  /* set up core */
+  virtual->physical = physical;
+
+  /* set up the address decoders */
+  virtual->instruction_map.translation.bat_registers = &virtual->ibats;
+  virtual->instruction_map.translation.segment_tlb = &virtual->segment_tlb;
+  virtual->instruction_map.translation.page_tlb = &virtual->instruction_tlb;
+  virtual->instruction_map.translation.is_relocate = 0;
+  virtual->instruction_map.translation.is_problem_state = 0;
+  virtual->instruction_map.translation.physical = core_readable(physical);
+  virtual->instruction_map.code = core_readable(physical);
+
+  virtual->data_map.translation.bat_registers = &virtual->dbats;
+  virtual->data_map.translation.segment_tlb = &virtual->segment_tlb;
+  virtual->data_map.translation.page_tlb = &virtual->data_tlb;
+  virtual->data_map.translation.is_relocate = 0;
+  virtual->data_map.translation.is_problem_state = 0;
+  virtual->data_map.translation.physical = core_readable(physical);
+  virtual->data_map.read = core_readable(physical);
+  virtual->data_map.write = core_writeable(physical);
+
+  return virtual;
+}
+
+
+STATIC_INLINE_VM om_bat *
+om_effective_to_bat(om_map *map,
+                   unsigned_word ea)
+{
+  int curr_bat = 0;
+  om_bats *bats = map->bat_registers;
+  int nr_bats = bats->nr_valid_bat_registers;
+
+  for (curr_bat = 0; curr_bat < nr_bats; curr_bat++) {
+    om_bat *bat = bats->bat + curr_bat;
+    if ((ea & bat->block_effective_page_index_mask)
+       != bat->block_effective_page_index)
+      continue;
+    return bat;
+  }
+
+  return NULL;
+}
+
+
+STATIC_INLINE_VM om_segment_tlb_entry *
+om_effective_to_virtual(om_map *map, 
+                       unsigned_word ea,
+                       cpu *processor,
+                       unsigned_word cia)
+{
+  /* first try the segment tlb */
+  om_segment_tlb_entry *segment_tlb_entry = (map->segment_tlb->entry
+                                            + om_segment_tlb_index(ea));
+
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+  return segment_tlb_entry;
+#endif
+
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+  if (segment_tlb_entry->is_valid
+      && (segment_tlb_entry->masked_effective_segment_id == MASKED(ea, 0, 35))) {
+    error("fixme - is there a need to update any bits\n");
+    return segment_tlb_entry;
+  }
+
+  /* drats, segment tlb missed */
+  {
+    unsigned_word segment_id_hash = ea;
+    int current_hash = 0;
+    for (current_hash = 0; current_hash < 2; current_hash += 1) {
+      unsigned_word segment_table_entry_group =
+       (map->real_address_of_segment_table
+        | (MASKED64(segment_id_hash, 31, 35) >> (56-35)));
+      unsigned_word segment_table_entry;
+      for (segment_table_entry = segment_table_entry_group;
+          segment_table_entry < (segment_table_entry_group
+                                 + sizeof_segment_table_entry_group);
+          segment_table_entry += sizeof_segment_table_entry) {
+       /* byte order? */
+       unsigned_word segment_table_entry_dword_0 =
+         core_map_read_8(map->physical, segment_table_entry, processor, cia);
+       unsigned_word segment_table_entry_dword_1 =
+         core_map_read_8(map->physical, segment_table_entry + 8, processor, cia);
+       int is_valid = MASKED64(segment_table_entry_dword_0, 56, 56) != 0;
+       unsigned_word masked_effective_segment_id =
+         MASKED64(segment_table_entry_dword_0, 0, 35);
+       if (is_valid && masked_effective_segment_id == MASKED64(ea, 0, 35)) {
+         /* don't permit some things */
+         if (MASKED64(segment_table_entry_dword_0, 57, 57))
+           error("om_effective_to_virtual() - T=1 in STE not supported\n");
+         /* update segment tlb */
+         segment_tlb_entry->is_valid = is_valid;
+         segment_tlb_entry->masked_effective_segment_id =
+           masked_effective_segment_id;
+         segment_tlb_entry->key[om_supervisor_state] =
+           EXTRACTED64(segment_table_entry_dword_0, 58, 58);
+         segment_tlb_entry->key[om_problem_state] =
+           EXTRACTED64(segment_table_entry_dword_0, 59, 59);
+         segment_tlb_entry->invalid_access =
+           (MASKED64(segment_table_entry_dword_0, 60, 60)
+            ? om_instruction_read
+            : om_access_any);
+         segment_tlb_entry->masked_virtual_segment_id =
+           MASKED(segment_table_entry_dword_1, 0, 51);
+         return segment_tlb_entry;
+       }
+      }
+      segment_id_hash = ~segment_id_hash;
+    }
+  }
+  return NULL;
+#endif
+}
+
+
+
+STATIC_INLINE_VM om_page_tlb_entry *
+om_virtual_to_real(om_map *map, 
+                  unsigned_word ea,
+                  om_segment_tlb_entry *segment_tlb_entry,
+                  om_access_types access,
+                  cpu *processor,
+                  unsigned_word cia)
+{
+  om_page_tlb_entry *page_tlb_entry = (map->page_tlb->entry
+                                      + om_page_tlb_index(ea));
+
+  /* is it a tlb hit? */
+  if (page_tlb_entry->valid
+      && (page_tlb_entry->masked_virtual_segment_id ==
+         segment_tlb_entry->masked_virtual_segment_id)
+      && (page_tlb_entry->masked_page == om_masked_page(ea))) {
+    error("fixme - it is not a hit if direction/update bits do not match\n");
+    return page_tlb_entry;
+  }
+      
+  /* drats, it is a tlb miss */
+  {
+    unsigned_word page_hash = (segment_tlb_entry->masked_virtual_segment_id 
+                              ^ om_masked_page(ea));
+    int current_hash;
+    for (current_hash = 0; current_hash < 2; current_hash += 1) {
+      unsigned_word real_address_of_pte_group =
+       (map->real_address_of_page_table
+        | (page_hash & map->page_table_hash_mask));
+      unsigned_word real_address_of_pte;
+      for (real_address_of_pte = real_address_of_pte_group;
+          real_address_of_pte < (real_address_of_pte_group
+                                 + sizeof_pte_group);
+          real_address_of_pte += sizeof_pte) {
+       unsigned_word pte_word_0 =
+         core_map_read_word(map->physical,
+                            real_address_of_pte,
+                            processor, cia);
+       unsigned_word pte_word_1 =
+         core_map_read_word(map->physical,
+                            real_address_of_pte + sizeof_pte / 2,
+                            processor, cia);
+       error("fixme - check pte hit\n");
+       if (1) {
+         error("fixme - update the page_tlb\n");
+         page_tlb_entry->valid = 1;
+         page_tlb_entry->protection = 0;
+         page_tlb_entry->masked_virtual_segment_id = 0;
+         page_tlb_entry->masked_page = 0;
+         page_tlb_entry->masked_real_page_number = 0;
+         return page_tlb_entry;
+       }
+      }
+      page_hash = ~page_hash; /*???*/
+    }
+  }
+  return NULL;
+}
+
+
+static void
+om_interrupt(cpu *processor,
+            unsigned_word cia,
+            unsigned_word ea,
+            om_access_types access,
+            storage_interrupt_reasons reason)
+{
+  switch (access) {
+  case om_data_read:
+    data_storage_interrupt(processor, cia, ea, reason, 0/*!is_store*/);
+    break;
+  case om_data_write:
+    data_storage_interrupt(processor, cia, ea, reason, 1/*is_store*/);
+    break;
+  case om_instruction_read:
+    instruction_storage_interrupt(processor, cia, reason);
+    break;
+  default:
+    error("om_interrupt - unexpected access type %d, cia=0x%x, ea=0x%x\n",
+         access, cia, ea);
+  }
+}
+
+
+STATIC_INLINE_VM unsigned_word
+om_translate_effective_to_real(om_map *map,
+                              unsigned_word ea,
+                              om_access_types access,
+                              cpu *processor,
+                              unsigned_word cia,
+                              int abort)
+{
+  om_bat *bat = NULL;
+  om_segment_tlb_entry *segment_tlb_entry = NULL;
+  om_page_tlb_entry *page_tlb_entry = NULL;
+  unsigned_word ra;
+
+  if (!map->is_relocate) {
+    ra = ea;
+    TRACE(trace_vm, ("%s, direct map, ea=0x%x\n",
+                    "om_translate_effective_to_real",
+                    ea));
+    return ra;
+  }
+
+  /* match with BAT? */
+  bat = om_effective_to_bat(map, ea);
+  if (bat != NULL) {
+    if (!om_valid_access[1][bat->protection_bits][access]) {
+      TRACE(trace_vm, ("%s, bat protection violation, ea=0x%x\n",
+                      "om_translate_effective_to_real",
+                      ea));
+      if (abort)
+       om_interrupt(processor, cia, ea, access,
+                    protection_violation_storage_interrupt);
+      else
+       return MASK(0, 63);
+    }
+
+    ra = ((ea & bat->block_length_mask) | bat->block_real_page_number);
+    TRACE(trace_vm, ("%s, bat translation, ea=0x%x, ra=0x%x\n",
+                    "om_translate_effective_to_real",
+                    ea, ra));
+    return ra;
+  }
+
+  /* translate ea to va using segment map */
+  segment_tlb_entry = om_effective_to_virtual(map, ea, processor, cia);
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+  if (segment_tlb_entry == NULL) {
+    TRACE(trace_vm, ("%s, segment tlb lookup failed - ea=0x%x\n",
+                    "om_translate_effective_to_real",
+                    ea));
+    if (abort)
+      om_interrupt(processor, cia, ea, access,
+                  segment_table_miss_storage_interrupt);
+    else
+      return MASK(0, 63);
+  }
+#endif
+  /* check for invalid segment access type */
+  if (segment_tlb_entry->invalid_access == access) {
+    TRACE(trace_vm, ("%s, segment tlb access invalid - ea=0x%x\n",
+                    "om_translate_effective_to_real",
+                    ea));
+    if (abort)
+      om_interrupt(processor, cia, ea, access,
+                  protection_violation_storage_interrupt);
+    else
+      return MASK(0, 63);
+  }
+
+  /* lookup in PTE */
+  page_tlb_entry = om_virtual_to_real(map, ea, segment_tlb_entry,
+                                     access,
+                                     processor, cia);
+  if (page_tlb_entry == NULL) {
+    TRACE(trace_vm, ("%s, page tlb lookup failed - ea=0x%x\n",
+                    "om_translate_effective_to_real",
+                    ea));
+    if (abort)
+      om_interrupt(processor, cia, ea, access,
+                  hash_table_miss_storage_interrupt);
+    else
+      return MASK(0, 63);
+  }
+  if (!(om_valid_access
+       [segment_tlb_entry->key[map->is_problem_state]]
+       [page_tlb_entry->protection]
+       [access])) {
+    TRACE(trace_vm, ("%s, page tlb access invalid - ea=0x%x\n",
+                    "om_translate_effective_to_real",
+                    ea));
+    if (abort)
+      om_interrupt(processor, cia, ea, access,
+                  protection_violation_storage_interrupt);
+    else
+      return MASK(0, 63);
+  }
+
+  ra = (page_tlb_entry->masked_real_page_number
+       | om_masked_byte(ea));
+  TRACE(trace_vm, ("%s, page - ea=0x%x, ra=0x%x\n",
+                  "om_translate_effective_to_real",
+                  ea, ra));
+  return ra;
+}
+
+
+/*
+ * Definition of operations for memory management
+ */
+
+
+/* rebuild all the relevant bat information */
+STATIC_INLINE_VM void
+om_unpack_bat(om_bat *bat,
+             spreg ubat,
+             spreg lbat)
+{
+  /* for extracting out the offset within a page */
+  bat->block_length_mask = ((MASKED(ubat, 51, 61) << (17-2))
+                           | MASK(63-17+1, 63));
+
+  /* for checking the effective page index */
+  bat->block_effective_page_index = MASKED(ubat, 0, 46);
+  bat->block_effective_page_index_mask = ~bat->block_length_mask;
+
+  /* protection information */
+  bat->protection_bits = EXTRACTED(lbat, 62, 63);
+  bat->block_real_page_number = MASKED(lbat, 0, 46);
+}
+
+
+/* rebuild the given bat table */
+STATIC_INLINE_VM void
+om_unpack_bats(om_bats *bats,
+              spreg *raw_bats,
+              msreg msr)
+{
+  int i;
+  bats->nr_valid_bat_registers = 0;
+  for (i = 0; i < nr_om_bat_registers*2; i += 2) {
+    spreg ubat = raw_bats[i];
+    spreg lbat = raw_bats[i+1];
+    if ((msr & msr_problem_state)
+       ? EXTRACTED(ubat, 62, 62)
+       : EXTRACTED(ubat, 63, 63)) {
+      om_unpack_bat(&bats->bat[bats->nr_valid_bat_registers],
+                   ubat, lbat);
+      bats->nr_valid_bat_registers += 1;
+    }
+  }
+}
+
+
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+STATIC_INLINE_VM void
+om_unpack_sr(vm *virtual,
+            sreg *srs,
+            int which_sr)
+{
+  om_segment_tlb_entry *segment_tlb_entry = 0;
+  sreg new_sr_value = 0;
+
+  /* check register in range */
+  if (which_sr < 0 || which_sr > nr_om_segment_tlb_entries)
+    error("om_set_sr: segment register out of bounds\n");
+
+  /* get the working values */
+  segment_tlb_entry = &virtual->segment_tlb.entry[which_sr];  
+  new_sr_value = srs[which_sr];
+  
+  /* do we support this */
+  if (MASKED32(new_sr_value, 0, 0))
+    error("om_ser_sr(): unsupported value of T in segment register %d\n",
+         which_sr);
+
+  /* update info */
+  segment_tlb_entry->key[om_supervisor_state] = EXTRACTED32(new_sr_value, 1, 1);
+  segment_tlb_entry->key[om_problem_state] = EXTRACTED32(new_sr_value, 2, 2);
+  segment_tlb_entry->invalid_access = (MASKED32(new_sr_value, 3, 3)
+                                      ? om_instruction_read
+                                      : om_access_any);
+  segment_tlb_entry->masked_virtual_segment_id = MASKED32(new_sr_value, 8, 31);
+}
+#endif
+
+
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+STATIC_INLINE_VM void
+om_unpack_srs(vm *virtual,
+             sreg *srs)
+{
+  int which_sr;
+  for (which_sr = 0; which_sr < nr_om_segment_tlb_entries; which_sr++) {
+    om_unpack_sr(virtual, srs, which_sr);
+  }
+}
+#endif
+
+
+/* Rebuild all the data structures for the new context as specifed by
+   the passed registers */
+INLINE_VM void
+vm_synchronize_context(vm *virtual,
+                      spreg *sprs,
+                      sreg *srs,
+                      msreg msr)
+{
+
+  /* enable/disable translation */
+  int problem_state = (msr & msr_problem_state) != 0;
+  int data_relocate = (msr & msr_data_relocate) != 0;
+  int instruction_relocate = (msr & msr_instruction_relocate) != 0;
+
+  unsigned_word page_table_hash_mask;
+  unsigned_word real_address_of_page_table;
+
+
+  /* update current processor mode */
+  virtual->instruction_map.translation.is_relocate = instruction_relocate;
+  virtual->instruction_map.translation.is_problem_state = problem_state;
+  virtual->data_map.translation.is_relocate = data_relocate;
+  virtual->data_map.translation.is_problem_state = problem_state;
+
+
+  /* update bat registers for the new context */
+  om_unpack_bats(&virtual->ibats, &sprs[spr_ibat0u], msr);
+  om_unpack_bats(&virtual->dbats, &sprs[spr_dbat0u], msr);
+
+
+  /* unpack SDR1 - the storage description register 1 */
+#if (WITH_TARGET_WORD_BITSIZE == 64)
+  real_address_of_page_table = EXTRACTED64(sprs[spr_sdr1], 0, 45);
+  page_table_hash_mask = MASK64(47-EXTRACTED64(sprs[spr_sdr1], 59, 63),
+                               57);
+#endif
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+  real_address_of_page_table = EXTRACTED32(sprs[spr_sdr1], 0, 15);
+  page_table_hash_mask = ((EXTRACTED32(sprs[spr_sdr1], 23, 31) << (10+6))
+                         | MASK32(16, 25));
+#endif
+  virtual->instruction_map.translation.real_address_of_page_table = real_address_of_page_table;
+  virtual->instruction_map.translation.page_table_hash_mask = page_table_hash_mask;
+  virtual->data_map.translation.real_address_of_page_table = real_address_of_page_table;
+  virtual->data_map.translation.page_table_hash_mask = page_table_hash_mask;
+
+
+#if (WITH_TARGET_WORD_BITSIZE == 32)
+  /* unpack the segment tlb registers */
+  om_unpack_srs(virtual, srs);
+#endif
+}
+
+
+INLINE_VM vm_data_map *
+vm_create_data_map(vm *memory)
+{
+  return &memory->data_map;
+}
+
+
+INLINE_VM vm_instruction_map *
+vm_create_instruction_map(vm *memory)
+{
+  return &memory->instruction_map;
+}
+
+
+STATIC_INLINE_VM unsigned_word
+vm_translate(om_map *map,
+            unsigned_word ea,
+            om_access_types access,
+            cpu *processor,
+            unsigned_word cia,
+            int abort)
+{
+  switch (CURRENT_ENVIRONMENT) {
+  case USER_ENVIRONMENT:
+  case VIRTUAL_ENVIRONMENT:
+    return ea;
+  case OPERATING_ENVIRONMENT:
+    return om_translate_effective_to_real(map, ea, access,
+                                         processor, cia,
+                                         abort);
+  default:
+    error("vm_translate() - unknown environment\n");
+    return 0;
+  }
+}
+
+
+INLINE_VM unsigned_word
+vm_real_data_addr(vm_data_map *map,
+                 unsigned_word ea,
+                 int is_read,
+                 cpu *processor,
+                 unsigned_word cia)
+{
+  return vm_translate(&map->translation,
+                     ea,
+                     is_read ? om_data_read : om_data_write,
+                     processor,
+                     cia,
+                     1); /*abort*/
+}
+
+
+INLINE_VM unsigned_word
+vm_real_instruction_addr(vm_instruction_map *map,
+                        cpu *processor,
+                        unsigned_word cia)
+{
+  return vm_translate(&map->translation,
+                     cia,
+                     om_instruction_read,
+                     processor,
+                     cia,
+                     1); /*abort*/
+}
+
+INLINE_VM instruction_word
+vm_instruction_map_read(vm_instruction_map *map,
+                       cpu *processor,
+                       unsigned_word cia)
+{
+  unsigned_word ra = vm_real_instruction_addr(map, processor, cia);
+  ASSERT((cia & 0x3) == 0); /* always aligned */
+  return core_map_read_4(map->code, ra, processor, cia);
+}
+
+
+INLINE_VM int
+vm_data_map_read_buffer(vm_data_map *map,
+                       void *target,
+                       unsigned_word addr,
+                       unsigned nr_bytes)
+{
+  unsigned count;
+  for (count = 0; count < nr_bytes; count++) {
+    unsigned_1 byte;
+    unsigned_word ea = addr + count;
+    unsigned_word ra = vm_translate(&map->translation,
+                                   ea, om_data_read,
+                                   NULL, /*processor*/
+                                   0, /*cia*/
+                                   0); /*dont-abort*/
+    if (ra == MASK(0, 63))
+      break;
+    if (core_map_read_buffer(map->read, &byte, ea, sizeof(byte))
+       != sizeof(byte))
+      break;
+    ((unsigned_1*)target)[count] = T2H_1(byte);
+  }
+  return count;
+}
+
+
+INLINE_VM int
+vm_data_map_write_buffer(vm_data_map *map,
+                        const void *source,
+                        unsigned_word addr,
+                        unsigned nr_bytes,
+                        int violate_read_only_section)
+{
+  unsigned count;
+  unsigned_1 byte;
+  for (count = 0; count < nr_bytes; count++) {
+    unsigned_word ea = addr + count;
+    unsigned_word ra = vm_translate(&map->translation,
+                                   ea, om_data_write,
+                                   NULL/*processor*/,
+                                   0, /*cia*/
+                                   0); /*dont-abort*/
+    if (ra == MASK(0, 63))
+      break;
+    byte = T2H_1(((unsigned_1*)source)[count]);
+    if (core_map_write_buffer((violate_read_only_section
+                              ? map->read
+                              : map->write),
+                             &byte, ra, sizeof(byte)) != sizeof(byte))
+      break;
+  }
+  return count;
+}
+
+
+/* define the read/write 1/2/4/8/word functions */
+
+#undef N
+#define N 1
+#include "vm_n.h"
+
+#undef N
+#define N 2
+#include "vm_n.h"
+
+#undef N
+#define N 4
+#include "vm_n.h"
+
+#undef N
+#define N 8
+#include "vm_n.h"
+
+#undef N
+#define N word
+#include "vm_n.h"
+
+
+
+#endif /* _VM_C_ */
diff --git a/sim/ppc/vm_n.h b/sim/ppc/vm_n.h
new file mode 100644 (file)
index 0000000..63bd54c
--- /dev/null
@@ -0,0 +1,117 @@
+/*  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_VM unsigned_N
+XCONCAT2(vm_data_map_read_,N)(vm_data_map *map,
+                             unsigned_word ea,
+                             cpu *processor,
+                             unsigned_word cia)
+{
+  if ((ea & (sizeof(unsigned_N)-1)) == 0) {
+    unsigned ra = vm_real_data_addr(map, ea, 1/*is-read*/, processor, cia);
+    unsigned_N val = XCONCAT2(core_map_read_,N)(map->read, ra, processor, cia);
+    if (WITH_MON & MONITOR_LOAD_STORE_UNIT)
+      mon_read(ea, ra, sizeof(unsigned_N), processor, cia);
+    TRACE(trace_load_store, ("load cia=0x%x ea=0x%x N=%d val=0x%x\n",
+                            cia, ea, sizeof(unsigned_N), val));
+    return val;
+  }
+  else {
+    switch (CURRENT_ALIGNMENT) {
+    case STRICT_ALIGNMENT:
+      alignment_interrupt(processor, cia, ea);
+      return 0;
+    case NONSTRICT_ALIGNMENT:
+      {
+       unsigned_N rval;
+       unsigned_N val;
+       if (vm_data_map_read_buffer(map, &val, ea, sizeof(unsigned_N))
+           != sizeof(unsigned_N))
+         alignment_interrupt(processor, cia, ea);
+       val = T2H_N(val);
+       if (WITH_MON & MONITOR_LOAD_STORE_UNIT) {
+         /* YUCK */
+         unsigned ra = vm_real_data_addr(map, ea, 1, processor, cia);
+         mon_read(ea, ra, sizeof(unsigned_N), processor, cia);
+       }
+       TRACE(trace_load_store, ("load cia=0x%x ea=0x%x N=%d data=0x%x\n",
+                                cia, ea, sizeof(unsigned_N), val));
+       return val;
+      }
+    default:
+      error("unknown alignment support\n");
+      return 0;
+    }
+  }
+}
+
+INLINE_VM void
+XCONCAT2(vm_data_map_write_,N)(vm_data_map *map,
+                              unsigned_word ea,
+                              unsigned_N val,
+                              cpu *processor,
+                              unsigned_word cia)
+{
+  if ((ea & (sizeof(unsigned_N)-1)) == 0) {
+    unsigned ra = vm_real_data_addr(map, ea, 0/*is-read?*/, processor, cia);
+    XCONCAT2(core_map_write_,N)(map->write, ra, val, processor, cia);
+    if (WITH_MON & MONITOR_LOAD_STORE_UNIT)
+      mon_write(ea, ra, sizeof(unsigned_N), processor, cia);
+    TRACE(trace_load_store, ("store cia=0x%x ea=0x%x N=%d val=0x%x\n",
+                            cia, ea, sizeof(unsigned_N), val));
+  }
+  else {
+    switch (CURRENT_ALIGNMENT) {
+    case STRICT_ALIGNMENT:
+      alignment_interrupt(processor, cia, ea);
+      break;
+    case NONSTRICT_ALIGNMENT:
+      {
+       unsigned_N data = H2T_N(val);
+        if (vm_data_map_write_buffer(map, &data, ea, sizeof(unsigned_N), 0)
+           != sizeof(unsigned_N))
+          alignment_interrupt(processor, cia, ea);
+       if (WITH_MON & MONITOR_LOAD_STORE_UNIT) {
+         /* YUCK */
+         unsigned ra = vm_real_data_addr(map, ea, 1, processor, cia);
+         mon_write(ea, ra, sizeof(unsigned_N), processor, cia);
+       }
+       TRACE(trace_load_store, ("store cia=0x%x ea=0x%x N=%d val=0x%x\n",
+                                cia, ea, sizeof(unsigned_N), val));
+      }
+      break;
+    default:
+      error("unknown alignment support\n");
+    }
+  }
+}