mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
68ed285428
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.
398 lines
7.9 KiB
C
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_ */
|