Andrew's latest changes & print all instruction counts if -I

This commit is contained in:
Michael Meissner 1995-11-02 14:27:18 +00:00
parent f2cd344130
commit a983c8f080
19 changed files with 2931 additions and 482 deletions

View File

@ -1,3 +1,59 @@
Thu Nov 2 08:54:04 1995 Michael Meissner <meissner@tiktok.cygnus.com>
* main.c (main): Call psim_print_info with verbose == 2.
* mon.c (mon_print_info): Align the cpu number and number of
instructions fields. Do not print an instruction category if the
CPU did not execute any of those instructions.
* configure.in: Add support for --enable-sim-opcode=stupid.
* configure: Regenerate.
Wed Nov 1 23:46:59 1995 Andrew Cagney - aka Noid <cagney@highland.com.au>
* std-config (INLINE_DEVICE_TREE): Don't inline either of
device_tree.c or devices.c. There is no significant gain.
* configure.in, Makefile.in: add --enable-sim-icache=[0-9]* and
IGEN_ICACHE macro.
Wed Nov 1 23:46:59 1995 Andrew Cagney - aka Noid <cagney@highland.com.au>
* igen.c (main), misc.h (target_a2i, i2target), misc.c: Add
functions to convert between target and igen internal bit numbers.
Make IO go through these functions. Add -b (bit size) and -h (high
bit nr) options to igen. Typical usage would be: ./igen -b 16 -h
15 for a 16 bit instruction format with the msb given a number 15.
Wed Nov 1 22:17:32 1995 Andrew Cagney - aka Noid <cagney@highland.com.au>
* dgen.c (main): Was outputting optarg even when it was NULL.
Tue Oct 31 23:48:33 1995 Andrew Cagney - aka Noid <cagney@highland.com.au>
* vm_n.h (vm_data_map_load_N, vm_data_map_store_n), debug.h,
debug.c: Add tracing of load/store unit (virtual) with -t
load-store.
Tue Oct 31 21:44:01 1995 Andrew Cagney - aka Noid <cagney@highland.com.au>
* std-config.h (WITH_ENVIRONMENT): Add USER_ENVIRONMENT which does
not include things such as the time base and events.
* interrupt.c, sim_calls.c, cpu.h, vm.c, configure.in: Add UEA to
all environment switches for above.
* psim.c (psim_create): ditto - new device tree node name is
/options/environment-architecture with values user, virtual and
operating.
Tue Oct 31 21:31:32 1995 Andrew Cagney - aka Noid <cagney@highland.com.au>
* ppc-opcode-stupid: Third example of use of opcode table - this
one expands all mtspr/mfspr and branch instructions. Appears to
give about a 10% gain in performance if everything enabled. Also
takes about 150mb of swap to build.
Wed Nov 1 10:49:48 1995 Michael Meissner <meissner@tiktok.cygnus.com>
* emul_netbsd.c (do_exit): Print arguments and close parenthesis

View File

@ -68,7 +68,7 @@ RANLIB = @RANLIB@
HDEFINES = @HDEFINES@
TDEFINES =
IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER)
IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER) $(IGEN_ICACHE)
.NOEXPORT:
MAKEOVERRIDES=

9
sim/ppc/configure vendored
View File

@ -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

View File

