October 11th changes from Andrew

This commit is contained in:
Michael Meissner 1995-10-11 20:17:49 +00:00
parent ee9f09cd26
commit dec38daceb
16 changed files with 4069 additions and 2302 deletions

View File

@ -36,6 +36,7 @@ configure
configure.in
core.c
core.h
core_n.h
cpu.c
cpu.h
debug.c
@ -52,14 +53,11 @@ gen.c
idecode_branch.h
idecode_expression.h
idecode_fields.h
idecode_insn.h
inline.c
inline.h
interrupts.c
interrupts.h
main.c
memory_map.c
memory_map.h
ppc-endian.c
ppc-endian.h
ppc-instructions
@ -76,6 +74,7 @@ system.c
system.h
vm.c
vm.h
vm_n.h
words.h
Things-to-lose:

View File

@ -4,63 +4,47 @@
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
This directory contains the program PSIM that models the PowerPC
architecture. It can either be run stand alone (psim) or linked with
GDB.
architecture. It can either be run stand alone (psim or run) or used
as part of GDB.
CONTENTS:
SOURCE:
psim-*.tar:
PSIM is now part of the Cygnus GDB source tree (hopefully it
will in turn become part of the next FSF release of GDB).
psim-sim-*.tar.gz simulator source code
If you're looking for a more `cutting' edge version of this
program then it can be found in:
psim-test-*.tar.gz test directory for simulator
ftp.ci.com.au:pub/clayton/psim-sim-*.tar.gz
psim-gdb-*.diff.gz patches to integrated psim
into gdb
This contains a replacement for the directory sim/ppc. As
these releases prove stable they are merged back into the GDB
source tree.
gnu-*.tar:
If you find bugs or experience problems, please e-mail them to
the alias:
gnu-gdb-*.diff.gz patches to gdb that may have
already been merged into the
GDB source tree.
powerpc-psim@ci.com.au
gnu-*-*.diff.gz Other noise
It's a majordomo mailing list.
BUILDING:
o Install flex, bison, gnu-make, native gcc and probably also byacc.
o At present PSIM can only be built using the compiler GCC
(yes that is bug). This is because, among other things the
code exploits GCC's suport of long ongs.
o I also suggest that you install: flex, bision, gnu-make and
byacc. Doing this just makes builds easier.
o First you will need a fairly current copy of GDB (try the ftp site
ftp.cygnus.com:pub). I've built it with a beta version of gdb-4.15.
o Configure almost as per normal, specifing the special target
eabisim vis:
Unpack gdb vis:
$ gunzip < gdb-4.15.tar.gz | tar xf -
o Apply any patches that haven't yet been merged into the GDB source
tree.
$ cd gdb-4.15
$ gunzip < ../psim-gdb-*.diff.gz | patch -p1
$ gunzip < ../gnu-gdb-*.diff.gz | patch -p1
o Unpack the psim source code (and optionally the test directory)
$ cd gdb-4.15
$ gunzip < ../psim-sim-*.tar.gz | tar xvf -
$ gunzip < ../psim-test-*.tar.gz | tar xvf -
o Configure gdb as per normal. I use something along the lines of:
$ cd gdb-4.15
$ CC=gcc ./configure --target=powerpcle-unknown-eabi
$ CC=gcc ./configure --target=powerpcle-unknown-eabisim
by default (because of its dependency on GCC).
o Build your entire gdb tree as per normal. Something along the
lines of:
@ -78,15 +62,17 @@ BUILDING:
$ cd gdb-4.15
$ make CC=gcc install
The program sim/ppc/psim is not installed.
RUNNING:
PSIM can either be run as a stand alone program or as part
of gdb. The psim-test archive contains pre-compiled and
linked programs that can be run on PSIM. The notes below
assume that you have unpacked that tar archive.
of gdb. The psim-test archive (found in:
ftp.ci.com.au:pub/clayton
contains pre-compiled and linked programs that can be run on
PSIM. The notes below assume that you have unpacked that tar
archive.
To rebuild the archive you will need to obtain a working
version of an ELF compiler/linker for the PowerPC.
@ -135,68 +121,105 @@ RUNNING:
.
CONFIGURATION: Making it go faster
CONFIGURATION:
See the file sim/ppc/config.h (a.k.a. sim/ppc/data/ppc-config)
for notes.
Making it go faster
See the file sim/ppc/config.h (which is copied from
sim/ppc/std-config.h) for further information.
KNOWN FEATURES
SMP, dual-endian, VEA and OEA models, hardware devices
(console, icu, reset) ...
SMP: A Symetric Multi-Processor configuration is suported.
This includes a model of the PowerPC load word and reserve
et.al. instructions (if intending to use this feature you are
well advised to read the the source code for the reservation
instructions so that you are aware of any potential
limitations in the model).
DUAL-ENDIAN: Both little and big endian modes are suported.
Switching between the two modes at run time, however, is not.
UIEA, VEA and OEA: The PowerPC architecture defines three
levels of the PowerPC architecture. This simulator, to a
reasonable degree, is capable of modeling all three of them.
That is the User Instruction Set Architecture, the Virtual
Environment Architecture and finally the Operating Environment
Architecture.
HARDWARE DEVICES: The OEA model includes facilities that allow
a programmer to (I won't say easily) extend this simulator so
that a program can interact with models of real devices.
Illustrating this is the phony machine clayton that includes
console, interrupt control unit and reset register devices.
PEDANTIC VEA MEMORY MODEL: User programs can not assume that
they can stray off the end of valid memory areas. This model
defines valid memory addresses in strict accordance to the
executable and does not page allign their values. At first
this was a bug but since then has turned up several bugs in
peoples code so I've renamed it `a feature' :-)
RUNTIME CONFIG OF HARDWARE: In addition to the three builtin
models of hardware - VEA, OEA/Hardware and (the start of) OpenBoot,
it is possible to load a file containing a specification of a
custom device tree.
KNOWN PROBLEMS:
Configuration could be better.
FLOATING POINT: Need to add suport for non IEEE float
machines. Need to more fully handle exceptions (eg things
like divide by zero).
DEVICE TREE DOC: How to create and use the device tree is not
documented at all.
INITIALIZATION: When running from gdb, things are not
re-initialzied very well e.g. registers are not rezeroed.
HTAB (page) code for OEA model untested. Some of the vm code
instructions unimplemented.
Doesn't detect/handle changing endian bits. In fact they are
ignored.
Return from interrupt instruction unimplemented.
Flush instruction cache instructions do nothing. Perhaphs they
should (if there is an instruction cache) flush it.
PowerOpen VEA model (a.k.a XCOFF a.k.a AIX) broken. It was
working but that is before I changed the create stack frame
code into an ELF version.
Lacks PowerOpen (a.k.a. XCOFF a.k.a. AIX) and NT startups.
The PowerOpen worked until I added the ELF one.
OpenBoot and PR*P interfaces missing. Open boot could be
implemented by putting special instructions at the address
of the OpenBoot callback functions. Those instructions
could than emulate OpenBoot behavour.
VEA memory read/write performance could be improved by merging
the data sections.
When reading in a VEA executable, the binaries text and data
sections are not made page aligned.
Missing VEA system calls.
Missing or commented out instructions.
Lack of floating point support.
[workaround: build everything using -msoft-float]
Only basic (hackish) floating point implemented, I would not
trust it and it is going to change.
64bit untested.
64bit target untested.
Event code for pending events from signal handlers not
64bit host broken. For instance use of scanf "%x", &long long.
Event code for pending events from within signal handlers not
finished/tested.
Better and more devices.
Only two device trees VEA and OEA (clayton) and those hard coded.
Should be possible to specify a file containing a device tree
description as the program to run. At present it a device tree
file is detected causing psim to abort.
I wonder if I've got my ppc.instructions copyright
notice correct.
PORTABILITY (Notes taken from Michael Meissner): Heavy use of
the ## operator - fix using the clasic X/**/Y hack; Use of the
signed keyword. In particular, signed char has no analogue in
classic C (though most implementations of classic C use signed
chars); Use of long long which restricts the target compiler
to be GCC.
OPTIONS/FLAGS: Need a function that can parse command line
options so that both psim and sim_{load,open,command} can all
call it. Options should be extended to allow the setting of
things like floating point support.
THANKS:
@ -251,3 +274,7 @@ i486DX2/66
1/270/316 - switch=2/2,expand=0,inline=1,nia=0
1/271/281 - switch=1/1,expand=0,inline=1,nia=1
1/267/274 - switch=2/1,expand=0,inline=1,nia=1
----
CFLAGS = -g -Wall -Wno-unused -Wmissing-prototypes -Werror

View File

@ -26,354 +26,468 @@
#define STATIC_INLINE_CORE STATIC_INLINE
#endif
#include "basics.h"
#include "device_tree.h"
#include "memory_map.h"
#include "core.h"
typedef struct _core_mapping core_mapping;
struct _core_mapping {
/* ram map */
int free_buffer;
void *buffer;
/* device map */
const device *device;
device_io_read_buffer_callback *reader;
device_io_write_buffer_callback *writer;
/* common */
int address_space;
unsigned_word base;
unsigned_word bound;
unsigned nr_bytes;
core_mapping *next;
};
struct _core_map {
core_mapping *first;
core_mapping *default_map;
};
typedef enum {
core_read_map,
core_write_map,
core_execute_map,
nr_core_map_types,
} core_map_types;
struct _core {
/* attached devices */
device_node *device_tree;
/* different memory maps */
memory_map *readable; /* really everything */
memory_map *writeable;
memory_map *executable;
/* VEA model requires additional memory information */
unsigned_word data_upper_bound;
unsigned_word data_high_water;
unsigned_word stack_upper_bound;
unsigned_word stack_lower_bound;
unsigned_word stack_low_water;
/* misc */
int trace;
core_map map[nr_core_map_types];
};
STATIC_INLINE_CORE void
create_core_from_addresses(device_node *device,
void *data)
{
core *memory = (core*)data;
device_address *address;
for (address = device->addresses;
address != NULL;
address = address->next_address) {
switch (device->type) {
case memory_device:
{
void *ram = zalloc(address->size);
TRACE(trace_core,
("create_core_from_addresses() adding memory at 0x%.8x-0x%.8x, size %8d\n",
address->lower_bound, address->lower_bound + address->size - 1, address->size));
core_add_raw_memory(memory,
ram,
address->lower_bound,
address->size,
address->access);
}
break;
case sequential_device:
case block_device:
case bus_device:
case other_device:
{
TRACE(trace_core,
("create_core_from_addresses() adding device at 0x%.8x-0x%.8x, size %8d\n",
address->lower_bound, address->lower_bound + address->size - 1, address->size));
ASSERT(device->callbacks != NULL);
core_add_callback_memory(memory,
device,
device->callbacks->read_callback,
device->callbacks->write_callback,
address->lower_bound,
address->size,
address->access);
}
break;
default:
TRACE(trace_core,
("create_core_from_addresses() unknown type %d\n", (int)device->type));
break;
/* nothing happens here */
}
}
}
INLINE_CORE core *
core_create(device_node *root,
int trace)
core_create(void)
{
core *memory;
/* Initialize things */
memory = ZALLOC(core);
memory->trace = trace;
memory->device_tree = root;
/* allocate space for the separate virtual to physical maps */
memory->executable = new_memory_map();
memory->readable = new_memory_map();
memory->writeable = new_memory_map();
/* initial values for the water marks */
memory->data_high_water = 0;
memory->stack_low_water = memory->data_high_water - sizeof(unsigned_word);
/* go over the device tree looking for address ranges to add to
memory */
device_tree_traverse(root,
create_core_from_addresses,
NULL,
memory);
/* return the created core object */
return memory;
core *new_core = ZALLOC(core);
return new_core;
}
STATIC_INLINE_CORE void
zero_core_from_addresses(device_node *device,
void *data)
{
core *memory = (core*)data;
device_address *address;
/* for memory nodes, copy or zero any data */
if (device->type == memory_device) {
for (address = device->addresses;
address != NULL;
address = address->next_address) {
if (memory_map_zero(memory->readable,
address->lower_bound,
address->size) != address->size)
error("init_core_from_addresses() - zero failed\n");
/* adjust high water mark (sbrk) */
if (memory->data_upper_bound < address->upper_bound)
memory->data_upper_bound = address->upper_bound;
}
}
}
STATIC_INLINE_CORE void
load_core_from_addresses(device_node *device,
void *data)
{
core *memory = (core*)data;
device_address *address;
/* initialize the address range with the value attached to the
address. Even works for devices! */
for (address = device->addresses;
address != NULL;
address = address->next_address) {
/* (re)init the address range. I don't want to think about what
this is doing to callback devices! */
if (address->init) {
if (memory_map_write_buffer(memory->readable,
address->init,
address->lower_bound,
address->size,
raw_transfer) != address->size)
error("init_core_from_addresses() - write failed\n");
}
}
}
INLINE_CORE void
core_init(core *memory)
{
unsigned nr_cleared;
unsigned_word clear_base;
unsigned_word clear_bound;
/* for vea, several memory break points */
memory->data_upper_bound = 0;
memory->stack_upper_bound = device_tree_find_int(memory->device_tree,
"/options/stack-pointer");;
memory->stack_lower_bound = memory->stack_upper_bound;
/* (re) clear all of memory that is specified by memory-address
entries. While we're at it determine the upper bound for memory
areas */
device_tree_traverse(memory->device_tree,
NULL,
zero_core_from_addresses,
memory);
/* May have grown the data sectioin (vea model), zero that too if
present */
clear_base = memory->data_upper_bound;
clear_bound = memory->data_high_water;
if (clear_bound > clear_base) {
while ((nr_cleared = memory_map_zero(memory->readable,
clear_base,
clear_bound - clear_base)) > 0) {
clear_base += nr_cleared;
core_map_types access_type;
for (access_type = 0;
access_type < nr_core_map_types;
access_type++) {
core_map *map = memory->map + access_type;
/* blow away old mappings */
core_mapping *curr = map->first;
while (curr != NULL) {
core_mapping *tbd = curr;
curr = curr->next;
if (tbd->free_buffer) {
ASSERT(tbd->buffer != NULL);
zfree(tbd->buffer);
}
zfree(tbd);
}
}
/* clear any part of the stack that was dynamically allocated */
clear_base = memory->stack_low_water;
clear_bound = memory->stack_upper_bound;
if (clear_bound > clear_base) {
while ((nr_cleared = memory_map_zero(memory->readable,
clear_base,
clear_bound - clear_base)) > 0) {
clear_base += nr_cleared;
map->first = NULL;
/* blow away the default */
if (map->default_map != NULL) {
ASSERT(map->default_map->buffer == NULL);
zfree(map->default_map);
}
map->default_map = NULL;
}
/* with everything zero'ed, now (re) load any data sections */
device_tree_traverse(memory->device_tree,
NULL,
load_core_from_addresses,
memory);
}
INLINE_CORE void
core_add_raw_memory(core *memory,
void *buffer,
unsigned_word base,
unsigned size,
device_access access)
/* the core has three sub mappings that the more efficient
read/write fixed quantity functions use */
INLINE_CORE core_map *
core_readable(core *memory)
{
if (access & device_is_readable)
memory_map_add_raw_memory(memory->readable,
buffer, base, size);
if (access & device_is_writeable)
memory_map_add_raw_memory(memory->writeable,
buffer, base, size);
if (access & device_is_executable)
memory_map_add_raw_memory(memory->executable,
buffer, base, size);
return memory->map + core_read_map;
}
INLINE_CORE core_map *
core_writeable(core *memory)
{
return memory->map + core_write_map;
}
INLINE_CORE core_map *
core_executable(core *memory)
{
return memory->map + core_execute_map;
}
INLINE_CORE void
core_add_callback_memory(core *memory,
device_node *device,
device_reader_callback *reader,
device_writer_callback *writer,
unsigned_word base,
unsigned size,
device_access access)
STATIC_INLINE_CORE core_mapping *
new_core_mapping(attach_type attach,
int address_space,
unsigned_word addr,
unsigned nr_bytes,
const device *device,
void *buffer,
int free_buffer)
{
if (access & device_is_readable)
memory_map_add_callback_memory(memory->readable,
device, reader, writer,
base, size);
if (access & device_is_writeable)
memory_map_add_callback_memory(memory->writeable,
device, reader, writer,
base, size);
if (access & device_is_executable)
memory_map_add_callback_memory(memory->executable,
device, reader, writer,
base, size);
core_mapping *new_mapping = ZALLOC(core_mapping);
switch (attach) {
case attach_default:
case attach_callback:
new_mapping->device = device;
new_mapping->reader = device->callback->io_read_buffer;
new_mapping->writer = device->callback->io_write_buffer;
break;
case attach_raw_memory:
new_mapping->buffer = buffer;
new_mapping->free_buffer = free_buffer;
break;
default:
error("new_core_mapping() - internal error - unknown attach type %d\n",
attach);
}
/* common */
new_mapping->address_space = address_space;
new_mapping->base = addr;
new_mapping->nr_bytes = nr_bytes;
new_mapping->bound = addr + (nr_bytes - 1);
return new_mapping;
}
STATIC_INLINE_CORE void
malloc_core_memory(core *memory,
unsigned_word base,
unsigned size,
device_access access)
core_map_attach(core_map *access_map,
attach_type attach,
int address_space,
unsigned_word addr,
unsigned nr_bytes, /* host limited */
const device *device, /*callback/default*/
void *buffer, /*raw_memory*/
int free_buffer) /*raw_memory*/
{
void *buffer = (void*)zalloc(size);
core_add_raw_memory(memory, buffer, base, size, access);
}
INLINE_CORE unsigned_word
core_data_upper_bound(core *memory)
{
return memory->data_upper_bound;
}
INLINE_CORE unsigned_word
core_stack_lower_bound(core *memory)
{
return memory->stack_lower_bound;
}
INLINE_CORE unsigned_word
core_stack_size(core *memory)
{
return (memory->stack_upper_bound - memory->stack_lower_bound);
}
INLINE_CORE void
core_add_data(core *memory, unsigned_word incr)
{
unsigned_word new_upper_bound = memory->data_upper_bound + incr;
if (new_upper_bound > memory->data_high_water) {
if (memory->data_upper_bound >= memory->data_high_water)
/* all the memory is new */
malloc_core_memory(memory,
memory->data_upper_bound,
incr,
device_is_readable | device_is_writeable);
else
/* some of the memory was already allocated, only need to add
missing bit */
malloc_core_memory(memory,
memory->data_high_water,
new_upper_bound - memory->data_high_water,
device_is_readable | device_is_writeable);
memory->data_high_water = new_upper_bound;
if (attach == attach_default) {
if (access_map->default_map != NULL)
error("core_map_attach() default mapping already in place\n");
ASSERT(buffer == NULL);
access_map->default_map = new_core_mapping(attach,
address_space, addr, nr_bytes,
device, buffer, free_buffer);
}
memory->data_upper_bound = new_upper_bound;
}
else {
/* find the insertion point for this additional mapping and insert */
core_mapping *next_mapping;
core_mapping **last_mapping;
/* actually do occasionally get a zero size map */
if (nr_bytes == 0)
error("core_map_attach() size == 0\n");
INLINE_CORE void
core_add_stack(core *memory, unsigned_word incr)
{
unsigned_word new_lower_bound = memory->stack_lower_bound - incr;
if (new_lower_bound < memory->stack_low_water) {
if (memory->stack_lower_bound <= memory->stack_low_water)
/* all the memory is new */
malloc_core_memory(memory,
new_lower_bound,
incr,
device_is_readable | device_is_writeable);
else
/* allocate only the extra bit */
malloc_core_memory(memory,
new_lower_bound,
memory->stack_low_water - new_lower_bound,
device_is_readable | device_is_writeable);
memory->stack_low_water = new_lower_bound;
/* find the insertion point (between last/next) */
next_mapping = access_map->first;
last_mapping = &access_map->first;
while(next_mapping != NULL && next_mapping->bound < addr) {
/* assert: next_mapping->base > all bases before next_mapping */
/* assert: next_mapping->bound >= all bounds before next_mapping */
last_mapping = &next_mapping->next;
next_mapping = next_mapping->next;
}
/* check insertion point correct */
if (next_mapping != NULL && next_mapping->base < (addr + (nr_bytes - 1))) {
error("core_map_attach() map overlap\n");
}
/* create/insert the new mapping */
*last_mapping = new_core_mapping(attach,
address_space, addr, nr_bytes,
device, buffer, free_buffer);
(*last_mapping)->next = next_mapping;
}
memory->stack_lower_bound = new_lower_bound;
}
INLINE_CORE memory_map *
core_readable(core *core)
INLINE_CORE void
core_attach(core *memory,
attach_type attach,
int address_space,
access_type access,
unsigned_word addr,
unsigned nr_bytes, /* host limited */
const device *device) /*callback/default*/
{
return core->readable;
core_map_types access_map;
int free_buffer = 0;
void *buffer = NULL;
ASSERT(attach == attach_default || nr_bytes > 0);
if (attach == attach_raw_memory)
buffer = zalloc(nr_bytes);
for (access_map = 0;
access_map < nr_core_map_types;
access_map++) {
switch (access_map) {
case core_read_map:
if (access & access_read)
core_map_attach(memory->map + access_map,
attach,
address_space, addr, nr_bytes,
device, buffer, !free_buffer);
free_buffer ++;
break;
case core_write_map:
if (access & access_write)
core_map_attach(memory->map + access_map,
attach,
address_space, addr, nr_bytes,
device, buffer, !free_buffer);
free_buffer ++;
break;
case core_execute_map:
if (access & access_exec)
core_map_attach(memory->map + access_map,
attach,
address_space, addr, nr_bytes,
device, buffer, !free_buffer);
free_buffer ++;
break;
default:
error("core_attach() internal error\n");
break;
}
}
ASSERT(free_buffer > 0); /* must attach to at least one thing */
}
INLINE_CORE memory_map *
core_writeable(core *core)
STATIC_INLINE_CORE core_mapping *
core_map_find_mapping(core_map *map,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia,
int abort) /*either 0 or 1 - helps inline */
{
return core->writeable;
core_mapping *mapping = map->first;
ASSERT((addr & (nr_bytes - 1)) == 0); /* must be aligned */
ASSERT((addr + (nr_bytes - 1)) >= addr); /* must not wrap */
while (mapping != NULL) {
if (addr >= mapping->base
&& (addr + (nr_bytes - 1)) <= mapping->bound)
return mapping;
mapping = mapping->next;
}
if (map->default_map != NULL)
return map->default_map;
if (abort)
error("core_find_mapping() - access to unmaped address, attach a default map to handle this - addr=0x%x nr_bytes=0x%x processor=0x%x cia=0x%x\n",
addr, nr_bytes, processor, cia);
return NULL;
}
INLINE_CORE memory_map *
core_executable(core *core)
STATIC_INLINE_CORE void *
core_translate(core_mapping *mapping,
unsigned_word addr)
{
return core->executable;
return mapping->buffer + addr - mapping->base;
}
#endif /* _CORE_ */
INLINE_CORE unsigned
core_map_read_buffer(core_map *map,
void *buffer,
unsigned_word addr,
unsigned len)
{
unsigned count;
unsigned_1 byte;
for (count = 0; count < len; count++) {
unsigned_word raddr = addr + count;
core_mapping *mapping =
core_map_find_mapping(map,
raddr, 1,
NULL, /*processor*/
0, /*cia*/
0); /*dont-abort*/
if (mapping == NULL)
break;
if (mapping->reader != NULL) {
if (mapping->reader(mapping->device,
&byte,
mapping->address_space,
raddr - mapping->base,
1, /* nr_bytes */
0, /*processor*/
0 /*cpu*/) != 1)
break;
}
else
byte = *(unsigned_1*)core_translate(mapping,
raddr);
((unsigned_1*)buffer)[count] = T2H_1(byte);
}
return count;
}
INLINE_CORE unsigned
core_map_write_buffer(core_map *map,
const void *buffer,
unsigned_word addr,
unsigned len)
{
unsigned count;
unsigned_1 byte;
for (count = 0; count < len; count++) {
unsigned_word raddr = addr + count;
core_mapping *mapping = core_map_find_mapping(map,
raddr, 1,
NULL, /*processor*/
0, /*cia*/
0); /*dont-abort*/
if (mapping == NULL)
break;
byte = H2T_1(((unsigned_1*)buffer)[count]);
if (mapping->writer != NULL) {
if (mapping->writer(mapping->device,
&byte,
mapping->address_space,
raddr - mapping->base,
1, /*nr_bytes*/
0, /*processor*/
0 /*cpu*/) != 1)
break;
}
else
*(unsigned_1*)core_translate(mapping, raddr) = byte;
}
return count;
}
/* Top level core(root) device: core@garbage
The core device captures incomming dma requests and changes them to
outgoing io requests. */
STATIC_INLINE_CORE void
core_init_callback(const device *me,
psim *system)
{
core *memory = (core*)me->data;
core_init(memory);
}
STATIC_INLINE_CORE void
core_attach_address_callback(const device *me,
const char *name,
attach_type attach,
int address_space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
const device *who) /*callback/default*/
{
core *memory = (core*)me->data;
unsigned_word device_address;
if (address_space != 0)
error("core_attach_address_callback() invalid address space\n");
core_attach(memory,
attach,
address_space,
access,
addr,
nr_bytes,
who);
}
STATIC_INLINE_CORE unsigned
core_dma_read_buffer_callback(const device *me,
void *target,
int address_space,
unsigned_word offset,
unsigned nr_bytes)
{
core *memory = (core*)me->data;
return core_map_read_buffer(core_readable(memory),
target,
offset,
nr_bytes);
}
STATIC_INLINE_CORE unsigned
core_dma_write_buffer_callback(const device *me,
const void *source,
int address_space,
unsigned_word offset,
unsigned nr_bytes,
int violate_read_only_section)
{
core *memory = (core*)me->data;
core_map *map = (violate_read_only_section
? core_readable(memory)
: core_writeable(memory));
return core_map_write_buffer(map,
source,
offset,
nr_bytes);
}
static device_callbacks const core_callbacks = {
core_init_callback,
core_attach_address_callback,
unimp_device_detach_address,
unimp_device_io_read_buffer,
unimp_device_io_write_buffer,
core_dma_read_buffer_callback,
core_dma_write_buffer_callback,
unimp_device_attach_interrupt,
unimp_device_detach_interrupt,
unimp_device_interrupt,
unimp_device_interrupt_ack,
unimp_device_ioctl,
};
INLINE_CORE const device *
core_device_create(core *memory)
{
return device_create_from("core", memory, &core_callbacks, NULL);
}
/* define the read/write 1/2/4/8/word functions */
#undef N
#define N 1
#include "core_n.h"
#undef N
#define N 2
#include "core_n.h"
#undef N
#define N 4
#include "core_n.h"
#undef N
#define N 8
#include "core_n.h"
#undef N
#define N word
#include "core_n.h"
#endif /* _CORE_C_ */

View File

@ -26,78 +26,130 @@
#define INLINE_CORE
#endif
/* the base type */
/* basic types */
typedef struct _core core;
typedef struct _core_map core_map;
/* constructor */
/* create the hardware's core (memory and devices) from the device
tree */
INLINE_CORE core *core_create
(device_node *root,
int trace);
(void);
INLINE_CORE const device *core_device_create
(core *);
/* given a created core object, (re)initialize it from the
information provided in it's associated device tree */
INLINE_CORE void core_init
/* the core has three sub mappings that the more efficient
read/write fixed quantity functions use */
INLINE_CORE core_map *core_readable
(core *memory);
INLINE_CORE core_map *core_writeable
(core *memory);
INLINE_CORE core_map *core_executable
(core *memory);
/* from this core extract out the three different types of memory -
executable, readable, writeable */
INLINE_CORE memory_map *core_readable
(core *memory);
/* operators to add/remove a mapping in the core
INLINE_CORE memory_map *core_writeable
(core *memory);
callback-memory:
INLINE_CORE memory_map *core_executable
(core *memory);
All access are passed onto the specified devices callback routines
after being `translated'. DEFAULT indicates that the specified
memory should be called if all other mappings fail.
For callback-memory, the device must be specified.
raw-memory:
While RAM could be implemented using the callback interface
core instead treats it as the common case including the code
directly in the read/write operators.
For raw-memory, the device is ignored and the core alloc's a
block to act as the memory.
default-memory:
Should, for the core, there be no defined mapping for a given
address then the default map (if present) is called.
For default-memory, the device must be specified. */
INLINE_CORE void core_attach
(core *map,
attach_type attach,
int address_space,
access_type access,
unsigned_word addr,
unsigned nr_bytes, /* host limited */
const device *device); /*callback/default*/
INLINE_CORE void core_detach
(core *map,
attach_type attach,
int address_space,
unsigned_word addr,
unsigned nr_bytes, /* host limited */
access_type access,
const device *device); /*callback/default*/
/* operators to grow memory on the fly */
/* Variable sized read/write:
INLINE_CORE void core_add_raw_memory
(core *memory,
Transfer (zero) a variable size block of data between the host and
target (possibly byte swapping it). Should any problems occure,
the number of bytes actually transfered is returned. */
INLINE_CORE unsigned core_map_read_buffer
(core_map *map,
void *buffer,
unsigned_word base,
unsigned size,
device_access access);
unsigned_word addr,
unsigned nr_bytes);
INLINE_CORE void core_add_callback_memory
(core *memory,
device_node *device,
device_reader_callback *reader,
device_writer_callback *writer,
unsigned_word base,
unsigned size,
device_access access);
INLINE_CORE unsigned core_map_write_buffer
(core_map *map,
const void *buffer,
unsigned_word addr,
unsigned nr_bytes);
/* In the VEA model, memory grow's after it is created. Operators
below grow memory as required.
/* Fixed sized read/write:
FIXME - should this be inside of vm? */
Transfer a fixed amout of memory between the host and target. The
memory always being translated and the operation always aborting
should a problem occure */
INLINE_CORE unsigned_word core_data_upper_bound
(core *memory);
#define DECLARE_CORE_WRITE_N(N) \
INLINE_CORE void core_map_write_##N \
(core_map *map, \
unsigned_word addr, \
unsigned_##N val, \
cpu *processor, \
unsigned_word cia);
INLINE_CORE unsigned_word core_stack_lower_bound
(core *memory);
DECLARE_CORE_WRITE_N(1)
DECLARE_CORE_WRITE_N(2)
DECLARE_CORE_WRITE_N(4)
DECLARE_CORE_WRITE_N(8)
DECLARE_CORE_WRITE_N(word)
INLINE_CORE unsigned_word core_stack_size
(core *memory);
#define DECLARE_CORE_READ_N(N) \
INLINE_CORE unsigned_##N core_map_read_##N \
(core_map *map, \
unsigned_word addr, \
cpu *processor, \
unsigned_word cia);
INLINE_CORE void core_add_data
(core *memory,
unsigned_word incr);
DECLARE_CORE_READ_N(1)
DECLARE_CORE_READ_N(2)
DECLARE_CORE_READ_N(4)
DECLARE_CORE_READ_N(8)
DECLARE_CORE_READ_N(word)
INLINE_CORE void core_add_stack
(core *memory,
unsigned_word incr);
#endif /* _CORE_ */
#endif

91
sim/ppc/core_n.h Normal file
View File

@ -0,0 +1,91 @@
/* 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 N
#error "N must be #defined"
#endif
#undef unsigned_N
#define unsigned_N XCONCAT2(unsigned_,N)
#undef T2H_N
#define T2H_N XCONCAT2(T2H_,N)
#undef H2T_N
#define H2T_N XCONCAT2(H2T_,N)
INLINE_CORE unsigned_N
XCONCAT2(core_map_read_,N)(core_map *map,
unsigned_word addr,
cpu *processor,
unsigned_word cia)
{
core_mapping *mapping = core_map_find_mapping(map,
addr,
sizeof(unsigned_N),
processor,
cia,
1); /*abort*/
if (WITH_CALLBACK_MEMORY && mapping->reader != NULL) {
unsigned_N data;
if (mapping->reader(mapping->device,
&data,
mapping->address_space,
addr - mapping->base,
sizeof(unsigned_N), /* nr_bytes */
processor,
cia) != sizeof(unsigned_N))
error("core_read_,N() reader should not fail\n");
return T2H_N(data);
}
else
return T2H_N(*(unsigned_N*)core_translate(mapping, addr));
}
INLINE_CORE void
XCONCAT2(core_map_write_,N)(core_map *map,
unsigned_word addr,
unsigned_N val,
cpu *processor,
unsigned_word cia)
{
core_mapping *mapping = core_map_find_mapping(map,
addr,
sizeof(unsigned_N),
processor,
cia,
1); /*abort*/
if (WITH_CALLBACK_MEMORY && mapping->writer != NULL) {
unsigned_N data = H2T_N(val);
if (mapping->writer(mapping->device,
&data,
mapping->address_space,
addr - mapping->base,
sizeof(unsigned_N), /* nr_bytes */
processor,
cia) != sizeof(unsigned_N))
error("core_read_,N() writer should not fail\n");
}
else
*(unsigned_N*)core_translate(mapping, addr) = H2T_N(val);
}

File diff suppressed because it is too large Load Diff

View File

@ -27,208 +27,147 @@
#endif
/* forward declaration of types */
#include "devices.h"
typedef struct _device_node device_node;
typedef struct _device_address device_address;
typedef struct _device_callbacks device_callbacks;
typedef struct _device_tree device_tree;
/* Device callbacks: */
/* extend the device tree, each function returns the address of the
new node */
INLINE_DEVICE_TREE device_tree *device_tree_add_passthrough
(device_tree *root,
const char *path);
INLINE_DEVICE_TREE device_tree *device_tree_add_device
(device_tree *root,
const char *path,
const device *dev);
INLINE_DEVICE_TREE device_tree *device_tree_add_integer
(device_tree *root,
const char *path,
signed_word integer);
INLINE_DEVICE_TREE device_tree *device_tree_add_string
(device_tree *root,
const char *path,
const char *string);
INLINE_DEVICE_TREE device_tree *device_tree_add_boolean
(device_tree *root,
const char *path,
int bool);
INLINE_DEVICE_TREE device_tree *device_tree_add_found_device
(device_tree *root,
const char *path);
/* query the device tree */
INLINE_DEVICE_TREE const device *device_tree_find_device
(device_tree *root,
const char *path);
INLINE_DEVICE_TREE signed_word device_tree_find_integer
(device_tree *root,
const char *path);
INLINE_DEVICE_TREE const char *device_tree_find_string
(device_tree *root,
const char *path);
INLINE_DEVICE_TREE int device_tree_find_boolean
(device_tree *root,
const char *path);
/* Memory operations: transfer data to/from a processor.
/* initialize the entire tree */
These callbacks pass/return data in *host* byte order.
Should a memory read/write operation cause an interrupt (external
exception) then a device would typically pass an interrupt message
to the devices parent. Hopefully that is an interrupt controler
and will know what to do with it.
Devices normally never either restart a processor or issue an
interrupt directly. The only exception I've thought of could be
machine check type event. */
typedef unsigned64 (device_reader_callback)
(device_node *device,
unsigned_word base,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
typedef void (device_writer_callback)
(device_node *device,
unsigned_word base,
unsigned nr_bytes,
unsigned64 val,
cpu *processor,
unsigned_word cia);
/* Interrupts:
A child device uses the below to pass on to its parent changes in
the state of a child devices interrupt lines.
Typically, the parent being an interrupt control device, would, in
responce, schedule an event at the start of the next clock cycle.
On this event, the state of any cpu could be changed. Other
devices could either ignore or pass on the interrupt message */
typedef void (device_interrupt_callback)
(device_node *me,
int interrupt_status,
device_node *device,
cpu *processor,
unsigned_word cia);
/* Create:
DEVICE_CREATOR is called once, as part of building the device tree.
This function gives the device the chance to attach any additional
data to this particular device instance.
DEVICE_INIT_CALLBACK is (re)called when ever the system is
(re)initialised. */
typedef device_node *(device_creator)
(device_node *parent,
char *name);
typedef void (device_init_callback)
(device_node *device);
/* constructs to describe the hardware's tree of devices */
typedef enum _device_type {
/* default */
unknown_device,
/* typical devices */
memory_device,
sequential_device,
block_device,
bus_device,
other_device,
/* atypical devices, these are for data being loaded into ram/rom */
data_device,
options_device,
/* types of primative nodes containing just data */
boolean_type_device,
integer_type_device,
string_type_device,
byte_type_device,
} device_type;
typedef enum _device_access {
device_is_readable = 1,
device_is_writeable = 2,
device_is_read_write = 3,
device_is_executable = 4,
device_is_read_exec = 5,
device_is_write_exec = 6,
device_is_read_write_exec = 7,
} device_access;
struct _device_address {
unsigned_word lower_bound;
unsigned_word upper_bound;
unsigned size; /* host limited */
void *init; /* initial data */
device_access access;
device_address *next_address;
};
struct _device_callbacks {
device_reader_callback *read_callback;
device_writer_callback *write_callback;
device_interrupt_callback *interrupt_callback;
/* device_init_callback *init_callback; */
/* device_init_hander *post_init_handler; */
};
struct _device_node {
/* where i am */
device_node *parent;
device_node *children;
device_node *sibling;
/* what I am */
char *name; /* eg rom@0x1234,0x40 */
device_type type;
device_callbacks *callbacks;
device_address *addresses;
void *data;
};
/* given the image to run, return its device tree */
INLINE_DEVICE_TREE device_node *device_tree_create
(const char *hardware_description);
INLINE_DEVICE_TREE void device_tree_init
(device_tree *root,
psim *system);
/* traverse the tree eiter pre or post fix */
typedef void (device_tree_traverse_function)
(device_node *device,
(device_tree *device,
void *data);
INLINE_DEVICE_TREE void device_tree_traverse
(device_node *root,
(device_tree *root,
device_tree_traverse_function *prefix,
device_tree_traverse_function *postfix,
void *data);
/* query the device tree */
INLINE_DEVICE_TREE device_node *device_tree_find_node
(device_node *root,
const char *path);
INLINE_DEVICE_TREE device_node *device_tree_find_next_node
(device_node *root,
const char *path,
device_node *last);
INLINE_DEVICE_TREE signed_word device_tree_find_int
(device_node *root,
const char *path);
INLINE_DEVICE_TREE const char *device_tree_find_string
(device_node *root,
const char *path);
INLINE_DEVICE_TREE int device_tree_find_boolean
(device_node *root,
const char *path);
INLINE_DEVICE_TREE void *device_tree_find_bytes
(device_node *root,
const char *path);
/* add to the device tree */
INLINE_DEVICE_TREE device_node *device_node_create
(device_node *parent,
char *name,
device_type type,
device_callbacks *callbacks,
void *data);
INLINE_DEVICE_TREE void device_node_add_address
(device_node *node,
unsigned_word lower_bound,
unsigned size,
device_access access,
void *init);
/* dump a node, pass this to the device_tree_traverse() function to
dump the tree */
/* dump a node, this can be passed to the device_tree_traverse()
function to dump out the entire device tree */
INLINE_DEVICE_TREE void device_tree_dump
(device_node *device,
(device_tree *device,
void *ignore_data_argument);
/* Parse a device name, various formats */
INLINE_DEVICE_TREE int scand_uw
(const char *name,
unsigned_word *uw1);
INLINE_DEVICE_TREE int scand_uw_u
(const char *name,
unsigned_word *uw1,
unsigned *u2);
INLINE_DEVICE_TREE int scand_uw_u_u
(const char *name,
unsigned_word *uw1,
unsigned *u2,
unsigned *u3);
INLINE_DEVICE_TREE int scand_uw_uw_u
(const char *name,
unsigned_word *uw1,
unsigned_word *uw2,
unsigned *u3);
INLINE_DEVICE_TREE int scand_c
(const char *name,
char *c1);
INLINE_DEVICE_TREE int scand_c_uw_u
(const char *name,
char *c1,
unsigned_word *uw2,
unsigned *u3);
INLINE_DEVICE_TREE char *printd_uw_u
(const char *name,
unsigned_word uw1,
unsigned u2);
INLINE_DEVICE_TREE char *printd_uw_u_u
(const char *name,
unsigned_word uw1,
unsigned u2,
unsigned u3);
INLINE_DEVICE_TREE char *printd_uw_u_u_c
(const char *name,
unsigned_word uw1,
unsigned u2,
unsigned u3,
const char *c4);
INLINE_DEVICE_TREE char *printd_c
(const char *name,
const char *c1);
INLINE_DEVICE_TREE char *printd_c_uw
(const char *name,
const char *c1,
unsigned_word uw2);
#endif /* _DEVICE_TREE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -26,17 +26,311 @@
#define INLINE_DEVICES
#endif
#include "device_tree.h"
/* table of all the configured devices */
/* forward declaration of types */
/* typedef struct _device device; -- in devices.h */
typedef struct _device_descriptor device_descriptor;
struct _device_descriptor {
char *name;
device_creator *creator;
/* Address access attributes that can be attached to a devices address
range */
typedef enum _access_type {
access_invalid = 0,
access_read = 1,
access_write = 2,
access_read_write = 3,
access_exec = 4,
access_read_exec = 5,
access_write_exec = 6,
access_read_write_exec = 7,
} access_type;
/* Address attachement types */
typedef enum _attach_type {
attach_invalid,
attach_callback,
attach_default,
attach_raw_memory,
} attach_type;
/* Operators on devices: */
/* Initialization:
A device is made fully functional in two stages.
1. It is created. A device is created _before_ it is entered into
the device tree. During creation any permenant structures needed
by the device should be created/initialized.
2. It is initialized. Before a simulation run, each device in the
device tree is initialized in prefix order. As part of this
initialization, a device should (re)attach its self to its parent
as needed.
*/
typedef void (device_init_callback)
(const device *me,
psim *system);
/* Data transfers:
A device may permit the reading/writing (IO) of its registers in
one or more address spaces. For instance, a PCI device may have
config registers in its config space and control registers in both
the io and memory spaces of a PCI bus.
Similarly, a device may initiate a data transfer (DMA) by passing
such a request up to its parent.
Init:
As part of its initialization (not creation) and possibly also as a
consequence of IO a device may attach its self to one or more of
the address spaces of its parent device.
For instance, a PCI device, during initialization would attach its
config registers (space=0?, base=0, nr_bytes=64) to its parent PCI
bridge. Later, due to a write to this config space, the same
device may in turn find it necessary to also attach its self to
it's parent's `memory' or `io' space.
To perform these operations, a device will call upon its parent
using either device_attach_address or device_detach_address.
* Any address specified is according to what the device expects to
see.
* Any detach operation must exactly match a previous attach.
* included with the attach or detach is the devices name, the
parent may use this as part of determining how to map map between a
child's address + space and its own.
* at any time, at most one device can have a default mapping
registered.
IO:
A device receives requests to perform reads/writes to its registers
or memory either A. from a processor or B. from a parent device.
The device may then in turn either A. resolve the IO request
locally by processing the data or trigering an exception or
B. re-mapping the access onto one of its local address spaces and
then in turn passing that on to one of its children.
* Any address passed is relative to the local device. Eg for PCI
config registers, the address would (normally) be in the range of 0
to 63.
* Any exception situtation triggered by an IO operation (processor
!= NULL) is handled in one of the following ways: 1. Machine check
(and similar): issued immediatly by restarting the cpu; 2. External
exception: issue delayed (using events.h) until the current
instruction execution cycle is completed; 3. Slave device (and
similar): the need for the interrupt is passed on to the devices
parent (which being an interrupt control unit will in turn take one
of the actions described here); 4. Forget it.
* Any exception situtation trigered by a non IO operation
(processor == NULL) is handled buy returning 0.
* Transfers of size <= 8 and of a power of 2 *must* be correctly
aligned and should be treated as a `single cycle' transfer.
DMA:
A device initiates a DMA transfer by calling its parent with the
request. At the top level (if not done earlier) this is reflected
back down the tree as io read/writes to the target device.
This function is subject to change ...
*/
typedef void (device_config_address_callback)
(const device *me,
const char *name,
attach_type type,
int address_space,
unsigned_word addr,
unsigned nr_bytes,
access_type access,
const device *who); /*callback/default*/
typedef unsigned (device_io_read_buffer_callback)
(const device *me,
void *dest,
int address_space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
typedef unsigned (device_io_write_buffer_callback)
(const device *me,
const void *source,
int address_space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia);
typedef unsigned (device_dma_read_buffer_callback)
(const device *me,
void *dest,
int address_space,
unsigned_word addr,
unsigned nr_bytes);
typedef unsigned (device_dma_write_buffer_callback)
(const device *me,
const void *source,
int address_space,
unsigned_word addr,
unsigned nr_bytes,
int violate_read_only_section);
/* Interrupts:
As mentioned above. Instead of handling an interrupt directly, a
device may instead pass the need to interrupt on to its parent.
Init:
Before passing interrupts up to is parent, a device must first
attach its interrupt lines to the parent device. To do this, the
device uses the parents attach/detach calls.
Interrupts:
A child notifies a parent of a change in an interrupt lines status
using the interrupt call. Similarly, a parent may notify a child
of any `interrupt ack' sequence using the interrupt_ack call.
*/
typedef void (device_config_interrupt_callback)
(const device *me,
const device *who,
int interrupt_line,
const char *name);
typedef void (device_interrupt_ack_callback)
(const device *me,
int interrupt_line,
int interrupt_status);
typedef void (device_interrupt_callback)
(const device *me,
const device *who,
int interrupt_line,
int interrupt_status,
cpu *processor,
unsigned_word cia);
/* IOCTL:
Very simply, a catch all for any thing that turns up that until now
either hasn't been thought of or doesn't justify an extra function. */
typedef void (device_ioctl_callback)
(const device *me,
psim *system,
cpu *processor,
unsigned_word cia,
...);
/* the callbacks */
typedef struct _device_callbacks {
/* initialization */
device_init_callback *init;
/* address/data config - from child */
device_config_address_callback *attach_address;
device_config_address_callback *detach_address;
/* address/data transfer - to child */
device_io_read_buffer_callback *io_read_buffer;
device_io_write_buffer_callback *io_write_buffer;
/* address/data transfer - from child */
device_dma_read_buffer_callback *dma_read_buffer;
device_dma_write_buffer_callback *dma_write_buffer;
/* interrupt config - from child */
device_config_interrupt_callback *attach_interrupt;
device_config_interrupt_callback *detach_interrupt;
/* interrupt transfer - from child */
device_interrupt_callback *interrupt;
/* interrupt transfer - to child */
device_interrupt_ack_callback *interrupt_ack;
/* back door to anything we've forgot */
device_ioctl_callback *ioctl;
} device_callbacks;
/* A device */
struct _device {
const char *name; /* eg rom@0x1234, 0x400 */
void *data; /* device specific data */
const device_callbacks *callback;
const device *parent;
};
INLINE_DEVICES device_descriptor *find_device_descriptor(char *name);
/* Create a new device, finding it in the builtin device table */
INLINE_DEVICES const device *device_create
(const char *name,
const device *parent);
/* create a new device using the parameterized data */
INLINE_DEVICES const device *device_create_from
(const char *name,
void *data,
const device_callbacks *callback,
const device *parent);
/* Unimplemented call back functions. These abort the simulation */
INLINE_DEVICES device_init_callback unimp_device_init;
INLINE_DEVICES device_config_address_callback unimp_device_attach_address;
INLINE_DEVICES device_config_address_callback unimp_device_detach_address;
INLINE_DEVICES device_io_read_buffer_callback unimp_device_io_read_buffer;
INLINE_DEVICES device_io_write_buffer_callback unimp_device_io_write_buffer;
INLINE_DEVICES device_dma_read_buffer_callback unimp_device_dma_read_buffer;
INLINE_DEVICES device_dma_write_buffer_callback unimp_device_dma_write_buffer;
INLINE_DEVICES device_config_interrupt_callback unimp_device_attach_interrupt;
INLINE_DEVICES device_config_interrupt_callback unimp_device_detach_interrupt;
INLINE_DEVICES device_interrupt_callback unimp_device_interrupt;
INLINE_DEVICES device_interrupt_ack_callback unimp_device_interrupt_ack;
INLINE_DEVICES device_ioctl_callback unimp_device_ioctl;
/* Pass through and ignore callback functions. A call going towards
the root device are passed on up, local calls are ignored and call
downs abort */
INLINE_DEVICES device_init_callback ignore_device_init;
INLINE_DEVICES device_config_address_callback pass_device_attach_address;
INLINE_DEVICES device_config_address_callback pass_device_detach_address;
INLINE_DEVICES device_dma_read_buffer_callback pass_device_dma_read_buffer;
INLINE_DEVICES device_dma_write_buffer_callback pass_device_dma_write_buffer;
INLINE_DEVICES device_config_interrupt_callback pass_device_attach_interrupt;
INLINE_DEVICES device_config_interrupt_callback pass_device_detach_interrupt;
INLINE_DEVICES device_interrupt_callback pass_device_interrupt;
INLINE_DEVICES const device_callbacks *passthrough_device_callbacks
(void);
#endif /* _DEVICES_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +0,0 @@
/* 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.
*/
/*
* Interface for the Instruction execution routines
*/
/*
* Macro's that define the parts of an instruction
*/
#define FLOATING_POINT_ENABLED_PROGRAM_INTERRUPT \
program_interrupt(processor, \
cia, \
floating_point_enabled_program_interrupt)
#define ILLEGAL_INSN_PROGRAM_INTERRUPT \
program_interrupt(processor, \
cia, \
illegal_instruction_program_interrupt)
#define PRIVILEGED_INSN_PROGRAM_INTERRUPT \
program_interrupt(processor, \
cia, \
privileged_instruction_program_interrupt)
#define TRAP_PROGRAM_INTERRUPT \
program_interrupt(processor, \
cia, \
trap_program_interrupt)
#define FLOATING_POINT_UNAVAILABLE_INTERRUPT \
floating_point_unavailable_interrupt(processor, \
cia)
#define FLOATING_POINT_ASSIST_INTERRUPT \
floating_point_assist_interrupt(processor, \
cia)
#define BREAKPOINT \
do { \
ITRACE(trace_breakpoint, \
("breakpoint - cia0x%x\n", \
cia)); \
cpu_halt(processor, cia, was_trap, 0); \
} while (0)
#define SYSTEM_CALL_INTERRUPT \
system_call_interrupt(processor, \
cia)

View File

@ -1,355 +0,0 @@
/* 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 _MEMORY_MAP_C_
#define _MEMORY_MAP_C_
#ifndef STATIC_INLINE_MEMORY_MAP
#define STATIC_INLINE_MEMORY_MAP STATIC_INLINE
#endif
#include "basics.h"
#include "device_tree.h"
#include "memory_map.h"
#include "interrupts.h"
typedef struct _memory_mapping memory_mapping;
struct _memory_mapping {
/* ram map */
void *buffer;
/* device map */
device_node *device;
device_reader_callback *reader;
device_writer_callback *writer;
/* common */
unsigned_word base;
unsigned_word bound;
unsigned_word size;
struct _memory_mapping *next;
};
struct _memory_map {
memory_mapping *first;
};
INLINE_MEMORY_MAP memory_map *
new_memory_map(void)
{
memory_map *new_map;
new_map = ZALLOC(memory_map);
return new_map;
}
STATIC_INLINE_MEMORY_MAP void
memory_map_add_memory(memory_map *map,
device_node *device,
device_reader_callback *reader,
device_writer_callback *writer,
void *buffer,
unsigned_word base,
unsigned size)
{
memory_mapping *new_mapping;
memory_mapping *next_mapping;
memory_mapping **last_mapping;
/* actually do occasionally get a zero size map */
if (size == 0)
return;
new_mapping = ZALLOC(memory_mapping);
/* ram */
new_mapping->buffer = buffer;
/* devices */
new_mapping->device = device;
new_mapping->reader = reader;
new_mapping->writer = writer;
/* common */
new_mapping->base = base;
new_mapping->size = size;
new_mapping->bound = base + size;
/* find the insertion point (between last/next) */
next_mapping = map->first;
last_mapping = &map->first;
while(next_mapping != NULL && next_mapping->bound <= new_mapping->base) {
/* assert: new_mapping->base > all bases before next_mapping */
/* assert: new_mapping->bound >= all bounds before next_mapping */
last_mapping = &next_mapping->next;
next_mapping = next_mapping->next;
}
/* check insertion point correct */
if (next_mapping != NULL && next_mapping->base < new_mapping->bound) {
error("memory_map_add_callback_memory() internal error - map overlap\n");
}
/* insert the new mapping */
*last_mapping = new_mapping;
new_mapping->next = next_mapping;
}
INLINE_MEMORY_MAP void
memory_map_add_callback_memory(memory_map *map,
device_node *device,
device_reader_callback *reader,
device_writer_callback *writer,
unsigned_word base,
unsigned size)
{
memory_map_add_memory(map, device, reader, writer, NULL, base, size);
}
INLINE_MEMORY_MAP void
memory_map_add_raw_memory(memory_map *map,
void *buffer,
unsigned_word base,
unsigned size)
{
memory_map_add_memory(map, NULL, NULL, NULL, buffer, base, size);
}
STATIC_INLINE_MEMORY_MAP memory_mapping *
memory_map_find_mapping(memory_map *map,
unsigned_word addr,
unsigned nr_bytes,
int abort,
cpu *processor,
unsigned_word cia)
{
memory_mapping *mapping = map->first;
ASSERT((addr & (nr_bytes-1)) == 0);
while (1) {
if (addr >= mapping->base
&& (addr + nr_bytes) <= mapping->bound)
break;
mapping = mapping->next;
if (mapping == NULL) {
if (abort) {
switch (CURRENT_ENVIRONMENT) {
case VIRTUAL_ENVIRONMENT:
data_storage_interrupt(processor,
cia,
addr,
vea_storage_interrupt,
0/* doesnt matter */);
break;
default:
error("memory_map_find_mapping() - %s%x%s%s%s%s%s",
"access to undefined address 0x", addr, "\n",
"this code should be passing back up the device tree an\n",
"abort event (with processor attached). Somewhere in\n",
"the device tree this would be caught and either halt,\n",
"interrupt, or reset the processor\n");
}
return NULL;
}
else
return NULL;
}
}
return mapping;
}
STATIC_INLINE_MEMORY_MAP void *
memory_map_translate(memory_mapping *mapping,
unsigned_word addr)
{
return mapping->buffer + addr - mapping->base;
}
INLINE_MEMORY_MAP unsigned
memory_map_read_buffer(memory_map *map,
void *buffer,
unsigned_word addr,
unsigned len,
transfer_mode mode)
{
unsigned count;
unsigned_1 byte;
for (count = 0; count < len; count++) {
unsigned pos = 0;
unsigned_word raddr = addr + count;
memory_mapping *mapping =
memory_map_find_mapping(map, raddr, 1,
0/*abort*/,
0, 0/*processor, cia*/);
if (mapping == NULL)
break;
if (mode == raw_transfer ||
CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER)
pos = count;
else if (mode == cooked_transfer)
pos = len-count-1;
else
error("memory_map_read_buffer() - transfer mode unknown\n");
if (mapping->reader != NULL)
/* hope it doesn't barf */
byte = mapping->reader(mapping->device,
raddr - mapping->base,
1,
0, 0/*processor, cia*/);
else
byte = *(unsigned_1*)memory_map_translate(mapping,
raddr);
((unsigned_1*)buffer)[pos] = T2H_1(byte);
}
return count;
}
INLINE_MEMORY_MAP unsigned
memory_map_write_buffer(memory_map *map,
const void *buffer,
unsigned_word addr,
unsigned len,
transfer_mode mode)
{
unsigned count;
unsigned_1 byte;
for (count = 0; count < len; count++) {
unsigned pos = 0;
unsigned_word raddr = addr + count;
memory_mapping *mapping =
memory_map_find_mapping(map, raddr, 1,
0/*abort*/,
0, 0/*processor, cia*/);
if (mapping == NULL)
break;
if (mode == raw_transfer ||
CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER)
pos = count;
else if (mode == cooked_transfer)
pos = len-count-1;
else
error("memory_map_write_buffer() - transfer mode unknown\n");
byte = H2T_1(((unsigned_1*)buffer)[pos]);
if (mapping->writer != NULL)
/* hope it doesn't barf */
mapping->writer(mapping->device,
raddr - mapping->base,
1,
byte,
0, 0/*processor, cia*/);
else
*(unsigned_1*)memory_map_translate(mapping, raddr) = byte;
}
return count;
}
INLINE_MEMORY_MAP unsigned
memory_map_zero(memory_map *map,
unsigned_word addr,
unsigned len)
{
unsigned pos;
for (pos = 0; pos < len; pos++) {
unsigned_word raddr = addr + pos;
memory_mapping *mapping =
memory_map_find_mapping(map, raddr, 1,
0/*abort*/,
0, 0/*processor, cia*/);
if (mapping == NULL)
break;
if (mapping->writer != NULL)
mapping->writer(mapping->device,
raddr - mapping->base,
1,
0,
0, 0/*processor, cia*/);
else
*(unsigned_1*)memory_map_translate(mapping, raddr) = 0;
}
return pos;
}
#define DEFINE_MEMORY_MAP_READ_N(N) \
INLINE_MEMORY_MAP unsigned_##N \
memory_map_read_##N(memory_map *map, \
unsigned_word addr, \
cpu *processor, \
unsigned_word cia) \
{ \
memory_mapping *mapping = memory_map_find_mapping(map, addr, \
sizeof(unsigned_##N), \
1, \
processor, \
cia); \
if (WITH_CALLBACK_MEMORY && mapping->reader != NULL) \
return ((unsigned_##N) \
mapping->reader(mapping->device, \
addr - mapping->base, \
sizeof(unsigned_##N), \
processor, \
cia)); \
else \
return T2H_##N(*(unsigned_##N*)memory_map_translate(mapping, addr)); \
}
DEFINE_MEMORY_MAP_READ_N(1)
DEFINE_MEMORY_MAP_READ_N(2)
DEFINE_MEMORY_MAP_READ_N(4)
DEFINE_MEMORY_MAP_READ_N(8)
DEFINE_MEMORY_MAP_READ_N(word)
#define DEFINE_MEMORY_MAP_WRITE_N(N) \
INLINE_MEMORY_MAP void \
memory_map_write_##N(memory_map *map, \
unsigned_word addr, \
unsigned_##N val, \
cpu *processor, \
unsigned_word cia) \
{ \
memory_mapping *mapping = memory_map_find_mapping(map, addr, \
sizeof(unsigned_##N), \
1, \
processor, \
cia); \
if (WITH_CALLBACK_MEMORY && mapping->writer != NULL) \
mapping->writer(mapping->device, \
addr - mapping->base, \
sizeof(unsigned_##N), \
val, \
processor, \
cia); \
else \
*(unsigned_##N*)memory_map_translate(mapping, addr) = H2T_##N(val); \
}
DEFINE_MEMORY_MAP_WRITE_N(1)
DEFINE_MEMORY_MAP_WRITE_N(2)
DEFINE_MEMORY_MAP_WRITE_N(4)
DEFINE_MEMORY_MAP_WRITE_N(8)
DEFINE_MEMORY_MAP_WRITE_N(word)
#endif /* _MEMORY_MAP_C_ */

View File

@ -1,126 +0,0 @@
/* 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 _MEMORY_MAP_H_
#define _MEMORY_MAP_H_
#ifndef INLINE_MEMORY_MAP
#define INLINE_MEMORY_MAP
#endif
/* basic types */
typedef struct _memory_map memory_map;
/* constructor */
INLINE_MEMORY_MAP memory_map *new_memory_map
(void);
/* operators to add memory to a memory map
callback-memory:
includes a callback routine that is called upon for the data.
Useful when modeling memory mapped devices.
raw-memory:
normal base and bound memory map used to model ram or mapped memory
pages */
INLINE_MEMORY_MAP void memory_map_add_callback_memory
(memory_map *map,
device_node *device,
device_reader_callback *reader,
device_writer_callback *writer,
unsigned_word base,
unsigned size); /* host limited */
INLINE_MEMORY_MAP void memory_map_add_raw_memory
(memory_map *map,
void *buffer,
unsigned_word base,
unsigned size/*host limited*/);
/* Variable sized read/write/zero:
Transfer (zero) a variable size block of data between the host and
target (possibly byte swapping it). Should any problems occure,
the number of bytes actually transfered is returned. */
INLINE_MEMORY_MAP unsigned memory_map_read_buffer
(memory_map *map,
void *buffer,
unsigned_word addr,
unsigned len,
transfer_mode mode);
INLINE_MEMORY_MAP unsigned memory_map_write_buffer
(memory_map *map,
const void *buffer,
unsigned_word addr,
unsigned len,
transfer_mode mode);
INLINE_MEMORY_MAP unsigned memory_map_zero
(memory_map *map,
unsigned_word addr,
unsigned len);
/* Fixed sized read/write:
Transfer a fixed amout of memory between the host and target. The
memory always being translated and the operation always aborting
should a problem occure */
#define DECLARE_MEMORY_MAP_WRITE_N(N) \
INLINE_MEMORY_MAP void memory_map_write_##N \
(memory_map *map, \
unsigned_word addr, \
unsigned_##N val, \
cpu *processor, \
unsigned_word cia);
DECLARE_MEMORY_MAP_WRITE_N(1)
DECLARE_MEMORY_MAP_WRITE_N(2)
DECLARE_MEMORY_MAP_WRITE_N(4)
DECLARE_MEMORY_MAP_WRITE_N(8)
DECLARE_MEMORY_MAP_WRITE_N(word)
#define DECLARE_MEMORY_MAP_READ_N(N) \
INLINE_MEMORY_MAP unsigned_##N memory_map_read_##N \
(memory_map *map, \
unsigned_word addr, \
cpu *processor, \
unsigned_word cia);
DECLARE_MEMORY_MAP_READ_N(1)
DECLARE_MEMORY_MAP_READ_N(2)
DECLARE_MEMORY_MAP_READ_N(4)
DECLARE_MEMORY_MAP_READ_N(8)
DECLARE_MEMORY_MAP_READ_N(word)
#endif

View File

@ -184,10 +184,11 @@ do { \
Byte swap a quantity the size of the targets word */
#if WITH_64BIT_TARGET
#if (WITH_TARGET_WORD_BITSIZE == 64)
#define H2T_word(X) H2T_8(X)
#define T2H_word(X) T2H_8(X)
#else
#endif
#if (WITH_TARGET_WORD_BITSIZE == 32)
#define H2T_word(X) H2T_4(X)
#define T2H_word(X) T2H_4(X)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,11 @@
#ifndef _SYSTEM_H_
#define _SYSTEM_H_
void system_call
#ifndef INLINE_SYSTEM
#define INLINE_SYSTEM
#endif
INLINE_SYSTEM void system_call
(cpu *processor,
unsigned_word cia);