/* 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
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
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.
+ along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CPU_C_
#define _CPU_C_
-#ifndef STATIC_INLINE_CPU
-#define STATIC_INLINE_CPU STATIC_INLINE
-#endif
-
#include <setjmp.h>
#include "cpu.h"
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;
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;
};
-
-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);
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)
{
- 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,
}
-/* 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)
{
}
-INLINE_CPU void
+INLINE_CPU\
+(void)
cpu_flush_icache(cpu *processor)
{
int i;
/* 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;
/* 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
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)
{
}