@ -48,7 +48,7 @@ $srcdir/config.make Makefile CONFIG_FILE --enable-sim-config "$enable_sim_config
$srcdir/config.make Makefile IGEN_OPCODE_RULES --enable-sim-opcode "$enable_sim_opcode" \
"" "ppc-opcode-simple" "no" "ppc-opcode-simple" "yes" "ppc-opcode-simple" \
"complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" 1>&6
"complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" "stupid" "ppc-opcode-stupid" 1>&6
$srcdir/config.make Makefile DGEN_FLAGS --enable-sim-switch "$enable_sim_switch" \
"" "" "no" "" "yes" "-s" 1>&6
@ -59,6 +59,9 @@ $srcdir/config.make Makefile IGEN_DUPLICATE --enable-sim-duplicate "$enable_sim_
$srcdir/config.make Makefile IGEN_FILTER --enable-sim-filter "$enable_sim_filter" \
"" "-f 64" "no" "" "yes" "-f 64" "*" "$enable_sim_filter" 1>&6
$srcdir/config.make Makefile IGEN_ICACHE --enable-sim-icache "$enable_sim_icache" \
"" "" "no" "" "yes" "-r 1024" "*" "-r $enable_sim_icache" 1>&6
flags=""
if test x"$enable_sim_inline" != x""; then
case "$enable_sim_inline" in
@ -117,7 +120,9 @@ $srcdir/config.hdr config.h WITH_HOST_WORD_BITSIZE --enable-sim-hostbitsize "$en
$srcdir/config.hdr config.h WITH_ENVIRONMENT --enable-sim-env "$enable_sim_env" \
"yes" "0" \
"operating" "OPERATING_ENVIRONMENT" "os" "OPERATING_ENVIRONMENT" "oea" "OPERATING_ENVIRONMENT" \
"virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" 1>&6
"virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" \
"user" "USER_ENVIRONMENT" "uea" "USER_ENVIRONMENT" \
1>&6
$srcdir/config.hdr config.h WITH_TIME_BASE --enable-sim-timebase "$enable_sim_timebase" \
"no" "0" "yes" "1" 1>&6

View File

@ -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
View 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_ */

View File

@ -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
View 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;
}

View File

@ -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
View 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_ */

View File

@ -70,7 +70,9 @@ zfree(void *chunk)
static void
usage(void)
{
error ("Usage: psim [ -a -p -c -C -s -i -I -t -g ] <image> [ <image-args> ... ]\n");
printf_filtered("Usage:\n\tpsim [ -t <trace-option> ] <image> [ <image-args> ... ]\n");
trace_usage();
error("");
}
int
@ -87,37 +89,15 @@ main(int argc, char **argv)
/* check for arguments -- note sim_calls.c also contains argument processing
code for the simulator linked within gdb. */
while ((letter = getopt (argc, argv, "acCiIpstg")) != EOF)
while ((letter = getopt (argc, argv, "It:")) != EOF)
{
switch (letter) {
case 'a':
for (i = 0; i < nr_trace; i++)
ppc_trace[i] = 1;
break;
case 'p':
ppc_trace[trace_cpu] = ppc_trace[trace_semantics] = 1;
break;
case 'c':
ppc_trace[trace_core] = 1;
break;
case 'C':
ppc_trace[trace_console_device] = 1;
break;
case 's':
ppc_trace[trace_create_stack] = 1;
break;
case 'i':
ppc_trace[trace_icu_device] = 1;
case 't':
trace_option(optarg);
break;
case 'I':
print_info = 1;
break;
case 't':
ppc_trace[trace_device_tree] = 1;
break;
case 'g':
ppc_trace[trace_gdb] = 1;
break;
default:
usage();
}
@ -127,7 +107,7 @@ main(int argc, char **argv)
name_of_file = argv[optind];
/* create the simulator */
system = psim_create(name_of_file, ((WITH_SMP > 0) ? WITH_SMP : 1));
system = psim_create(name_of_file);
/* fudge the environment so that _=prog-name */
arg_ = (char*)zalloc(strlen(argv[optind]) + strlen("_=") + 1);
@ -143,7 +123,7 @@ main(int argc, char **argv)
/* any final clean up */
if (print_info)
psim_print_info (system, 1);
psim_print_info (system, 2);
/* why did we stop */
status = psim_get_status(system);
@ -158,8 +138,8 @@ main(int argc, char **argv)
return status.signal;
case was_signalled:
printf ("%s: Caught signal %d at address 0x%lx\n",
name_of_file, (int)status.signal,
(long)status.program_counter);
name_of_file, (int)status.signal,
(long)status.program_counter);
return status.signal;
default:
error("unknown halt condition\n");

107
sim/ppc/misc.c Normal file
View 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
View 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
View 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

View File

