configure.in
core.c
core.h
+core_n.h
cpu.c
cpu.h
debug.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
system.h
vm.c
vm.h
+vm_n.h
words.h
Things-to-lose:
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:
$ 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.
.
-CONFIGURATION: Making it go faster
+CONFIGURATION:
+
+ Making it go faster
- See the file sim/ppc/config.h (a.k.a. sim/ppc/data/ppc-config)
- for notes.
+ 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).
- HTAB (page) code for OEA model untested. Some of the vm code
- instructions unimplemented.
+ DEVICE TREE DOC: How to create and use the device tree is not
+ documented at all.
- Doesn't detect/handle changing endian bits. In fact they are
- ignored.
+ INITIALIZATION: When running from gdb, things are not
+ re-initialzied very well e.g. registers are not rezeroed.
- Return from interrupt instruction unimplemented.
+ HTAB (page) code for OEA model untested. Some of the vm code
+ instructions 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 target untested.
- 64bit untested.
+ 64bit host broken. For instance use of scanf "%x", &long long.
- Event code for pending events from signal handlers not
+ 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:
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
#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];
};
+INLINE_CORE core *
+core_create(void)
+{
+ core *new_core = ZALLOC(core);
+ return new_core;
+}
+
+
STATIC_INLINE_CORE void
-create_core_from_addresses(device_node *device,
- void *data)
+core_init(core *memory)
{
- 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);
+ 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);
}
- 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 */
+ zfree(tbd);
+ }
+ 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;
}
}
-INLINE_CORE core *
-core_create(device_node *root,
- int trace)
+
+/* the core has three sub mappings that the more efficient
+ read/write fixed quantity functions use */
+
+INLINE_CORE core_map *
+core_readable(core *memory)
{
- 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;
+ return memory->map + core_read_map;
}
+INLINE_CORE core_map *
+core_writeable(core *memory)
+{
+ return memory->map + core_write_map;
+}
-STATIC_INLINE_CORE void
-zero_core_from_addresses(device_node *device,
- void *data)
+INLINE_CORE core_map *
+core_executable(core *memory)
{
- 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;
- }
- }
+ return memory->map + core_execute_map;
}
-STATIC_INLINE_CORE void
-load_core_from_addresses(device_node *device,
- void *data)
+
+
+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)
{
- 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");
- }
+ 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;
}
-INLINE_CORE void
-core_init(core *memory)
+
+STATIC_INLINE_CORE void
+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*/
{
- 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;
- }
+ 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);
}
-
- /* 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;
+ 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");
+
+ /* 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;
}
- }
- /* with everything zero'ed, now (re) load any data sections */
- device_tree_traverse(memory->device_tree,
- NULL,
- load_core_from_addresses,
- memory);
+ /* 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;
+ }
}
-
INLINE_CORE void
-core_add_raw_memory(core *memory,
- void *buffer,
- unsigned_word base,
- unsigned size,
- device_access access)
+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*/
{
- 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);
+ 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 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 *
+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 */
{
- 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 *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;
}
-STATIC_INLINE_CORE void
-malloc_core_memory(core *memory,
- unsigned_word base,
- unsigned size,
- device_access access)
+STATIC_INLINE_CORE void *
+core_translate(core_mapping *mapping,
+ unsigned_word addr)
{
- void *buffer = (void*)zalloc(size);
- core_add_raw_memory(memory, buffer, base, size, access);
+ return mapping->buffer + addr - mapping->base;
}
-INLINE_CORE unsigned_word
-core_data_upper_bound(core *memory)
+
+INLINE_CORE unsigned
+core_map_read_buffer(core_map *map,
+ void *buffer,
+ unsigned_word addr,
+ unsigned len)
{
- return memory->data_upper_bound;
+ 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_word
-core_stack_lower_bound(core *memory)
+INLINE_CORE unsigned
+core_map_write_buffer(core_map *map,
+ const void *buffer,
+ unsigned_word addr,
+ unsigned len)
{
- return memory->stack_lower_bound;
+ 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;
}
-INLINE_CORE unsigned_word
-core_stack_size(core *memory)
-{
- return (memory->stack_upper_bound - memory->stack_lower_bound);
-}
+/* Top level core(root) device: core@garbage
+
+ The core device captures incomming dma requests and changes them to
+ outgoing io requests. */
-INLINE_CORE void
-core_add_data(core *memory, unsigned_word incr)
+STATIC_INLINE_CORE void
+core_init_callback(const device *me,
+ psim *system)
{
- 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;
+ core *memory = (core*)me->data;
+ core_init(memory);
}
-INLINE_CORE void
-core_add_stack(core *memory, unsigned_word incr)
+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*/
{
- 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;
- }
- memory->stack_lower_bound = new_lower_bound;
+ 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);
}
-INLINE_CORE memory_map *
-core_readable(core *core)
+STATIC_INLINE_CORE unsigned
+core_dma_read_buffer_callback(const device *me,
+ void *target,
+ int address_space,
+ unsigned_word offset,
+ unsigned nr_bytes)
{
- return core->readable;
+ core *memory = (core*)me->data;
+ return core_map_read_buffer(core_readable(memory),
+ target,
+ offset,
+ nr_bytes);
}
-INLINE_CORE memory_map *
-core_writeable(core *core)
+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)
{
- return core->writeable;
+ 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);
}
-INLINE_CORE memory_map *
-core_executable(core *core)
+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 core->executable;
+ return device_create_from("core", memory, &core_callbacks, NULL);
}
-#endif /* _CORE_ */
+
+
+/* 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_ */
#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
-(core *memory);
-/* from this core extract out the three different types of memory -
- executable, readable, writeable */
+/* the core has three sub mappings that the more efficient
+ read/write fixed quantity functions use */
-INLINE_CORE memory_map *core_readable
+INLINE_CORE core_map *core_readable
(core *memory);
-INLINE_CORE memory_map *core_writeable
+INLINE_CORE core_map *core_writeable
(core *memory);
-INLINE_CORE memory_map *core_executable
+INLINE_CORE core_map *core_executable
(core *memory);
-/* operators to grow memory on the fly */
-INLINE_CORE void core_add_raw_memory
-(core *memory,
- void *buffer,
- unsigned_word base,
- unsigned size,
- device_access access);
+/* operators to add/remove a mapping in the core
-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);
+ callback-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.
-/* In the VEA model, memory grow's after it is created. Operators
- below grow memory as required.
+ raw-memory:
- FIXME - should this be inside of vm? */
+ 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.
-INLINE_CORE unsigned_word core_data_upper_bound
-(core *memory);
+ For raw-memory, the device is ignored and the core alloc's a
+ block to act as the memory.
-INLINE_CORE unsigned_word core_stack_lower_bound
-(core *memory);
+ default-memory:
-INLINE_CORE unsigned_word core_stack_size
-(core *memory);
+ Should, for the core, there be no defined mapping for a given
+ address then the default map (if present) is called.
-INLINE_CORE void core_add_data
-(core *memory,
- unsigned_word incr);
+ For default-memory, the device must be specified. */
-INLINE_CORE void core_add_stack
-(core *memory,
- unsigned_word incr);
+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*/
-#endif /* _CORE_ */
+
+/* Variable sized read/write:
+
+ 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 addr,
+ unsigned nr_bytes);
+
+INLINE_CORE unsigned core_map_write_buffer
+(core_map *map,
+ const void *buffer,
+ unsigned_word addr,
+ unsigned nr_bytes);
+
+
+/* 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_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);
+
+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)
+
+#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);
+
+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)
+
+#endif
--- /dev/null
+/* 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);
+}
+
#endif
#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
#include "basics.h"
#include "device_tree.h"
-#include "devices.h"
-#include "bfd.h"
-
-/* Any starting address less than this is assumed to be an OEA program
- rather than VEA. */
-#ifndef OEA_START_ADDRESS
-#define OEA_START_ADDRESS 4096
-#endif
-
-#ifndef OEA_MEMORY_SIZE
-#define OEA_MEMORY_SIZE 0x100000
-#endif
-
-enum { clayton_memory_size = OEA_MEMORY_SIZE };
-
-/* insert the address into the device_nodes sorted list of addresses */
-INLINE_DEVICE_TREE void
-device_node_add_address(device_node *node,
- unsigned_word lower_bound,
- unsigned size,
- device_access access,
- void *init)
-{
- unsigned_word upper_bound = lower_bound + size;
- device_address *new_address;
- device_address **current_address;
-
- /* find the insertion point */
- current_address = &node->addresses;
- while (*current_address != NULL
- && (*current_address)->upper_bound >= upper_bound) {
- current_address = &(*current_address)->next_address;
- }
-
- /* insert */
- new_address = ZALLOC(device_address);
- new_address->lower_bound = lower_bound;
- new_address->upper_bound = lower_bound + size;
- new_address->size = size;
- new_address->access = access;
- new_address->init = init;
- new_address->next_address = *current_address;
- *current_address = new_address;
-}
-
-
-/* create a new device tree optionally making it a child of the parent
- node */
-
-INLINE_DEVICE_TREE device_node *
-device_node_create(device_node *parent,
- char *name,
- device_type type,
- device_callbacks *callbacks,
- void *data)
+typedef enum {
+ node_any = 0,
+ node_device,
+ node_integer,
+ node_boolean,
+ node_string
+} node_type;
+
+
+struct _device_tree {
+ /* where i am */
+ device_tree *parent;
+ device_tree *children;
+ device_tree *sibling;
+ /* what i am */
+ node_type type;
+ const char *name;
+ /* the value */
+ const device *device;
+ int boolean;
+ const char *string;
+ signed_word integer;
+};
+
+
+STATIC_INLINE_DEVICE_TREE device_tree *
+new_device_tree(device_tree *parent,
+ const char *name,
+ node_type type)
{
- device_node *new_node;
- new_node = ZALLOC(device_node);
+ device_tree *new_node;
+ new_node = ZALLOC(device_tree);
new_node->parent = parent;
- new_node->name = name;
+ new_node->name = strdup(name);
new_node->type = type;
- new_node->callbacks = callbacks;
- new_node->data = data;
if (parent != NULL) {
- new_node->sibling = parent->children;
- parent->children = new_node;
+ device_tree **sibling = &parent->children;
+ while ((*sibling) != NULL)
+ sibling = &(*sibling)->sibling;
+ *sibling = new_node;
}
return new_node;
}
-/* Binary file:
+/* find/create a node in the device tree */
- The specified file is a binary, assume VEA is required, construct a
- fake device tree based on the addresses of the text / data segments
- requested by the binary */
+typedef enum {
+ device_tree_grow = 1,
+ device_tree_return_null = 2,
+ device_tree_abort = 3,
+} device_tree_action;
-
-/* Update the fake device tree so that memory is allocated for this
- section */
-STATIC_INLINE_DEVICE_TREE void
-update_memory_node_for_section(bfd *abfd,
- asection *the_section,
- PTR obj)
+STATIC_INLINE_DEVICE_TREE device_tree *
+device_tree_find_node(device_tree *root,
+ const char *path,
+ node_type type,
+ device_tree_action action)
{
- unsigned_word section_vma;
- unsigned_word section_size;
- device_access section_access;
- void *section_init;
- device_node *memory = (device_node*)obj;
-
- /* skip the section if no memory to allocate */
- if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
- return;
-
- /* check/ignore any sections of size zero */
- section_size = bfd_get_section_size_before_reloc(the_section);
- if (section_size == 0)
- return;
-
- /* find where it is to go */
- section_vma = bfd_get_section_vma(abfd, the_section);
-
- TRACE(trace_device_tree,
- ("name=%-7s, vma=0x%.8x, size=%6d, flags=%3x(%s%s%s%s )\n",
- bfd_get_section_name(abfd, the_section),
- section_vma, section_size,
- bfd_get_section_flags(abfd, the_section),
- bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
- bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
- bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
- bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
- bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
- ));
-
- if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
- section_init = zalloc(section_size);
- if (!bfd_get_section_contents(abfd,
- the_section,
- section_init, 0,
- section_size)) {
- bfd_perror("core:load_section()");
- error("load of data failed");
- return;
+ const char *chp;
+ int name_len;
+ device_tree *child;
+
+ /* strip off any leading `/', `../' or `./' */
+ while (1) {
+ if (strncmp(path, "/", strlen("/")) == 0) {
+ while (root != NULL && root->parent != NULL)
+ root = root->parent;
+ path += strlen("/");
+ }
+ else if (strncmp(path, "./", strlen("./")) == 0) {
+ root = root;
+ path += strlen("./");
+ }
+ else if (strncmp(path, "../", strlen("../")) == 0) {
+ if (root != NULL && root->parent != NULL)
+ root = root->parent;
+ path += strlen("../");
+ }
+ else {
+ break;
}
}
- else {
- section_init = NULL;
+
+ /* find the qualified (with @) and unqualified names in the path,
+ remembering to skip any "\/" */
+ chp = path;
+ do {
+ chp = strchr(chp+1, '/');
+ } while (chp != NULL && chp[-1] == '\\');
+ name_len = (chp == NULL
+ ? strlen(path)
+ : chp - path);
+
+ /* leaf? and growing? */
+ if (root != NULL) {
+ for (child = root->children;
+ child != NULL;
+ child = child->sibling) {
+ if (strncmp(path, child->name, name_len) == 0
+ && (strlen(child->name) == name_len
+ || (strchr(child->name, '@')
+ == child->name + name_len))) {
+ if (path[name_len] == '\0') {
+ if (action == device_tree_grow)
+ error("device_tree_find_node() node %s already present\n",
+ path);
+ if (type != node_any && child->type != type) {
+ if (action == device_tree_return_null)
+ return NULL;
+ else
+ error("device_tree_find_node() node %s does not match type %d\n",
+ path, type);
+ }
+ else
+ return child;
+ }
+ else
+ return device_tree_find_node(child,
+ path + name_len + 1,
+ type,
+ action);
+ }
+ }
+ }
+
+ /* search failed, take default action */
+ switch (action) {
+ case device_tree_grow:
+ if (path[name_len] != '\0')
+ error("device_tree_find_node() not a leaf %s\n", path);
+ return new_device_tree(root, path, type);
+ case device_tree_return_null:
+ return NULL;
+ default:
+ error("device_tree_find_node() invalid default action %d\n", action);
+ return NULL;
}
+}
- /* determine the devices access */
- if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
- section_access = (device_is_readable | device_is_executable);
- else if (bfd_get_section_flags(abfd, the_section) & SEC_READONLY)
- section_access = device_is_readable;
- else
- section_access = (device_is_readable | device_is_writeable);
-
- /* find our memory and add this section to its list of addresses */
- device_node_add_address(memory,
- section_vma,
- section_size,
- section_access,
- section_init);
+
+/* grow the device tree */
+
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_passthrough(device_tree *root,
+ const char *path)
+{
+ device_tree *new_node = device_tree_find_node(root,
+ path,
+ node_device,
+ device_tree_grow);
+ new_node->device = device_create_from(new_node->name,
+ NULL,
+ passthrough_device_callbacks(),
+ new_node->parent->device);
+ return new_node;
}
-/* construct the device tree from the executable */
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_device(device_tree *root,
+ const char *path,
+ const device *dev)
+{
+ device_tree *new_node = device_tree_find_node(root,
+ path,
+ node_device,
+ device_tree_grow);
+ new_node->device = dev;
+ return new_node;
+}
-STATIC_INLINE_DEVICE_TREE device_node *
-create_option_device_node(device_node *root,
- bfd *image)
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_integer(device_tree *root,
+ const char *path,
+ signed_word integer)
{
- int oea = (bfd_get_start_address(image) < OEA_START_ADDRESS);
- int elf = (image->xvec->flavour == bfd_target_elf_flavour);
- device_node *option_node;
-
- /* the option node and than its members */
- option_node = device_node_create(root, "options", options_device,
- NULL, NULL);
-
- /* which endian are we ? */
- device_node_create(option_node,
- "little-endian?",
- boolean_type_device,
- NULL,
- (void*)(image->xvec->byteorder_big_p ? 0 : -1));
-
- /* what is the initial entry point */
- device_node_create(option_node,
- "program-counter",
- integer_type_device,
- NULL,
- (void*)(bfd_get_start_address(image)));
-
- /* address of top of boot stack */
- TRACE(trace_tbd, ("create_optioin_device_node() - TBD - NT/OpenBoot?\n"));
- device_node_create(option_node,
- "stack-pointer",
- integer_type_device,
- NULL,
- (void *)((oea)
- ? clayton_memory_size /* OEA */
- : ((elf)
- ? 0xe0000000 /* elf */
- : 0x20000000 /* xcoff */)));
-
- /* execution environment */
- device_node_create(option_node,
- "vea?",
- boolean_type_device,
- NULL,
- (void *)((oea) ? 0 : -1));
-
- /* what type of binary */
- TRACE(trace_tbd, ("create_optioin_device_node() - TBD - NT/OpenBoot?\n"));
- device_node_create(option_node,
- "elf?",
- boolean_type_device,
- NULL,
- (void *)((elf) ? -1 : 0));
-
- /* must all memory transfers be naturally aligned? */
- device_node_create(option_node,
- "aligned?",
- boolean_type_device,
- NULL,
- (void*)((WITH_ALIGNMENT == NONSTRICT_ALIGNMENT
- || image->xvec->byteorder_big_p
- || !oea)
- ? 0
- : -1));
-
-
- return option_node;
+ device_tree *new_node = device_tree_find_node(root,
+ path,
+ node_integer,
+ device_tree_grow);
+ new_node->integer = integer;
+ return new_node;
}
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_string(device_tree *root,
+ const char *path,
+ const char *string)
+{
+ device_tree *new_node = device_tree_find_node(root,
+ path,
+ node_string,
+ device_tree_grow);
+ new_node->string = string;
+ return new_node;
+}
-/* clatyon is a simple machine that does not require interrupts or any
- thing else */
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_boolean(device_tree *root,
+ const char *path,
+ int boolean)
+{
+ device_tree *new_node = device_tree_find_node(root,
+ path,
+ node_boolean,
+ device_tree_grow);
+ new_node->boolean = boolean;
+ return new_node;
+}
-STATIC_INLINE_DEVICE_TREE device_node *
-create_clayton_device_tree(bfd *image)
+INLINE_DEVICE_TREE device_tree *
+device_tree_add_found_device(device_tree *root,
+ const char *path)
{
- device_node *root;
- device_node *io_node;
- device_node *data_node;
- device_node *memory_node;
-
- /* the root */
- root = ZALLOC(device_node);
-
- /* memory - clayton has 2mb of RAM at location 0 */
- memory_node = device_node_create(root,
- "memory",
- memory_device,
- NULL,
- NULL);
- device_node_add_address(memory_node, 0x0, clayton_memory_size,
- (device_is_readable
- | device_is_writeable
- | device_is_executable),
- NULL);
-
- /* io address space */
- io_node = device_node_create(root, "io", bus_device, NULL, NULL);
-
- /* and IO devices */
- find_device_descriptor("console")
- ->creator(io_node, "console@0x400000,0");
- find_device_descriptor("halt")
- ->creator(io_node, "halt@0x500000,0");
- find_device_descriptor("icu")
- ->creator(io_node, "icu@0x600000,0");
-
- /* data to load */
- data_node = device_node_create(root, "image", data_device, NULL, NULL);
- bfd_map_over_sections(image,
- update_memory_node_for_section,
- (PTR)data_node);
-
- /* options */
- create_option_device_node(root, image);
-
- return root;
+ device_tree *new_node = device_tree_add_device(root, path, NULL);
+ new_node->device = device_create(new_node->name,
+ new_node->parent->device);
+ return new_node;
}
-/* user mode executable build up a device tree that reflects this */
+/* look up the device tree */
-STATIC_INLINE_DEVICE_TREE device_node *
-create_vea_device_tree(bfd *image)
+INLINE_DEVICE_TREE const device *
+device_tree_find_device(device_tree *root,
+ const char *path)
{
- device_node *root;
- device_node *memory_node;
- device_node *option_node;
-
- /* the root */
- root = ZALLOC(device_node);
-
- /* memory */
- memory_node = device_node_create(root, "memory", memory_device,
- NULL, NULL);
- bfd_map_over_sections(image,
- update_memory_node_for_section,
- (PTR)memory_node);
- /* options - only endian so far */
- option_node = create_option_device_node(root, image);
-
- return root;
+ device_tree *node = device_tree_find_node(root,
+ path,
+ node_device,
+ device_tree_abort);
+ return node->device;
}
+INLINE_DEVICE_TREE signed_word
+device_tree_find_integer(device_tree *root,
+ const char *path)
+{
+ device_tree *node = device_tree_find_node(root,
+ path,
+ node_integer,
+ device_tree_abort);
+ return node->integer;
+}
-/* create a device tree from the specified file */
-INLINE_DEVICE_TREE device_node *
-device_tree_create(const char *file_name)
+INLINE_DEVICE_TREE const char *
+device_tree_find_string(device_tree *root,
+ const char *path)
{
- bfd *image;
- device_node *tree;
+ device_tree *node = device_tree_find_node(root,
+ path,
+ node_string,
+ device_tree_abort);
+ return node->string;
+}
- bfd_init(); /* could be redundant but ... */
+INLINE_DEVICE_TREE int
+device_tree_find_boolean(device_tree *root,
+ const char *path)
+{
+ device_tree *node = device_tree_find_node(root,
+ path,
+ node_boolean,
+ device_tree_abort);
+ return node->boolean;
+}
- /* open the file */
- image = bfd_openr(file_name, NULL);
- if (image == NULL) {
- bfd_perror("open failed:");
- error("nothing loaded\n");
- return NULL;
- }
- /* check it is valid */
- if (!bfd_check_format(image, bfd_object)) {
- printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
- printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
- bfd_close(image);
- image = NULL;
- }
+/* init all the devices */
- /* depending on what was found about the file, load it */
- if (image != NULL) {
- if (bfd_get_start_address(image) == 0) {
- TRACE(trace_device_tree, ("create_device_tree() - clayton image\n"));
- tree = create_clayton_device_tree(image);
- }
- else if (bfd_get_start_address(image) > 0) {
- TRACE(trace_device_tree, ("create_device_tree() - vea image\n"));
- tree = create_vea_device_tree(image);
- }
- bfd_close(image);
- }
- else {
- error("TBD - create_device_tree() text file defining device tree\n");
- tree = NULL;
- }
+STATIC_INLINE_DEVICE_TREE void
+device_tree_init_device(device_tree *root,
+ void *data)
+{
+ psim *system = (psim*)data;
+ if (root->type == node_device)
+ root->device->callback->init(root->device, system);
+}
- return tree;
+
+INLINE_DEVICE_TREE void
+device_tree_init(device_tree *root,
+ psim *system)
+{
+ device_tree_traverse(root, device_tree_init_device, NULL, system);
}
/* traverse a device tree applying prefix/postfix functions to it */
INLINE_DEVICE_TREE void
-device_tree_traverse(device_node *root,
+device_tree_traverse(device_tree *root,
device_tree_traverse_function *prefix,
device_tree_traverse_function *postfix,
void *data)
{
- device_node *child;
+ device_tree *child;
if (prefix != NULL)
prefix(root, data);
for (child = root->children; child != NULL; child = child->sibling) {
}
-/* query the device tree */
+/* dump out a device node and addresses */
-INLINE_DEVICE_TREE device_node *
-device_tree_find_node(device_node *root,
- const char *path)
+INLINE_DEVICE_TREE void
+device_tree_dump(device_tree *device,
+ void *ignore_data_argument)
{
- char *chp;
- int name_len;
- device_node *child;
+ printf_filtered("(device_tree@0x%x\n", device);
+ printf_filtered(" (parent 0x%x)\n", device->parent);
+ printf_filtered(" (children 0x%x)\n", device->children);
+ printf_filtered(" (sibling 0x%x)\n", device->sibling);
+ printf_filtered(" (type %d)\n", device->type);
+ printf_filtered(" (name %s)\n", device->name);
+ printf_filtered(" (device 0x%x)\n", device->device);
+ printf_filtered(" (boolean %d)\n", device->boolean);
+ printf_filtered(" (string %s)\n", device->string);
+ printf_filtered(" (integer %d)\n", device->integer);
+ printf_filtered(")\n");
+}
- /* strip off any leading `/', `../' or `./' */
- while (1) {
- if (strncmp(path, "/", strlen("/")) == 0) {
- while (root->parent != NULL)
- root = root->parent;
- path += strlen("/");
- }
- else if (strncmp(path, "./", strlen("./")) == 0) {
- root = root;
- path += strlen("./");
- }
- else if (strncmp(path, "../", strlen("../")) == 0) {
- if (root->parent != NULL)
- root = root->parent;
- path += strlen("../");
- }
- else {
- break;
- }
- }
- /* find the qualified (with @) and unqualified names in the path */
- chp = strchr(path, '/');
- name_len = (chp == NULL
- ? strlen(path)
- : chp - path);
+/* Parse a device name, various formats */
- /* search through children for a match */
- for (child = root->children;
- child != NULL;
- child = child->sibling) {
- if (strncmp(path, child->name, name_len) == 0
- && (strlen(child->name) == name_len
- || strchr(child->name, '@') == child->name + name_len)) {
- if (path[name_len] == '\0')
- return child;
- else
- return device_tree_find_node(child, path + name_len + 1);
- }
- }
- return NULL;
+#ifndef __NetBSD__
+#define strtouq strtoul
+#endif
+
+#define SCAN_INIT(START, END, COUNT, NAME) \
+ char *START = NULL; \
+ char *END = strchr(NAME, '@'); \
+ int COUNT = 0; \
+ if (END == NULL) \
+ return 0; \
+ START = END + 1
+
+#define SCAN_U(START, END, COUNT, U) \
+do { \
+ *U = strtouq(START, &END, 0); \
+ if (START == END) \
+ return COUNT; \
+ COUNT++; \
+ if (*END != ',') \
+ return COUNT; \
+ START = END + 1; \
+} while (0)
+
+#define SCAN_P(START, END, COUNT, P) \
+do { \
+ *P = (void*)(unsigned)strtouq(START, &END, 0); \
+ if (START == END) \
+ return COUNT; \
+ COUNT++; \
+ if (*END != ',') \
+ return COUNT; \
+ START = END + 1; \
+} while (0)
+
+#define SCAN_C(START, END, COUNT, C) \
+do { \
+ char *chp = C; \
+ END = START; \
+ while (*END != '\0' && *END != ',') { \
+ if (*END == '\\') \
+ END++; \
+ *chp = *END; \
+ chp += 1; \
+ END += 1; \
+ } \
+ *chp = '\0'; \
+ if (START == END) \
+ return COUNT; \
+ COUNT++; \
+ if (*END != ',') \
+ return COUNT; \
+ START = END + 1; \
+} while (0)
+
+INLINE_DEVICE_TREE int
+scand_uw(const char *name,
+ unsigned_word *uw1)
+{
+ SCAN_INIT(start, end, count, name);
+ SCAN_U(start, end, count, uw1);
+ return count;
}
-INLINE_DEVICE_TREE device_node *device_tree_find_next_node
-(device_node *root,
- const char *path,
- device_node *last);
+INLINE_DEVICE_TREE int
+scand_uw_u(const char *name,
+ unsigned_word *uw1,
+ unsigned *u2)
+{
+ SCAN_INIT(start, end, count, name);
+ SCAN_U(start, end, count, uw1);
+ SCAN_U(start, end, count, u2);
+ return count;
+}
-INLINE_DEVICE_TREE signed_word
-device_tree_find_int(device_node *root,
- const char *path)
+INLINE_DEVICE_TREE int
+scand_uw_u_u(const char *name,
+ unsigned_word *uw1,
+ unsigned *u2,
+ unsigned *u3)
{
- device_node *int_node = device_tree_find_node(root, path);
- if (int_node == NULL) {
- error("device_tree_find_int() - node %s does not exist\n", path);
- return 0;
- }
- else if (int_node->type != integer_type_device) {
- error("device_tree_find_int() - node %s is not an int\n", path);
- return 0;
- }
- else {
- return (signed_word)(int_node->data);
- }
+ SCAN_INIT(start, end, count, name);
+ SCAN_U(start, end, count, uw1);
+ SCAN_U(start, end, count, u2);
+ SCAN_U(start, end, count, u3);
+ return count;
}
+INLINE_DEVICE_TREE int
+scand_uw_uw_u(const char *name,
+ unsigned_word *uw1,
+ unsigned_word *uw2,
+ unsigned *u3)
+{
+ SCAN_INIT(start, end, count, name);
+ SCAN_U(start, end, count, uw1);
+ SCAN_U(start, end, count, uw2);
+ SCAN_U(start, end, count, u3);
+ return count;
+}
-INLINE_DEVICE_TREE const char *device_tree_find_string
-(device_node *root,
- const char *path);
+INLINE_DEVICE_TREE int
+scand_c(const char *name,
+ char *c1)
+{
+ SCAN_INIT(start, end, count, name);
+ SCAN_C(start, end, count, c1);
+ return count;
+}
INLINE_DEVICE_TREE int
-device_tree_find_boolean(device_node *root,
- const char *path)
+scand_c_uw_u(const char *name,
+ char *c1,
+ unsigned_word *uw2,
+ unsigned *u3)
{
- device_node *int_node = device_tree_find_node(root, path);
- if (int_node == NULL) {
- error("device_tree_find_boolean() - node %s does not exist\n", path);
- return 0;
- }
- else if (int_node->type != boolean_type_device) {
- error("device_tree_find_boolean() - node %s is not a boolean\n", path);
- return 0;
+ SCAN_INIT(start, end, count, name);
+ SCAN_C(start, end, count, c1);
+ SCAN_U(start, end, count, uw2);
+ SCAN_U(start, end, count, u3);
+ return count;
+}
+
+
+STATIC_INLINE_DEVICE_TREE void
+u_strcat(char *buf,
+ unsigned_word uw)
+{
+ if (MASKED64(uw, 32, 63) == uw
+ || WITH_HOST_WORD_BITSIZE == 64) {
+ char *end = strchr(buf, '\0');
+ sprintf(end, "0x%x", (unsigned)uw);
}
else {
- return (signed_word)(int_node->data);
+ char *end = strchr(buf, '\0');
+ sprintf(end, "0x%x%08x",
+ (unsigned)EXTRACTED64(uw, 0, 31),
+ (unsigned)EXTRACTED64(uw, 32, 63));
+ }
+}
+
+STATIC_INLINE_DEVICE_TREE void
+c_strcat(char *buf,
+ const char *c)
+{
+ char *end = strchr(buf, '\0');
+ while (*c) {
+ if (*c == '/' || *c == ',')
+ *end++ = '\\';
+ *end++ = *c++;
+ }
+ *end = '\0';
+}
+
+STATIC_INLINE_DEVICE_TREE int
+c_strlen(const char *c)
+{
+ int len = 0;
+ while (*c) {
+ if (*c == '/' || *c == ',')
+ len++;
+ len++;
+ c++;
}
+ return len;
}
+enum {
+ strlen_unsigned = 10,
+ strlen_unsigned_word = 18,
+};
-INLINE_DEVICE_TREE void *device_tree_find_bytes
-(device_node *root,
- const char *path);
+INLINE_DEVICE_TREE char *
+printd_uw_u(const char *name,
+ unsigned_word uw1,
+ unsigned u2)
+{
+ int sizeof_buf = (strlen(name)
+ + strlen("@")
+ + strlen_unsigned_word
+ + strlen(",")
+ + strlen_unsigned
+ + 1);
+ char *buf = (char*)zalloc(sizeof_buf);
+ strcpy(buf, name);
+ strcat(buf, "@");
+ u_strcat(buf, uw1);
+ strcat(buf, ",");
+ u_strcat(buf, u2);
+ ASSERT(strlen(buf) < sizeof_buf);
+ return buf;
+}
-/* dump out a device node and addresses */
+INLINE_DEVICE_TREE char *
+printd_uw_u_u(const char *name,
+ unsigned_word uw1,
+ unsigned u2,
+ unsigned u3)
+{
+ int sizeof_buf = (strlen(name)
+ + strlen("@")
+ + strlen_unsigned_word
+ + strlen(",")
+ + strlen_unsigned
+ + strlen(",")
+ + strlen_unsigned
+ + 1);
+ char *buf = (char*)zalloc(sizeof_buf);
+ strcpy(buf, name);
+ strcat(buf, "@");
+ u_strcat(buf, uw1);
+ strcat(buf, ",");
+ u_strcat(buf, u2);
+ strcat(buf, ",");
+ u_strcat(buf, u3);
+ ASSERT(strlen(buf) < sizeof_buf);
+ return buf;
+}
-INLINE_DEVICE_TREE void
-device_tree_dump(device_node *device,
- void *ignore_data_argument)
+INLINE_DEVICE_TREE char *
+printd_uw_u_u_c(const char *name,
+ unsigned_word uw1,
+ unsigned u2,
+ unsigned u3,
+ const char *c4)
{
- printf_filtered("(device_node@0x%x\n", device);
- printf_filtered(" (parent 0x%x)\n", device->parent);
- printf_filtered(" (children 0x%x)\n", device->children);
- printf_filtered(" (sibling 0x%x)\n", device->sibling);
- printf_filtered(" (name %s)\n", device->name ? device->name : "(null)");
- printf_filtered(" (type %d)\n", device->type);
- printf_filtered(" (handlers 0x%x)\n", device->callbacks);
- printf_filtered(" (addresses %d)\n", device->addresses);
- printf_filtered(" (data %d)\n", device->data);
- printf_filtered(")\n");
+ int sizeof_buf = (strlen(name)
+ + strlen("@")
+ + strlen_unsigned_word
+ + strlen(",")
+ + strlen_unsigned
+ + strlen(",")
+ + strlen_unsigned
+ + strlen(",")
+ + c_strlen(c4)
+ + 1);
+ char *buf = (char*)zalloc(sizeof_buf);
+ strcpy(buf, name);
+ strcat(buf, "@");
+ u_strcat(buf, uw1);
+ strcat(buf, ",");
+ u_strcat(buf, u2);
+ strcat(buf, ",");
+ u_strcat(buf, u3);
+ strcat(buf, ",");
+ c_strcat(buf, c4);
+ ASSERT(strlen(buf) < sizeof_buf);
+ return buf;
+}
+
+INLINE_DEVICE_TREE char *
+printd_c(const char *name,
+ const char *c1)
+{
+ int sizeof_buf = (strlen(name)
+ + strlen("@")
+ + c_strlen(c1)
+ + 1);
+ char *buf = (char*)zalloc(sizeof_buf);
+ strcpy(buf, name);
+ strcat(buf, "@");
+ c_strcat(buf, c1);
+ ASSERT(strlen(buf) < sizeof_buf);
+ return buf;
+}
+
+INLINE_DEVICE_TREE char *
+printd_c_uw(const char *name,
+ const char *c1,
+ unsigned_word uw2)
+{
+ int sizeof_buf = (strlen(name)
+ + strlen("@")
+ + c_strlen(c1)
+ + strlen(",")
+ + strlen_unsigned_word
+ + 1);
+ char *buf = (char*)zalloc(sizeof_buf);
+ strcpy(buf, name);
+ strcat(buf, "@");
+ c_strcat(buf, c1);
+ strcat(buf, ",");
+ u_strcat(buf, uw2);
+ ASSERT(strlen(buf) < sizeof_buf);
+ return buf;
}
#endif /* _DEVICE_TREE_C_ */
#endif
-/* forward declaration of types */
-
-typedef struct _device_node device_node;
-typedef struct _device_address device_address;
-typedef struct _device_callbacks device_callbacks;
-
-
-/* Device callbacks: */
-
-
-/* Memory operations: transfer data to/from a processor.
-
- 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);
+#include "devices.h"
+typedef struct _device_tree device_tree;
-/* traverse the tree eiter pre or post fix */
-typedef void (device_tree_traverse_function)
- (device_node *device,
- void *data);
+/* extend the device tree, each function returns the address of the
+ new node */
-INLINE_DEVICE_TREE void device_tree_traverse
-(device_node *root,
- device_tree_traverse_function *prefix,
- device_tree_traverse_function *postfix,
- void *data);
+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);
-/* query the device tree */
+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_node *device_tree_find_node
-(device_node *root,
+INLINE_DEVICE_TREE device_tree *device_tree_add_found_device
+(device_tree *root,
const char *path);
-INLINE_DEVICE_TREE device_node *device_tree_find_next_node
-(device_node *root,
- const char *path,
- device_node *last);
+/* 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_int
-(device_node *root,
+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_node *root,
+(device_tree *root,
const char *path);
INLINE_DEVICE_TREE int device_tree_find_boolean
-(device_node *root,
+(device_tree *root,
const char *path);
-INLINE_DEVICE_TREE void *device_tree_find_bytes
-(device_node *root,
- const char *path);
-/* add to the device tree */
+/* initialize the entire tree */
+
+INLINE_DEVICE_TREE void device_tree_init
+(device_tree *root,
+ psim *system);
+
+
+/* traverse the tree eiter pre or post fix */
-INLINE_DEVICE_TREE device_node *device_node_create
-(device_node *parent,
- char *name,
- device_type type,
- device_callbacks *callbacks,
+typedef void (device_tree_traverse_function)
+ (device_tree *device,
+ void *data);
+
+INLINE_DEVICE_TREE void device_tree_traverse
+(device_tree *root,
+ device_tree_traverse_function *prefix,
+ device_tree_traverse_function *postfix,
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_ */
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
#include "basics.h"
-#include "device_tree.h"
#include "devices.h"
#include "events.h"
-#include "cpu.h" /* drats */
+#include "cpu.h"
+
+#include "bfd.h"
/* Helper functions */
+/* Generic device init: Attaches the device of size <nr_bytes> (taken
+ from <name>@<int>,<nr_bytes>) to its parent at address zero and
+ with read/write access. */
+
STATIC_INLINE_DEVICES void
-parse_device_address(char *name,
- unsigned *base,
- unsigned *flags)
+generic_init_callback(const device *me,
+ psim *system)
{
- /* extract the two arguments */
- name = strchr(name, '@');
- if (name == NULL)
- error("missing address for device %s\n", name);
- name++;
- *base = strtol(name, &name, 0);
- *flags = (*name == ','
- ? strtol(name+1, &name, 0)
- : 0);
+ unsigned_word addr;
+ unsigned nr_bytes;
+ if (scand_uw_u(me->name, &addr, &nr_bytes) != 2)
+ error("generic_init_callback() invalid nr_bytes in %s\n", me->name);
+ me->parent->callback->attach_address(me->parent,
+ me->name,
+ attach_callback,
+ 0 /*address_space*/,
+ addr,
+ nr_bytes,
+ access_read_write,
+ me);
}
-/* Simple console device:
+\f
+/* inimplemented versions of each function */
- Implements a simple text output device that is attached to stdout
- of the process running the simulation. The devices has four
- word registers:
+INLINE_DEVICES void
+unimp_device_init(const device *me,
+ psim *system)
+{
+ error("device_init_callback for %s not implemented\n", me->name);
+}
- 0: read
- 4: read-status
- 8: write
- c: write-status
+INLINE_DEVICES void
+unimp_device_attach_address(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*/
+{
+ error("device_attach_address_callback for %s not implemented\n", me->name);
+}
- Where a nonzero status register indicates that the device is ready
- (input fifo contains a character or output fifo has space).
+INLINE_DEVICES void
+unimp_device_detach_address(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*/
+{
+ error("device_detach_address_callback for %s not implemented\n", me->name);
+}
- Illustrates: Mapping read/write to device operations onto actual
- registers.
+INLINE_DEVICES unsigned
+unimp_device_io_read_buffer(const device *me,
+ void *dest,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("device_io_read_buffer_callback for %s not implemented\n", me->name);
+ return 0;
+}
- */
+INLINE_DEVICES unsigned
+unimp_device_io_write_buffer(const device *me,
+ const void *source,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("device_io_write_buffer_callback for %s not implemented\n", me->name);
+ return 0;
+}
+
+INLINE_DEVICES unsigned
+unimp_device_dma_read_buffer(const device *me,
+ void *target,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes)
+{
+ error("device_dma_read_buffer_callback for %s not implemented\n", me->name);
+ return 0;
+}
+
+INLINE_DEVICES unsigned
+unimp_device_dma_write_buffer(const device *me,
+ const void *source,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section)
+{
+ error("device_dma_write_buffer_callback for %s not implemented\n", me->name);
+ return 0;
+}
+
+INLINE_DEVICES void
+unimp_device_attach_interrupt(const device *me,
+ const device *who,
+ int interrupt_line,
+ const char *name)
+{
+ error("device_attach_interrupt_callback for %s not implemented\n", me->name);
+}
+
+INLINE_DEVICES void
+unimp_device_detach_interrupt(const device *me,
+ const device *who,
+ int interrupt_line,
+ const char *name)
+{
+ error("device_detach_interrupt_callback for %s not implemented\n", me->name);
+}
+
+INLINE_DEVICES void
+unimp_device_interrupt(const device *me,
+ const device *who,
+ int interrupt_line,
+ int interrupt_status,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("device_interrupt_callback for %s not implemented\n", me->name);
+}
+
+INLINE_DEVICES void
+unimp_device_interrupt_ack(const device *me,
+ int interrupt_line,
+ int interrupt_status)
+{
+ error("device_interrupt_ack_callback for %s not implemented\n", me->name);
+}
+
+INLINE_DEVICES void
+unimp_device_ioctl(const device *me,
+ psim *system,
+ cpu *processor,
+ unsigned_word cia,
+ ...)
+{
+ error("device_ioctl_callback for %s not implemented\n", me->name);
+}
+
+
+\f
+/* ignore/passthrough versions of each function */
+
+INLINE_DEVICES void
+ignore_device_init(const device *me,
+ psim *system)
+{
+ /*null*/
+}
+
+INLINE_DEVICES void
+pass_device_attach_address(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*/
+{
+ me->parent->callback->attach_address(me->parent, name, type,
+ address_space, addr, nr_bytes,
+ access,
+ who);
+}
+
+INLINE_DEVICES void
+pass_device_detach_address(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*/
+{
+ me->parent->callback->detach_address(me->parent, name, type,
+ address_space, addr, nr_bytes, access,
+ who);
+}
+
+INLINE_DEVICES unsigned
+pass_device_dma_read_buffer(const device *me,
+ void *target,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes)
+{
+ return me->parent->callback->dma_read_buffer(me->parent, target,
+ address_space, addr, nr_bytes);
+}
+
+INLINE_DEVICES unsigned
+pass_device_dma_write_buffer(const device *me,
+ const void *source,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ int violate_read_only_section)
+{
+ return me->parent->callback->dma_write_buffer(me->parent, source,
+ address_space, addr,
+ nr_bytes,
+ violate_read_only_section);
+}
+
+INLINE_DEVICES void
+pass_device_attach_interrupt(const device *me,
+ const device *who,
+ int interrupt_line,
+ const char *name)
+{
+ me->parent->callback->attach_interrupt(me->parent, who,
+ interrupt_line, name);
+}
+
+INLINE_DEVICES void
+pass_device_detach_interrupt(const device *me,
+ const device *who,
+ int interrupt_line,
+ const char *name)
+{
+ me->parent->callback->detach_interrupt(me->parent, who,
+ interrupt_line, name);
+}
+
+
+INLINE_DEVICES void
+pass_device_interrupt(const device *me,
+ const device *who,
+ int interrupt_line,
+ int interrupt_status,
+ cpu *processor,
+ unsigned_word cia)
+{
+ me->parent->callback->interrupt(me->parent, who,
+ interrupt_line, interrupt_status,
+ processor, cia);
+}
+
+
+\f
+/* Simple console device: console@)x<address>,16
+
+ Input characters are taken from the keyboard, output characters
+ sent to the terminal. Echoing of characters is not disabled.
+
+ The device has four registers:
+
+ 0x0: read
+ 0x4: read-status
+ 0x8: write
+ 0xC: write-status
+
+ Where a nonzero status register indicates that the device is ready
+ (input fifo contains a character or output fifo has space). */
typedef struct _console_buffer {
char buffer;
} console_buffer;
typedef struct _console_device {
- unsigned_word my_base_address;
- int interrupt_delay;
console_buffer input;
console_buffer output;
} console_device;
} console_offsets;
-STATIC_INLINE_DEVICES unsigned64
-console_read_callback(device_node *device,
- unsigned_word base,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
+STATIC_INLINE_DEVICES unsigned
+console_io_read_buffer_callback(const device *me,
+ void *dest,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
{
- console_device *con = (console_device*)device->data;
+ console_device *console = (console_device*)me->data;
+ unsigned_1 val;
TRACE(trace_console_device,
- ("device=0x%x, base=0x%x, nr_bytes=%d\n",
- device, base, nr_bytes));
+ ("device=0x%x, addr=0x%x, nr_bytes=%d\n",
+ me, addr, nr_bytes));
- /* handle the request */
+ /* determine what was read */
- switch (base & console_offset_mask) {
+ switch (addr) {
case console_read_buffer:
- return con->input.buffer;
+ val = console->input.buffer;
+ break;
case console_read_status:
{ /* check for input */
flags = fcntl(0, F_GETFL, 0);
if (flags == -1) {
perror("console");
- return 0;
+ val = 0;
+ break;
}
/* temp, disable blocking IO */
status = fcntl(0, F_SETFL, flags | O_NDELAY);
if (status == -1) {
perror("console");
- return 0;
+ val = 0;
+ break;
}
/* try for input */
- status = read(0, &con->input.buffer, 1);
+ status = read(0, &console->input.buffer, 1);
if (status == 1) {
- con->input.status = 1;
+ console->input.status = 1;
}
else {
- con->input.status = 0;
+ console->input.status = 0;
}
/* return to regular vewing */
fcntl(0, F_SETFL, flags);
}
- return con->input.status;
+ val = console->input.status;
+ break;
case console_write_buffer:
- return con->output.buffer;
+ val = console->output.buffer;
+ break;
case console_write_status:
- return con->output.status;
+ val = console->output.status;
+ break;
default:
error("console_read_callback() internal error\n");
- return 0;
+ val = 0;
+ break;
}
+ bzero(dest, nr_bytes);
+ *(unsigned_1*)dest = val;
+ return nr_bytes;
}
-STATIC_INLINE_DEVICES void
-console_write_callback(device_node *device,
- unsigned_word base,
- unsigned nr_bytes,
- unsigned64 val,
- cpu *processor,
- unsigned_word cia)
+STATIC_INLINE_DEVICES unsigned
+console_io_write_buffer_callback(const device *me,
+ const void *source,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
{
- console_device *con = (console_device*)device->data;
+ console_device *console = (console_device*)me->data;
+ unsigned_1 val = *(unsigned8*)source;
TRACE(trace_console_device,
- ("device=0x%x, base=0x%x, nr_bytes=%d, val=0x%x\n",
- device, base, nr_bytes, val));
+ ("device=0x%x, addr=0x%x, nr_bytes=%d, val=%d\n",
+ me, addr, nr_bytes, val));
- /* check for bus error */
- if (base & 0x3) {
- error("%s - misaligned base address, base=0x%x, nr_bytes=%d\n",
- "console_write_callback", base, nr_bytes);
- }
-
- switch (base & console_offset_mask) {
- case console_read_buffer: con->input.buffer = val; break;
- case console_read_status: con->input.status = val; break;
+ switch (addr) {
+ case console_read_buffer:
+ console->input.buffer = val;
+ break;
+ case console_read_status:
+ console->input.status = val;
+ break;
case console_write_buffer:
TRACE(trace_console_device,
("<%c:%d>", val, val));
- printf_filtered("%c", val);
- con->output.buffer = val;
- con->output.status = 1;
+ printf_filtered("%c",val) ;
+ console->output.buffer = val;
+ console->output.status = 1;
break;
case console_write_status:
- con->output.status = val;
+ console->output.status = val;
break;
+ default:
+ error("console_write_callback() internal error\n");
}
-
+
+ return nr_bytes;
}
-static device_callbacks console_callbacks = {
- console_read_callback,
- console_write_callback,
+
+static device_callbacks const console_callbacks = {
+ generic_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ console_io_read_buffer_callback,
+ console_io_write_buffer_callback,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
};
-STATIC_INLINE_DEVICES device_node *
-console_create(device_node *parent,
- char *name)
-{
- device_node *device;
- unsigned address_base;
- unsigned address_flags;
+STATIC_INLINE_DEVICES const device *
+console_create(const char *name,
+ const device *parent)
+{
/* create the descriptor */
console_device *console = ZALLOC(console_device);
- /* extract the two arguments */
- parse_device_address(name, &address_base, &address_flags);
-
/* fill in the details */
- console->my_base_address = address_base;
- console->interrupt_delay = address_flags;
console->output.status = 1;
console->output.buffer = '\0';
console->input.status = 0;
console->input.buffer = '\0';
/* insert into the device tree along with its address info */
- device = device_node_create(parent, name, sequential_device,
- &console_callbacks, console);
- device_node_add_address(device,
- address_base,
- console_size,
- device_is_read_write_exec,
- NULL);
-
- return device;
+ return device_create_from(name,
+ console, /* data */
+ &console_callbacks,
+ parent);
}
-static device_descriptor console_descriptor = {
- "console",
- console_create,
-};
-
-/* ICU device:
+\f
+/* ICU device: icu@0x<address>,4
Single 4 byte register. Read returns processor number. Write
interrupts specified processor.
device doesn't pass interrupt events to its parent. Instead it
passes them back to its self. */
-STATIC_INLINE_DEVICES unsigned64
-icu_read_callback(device_node *device,
- unsigned_word base,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
+STATIC_INLINE_DEVICES unsigned
+icu_io_read_buffer_callback(const device *me,
+ void *dest,
+ int address_space,
+ unsigned_word base,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
{
+ unsigned_1 val;
TRACE(trace_icu_device,
("device=0x%x, base=0x%x, nr_bytes=%d\n",
- device, base, nr_bytes));
- return cpu_nr(processor);
+ me, base, nr_bytes));
+ val = cpu_nr(processor);
+ bzero(dest, nr_bytes);
+ *(unsigned_1*)dest = val;
+ return nr_bytes;
}
-STATIC_INLINE_DEVICES void
-icu_write_callback(device_node *device,
- unsigned_word base,
- unsigned nr_bytes,
- unsigned64 val,
- cpu *processor,
- unsigned_word cia)
+
+STATIC_INLINE_DEVICES unsigned
+icu_io_write_buffer_callback(const device *me,
+ const void *source,
+ int address_space,
+ unsigned_word base,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
{
psim *system = cpu_system(processor);
- device_node *parent = device; /* NB: normally would be device->parent */
+ unsigned_1 val = H2T_1(*(unsigned_1*)source);
TRACE(trace_icu_device,
("device=0x%x, base=0x%x, nr_bytes=%d, val=0x%x\n",
- device, base, nr_bytes, val));
+ me, base, nr_bytes, val));
/* tell the parent device that the interrupt lines have changed.
For this fake ICU. The interrupt lines just indicate the cpu to
interrupt next */
- parent->callbacks->interrupt_callback(parent, val, device, processor, cia);
+ me->parent->callback->interrupt(me->parent, me,
+ val, val,
+ processor, cia);
+ return nr_bytes;
}
+
+static device_callbacks const icu_callbacks = {
+ generic_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ icu_io_read_buffer_callback,
+ icu_io_write_buffer_callback,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* HALT device: halt@0x<address>,4
+
+ With real hardware, the processor operation is normally terminated
+ through a reset. This device illustrates how a reset device could
+ be attached to an address */
+
+
+STATIC_INLINE_DEVICES unsigned
+halt_io_read_buffer_callback(const device *me,
+ void *dest,
+ int address_space,
+ unsigned_word base,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ cpu_halt(processor, cia, was_exited, 0);
+ return 0;
+}
+
+
+STATIC_INLINE_DEVICES unsigned
+halt_io_write_buffer_callback(const device *me,
+ const void *source,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ cpu_halt(processor, cia, was_exited, 0);
+ return 0;
+}
+
+
+static device_callbacks const halt_callbacks = {
+ generic_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ halt_io_read_buffer_callback,
+ halt_io_write_buffer_callback,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* Register init device: register@<name>,0x<value>[,<processor>]
+
+ This strange device is used to initialize the processors registers
+ as part of the initialization. */
+
+STATIC_INLINE_DEVICES void
+register_init_callback(const device *me,
+ psim *system)
+{
+ char name[100];
+ unsigned_word value;
+ unsigned which_cpu;
+ int status;
+ status = scand_c_uw_u(me->name, name, &value, &which_cpu);
+ switch (status) {
+ case 2: /* register@<name>,<value> */
+ psim_write_register(system, -1, &value, name, cooked_transfer);
+ break;
+ case 3: /* register@<name>,<value>,<processor> */
+ psim_write_register(system, which_cpu, &value, name, cooked_transfer);
+ break;
+ default:
+ error("register_init_callback() invalid register init %s\n", me->name);
+ break;
+ }
+}
+
+
+static device_callbacks const register_callbacks = {
+ register_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* VEA VM device: vm@0x<stack-base>,<nr_bytes>
+
+ A VEA mode device. This sets its self up as the default memory
+ device capturing all accesses (reads/writes) to currently unmapped
+ addresses. If the unmaped access falls within unallocated stack or
+ heap address ranges then memory is allocated and the access is
+ allowed to continue.
+
+ During init phase, this device expects to receive `attach' requests
+ from its children for the text/data/bss memory areas. Typically,
+ this would be done by the binary device.
+
+ STACK: The location of the stack in memory is specified as part of
+ the devices name. Unmaped accesses that fall within the stack
+ space result in the allocated stack being grown downwards so that
+ it includes the page of the culprit access.
+
+ HEAP: During initialization, the vm device monitors all `attach'
+ operations from its children using this to determine the initial
+ location of the heap. The heap is then extended by system calls
+ that frob the heap upper bound variable (see system.c). */
+
+
+typedef struct _vm_device {
+ /* area of memory valid for stack addresses */
+ unsigned_word stack_base; /* min possible stack value */
+ unsigned_word stack_bound;
+ unsigned_word stack_lower_limit;
+ /* area of memory valid for heap addresses */
+ unsigned_word heap_base;
+ unsigned_word heap_bound;
+ unsigned_word heap_upper_limit;
+} vm_device;
+
+
STATIC_INLINE_DEVICES void
-icu_do_interrupt(event_queue *queue,
- void *data)
+vm_init_callback(const device *me,
+ psim *system)
+{
+ vm_device *vm = (vm_device*)me->data;
+
+ /* revert the stack/heap variables to their defaults */
+ vm->stack_lower_limit = vm->stack_bound;
+ vm->heap_base = 0;
+ vm->heap_bound = 0;
+ vm->heap_upper_limit = 0;
+
+ /* establish this device as the default memory handler */
+ me->parent->callback->attach_address(me->parent,
+ me->name,
+ attach_default,
+ 0 /*address space - ignore*/,
+ 0 /*addr - ignore*/,
+ 0 /*nr_bytes - ignore*/,
+ access_read_write /*access*/,
+ me);
+}
+
+
+STATIC_INLINE_DEVICES void
+vm_attach_address(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*/
+{
+ vm_device *vm = (vm_device*)me->data;
+ /* update end of bss if necessary */
+ if (vm->heap_base < addr + nr_bytes) {
+ vm->heap_base = addr + nr_bytes;
+ vm->heap_bound = addr + nr_bytes;
+ vm->heap_upper_limit = addr + nr_bytes;
+ }
+ me->parent->callback->attach_address(me->parent,
+ "vm@0x0,0", /* stop remap */
+ attach_raw_memory,
+ 0 /*address space*/,
+ addr,
+ nr_bytes,
+ access,
+ me);
+}
+
+
+STATIC_INLINE_DEVICES unsigned
+add_vm_space(const device *me,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ vm_device *vm = (vm_device*)me->data;
+ unsigned_word block_addr;
+ unsigned block_nr_bytes;
+
+ /* an address in the stack area, allocate just down to the addressed
+ page */
+ if (addr >= vm->stack_base && addr < vm->stack_lower_limit) {
+ block_addr = FLOOR_PAGE(addr);
+ block_nr_bytes = vm->stack_lower_limit - block_addr;
+ vm->stack_lower_limit = block_addr;
+ }
+ /* an address in the heap area, allocate all of the required heap */
+ else if (addr >= vm->heap_upper_limit && addr < vm->heap_bound) {
+ block_addr = vm->heap_upper_limit;
+ block_nr_bytes = vm->heap_bound - vm->heap_upper_limit;
+ vm->heap_upper_limit = vm->heap_bound;
+ }
+ /* oops - an invalid address - abort the cpu */
+ else if (processor != NULL) {
+ cpu_halt(processor, cia, was_signalled, SIGSEGV);
+ return 0;
+ }
+ /* 2*oops - an invalid address and no processor */
+ else {
+ return 0;
+ }
+
+ /* got the parameters, allocate the space */
+ me->parent->callback->attach_address(me->parent,
+ "vm@0x0,0", /* stop remap */
+ attach_raw_memory,
+ 0 /*address space*/,
+ block_addr,
+ block_nr_bytes,
+ access_read_write,
+ me);
+ return block_nr_bytes;
+}
+
+
+STATIC_INLINE_DEVICES unsigned
+vm_io_read_buffer_callback(const device *me,
+ void *dest,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
+ bzero(dest, nr_bytes); /* always initialized to zero */
+ return nr_bytes;
+ }
+ else
+ return 0;
+}
+
+
+STATIC_INLINE_DEVICES unsigned
+vm_io_write_buffer_callback(const device *me,
+ const void *source,
+ int address_space,
+ unsigned_word addr,
+ unsigned nr_bytes,
+ cpu *processor,
+ unsigned_word cia)
+{
+ if (add_vm_space(me, addr, nr_bytes, processor, cia) >= nr_bytes) {
+ return me->parent->callback->dma_write_buffer(me->parent, source,
+ address_space, addr,
+ nr_bytes,
+ 0/*violate_read_only*/);
+ }
+ else
+ return 0;
+}
+
+
+STATIC_INLINE_DEVICES void
+vm_ioctl_callback(const device *me,
+ psim *system,
+ cpu *processor,
+ unsigned_word cia,
+ ...)
+{
+ /* While the caller is notified that the heap has grown by the
+ requested amount, the heap is infact extended out to a page
+ boundary. */
+ vm_device *vm = (vm_device*)me->data;
+ unsigned_word new_break = ALIGN_8(cpu_registers(processor)->gpr[3]);
+ unsigned_word old_break = vm->heap_bound;
+ signed_word delta = new_break - old_break;
+ if (delta > 0)
+ vm->heap_bound = ALIGN_PAGE(new_break);
+ cpu_registers(processor)->gpr[0] = 0;
+ cpu_registers(processor)->gpr[3] = new_break;
+}
+
+
+static device_callbacks const vm_callbacks = {
+ vm_init_callback,
+ vm_attach_address,
+ pass_device_detach_address,
+ vm_io_read_buffer_callback,
+ vm_io_write_buffer_callback,
+ unimp_device_dma_read_buffer,
+ pass_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ vm_ioctl_callback,
+};
+
+
+STATIC_INLINE_DEVICES const device *
+vea_vm_create(const char *name,
+ const device *parent)
+{
+ vm_device *vm = ZALLOC(vm_device);
+ unsigned_word addr;
+ unsigned nr_bytes;
+
+ /* extract out the stack parameters */
+ if (scand_uw_u(name, &addr, &nr_bytes) != 2)
+ error("vm_device_create() invalid vm device %s\n", name);
+ vm->stack_base = addr;
+ vm->stack_bound = addr + nr_bytes;
+
+ /* insert in the tree including the buffer */
+ return device_create_from(name,
+ vm, /* data */
+ &vm_callbacks,
+ parent);
+}
+
+
+\f
+/* Memory init device: memory@0x<addr>,<size>,<access>
+
+ This strange device is used create sections of memory */
+
+STATIC_INLINE_DEVICES void
+memory_init_callback(const device *me,
+ psim *system)
+{
+ unsigned_word addr;
+ unsigned nr_bytes;
+ unsigned access;
+
+ if (scand_uw_u_u(me->name, &addr, &nr_bytes, &access) != 3)
+ error("memory_init_callback() invalid memory device %s\n", me->name);
+
+ me->parent->callback->attach_address(me->parent,
+ me->name,
+ attach_raw_memory,
+ 0 /*address space*/,
+ addr,
+ nr_bytes,
+ (access_type)access,
+ me);
+}
+
+
+static device_callbacks const memory_callbacks = {
+ memory_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+STATIC_INLINE_DEVICES const device *
+memory_create(const char *name,
+ const device *parent)
+{
+ void *buffer;
+ unsigned_word addr;
+ unsigned nr_bytes;
+ if (scand_uw_u(name, &addr, &nr_bytes) != 2)
+ error("memory_create() invalid memory device %s\n");
+
+ /* insert in the tree including the buffer */
+ return device_create_from(name,
+ buffer, /* data */
+ &memory_callbacks,
+ parent);
+}
+
+
+\f
+/* IOBUS device: iobus@<address>
+
+ Simple bus on which some IO devices live */
+
+STATIC_INLINE_DEVICES void
+iobus_attach_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*/
+{
+ unsigned_word iobus_addr;
+ /* sanity check */
+ if (type == attach_default)
+ error("iobus_attach_address_callback() no default for %s/%s\n",
+ me->name, name);
+ if (address_space != 0)
+ error("iobus_attach_address_callback() no address_space for %s/%s\n",
+ me->name, name);
+ /* get the bus address */
+ if (scand_uw(me->name, &iobus_addr) != 1)
+ error("iobus_attach_address_callback() invalid address for %s\n",
+ me->name);
+ me->parent->callback->attach_address(me->parent,
+ me->name,
+ type,
+ 0 /*address_space*/,
+ iobus_addr + addr,
+ nr_bytes,
+ access,
+ who);
+}
+
+
+STATIC_INLINE_DEVICES void
+iobus_do_interrupt(event_queue *queue,
+ void *data)
{
cpu *target = (cpu*)data;
/* try to interrupt the processor. If the attempt fails, try again
on the next tick */
if (!external_interrupt(target))
- event_queue_schedule(queue, 1, icu_do_interrupt, target);
+ event_queue_schedule(queue, 1, iobus_do_interrupt, target);
}
+
STATIC_INLINE_DEVICES void
-icu_interrupt_callback(device_node *me,
- int interrupt_status,
- device_node *device,
- cpu *processor,
- unsigned_word cia)
+iobus_interrupt_callback(const device *me,
+ const device *who,
+ int interrupt_line,
+ int interrupt_status,
+ cpu *processor,
+ unsigned_word cia)
{
/* the interrupt controler can't interrupt a cpu at any time.
Rather it must synchronize with the system clock before
cpu *target = psim_cpu(system, interrupt_status);
if (target != NULL) {
event_queue *events = cpu_event_queue(target);
- event_queue_schedule(events, 1, icu_do_interrupt, target);
+ event_queue_schedule(events, 1, iobus_do_interrupt, target);
}
}
-static device_callbacks icu_callbacks = {
- icu_read_callback,
- icu_write_callback,
- icu_interrupt_callback,
+
+static device_callbacks const iobus_callbacks = {
+ ignore_device_init,
+ iobus_attach_address_callback,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ iobus_interrupt_callback,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
};
-STATIC_INLINE_DEVICES device_node *
-icu_create(device_node *parent,
- char *name)
+
+\f
+/* FILE device: file@0x<address>,<file-name>
+ (later - file@0x<address>,<size>,<file-offset>,<file-name>)
+
+ Specifies a file to read directly into memory starting at <address> */
+
+
+STATIC_INLINE_DEVICES void
+file_init_callback(const device *me,
+ psim *system)
{
- device_node *device;
- unsigned address_base;
- unsigned address_flags;
+ unsigned_word addr;
+ char *file_name;
+ char buf;
+ FILE *image;
+
+ if ((file_name = strchr(me->name, ',')) == NULL
+ || scand_uw(me->name, &addr) != 1)
+ error("file_init_callback() invalid file device %s\n", me->name);
+
+ /* open the file to load */
+ file_name++; /* skip the `,' */
+ image = fopen(file_name, "r");
+ if (image == NULL)
+ error("file_init_callback() file open failed for %s\n", me->name);
+
+ /* read it in slowly */
+ while (fread(&buf, 1, 1, image) > 0) {
+ me->parent->callback->dma_write_buffer(me->parent,
+ &buf,
+ 0 /*address-space*/,
+ addr,
+ 1 /*nr-bytes*/,
+ 1 /*violate ro*/);
+ addr++;
+ }
- /* extract the two arguments */
- parse_device_address(name, &address_base, &address_flags);
+ /* close down again */
+ fclose(image);
+}
- /* insert into the device tree along with its address info */
- device = device_node_create(parent, name, sequential_device,
- &icu_callbacks, 0);
- device_node_add_address(device,
- address_base,
- 4,
- device_is_read_write_exec,
- NULL);
- return device;
+static device_callbacks const file_callbacks = {
+ file_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+
+
+\f
+/* HTAB: htab@0x<address>,<nr_bytes>
+ PTE: pte@0x<effective-address>,0x<real-address>,<nr_bytes>
+
+ HTAB defines the location (in physical memory) of a HASH table.
+ PTE (as a child of HTAB) defines a mapping that is to be entered
+ into that table.
+
+ NB: All the work in this device is done during init by the PTE.
+ The pte, looks up its parent to determine the address of the HTAB
+ and then uses DMA calls to establish the required mapping. */
+
+
+STATIC_INLINE_DEVICES void
+htab_init_callback(const device *me,
+ psim *system)
+{
+ /* only the pte does work */
+ if (strncmp(me->name, "pte@", strlen("pte@")) == 0) {
+ unsigned_word htab_ra;
+ unsigned htab_nr_bytes;
+ unsigned_word pte_ea;
+ unsigned_word pte_ra;
+ unsigned pte_nr_bytes;
+ /* determine the location/size of the hash table */
+ if (scand_uw_u(me->parent->name, &htab_ra, &htab_nr_bytes) != 2)
+ error("htab_init_callback() htab entry %s invalid\n",
+ me->parent->name);
+ /* determine the location/size of the mapping */
+ if (scand_uw_uw_u(me->name, &pte_ea, &pte_ra, &pte_nr_bytes) != 3)
+ error("htab_init_callback() pte entry %s invalid\n", me->name);
+ error("Map ea=0x%x, ra=0x%x, nr_bytes=%d using htab=0x%x, nr_bytes=%d\n",
+ pte_ea, pte_ra, pte_nr_bytes, htab_ra, htab_nr_bytes);
+ }
}
-static device_descriptor icu_descriptor = {
- "icu",
- icu_create,
+
+static device_callbacks const htab_callbacks = {
+ htab_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
};
+\f
+/* Simulator device: sim@0x<address>,<nr_bytes>
+
+ Eventually gives access to the hardware configuration. For
+ instance, it could allow the setting (on the fly) of variables such
+ as hardware floating-point or strict-alignment.
+
+ It's intended use is as part of testing the simulators
+ functionality */
+
+static device_callbacks const sim_callbacks = {
+ ignore_device_init,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+};
+\f
+/* Load device: *binary@<file-name>
-/* HALT device:
+ Assuming that <file-name> is an executable file understood by BFD,
+ this device loads or maps the relevant text/data segments into
+ memory using dma. */
- With real hardware, the processor operation is normally terminated
- through a reset. This device illustrates how a reset device could
- be attached to an address */
+/* create a device tree from the image */
-STATIC_INLINE_DEVICES unsigned64
-halt_read_callback(device_node *device,
- unsigned_word base,
- unsigned nr_bytes,
- cpu *processor,
- unsigned_word cia)
+STATIC_INLINE_DEVICES void
+update_device_tree_for_section(bfd *abfd,
+ asection *the_section,
+ PTR obj)
{
- cpu_halt(processor, cia, was_exited, 0);
- return 0;
+ unsigned_word section_vma;
+ unsigned_word section_size;
+ access_type access;
+ device *me = (device*)obj;
+
+ /* skip the section if no memory to allocate */
+ if (! (bfd_get_section_flags(abfd, the_section) & SEC_ALLOC))
+ return;
+
+ /* check/ignore any sections of size zero */
+ section_size = bfd_get_section_size_before_reloc(the_section);
+ if (section_size == 0)
+ return;
+
+ /* find where it is to go */
+ section_vma = bfd_get_section_vma(abfd, the_section);
+
+ TRACE(trace_device_tree,
+ ("name=%-7s, vma=0x%.8x, size=%6d, flags=%3x(%s%s%s%s )\n",
+ bfd_get_section_name(abfd, the_section),
+ section_vma, section_size,
+ bfd_get_section_flags(abfd, the_section),
+ bfd_get_section_flags(abfd, the_section) & SEC_LOAD ? " LOAD" : "",
+ bfd_get_section_flags(abfd, the_section) & SEC_CODE ? " CODE" : "",
+ bfd_get_section_flags(abfd, the_section) & SEC_DATA ? " DATA" : "",
+ bfd_get_section_flags(abfd, the_section) & SEC_ALLOC ? " ALLOC" : "",
+ bfd_get_section_flags(abfd, the_section) & SEC_READONLY ? " READONLY" : ""
+ ));
+
+ /* determine the devices access */
+ access = access_read;
+ if (bfd_get_section_flags(abfd, the_section) & SEC_CODE)
+ access |= access_exec;
+ if (!(bfd_get_section_flags(abfd, the_section) & SEC_READONLY))
+ access |= access_write;
+
+ /* if a map, pass up a request to create the memory in core */
+ if (strncmp(me->name, "map-binary@", strlen("map-binary@")) == 0)
+ me->parent->callback->attach_address(me->parent,
+ me->name,
+ attach_raw_memory,
+ 0 /*address space*/,
+ section_vma,
+ section_size,
+ access,
+ me);
+
+ /* if a load dma in the required data */
+ if (bfd_get_section_flags(abfd, the_section) & SEC_LOAD) {
+ void *section_init = zalloc(section_size);
+ if (!bfd_get_section_contents(abfd,
+ the_section,
+ section_init, 0,
+ section_size)) {
+ bfd_perror("core:load_section()");
+ error("load of data failed");
+ return;
+ }
+ if (me->parent->callback->dma_write_buffer(me->parent,
+ section_init,
+ 0 /*address_space*/,
+ section_vma,
+ section_size,
+ 1 /*violate_read_only*/)
+ != section_size)
+ error("data_init_callback() broken transfer for %s\n", me->name);
+ zfree(section_init); /* only free if load */
+ }
}
+
STATIC_INLINE_DEVICES void
-halt_write_callback(device_node *device,
- unsigned_word base,
- unsigned nr_bytes,
- unsigned64 val,
- cpu *processor,
- unsigned_word cia)
+binary_init_callback(const device *me,
+ psim *system)
{
- cpu_halt(processor, cia, was_exited, 0);
+ char file_name[100];
+ bfd *image;
+
+ /* get a file name */
+ if (scand_c(me->name, file_name) != 1)
+ error("load_binary_init_callback() invalid load-binary device %s\n",
+ me->name);
+
+ /* open the file */
+ image = bfd_openr(file_name, NULL);
+ if (image == NULL) {
+ bfd_perror("open failed:");
+ error("nothing loaded\n");
+ }
+
+ /* check it is valid */
+ if (!bfd_check_format(image, bfd_object)) {
+ printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
+ printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
+ bfd_close(image);
+ image = NULL;
+ }
+
+ /* and the data sections */
+ bfd_map_over_sections(image,
+ update_device_tree_for_section,
+ (PTR)me);
+
+ bfd_close(image);
}
-static device_callbacks halt_callbacks = {
- halt_read_callback,
- halt_write_callback,
+static device_callbacks const binary_callbacks = {
+ binary_init_callback,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
};
-STATIC_INLINE_DEVICES device_node *
-halt_create(device_node *parent,
- char *name)
+
+\f
+/* Stack device: stack@<type>
+
+ Has a single IOCTL to create a stack frame of the specified type.
+ If <type> is elf or xcoff then a corresponding stack is created.
+ Any other value of type is ignored.
+
+ The IOCTL takes the additional arguments:
+
+ unsigned_word stack_end -- where the stack should come down from
+ char **argv -- ...
+ char **envp -- ...
+
+ */
+
+STATIC_INLINE_DEVICES int
+sizeof_argument_strings(char **arg)
+{
+ int sizeof_strings = 0;
+
+ /* robust */
+ if (arg == NULL)
+ return 0;
+
+ /* add up all the string sizes (padding as we go) */
+ for (; *arg != NULL; arg++) {
+ int len = strlen(*arg) + 1;
+ sizeof_strings += ALIGN_8(len);
+ }
+
+ return sizeof_strings;
+}
+
+STATIC_INLINE_DEVICES int
+number_of_arguments(char **arg)
+{
+ int nr;
+ if (arg == NULL)
+ return 0;
+ for (nr = 0; *arg != NULL; arg++, nr++);
+ return nr;
+}
+
+STATIC_INLINE_DEVICES int
+sizeof_arguments(char **arg)
+{
+ return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word));
+}
+
+STATIC_INLINE_DEVICES void
+write_stack_arguments(psim *system,
+ char **arg,
+ unsigned_word start_block,
+ unsigned_word end_block,
+ unsigned_word start_arg,
+ unsigned_word end_arg)
+{
+ TRACE(trace_create_stack,
+ ("write_stack_arguments() - %s=0x%x %s=0x%x %s=0x%x %s=0x%x\n",
+ "system", system, "arg", arg,
+ "start_block", start_block, "start_arg", start_arg));
+ if (arg == NULL)
+ error("write_arguments: character array NULL\n");
+ /* only copy in arguments, memory is already zero */
+ for (; *arg != NULL; arg++) {
+ int len = strlen(*arg)+1;
+ unsigned_word target_start_block;
+ TRACE(trace_create_stack,
+ ("write_stack_arguments - write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n",
+ "**arg", *arg, "start_block", start_block,
+ "len", len, "start_arg", start_arg));
+ if (psim_write_memory(system, 0, *arg,
+ start_block, len,
+ 0/*violate_readonly*/) != len)
+ error("write_stack_arguments() - write of **arg (%s) at 0x%x failed\n",
+ *arg, start_block);
+ target_start_block = H2T_word(start_block);
+ if (psim_write_memory(system, 0, &target_start_block,
+ start_arg, sizeof(target_start_block),
+ 0) != sizeof(target_start_block))
+ error("write_stack_arguments() - write of *arg failed\n");
+ start_block += ALIGN_8(len);
+ start_arg += sizeof(start_block);
+ }
+ start_arg += sizeof(start_block); /*the null at the end*/
+ if (start_block != end_block
+ || ALIGN_8(start_arg) != end_arg)
+ error("write_stack_arguments - possible corruption\n");
+}
+
+STATIC_INLINE_DEVICES void
+create_elf_stack_frame(psim *system,
+ unsigned_word bottom_of_stack,
+ char **argv,
+ char **envp)
+{
+ /* fixme - this is over aligned */
+
+ /* information block */
+ const unsigned sizeof_envp_block = sizeof_argument_strings(envp);
+ const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block;
+ const unsigned sizeof_argv_block = sizeof_argument_strings(argv);
+ const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block;
+
+ /* auxiliary vector - contains only one entry */
+ const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */
+ const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry);
+
+ /* environment points (including null sentinal) */
+ const unsigned sizeof_envp = sizeof_arguments(envp);
+ const unsigned_word start_envp = start_aux - sizeof_envp;
+
+ /* argument pointers (including null sentinal) */
+ const int argc = number_of_arguments(argv);
+ const unsigned sizeof_argv = sizeof_arguments(argv);
+ const unsigned_word start_argv = start_envp - sizeof_argv;
+
+ /* link register save address - alligned to a 16byte boundary */
+ const unsigned_word top_of_stack = ((start_argv
+ - 2 * sizeof(unsigned_word))
+ & ~0xf);
+
+ /* install arguments on stack */
+ write_stack_arguments(system, envp,
+ start_envp_block, bottom_of_stack,
+ start_envp, start_aux);
+ write_stack_arguments(system, argv,
+ start_argv_block, start_envp_block,
+ start_argv, start_envp);
+
+ /* set up the registers */
+ psim_write_register(system, -1,
+ &top_of_stack, "sp", cooked_transfer);
+ psim_write_register(system, -1,
+ &argc, "r3", cooked_transfer);
+ psim_write_register(system, -1,
+ &start_argv, "r4", cooked_transfer);
+ psim_write_register(system, -1,
+ &start_envp, "r5", cooked_transfer);
+ psim_write_register(system, -1,
+ &start_aux, "r6", cooked_transfer);
+}
+
+STATIC_INLINE_DEVICES void
+create_aix_stack_frame(psim *system,
+ unsigned_word bottom_of_stack,
+ char **argv,
+ char **envp)
{
- device_node *device;
- unsigned address_base;
- unsigned address_flags;
+ unsigned_word core_envp;
+ unsigned_word core_argv;
+ unsigned_word core_argc;
+ unsigned_word core_aux;
+ unsigned_word top_of_stack;
+
+ /* cheat - create an elf stack frame */
+ create_elf_stack_frame(system, bottom_of_stack, argv, envp);
+
+ /* extract argument addresses from registers */
+ psim_read_register(system, 0, &top_of_stack, "r1", cooked_transfer);
+ psim_read_register(system, 0, &core_argc, "r3", cooked_transfer);
+ psim_read_register(system, 0, &core_argv, "r4", cooked_transfer);
+ psim_read_register(system, 0, &core_envp, "r5", cooked_transfer);
+ psim_read_register(system, 0, &core_aux, "r6", cooked_transfer);
+
+ /* extract arguments from registers */
+ error("create_aix_stack_frame() - what happens next?\n");
+}
+
+
- parse_device_address(name, &address_base, &address_flags);
- device = device_node_create(parent, name, other_device,
- &halt_callbacks, NULL);
- device_node_add_address(device,
- address_base,
- 4,
- device_is_read_write_exec,
- NULL);
- return device;
+STATIC_INLINE_DEVICES void
+stack_ioctl_callback(const device *me,
+ psim *system,
+ cpu *processor,
+ unsigned_word cia,
+ ...)
+{
+ va_list ap;
+ unsigned_word stack_pointer;
+ char **argv;
+ char **envp;
+ va_start(ap, cia);
+ stack_pointer = va_arg(ap, unsigned_word);
+ argv = va_arg(ap, char **);
+ envp = va_arg(ap, char **);
+ if (strcmp(me->name, "stack@elf") == 0)
+ create_elf_stack_frame(system, stack_pointer, argv, envp);
+ else if (strcmp(me->name, "stack@xcoff") == 0)
+ create_aix_stack_frame(system, stack_pointer, argv, envp);
}
-static device_descriptor halt_descriptor = {
- "halt",
- halt_create,
+
+static device_callbacks const stack_callbacks = {
+ ignore_device_init,
+ unimp_device_attach_address,
+ unimp_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ unimp_device_dma_read_buffer,
+ unimp_device_dma_write_buffer,
+ unimp_device_attach_interrupt,
+ unimp_device_detach_interrupt,
+ unimp_device_interrupt,
+ unimp_device_interrupt_ack,
+ stack_ioctl_callback,
};
-static device_descriptor *devices[] = {
- &console_descriptor,
- &halt_descriptor,
- &icu_descriptor,
- NULL,
+\f
+/* Table of all the devices and a function to lookup/create a device
+ from its name */
+
+typedef const device *(device_creator)
+ (const char *name,
+ const device *parent);
+
+typedef struct _device_descriptor device_descriptor;
+struct _device_descriptor {
+ const char *name;
+ device_creator *creator;
+ const device_callbacks *callbacks;
+};
+
+static device_descriptor devices[] = {
+ { "console", console_create, NULL },
+ { "memory", memory_create, NULL },
+ { "vm", vea_vm_create, NULL },
+ { "halt", NULL, &halt_callbacks },
+ { "icu", NULL, &icu_callbacks },
+ { "register", NULL, ®ister_callbacks },
+ { "iobus", NULL, &iobus_callbacks },
+ { "file", NULL, &file_callbacks },
+ { "htab", NULL, &htab_callbacks },
+ { "pte", NULL, &htab_callbacks }, /* yep - uses htab's table */
+ { "stack", NULL, &stack_callbacks },
+ { "sim", NULL, &sim_callbacks },
+ { "load-binary", NULL, &binary_callbacks },
+ { "map-binary", NULL, &binary_callbacks },
+ { NULL },
};
-INLINE_DEVICES device_descriptor *
-find_device_descriptor(char *name)
+INLINE_DEVICES const device *
+device_create(const char *name,
+ const device *parent)
{
- device_descriptor **device;
+ device_descriptor *device;
int name_len;
char *chp;
chp = strchr(name, '@');
name_len = (chp == NULL ? strlen(name) : chp - name);
- for (device = devices; *device != NULL; device++) {
- if (strncmp(name, (*device)->name, name_len) == 0
- && ((*device)->name[name_len] == '\0'
- || (*device)->name[name_len] == '@'))
- return *device;
+ for (device = devices; device->name != NULL; device++) {
+ if (strncmp(name, device->name, name_len) == 0
+ && (device->name[name_len] == '\0'
+ || device->name[name_len] == '@'))
+ if (device->creator != NULL)
+ return device->creator(name, parent);
+ else
+ return device_create_from(name,
+ NULL /* data */,
+ device->callbacks,
+ parent);
}
+ error("device_create() unknown device %s\n", name);
return NULL;
}
+
+INLINE_DEVICES const device *
+device_create_from(const char *name,
+ void *data,
+ const device_callbacks *callback,
+ const device *parent)
+{
+ device *me = ZALLOC(device);
+ me->name = strdup(name);
+ me->data = data;
+ me->callback = callback;
+ me->parent = parent;
+ return me;
+}
+
+
+INLINE_DEVICES const device_callbacks *
+passthrough_device_callbacks(void)
+{
+ static const device_callbacks callbacks = {
+ ignore_device_init,
+ pass_device_attach_address,
+ pass_device_detach_address,
+ unimp_device_io_read_buffer,
+ unimp_device_io_write_buffer,
+ pass_device_dma_read_buffer,
+ pass_device_dma_write_buffer,
+ pass_device_attach_interrupt,
+ pass_device_detach_interrupt,
+ pass_device_interrupt,
+ unimp_device_interrupt_ack,
+ unimp_device_ioctl,
+ };
+ return &callbacks;
+}
+
+
+
#endif /* _DEVICES_C_ */
#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_ */
Instead of using/abusing macro's the semantic code should be parsed
and each `cachable' expression replaced with the corresponding
- value.
-
- If not expanding fields, invalid_insn has call to its self this is
- a little fatal when semantic_invalid() is being called because an
- instruction is invalid */
+ value. */
#include <sys/types.h>
/****************************************************************/
-void
+static void
error (char *msg, ...)
{
va_list ap;
exit (1);
}
-void *
+static void *
zmalloc(long size)
{
void *memory = malloc(size);
return memory;
}
-void
+static void
dumpf (int indent, char *msg, ...)
{
va_list ap;
/* FIXME - this should be loaded from a file */
opcode_rules opcode_table[] = WITH_IDECODE_OPCODE_RULES;
+static void
dump_opcode_rule(opcode_rules *rule,
int indent)
{
- printf("(opcode_rules*)0x%x\n", rule);
+ printf("(opcode_rules*)%p\n", rule);
dumpf(indent, "(valid %d)\n", rule->valid);
ASSERT(rule != NULL);
if (rule->valid) {
/****************************************************************/
-int
+static int
bin2i(char *bin, int width)
{
int i = 0;
}
-int
+static int
it_is(char *flag,
char *flags)
{
};
-lf *
-lf_open(char *name)
+static lf *
+lf_open(char *name,
+ char *real_name)
{
/* create a file object */
lf *new_lf = zmalloc(sizeof(lf));
ASSERT(new_lf != NULL);
- new_lf->file_name = name;
+ new_lf->file_name = (real_name == NULL
+ ? name
+ : real_name);
/* attach to stdout if pipe */
if (!strcmp(name, "-")) {
}
-void
+static void
lf_close(lf *file)
{
if (file->stream != stdout) {
}
-void
+static void
lf_putchr(lf *file,
const char chr)
{
putc(chr, file->stream);
}
-void
+static void
lf_indent_suppress(lf *file)
{
file->line_blank = 0;
}
-void
+static void
lf_putstr(lf *file,
const char *string)
{
}
}
-void
+static void
do_lf_putunsigned(lf *file,
unsigned u)
{
}
-void
+static void
lf_putint(lf *file,
int decimal)
{
ASSERT(0);
}
-void
+static void
lf_printf(lf *file,
const char *fmt,
...)
va_end(ap);
}
-void
+static void
lf_print_file_line_nr(lf *file)
{
#if WITH_LINE_NUMBERS
#endif
}
+static void
lf_indent(lf *file, int delta)
{
file->indent += delta;
};
-file_table *
+static file_table *
file_table_open(char *file_name)
{
int fd;
}
-file_table_entry *
+static file_table_entry *
file_table_read(file_table *file)
{
int field;
}
-void
+static void
dump_file_table_entry(file_table_entry *entry,
int indent)
{
- printf("(file_table_entry*)0x%x\n", entry);
+ printf("(file_table_entry*)%p\n", entry);
if (entry != NULL) {
int field;
unsigned value;
};
-insn_field *
+static insn_field *
insn_field_new()
{
insn_field *new_field = (insn_field*)zmalloc(sizeof(insn_field));
return new_field;
}
-insn_fields *
+static insn_fields *
insn_fields_new()
{
insn_fields *new_fields = (insn_fields*)zmalloc(sizeof(insn_fields));
}
-insn_fields *
+static insn_fields *
parse_insn_format(file_table_entry *entry,
char *format)
{
/* sanity check */
if (!isdigit(*chp)) {
- fprintf(stderr, "%s:%d: missing position field at %s\n",
- entry->file_name, entry->line_nr, chp);
- break;
+ error("%s:%d: missing position field at `%s'\n",
+ entry->file_name, entry->line_nr, chp);
}
/* break out the bit position */
if (*chp == '.' && strlen_pos > 0)
chp++;
else {
- fprintf(stderr, "%s:%d: missing field value at %s\n",
- entry->file_name, entry->line_nr, chp);
+ error("%s:%d: missing field value at %s\n",
+ entry->file_name, entry->line_nr, chp);
break;
}
/* break out the value */
start_val = chp;
- while (*start_val == '/' && *chp == '/'
- || isdigit(*start_val) && isdigit(*chp)
- || isalpha(*start_val) && (isalnum(*chp) || *chp == '_'))
+ while ((*start_val == '/' && *chp == '/')
+ || (isdigit(*start_val) && isdigit(*chp))
+ || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_')))
chp++;
strlen_val = chp - start_val;
if (*chp == ',')
chp++;
else if (*chp != '\0' || strlen_val == 0) {
- fprintf(stderr, "%s:%d: missing field terminator at %s\n",
- entry->file_name, entry->line_nr, chp);
+ error("%s:%d: missing field terminator at %s\n",
+ entry->file_name, entry->line_nr, chp);
break;
}
} constant_field_types;
-int
+static int
insn_field_is_constant(insn_field *field,
opcode_rules *rule)
{
}
-void
+static void
dump_insn_field(insn_field *field,
int indent)
{
- printf("(insn_field*)0x%x\n", field);
+ printf("(insn_field*)0x%x\n", (unsigned)field);
dumpf(indent, "(first %d)\n", field->first);
}
-void
+static void
dump_insn_fields(insn_fields *fields,
int indent)
{
insn_field *field;
int i;
- printf("(insn_fields*)0x%x\n", fields);
+ printf("(insn_fields*)%p\n", fields);
dumpf(indent, "(first 0x%x)\n", fields->first);
dumpf(indent, "(last 0x%x)\n", fields->last);
opcode_field *parent;
};
-opcode_field *
+static opcode_field *
opcode_field_new()
{
opcode_field *new_field = (opcode_field*)zmalloc(sizeof(opcode_field));
return new_field;
}
-void
+static void
dump_opcode_field(opcode_field *field, int indent, int levels)
{
- printf("(opcode_field*)0x%x\n", field);
+ printf("(opcode_field*)%p\n", field);
if (levels && field != NULL) {
dumpf(indent, "(first %d)\n", field->first);
dumpf(indent, "(last %d)\n", field->last);
insn_bits *last;
};
-insn_bits *
+static insn_bits *
insn_bits_new()
{
insn_bits *new_bits = (insn_bits*)zmalloc(sizeof(insn_bits));
}
-void
+static void
dump_insn_bits(insn_bits *bits, int indent, int levels)
{
- printf("(insn_bits*)0x%x\n", bits);
+ printf("(insn_bits*)%p\n", bits);
if (levels && bits != NULL) {
dumpf(indent, "(value %d)\n", bits->value);
insn_nmemonic,
insn_name,
insn_comment,
- nr_insn_table_fields = file_table_max_fields
+ nr_insn_table_fields = file_table_max_fields,
} insn_table_fields;
char *insn_field_name[] = {
"format", "form", "flags", "nmemonic", "name", "comments"
};
+typedef enum {
+ function_type = insn_format,
+ function_name = insn_name,
+ function_param = insn_comment,
+} function_table_fields;
+
+
typedef struct _insn insn;
struct _insn {
file_table_entry *file_entry;
insn_bits *expanded_bits;
int nr_insn;
insn *insns;
+ insn *functions;
opcode_rules *opcode_rule;
opcode_field *opcode;
int nr_entries;
-insn *
+static insn *
insn_new()
{
insn *new_entry = ((insn*) zmalloc(sizeof(insn)));
return new_entry;
}
-insn_table *
+static insn_table *
insn_table_new()
{
insn_table *new_table = (insn_table*)zmalloc(sizeof(insn_table));
}
-void
+static void
+insn_table_insert_function(insn_table *table,
+ file_table_entry *file_entry)
+{
+ insn **ptr_to_cur_function = &table->functions;
+
+ /* create a new function */
+ insn *new_function = insn_new();
+ new_function->file_entry = file_entry;
+
+ /* append it to the end of the function list */
+ while (*ptr_to_cur_function != NULL) {
+ ptr_to_cur_function = &(*ptr_to_cur_function)->next;
+ }
+ *ptr_to_cur_function = new_function;
+}
+
+
+static void
insn_table_insert_insn(insn_table *table,
file_table_entry *file_entry,
insn_fields *fields)
}
-opcode_field *
+static opcode_field *
insn_table_find_opcode_field(insn *insns,
opcode_rules *rule,
int string_only)
}
-void
+static void
insn_table_insert_expanded(insn_table *table,
insn *old_insn,
int new_opcode_nr,
old_insn->fields);
}
-void
+static void
insn_table_expand_opcode(insn_table *table,
insn *instruction,
int field_nr,
}
}
+static void
insn_table_insert_expanding(insn_table *table,
insn *entry)
{
}
-void
+static void
insn_table_expand_insns(insn_table *table)
{
-insn_table *
+static insn_table *
insn_table_load_insns(char *file_name)
{
file_table *file = file_table_open(file_name);
file_table_entry *file_entry;
table->opcode_rule = opcode_table;
- while (file_entry = file_table_read(file)) {
- insn_fields *fields;
- /* skip instructions that aren't relevant to the mode */
- if (it_is("64", file_entry->fields[insn_flags]) && !WITH_64BIT_TARGET
- || it_is("32", file_entry->fields[insn_flags]) && WITH_64BIT_TARGET)
- continue;
- /* create/insert the new instruction */
- fields = parse_insn_format(file_entry, file_entry->fields[insn_format]);
- insn_table_insert_insn(table, file_entry, fields);
+ while ((file_entry = file_table_read(file)) != NULL) {
+ if (it_is("function", file_entry->fields[insn_flags])) {
+ insn_table_insert_function(table, file_entry);
+ }
+ else {
+ insn_fields *fields;
+ /* skip instructions that aren't relevant to the mode */
+ if ((it_is("64", file_entry->fields[insn_flags])
+ && WITH_TARGET_WORD_BITSIZE != 64)
+ || (it_is("32", file_entry->fields[insn_flags])
+ && WITH_TARGET_WORD_BITSIZE != 32)
+ || (it_is("f", file_entry->fields[insn_flags])
+ && WITH_FLOATING_POINT == SOFT_FLOATING_POINT))
+ continue;
+ /* create/insert the new instruction */
+ fields = parse_insn_format(file_entry, file_entry->fields[insn_format]);
+ insn_table_insert_insn(table, file_entry, fields);
+ }
}
-
return table;
}
-void
+static void
dump_insn(insn *entry, int indent, int levels)
{
- printf("(insn*)0x%x\n", entry);
+ printf("(insn*)%p\n", entry);
if (levels && entry != NULL) {
}
-void
+static void
dump_insn_table(insn_table *table,
int indent, int levels)
{
- printf("(insn_table*)0x%x\n", table);
+ printf("(insn_table*)%p\n", table);
if (levels && table != NULL) {
insn *entry;
/****************************************************************/
-void
+static void
lf_print_copyleft(lf *file)
{
lf_putstr(file, "\
}
-void
+static void
lf_print_c_line_nr(lf *file, file_table_entry *entry)
{
#if WITH_LINE_NUMBERS
}
-void
+static void
lf_print_c_code(lf *file, char *code)
{
char *chp = code;
}
-void
+static void
lf_print_binary(lf *file, int decimal, int width)
{
int bit;
}
-void
+static void
lf_print_insn_bits(lf *file, insn_bits *bits)
{
if (bits == NULL)
}
}
-void
+static void
lf_print_opcodes(lf *file,
insn_table *table)
{
}
}
-void
+static void
lf_print_table_name(lf *file,
insn_table *table)
{
function_name_prefix_none
} lf_function_name_prefixes;
-void
+static void
lf_print_function_name(lf *file,
- insn *instruction,
+ char *basename,
insn_bits *expanded_bits,
lf_function_name_prefixes prefix)
{
+
/* the prefix */
switch (prefix) {
case function_name_prefix_semantics:
/* the function name */
{
char *pos;
- for (pos = instruction->file_entry->fields[insn_name];
+ for (pos = basename;
*pos != '\0';
pos++) {
switch (*pos) {
}
-void
+static void
lf_print_idecode_table(lf *file,
insn_table *entry)
{
}
-void
+static void
lf_print_my_prefix(lf *file,
file_table_entry *file_entry)
{
}
-void
+static void
lf_print_ptrace(lf *file)
{
lf_printf(file, "\n");
int opcode_nr);
-void
+static void
insn_table_traverse_tree(insn_table *table,
void *data,
int depth,
}
+typedef void function_handler
+(insn_table *table,
+ void *data,
+ file_table_entry *function);
+
+static void
+insn_table_traverse_function(insn_table *table,
+ void *data,
+ function_handler *leaf)
+{
+ insn *function;
+ for (function = table->functions;
+ function != NULL;
+ function = function->next) {
+ leaf(table, data, function->file_entry);
+ }
+}
+
+
typedef void insn_handler
(insn_table *table,
void *data,
insn *instruction);
-void
+static void
insn_table_traverse_insn(insn_table *table,
void *data,
insn_handler *leaf)
}
-void
+static void
update_depth(insn_table *entry,
void *data,
int depth)
}
-int
+static int
insn_table_depth(insn_table *table)
{
int depth = 0;
/****************************************************************/
-void
+static void
dump_traverse_start(insn_table *table,
void *data,
int depth)
dumpf(depth*2, "(%d\n", table->opcode_nr);
}
-void
+static void
dump_traverse_leaf(insn_table *entry,
void *data,
int depth)
entry->insns->file_entry->fields[insn_format]);
}
-void
+static void
dump_traverse_end(insn_table *table,
void *data,
int depth)
dumpf(depth*2, ")\n");
}
-void
+static void
dump_traverse_padding(insn_table *table,
void *data,
int depth,
}
-void
+static void
dump_traverse(insn_table *table)
{
insn_table_traverse_tree(table, NULL, 1,
/****************************************************************/
-void
+static void
semantics_h_print_function(lf *file,
- insn *instruction,
+ char *basename,
insn_bits *expanded_bits)
{
lf_printf(file, "\n");
lf_printf(file, "INLINE_SEMANTICS unsigned_word ");
lf_print_function_name(file,
- instruction,
+ basename,
expanded_bits,
function_name_prefix_semantics);
lf_printf(file, "\n(%s);\n",
}
-void
+static void
semantics_h_leaf(insn_table *entry,
void *data,
int depth)
{
lf *file = (lf*)data;
ASSERT(entry->nr_insn == 1);
- semantics_h_print_function(file, entry->insns, entry->expanded_bits);
+ semantics_h_print_function(file,
+ entry->insns->file_entry->fields[insn_name],
+ entry->expanded_bits);
}
-void
+static void
semantics_h_insn(insn_table *entry,
void *data,
insn *instruction)
{
lf *file = (lf*)data;
- semantics_h_print_function(file, instruction, NULL);
+ semantics_h_print_function(file,
+ instruction->file_entry->fields[insn_name],
+ NULL);
+}
+
+static void
+semantics_h_function(insn_table *entry,
+ void *data,
+ file_table_entry *function)
+{
+ lf *file = (lf*)data;
+ if (function->fields[function_type] == NULL
+ || function->fields[function_type][0] == '\0') {
+ semantics_h_print_function(file,
+ function->fields[function_name],
+ NULL);
+ }
+ else {
+ lf_printf(file, "\n");
+ lf_printf(file, "INLINE_SEMANTICS %s %s\n(%s);\n",
+ function->fields[function_type],
+ function->fields[function_name],
+ function->fields[function_param]);
+ }
}
-void
+static void
gen_semantics_h(insn_table *table, lf *file)
{
lf_printf(file, "\n");
lf_printf(file, "\n");
+ /* output a declaration for all functions */
+ insn_table_traverse_function(table,
+ file,
+ semantics_h_function);
+
+ /* output a declaration for all instructions */
if (idecode_expand_semantics)
insn_table_traverse_tree(table,
file,
icache_tree *children;
};
-icache_tree *
+static icache_tree *
icache_tree_new()
{
icache_tree *new_tree = (icache_tree*)zmalloc(sizeof(icache_tree));
return new_tree;
}
-icache_tree *
+static icache_tree *
icache_tree_insert(icache_tree *tree,
char *name)
{
}
-icache_tree *
+static icache_tree *
insn_table_cache_fields(insn_table *table)
{
icache_tree *tree = icache_tree_new();
-void
+static void
gen_icache_h(icache_tree *tree,
lf *file)
{
/****************************************************************/
-void
+static void
lf_print_c_extraction(lf *file,
insn *instruction,
char *field_name,
}
-void
+static void
lf_print_c_extractions(lf *file,
insn *instruction,
insn_bits *expanded_bits,
lf_print_file_line_nr(file);
}
-void
+
+static void
+lf_print_idecode_illegal(lf *file)
+{
+ switch (idecode_cache) {
+ case 0:
+ lf_printf(file, "return semantic_illegal(%s);\n", insn_actual);
+ break;
+ case 1:
+ lf_printf(file, "return semantic_illegal;\n");
+ break;
+ default:
+ lf_printf(file, "return idecode_illegal(%s);\n", cache_idecode_actual);
+ }
+}
+
+
+static void
lf_print_c_validate(lf *file,
insn *instruction,
opcode_field *opcodes)
}
/* if any bits not checked by opcode tables, output code to check them */
- if (!it_is("illegal", instruction->file_entry->fields[insn_flags])
- && check_mask) {
+ if (check_mask) {
lf_printf(file, "\n");
lf_printf(file, "/* validate: %s */\n",
instruction->file_entry->fields[insn_format]);
- lf_printf(file, "if ((instruction & 0x%x) != 0x%x) {\n",
+ lf_printf(file, "if ((instruction & 0x%x) != 0x%x)\n",
check_mask, check_val);
- switch (idecode_cache) {
- case 0:
- lf_printf(file, " return semantic_illegal(%s);\n", insn_actual);
- break;
- case 1:
- lf_printf(file, " return semantic_illegal;\n");
- break;
- default:
- lf_printf(file, " return idecode_illegal(%s);\n", cache_idecode_actual);
- }
- lf_printf(file, "}\n");
+ lf_indent(file, +2);
+ lf_print_idecode_illegal(file);
+ lf_indent(file, -2);
}
}
-void
+static void
lf_print_c_cracker(lf *file,
insn *instruction,
insn_bits *expanded_bits,
lf_print_c_line_nr(file, instruction->file_entry);
lf_printf(file, "return ");
lf_print_function_name(file,
- instruction,
+ instruction->file_entry->fields[insn_name],
expanded_bits,
function_name_prefix_semantics);
lf_printf(file, ";\n");
}
-void
+static void
lf_print_c_semantic(lf *file,
insn *instruction,
insn_bits *expanded_bits,
if (idecode_cache < 2)
lf_print_c_validate(file, instruction, opcodes);
- /* if OEA and a floating point generate a check that fp is enabled */
+ /* if floating-point generate checks that a. floating point hardware
+ exists and b. floating point is enabled */
if (it_is("f", instruction->file_entry->fields[insn_flags])) {
lf_printf(file, "\n");
- lf_printf(file, "/* verify FP is enabled */\n");
+ lf_printf(file, "/* verify: FP hardware exists */\n");
+ lf_printf(file, "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT)\n");
+ lf_indent(file, +2);
+ lf_print_idecode_illegal(file);
+ lf_indent(file, -2);
+ lf_printf(file, "\n");
+ lf_printf(file, "/* verify: FP is enabled */\n");
lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n");
- lf_printf(file, " floating_point_unavailable_interrupt(processor, cia);\n");
+ lf_indent(file, +2);
+ lf_printf(file, "floating_point_unavailable_interrupt(processor, cia);\n");
+ lf_indent(file, -2);
}
/* generate the code (or at least something */
lf_print_file_line_nr(file);
}
else if (it_is("f", instruction->file_entry->fields[insn_flags])) {
- /* unimplemented floating point - call for assistance */
+ /* unimplemented floating point instruction - call for assistance */
lf_printf(file, "\n");
+ lf_printf(file, "/* unimplemented floating point instruction - call for assistance */\n");
lf_print_c_line_nr(file, instruction->file_entry);
lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n");
lf_print_file_line_nr(file);
lf_printf(file, "}\n");
}
-void
-lf_print_c_semantic_function(lf *file,
- insn *instruction,
- insn_bits *expanded_bits,
- opcode_field *opcodes)
+static void
+lf_print_c_semantic_function_header(lf *file,
+ char *basename,
+ insn_bits *expanded_bits)
{
-
- /* build the semantic routine to execute the instruction */
-
- /* function header */
lf_printf(file, "\n");
lf_printf(file, "INLINE_SEMANTICS unsigned_word\n");
lf_print_function_name(file,
- instruction,
+ basename,
expanded_bits,
function_name_prefix_semantics);
lf_printf(file, "\n(%s)\n",
idecode_cache > 1 ? cache_insn_formal : insn_formal);
+}
+static void
+lf_print_c_semantic_function(lf *file,
+ insn *instruction,
+ insn_bits *expanded_bits,
+ opcode_field *opcodes)
+{
+
+ /* build the semantic routine to execute the instruction */
+ lf_print_c_semantic_function_header(file,
+ instruction->file_entry->fields[insn_name],
+ expanded_bits);
lf_print_c_semantic(file,
instruction,
expanded_bits,
}
-void
+static void
semantics_c_leaf(insn_table *entry,
void *data,
int depth)
entry->parent->opcode);
}
-void
+static void
semantics_c_insn(insn_table *table,
void *data,
insn *instruction)
NULL, NULL);
}
+static void
+semantics_c_function(insn_table *table,
+ void *data,
+ file_table_entry *function)
+{
+ lf *file = (lf*)data;
+ if (function->fields[function_type] == NULL
+ || function->fields[function_type][0] == '\0') {
+ lf_print_c_semantic_function_header(file,
+ function->fields[function_name],
+ NULL);
+ }
+ else {
+ lf_printf(file, "\n");
+ lf_printf(file, "INLINE_SEMANTICS %s\n%s(%s)\n",
+ function->fields[function_type],
+ function->fields[function_name],
+ function->fields[function_param]);
+ }
+ lf_print_c_line_nr(file, function);
+ lf_printf(file, "{\n");
+ lf_indent(file, +2);
+ lf_print_c_code(file, function->annex);
+ lf_indent(file, -2);
+ lf_printf(file, "}\n");
+ lf_print_file_line_nr(file);
+}
+
-void
+static void
gen_semantics_c(insn_table *table, lf *file)
{
lf_print_copyleft(file);
lf_printf(file, "#include \"semantics.h\"\n");
lf_printf(file, "\n");
+ /* output a definition (c-code) for all functions */
+ insn_table_traverse_function(table,
+ file,
+ semantics_c_function);
+
+ /* output a definition (c-code) for all instructions */
if (idecode_expand_semantics)
insn_table_traverse_tree(table,
file,
/****************************************************************/
-void
+static void
gen_idecode_h(insn_table *table, lf *file)
{
lf_print_copyleft(file);
lf_printf(file, "#define INLINE_IDECODE\n");
lf_printf(file, "#endif\n");
lf_printf(file, "\n");
- lf_printf(file, "#include \"idecode_insn.h\"\n");
lf_printf(file, "#include \"idecode_expression.h\"\n");
lf_printf(file, "#include \"idecode_fields.h\"\n");
lf_printf(file, "#include \"idecode_branch.h\"\n");
/****************************************************************/
-void
+static void
idecode_table_start(insn_table *table,
void *data,
int depth)
}
}
-void
+static void
idecode_table_leaf(insn_table *entry,
void *data,
int depth)
/* table leaf entry */
lf_printf(file, " /*%d*/ { 0, 0, ", entry->opcode_nr);
lf_print_function_name(file,
- entry->insns,
+ entry->insns->file_entry->fields[insn_name],
entry->expanded_bits,
(idecode_cache < 2
? function_name_prefix_semantics
}
}
-void
+static void
idecode_table_end(insn_table *table,
void *data,
int depth)
}
}
-void
+static void
idecode_table_padding(insn_table *table,
void *data,
int depth,
insn_table *table);
-void
+static void
idecode_switch_start(insn_table *table,
void *data,
int depth)
}
-void
+static void
idecode_switch_leaf(insn_table *entry,
void *data,
int depth)
/* switch calling leaf */
lf_printf(file, "return ");
lf_print_function_name(file,
- entry->insns,
+ entry->insns->file_entry->fields[insn_name],
entry->expanded_bits,
(idecode_cache < 2
? function_name_prefix_semantics
lf_indent(file, -2);
}
+
+static void
lf_print_idecode_switch_illegal(lf *file)
{
- switch (idecode_cache) {
- case 0:
- lf_printf(file, " return semantic_illegal(%s);\n", insn_actual);
- break;
- case 1:
- lf_printf(file, " return semantic_illegal;\n");
- break;
- default:
- lf_printf(file, " return idecode_illegal(%s);\n", cache_idecode_actual);
- }
- lf_printf(file, " break;\n");
+ lf_indent(file, +2);
+ lf_print_idecode_illegal(file);
+ lf_printf(file, "break;\n");
+ lf_indent(file, -2);
}
-void
+static void
idecode_switch_end(insn_table *table,
void *data,
int depth)
lf_printf(file, "}\n");
}
-void
+static void
idecode_switch_padding(insn_table *table,
void *data,
int depth,
}
-void
+static void
idecode_expand_if_switch(insn_table *table,
void *data,
int depth)
}
+static void
lf_print_c_cracker_function(lf *file,
insn *instruction,
insn_bits *expanded_bits,
lf_printf(file, "\n");
lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n");
lf_print_function_name(file,
- instruction,
+ instruction->file_entry->fields[insn_name],
expanded_bits,
function_name_prefix_idecode);
lf_printf(file, "\n(%s)\n", cache_idecode_formal);
opcodes);
}
-void
+static void
idecode_crack_leaf(insn_table *entry,
void *data,
int depth)
entry->opcode);
}
-void
+static void
idecode_crack_insn(insn_table *entry,
void *data,
insn *instruction)
/****************************************************************/
+static void
gen_idecode_c(insn_table *table, lf *file)
{
int depth;
spreg_table_entry *sprs;
};
-spreg_table_entry *
+static spreg_table_entry *
spreg_table_entry_new()
{
spreg_table_entry *new_entry =
return new_entry;
}
-spreg_table *
+static spreg_table *
spreg_table_new()
{
spreg_table *new_table = (spreg_table*)zmalloc(sizeof(spreg_table));
return new_table;
}
-void
+static void
spreg_table_insert(spreg_table *table, file_table_entry *entry)
{
/* create a new spr entry */
}
-spreg_table *
+static spreg_table *
spreg_table_load(char *file_name)
{
file_table *file = file_table_open(file_name);
{
file_table_entry *entry;
- while (entry = file_table_read(file)) {
+ while ((entry = file_table_read(file)) != NULL) {
spreg_table_insert(table, entry);
}
}
0
};
-void
+static void
gen_spreg_h(spreg_table *table, lf *file)
{
spreg_table_entry *entry;
}
-void
+static void
gen_spreg_c(spreg_table *table, lf *file)
{
spreg_table_entry *entry;
insn_table *instructions = NULL;
spreg_table *sprs = NULL;
icache_tree *cache_fields = NULL;
+ char *real_file_name = NULL;
int ch;
- while ((ch = getopt(argc, argv, "i:I:r:S:s:D:d:P:p:C:")) != -1) {
+ while ((ch = getopt(argc, argv, "n:i:I:r:S:s:D:d:P:p:C:")) != -1) {
fprintf(stderr, "\t-%c %s\n", ch, optarg);
switch(ch) {
case 'I':
case 'r':
sprs = spreg_table_load(optarg);
break;
+ case 'n':
+ real_file_name = strdup(optarg);
+ break;
default:
{
- lf *file = lf_open(optarg);
+ lf *file = lf_open(optarg, real_file_name);
switch (ch) {
case 'S':
gen_semantics_h(instructions, file);
}
lf_close(file);
}
+ real_file_name = NULL;
}
}
return 0;
+++ /dev/null
-/* 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)
+++ /dev/null
-/* 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_ */
+++ /dev/null
-/* 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
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
#include <signal.h>
#include <sys/errno.h>
#include <sys/param.h>
+#include <fcntl.h>
#if (NetBSD >= 199306) /* here NetBSD as that is what we're emulating */
#include <sys/syscall.h> /* FIXME - should not be including this one */
#include "system.h"
-void
-system_call(cpu *processor,
- unsigned_word cia)
-{
- switch (cpu_registers(processor)->gpr[0]) {
-
-
- case 1/*SYS_exit*/:
-#if (NetBSD >= 199306) && (SYS_exit != 1)
-# error "SYS_exit"
+#ifndef STATIC_INLINE_SYSTEM
+#define STATIC_INLINE_SYSTEM STATIC_INLINE
#endif
- {
- int status = (int)cpu_registers(processor)->gpr[3];
- cpu_halt(processor, cia, was_exited, status);
- break;
- }
-
- case 3/*SYS_read*/:
-#if (NetBSD >= 199306) && (SYS_read != 3)
-# error "SYS_read"
-#endif
- {
- void *scratch_buffer;
- int d = (int)cpu_registers(processor)->gpr[3];
- unsigned_word buf = cpu_registers(processor)->gpr[4];
- int nbytes = cpu_registers(processor)->gpr[5];
- int status;
- int nr_moved;
-
- /* get a tempoary bufer */
- scratch_buffer = zalloc(cpu_registers(processor)->gpr[5]);
-
- /* check if buffer exists by reading it */
- nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
- scratch_buffer,
- buf,
- nbytes,
- raw_transfer);
- if (nr_moved != nbytes)
- error("system_call()read - check on buffer failed\n");
-
- /* read */
- if (d == 0) {
- status = fread (scratch_buffer, 1, nbytes, stdin);
- if (status == 0 && ferror (stdin))
- status = -1;
- } else {
- status = read (d, scratch_buffer, nbytes);
- }
-
- if (status == -1) {
- cpu_registers(processor)->gpr[0] = errno;
- break;
- } else {
- cpu_registers(processor)->gpr[0] = 0;
- cpu_registers(processor)->gpr[3] = status;
-
- if (status > 0) {
- nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
- scratch_buffer,
- buf,
- status,
- raw_transfer,
- 0/*violate_ro*/);
-
- if (nr_moved != nbytes)
- error("system_call()read - write to buffer failed\n");
- }
- }
-
- zfree(scratch_buffer);
-
- break;
- }
-
- case 4/*SYS_write*/:
-#if (NetBSD >= 199306) && (SYS_write != 4)
-# error "SYS_write"
+#if (NetBSD >= 199306)
+#define SYS(X) ASSERT(call == (SYS_##X))
+#else
+#define SYS(X)
#endif
- {
- void *scratch_buffer;
- int nr_moved;
- int d = (int)cpu_registers(processor)->gpr[3];
- unsigned_word buf = cpu_registers(processor)->gpr[4];
- int nbytes = cpu_registers(processor)->gpr[5];
- int status;
-
- /* get a tempoary bufer */
- scratch_buffer = zalloc(cpu_registers(processor)->gpr[5]);
-
- /* copy in */
- nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
- scratch_buffer,
- buf,
- nbytes,
- raw_transfer);
- if (nr_moved != nbytes) {
- /* FIXME - should handle better */
- error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n",
- nr_moved, nbytes);
- }
-
- /* write */
- status = write(d, scratch_buffer, nbytes);
- if (status == -1) {
- cpu_registers(processor)->gpr[0] = errno;
- break;
- }
- cpu_registers(processor)->gpr[0] = 0;
- cpu_registers(processor)->gpr[3] = status;
-
- zfree(scratch_buffer);
-
- break;
- }
-
- case 17/*SYS_break*/:
-#if (NetBSD >= 199306) && (SYS_break != 17)
-# error "SYS_break"
+#if (NetBSD >= 199306 && PATH_MAX != 1024)
+#error "PATH_MAX not 1024"
+#elif !defined(PATH_MAX)
+#define PATH_MAX 1024
#endif
- {
- /* pretend to extend the heap so that it reaches addresss
- new_break while in truth, if growth is needed grow it by a
- page aligned amount */
- unsigned_word new_break = ALIGN_8(cpu_registers(processor)->gpr[3]);
- unsigned_word old_break = core_data_upper_bound(cpu_core(processor));
- signed_word delta = new_break - old_break;
- if (delta > 0)
- core_add_data(cpu_core(processor),
- ALIGN_PAGE(new_break) - old_break);
- cpu_registers(processor)->gpr[0] = 0;
- cpu_registers(processor)->gpr[3] = new_break;
- break;
- }
- case 20/*SYS_getpid*/:
-#if (NetBSD >= 199306) && (SYS_getpid != 20)
-# error "SYS_getpid"
-#endif
- {
- cpu_registers(processor)->gpr[3] = (int)getpid();
+STATIC_INLINE_SYSTEM char *
+read_string(cpu *processor,
+ char *dest,
+ unsigned_word addr,
+ unsigned nr_bytes)
+{
+ unsigned nr_moved = 0;
+ if (addr == 0)
+ return NULL;
+ while (1) {
+ if (vm_data_map_read_buffer(cpu_data_map(processor),
+ &dest[nr_moved],
+ addr + nr_moved,
+ sizeof(dest[nr_moved]))
+ != sizeof(dest[nr_moved]))
+ return NULL;
+ if (dest[nr_moved] == '\0' || nr_moved >= nr_bytes)
break;
- }
-
+ nr_moved++;
+ }
+ dest[nr_moved] = '\0';
+ return dest;
+}
- case 37/*SYS_kill*/:
-#if (NetBSD >= 199306) && (SYS_kill != 37)
-# error "SYS_kill"
-#endif
- {
- pid_t pid = cpu_registers(processor)->gpr[3];
- int sig = cpu_registers(processor)->gpr[4];
- TRACE(trace_tbd, ("SYS_kill - more to this than just a kill\n"));
- cpu_halt(processor, cia, was_signalled, sig);
- break;
- }
-
- case 48/*SYS_sigprocmask*/:
-#if (NetBSD >= 199306) && (SYS_sigprocmask != 48)
-# error "SYS_sigprocmask"
-#endif
- {
- natural_word how = cpu_registers(processor)->gpr[3];
- unsigned_word set = cpu_registers(processor)->gpr[4];
- unsigned_word oset = cpu_registers(processor)->gpr[5];
- TRACE(trace_system, ("SYS_sigprocmask: how=%d, set=0x%x, oset=0x%x\n",
- how, set, oset));
- cpu_registers(processor)->gpr[0] = 0;
- cpu_registers(processor)->gpr[3] = 0;
- cpu_registers(processor)->gpr[4] = set;
- break;
- }
+STATIC_INLINE_SYSTEM void
+write_status(cpu *processor,
+ int status)
+{
+ cpu_registers(processor)->gpr[3] = status;
+ if (status < 0)
+ cpu_registers(processor)->gpr[0] = errno;
+ else
+ cpu_registers(processor)->gpr[0] = 0;
+}
- case 54/*SYS_ioctl*/:
-#if (NetBSD >= 199306) && (SYS_ioctl != 54)
-# error "SYS_ioctl"
+STATIC_INLINE_SYSTEM void
+write_stat(cpu *processor,
+ unsigned_word addr,
+ struct stat buf)
+{
+ int nr_moved;
+ H2T(buf.st_dev);
+ H2T(buf.st_ino);
+ H2T(buf.st_mode);
+ H2T(buf.st_nlink);
+ H2T(buf.st_uid);
+ H2T(buf.st_gid);
+ H2T(buf.st_rdev);
+ H2T(buf.st_size);
+ H2T(buf.st_atime);
+ /* H2T(buf.st_spare1); */
+ H2T(buf.st_mtime);
+ /* H2T(buf.st_spare2); */
+ H2T(buf.st_ctime);
+ /* H2T(buf.st_spare3); */
+ H2T(buf.st_blksize);
+ H2T(buf.st_blocks);
+#if (NetBSD >= 199306)
+ H2T(buf.st_flags);
+ H2T(buf.st_gen);
#endif
- {
- TRACE(trace_system, ("SYS_ioctl: d=%d, request=0x%x, argp=0x%x\n",
- cpu_registers(processor)->gpr[3], cpu_registers(processor)->gpr[4], cpu_registers(processor)->gpr[5]));
- cpu_registers(processor)->gpr[0] = 0;
- cpu_registers(processor)->gpr[3] = 0;
- break;
- }
+ nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
+ &buf,
+ addr,
+ sizeof(buf),
+ 0/*violate_ro*/);
+ if (nr_moved != sizeof(buf))
+ error("write_stat() write failed\n");
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_exit(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ int status = (int)cpu_registers(processor)->gpr[3];
+ SYS(exit);
+ cpu_halt(processor, cia, was_exited, status);
+}
- case 189/*SYS_fstat*/:
-#if (NetBSD >= 199306) && (SYS_fstat != 189)
-# error "SYS_fstat"
-#endif
- {
- int fd = cpu_registers(processor)->gpr[3];
- unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
- struct stat buf;
- int nr_moved;
- int status;
-
- /* check buffer all there, by reading it */
- nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
- &buf,
- stat_buf_addr,
- sizeof(buf),
- raw_transfer);
- if (nr_moved != sizeof(buf))
- error("system_call()fstat - check on buffer failed\n");
-
- /* do the fstat call */
- status = fstat(fd, &buf);
- if (status == -1) {
- cpu_registers(processor)->gpr[0] = errno;
- break;
- }
- cpu_registers(processor)->gpr[0] = 0;
- cpu_registers(processor)->gpr[3] = 0;
-
- H2T(buf.st_dev);
- H2T(buf.st_ino);
- H2T(buf.st_mode);
- H2T(buf.st_nlink);
- H2T(buf.st_uid);
- H2T(buf.st_gid);
- H2T(buf.st_rdev);
- H2T(buf.st_size);
- H2T(buf.st_atime);
- /* H2T(buf.st_spare1); */
- H2T(buf.st_mtime);
- /* H2T(buf.st_spare2); */
- H2T(buf.st_ctime);
- /* H2T(buf.st_spare3); */
- H2T(buf.st_blksize);
- H2T(buf.st_blocks);
-#if (NetBSD >= 199306)
- H2T(buf.st_flags);
- H2T(buf.st_gen);
+STATIC_INLINE_SYSTEM void
+do_read(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ void *scratch_buffer;
+ int d = (int)cpu_registers(processor)->gpr[3];
+ unsigned_word buf = cpu_registers(processor)->gpr[4];
+ int nbytes = cpu_registers(processor)->gpr[5];
+ int status;
+ int nr_moved;
+ SYS(read);
+
+ /* get a tempoary bufer */
+ scratch_buffer = zalloc(nbytes);
+
+ /* check if buffer exists by reading it */
+ nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
+ scratch_buffer,
+ buf,
+ nbytes);
+ if (nr_moved != nbytes)
+ error("system_call()read - check on buffer failed\n");
+
+ /* read */
+#if 0
+ if (d == 0) {
+ status = fread (scratch_buffer, 1, nbytes, stdin);
+ if (status == 0 && ferror (stdin))
+ status = -1;
+ }
#endif
-
+ status = read (d, scratch_buffer, nbytes);
+
+ if (status == -1) {
+ cpu_registers(processor)->gpr[0] = errno;
+ } else {
+ cpu_registers(processor)->gpr[3] = status;
+
+ if (status > 0) {
nr_moved = vm_data_map_write_buffer(cpu_data_map(processor),
- &buf,
- stat_buf_addr,
- sizeof(buf),
- raw_transfer,
+ scratch_buffer,
+ buf,
+ status,
0/*violate_ro*/);
- break;
+ if (nr_moved != status)
+ error("system_call()read - write to buffer failed\n");
}
+ }
+
+ zfree(scratch_buffer);
+}
- case 202/*SYS___sysctl*/:
-#if (NetBSD >= 199306) && (SYS___sysctl != 202)
-# error "SYS__sysctl"
-#endif
- {
- /* call the arguments by their real name */
- unsigned_word name = cpu_registers(processor)->gpr[3];
- natural_word namelen = cpu_registers(processor)->gpr[4];
- unsigned_word oldp = cpu_registers(processor)->gpr[5];
- unsigned_word oldlenp = cpu_registers(processor)->gpr[6];
- natural_word oldlen;
- natural_word mib;
- natural_word int_val;
-
- /* pluck out the management information base id */
- if (namelen < 1
- || sizeof(mib) != vm_data_map_read_buffer(cpu_data_map(processor),
- &mib,
- name,
- sizeof(mib),
- cooked_transfer))
- error("system_call()SYS___sysctl bad name[0]\n");
- name += sizeof(mib);
-
- /* see what to do with it ... */
- switch (mib) {
- case 6/*CTL_HW*/:
+STATIC_INLINE_SYSTEM void
+do_write(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ void *scratch_buffer = NULL;
+ int nr_moved;
+ int d = (int)cpu_registers(processor)->gpr[3];
+ unsigned_word buf = cpu_registers(processor)->gpr[4];
+ int nbytes = cpu_registers(processor)->gpr[5];
+ int status;
+ SYS(write);
+
+ /* get a tempoary bufer */
+ scratch_buffer = zalloc(nbytes); /* FIXME - nbytes == 0 */
+
+ /* copy in */
+ nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
+ scratch_buffer,
+ buf,
+ nbytes);
+ if (nr_moved != nbytes) {
+ /* FIXME - should handle better */
+ error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n",
+ nr_moved, nbytes);
+ }
+
+ /* write */
+ status = write(d, scratch_buffer, nbytes);
+ if (status == -1) {
+ cpu_registers(processor)->gpr[0] = errno;
+ }
+ cpu_registers(processor)->gpr[3] = status;
+
+ zfree(scratch_buffer);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_open(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ unsigned_word path_addr = cpu_registers(processor)->gpr[3];
+ char path_buf[PATH_MAX];
+ char *path = read_string(processor, path_buf, path_addr, PATH_MAX);
+ int flags = (int)cpu_registers(processor)->gpr[4];
+ int mode = (int)cpu_registers(processor)->gpr[4];
+ SYS(open);
+ write_status(processor, open(path, flags, mode));
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_close(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ int d = (int)cpu_registers(processor)->gpr[3];
+ SYS(close);
+ write_status(processor, close(d));
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_break(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+ /* just pass this onto the `vm' device */
+{
+ psim *system = cpu_system(processor);
+ const device *vm = psim_device(system, "/vm");
+ SYS(break);
+ vm->callback->ioctl(vm,
+ system,
+ processor,
+ cia,
+ 0, /*ioctl*/
+ NULL); /*ioctl-data*/
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_getpid(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ SYS(getpid);
+ cpu_registers(processor)->gpr[3] = (int)getpid();
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_getuid(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ SYS(getuid);
+ cpu_registers(processor)->gpr[3] = (int)getuid();
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_geteuid(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ SYS(geteuid);
+ cpu_registers(processor)->gpr[3] = (int)geteuid();
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_kill(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ pid_t pid = cpu_registers(processor)->gpr[3];
+ int sig = cpu_registers(processor)->gpr[4];
+ SYS(kill);
+ error("SYS_kill - more to this than just a kill\n");
+ cpu_halt(processor, cia, was_signalled, sig);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_sigprocmask(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ natural_word how = cpu_registers(processor)->gpr[3];
+ unsigned_word set = cpu_registers(processor)->gpr[4];
+ unsigned_word oset = cpu_registers(processor)->gpr[5];
+ SYS(sigprocmask);
+ TRACE(trace_system, ("SYS_sigprocmask: how=%d, set=0x%x, oset=0x%x\n",
+ how, set, oset));
+ cpu_registers(processor)->gpr[3] = 0;
+ cpu_registers(processor)->gpr[4] = set;
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_ioctl(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ SYS(ioctl);
+ TRACE(trace_system, ("SYS_ioctl: d=%d, request=0x%x, argp=0x%x\n",
+ cpu_registers(processor)->gpr[3], cpu_registers(processor)->gpr[4], cpu_registers(processor)->gpr[5]));
+ cpu_registers(processor)->gpr[3] = 0;
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_umask(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ SYS(umask);
+ cpu_registers(processor)->gpr[3] = umask(cpu_registers(processor)->gpr[3]);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_stat(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ char path_buf[PATH_MAX];
+ unsigned_word path_addr = cpu_registers(processor)->gpr[3];
+ unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
+ char *path = read_string(processor, path_buf, path_addr, PATH_MAX);
+ struct stat buf;
+ SYS(stat);
+ write_status(processor, stat(path, &buf));
+ write_stat(processor, stat_buf_addr, buf);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_fstat(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ int fd = cpu_registers(processor)->gpr[3];
+ unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
+ struct stat buf;
+ SYS(fstat);
+ write_status(processor, fstat(fd, &buf));
+ write_stat(processor, stat_buf_addr, buf);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do_lstat(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ char path_buf[PATH_MAX];
+ unsigned_word path_addr = cpu_registers(processor)->gpr[3];
+ char *path = read_string(processor, path_buf, path_addr, PATH_MAX);
+ unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[4];
+ struct stat buf;
+ SYS(lstat);
+ write_status(processor, stat(path, &buf));
+ write_stat(processor, stat_buf_addr, buf);
+}
+
+
+STATIC_INLINE_SYSTEM void
+do___sysctl(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ /* call the arguments by their real name */
+ unsigned_word name = cpu_registers(processor)->gpr[3];
+ natural_word namelen = cpu_registers(processor)->gpr[4];
+ unsigned_word oldp = cpu_registers(processor)->gpr[5];
+ unsigned_word oldlenp = cpu_registers(processor)->gpr[6];
+ natural_word oldlen;
+ natural_word mib;
+ natural_word int_val;
+ SYS(__sysctl);
+
+ /* pluck out the management information base id */
+ if (namelen < 1)
+ error("system_call()SYS___sysctl bad name[0]\n");
+ mib = vm_data_map_read_word(cpu_data_map(processor),
+ name,
+ processor,
+ cia);
+ name += sizeof(mib);
+
+ /* see what to do with it ... */
+ switch (mib) {
+ case 6/*CTL_HW*/:
#if (NetBSD >= 199306) && (CTL_HW != 6)
# error "CTL_HW"
#endif
- if (namelen < 2
- || sizeof(mib) != vm_data_map_read_buffer(cpu_data_map(processor),
- &mib,
- name,
- sizeof(mib),
- cooked_transfer))
- error("system_call()SYS___sysctl - CTL_HW - bad name[1]\n");
- name += sizeof(mib);
- switch (mib) {
- case 7/*HW_PAGESIZE*/:
+ if (namelen < 2)
+ error("system_call()SYS___sysctl - CTL_HW - bad name[1]\n");
+ mib = vm_data_map_read_word(cpu_data_map(processor),
+ name,
+ processor,
+ cia);
+ name += sizeof(mib);
+ switch (mib) {
+ case 7/*HW_PAGESIZE*/:
#if (NetBSD >= 199306) && (HW_PAGESIZE != 7)
# error "HW_PAGESIZE"
#endif
- if (sizeof(oldlen) != vm_data_map_read_buffer(cpu_data_map(processor),
- &oldlen,
- oldlenp,
- sizeof(oldlen),
- cooked_transfer))
- error("system_call()sysctl - CTL_HW.HW_PAGESIZE - oldlen read\n");
- if (sizeof(natural_word) > oldlen)
- error("system_call()sysctl - CTL_HW.HW_PAGESIZE - to small\n");
- int_val = 8192;
- oldlen = sizeof(int_val);
- if (sizeof(int_val) != vm_data_map_write_buffer(cpu_data_map(processor),
- &int_val,
- oldp,
- sizeof(int_val),
- cooked_transfer,
- 0/*violate_ro*/))
- error("system_call()sysctl - CTL_HW.HW_PAGESIZE - int_val\n");
- if (sizeof(oldlen) != vm_data_map_write_buffer(cpu_data_map(processor),
- &oldlen,
- oldlenp,
- sizeof(oldlen),
- cooked_transfer,
- 0/*violate_ro*/))
- error("system_call()sysctl - CTL_HW.HW_PAGESIZE - oldlen write\n");
- break;
- default:
- error("sysctl() CTL_HW.%d unknown\n", mib);
- break;
- }
- break;
- default:
- error("sysctl() name[0]=%s unknown\n", (int)mib);
- break;
- }
- cpu_registers(processor)->gpr[0] = 0;
- cpu_registers(processor)->gpr[3] = 0;
+ oldlen = vm_data_map_read_word(cpu_data_map(processor),
+ oldlenp,
+ processor,
+ cia);
+ if (sizeof(natural_word) > oldlen)
+ error("system_call()sysctl - CTL_HW.HW_PAGESIZE - to small\n");
+ int_val = 8192;
+ oldlen = sizeof(int_val);
+ vm_data_map_write_word(cpu_data_map(processor),
+ oldp,
+ int_val,
+ processor,
+ cia);
+ vm_data_map_write_word(cpu_data_map(processor),
+ oldlenp,
+ oldlen,
+ processor,
+ cia);
+ break;
+ default:
+ error("sysctl() CTL_HW.%d unknown\n", mib);
break;
}
-
-
+ break;
default:
- error("system_call() unimplemented system call %d, cia=0x%x, arg[0]=0x%x, lr=0x%x\n",
- cpu_registers(processor)->gpr[0], cia, cpu_registers(processor)->gpr[3], LR);
+ error("sysctl() name[0]=%s unknown\n", (int)mib);
break;
-
}
+ cpu_registers(processor)->gpr[3] = 0;
+}
+
+STATIC_INLINE_SYSTEM void
+unimp(unsigned call,
+ cpu *processor,
+ unsigned_word cia)
+{
+ error("unimplemented system call %d, cia=0x%x\n", call, cia);
+}
+
+
+typedef void (sys_handler)
+ (unsigned call,
+ cpu *processor,
+ unsigned_word cia);
+
+static sys_handler *(handlers[]) = {
+ unimp, /* SYS_syscall 0 */
+ do_exit, /* 1*/
+ unimp, /* SYS_fork 2 */
+ do_read, /* 3 */
+ do_write, /* 4 */
+ do_open, /* 5 */
+ do_close, /* 6 */
+ unimp, /* SYS_wait4 7 */
+ unimp, /* 8 is old creat */
+ unimp, /* SYS_link 9 */
+ unimp, /* SYS_unlink 10 */
+ unimp, /* 11 is obsolete execv */
+ unimp, /* SYS_chdir 12 */
+ unimp, /* SYS_fchdir 13 */
+ unimp, /* SYS_mknod 14 */
+ unimp, /* SYS_chmod 15 */
+ unimp, /* SYS_chown 16 */
+ do_break, /* 17 */
+ unimp, /* SYS_getfsstat 18 */
+ unimp, /* 19 is old lseek */
+ do_getpid, /* 20 */
+ unimp, /* SYS_mount 21 */
+ unimp, /* SYS_unmount 22 */
+ unimp, /* SYS_setuid 23 */
+ do_getuid, /* 24 */
+ do_geteuid, /* 25 */
+ unimp, /* SYS_ptrace 26 */
+ unimp, /* SYS_recvmsg 27 */
+ unimp, /* SYS_sendmsg 28 */
+ unimp, /* SYS_recvfrom 29 */
+ unimp, /* SYS_accept 30 */
+ unimp, /* SYS_getpeername 31 */
+ unimp, /* SYS_getsockname 32 */
+ unimp, /* SYS_access 33 */
+ unimp, /* SYS_chflags 34 */
+ unimp, /* SYS_fchflags 35 */
+ unimp, /* SYS_sync 36 */
+ do_kill, /* 37 */
+ unimp, /* 38 is old stat */
+ unimp, /* SYS_getppid 39 */
+ unimp, /* 40 is old lstat */
+ unimp, /* SYS_dup 41 */
+ unimp, /* SYS_pipe 42 */
+ unimp, /* SYS_getegid 43 */
+ unimp, /* SYS_profil 44 */
+ unimp, /* SYS_ktrace 45 */
+ unimp, /* SYS_sigaction 46 */
+ unimp, /* SYS_getgid 47 */
+ do_sigprocmask, /* 48 */
+ unimp, /* SYS_getlogin 49 */
+ unimp, /* SYS_setlogin 50 */
+ unimp, /* SYS_acct 51 */
+ unimp, /* SYS_sigpending 52 */
+ unimp, /* SYS_sigaltstack 53 */
+ do_ioctl, /* 54 */
+ unimp, /* SYS_reboot 55 */
+ unimp, /* SYS_revoke 56 */
+ unimp, /* SYS_symlink 57 */
+ unimp, /* SYS_readlink 58 */
+ unimp, /* SYS_execve 59 */
+ do_umask, /* 60 */
+ unimp, /* SYS_chroot 61 */
+ unimp, /* 62 is old fstat */
+ unimp, /* 63 is old getkerninfo */
+ unimp, /* 64 is old getpagesize */
+ unimp, /* SYS_msync 65 */
+ unimp, /* SYS_vfork 66 */
+ unimp, /* 67 is obsolete vread */
+ unimp, /* 68 is obsolete vwrite */
+ unimp, /* SYS_sbrk 69 */
+ unimp, /* SYS_sstk 70 */
+ unimp, /* 71 is old mmap */
+ unimp, /* SYS_vadvise 72 */
+ unimp, /* SYS_munmap 73 */
+ unimp, /* SYS_mprotect 74 */
+ unimp, /* SYS_madvise 75 */
+ unimp, /* 76 is obsolete vhangup */
+ unimp, /* 77 is obsolete vlimit */
+ unimp, /* SYS_mincore 78 */
+ unimp, /* SYS_getgroups 79 */
+ unimp, /* SYS_setgroups 80 */
+ unimp, /* SYS_getpgrp 81 */
+ unimp, /* SYS_setpgid 82 */
+ unimp, /* SYS_setitimer 83 */
+ unimp, /* 84 is old wait */
+ unimp, /* SYS_swapon 85 */
+ unimp, /* SYS_getitimer 86 */
+ unimp, /* 87 is old gethostname */
+ unimp, /* 88 is old sethostname */
+ unimp, /* 89 is old getdtablesize */
+ unimp, /* SYS_dup2 90 */
+ unimp, /* 91 */
+ unimp, /* SYS_fcntl 92 */
+ unimp, /* SYS_select 93 */
+ unimp, /* 94 */
+ unimp, /* SYS_fsync 95 */
+ unimp, /* SYS_setpriority 96 */
+ unimp, /* SYS_socket 97 */
+ unimp, /* SYS_connect 98 */
+ unimp, /* 99 is old accept */
+ unimp, /* SYS_getpriority 100 */
+ unimp, /* 101 is old send */
+ unimp, /* 102 is old recv */
+ unimp, /* SYS_sigreturn 103 */
+ unimp, /* SYS_bind 104 */
+ unimp, /* SYS_setsockopt 105 */
+ unimp, /* SYS_listen 106 */
+ unimp, /* 107 is obsolete vtimes */
+ unimp, /* 108 is old sigvec */
+ unimp, /* 109 is old sigblock */
+ unimp, /* 110 is old sigsetmask */
+ unimp, /* SYS_sigsuspend 111 */
+ unimp, /* 112 is old sigstack */
+ unimp, /* 113 is old recvmsg */
+ unimp, /* 114 is old sendmsg */
+ unimp, /* SYS_vtrace 115 - is obsolete vtrace */
+ unimp, /* SYS_gettimeofday 116 */
+ unimp, /* SYS_getrusage 117 */
+ unimp, /* SYS_getsockopt 118 */
+ unimp, /* SYS_resuba 119 */
+ unimp, /* SYS_readv 120 */
+ unimp, /* SYS_writev 121 */
+ unimp, /* SYS_settimeofday 122 */
+ unimp, /* SYS_fchown 123 */
+ unimp, /* SYS_fchmod 124 */
+ unimp, /* 125 is old recvfrom */
+ unimp, /* 126 is old setreuid */
+ unimp, /* 127 is old setregid */
+ unimp, /* SYS_rename 128 */
+ unimp, /* 129 is old truncate */
+ unimp, /* 130 is old ftruncate */
+ unimp, /* SYS_flock 131 */
+ unimp, /* SYS_mkfifo 132 */
+ unimp, /* SYS_sendto 133 */
+ unimp, /* SYS_shutdown 134 */
+ unimp, /* SYS_socketpair 135 */
+ unimp, /* SYS_mkdir 136 */
+ unimp, /* SYS_rmdir 137 */
+ unimp, /* SYS_utimes 138 */
+ unimp, /* 139 is obsolete 4.2 sigreturn */
+ unimp, /* SYS_adjtime 140 */
+ unimp, /* 141 is old getpeername */
+ unimp, /* 142 is old gethostid */
+ unimp, /* 143 is old sethostid */
+ unimp, /* 144 is old getrlimit */
+ unimp, /* 145 is old setrlimit */
+ unimp, /* 146 is old killpg */
+ unimp, /* SYS_setsid 147 */
+ unimp, /* SYS_quotactl 148 */
+ unimp, /* 149 is old quota */
+ unimp, /* 150 is old getsockname */
+ unimp, /* 151 */
+ unimp, /* 152 */
+ unimp, /* 153 */
+ unimp, /* 154 */
+ unimp, /* SYS_nfssvc 155 */
+ unimp, /* 156 is old getdirentries */
+ unimp, /* SYS_statfs 157 */
+ unimp, /* SYS_fstatfs 158 */
+ unimp, /* 159 */
+ unimp, /* 160 */
+ unimp, /* SYS_getfh 161 */
+ unimp, /* 162 is old getdomainname */
+ unimp, /* 163 is old setdomainname */
+ unimp, /* 164 is old uname */
+ unimp, /* SYS_sysarch 165 */
+ unimp, /* 166 */
+ unimp, /* 167 */
+ unimp, /* 168 */
+ unimp, /* SYS_semsys 169 */
+ unimp, /* SYS_msgsys 170 */
+ unimp, /* SYS_shmsys 171 */
+ unimp, /* 172 */
+ unimp, /* 173 */
+ unimp, /* 174 */
+ unimp, /* 175 */
+ unimp, /* 176 */
+ unimp, /* 177 */
+ unimp, /* 178 */
+ unimp, /* 179 */
+ unimp, /* 180 */
+ unimp, /* SYS_setgid 181 */
+ unimp, /* SYS_setegid 182 */
+ unimp, /* SYS_seteuid 183 */
+ unimp, /* SYS_lfs_bmapv 184 */
+ unimp, /* SYS_lfs_markv 185 */
+ unimp, /* SYS_lfs_segclean 186 */
+ unimp, /* SYS_lfs_segwait 187 */
+ do_stat, /* 188 */
+ do_fstat, /* 189 */
+ do_lstat, /* 190 */
+ unimp, /* SYS_pathconf 191 */
+ unimp, /* SYS_fpathconf 192 */
+ unimp, /* 193 */
+ unimp, /* SYS_getrlimit 194 */
+ unimp, /* SYS_setrlimit 195 */
+ unimp, /* SYS_getdirentries 196 */
+ unimp, /* SYS_mmap 197 */
+ unimp, /* SYS___syscall 198 */
+ unimp, /* SYS_lseek 199 */
+ unimp, /* SYS_truncate 200 */
+ unimp, /* SYS_ftruncate 201 */
+ do___sysctl, /* 202 */
+ unimp, /* SYS_mlock 203 */
+ unimp, /* SYS_munlock 204 */
+};
+
+INLINE_SYSTEM void
+system_call(cpu *processor,
+ unsigned_word cia)
+{
+ unsigned call = cpu_registers(processor)->gpr[0];
+ if (call >= sizeof(handlers)/sizeof(handlers[0]))
+ error("system call %d out-of-range\n", call);
+ cpu_registers(processor)->gpr[0] = 0; /* default success */
+ handlers[call](call, processor, cia);
}
#endif /* _SYSTEM_C_ */
#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);