diff options
-rw-r--r-- | sim/ppc/ChangeLog | 21 | ||||
-rw-r--r-- | sim/ppc/cpu.c | 300 | ||||
-rw-r--r-- | sim/ppc/cpu.h | 187 | ||||
-rw-r--r-- | sim/ppc/gen.c | 2 | ||||
-rw-r--r-- | sim/ppc/main.c | 9 | ||||
-rw-r--r-- | sim/ppc/psim.c | 14 | ||||
-rw-r--r-- | sim/ppc/psim.h | 140 | ||||
-rw-r--r-- | sim/ppc/sim_calls.c | 12 |
8 files changed, 680 insertions, 5 deletions
diff --git a/sim/ppc/ChangeLog b/sim/ppc/ChangeLog index ed3b900..f041e61 100644 --- a/sim/ppc/ChangeLog +++ b/sim/ppc/ChangeLog @@ -1,9 +1,28 @@ Mon Oct 2 11:46:37 1995 Michael Meissner <meissner@tiktok.cygnus.com> + * cpu.c (struct _cpu): Add number_of_insns field to tract how many + instructions are executed. + (cpu_increment_number_of_insns): New function to increment the + number of instructions issued. + (cpu_get_number_of_insns): New function to return the number of + instructions issued. + (cpu_print_info): New function to print cpu related information. + At present, print the number of instructions executed. + + * gen_idecode_c: Emit call to cpu_increment_number_of_insns within + idecode_issue. + + * psim.c (psim_print_info): New function to iterate over each of + the CPU's calling cpu_print_info. + + * psim.h,cpu.h: Add new declarations. + * sim_calls.c (sim_open): Add argument processing to add the same switches main.c accepts for the standalone processor. + (sim_close): Call psim_print_info if -I. + * main.c (main): Add comment saying to update sim_calls.c when - adding switches. + adding switches. Add -I to call psim_print_info when done. Sun Oct 1 13:52:59 1995 Michael Meissner <meissner@tiktok.cygnus.com> diff --git a/sim/ppc/cpu.c b/sim/ppc/cpu.c new file mode 100644 index 0000000..1ced239 --- /dev/null +++ b/sim/ppc/cpu.c @@ -0,0 +1,300 @@ +/* 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 _CPU_C_ +#define _CPU_C_ + +#ifndef STATIC_INLINE_CPU +#define STATIC_INLINE_CPU STATIC_INLINE +#endif + +#include <setjmp.h> + +#include "cpu.h" +#include "idecode.h" + +struct _cpu { + + /* the registers */ + registers regs; + + /* current instruction address */ + unsigned_word program_counter; + + /* the memory maps */ + core *physical; /* all of memory */ + vm *virtual; + vm_instruction_map *instruction_map; /* instructions */ + vm_data_map *data_map; /* data */ + + /* current state of interrupt inputs */ + int external_exception_pending; + + /* the system this processor is contained within */ + psim *system; + event_queue *events; + int cpu_nr; + + /* if required, a cache to store decoded instructions */ +#if WITH_IDECODE_CACHE + idecode_cache icache[IDECODE_CACHE_SIZE]; +#endif + + /* address reservation: keep the physical address and the contents + of memory at that address */ + memory_reservation reservation; + + /* offset from event time to this cpu's idea of the local time */ + signed64 time_base_local_time; + signed64 decrementer_local_time; + event_entry_tag decrementer_event; + + /* Counts of number of instructions executed. */ + long number_of_insns; +}; + + +INLINE_CPU cpu * +cpu_create(psim *system, + core *memory, + event_queue *events, + int cpu_nr) +{ + cpu *processor = ZALLOC(cpu); + + /* create the virtual memory map from the core */ + processor->physical = memory; + processor->virtual = vm_create(memory); + processor->instruction_map = vm_create_instruction_map(processor->virtual); + processor->data_map = vm_create_data_map(processor->virtual); + + /* link back to core system */ + processor->system = system; + processor->events = events; + processor->cpu_nr = cpu_nr; + + return processor; +} + + +/* find ones way home */ + +INLINE_CPU psim * +cpu_system(cpu *processor) +{ + return processor->system; +} + +INLINE_CPU int +cpu_nr(cpu *processor) +{ + return processor->cpu_nr; +} + +INLINE_CPU event_queue * +cpu_event_queue(cpu *processor) +{ + return processor->events; +} + + +/* The processors local concept of time */ + +INLINE_CPU signed64 +cpu_get_time_base(cpu *processor) +{ + return (event_queue_time(processor->events) + + processor->time_base_local_time); +} + +INLINE_CPU void +cpu_set_time_base(cpu *processor, + signed64 time_base) +{ + processor->time_base_local_time = (event_queue_time(processor->events) + - time_base); +} + +INLINE_CPU signed32 +cpu_get_decrementer(cpu *processor) +{ + return (processor->decrementer_local_time + - event_queue_time(processor->events)); +} + +STATIC_INLINE_CPU void +cpu_decrement_event(event_queue *queue, + void *data) +{ + cpu *processor = (cpu*)data; + if (!decrementer_interrupt(processor)) { + processor->decrementer_event = event_queue_schedule(processor->events, + 1, /* NOW! */ + cpu_decrement_event, + processor); + } +} + +INLINE_CPU void +cpu_set_decrementer(cpu *processor, + signed32 decrementer) +{ + signed64 old_decrementer = (processor->decrementer_local_time + - event_queue_time(processor->events)); + event_queue_deschedule(processor->events, processor->decrementer_event); + processor->decrementer_local_time = (event_queue_time(processor->events) + + decrementer); + if (decrementer < 0 && old_decrementer >= 0) + /* dec interrupt occures if the sign of the decrement reg is + changed by the load operation */ + processor->decrementer_event = event_queue_schedule(processor->events, + 1, /* NOW! */ + cpu_decrement_event, + processor); + else if (decrementer >= 0) + processor->decrementer_event = event_queue_schedule(processor->events, + decrementer, + cpu_decrement_event, + processor); +} + + +/* program counter manipulation */ + +INLINE_CPU void +cpu_set_program_counter(cpu *processor, + unsigned_word new_program_counter) +{ + processor->program_counter = new_program_counter; +} + +INLINE_CPU unsigned_word +cpu_get_program_counter(cpu *processor) +{ + return processor->program_counter; +} + +INLINE_CPU void +cpu_restart(cpu *processor, + unsigned_word nia) +{ + processor->program_counter = nia; + psim_restart(processor->system, processor->cpu_nr); +} + +INLINE_CPU void +cpu_halt(cpu *processor, + unsigned_word cia, + stop_reason reason, + int signal) +{ + processor->program_counter = cia; + psim_halt(processor->system, processor->cpu_nr, cia, reason, signal); +} + + +#if WITH_IDECODE_CACHE +/* allow access to the cpu's instruction cache */ +INLINE_CPU idecode_cache * +cpu_icache(cpu *processor) +{ + return processor->icache; +} +#endif + + +/* address map revelation */ + +INLINE_CPU vm_instruction_map * +cpu_instruction_map(cpu *processor) +{ + return processor->instruction_map; +} + +INLINE_CPU vm_data_map * +cpu_data_map(cpu *processor) +{ + return processor->data_map; +} + +INLINE_CPU core * +cpu_core(cpu *processor) +{ + return processor->physical; +} + + +/* reservation access */ + +INLINE_CPU memory_reservation * +cpu_reservation(cpu *processor) +{ + return &processor->reservation; +} + + +/* register access */ + +INLINE_CPU registers * +cpu_registers(cpu *processor) +{ + return &processor->regs; +} + +INLINE_CPU void +cpu_synchronize_context(cpu *processor) +{ +#if WITH_IDECODE_CACHE + /* kill off the contents of the cache */ + int i; + for (i = 0; i < IDECODE_CACHE_SIZE; i++) + processor->icache[i].address = MASK(0,63); +#endif + vm_synchronize_context(processor->virtual, + processor->regs.spr, + processor->regs.sr, + processor->regs.msr); +} + + +/* # of instructions counter access */ + +INLINE_CPU void +cpu_increment_number_of_insns(cpu *processor) +{ + processor->number_of_insns++; +} + +INLINE_CPU long +cpu_get_number_of_insns(cpu *processor) +{ + return processor->number_of_insns; +} + +INLINE_CPU void +cpu_print_info(cpu *processor, int verbose) +{ + printf_filtered("CPU %d executed %ld instructions.\n", + processor->cpu_nr+1, + processor->number_of_insns); +} + +#endif /* _CPU_C_ */ diff --git a/sim/ppc/cpu.h b/sim/ppc/cpu.h new file mode 100644 index 0000000..f9790e8 --- /dev/null +++ b/sim/ppc/cpu.h @@ -0,0 +1,187 @@ +/* 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 _CPU_H_ +#define _CPU_H_ + +#ifndef INLINE_CPU +#define INLINE_CPU +#endif + +#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" + + +/* typedef struct _cpu cpu; + + Declared in basics.h because it is used opaquely throughout the + code */ + + +/* Create a cpu object */ + +INLINE_CPU cpu *cpu_create +(psim *system, + core *memory, + event_queue *events, + int cpu_nr); + + +/* Find our way home */ + +INLINE_CPU psim *cpu_system +(cpu *processor); + +INLINE_CPU int cpu_nr +(cpu *processor); + +INLINE_CPU event_queue *cpu_event_queue +(cpu *processor); + + +/* The processors local concept of time */ + +INLINE_CPU signed64 cpu_get_time_base +(cpu *processor); + +INLINE_CPU void cpu_set_time_base +(cpu *processor, + signed64 time_base); + +INLINE_CPU signed32 cpu_get_decrementer +(cpu *processor); + +INLINE_CPU void cpu_set_decrementer +(cpu *processor, + signed32 decrementer); + + +/* manipulate the program counter + + The program counter is not included in the register file. Instead + it is extracted and then later restored (set, reset, halt). This + is to give the user of the cpu (and the compiler) the chance to + minimize the need to load/store the cpu's PC value. (Especially in + the case of a single processor) */ + +INLINE_CPU void cpu_set_program_counter +(cpu *processor, + unsigned_word new_program_counter); + +INLINE_CPU unsigned_word cpu_get_program_counter +(cpu *processor); + +INLINE_CPU void cpu_restart +(cpu *processor, + unsigned_word nia); + +INLINE_CPU void cpu_halt +(cpu *processor, + unsigned_word nia, + stop_reason reason, + int signal); + + +#if WITH_IDECODE_CACHE +/* gain acces to the processors instruction cracking cache + + Only useful (and visable) if we're cracking the cache */ +INLINE_CPU idecode_cache *cpu_icache +(cpu *processor); +#endif + + +/* reveal the processor address maps + + 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 + functions. (eg cpu_instruction_fetch() cpu_data_read_4()) + + Unfortunatly in addition to these functions is the need (for the + debugger) to be able to read/write to memory in ways that violate + 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 +(cpu *processor); + + +/* grant access to the reservation information */ +typedef struct _memory_reservation { + int valid; + unsigned_word addr; + unsigned_word data; +} memory_reservation; + +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 + to occure after (or before) the update of any context controlling + register. All context sync points must call the sync function + below to when ever a synchronization point is reached */ + +INLINE_CPU registers *cpu_registers +(cpu *processor); + +INLINE_CPU void cpu_synchronize_context +(cpu *processor); + +#define IS_PROBLEM_STATE(PROCESSOR) \ +(CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT \ + || (cpu_registers(PROCESSOR)->msr & msr_problem_state)) + +#define IS_64BIT_MODE(PROCESSOR) \ +((CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT && WITH_64BIT_TARGET) \ + || (cpu_registers(PROCESSOR)->msr & msr_64bit_mode)) + +#define IS_FP_AVAILABLE(PROCESSOR) \ +(CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT \ + || (cpu_registers(PROCESSOR)->msr & msr_floating_point_available)) + +#endif diff --git a/sim/ppc/gen.c b/sim/ppc/gen.c index 9341cd8..cc46952 100644 --- a/sim/ppc/gen.c +++ b/sim/ppc/gen.c @@ -2802,6 +2802,8 @@ gen_idecode_c(insn_table *table, lf *file) idecode_cache == 1 ? insn_formal : cache_idecode_formal); lf_printf(file, "{\n"); lf_indent(file, +2); + if (!idecode_cache) + lf_printf(file, "cpu_increment_number_of_insns (processor);\n"); if (table->opcode_rule->use_switch) lf_print_idecode_switch(file, table); else diff --git a/sim/ppc/main.c b/sim/ppc/main.c index 31c85e0..5ce3a0d 100644 --- a/sim/ppc/main.c +++ b/sim/ppc/main.c @@ -81,10 +81,11 @@ main(int argc, char **argv) psim_status status; int letter; int i; + int print_info = 0; /* check for arguments -- note sim_calls.c also contains argument processing code for the simulator linked within gdb. */ - while ((letter = getopt (argc, argv, "acCipst")) != EOF) + while ((letter = getopt (argc, argv, "acCiIpst")) != EOF) { switch (letter) { case 'a': @@ -106,6 +107,9 @@ main(int argc, char **argv) case 'i': trace[trace_icu_device] = 1; break; + case 'I': + print_info = 1; + break; case 't': trace[trace_device_tree] = 1; break; @@ -133,6 +137,9 @@ main(int argc, char **argv) psim_run(system); + if (print_info) + psim_print_info (system, 1); + /* why did we stop */ status = psim_get_status(system); switch (status.reason) { diff --git a/sim/ppc/psim.c b/sim/ppc/psim.c index 45fb821..405cf12 100644 --- a/sim/ppc/psim.c +++ b/sim/ppc/psim.c @@ -226,6 +226,12 @@ write_stack_arguments(psim *system, 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, @@ -901,4 +907,12 @@ psim_write_memory(psim *system, } +INLINE_PSIM void +psim_print_info(psim *system, int verbose) +{ + int i; + for (i = 0; i < system->nr_cpus; i++) + cpu_print_info (system->processors[i], verbose); +} + #endif /* _PSIM_C_ */ diff --git a/sim/ppc/psim.h b/sim/ppc/psim.h new file mode 100644 index 0000000..bfb8c13 --- /dev/null +++ b/sim/ppc/psim.h @@ -0,0 +1,140 @@ +/* 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 _PSIM_H_ +#define _PSIM_H_ + +#ifndef INLINE_PSIM +#define INLINE_PSIM +#endif + + +#include "basics.h" + +/* the system object */ + +typedef struct _psim psim; + + +/* when the `system' stops, find out why. FIXME - at this point this + is really a bit puzzling. After all, how can there be a status + when there several processors involved */ + +typedef struct _psim_status { + int cpu_nr; + stop_reason reason; + int signal; + unsigned_word program_counter; +} psim_status; + + +/* create a new simulator */ + +extern psim *psim_create +(const char *file_name, + int nr_processors); + + +/* Given the created simulator load either its low or high memory */ + +extern void psim_load +(psim *system); + +extern void psim_stack +(psim *system, + char **argv, + char **envp); + + +/* Run/stop the system */ + +extern void psim_step +(psim *system); + +extern void psim_run +(psim *system); + +extern void psim_run_until_stop +(psim *system, + volatile int *stop); + +extern void psim_restart +(psim *system, + int cpu_nr); + +extern void psim_halt +(psim *system, + int cpu_nr, + unsigned_word cia, + stop_reason reason, + int signal); + +extern psim_status psim_get_status +(psim *system); + + +/* reveal the internals of the simulation, giving access to the cpu's */ + +extern cpu *psim_cpu +(psim *system, + int cpu_nr); + + +/* manipulate the state (registers or memory) of a processor within + the system. In the case of memory, the read/write is performed + using the specified processors address translation tables */ + +extern void psim_read_register +(psim *system, + int which_processor, + void *host_ordered_buf, + const char reg[], + transfer_mode mode); + +extern void psim_write_register +(psim *system, + int which_processor, + const void *host_ordered_buf, + const char reg[], + transfer_mode mode); + +extern unsigned psim_read_memory +(psim *system, + int which_processor, + void *buf, + unsigned_word vaddr, + unsigned len, + transfer_mode mode); + +extern unsigned psim_write_memory +(psim *system, + int which_processor, + const void *buf, + unsigned_word vaddr, + unsigned len, + transfer_mode mode, + int violate_read_only_section); + +extern void psim_print_info +(psim *system, + int verbose); + +#endif /* _PSIM_H_ */ diff --git a/sim/ppc/sim_calls.c b/sim/ppc/sim_calls.c index 542267c..44ab5b7 100644 --- a/sim/ppc/sim_calls.c +++ b/sim/ppc/sim_calls.c @@ -40,6 +40,7 @@ static psim *simulator; static int nr_cpus; static char *register_names[] = REGISTER_NAMES; +static int print_info = 0; void sim_open (char *args) @@ -65,7 +66,7 @@ sim_open (char *args) while (*++p != '\0') { switch (*p) { default: - error ("Usage: target sim [ -a -p -c -C -s -i -t ]\n"); + error ("Usage: target sim [ -a -p -c -C -s -i -I -t ]\n"); break; case 'a': for (i = 0; i < nr_trace; i++) @@ -86,6 +87,9 @@ sim_open (char *args) case 'i': trace[trace_icu_device] = 1; break; + case 'I': + print_info = 1; + break; case 't': trace[trace_device_tree] = 1; break; @@ -107,6 +111,9 @@ void sim_close (int quitting) { TRACE(trace_gdb, ("sim_close(quitting=%d) called\n", quitting)); + if (print_info) + psim_print_info (simulator, 1); + /* nothing to do */ } @@ -187,8 +194,7 @@ void sim_info (int verbose) { TRACE(trace_gdb, ("sim_info(verbose=%d) called\n", verbose)); - TRACE(trace_tbd, ("sim_info(verbose=%d) should do something\n")); - /* FIXME: */ + psim_print_info (simulator, verbose); } |