/* This file is part of the program psim. Copyright (C) 1994-1995, Andrew Cagney 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 _CORE_C_ #define _CORE_C_ #ifndef STATIC_INLINE_CORE #define STATIC_INLINE_CORE STATIC_INLINE #endif #include "basics.h" #include "device_tree.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 { 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 core_init(core *memory) { core_map_types access_type; for (access_type = 0; access_type < nr_core_map_types; access_type++) { core_map *map = memory->map + access_type; /* blow away old mappings */ core_mapping *curr = map->first; while (curr != NULL) { core_mapping *tbd = curr; curr = curr->next; if (tbd->free_buffer) { ASSERT(tbd->buffer != NULL); zfree(tbd->buffer); } zfree(tbd); } 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; } } /* the core has three sub mappings that the more efficient read/write fixed quantity functions use */ INLINE_CORE core_map * core_readable(core *memory) { return memory->map + core_read_map; } INLINE_CORE core_map * core_writeable(core *memory) { return memory->map + core_write_map; } INLINE_CORE core_map * core_executable(core *memory) { return memory->map + core_execute_map; } 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_mapping *new_mapping = ZALLOC(core_mapping); switch (attach) { case attach_default: case attach_callback: new_mapping->device = device; new_mapping->reader = device->callback->io_read_buffer; new_mapping->writer = device->callback->io_write_buffer; break; case attach_raw_memory: new_mapping->buffer = buffer; new_mapping->free_buffer = free_buffer; break; default: error("new_core_mapping() - internal error - unknown attach type %d\n", attach); } /* common */ new_mapping->address_space = address_space; new_mapping->base = addr; new_mapping->nr_bytes = nr_bytes; new_mapping->bound = addr + (nr_bytes - 1); return new_mapping; } STATIC_INLINE_CORE void 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*/ { 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); } 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; } /* 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_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*/ { 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 */ } 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 */ { 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 * core_translate(core_mapping *mapping, unsigned_word addr) { return mapping->buffer + addr - mapping->base; } INLINE_CORE unsigned core_map_read_buffer(core_map *map, void *buffer, unsigned_word addr, unsigned len) { unsigned count; unsigned_1 byte; for (count = 0; count < len; count++) { unsigned_word raddr = addr + count; core_mapping *mapping = core_map_find_mapping(map, raddr, 1, NULL, /*processor*/ 0, /*cia*/ 0); /*dont-abort*/ if (mapping == NULL) break; if (mapping->reader != NULL) { if (mapping->reader(mapping->device, &byte, mapping->address_space, raddr - mapping->base, 1, /* nr_bytes */ 0, /*processor*/ 0 /*cpu*/) != 1) break; } else byte = *(unsigned_1*)core_translate(mapping, raddr); ((unsigned_1*)buffer)[count] = T2H_1(byte); } return count; } INLINE_CORE unsigned core_map_write_buffer(core_map *map, const void *buffer, unsigned_word addr, unsigned len) { unsigned count; unsigned_1 byte; for (count = 0; count < len; count++) { unsigned_word raddr = addr + count; core_mapping *mapping = core_map_find_mapping(map, raddr, 1, NULL, /*processor*/ 0, /*cia*/ 0); /*dont-abort*/ if (mapping == NULL) break; byte = H2T_1(((unsigned_1*)buffer)[count]); if (mapping->writer != NULL) { if (mapping->writer(mapping->device, &byte, mapping->address_space, raddr - mapping->base, 1, /*nr_bytes*/ 0, /*processor*/ 0 /*cpu*/) != 1) break; } else *(unsigned_1*)core_translate(mapping, raddr) = byte; } return count; } /* Top level core(root) device: core@garbage The core device captures incomming dma requests and changes them to outgoing io requests. */ STATIC_INLINE_CORE void core_init_callback(const device *me, psim *system) { core *memory = (core*)me->data; core_init(memory); } STATIC_INLINE_CORE void core_attach_address_callback(const device *me, const char *name, attach_type attach, int address_space, unsigned_word addr, unsigned nr_bytes, access_type access, const device *who) /*callback/default*/ { core *memory = (core*)me->data; unsigned_word device_address; if (address_space != 0) error("core_attach_address_callback() invalid address space\n"); core_attach(memory, attach, address_space, access, addr, nr_bytes, who); } STATIC_INLINE_CORE unsigned core_dma_read_buffer_callback(const device *me, void *target, int address_space, unsigned_word offset, unsigned nr_bytes) { core *memory = (core*)me->data; return core_map_read_buffer(core_readable(memory), target, offset, nr_bytes); } STATIC_INLINE_CORE unsigned core_dma_write_buffer_callback(const device *me, const void *source, int address_space, unsigned_word offset, unsigned nr_bytes, int violate_read_only_section) { core *memory = (core*)me->data; core_map *map = (violate_read_only_section ? core_readable(memory) : core_writeable(memory)); return core_map_write_buffer(map, source, offset, nr_bytes); } static device_callbacks const core_callbacks = { core_init_callback, core_attach_address_callback, unimp_device_detach_address, unimp_device_io_read_buffer, unimp_device_io_write_buffer, core_dma_read_buffer_callback, core_dma_write_buffer_callback, unimp_device_attach_interrupt, unimp_device_detach_interrupt, unimp_device_interrupt, unimp_device_interrupt_ack, unimp_device_ioctl, }; INLINE_CORE const device * core_device_create(core *memory) { return device_create_from("core", memory, &core_callbacks, NULL); } /* define the read/write 1/2/4/8/word functions */ #undef N #define N 1 #include "core_n.h" #undef N #define N 2 #include "core_n.h" #undef N #define N 4 #include "core_n.h" #undef N #define N 8 #include "core_n.h" #undef N #define N word #include "core_n.h" #endif /* _CORE_C_ */