+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
HDEFINES = @HDEFINES@
TDEFINES =
-IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER)
+IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER) $(IGEN_ICACHE)
.NOEXPORT:
MAKEOVERRIDES=
$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
$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
$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
$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
$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
$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
#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;
(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);
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
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);
(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
(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
--- /dev/null
+/* 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_ */
trace_semantics,
trace_idecode,
trace_alu,
+ trace_load_store,
/**/
trace_vm,
trace_core,
--- /dev/null
+/* 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;
+}
/****************************************************************/
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;
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;";
/****************************************************************/
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])
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]);
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;
/* 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*/
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);
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
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,
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");
}
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));
}
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':
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);
--- /dev/null
+/* 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_ */
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
/* 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();
}
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);
/* 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);
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");
--- /dev/null
+/* 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;
+}
+
+
--- /dev/null
+/* 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_ */
--- /dev/null
+#
+# 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
#ifndef _PSIM_C_
#define _PSIM_C_
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
#include "config.h"
#include "ppc-config.h"
#include "inline.h"
#include "cpu.h" /* includes psim.h */
#include "idecode.h"
+#include "bfd.h"
+
+
#include "inline.c"
+/* Any starting address less than this is assumed to be an OEA program
+ rather than VEA. */
+#ifndef OEA_START_ADDRESS
+#define OEA_START_ADDRESS 4096
+#endif
+
+/* Any starting address greater than this is assumed to be an OpenBoot
+ rather than VEA */
+#ifndef OPENBOOT_START_ADDRESS
+#define OPENBOOT_START_ADDRESS 0x80000000
+#endif
+
+#ifndef OEA_MEMORY_SIZE
+#define OEA_MEMORY_SIZE 0x100000
+#endif
+
/* system structure, actual size of processor array determined at
runtime */
struct _psim {
event_queue *events;
- device_node *devices;
+ device_tree *devices;
+ mon *monitor;
core *memory;
/* escape routine for inner functions */
void *path_to_halt;
/* 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];
};
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*)(¤t_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*)(¤t_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;
}
}
-
-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
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);
}
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.
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)) {
}
} 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
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)) {
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);
}
} 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
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)
}
} 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 ...
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)
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))
}
} while (keep_running == NULL || *keep_running);
}
- psim_clear_halt_and_restart(system);
#endif
+
+ psim_clear_halt_and_restart(system);
}
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
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 */
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);
}
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);
}
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_ */
/* 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;
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;
}
}
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;
}
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;
}
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);
}
{
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);
}
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 */,
switch (CURRENT_ENVIRONMENT) {
+ case USER_ENVIRONMENT:
case VIRTUAL_ENVIRONMENT:
switch (status.reason) {
case was_continuing:
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));
}
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;
/* 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
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:
of of some instruction cycles. */
#ifndef WITH_TIME_BASE
-#define WITH_TIME_BASE 1
+#define WITH_TIME_BASE (WITH_ENVIRONMENT != USER_ENVIRONMENT)
#endif
not a leaf */
#ifndef DEVICE_TREE_INLINE
-#define DEVICE_TREE_INLINE DEFAULT_INLINE
+#define DEVICE_TREE_INLINE 0
#endif
#ifndef DEVICES_INLINE
--- /dev/null
+/* 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_ */
--- /dev/null
+/* 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");
+ }
+ }
+}