diff options
author | Michael Meissner <gnu@the-meissners.org> | 1995-10-11 20:17:49 +0000 |
---|---|---|
committer | Michael Meissner <gnu@the-meissners.org> | 1995-10-11 20:17:49 +0000 |
commit | dec38dacebf86c97d6c779d021b11ae3010ac985 (patch) | |
tree | 95aab8601046f2942a7561036f5f54f7f67f9984 | |
parent | ee9f09cd2624af3cccfd08955c8aba7ede3b1c95 (diff) | |
download | gdb-dec38dacebf86c97d6c779d021b11ae3010ac985.zip gdb-dec38dacebf86c97d6c779d021b11ae3010ac985.tar.gz gdb-dec38dacebf86c97d6c779d021b11ae3010ac985.tar.bz2 |
October 11th changes from Andrew
-rw-r--r-- | sim/ppc/.Sanitize | 5 | ||||
-rw-r--r-- | sim/ppc/README.psim | 177 | ||||
-rw-r--r-- | sim/ppc/core.c | 662 | ||||
-rw-r--r-- | sim/ppc/core.h | 144 | ||||
-rw-r--r-- | sim/ppc/core_n.h | 91 | ||||
-rw-r--r-- | sim/ppc/device_tree.c | 926 | ||||
-rw-r--r-- | sim/ppc/device_tree.h | 293 | ||||
-rw-r--r-- | sim/ppc/devices.c | 1597 | ||||
-rw-r--r-- | sim/ppc/devices.h | 308 | ||||
-rw-r--r-- | sim/ppc/gen.c | 506 | ||||
-rw-r--r-- | sim/ppc/idecode_insn.h | 67 | ||||
-rw-r--r-- | sim/ppc/memory_map.c | 355 | ||||
-rw-r--r-- | sim/ppc/memory_map.h | 126 | ||||
-rw-r--r-- | sim/ppc/ppc-endian.h | 5 | ||||
-rw-r--r-- | sim/ppc/system.c | 945 | ||||
-rw-r--r-- | sim/ppc/system.h | 6 |
16 files changed, 3990 insertions, 2223 deletions
diff --git a/sim/ppc/.Sanitize b/sim/ppc/.Sanitize index e99ca8a..c25d589 100644 --- a/sim/ppc/.Sanitize +++ b/sim/ppc/.Sanitize @@ -36,6 +36,7 @@ configure configure.in core.c core.h +core_n.h cpu.c cpu.h debug.c @@ -52,14 +53,11 @@ gen.c idecode_branch.h idecode_expression.h idecode_fields.h -idecode_insn.h inline.c inline.h interrupts.c interrupts.h main.c -memory_map.c -memory_map.h ppc-endian.c ppc-endian.h ppc-instructions @@ -76,6 +74,7 @@ system.c system.h vm.c vm.h +vm_n.h words.h Things-to-lose: diff --git a/sim/ppc/README.psim b/sim/ppc/README.psim index c76c023..f9a1486 100644 --- a/sim/ppc/README.psim +++ b/sim/ppc/README.psim @@ -4,63 +4,47 @@ Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> This directory contains the program PSIM that models the PowerPC -architecture. It can either be run stand alone (psim) or linked with -GDB. +architecture. It can either be run stand alone (psim or run) or used +as part of GDB. -CONTENTS: +SOURCE: - psim-*.tar: + PSIM is now part of the Cygnus GDB source tree (hopefully it + will in turn become part of the next FSF release of GDB). - psim-sim-*.tar.gz simulator source code + If you're looking for a more `cutting' edge version of this + program then it can be found in: - psim-test-*.tar.gz test directory for simulator + ftp.ci.com.au:pub/clayton/psim-sim-*.tar.gz - psim-gdb-*.diff.gz patches to integrated psim - into gdb + This contains a replacement for the directory sim/ppc. As + these releases prove stable they are merged back into the GDB + source tree. - gnu-*.tar: + If you find bugs or experience problems, please e-mail them to + the alias: - gnu-gdb-*.diff.gz patches to gdb that may have - already been merged into the - GDB source tree. + powerpc-psim@ci.com.au - gnu-*-*.diff.gz Other noise + It's a majordomo mailing list. BUILDING: - o Install flex, bison, gnu-make, native gcc and probably also byacc. + o At present PSIM can only be built using the compiler GCC + (yes that is bug). This is because, among other things the + code exploits GCC's suport of long ongs. + o I also suggest that you install: flex, bision, gnu-make and + byacc. Doing this just makes builds easier. - o First you will need a fairly current copy of GDB (try the ftp site - ftp.cygnus.com:pub). I've built it with a beta version of gdb-4.15. + o Configure almost as per normal, specifing the special target + eabisim vis: - Unpack gdb vis: - - $ gunzip < gdb-4.15.tar.gz | tar xf - - - - o Apply any patches that haven't yet been merged into the GDB source - tree. - - $ cd gdb-4.15 - $ gunzip < ../psim-gdb-*.diff.gz | patch -p1 - $ gunzip < ../gnu-gdb-*.diff.gz | patch -p1 - - - o Unpack the psim source code (and optionally the test directory) - - $ cd gdb-4.15 - $ gunzip < ../psim-sim-*.tar.gz | tar xvf - - $ gunzip < ../psim-test-*.tar.gz | tar xvf - - - - o Configure gdb as per normal. I use something along the lines of: - - $ cd gdb-4.15 - $ CC=gcc ./configure --target=powerpcle-unknown-eabi + $ CC=gcc ./configure --target=powerpcle-unknown-eabisim + by default (because of its dependency on GCC). o Build your entire gdb tree as per normal. Something along the lines of: @@ -78,15 +62,17 @@ BUILDING: $ cd gdb-4.15 $ make CC=gcc install - The program sim/ppc/psim is not installed. - RUNNING: PSIM can either be run as a stand alone program or as part - of gdb. The psim-test archive contains pre-compiled and - linked programs that can be run on PSIM. The notes below - assume that you have unpacked that tar archive. + of gdb. The psim-test archive (found in: + + ftp.ci.com.au:pub/clayton + + contains pre-compiled and linked programs that can be run on + PSIM. The notes below assume that you have unpacked that tar + archive. To rebuild the archive you will need to obtain a working version of an ELF compiler/linker for the PowerPC. @@ -135,68 +121,105 @@ RUNNING: . -CONFIGURATION: Making it go faster +CONFIGURATION: + + 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: @@ -251,3 +274,7 @@ i486DX2/66 1/270/316 - switch=2/2,expand=0,inline=1,nia=0 1/271/281 - switch=1/1,expand=0,inline=1,nia=1 1/267/274 - switch=2/1,expand=0,inline=1,nia=1 + +---- + +CFLAGS = -g -Wall -Wno-unused -Wmissing-prototypes -Werror diff --git a/sim/ppc/core.c b/sim/ppc/core.c index 9c47a6c..a40128e 100644 --- a/sim/ppc/core.c +++ b/sim/ppc/core.c @@ -26,354 +26,468 @@ #define STATIC_INLINE_CORE STATIC_INLINE #endif + #include "basics.h" #include "device_tree.h" -#include "memory_map.h" #include "core.h" +typedef struct _core_mapping core_mapping; +struct _core_mapping { + /* ram map */ + int free_buffer; + void *buffer; + /* device map */ + const device *device; + device_io_read_buffer_callback *reader; + device_io_write_buffer_callback *writer; + /* common */ + int address_space; + unsigned_word base; + unsigned_word bound; + unsigned nr_bytes; + core_mapping *next; +}; + +struct _core_map { + core_mapping *first; + core_mapping *default_map; +}; + +typedef enum { + core_read_map, + core_write_map, + core_execute_map, + nr_core_map_types, +} core_map_types; + struct _core { - /* attached devices */ - device_node *device_tree; - /* different memory maps */ - memory_map *readable; /* really everything */ - memory_map *writeable; - memory_map *executable; - /* VEA model requires additional memory information */ - unsigned_word data_upper_bound; - unsigned_word data_high_water; - unsigned_word stack_upper_bound; - unsigned_word stack_lower_bound; - unsigned_word stack_low_water; - /* misc */ - int trace; + core_map map[nr_core_map_types]; }; +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_ */ diff --git a/sim/ppc/core.h b/sim/ppc/core.h index 5d7837a..38871e6 100644 --- a/sim/ppc/core.h +++ b/sim/ppc/core.h @@ -26,78 +26,130 @@ #define INLINE_CORE #endif -/* the base type */ +/* basic types */ typedef struct _core core; +typedef struct _core_map core_map; +/* constructor */ -/* create the hardware's core (memory and devices) from the device - tree */ INLINE_CORE core *core_create -(device_node *root, - int trace); +(void); +INLINE_CORE const device *core_device_create +(core *); -/* given a created core object, (re)initialize it from the - information provided in it's associated device tree */ - -INLINE_CORE void core_init -(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 diff --git a/sim/ppc/core_n.h b/sim/ppc/core_n.h new file mode 100644 index 0000000..d4c54bc --- /dev/null +++ b/sim/ppc/core_n.h @@ -0,0 +1,91 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef N +#error "N must be #defined" +#endif + +#undef unsigned_N +#define unsigned_N XCONCAT2(unsigned_,N) +#undef T2H_N +#define T2H_N XCONCAT2(T2H_,N) +#undef H2T_N +#define H2T_N XCONCAT2(H2T_,N) + + +INLINE_CORE unsigned_N +XCONCAT2(core_map_read_,N)(core_map *map, + unsigned_word addr, + cpu *processor, + unsigned_word cia) +{ + core_mapping *mapping = core_map_find_mapping(map, + addr, + sizeof(unsigned_N), + processor, + cia, + 1); /*abort*/ + if (WITH_CALLBACK_MEMORY && mapping->reader != NULL) { + unsigned_N data; + if (mapping->reader(mapping->device, + &data, + mapping->address_space, + addr - mapping->base, + sizeof(unsigned_N), /* nr_bytes */ + processor, + cia) != sizeof(unsigned_N)) + error("core_read_,N() reader should not fail\n"); + return T2H_N(data); + } + else + return T2H_N(*(unsigned_N*)core_translate(mapping, addr)); +} + + + +INLINE_CORE void +XCONCAT2(core_map_write_,N)(core_map *map, + unsigned_word addr, + unsigned_N val, + cpu *processor, + unsigned_word cia) +{ + core_mapping *mapping = core_map_find_mapping(map, + addr, + sizeof(unsigned_N), + processor, + cia, + 1); /*abort*/ + if (WITH_CALLBACK_MEMORY && mapping->writer != NULL) { + unsigned_N data = H2T_N(val); + if (mapping->writer(mapping->device, + &data, + mapping->address_space, + addr - mapping->base, + sizeof(unsigned_N), /* nr_bytes */ + processor, + cia) != sizeof(unsigned_N)) + error("core_read_,N() writer should not fail\n"); + } + else + *(unsigned_N*)core_translate(mapping, addr) = H2T_N(val); +} + diff --git a/sim/ppc/device_tree.c b/sim/ppc/device_tree.c index 3a0f60e..78b6e1b 100644 --- a/sim/ppc/device_tree.c +++ b/sim/ppc/device_tree.c @@ -27,358 +27,310 @@ #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) { @@ -389,126 +341,312 @@ device_tree_traverse(device_node *root, } -/* 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_ */ diff --git a/sim/ppc/device_tree.h b/sim/ppc/device_tree.h index 59d764e..d8e5481 100644 --- a/sim/ppc/device_tree.h +++ b/sim/ppc/device_tree.h @@ -27,208 +27,147 @@ #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_ */ diff --git a/sim/ppc/devices.c b/sim/ppc/devices.c index 96b8109..983b693 100644 --- a/sim/ppc/devices.c +++ b/sim/ppc/devices.c @@ -31,51 +31,291 @@ #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: + +/* 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); +} + + + +/* 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); +} + + + +/* 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; @@ -84,8 +324,6 @@ typedef struct _console_buffer { } console_buffer; typedef struct _console_device { - unsigned_word my_base_address; - int interrupt_delay; console_buffer input; console_buffer output; } console_device; @@ -100,24 +338,28 @@ typedef enum { } 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 */ @@ -127,124 +369,130 @@ console_read_callback(device_node *device, 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: + +/* ICU device: icu@0x<address>,4 Single 4 byte register. Read returns processor number. Write interrupts specified processor. @@ -256,55 +504,513 @@ static device_descriptor console_descriptor = { 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, +}; + + + +/* 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, +}; + + + +/* 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, +}; + + + +/* 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); +} + + + +/* 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); +} + + + +/* 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 @@ -313,130 +1019,605 @@ icu_interrupt_callback(device_node *me, 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) + + +/* 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, +}; + + + +/* 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, }; + +/* 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, +}; + +/* 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) + + +/* 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, + +/* 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_ */ diff --git a/sim/ppc/devices.h b/sim/ppc/devices.h index e115779..681992e 100644 --- a/sim/ppc/devices.h +++ b/sim/ppc/devices.h @@ -26,17 +26,311 @@ #define INLINE_DEVICES #endif -#include "device_tree.h" -/* table of all the configured devices */ +/* forward declaration of types */ +/* typedef struct _device device; -- in devices.h */ -typedef struct _device_descriptor device_descriptor; -struct _device_descriptor { - char *name; - device_creator *creator; + +/* Address access attributes that can be attached to a devices address + range */ +typedef enum _access_type { + access_invalid = 0, + access_read = 1, + access_write = 2, + access_read_write = 3, + access_exec = 4, + access_read_exec = 5, + access_write_exec = 6, + access_read_write_exec = 7, +} access_type; + +/* Address attachement types */ +typedef enum _attach_type { + attach_invalid, + attach_callback, + attach_default, + attach_raw_memory, +} attach_type; + + +/* Operators on devices: */ + + +/* Initialization: + + A device is made fully functional in two stages. + + 1. It is created. A device is created _before_ it is entered into + the device tree. During creation any permenant structures needed + by the device should be created/initialized. + + 2. It is initialized. Before a simulation run, each device in the + device tree is initialized in prefix order. As part of this + initialization, a device should (re)attach its self to its parent + as needed. + + */ + +typedef void (device_init_callback) + (const device *me, + psim *system); + + +/* Data transfers: + + A device may permit the reading/writing (IO) of its registers in + one or more address spaces. For instance, a PCI device may have + config registers in its config space and control registers in both + the io and memory spaces of a PCI bus. + + Similarly, a device may initiate a data transfer (DMA) by passing + such a request up to its parent. + + Init: + + As part of its initialization (not creation) and possibly also as a + consequence of IO a device may attach its self to one or more of + the address spaces of its parent device. + + For instance, a PCI device, during initialization would attach its + config registers (space=0?, base=0, nr_bytes=64) to its parent PCI + bridge. Later, due to a write to this config space, the same + device may in turn find it necessary to also attach its self to + it's parent's `memory' or `io' space. + + To perform these operations, a device will call upon its parent + using either device_attach_address or device_detach_address. + + * Any address specified is according to what the device expects to + see. + + * Any detach operation must exactly match a previous attach. + + * included with the attach or detach is the devices name, the + parent may use this as part of determining how to map map between a + child's address + space and its own. + + * at any time, at most one device can have a default mapping + registered. + + + IO: + + A device receives requests to perform reads/writes to its registers + or memory either A. from a processor or B. from a parent device. + + The device may then in turn either A. resolve the IO request + locally by processing the data or trigering an exception or + B. re-mapping the access onto one of its local address spaces and + then in turn passing that on to one of its children. + + * Any address passed is relative to the local device. Eg for PCI + config registers, the address would (normally) be in the range of 0 + to 63. + + * Any exception situtation triggered by an IO operation (processor + != NULL) is handled in one of the following ways: 1. Machine check + (and similar): issued immediatly by restarting the cpu; 2. External + exception: issue delayed (using events.h) until the current + instruction execution cycle is completed; 3. Slave device (and + similar): the need for the interrupt is passed on to the devices + parent (which being an interrupt control unit will in turn take one + of the actions described here); 4. Forget it. + + * Any exception situtation trigered by a non IO operation + (processor == NULL) is handled buy returning 0. + + * Transfers of size <= 8 and of a power of 2 *must* be correctly + aligned and should be treated as a `single cycle' transfer. + + DMA: + + A device initiates a DMA transfer by calling its parent with the + request. At the top level (if not done earlier) this is reflected + back down the tree as io read/writes to the target device. + + This function is subject to change ... + + */ + +typedef void (device_config_address_callback) + (const device *me, + const char *name, + attach_type type, + int address_space, + unsigned_word addr, + unsigned nr_bytes, + access_type access, + const device *who); /*callback/default*/ + +typedef unsigned (device_io_read_buffer_callback) + (const device *me, + void *dest, + int address_space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia); + +typedef unsigned (device_io_write_buffer_callback) + (const device *me, + const void *source, + int address_space, + unsigned_word addr, + unsigned nr_bytes, + cpu *processor, + unsigned_word cia); + +typedef unsigned (device_dma_read_buffer_callback) + (const device *me, + void *dest, + int address_space, + unsigned_word addr, + unsigned nr_bytes); + +typedef unsigned (device_dma_write_buffer_callback) + (const device *me, + const void *source, + int address_space, + unsigned_word addr, + unsigned nr_bytes, + int violate_read_only_section); + + +/* Interrupts: + + As mentioned above. Instead of handling an interrupt directly, a + device may instead pass the need to interrupt on to its parent. + + Init: + + Before passing interrupts up to is parent, a device must first + attach its interrupt lines to the parent device. To do this, the + device uses the parents attach/detach calls. + + Interrupts: + + A child notifies a parent of a change in an interrupt lines status + using the interrupt call. Similarly, a parent may notify a child + of any `interrupt ack' sequence using the interrupt_ack call. + + */ + +typedef void (device_config_interrupt_callback) + (const device *me, + const device *who, + int interrupt_line, + const char *name); + +typedef void (device_interrupt_ack_callback) + (const device *me, + int interrupt_line, + int interrupt_status); + +typedef void (device_interrupt_callback) + (const device *me, + const device *who, + int interrupt_line, + int interrupt_status, + cpu *processor, + unsigned_word cia); + + +/* IOCTL: + + Very simply, a catch all for any thing that turns up that until now + either hasn't been thought of or doesn't justify an extra function. */ + + +typedef void (device_ioctl_callback) + (const device *me, + psim *system, + cpu *processor, + unsigned_word cia, + ...); + + + +/* the callbacks */ + +typedef struct _device_callbacks { + /* initialization */ + device_init_callback *init; + /* address/data config - from child */ + device_config_address_callback *attach_address; + device_config_address_callback *detach_address; + /* address/data transfer - to child */ + device_io_read_buffer_callback *io_read_buffer; + device_io_write_buffer_callback *io_write_buffer; + /* address/data transfer - from child */ + device_dma_read_buffer_callback *dma_read_buffer; + device_dma_write_buffer_callback *dma_write_buffer; + /* interrupt config - from child */ + device_config_interrupt_callback *attach_interrupt; + device_config_interrupt_callback *detach_interrupt; + /* interrupt transfer - from child */ + device_interrupt_callback *interrupt; + /* interrupt transfer - to child */ + device_interrupt_ack_callback *interrupt_ack; + /* back door to anything we've forgot */ + device_ioctl_callback *ioctl; +} device_callbacks; + +/* A device */ +struct _device { + const char *name; /* eg rom@0x1234, 0x400 */ + void *data; /* device specific data */ + const device_callbacks *callback; + const device *parent; }; -INLINE_DEVICES device_descriptor *find_device_descriptor(char *name); +/* Create a new device, finding it in the builtin device table */ + +INLINE_DEVICES const device *device_create +(const char *name, + const device *parent); + +/* create a new device using the parameterized data */ + +INLINE_DEVICES const device *device_create_from +(const char *name, + void *data, + const device_callbacks *callback, + const device *parent); + + +/* Unimplemented call back functions. These abort the simulation */ + +INLINE_DEVICES device_init_callback unimp_device_init; +INLINE_DEVICES device_config_address_callback unimp_device_attach_address; +INLINE_DEVICES device_config_address_callback unimp_device_detach_address; +INLINE_DEVICES device_io_read_buffer_callback unimp_device_io_read_buffer; +INLINE_DEVICES device_io_write_buffer_callback unimp_device_io_write_buffer; +INLINE_DEVICES device_dma_read_buffer_callback unimp_device_dma_read_buffer; +INLINE_DEVICES device_dma_write_buffer_callback unimp_device_dma_write_buffer; +INLINE_DEVICES device_config_interrupt_callback unimp_device_attach_interrupt; +INLINE_DEVICES device_config_interrupt_callback unimp_device_detach_interrupt; +INLINE_DEVICES device_interrupt_callback unimp_device_interrupt; +INLINE_DEVICES device_interrupt_ack_callback unimp_device_interrupt_ack; +INLINE_DEVICES device_ioctl_callback unimp_device_ioctl; + +/* Pass through and ignore callback functions. A call going towards + the root device are passed on up, local calls are ignored and call + downs abort */ + +INLINE_DEVICES device_init_callback ignore_device_init; +INLINE_DEVICES device_config_address_callback pass_device_attach_address; +INLINE_DEVICES device_config_address_callback pass_device_detach_address; +INLINE_DEVICES device_dma_read_buffer_callback pass_device_dma_read_buffer; +INLINE_DEVICES device_dma_write_buffer_callback pass_device_dma_write_buffer; +INLINE_DEVICES device_config_interrupt_callback pass_device_attach_interrupt; +INLINE_DEVICES device_config_interrupt_callback pass_device_detach_interrupt; +INLINE_DEVICES device_interrupt_callback pass_device_interrupt; + +INLINE_DEVICES const device_callbacks *passthrough_device_callbacks +(void); + + #endif /* _DEVICES_H_ */ diff --git a/sim/ppc/gen.c b/sim/ppc/gen.c index cc46952..b9870ab 100644 --- a/sim/ppc/gen.c +++ b/sim/ppc/gen.c @@ -23,11 +23,7 @@ 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> @@ -52,7 +48,7 @@ /****************************************************************/ -void +static void error (char *msg, ...) { va_list ap; @@ -62,7 +58,7 @@ error (char *msg, ...) exit (1); } -void * +static void * zmalloc(long size) { void *memory = malloc(size); @@ -72,7 +68,7 @@ zmalloc(long size) return memory; } -void +static void dumpf (int indent, char *msg, ...) { va_list ap; @@ -121,10 +117,11 @@ typedef struct _opcode_rules { /* 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) { @@ -158,7 +155,7 @@ char insn_local[] = "unsigned_word nia = cia + 4;"; /****************************************************************/ -int +static int bin2i(char *bin, int width) { int i = 0; @@ -171,7 +168,7 @@ bin2i(char *bin, int width) } -int +static int it_is(char *flag, char *flags) { @@ -203,13 +200,16 @@ struct _lf { }; -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, "-")) { @@ -224,7 +224,7 @@ lf_open(char *name) } -void +static void lf_close(lf *file) { if (file->stream != stdout) { @@ -237,7 +237,7 @@ lf_close(lf *file) } -void +static void lf_putchr(lf *file, const char chr) { @@ -254,14 +254,14 @@ lf_putchr(lf *file, 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) { @@ -273,7 +273,7 @@ lf_putstr(lf *file, } } -void +static void do_lf_putunsigned(lf *file, unsigned u) { @@ -284,7 +284,7 @@ do_lf_putunsigned(lf *file, } -void +static void lf_putint(lf *file, int decimal) { @@ -301,7 +301,7 @@ lf_putint(lf *file, ASSERT(0); } -void +static void lf_printf(lf *file, const char *fmt, ...) @@ -318,7 +318,7 @@ lf_printf(lf *file, va_end(ap); } -void +static void lf_print_file_line_nr(lf *file) { #if WITH_LINE_NUMBERS @@ -331,6 +331,7 @@ lf_print_file_line_nr(lf *file) #endif } +static void lf_indent(lf *file, int delta) { file->indent += delta; @@ -363,7 +364,7 @@ struct _file_table_entry { }; -file_table * +static file_table * file_table_open(char *file_name) { int fd; @@ -411,7 +412,7 @@ file_table_open(char *file_name) } -file_table_entry * +static file_table_entry * file_table_read(file_table *file) { int field; @@ -494,11 +495,11 @@ file_table_read(file_table *file) } -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; @@ -548,7 +549,7 @@ struct _insn_fields { unsigned value; }; -insn_field * +static insn_field * insn_field_new() { insn_field *new_field = (insn_field*)zmalloc(sizeof(insn_field)); @@ -556,7 +557,7 @@ insn_field_new() return new_field; } -insn_fields * +static insn_fields * insn_fields_new() { insn_fields *new_fields = (insn_fields*)zmalloc(sizeof(insn_fields)); @@ -565,7 +566,7 @@ insn_fields_new() } -insn_fields * +static insn_fields * parse_insn_format(file_table_entry *entry, char *format) { @@ -600,9 +601,8 @@ parse_insn_format(file_table_entry *entry, /* 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 */ @@ -613,23 +613,23 @@ parse_insn_format(file_table_entry *entry, 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; } @@ -706,7 +706,7 @@ typedef enum { } constant_field_types; -int +static int insn_field_is_constant(insn_field *field, opcode_rules *rule) { @@ -738,12 +738,12 @@ insn_field_is_constant(insn_field *field, } -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); @@ -767,14 +767,14 @@ dump_insn_field(insn_field *field, } -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); @@ -800,7 +800,7 @@ struct _opcode_field { opcode_field *parent; }; -opcode_field * +static opcode_field * opcode_field_new() { opcode_field *new_field = (opcode_field*)zmalloc(sizeof(opcode_field)); @@ -810,10 +810,10 @@ opcode_field_new() 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); @@ -835,7 +835,7 @@ struct _insn_bits { insn_bits *last; }; -insn_bits * +static insn_bits * insn_bits_new() { insn_bits *new_bits = (insn_bits*)zmalloc(sizeof(insn_bits)); @@ -844,10 +844,10 @@ insn_bits_new() } -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); @@ -873,12 +873,19 @@ typedef enum { 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; @@ -892,6 +899,7 @@ struct _insn_table { insn_bits *expanded_bits; int nr_insn; insn *insns; + insn *functions; opcode_rules *opcode_rule; opcode_field *opcode; int nr_entries; @@ -902,7 +910,7 @@ struct _insn_table { -insn * +static insn * insn_new() { insn *new_entry = ((insn*) zmalloc(sizeof(insn))); @@ -910,7 +918,7 @@ insn_new() return new_entry; } -insn_table * +static insn_table * insn_table_new() { insn_table *new_table = (insn_table*)zmalloc(sizeof(insn_table)); @@ -919,7 +927,25 @@ insn_table_new() } -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) @@ -946,7 +972,7 @@ insn_table_insert_insn(insn_table *table, } -opcode_field * +static opcode_field * insn_table_find_opcode_field(insn *insns, opcode_rules *rule, int string_only) @@ -1047,7 +1073,7 @@ insn_table_find_opcode_field(insn *insns, } -void +static void insn_table_insert_expanded(insn_table *table, insn *old_insn, int new_opcode_nr, @@ -1081,7 +1107,7 @@ insn_table_insert_expanded(insn_table *table, old_insn->fields); } -void +static void insn_table_expand_opcode(insn_table *table, insn *instruction, int field_nr, @@ -1124,6 +1150,7 @@ insn_table_expand_opcode(insn_table *table, } } +static void insn_table_insert_expanding(insn_table *table, insn *entry) { @@ -1135,7 +1162,7 @@ insn_table_insert_expanding(insn_table *table, } -void +static void insn_table_expand_insns(insn_table *table) { @@ -1196,7 +1223,7 @@ 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); @@ -1204,25 +1231,33 @@ insn_table_load_insns(char *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) { @@ -1243,12 +1278,12 @@ dump_insn(insn *entry, int indent, int levels) } -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; @@ -1293,7 +1328,7 @@ dump_insn_table(insn_table *table, /****************************************************************/ -void +static void lf_print_copyleft(lf *file) { lf_putstr(file, "\ @@ -1326,7 +1361,7 @@ lf_print_copyleft(lf *file) } -void +static void lf_print_c_line_nr(lf *file, file_table_entry *entry) { #if WITH_LINE_NUMBERS @@ -1340,7 +1375,7 @@ lf_print_c_line_nr(lf *file, file_table_entry *entry) } -void +static void lf_print_c_code(lf *file, char *code) { char *chp = code; @@ -1378,7 +1413,7 @@ lf_print_c_code(lf *file, char *code) } -void +static void lf_print_binary(lf *file, int decimal, int width) { int bit; @@ -1394,7 +1429,7 @@ lf_print_binary(lf *file, int decimal, int width) } -void +static void lf_print_insn_bits(lf *file, insn_bits *bits) { if (bits == NULL) @@ -1410,7 +1445,7 @@ lf_print_insn_bits(lf *file, insn_bits *bits) } } -void +static void lf_print_opcodes(lf *file, insn_table *table) { @@ -1426,7 +1461,7 @@ lf_print_opcodes(lf *file, } } -void +static void lf_print_table_name(lf *file, insn_table *table) { @@ -1442,12 +1477,13 @@ typedef enum { 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: @@ -1463,7 +1499,7 @@ lf_print_function_name(lf *file, /* the function name */ { char *pos; - for (pos = instruction->file_entry->fields[insn_name]; + for (pos = basename; *pos != '\0'; pos++) { switch (*pos) { @@ -1486,7 +1522,7 @@ lf_print_function_name(lf *file, } -void +static void lf_print_idecode_table(lf *file, insn_table *entry) { @@ -1574,7 +1610,7 @@ lf_print_idecode_table(lf *file, } -void +static void lf_print_my_prefix(lf *file, file_table_entry *file_entry) { @@ -1586,7 +1622,7 @@ lf_print_my_prefix(lf *file, } -void +static void lf_print_ptrace(lf *file) { lf_printf(file, "\n"); @@ -1607,7 +1643,7 @@ typedef void padding_handler int opcode_nr); -void +static void insn_table_traverse_tree(insn_table *table, void *data, int depth, @@ -1657,12 +1693,31 @@ insn_table_traverse_tree(insn_table *table, } +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) @@ -1676,7 +1731,7 @@ insn_table_traverse_insn(insn_table *table, } -void +static void update_depth(insn_table *entry, void *data, int depth) @@ -1687,7 +1742,7 @@ update_depth(insn_table *entry, } -int +static int insn_table_depth(insn_table *table) { int depth = 0; @@ -1704,7 +1759,7 @@ insn_table_depth(insn_table *table) /****************************************************************/ -void +static void dump_traverse_start(insn_table *table, void *data, int depth) @@ -1712,7 +1767,7 @@ dump_traverse_start(insn_table *table, dumpf(depth*2, "(%d\n", table->opcode_nr); } -void +static void dump_traverse_leaf(insn_table *entry, void *data, int depth) @@ -1724,7 +1779,7 @@ dump_traverse_leaf(insn_table *entry, entry->insns->file_entry->fields[insn_format]); } -void +static void dump_traverse_end(insn_table *table, void *data, int depth) @@ -1732,7 +1787,7 @@ dump_traverse_end(insn_table *table, dumpf(depth*2, ")\n"); } -void +static void dump_traverse_padding(insn_table *table, void *data, int depth, @@ -1742,7 +1797,7 @@ dump_traverse_padding(insn_table *table, } -void +static void dump_traverse(insn_table *table) { insn_table_traverse_tree(table, NULL, 1, @@ -1756,15 +1811,15 @@ dump_traverse(insn_table *table) /****************************************************************/ -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", @@ -1772,27 +1827,52 @@ semantics_h_print_function(lf *file, } -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) { @@ -1807,6 +1887,12 @@ 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, @@ -1834,7 +1920,7 @@ struct _icache_tree { icache_tree *children; }; -icache_tree * +static icache_tree * icache_tree_new() { icache_tree *new_tree = (icache_tree*)zmalloc(sizeof(icache_tree)); @@ -1842,7 +1928,7 @@ icache_tree_new() return new_tree; } -icache_tree * +static icache_tree * icache_tree_insert(icache_tree *tree, char *name) { @@ -1872,7 +1958,7 @@ icache_tree_insert(icache_tree *tree, } -icache_tree * +static icache_tree * insn_table_cache_fields(insn_table *table) { icache_tree *tree = icache_tree_new(); @@ -1896,7 +1982,7 @@ insn_table_cache_fields(insn_table *table) -void +static void gen_icache_h(icache_tree *tree, lf *file) { @@ -1976,7 +2062,7 @@ gen_icache_h(icache_tree *tree, /****************************************************************/ -void +static void lf_print_c_extraction(lf *file, insn *instruction, char *field_name, @@ -2030,7 +2116,7 @@ lf_print_c_extraction(lf *file, } -void +static void lf_print_c_extractions(lf *file, insn *instruction, insn_bits *expanded_bits, @@ -2126,7 +2212,24 @@ lf_print_c_extractions(lf *file, 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) @@ -2161,30 +2264,21 @@ lf_print_c_validate(lf *file, } /* 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, @@ -2219,7 +2313,7 @@ lf_print_c_cracker(lf *file, 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"); @@ -2230,7 +2324,7 @@ lf_print_c_cracker(lf *file, } -void +static void lf_print_c_semantic(lf *file, insn *instruction, insn_bits *expanded_bits, @@ -2258,12 +2352,21 @@ lf_print_c_semantic(lf *file, 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 */ @@ -2282,8 +2385,9 @@ lf_print_c_semantic(lf *file, 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); @@ -2302,25 +2406,32 @@ lf_print_c_semantic(lf *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, @@ -2329,7 +2440,7 @@ lf_print_c_semantic_function(lf *file, } -void +static void semantics_c_leaf(insn_table *entry, void *data, int depth) @@ -2345,7 +2456,7 @@ semantics_c_leaf(insn_table *entry, entry->parent->opcode); } -void +static void semantics_c_insn(insn_table *table, void *data, insn *instruction) @@ -2355,9 +2466,37 @@ semantics_c_insn(insn_table *table, 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); @@ -2374,6 +2513,12 @@ gen_semantics_c(insn_table *table, lf *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, @@ -2394,7 +2539,7 @@ gen_semantics_c(insn_table *table, lf *file) /****************************************************************/ -void +static void gen_idecode_h(insn_table *table, lf *file) { lf_print_copyleft(file); @@ -2406,7 +2551,6 @@ gen_idecode_h(insn_table *table, lf *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"); @@ -2430,7 +2574,7 @@ gen_idecode_h(insn_table *table, lf *file) /****************************************************************/ -void +static void idecode_table_start(insn_table *table, void *data, int depth) @@ -2446,7 +2590,7 @@ idecode_table_start(insn_table *table, } } -void +static void idecode_table_leaf(insn_table *entry, void *data, int depth) @@ -2461,7 +2605,7 @@ idecode_table_leaf(insn_table *entry, /* 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 @@ -2491,7 +2635,7 @@ idecode_table_leaf(insn_table *entry, } } -void +static void idecode_table_end(insn_table *table, void *data, int depth) @@ -2504,7 +2648,7 @@ idecode_table_end(insn_table *table, } } -void +static void idecode_table_padding(insn_table *table, void *data, int depth, @@ -2528,7 +2672,7 @@ void lf_print_idecode_switch insn_table *table); -void +static void idecode_switch_start(insn_table *table, void *data, int depth) @@ -2542,7 +2686,7 @@ idecode_switch_start(insn_table *table, } -void +static void idecode_switch_leaf(insn_table *entry, void *data, int depth) @@ -2559,7 +2703,7 @@ idecode_switch_leaf(insn_table *entry, /* 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 @@ -2585,22 +2729,17 @@ idecode_switch_leaf(insn_table *entry, 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) @@ -2616,7 +2755,7 @@ idecode_switch_end(insn_table *table, lf_printf(file, "}\n"); } -void +static void idecode_switch_padding(insn_table *table, void *data, int depth, @@ -2648,7 +2787,7 @@ lf_print_idecode_switch(lf *file, } -void +static void idecode_expand_if_switch(insn_table *table, void *data, int depth) @@ -2674,6 +2813,7 @@ idecode_expand_if_switch(insn_table *table, } +static void lf_print_c_cracker_function(lf *file, insn *instruction, insn_bits *expanded_bits, @@ -2683,7 +2823,7 @@ lf_print_c_cracker_function(lf *file, 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); @@ -2694,7 +2834,7 @@ lf_print_c_cracker_function(lf *file, opcodes); } -void +static void idecode_crack_leaf(insn_table *entry, void *data, int depth) @@ -2710,7 +2850,7 @@ idecode_crack_leaf(insn_table *entry, entry->opcode); } -void +static void idecode_crack_insn(insn_table *entry, void *data, insn *instruction) @@ -2724,6 +2864,7 @@ idecode_crack_insn(insn_table *entry, /****************************************************************/ +static void gen_idecode_c(insn_table *table, lf *file) { int depth; @@ -2841,7 +2982,7 @@ struct _spreg_table { spreg_table_entry *sprs; }; -spreg_table_entry * +static spreg_table_entry * spreg_table_entry_new() { spreg_table_entry *new_entry = @@ -2850,7 +2991,7 @@ spreg_table_entry_new() return new_entry; } -spreg_table * +static spreg_table * spreg_table_new() { spreg_table *new_table = (spreg_table*)zmalloc(sizeof(spreg_table)); @@ -2858,7 +2999,7 @@ spreg_table_new() return new_table; } -void +static void spreg_table_insert(spreg_table *table, file_table_entry *entry) { /* create a new spr entry */ @@ -2898,7 +3039,7 @@ spreg_table_insert(spreg_table *table, file_table_entry *entry) } -spreg_table * +static spreg_table * spreg_table_load(char *file_name) { file_table *file = file_table_open(file_name); @@ -2906,7 +3047,7 @@ spreg_table_load(char *file_name) { file_table_entry *entry; - while (entry = file_table_read(file)) { + while ((entry = file_table_read(file)) != NULL) { spreg_table_insert(table, entry); } } @@ -2926,7 +3067,7 @@ char *spreg_attributes[] = { 0 }; -void +static void gen_spreg_h(spreg_table *table, lf *file) { spreg_table_entry *entry; @@ -2969,7 +3110,7 @@ gen_spreg_h(spreg_table *table, lf *file) } -void +static void gen_spreg_c(spreg_table *table, lf *file) { spreg_table_entry *entry; @@ -3060,9 +3201,10 @@ main(int argc, 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': @@ -3080,9 +3222,12 @@ main(int argc, 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); @@ -3108,6 +3253,7 @@ main(int argc, } lf_close(file); } + real_file_name = NULL; } } return 0; diff --git a/sim/ppc/idecode_insn.h b/sim/ppc/idecode_insn.h deleted file mode 100644 index 4e56b78..0000000 --- a/sim/ppc/idecode_insn.h +++ /dev/null @@ -1,67 +0,0 @@ -/* This file is part of the program psim. - - Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - */ - - -/* - * Interface for the Instruction execution routines - */ - -/* - * Macro's that define the parts of an instruction - */ - -#define FLOATING_POINT_ENABLED_PROGRAM_INTERRUPT \ - program_interrupt(processor, \ - cia, \ - floating_point_enabled_program_interrupt) - -#define ILLEGAL_INSN_PROGRAM_INTERRUPT \ - program_interrupt(processor, \ - cia, \ - illegal_instruction_program_interrupt) -#define PRIVILEGED_INSN_PROGRAM_INTERRUPT \ - program_interrupt(processor, \ - cia, \ - privileged_instruction_program_interrupt) - -#define TRAP_PROGRAM_INTERRUPT \ - program_interrupt(processor, \ - cia, \ - trap_program_interrupt) - -#define FLOATING_POINT_UNAVAILABLE_INTERRUPT \ - floating_point_unavailable_interrupt(processor, \ - cia) - -#define FLOATING_POINT_ASSIST_INTERRUPT \ - floating_point_assist_interrupt(processor, \ - cia) - -#define BREAKPOINT \ - do { \ - ITRACE(trace_breakpoint, \ - ("breakpoint - cia0x%x\n", \ - cia)); \ - cpu_halt(processor, cia, was_trap, 0); \ - } while (0) - -#define SYSTEM_CALL_INTERRUPT \ - system_call_interrupt(processor, \ - cia) diff --git a/sim/ppc/memory_map.c b/sim/ppc/memory_map.c deleted file mode 100644 index af97006..0000000 --- a/sim/ppc/memory_map.c +++ /dev/null @@ -1,355 +0,0 @@ -/* This file is part of the program psim. - - Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - */ - - -#ifndef _MEMORY_MAP_C_ -#define _MEMORY_MAP_C_ - -#ifndef STATIC_INLINE_MEMORY_MAP -#define STATIC_INLINE_MEMORY_MAP STATIC_INLINE -#endif - - -#include "basics.h" -#include "device_tree.h" -#include "memory_map.h" -#include "interrupts.h" - - -typedef struct _memory_mapping memory_mapping; -struct _memory_mapping { - /* ram map */ - void *buffer; - /* device map */ - device_node *device; - device_reader_callback *reader; - device_writer_callback *writer; - /* common */ - unsigned_word base; - unsigned_word bound; - unsigned_word size; - struct _memory_mapping *next; -}; - -struct _memory_map { - memory_mapping *first; -}; - -INLINE_MEMORY_MAP memory_map * -new_memory_map(void) -{ - memory_map *new_map; - new_map = ZALLOC(memory_map); - return new_map; -} - -STATIC_INLINE_MEMORY_MAP void -memory_map_add_memory(memory_map *map, - device_node *device, - device_reader_callback *reader, - device_writer_callback *writer, - void *buffer, - unsigned_word base, - unsigned size) -{ - memory_mapping *new_mapping; - memory_mapping *next_mapping; - memory_mapping **last_mapping; - - /* actually do occasionally get a zero size map */ - if (size == 0) - return; - - new_mapping = ZALLOC(memory_mapping); - - /* ram */ - new_mapping->buffer = buffer; - /* devices */ - new_mapping->device = device; - new_mapping->reader = reader; - new_mapping->writer = writer; - /* common */ - new_mapping->base = base; - new_mapping->size = size; - new_mapping->bound = base + size; - - /* find the insertion point (between last/next) */ - next_mapping = map->first; - last_mapping = &map->first; - while(next_mapping != NULL && next_mapping->bound <= new_mapping->base) { - /* assert: new_mapping->base > all bases before next_mapping */ - /* assert: new_mapping->bound >= all bounds before next_mapping */ - last_mapping = &next_mapping->next; - next_mapping = next_mapping->next; - } - - /* check insertion point correct */ - if (next_mapping != NULL && next_mapping->base < new_mapping->bound) { - error("memory_map_add_callback_memory() internal error - map overlap\n"); - } - - /* insert the new mapping */ - *last_mapping = new_mapping; - new_mapping->next = next_mapping; - -} - - -INLINE_MEMORY_MAP void -memory_map_add_callback_memory(memory_map *map, - device_node *device, - device_reader_callback *reader, - device_writer_callback *writer, - unsigned_word base, - unsigned size) -{ - memory_map_add_memory(map, device, reader, writer, NULL, base, size); -} - -INLINE_MEMORY_MAP void -memory_map_add_raw_memory(memory_map *map, - void *buffer, - unsigned_word base, - unsigned size) -{ - memory_map_add_memory(map, NULL, NULL, NULL, buffer, base, size); -} - - - - -STATIC_INLINE_MEMORY_MAP memory_mapping * -memory_map_find_mapping(memory_map *map, - unsigned_word addr, - unsigned nr_bytes, - int abort, - cpu *processor, - unsigned_word cia) -{ - memory_mapping *mapping = map->first; - ASSERT((addr & (nr_bytes-1)) == 0); - while (1) { - if (addr >= mapping->base - && (addr + nr_bytes) <= mapping->bound) - break; - mapping = mapping->next; - if (mapping == NULL) { - if (abort) { - switch (CURRENT_ENVIRONMENT) { - case VIRTUAL_ENVIRONMENT: - data_storage_interrupt(processor, - cia, - addr, - vea_storage_interrupt, - 0/* doesnt matter */); - break; - default: - error("memory_map_find_mapping() - %s%x%s%s%s%s%s", - "access to undefined address 0x", addr, "\n", - "this code should be passing back up the device tree an\n", - "abort event (with processor attached). Somewhere in\n", - "the device tree this would be caught and either halt,\n", - "interrupt, or reset the processor\n"); - } - return NULL; - } - else - return NULL; - } - } - return mapping; -} - - -STATIC_INLINE_MEMORY_MAP void * -memory_map_translate(memory_mapping *mapping, - unsigned_word addr) -{ - return mapping->buffer + addr - mapping->base; -} - - -INLINE_MEMORY_MAP unsigned -memory_map_read_buffer(memory_map *map, - void *buffer, - unsigned_word addr, - unsigned len, - transfer_mode mode) -{ - unsigned count; - unsigned_1 byte; - for (count = 0; count < len; count++) { - unsigned pos = 0; - unsigned_word raddr = addr + count; - memory_mapping *mapping = - memory_map_find_mapping(map, raddr, 1, - 0/*abort*/, - 0, 0/*processor, cia*/); - if (mapping == NULL) - break; - if (mode == raw_transfer || - CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER) - pos = count; - else if (mode == cooked_transfer) - pos = len-count-1; - else - error("memory_map_read_buffer() - transfer mode unknown\n"); - if (mapping->reader != NULL) - /* hope it doesn't barf */ - byte = mapping->reader(mapping->device, - raddr - mapping->base, - 1, - 0, 0/*processor, cia*/); - else - byte = *(unsigned_1*)memory_map_translate(mapping, - raddr); - ((unsigned_1*)buffer)[pos] = T2H_1(byte); - } - return count; -} - - -INLINE_MEMORY_MAP unsigned -memory_map_write_buffer(memory_map *map, - const void *buffer, - unsigned_word addr, - unsigned len, - transfer_mode mode) -{ - unsigned count; - unsigned_1 byte; - for (count = 0; count < len; count++) { - unsigned pos = 0; - unsigned_word raddr = addr + count; - memory_mapping *mapping = - memory_map_find_mapping(map, raddr, 1, - 0/*abort*/, - 0, 0/*processor, cia*/); - if (mapping == NULL) - break; - if (mode == raw_transfer || - CURRENT_TARGET_BYTE_ORDER == CURRENT_HOST_BYTE_ORDER) - pos = count; - else if (mode == cooked_transfer) - pos = len-count-1; - else - error("memory_map_write_buffer() - transfer mode unknown\n"); - byte = H2T_1(((unsigned_1*)buffer)[pos]); - if (mapping->writer != NULL) - /* hope it doesn't barf */ - mapping->writer(mapping->device, - raddr - mapping->base, - 1, - byte, - 0, 0/*processor, cia*/); - else - *(unsigned_1*)memory_map_translate(mapping, raddr) = byte; - } - return count; -} - - -INLINE_MEMORY_MAP unsigned -memory_map_zero(memory_map *map, - unsigned_word addr, - unsigned len) -{ - unsigned pos; - for (pos = 0; pos < len; pos++) { - unsigned_word raddr = addr + pos; - memory_mapping *mapping = - memory_map_find_mapping(map, raddr, 1, - 0/*abort*/, - 0, 0/*processor, cia*/); - if (mapping == NULL) - break; - if (mapping->writer != NULL) - mapping->writer(mapping->device, - raddr - mapping->base, - 1, - 0, - 0, 0/*processor, cia*/); - else - *(unsigned_1*)memory_map_translate(mapping, raddr) = 0; - } - return pos; -} - - -#define DEFINE_MEMORY_MAP_READ_N(N) \ -INLINE_MEMORY_MAP unsigned_##N \ -memory_map_read_##N(memory_map *map, \ - unsigned_word addr, \ - cpu *processor, \ - unsigned_word cia) \ -{ \ - memory_mapping *mapping = memory_map_find_mapping(map, addr, \ - sizeof(unsigned_##N), \ - 1, \ - processor, \ - cia); \ - if (WITH_CALLBACK_MEMORY && mapping->reader != NULL) \ - return ((unsigned_##N) \ - mapping->reader(mapping->device, \ - addr - mapping->base, \ - sizeof(unsigned_##N), \ - processor, \ - cia)); \ - else \ - return T2H_##N(*(unsigned_##N*)memory_map_translate(mapping, addr)); \ -} - -DEFINE_MEMORY_MAP_READ_N(1) -DEFINE_MEMORY_MAP_READ_N(2) -DEFINE_MEMORY_MAP_READ_N(4) -DEFINE_MEMORY_MAP_READ_N(8) -DEFINE_MEMORY_MAP_READ_N(word) - -#define DEFINE_MEMORY_MAP_WRITE_N(N) \ -INLINE_MEMORY_MAP void \ -memory_map_write_##N(memory_map *map, \ - unsigned_word addr, \ - unsigned_##N val, \ - cpu *processor, \ - unsigned_word cia) \ -{ \ - memory_mapping *mapping = memory_map_find_mapping(map, addr, \ - sizeof(unsigned_##N), \ - 1, \ - processor, \ - cia); \ - if (WITH_CALLBACK_MEMORY && mapping->writer != NULL) \ - mapping->writer(mapping->device, \ - addr - mapping->base, \ - sizeof(unsigned_##N), \ - val, \ - processor, \ - cia); \ - else \ - *(unsigned_##N*)memory_map_translate(mapping, addr) = H2T_##N(val); \ -} - -DEFINE_MEMORY_MAP_WRITE_N(1) -DEFINE_MEMORY_MAP_WRITE_N(2) -DEFINE_MEMORY_MAP_WRITE_N(4) -DEFINE_MEMORY_MAP_WRITE_N(8) -DEFINE_MEMORY_MAP_WRITE_N(word) - -#endif /* _MEMORY_MAP_C_ */ diff --git a/sim/ppc/memory_map.h b/sim/ppc/memory_map.h deleted file mode 100644 index c197f43..0000000 --- a/sim/ppc/memory_map.h +++ /dev/null @@ -1,126 +0,0 @@ -/* This file is part of the program psim. - - Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - */ - - -#ifndef _MEMORY_MAP_H_ -#define _MEMORY_MAP_H_ - -#ifndef INLINE_MEMORY_MAP -#define INLINE_MEMORY_MAP -#endif - -/* basic types */ - -typedef struct _memory_map memory_map; - - -/* constructor */ - -INLINE_MEMORY_MAP memory_map *new_memory_map -(void); - - -/* operators to add memory to a memory map - - callback-memory: - - includes a callback routine that is called upon for the data. - Useful when modeling memory mapped devices. - - raw-memory: - - normal base and bound memory map used to model ram or mapped memory - pages */ - -INLINE_MEMORY_MAP void memory_map_add_callback_memory -(memory_map *map, - device_node *device, - device_reader_callback *reader, - device_writer_callback *writer, - unsigned_word base, - unsigned size); /* host limited */ - -INLINE_MEMORY_MAP void memory_map_add_raw_memory -(memory_map *map, - void *buffer, - unsigned_word base, - unsigned size/*host limited*/); - - -/* Variable sized read/write/zero: - - Transfer (zero) a variable size block of data between the host and - target (possibly byte swapping it). Should any problems occure, - the number of bytes actually transfered is returned. */ - -INLINE_MEMORY_MAP unsigned memory_map_read_buffer -(memory_map *map, - void *buffer, - unsigned_word addr, - unsigned len, - transfer_mode mode); - -INLINE_MEMORY_MAP unsigned memory_map_write_buffer -(memory_map *map, - const void *buffer, - unsigned_word addr, - unsigned len, - transfer_mode mode); - -INLINE_MEMORY_MAP unsigned memory_map_zero -(memory_map *map, - unsigned_word addr, - unsigned len); - - -/* Fixed sized read/write: - - Transfer a fixed amout of memory between the host and target. The - memory always being translated and the operation always aborting - should a problem occure */ - -#define DECLARE_MEMORY_MAP_WRITE_N(N) \ -INLINE_MEMORY_MAP void memory_map_write_##N \ -(memory_map *map, \ - unsigned_word addr, \ - unsigned_##N val, \ - cpu *processor, \ - unsigned_word cia); - -DECLARE_MEMORY_MAP_WRITE_N(1) -DECLARE_MEMORY_MAP_WRITE_N(2) -DECLARE_MEMORY_MAP_WRITE_N(4) -DECLARE_MEMORY_MAP_WRITE_N(8) -DECLARE_MEMORY_MAP_WRITE_N(word) - -#define DECLARE_MEMORY_MAP_READ_N(N) \ -INLINE_MEMORY_MAP unsigned_##N memory_map_read_##N \ -(memory_map *map, \ - unsigned_word addr, \ - cpu *processor, \ - unsigned_word cia); - -DECLARE_MEMORY_MAP_READ_N(1) -DECLARE_MEMORY_MAP_READ_N(2) -DECLARE_MEMORY_MAP_READ_N(4) -DECLARE_MEMORY_MAP_READ_N(8) -DECLARE_MEMORY_MAP_READ_N(word) - -#endif diff --git a/sim/ppc/ppc-endian.h b/sim/ppc/ppc-endian.h index 6ac0601..496d36a 100644 --- a/sim/ppc/ppc-endian.h +++ b/sim/ppc/ppc-endian.h @@ -184,10 +184,11 @@ do { \ Byte swap a quantity the size of the targets word */ -#if WITH_64BIT_TARGET +#if (WITH_TARGET_WORD_BITSIZE == 64) #define H2T_word(X) H2T_8(X) #define T2H_word(X) T2H_8(X) -#else +#endif +#if (WITH_TARGET_WORD_BITSIZE == 32) #define H2T_word(X) H2T_4(X) #define T2H_word(X) T2H_4(X) #endif diff --git a/sim/ppc/system.c b/sim/ppc/system.c index c032688..25ea8eb 100644 --- a/sim/ppc/system.c +++ b/sim/ppc/system.c @@ -30,6 +30,7 @@ #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 */ @@ -45,347 +46,675 @@ extern int errno; #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_ */ diff --git a/sim/ppc/system.h b/sim/ppc/system.h index 4a0df87..709d5c5 100644 --- a/sim/ppc/system.h +++ b/sim/ppc/system.h @@ -22,7 +22,11 @@ #ifndef _SYSTEM_H_ #define _SYSTEM_H_ -void system_call +#ifndef INLINE_SYSTEM +#define INLINE_SYSTEM +#endif + +INLINE_SYSTEM void system_call (cpu *processor, unsigned_word cia); |