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