aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sim/ppc/ChangeLog56
-rw-r--r--sim/ppc/Makefile.in2
-rwxr-xr-xsim/ppc/configure9
-rw-r--r--sim/ppc/configure.in9
-rw-r--r--sim/ppc/cpu.h53
-rw-r--r--sim/ppc/debug.c114
-rw-r--r--sim/ppc/debug.h1
-rw-r--r--sim/ppc/dgen.c319
-rw-r--r--sim/ppc/igen.c76
-rw-r--r--sim/ppc/interrupts.c413
-rw-r--r--sim/ppc/main.c40
-rw-r--r--sim/ppc/misc.c107
-rw-r--r--sim/ppc/mon.c189
-rw-r--r--sim/ppc/ppc-opcode-stupid96
-rw-r--r--sim/ppc/psim.c748
-rw-r--r--sim/ppc/sim_calls.c107
-rw-r--r--sim/ppc/std-config.h19
-rw-r--r--sim/ppc/vm.c938
-rw-r--r--sim/ppc/vm_n.h117
19 files changed, 2931 insertions, 482 deletions
diff --git a/sim/ppc/ChangeLog b/sim/ppc/ChangeLog
index 66b2465..8094bdc 100644
--- a/sim/ppc/ChangeLog
+++ b/sim/ppc/ChangeLog
@@ -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
diff --git a/sim/ppc/Makefile.in b/sim/ppc/Makefile.in
index f2c7625..566d89e 100644
--- a/sim/ppc/Makefile.in
+++ b/sim/ppc/Makefile.in
@@ -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=
diff --git a/sim/ppc/configure b/sim/ppc/configure
index 3b5059a..3d6b563 100755
--- a/sim/ppc/configure
+++ b/sim/ppc/configure
@@ -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
diff --git a/sim/ppc/configure.in b/sim/ppc/configure.in
index 7b319f5..2f24d64 100644
--- a/sim/ppc/configure.in
+++ b/sim/ppc/configure.in
@@ -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
diff --git a/sim/ppc/cpu.h b/sim/ppc/cpu.h
index f9790e8..a4e4b02 100644
--- a/sim/ppc/cpu.h
+++ b/sim/ppc/cpu.h
@@ -29,13 +29,14 @@
#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
index 0000000..b23644c
--- /dev/null
+++ b/sim/ppc/debug.c
@@ -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_ */
diff --git a/sim/ppc/debug.h b/sim/ppc/debug.h
index b300add..e1cb053 100644
--- a/sim/ppc/debug.h
+++ b/sim/ppc/debug.h
@@ -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
index 0000000..2d6d3a3
--- /dev/null
+++ b/sim/ppc/dgen.c
@@ -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;
+}
diff --git a/sim/ppc/igen.c b/sim/ppc/igen.c
index 78c1494..cab46a0 100644
--- a/sim/ppc/igen.c
+++ b/sim/ppc/igen.c
@@ -31,9 +31,11 @@
/****************************************************************/
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
index 0000000..453ebdb
--- /dev/null
+++ b/sim/ppc/interrupts.c
@@ -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_ */
diff --git a/sim/ppc/main.c b/sim/ppc/main.c
index 1227940..47f506d 100644
--- a/sim/ppc/main.c
+++ b/sim/ppc/main.c
@@ -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
index 0000000..8c62ad2
--- /dev/null
+++ b/sim/ppc/misc.c
@@ -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
index 0000000..60b6fdb
--- /dev/null
+++ b/sim/ppc/mon.c
@@ -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
index 0000000..39795c8
--- /dev/null
+++ b/sim/ppc/ppc-opcode-stupid
@@ -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
diff --git a/sim/ppc/psim.c b/sim/ppc/psim.c
index 96b94e5..66c54ed 100644
--- a/sim/ppc/psim.c
+++ b/sim/ppc/psim.c
@@ -22,6 +22,10 @@
#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"
@@ -36,15 +40,35 @@
#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_ */
diff --git a/sim/ppc/sim_calls.c b/sim/ppc/sim_calls.c
index d3462b3..e262e05 100644
--- a/sim/ppc/sim_calls.c
+++ b/sim/ppc/sim_calls.c
@@ -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;
diff --git a/sim/ppc/std-config.h b/sim/ppc/std-config.h
index 868ab19..69359f4 100644
--- a/sim/ppc/std-config.h
+++ b/sim/ppc/std-config.h
@@ -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
index 0000000..f15e0bf
--- /dev/null
+++ b/sim/ppc/vm.c
@@ -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
index 0000000..63bd54c
--- /dev/null
+++ b/sim/ppc/vm_n.h
@@ -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");
+ }
+ }
+}