Add support to count the number of instructions issued.
authorMichael Meissner <gnu@the-meissners.org>
Mon, 2 Oct 1995 18:19:17 +0000 (18:19 +0000)
committerMichael Meissner <gnu@the-meissners.org>
Mon, 2 Oct 1995 18:19:17 +0000 (18:19 +0000)
sim/ppc/ChangeLog
sim/ppc/cpu.c [new file with mode: 0644]
sim/ppc/cpu.h [new file with mode: 0644]
sim/ppc/gen.c
sim/ppc/main.c
sim/ppc/psim.c
sim/ppc/psim.h [new file with mode: 0644]
sim/ppc/sim_calls.c

index ed3b90047860adbb9984d15127ea026713e004d7..f041e61ae76eacd1b629c80e5b7ca08897de9b6f 100644 (file)
@@ -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 (file)
index 0000000..1ced239
--- /dev/null
@@ -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 (file)
index 0000000..f9790e8
--- /dev/null
@@ -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
index 9341cd8148673d01ee370072e8bf3ccc7b04d999..cc46952d05548dfb1bfa01f9e53768f5897746f1 100644 (file)
@@ -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
index 31c85e097ae8f8bde77b130169774b0e1ecdd543..5ce3a0de226c2f03e0be8bb3e496c805e4f52ead 100644 (file)
@@ -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) {
index 45fb821bcafcdc5051f6a749144b675b6dc56317..405cf129cdc046d60f865d730d218f43c30b6908 100644 (file)
@@ -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 (file)
index 0000000..bfb8c13
--- /dev/null
@@ -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_ */
index 542267c8bd5220a43073c691757c0079589ccba3..44ab5b703d6cc1a6742bcbdff147977109de892d 100644 (file)
@@ -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);
 }