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

View File

@ -4,63 +4,47 @@
Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
This directory contains the program PSIM that models the PowerPC This directory contains the program PSIM that models the PowerPC
architecture. It can either be run stand alone (psim) or linked with architecture. It can either be run stand alone (psim or run) or used
GDB. 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 This contains a replacement for the directory sim/ppc. As
into gdb 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 powerpc-psim@ci.com.au
already been merged into the
GDB source tree.
gnu-*-*.diff.gz Other noise It's a majordomo mailing list.
BUILDING: 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 o Configure almost as per normal, specifing the special target
ftp.cygnus.com:pub). I've built it with a beta version of gdb-4.15. eabisim vis:
Unpack gdb vis: $ CC=gcc ./configure --target=powerpcle-unknown-eabisim
$ 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
by default (because of its dependency on GCC).
o Build your entire gdb tree as per normal. Something along the o Build your entire gdb tree as per normal. Something along the
lines of: lines of:
@ -78,15 +62,17 @@ BUILDING:
$ cd gdb-4.15 $ cd gdb-4.15
$ make CC=gcc install $ make CC=gcc install
The program sim/ppc/psim is not installed.
RUNNING: RUNNING:
PSIM can either be run as a stand alone program or as part PSIM can either be run as a stand alone program or as part
of gdb. The psim-test archive contains pre-compiled and of gdb. The psim-test archive (found in:
linked programs that can be run on PSIM. The notes below
assume that you have unpacked that tar archive. 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 To rebuild the archive you will need to obtain a working
version of an ELF compiler/linker for the PowerPC. 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) Making it go faster
for notes.
See the file sim/ppc/config.h (which is copied from
sim/ppc/std-config.h) for further information.
KNOWN FEATURES KNOWN FEATURES
SMP, dual-endian, VEA and OEA models, hardware devices SMP: A Symetric Multi-Processor configuration is suported.
(console, icu, reset) ... 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: 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 HTAB (page) code for OEA model untested. Some of the vm code
instructions unimplemented. 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 Flush instruction cache instructions do nothing. Perhaphs they
should (if there is an instruction cache) flush it. should (if there is an instruction cache) flush it.
PowerOpen VEA model (a.k.a XCOFF a.k.a AIX) broken. It was Lacks PowerOpen (a.k.a. XCOFF a.k.a. AIX) and NT startups.
working but that is before I changed the create stack frame The PowerOpen worked until I added the ELF one.
code into an ELF version.
OpenBoot and PR*P interfaces missing. Open boot could be OpenBoot and PR*P interfaces missing. Open boot could be
implemented by putting special instructions at the address implemented by putting special instructions at the address
of the OpenBoot callback functions. Those instructions of the OpenBoot callback functions. Those instructions
could than emulate OpenBoot behavour. could than emulate OpenBoot behavour.
VEA memory read/write performance could be improved by merging Missing VEA system calls.
the data sections.
When reading in a VEA executable, the binaries text and data
sections are not made page aligned.
Missing or commented out instructions. Missing or commented out instructions.
Lack of floating point support. Only basic (hackish) floating point implemented, I would not
[workaround: build everything using -msoft-float] 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. finished/tested.
Better and more devices. Better and more devices.
Only two device trees VEA and OEA (clayton) and those hard coded. PORTABILITY (Notes taken from Michael Meissner): Heavy use of
Should be possible to specify a file containing a device tree the ## operator - fix using the clasic X/**/Y hack; Use of the
description as the program to run. At present it a device tree signed keyword. In particular, signed char has no analogue in
file is detected causing psim to abort. classic C (though most implementations of classic C use signed
chars); Use of long long which restricts the target compiler
I wonder if I've got my ppc.instructions copyright to be GCC.
notice correct.
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: THANKS:
@ -251,3 +274,7 @@ i486DX2/66
1/270/316 - switch=2/2,expand=0,inline=1,nia=0 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/271/281 - switch=1/1,expand=0,inline=1,nia=1
1/267/274 - switch=2/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 #define STATIC_INLINE_CORE STATIC_INLINE
#endif #endif
#include "basics.h" #include "basics.h"
#include "device_tree.h" #include "device_tree.h"
#include "memory_map.h"
#include "core.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 { struct _core {
/* attached devices */ core_map map[nr_core_map_types];
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;
}; };
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 * INLINE_CORE core *
core_create(device_node *root, core_create(void)
int trace)
{ {
core *memory; core *new_core = ZALLOC(core);
return new_core;
/* 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;
} }
STATIC_INLINE_CORE void 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) core_init(core *memory)
{ {
unsigned nr_cleared; core_map_types access_type;
unsigned_word clear_base; for (access_type = 0;
unsigned_word clear_bound; access_type < nr_core_map_types;
access_type++) {
/* for vea, several memory break points */ core_map *map = memory->map + access_type;
memory->data_upper_bound = 0; /* blow away old mappings */
memory->stack_upper_bound = device_tree_find_int(memory->device_tree, core_mapping *curr = map->first;
"/options/stack-pointer");; while (curr != NULL) {
memory->stack_lower_bound = memory->stack_upper_bound; core_mapping *tbd = curr;
curr = curr->next;
/* (re) clear all of memory that is specified by memory-address if (tbd->free_buffer) {
entries. While we're at it determine the upper bound for memory ASSERT(tbd->buffer != NULL);
areas */ zfree(tbd->buffer);
device_tree_traverse(memory->device_tree, }
NULL, zfree(tbd);
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;
} }
} map->first = NULL;
/* blow away the default */
/* clear any part of the stack that was dynamically allocated */ if (map->default_map != NULL) {
clear_base = memory->stack_low_water; ASSERT(map->default_map->buffer == NULL);
clear_bound = memory->stack_upper_bound; zfree(map->default_map);
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->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 /* the core has three sub mappings that the more efficient
core_add_raw_memory(core *memory, read/write fixed quantity functions use */
void *buffer,
unsigned_word base, INLINE_CORE core_map *
unsigned size, core_readable(core *memory)
device_access access)
{ {
if (access & device_is_readable) return memory->map + core_read_map;
memory_map_add_raw_memory(memory->readable, }
buffer, base, size);
if (access & device_is_writeable) INLINE_CORE core_map *
memory_map_add_raw_memory(memory->writeable, core_writeable(core *memory)
buffer, base, size); {
if (access & device_is_executable) return memory->map + core_write_map;
memory_map_add_raw_memory(memory->executable, }
buffer, base, size);
INLINE_CORE core_map *
core_executable(core *memory)
{
return memory->map + core_execute_map;
} }
INLINE_CORE void
core_add_callback_memory(core *memory, STATIC_INLINE_CORE core_mapping *
device_node *device, new_core_mapping(attach_type attach,
device_reader_callback *reader, int address_space,
device_writer_callback *writer, unsigned_word addr,
unsigned_word base, unsigned nr_bytes,
unsigned size, const device *device,
device_access access) void *buffer,
int free_buffer)
{ {
if (access & device_is_readable) core_mapping *new_mapping = ZALLOC(core_mapping);
memory_map_add_callback_memory(memory->readable, switch (attach) {
device, reader, writer, case attach_default:
base, size); case attach_callback:
if (access & device_is_writeable) new_mapping->device = device;
memory_map_add_callback_memory(memory->writeable, new_mapping->reader = device->callback->io_read_buffer;
device, reader, writer, new_mapping->writer = device->callback->io_write_buffer;
base, size); break;
if (access & device_is_executable) case attach_raw_memory:
memory_map_add_callback_memory(memory->executable, new_mapping->buffer = buffer;
device, reader, writer, new_mapping->free_buffer = free_buffer;
base, size); 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 STATIC_INLINE_CORE void
malloc_core_memory(core *memory, core_map_attach(core_map *access_map,
unsigned_word base, attach_type attach,
unsigned size, int address_space,
device_access access) 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); if (attach == attach_default) {
core_add_raw_memory(memory, buffer, base, size, access); if (access_map->default_map != NULL)
} error("core_map_attach() default mapping already in place\n");
ASSERT(buffer == NULL);
INLINE_CORE unsigned_word access_map->default_map = new_core_mapping(attach,
core_data_upper_bound(core *memory) address_space, addr, nr_bytes,
{ device, buffer, free_buffer);
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;
} }
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 /* find the insertion point (between last/next) */
core_add_stack(core *memory, unsigned_word incr) next_mapping = access_map->first;
{ last_mapping = &access_map->first;
unsigned_word new_lower_bound = memory->stack_lower_bound - incr; while(next_mapping != NULL && next_mapping->bound < addr) {
if (new_lower_bound < memory->stack_low_water) { /* assert: next_mapping->base > all bases before next_mapping */
if (memory->stack_lower_bound <= memory->stack_low_water) /* assert: next_mapping->bound >= all bounds before next_mapping */
/* all the memory is new */ last_mapping = &next_mapping->next;
malloc_core_memory(memory, next_mapping = next_mapping->next;
new_lower_bound, }
incr,
device_is_readable | device_is_writeable); /* check insertion point correct */
else if (next_mapping != NULL && next_mapping->base < (addr + (nr_bytes - 1))) {
/* allocate only the extra bit */ error("core_map_attach() map overlap\n");
malloc_core_memory(memory, }
new_lower_bound,
memory->stack_low_water - new_lower_bound, /* create/insert the new mapping */
device_is_readable | device_is_writeable); *last_mapping = new_core_mapping(attach,
memory->stack_low_water = new_lower_bound; 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 * INLINE_CORE void
core_readable(core *core) 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 * STATIC_INLINE_CORE core_mapping *
core_writeable(core *core) 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 * STATIC_INLINE_CORE void *
core_executable(core *core) 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 #define INLINE_CORE
#endif #endif
/* the base type */ /* basic types */
typedef struct _core core; 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 INLINE_CORE core *core_create
(device_node *root, (void);
int trace);
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); (core *memory);
/* from this core extract out the three different types of memory -
executable, readable, writeable */
INLINE_CORE memory_map *core_readable /* operators to add/remove a mapping in the core
(core *memory);
INLINE_CORE memory_map *core_writeable callback-memory:
(core *memory);
INLINE_CORE memory_map *core_executable All access are passed onto the specified devices callback routines
(core *memory); 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 Transfer (zero) a variable size block of data between the host and
(core *memory, 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, void *buffer,
unsigned_word base, unsigned_word addr,
unsigned size, unsigned nr_bytes);
device_access access);
INLINE_CORE void core_add_callback_memory INLINE_CORE unsigned core_map_write_buffer
(core *memory, (core_map *map,
device_node *device, const void *buffer,
device_reader_callback *reader, unsigned_word addr,
device_writer_callback *writer, unsigned nr_bytes);
unsigned_word base,
unsigned size,
device_access access);
/* In the VEA model, memory grow's after it is created. Operators /* Fixed sized read/write:
below grow memory as required.
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 #define DECLARE_CORE_WRITE_N(N) \
(core *memory); 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 DECLARE_CORE_WRITE_N(1)
(core *memory); 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 #define DECLARE_CORE_READ_N(N) \
(core *memory); 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 DECLARE_CORE_READ_N(1)
(core *memory, DECLARE_CORE_READ_N(2)
unsigned_word incr); DECLARE_CORE_READ_N(4)
DECLARE_CORE_READ_N(8)
DECLARE_CORE_READ_N(word)
INLINE_CORE void core_add_stack #endif
(core *memory,
unsigned_word incr);
#endif /* _CORE_ */

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 #endif
/* forward declaration of types */ #include "devices.h"
typedef struct _device_node device_node; typedef struct _device_tree device_tree;
typedef struct _device_address device_address;
typedef struct _device_callbacks device_callbacks;
/* 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. INLINE_DEVICE_TREE void device_tree_init
(device_tree *root,
Should a memory read/write operation cause an interrupt (external psim *system);
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);
/* traverse the tree eiter pre or post fix */ /* traverse the tree eiter pre or post fix */
typedef void (device_tree_traverse_function) typedef void (device_tree_traverse_function)
(device_node *device, (device_tree *device,
void *data); void *data);
INLINE_DEVICE_TREE void device_tree_traverse INLINE_DEVICE_TREE void device_tree_traverse
(device_node *root, (device_tree *root,
device_tree_traverse_function *prefix, device_tree_traverse_function *prefix,
device_tree_traverse_function *postfix, device_tree_traverse_function *postfix,
void *data); void *data);
/* query the device tree */ /* dump a node, this can be passed to the device_tree_traverse()
function to dump out the entire 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 */
INLINE_DEVICE_TREE void device_tree_dump INLINE_DEVICE_TREE void device_tree_dump
(device_node *device, (device_tree *device,
void *ignore_data_argument); 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_ */ #endif /* _DEVICE_TREE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -26,17 +26,311 @@
#define INLINE_DEVICES #define INLINE_DEVICES
#endif #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 { /* Address access attributes that can be attached to a devices address
char *name; range */
device_creator *creator; 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_ */ #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 */ 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 H2T_word(X) H2T_8(X)
#define T2H_word(X) T2H_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 H2T_word(X) H2T_4(X)
#define T2H_word(X) T2H_4(X) #define T2H_word(X) T2H_4(X)
#endif #endif

File diff suppressed because it is too large Load Diff

View File

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