Add support to GDB for the Renesas rl78 architecture.
[external/binutils.git] / sim / ppc / cpu.c
index 6defe2f..bce82f1 100644 (file)
@@ -1,6 +1,6 @@
 /*  This file is part of the program psim.
 
-    Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+    Copyright (C) 1994-1997, 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
 #ifndef _CPU_C_
 #define _CPU_C_
 
-#ifndef STATIC_INLINE_CPU
-#define STATIC_INLINE_CPU STATIC_INLINE
-#endif
-
 #include <setjmp.h>
 
 #include "cpu.h"
@@ -53,18 +49,13 @@ struct _cpu {
   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 */
   cpu_mon *monitor;
+  os_emul *os_emulation;
   psim *system;
   event_queue *events;
   int cpu_nr;
 
-  /* Current functional unit information */
-  function_unit *func_unit;
-
   /* Current CPU model information */
   model_data *model_ptr;
 
@@ -73,6 +64,9 @@ struct _cpu {
   idecode_cache icache[WITH_IDECODE_CACHE_SIZE];
 #endif
 
+  /* any interrupt state */
+  interrupts ints;
+
   /* address reservation: keep the physical address and the contents
      of memory at that address */
   memory_reservation reservation;
@@ -84,12 +78,12 @@ struct _cpu {
 
 };
 
-
-INLINE_CPU cpu *
+INLINE_CPU\
+(cpu *)
 cpu_create(psim *system,
           core *memory,
-          event_queue *events,
           cpu_mon *monitor,
+          os_emul *os_emulation,
           int cpu_nr)
 {
   cpu *processor = ZALLOC(cpu);
@@ -99,83 +93,155 @@ cpu_create(psim *system,
   processor->virtual = vm_create(memory);
   processor->instruction_map = vm_create_instruction_map(processor->virtual);
   processor->data_map = vm_create_data_map(processor->virtual);
-  processor->model_ptr = model_create (processor);
+
+  if (CURRENT_MODEL_ISSUE > 0)
+    processor->model_ptr = model_create (processor);
 
   /* link back to core system */
   processor->system = system;
-  processor->events = events;
+  processor->events = psim_event_queue(system);
   processor->cpu_nr = cpu_nr;
   processor->monitor = monitor;
-
-  /* Create function unit if desired */
-  if (WITH_FUNCTION_UNIT)
-    processor->func_unit = function_unit_create ();
+  processor->os_emulation = os_emulation;
 
   return processor;
 }
 
 
-INLINE_CPU void
+INLINE_CPU\
+(void)
 cpu_init(cpu *processor)
 {
   memset(&processor->regs, 0, sizeof(processor->regs));
-  /* FIXME - should any of VM be inited also ? */
-
-  if (WITH_FUNCTION_UNIT)
-    function_unit_init (processor->func_unit);
-
-  model_init (processor, processor->model_ptr);
+  /* vm init is delayed until after the device tree has been init as
+     the devices may further init the cpu */
+  if (CURRENT_MODEL_ISSUE > 0)
+    model_init (processor->model_ptr);
 }
 
 
 /* find ones way home */
 
-INLINE_CPU psim *
+INLINE_CPU\
+(psim *)
 cpu_system(cpu *processor)
 {
   return processor->system;
 }
 
-INLINE_CPU int
+INLINE_CPU\
+(int)
 cpu_nr(cpu *processor)
 {
   return processor->cpu_nr;
 }
 
-INLINE_CPU event_queue *
-cpu_event_queue(cpu *processor)
-{
-  return processor->events;
-}
-
-INLINE_CPU cpu_mon *
+INLINE_CPU\
+(cpu_mon *)
 cpu_monitor(cpu *processor)
 {
   return processor->monitor;
 }
 
-INLINE_CPU function_unit *
-cpu_function_unit(cpu *processor)
+INLINE_CPU\
+(os_emul *)
+cpu_os_emulation(cpu *processor)
 {
-  return processor->func_unit;
+  return processor->os_emulation;
 }
 
-INLINE_CPU model_data *
+INLINE_CPU\
+(model_data *)
 cpu_model(cpu *processor)
 {
   return processor->model_ptr;
 }
 
+
+/* 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)
+{
+  ASSERT(processor != NULL);
+  cpu_set_program_counter(processor, nia);
+  psim_restart(processor->system, processor->cpu_nr);
+}
+
+INLINE_CPU\
+(void)
+cpu_halt(cpu *processor,
+        unsigned_word nia,
+        stop_reason reason,
+        int signal)
+{
+  ASSERT(processor != NULL);
+  if (CURRENT_MODEL_ISSUE > 0)
+    model_halt(processor->model_ptr);
+  cpu_set_program_counter(processor, nia);
+  psim_halt(processor->system, processor->cpu_nr, reason, signal);
+}
+
+EXTERN_CPU\
+(void)
+cpu_error(cpu *processor,
+         unsigned_word cia,
+         const char *fmt,
+         ...)
+{
+  char message[1024];
+  va_list ap;
+
+  /* format the message */
+  va_start(ap, fmt);
+  vsprintf(message, fmt, ap);
+  va_end(ap);
+
+  /* sanity check */
+  if (strlen(message) >= sizeof(message))
+    error("cpu_error: buffer overflow");
+
+  if (processor != NULL) {
+    printf_filtered("cpu %d, cia 0x%lx: %s\n",
+                   processor->cpu_nr + 1, (unsigned long)cia, message);
+    cpu_halt(processor, cia, was_signalled, -1);
+  }
+  else {
+    error("cpu: %s", message);
+  }
+}
+
+
 /* The processors local concept of time */
 
-INLINE_CPU signed64
+INLINE_CPU\
+(signed64)
 cpu_get_time_base(cpu *processor)
 {
   return (event_queue_time(processor->events)
          - processor->time_base_local_time);
 }
 
-INLINE_CPU void
+INLINE_CPU\
+(void)
 cpu_set_time_base(cpu *processor,
                  signed64 time_base)
 {
@@ -183,42 +249,38 @@ cpu_set_time_base(cpu *processor,
                                     - time_base);
 }
 
-INLINE_CPU signed32
+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)
+STATIC_INLINE_CPU\
+(void)
+cpu_decrement_event(void *data)
 {
   cpu *processor = (cpu*)data;
-  if (!decrementer_interrupt(processor)) {
-    processor->decrementer_event = event_queue_schedule(processor->events,
-                                                       1, /* NOW! */
-                                                       cpu_decrement_event,
-                                                       processor);
-  }
+  processor->decrementer_event = NULL;
+  decrementer_interrupt(processor);
 }
 
