binutils-gdb/sim/ppc/cpu.c
Mike Frysinger 68ed285428 sim: clean up C11 header includes
Since we require C11 now, we can assume many headers exist, and
clean up all of the conditional includes.  It's not like any of
this code actually accounted for the headers not existing, just
whether we could include them.

The strings.h cleanup is a little nuanced: it isn't in C11, but
every use of it in the codebase will include strings.h only if
string.h doesn't exist.  Since we now assume the C11 string.h
exists, we'll never include strings.h, so we can delete it.
2021-01-11 08:05:54 -05:00

398 lines
7.9 KiB
C

/* This file is part of the program psim.
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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CPU_C_
#define _CPU_C_
#include <setjmp.h>
#include "cpu.h"
#include "idecode.h"
#include <string.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 */
/* the system this processor is contained within */
cpu_mon *monitor;
os_emul *os_emulation;
psim *system;
event_queue *events;
int cpu_nr;
/* Current CPU model information */
model_data *model_ptr;
#if WITH_IDECODE_CACHE_SIZE
/* a cache to store cracked instructions */
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;
/* 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;
};
INLINE_CPU\
(cpu *)
cpu_create(psim *system,
core *memory,
cpu_mon *monitor,
os_emul *os_emulation,
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);
if (CURRENT_MODEL_ISSUE > 0)
processor->model_ptr = model_create (processor);
/* link back to core system */
processor->system = system;
processor->events = psim_event_queue(system);
processor->cpu_nr = cpu_nr;
processor->monitor = monitor;
processor->os_emulation = os_emulation;
return processor;
}
INLINE_CPU\
(void)
cpu_init(cpu *processor)
{
memset(&processor->regs, 0, sizeof(processor->regs));
/* 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 *)
cpu_system(cpu *processor)
{
return processor->system;
}
INLINE_CPU\
(int)
cpu_nr(cpu *processor)
{
return processor->cpu_nr;
}
INLINE_CPU\
(cpu_mon *)
cpu_monitor(cpu *processor)
{
return processor->monitor;
}
INLINE_CPU\
(os_emul *)
cpu_os_emulation(cpu *processor)
{
return processor->os_emulation;
}
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)
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(void *data)
{
cpu *processor = (cpu*)data;
processor->decrementer_event = NULL;
decrementer_interrupt(processor);
}
INLINE_CPU\
(void)
cpu_set_decrementer(cpu *processor,
signed32 decrementer)
{
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)
/* 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,
cpu_decrement_event,
processor);
}
#if WITH_IDECODE_CACHE_SIZE
/* allow access to the cpu's instruction cache */
INLINE_CPU\
(idecode_cache *)
cpu_icache_entry(cpu *processor,
unsigned_word cia)
{
return &processor->icache[cia / 4 % WITH_IDECODE_CACHE_SIZE];
}
INLINE_CPU\
(void)
cpu_flush_icache(cpu *processor)
{
int i;
/* force all addresses to 0xff... so that they never hit */
for (i = 0; i < WITH_IDECODE_CACHE_SIZE; i++)
processor->icache[i].address = MASK(0, 63);
}
#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\
(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 *)
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,
unsigned_word cia)
{
#if (WITH_IDECODE_CACHE_SIZE)
/* kill of the cache */
cpu_flush_icache(processor);
#endif
/* update virtual memory */
vm_synchronize_context(processor->virtual,
processor->regs.spr,
processor->regs.sr,
processor->regs.msr,
processor, cia);
}
/* might again be useful one day */
INLINE_CPU\
(void)
cpu_print_info(cpu *processor, int verbose)
{
}
#endif /* _CPU_C_ */