@ -22,6 +22,10 @@
#ifndef _PSIM_C_
#define _PSIM_C_
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include "config.h"
#include "ppc-config.h"
#include "inline.h"
@ -36,15 +40,35 @@
#include "cpu.h" /* includes psim.h */
#include "idecode.h"
#include "bfd.h"
#include "inline.c"
/* Any starting address less than this is assumed to be an OEA program
rather than VEA. */
#ifndef OEA_START_ADDRESS
#define OEA_START_ADDRESS 4096
#endif
/* Any starting address greater than this is assumed to be an OpenBoot
rather than VEA */
#ifndef OPENBOOT_START_ADDRESS
#define OPENBOOT_START_ADDRESS 0x80000000
#endif
#ifndef OEA_MEMORY_SIZE
#define OEA_MEMORY_SIZE 0x100000
#endif
/* system structure, actual size of processor array determined at
runtime */
struct _psim {
event_queue *events;
device_node *devices;
device_tree *devices;
mon *monitor;
core *memory;
/* escape routine for inner functions */
void *path_to_halt;
@ -54,7 +78,7 @@ struct _psim {
/* the processes proper */
int nr_cpus;
int last_cpu; /* CPU that last (tried to) execute an instruction */
cpu *processors[0];
cpu *processors[MAX_NR_PROCESSORS];
};
@ -62,64 +86,348 @@ int current_target_byte_order;
int current_host_byte_order;
int current_environment;
int current_alignment;
int current_floating_point;
/* create a device tree from the image */
/* Raw hardware tree:
A small default set of devices are configured. Each section of the
image is loaded directly into physical memory. */
STATIC_INLINE_PSIM void
create_hardware_device_tree(bfd *image,
device_tree *root)
{
char *name;
const memory_size = OEA_MEMORY_SIZE;
/* options */
device_tree_add_passthrough(root, "/options");
device_tree_add_integer(root, "/options/smp",
MAX_NR_PROCESSORS);
device_tree_add_boolean(root, "/options/little-endian?",
!image->xvec->byteorder_big_p);
device_tree_add_string(root, "/options/environment-architecture",
"operating");
device_tree_add_boolean(root, "/options/strict-alignment?",
(WITH_ALIGNMENT == STRICT_ALIGNMENT
|| !image->xvec->byteorder_big_p));
device_tree_add_boolean(root, "/options/floating-point?",
WITH_FLOATING_POINT);
/* hardware */
name = printd_uw_u_u("/memory", 0, memory_size, access_read_write_exec);
device_tree_add_found_device(root, name);
zfree(name);
device_tree_add_found_device(root, "/iobus@0x400000");
device_tree_add_found_device(root, "/iobus/console@0x000000,16");
device_tree_add_found_device(root, "/iobus/halt@0x100000,4");
device_tree_add_found_device(root, "/iobus/icu@0x200000,4");
/* initialization */
device_tree_add_passthrough(root, "/init");
device_tree_add_found_device(root, "/init/register@pc,0x0");
name = printd_c_uw("/init/register", "sp", memory_size);
device_tree_add_found_device(root, name);
zfree(name);
name = printd_c_uw("/init/register", "msr",
(image->xvec->byteorder_big_p
? 0
: msr_little_endian_mode));
device_tree_add_found_device(root, name);
zfree(name);
/* AJC puts the PC at zero and wants a stack while MM puts it above
zero and doesn't. Really there should be no stack *but* this
makes testing easier */
device_tree_add_found_device(root,
(bfd_get_start_address(image) == 0
? "/init/stack@elf"
: "/init/stack@none"));
name = printd_c("/init/load-binary", bfd_get_filename(image));
device_tree_add_found_device(root, name);
zfree(name);
}
/* Openboot model (under development):
An extension of the hardware model. The image is read into memory
as a single block. Sections of the image are then mapped as
required using a HTAB. */
STATIC_INLINE_PSIM void
create_openboot_device_tree(bfd *image,
device_tree *root)
{
create_hardware_device_tree(image, root);
}
/* User mode model:
Image sections loaded into virtual addresses as specified. A
(large) stack is reserved (but only allocated as needed). System
calls that include suport for heap growth are attached. */
STATIC_INLINE_PSIM void
create_vea_device_tree(bfd *image,
device_tree *root)
{
unsigned_word top_of_stack;
unsigned stack_size;
int elf_binary;
char *name;
/* establish a few defaults */
if (image->xvec->flavour == bfd_target_elf_flavour) {
elf_binary = 1;
top_of_stack = 0xe0000000;
stack_size = 0x00100000;
}
else {
elf_binary = 0;
top_of_stack = 0x20000000;
stack_size = 0x00100000;
}
/* options */
device_tree_add_passthrough(root, "/options");
device_tree_add_integer(root, "/options/smp", 1); /* always */
device_tree_add_boolean(root, "/options/little-endian?",
!image->xvec->byteorder_big_p);
device_tree_add_string(root, "/options/environment-architecture",
(WITH_ENVIRONMENT == USER_ENVIRONMENT
? "user" : "virtual"));
device_tree_add_boolean(root, "/options/strict-alignment?",
(WITH_ALIGNMENT == STRICT_ALIGNMENT
|| !image->xvec->byteorder_big_p));
device_tree_add_boolean(root, "/options/floating-point?",
WITH_FLOATING_POINT);
/* virtual memory - handles growth of stack/heap */
name = printd_uw_u("/vm", top_of_stack - stack_size, stack_size);
device_tree_add_found_device(root, name);
zfree(name);
name = printd_c("/vm/map-binary", bfd_get_filename(image));
device_tree_add_found_device(root, name);
zfree(name);
/* finish the init */
device_tree_add_passthrough(root, "/init");
name = printd_c_uw("/init/register", "pc", bfd_get_start_address(image));
device_tree_add_found_device(root, name); /*pc*/
zfree(name);
name = printd_c_uw("/init/register", "sp", top_of_stack);
device_tree_add_found_device(root, name);
zfree(name);
name = printd_c_uw("/init/register", "msr",
(image->xvec->byteorder_big_p
? 0
: msr_little_endian_mode));
device_tree_add_found_device(root, name);
zfree(name);
device_tree_add_found_device(root, (elf_binary
? "/init/stack@elf"
: "/init/stack@xcoff"));
}
/* File device:
The file contains lines that specify the describe the device tree
to be created, read them in and load them into the tree */
STATIC_INLINE_PSIM void
create_filed_device_tree(const char *file_name,
device_tree *root)
{
FILE *description = fopen(file_name, "r");
int line_nr = 0;
char device_path[1000];
while (fgets(device_path, sizeof(device_path), description)) {
/* check all of line was read */
{
char *end = strchr(device_path, '\n');
if (end == NULL) {
fclose(description);
error("create_filed_device_tree() line %d to long: %s\n",
line_nr, device_path);
}
line_nr++;
*end = '\0';
}
/* check for leading comment */
if (device_path[0] != '/')
continue;
/* enter it in varying ways */
if (strchr(device_path, '@') != NULL) {
device_tree_add_found_device(root, device_path);
}
else {
char *space = strchr(device_path, ' ');
if (space == NULL) {
/* intermediate node */
device_tree_add_passthrough(root, device_path);
}
else if (space[-1] == '?') {
/* boolean */
*space = '\0';
device_tree_add_boolean(root, device_path, space[1] != '0');
}
else if (isdigit(space[1])) {
/* integer */
*space = '\0';
device_tree_add_integer(root, device_path, strtoul(space+1, 0, 0));
}
else if (space[1] == '"') {
/* quoted string */
char *end = strchr(space+2, '\0');
if (end[-1] == '"')
end[-1] = '\0';
*space = '\0';
device_tree_add_string(root, device_path, space + 2);
}
else {
/* any thing else */
space = '\0';
device_tree_add_string(root, device_path, space + 1);
}
}
}
fclose(description);
}
/* Given the file containing the `image', create a device tree that
defines the machine to be modeled */
STATIC_INLINE_PSIM device_tree *
create_device_tree(const char *file_name,
core *memory)
{
bfd *image;
const device *core_device = core_device_create(memory);
device_tree *root = device_tree_add_device(NULL, "/", core_device);
bfd_init(); /* could be redundant but ... */
/* open the file */
image = bfd_openr(file_name, NULL);
if (image == NULL) {
bfd_perror("open failed:");
error("nothing loaded\n");
}
/* check it is valid */
if (!bfd_check_format(image, bfd_object)) {
printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
bfd_close(image);
image = NULL;
}
/* depending on what was found about the file, load it */
if (image != NULL) {
if (bfd_get_start_address(image) < OEA_START_ADDRESS) {
TRACE(trace_device_tree, ("create_device_tree() - hardware image\n"));
create_hardware_device_tree(image, root);
}
else if (bfd_get_start_address(image) < OPENBOOT_START_ADDRESS) {
TRACE(trace_device_tree, ("create_device_tree() - vea image\n"));
create_vea_device_tree(image, root);
}
else {
TRACE(trace_device_tree, ("create_device_tree() - openboot? image\n"));
create_openboot_device_tree(image, root);
}
bfd_close(image);
}
else {
TRACE(trace_device_tree, ("create_device_tree() - text image\n"));
create_filed_device_tree(file_name, root);
}
return root;
}
INLINE_PSIM psim *
psim_create(const char *file_name,
int nr_processors)
psim_create(const char *file_name)
{
int cpu_nr;
const char *env;
psim *system;
/* sanity check */
if (nr_processors <= 0
|| (!WITH_SMP && nr_processors != 1))
error("psim_create() invalid number of cpus\n");
/* create things */
system = (psim*)zalloc(sizeof(psim)
+ sizeof(cpu*) * (nr_processors + 1));
system->nr_cpus = nr_processors;
system = ZALLOC(psim);
system->events = event_queue_create();
system->devices = device_tree_create(file_name);
system->memory = core_create(system->devices, 0);
for (cpu_nr = 0; cpu_nr < nr_processors; cpu_nr++) {
system->memory = core_create();
system->monitor = mon_create();
system->devices = create_device_tree(file_name, system->memory);
for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
system->processors[cpu_nr] = cpu_create(system,
system->memory,
system->events,
mon_cpu(system->monitor,
cpu_nr),
cpu_nr);
}
/* fill in the missing endian information */
current_target_byte_order
= (device_tree_find_boolean(system->devices, "/options/little-endian?")
? LITTLE_ENDIAN
: BIG_ENDIAN);
if (WITH_TARGET_BYTE_ORDER
&& WITH_TARGET_BYTE_ORDER != current_target_byte_order)
/* fill in the missing real number of CPU's */
system->nr_cpus = device_tree_find_integer(system->devices,
"/options/smp");
/* fill in the missing TARGET BYTE ORDER information */
current_target_byte_order = (device_tree_find_boolean(system->devices,
"/options/little-endian?")
? LITTLE_ENDIAN
: BIG_ENDIAN);
if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
error("target byte order conflict\n");
current_host_byte_order = 1;
current_host_byte_order = (*(char*)(&current_host_byte_order)
? LITTLE_ENDIAN
: BIG_ENDIAN);
if (WITH_HOST_BYTE_ORDER
&& WITH_HOST_BYTE_ORDER != current_host_byte_order)
/* fill in the missing HOST BYTE ORDER information */
current_host_byte_order = (current_host_byte_order = 1,
(*(char*)(&current_host_byte_order)
? LITTLE_ENDIAN
: BIG_ENDIAN));
if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order)
error("host byte order conflict\n");
/* fill in the missing OEA/VEA information */
current_environment = (device_tree_find_boolean(system->devices,
"/options/vea?")
env = device_tree_find_string(system->devices,
"/options/environment-architecture");
current_environment = (strcmp(env, "user") == 0
? USER_ENVIRONMENT
: strcmp(env, "virtual") == 0
? VIRTUAL_ENVIRONMENT
: OPERATING_ENVIRONMENT);
: strcmp(env, "operating") == 0
? OPERATING_ENVIRONMENT
: 0);
if (current_environment == 0)
error("unreconized /options/environment-architecture\n");
if (CURRENT_ENVIRONMENT != current_environment)
error("target environment conflict\n");
/* fill in the missing ALLIGNMENT information */
current_alignment = (device_tree_find_boolean(system->devices,
"/options/aligned?")
"/options/strict-alignment?")
? STRICT_ALIGNMENT
: NONSTRICT_ALIGNMENT);
if (WITH_ALIGNMENT
&& CURRENT_ALIGNMENT != WITH_ALIGNMENT)
error("target alignment support conflict\n");
if (CURRENT_ALIGNMENT != current_alignment)
error("target alignment conflict\n");
/* fill in the missing FLOATING POINT information */
current_floating_point = (device_tree_find_boolean(system->devices,
"/options/floating-point?")
? HARD_FLOATING_POINT
: SOFT_FLOATING_POINT);
if (CURRENT_FLOATING_POINT != current_floating_point)
error("target floating-point conflict\n");
return system;
}
@ -185,207 +493,32 @@ psim_cpu(psim *system,
}
STATIC_INLINE_PSIM int
sizeof_argument_strings(char **arg)
const device *
psim_device(psim *system,
const char *path)
{
int sizeof_strings = 0;
/* robust */
if (arg == NULL)
return 0;
/* add up all the string sizes (padding as we go) */
for (; *arg != NULL; arg++) {
int len = strlen(*arg) + 1;
sizeof_strings += ALIGN_8(len);
}
return sizeof_strings;
return device_tree_find_device(system->devices, path);
}
STATIC_INLINE_PSIM int
number_of_arguments(char **arg)
{
int nr;
if (arg == NULL)
return 0;
for (nr = 0; *arg != NULL; arg++, nr++);
return nr;
}
STATIC_INLINE_PSIM int
sizeof_arguments(char **arg)
{
return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
}
STATIC_INLINE_PSIM void
write_stack_arguments(psim *system,
char **arg,
unsigned_word start_block,
unsigned_word start_arg)
{
if (CURRENT_ENVIRONMENT != VIRTUAL_ENVIRONMENT)
{
TRACE(trace_create_stack, ("write_stack_arguments() - skipping, OEA program\n"));
return;
}
TRACE(trace_create_stack,
("write_stack_arguments() - %s=0x%x %s=0x%x %s=0x%x %s=0x%x\n",
"system", system, "arg", arg,
"start_block", start_block, "start_arg", start_arg));
if (arg == NULL)
error("write_arguments: character array NULL\n");
/* only copy in arguments, memory is already zero */
for (; *arg != NULL; arg++) {
int len = strlen(*arg)+1;
TRACE(trace_create_stack,
("write_stack_arguments - write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n",
"**arg", *arg, "start_block", start_block,
"len", len, "start_arg", start_arg));
if (psim_write_memory(system, 0, *arg,
start_block, len,
raw_transfer, 0) != len)
error("write_arguments() - write of **arg (%s) at 0x%x failed\n",
*arg, start_block);
if (psim_write_memory(system, 0, &start_block,
start_arg, sizeof(start_block),
cooked_transfer, 0) != sizeof(start_block))
error("write_arguments() - write of *arg failed\n");
start_block += ALIGN_8(len);
start_arg += sizeof(start_block);
}
}
STATIC_INLINE_PSIM void
create_elf_stack_frame(psim *system,
unsigned_word bottom_of_stack,
char **argv,
char **envp)
{
/* fixme - this is over aligned */
/* information block */
const unsigned sizeof_envp_block = sizeof_argument_strings(envp);
const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block;
const unsigned sizeof_argv_block = sizeof_argument_strings(argv);
const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block;
/* auxiliary vector - contains only one entry */
const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */
const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry);
/* environment points (including null sentinal) */
const unsigned sizeof_envp = sizeof_arguments(envp);
const unsigned_word start_envp = start_aux - sizeof_envp;
/* argument pointers (including null sentinal) */
const int argc = number_of_arguments(argv);
const unsigned sizeof_argv = sizeof_arguments(argv);
const unsigned_word start_argv = start_envp - sizeof_argv;
/* link register save address - alligned to a 16byte boundary */
const unsigned_word top_of_stack = ((start_argv
- 2 * sizeof(unsigned_word))
& ~0xf);
/* force some stack space */
if (CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT
&& core_stack_lower_bound(system->memory) > top_of_stack) {
unsigned_word extra_stack_space = (core_stack_lower_bound(system->memory)
- FLOOR_PAGE(top_of_stack));
TRACE(trace_create_stack,
("create_elf_stack_frame() - growing stack by 0x%x\n",
extra_stack_space));
core_add_stack(system->memory, extra_stack_space);
}
/* install arguments on stack */
write_stack_arguments(system, envp, start_envp_block, start_envp);
write_stack_arguments(system, argv, start_argv_block, start_argv);
/* set up the registers */
psim_write_register(system, -1,
&top_of_stack, "r1", cooked_transfer);
psim_write_register(system, -1,
&argc, "r3", cooked_transfer);
psim_write_register(system, -1,
&start_argv, "r4", cooked_transfer);
psim_write_register(system, -1,
&start_envp, "r5", cooked_transfer);
psim_write_register(system, -1,
&start_aux, "r6", cooked_transfer);
}
STATIC_INLINE_PSIM void
create_aix_stack_frame(psim *system,
unsigned_word bottom_of_stack,
char **argv,
char **envp)
{
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_ */

View File

@ -39,7 +39,6 @@
/* Structures used by the simulator, for gdb just have static structures */
static psim *simulator;
static int nr_cpus;
static char *register_names[] = REGISTER_NAMES;
static int print_info = 0;
@ -52,53 +51,39 @@ sim_open (char *args)
TRACE(trace_gdb, ("sim_open(args=%s) called\n", args ? args : "(null)"));
if (args) {
char *buf = (char *)alloca (strlen (args) + 1);
char *p;
strcpy (buf, args);
char **argv = buildargv(args);
int argp = 0;
int argc;
for (argc = 0; argv[argc]; argc++);
p = strtok (args, " \t");
while (p != (char *)0) {
if (*p != '-')
error ("Argument is not an option '%s'", p);
while (argp < argc) {
if (*argv[argp] != '-')
error ("Argument is not an option '%s'", argv[argp]);
else {
/* check arguments -- note, main.c also contains argument processing
code for the standalone emulator. */
while (*++p != '\0') {
char *p = argv[argp] + 1;
while (*p != '\0') {
switch (*p) {
default:
error ("Usage: target sim [ -a -p -c -C -s -i -I -t ]\n");
printf_filtered("Usage:\n\ttarget sim [ -t <trace-option> ]\n");
trace_usage();
error ("");
break;
case 'a':
for (i = 0; i < nr_trace; i++)
trace[i] = 1;
break;
case 'p':
trace[trace_cpu] = trace[trace_semantics] = 1;
break;
case 'c':
trace[trace_core] = 1;
break;
case 'C':
trace[trace_console_device] = 1;
break;
case 's':
trace[trace_create_stack] = 1;
break;
case 'i':
trace[trace_icu_device] = 1;
case 't':
argp += 1;
if (argv[argp] == NULL)
error("Missing <trace> option for -t\n");
trace_option(argv[argp]); /* better fail if NULL */
break;
case 'I':
print_info = 1;
break;
case 't':
trace[trace_device_tree] = 1;
break;
}
}
}
p = strtok ((char *)0, " \t");
argp += 1;
}
}
@ -122,24 +107,26 @@ sim_close (int quitting)
int
sim_load (char *prog, int from_tty)
{
char **argv;
TRACE(trace_gdb, ("sim_load(prog=%s, from_tty=%d) called\n",
prog, from_tty));
ASSERT(prog != NULL);
/* sanity check */
if (prog == NULL) {
error ("sim_load() - TBD - read stan shebs e-mail about how to find the program name?\n");
return -1;
}
TRACE(trace_tbd, ("sim_load() - TBD - parse that prog stripping things like quotes\n"));
/* parse the arguments, assume that the file is argument 0 */
argv = buildargv(prog);
ASSERT(argv != NULL && argv[0] != NULL);
/* create the simulator */
TRACE(trace_gdb, ("sim_load() - first time, create the simulator\n"));
nr_cpus = (WITH_SMP ? WITH_SMP : 1);
simulator = psim_create(prog, nr_cpus);
simulator = psim_create(argv[0]);
/* bring in all the data section */
psim_load(simulator);
psim_init(simulator);
/* release the arguments */
freeargv(argv);
/* `I did it my way' */
return 0;
}
@ -155,16 +142,23 @@ sim_kill (void)
int
sim_read (SIM_ADDR mem, unsigned char *buf, int length)
{
return psim_read_memory(simulator, nr_cpus, buf, mem, length,
raw_transfer);
int result = psim_read_memory(simulator, MAX_NR_PROCESSORS,
buf, mem, length);
TRACE(trace_gdb, ("sim_read(mem=0x%x, buf=0x%x, length=%d) = %d\n",
mem, buf, length, result));
return result;
}
int
sim_write (SIM_ADDR mem, unsigned char *buf, int length)
{
return psim_write_memory(simulator, nr_cpus, buf, mem, length,
raw_transfer, 1/*violate_ro*/);
int result = psim_write_memory(simulator, MAX_NR_PROCESSORS,
buf, mem, length,
1/*violate_ro*/);
TRACE(trace_gdb, ("sim_write(mem=0x%x, buf=0x%x, length=%d) = %d\n",
mem, buf, length, result));
return result;
}
@ -174,8 +168,10 @@ sim_fetch_register (int regno, unsigned char *buf)
if (simulator == NULL) {
return;
}
psim_read_register(simulator, nr_cpus, buf, register_names[regno],
TRACE(trace_gdb, ("sim_fetch_register(regno=%d(%s), buf=0x%x)\n",
regno, register_names[regno], buf));
psim_read_register(simulator, MAX_NR_PROCESSORS,
buf, register_names[regno],
raw_transfer);
}
@ -185,8 +181,10 @@ sim_store_register (int regno, unsigned char *buf)
{
if (simulator == NULL)
return;
psim_write_register(simulator, nr_cpus, buf, register_names[regno],
TRACE(trace_gdb, ("sim_store_register(regno=%d(%s), buf=0x%x)\n",
regno, register_names[regno], buf));
psim_write_register(simulator, MAX_NR_PROCESSORS,
buf, register_names[regno],
raw_transfer);
}
@ -207,7 +205,7 @@ sim_create_inferior (SIM_ADDR start_address, char **argv, char **envp)
TRACE(trace_gdb, ("sim_create_inferior(start_address=0x%x, ...)\n",
start_address));
psim_load(simulator);
psim_init(simulator);
psim_stack(simulator, argv, envp);
psim_write_register(simulator, -1 /* all start at same PC */,
@ -224,6 +222,7 @@ sim_stop_reason (enum sim_stop *reason, int *sigrc)
switch (CURRENT_ENVIRONMENT) {
case USER_ENVIRONMENT:
case VIRTUAL_ENVIRONMENT:
switch (status.reason) {
case was_continuing:
@ -257,6 +256,9 @@ sim_stop_reason (enum sim_stop *reason, int *sigrc)
error("sim_stop_reason() - unknown environment\n");
}
TRACE(trace_gdb, ("sim_stop_reason(reason=0x%x(%d), sigrc=0x%x(%d))\n",
reason, *reason, sigrc, *sigrc));
}
@ -274,6 +276,9 @@ sim_resume (int step, int siggnal)
void (*prev) ();
unsigned_word program_counter;
TRACE(trace_gdb, ("sim_resume(step=%d, siggnal=%d)\n",
step, siggnal));
prev = signal(SIGINT, sim_ctrl_c);
sim_should_run = 1;

View File

@ -96,18 +96,19 @@ extern int current_target_byte_order;
/* Program environment:
Two environments are available. VEA (or virtual environment
architecture) and OEA (or operating environment architecture). The
former is the environment that a user program would see while the
latter is the environment as seen by an operating system. By
Three environments are available - UEA (user), VEA (virtual) and
OEA (perating). The former two are environment that users would
expect to see (VEA includes things like coherency and the time
base) while OEA is what an operating system expects to see. By
setting these to specific values, the build process is able to
eliminate non relevent environment code
CURRENT_ENVIRONMENT specifies which of vea or oea is required for
the current runtime. */
#define VIRTUAL_ENVIRONMENT 1
#define OPERATING_ENVIRONMENT 2
#define USER_ENVIRONMENT 1
#define VIRTUAL_ENVIRONMENT 2
#define OPERATING_ENVIRONMENT 3
#ifndef WITH_ENVIRONMENT
#define WITH_ENVIRONMENT 0
@ -131,7 +132,7 @@ extern int current_environment;
queue implements this. Unfortunatly this adds the need to check
for any events once each full instruction cycle. */
#define WITH_EVENTS (WITH_ENVIRONMENT != VIRTUAL_ENVIRONMENT)
#define WITH_EVENTS (WITH_ENVIRONMENT != USER_ENVIRONMENT)
/* Time base:
@ -141,7 +142,7 @@ extern int current_environment;
of of some instruction cycles. */
#ifndef WITH_TIME_BASE
#define WITH_TIME_BASE 1
#define WITH_TIME_BASE (WITH_ENVIRONMENT != USER_ENVIRONMENT)
#endif
@ -374,7 +375,7 @@ extern int current_floating_point;
not a leaf */
#ifndef DEVICE_TREE_INLINE
#define DEVICE_TREE_INLINE DEFAULT_INLINE
#define DEVICE_TREE_INLINE 0
#endif
#ifndef DEVICES_INLINE

938
sim/ppc/vm.c Normal file
View 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
View 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");
}
}
}