-INLINE_CPU void
+INLINE_CPU\
+(void)
 cpu_set_decrementer(cpu *processor,
                    signed32 decrementer)
 {
-  signed64 old_decrementer = (processor->decrementer_local_time
-                             - event_queue_time(processor->events));
+  signed64 old_decrementer = cpu_get_decrementer(processor);
   event_queue_deschedule(processor->events, processor->decrementer_event);
+  processor->decrementer_event = NULL;
   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);
+    /* A decrementer interrupt occures if the sign of the decrement
+       register is changed from positive to negative by the load
+       instruction */
+    decrementer_interrupt(processor);
   else if (decrementer >= 0)
     processor->decrementer_event = event_queue_schedule(processor->events,
                                                        decrementer,
@@ -227,55 +289,10 @@ cpu_set_decrementer(cpu *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)
-{
-  if (processor == NULL) {
-    error("cpu_halt() processor=NULL, cia=0x%x, reason=%d, signal=%d\n",
-         cia,
-         reason,
-         signal);
-  }
-  else {
-    if (WITH_FUNCTION_UNIT)
-      function_unit_halt(processor, processor->func_unit);
-
-    model_halt(processor, processor->model_ptr);
-    processor->program_counter = cia;
-    psim_halt(processor->system, processor->cpu_nr, cia, reason, signal);
-  }
-}
-
-
 #if WITH_IDECODE_CACHE_SIZE
 /* allow access to the cpu's instruction cache */
-INLINE_CPU idecode_cache *
+INLINE_CPU\
+(idecode_cache *)
 cpu_icache_entry(cpu *processor,
                 unsigned_word cia)
 {
@@ -283,7 +300,8 @@ cpu_icache_entry(cpu *processor,
 }
 
 
-INLINE_CPU void
+INLINE_CPU\
+(void)
 cpu_flush_icache(cpu *processor)
 {
   int i;
@@ -296,22 +314,51 @@ cpu_flush_icache(cpu *processor)
 
 /* address map revelation */
 
-INLINE_CPU vm_instruction_map *
+INLINE_CPU\
+(vm_instruction_map *)
 cpu_instruction_map(cpu *processor)
 {
   return processor->instruction_map;
 }
 
-INLINE_CPU vm_data_map *
+INLINE_CPU\
+(vm_data_map *)
 cpu_data_map(cpu *processor)
 {
   return processor->data_map;
 }
 
+INLINE_CPU\
+(void)
+cpu_page_tlb_invalidate_entry(cpu *processor,
+                             unsigned_word ea)
+{
+  vm_page_tlb_invalidate_entry(processor->virtual, ea);
+}
+
+INLINE_CPU\
+(void)
+cpu_page_tlb_invalidate_all(cpu *processor)
+{
+  vm_page_tlb_invalidate_all(processor->virtual);
+}
+
+
+/* interrupt access */
+
+INLINE_CPU\
+(interrupts *)
+cpu_interrupts(cpu *processor)
+{
+  return &processor->ints;
+}
+
+
 
 /* reservation access */
 
-INLINE_CPU memory_reservation *
+INLINE_CPU\
+(memory_reservation *)
 cpu_reservation(cpu *processor)
 {
   return &processor->reservation;
@@ -320,16 +367,19 @@ cpu_reservation(cpu *processor)
 
 /* register access */
 
-INLINE_CPU registers *
+INLINE_CPU\
+(registers *)
 cpu_registers(cpu *processor)
 {
   return &processor->regs;
 }
 
-INLINE_CPU void
-cpu_synchronize_context(cpu *processor)
+INLINE_CPU\
+(void)
+cpu_synchronize_context(cpu *processor,
+                       unsigned_word cia)
 {
-#if (WITH_IDECODE_CACHE)
+#if (WITH_IDECODE_CACHE_SIZE)
   /* kill of the cache */
   cpu_flush_icache(processor);
 #endif
@@ -338,13 +388,15 @@ cpu_synchronize_context(cpu *processor)
   vm_synchronize_context(processor->virtual,
                         processor->regs.spr,
                         processor->regs.sr,
-                        processor->regs.msr);
+                        processor->regs.msr,
+                        processor, cia);
 }
 
 
 /* might again be useful one day */
 
-INLINE_CPU void
+INLINE_CPU\
+(void)
 cpu_print_info(cpu *processor, int verbose)
 {
 }