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