14e98e3e1Schristos /* The common simulator framework for GDB, the GNU Debugger. 24e98e3e1Schristos 3*88241920Schristos Copyright 2002-2024 Free Software Foundation, Inc. 44e98e3e1Schristos 54e98e3e1Schristos Contributed by Andrew Cagney and Red Hat. 64e98e3e1Schristos 74e98e3e1Schristos This file is part of GDB. 84e98e3e1Schristos 94e98e3e1Schristos This program is free software; you can redistribute it and/or modify 104e98e3e1Schristos it under the terms of the GNU General Public License as published by 114e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 124e98e3e1Schristos (at your option) any later version. 134e98e3e1Schristos 144e98e3e1Schristos This program is distributed in the hope that it will be useful, 154e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 164e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 174e98e3e1Schristos GNU General Public License for more details. 184e98e3e1Schristos 194e98e3e1Schristos You should have received a copy of the GNU General Public License 204e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 214e98e3e1Schristos 224e98e3e1Schristos 234e98e3e1Schristos #ifndef SIM_CORE_C 244e98e3e1Schristos #define SIM_CORE_C 254e98e3e1Schristos 264b169a6bSchristos /* This must come before any other includes. */ 274b169a6bSchristos #include "defs.h" 284b169a6bSchristos 294b169a6bSchristos #include <stdlib.h> 304b169a6bSchristos 314b169a6bSchristos #include "libiberty.h" 324b169a6bSchristos 334e98e3e1Schristos #include "sim-main.h" 344e98e3e1Schristos #include "sim-assert.h" 354b169a6bSchristos #include "sim-signal.h" 364e98e3e1Schristos 374e98e3e1Schristos #if (WITH_HW) 384e98e3e1Schristos #include "sim-hw.h" 394e98e3e1Schristos #endif 404e98e3e1Schristos 414e98e3e1Schristos /* "core" module install handler. 424e98e3e1Schristos 434e98e3e1Schristos This is called via sim_module_install to install the "core" 444e98e3e1Schristos subsystem into the simulator. */ 454e98e3e1Schristos 464e98e3e1Schristos #if EXTERN_SIM_CORE_P 474e98e3e1Schristos static MODULE_INIT_FN sim_core_init; 484e98e3e1Schristos static MODULE_UNINSTALL_FN sim_core_uninstall; 494e98e3e1Schristos #endif 504e98e3e1Schristos 514e98e3e1Schristos #if EXTERN_SIM_CORE_P 524e98e3e1Schristos SIM_RC 534e98e3e1Schristos sim_core_install (SIM_DESC sd) 544e98e3e1Schristos { 554e98e3e1Schristos SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 564e98e3e1Schristos 574e98e3e1Schristos /* establish the other handlers */ 584e98e3e1Schristos sim_module_add_uninstall_fn (sd, sim_core_uninstall); 594e98e3e1Schristos sim_module_add_init_fn (sd, sim_core_init); 604e98e3e1Schristos 614e98e3e1Schristos /* establish any initial data structures - none */ 624e98e3e1Schristos return SIM_RC_OK; 634e98e3e1Schristos } 644e98e3e1Schristos #endif 654e98e3e1Schristos 664e98e3e1Schristos 674e98e3e1Schristos /* Uninstall the "core" subsystem from the simulator. */ 684e98e3e1Schristos 694e98e3e1Schristos #if EXTERN_SIM_CORE_P 704e98e3e1Schristos static void 714e98e3e1Schristos sim_core_uninstall (SIM_DESC sd) 724e98e3e1Schristos { 734e98e3e1Schristos sim_core *core = STATE_CORE (sd); 744e98e3e1Schristos unsigned map; 754e98e3e1Schristos /* blow away any mappings */ 764e98e3e1Schristos for (map = 0; map < nr_maps; map++) { 774e98e3e1Schristos sim_core_mapping *curr = core->common.map[map].first; 784e98e3e1Schristos while (curr != NULL) { 794e98e3e1Schristos sim_core_mapping *tbd = curr; 804e98e3e1Schristos curr = curr->next; 814e98e3e1Schristos if (tbd->free_buffer != NULL) { 824e98e3e1Schristos SIM_ASSERT (tbd->buffer != NULL); 834e98e3e1Schristos free (tbd->free_buffer); 844e98e3e1Schristos } 854e98e3e1Schristos free (tbd); 864e98e3e1Schristos } 874e98e3e1Schristos core->common.map[map].first = NULL; 884e98e3e1Schristos } 894e98e3e1Schristos } 904e98e3e1Schristos #endif 914e98e3e1Schristos 924e98e3e1Schristos 934e98e3e1Schristos #if EXTERN_SIM_CORE_P 944e98e3e1Schristos static SIM_RC 954e98e3e1Schristos sim_core_init (SIM_DESC sd) 964e98e3e1Schristos { 974e98e3e1Schristos /* Nothing to do */ 984e98e3e1Schristos return SIM_RC_OK; 994e98e3e1Schristos } 1004e98e3e1Schristos #endif 1014e98e3e1Schristos 1024e98e3e1Schristos 1034e98e3e1Schristos 1044e98e3e1Schristos #ifndef SIM_CORE_SIGNAL 1054e98e3e1Schristos #define SIM_CORE_SIGNAL(SD,CPU,CIA,MAP,NR_BYTES,ADDR,TRANSFER,ERROR) \ 1064e98e3e1Schristos sim_core_signal ((SD), (CPU), (CIA), (MAP), (NR_BYTES), (ADDR), (TRANSFER), (ERROR)) 1074e98e3e1Schristos #endif 1084e98e3e1Schristos 1094e98e3e1Schristos #if EXTERN_SIM_CORE_P 1104e98e3e1Schristos void 1114e98e3e1Schristos sim_core_signal (SIM_DESC sd, 1124e98e3e1Schristos sim_cpu *cpu, 1134e98e3e1Schristos sim_cia cia, 1144e98e3e1Schristos unsigned map, 1154e98e3e1Schristos int nr_bytes, 1164e98e3e1Schristos address_word addr, 1174e98e3e1Schristos transfer_type transfer, 1184e98e3e1Schristos sim_core_signals sig) 1194e98e3e1Schristos { 1204e98e3e1Schristos const char *copy = (transfer == read_transfer ? "read" : "write"); 1214e98e3e1Schristos address_word ip = CIA_ADDR (cia); 1224e98e3e1Schristos switch (sig) 1234e98e3e1Schristos { 1244e98e3e1Schristos case sim_core_unmapped_signal: 1254e98e3e1Schristos sim_io_eprintf (sd, "core: %d byte %s to unmapped address 0x%lx at 0x%lx\n", 1264e98e3e1Schristos nr_bytes, copy, (unsigned long) addr, (unsigned long) ip); 1274e98e3e1Schristos sim_engine_halt (sd, cpu, NULL, cia, sim_stopped, SIM_SIGSEGV); 1284e98e3e1Schristos break; 1294e98e3e1Schristos case sim_core_unaligned_signal: 1304e98e3e1Schristos sim_io_eprintf (sd, "core: %d byte misaligned %s to address 0x%lx at 0x%lx\n", 1314e98e3e1Schristos nr_bytes, copy, (unsigned long) addr, (unsigned long) ip); 1324e98e3e1Schristos sim_engine_halt (sd, cpu, NULL, cia, sim_stopped, SIM_SIGBUS); 1334e98e3e1Schristos break; 1344e98e3e1Schristos default: 1354e98e3e1Schristos sim_engine_abort (sd, cpu, cia, 1364e98e3e1Schristos "sim_core_signal - internal error - bad switch"); 1374e98e3e1Schristos } 1384e98e3e1Schristos } 1394e98e3e1Schristos #endif 1404e98e3e1Schristos 1414e98e3e1Schristos 1424e98e3e1Schristos #if EXTERN_SIM_CORE_P 1434e98e3e1Schristos static sim_core_mapping * 1444e98e3e1Schristos new_sim_core_mapping (SIM_DESC sd, 1454e98e3e1Schristos int level, 1464e98e3e1Schristos int space, 1474e98e3e1Schristos address_word addr, 1484e98e3e1Schristos address_word nr_bytes, 1494e98e3e1Schristos unsigned modulo, 1504e98e3e1Schristos struct hw *device, 1514e98e3e1Schristos void *buffer, 1524e98e3e1Schristos void *free_buffer) 1534e98e3e1Schristos { 1544e98e3e1Schristos sim_core_mapping *new_mapping = ZALLOC (sim_core_mapping); 1554e98e3e1Schristos /* common */ 1564e98e3e1Schristos new_mapping->level = level; 1574e98e3e1Schristos new_mapping->space = space; 1584e98e3e1Schristos new_mapping->base = addr; 1594e98e3e1Schristos new_mapping->nr_bytes = nr_bytes; 1604e98e3e1Schristos new_mapping->bound = addr + (nr_bytes - 1); 1614e98e3e1Schristos new_mapping->mask = modulo - 1; 1624e98e3e1Schristos new_mapping->buffer = buffer; 1634e98e3e1Schristos new_mapping->free_buffer = free_buffer; 1644e98e3e1Schristos new_mapping->device = device; 1654e98e3e1Schristos return new_mapping; 1664e98e3e1Schristos } 1674e98e3e1Schristos #endif 1684e98e3e1Schristos 1694e98e3e1Schristos 1704e98e3e1Schristos #if EXTERN_SIM_CORE_P 1714e98e3e1Schristos static void 1724e98e3e1Schristos sim_core_map_attach (SIM_DESC sd, 1734e98e3e1Schristos sim_core_map *access_map, 1744e98e3e1Schristos int level, 1754e98e3e1Schristos int space, 1764e98e3e1Schristos address_word addr, 1774e98e3e1Schristos address_word nr_bytes, 1784e98e3e1Schristos unsigned modulo, 1794e98e3e1Schristos struct hw *client, /*callback/default*/ 1804e98e3e1Schristos void *buffer, /*raw_memory*/ 1814e98e3e1Schristos void *free_buffer) /*raw_memory*/ 1824e98e3e1Schristos { 1834e98e3e1Schristos /* find the insertion point for this additional mapping and then 1844e98e3e1Schristos insert */ 1854e98e3e1Schristos sim_core_mapping *next_mapping; 1864e98e3e1Schristos sim_core_mapping **last_mapping; 1874e98e3e1Schristos 1884e98e3e1Schristos SIM_ASSERT ((client == NULL) != (buffer == NULL)); 1894e98e3e1Schristos SIM_ASSERT ((client == NULL) >= (free_buffer != NULL)); 1904e98e3e1Schristos 1914e98e3e1Schristos /* actually do occasionally get a zero size map */ 1924e98e3e1Schristos if (nr_bytes == 0) 1934e98e3e1Schristos { 1944e98e3e1Schristos #if (WITH_HW) 1954e98e3e1Schristos sim_hw_abort (sd, client, "called on sim_core_map_attach with size zero"); 1964e98e3e1Schristos #endif 1974e98e3e1Schristos sim_io_error (sd, "called on sim_core_map_attach with size zero"); 1984e98e3e1Schristos } 1994e98e3e1Schristos 2004e98e3e1Schristos /* find the insertion point (between last/next) */ 2014e98e3e1Schristos next_mapping = access_map->first; 2024e98e3e1Schristos last_mapping = &access_map->first; 2034e98e3e1Schristos while (next_mapping != NULL 2044e98e3e1Schristos && (next_mapping->level < level 2054e98e3e1Schristos || (next_mapping->level == level 2064e98e3e1Schristos && next_mapping->bound < addr))) 2074e98e3e1Schristos { 2084e98e3e1Schristos /* provided levels are the same */ 2094e98e3e1Schristos /* assert: next_mapping->base > all bases before next_mapping */ 2104e98e3e1Schristos /* assert: next_mapping->bound >= all bounds before next_mapping */ 2114e98e3e1Schristos last_mapping = &next_mapping->next; 2124e98e3e1Schristos next_mapping = next_mapping->next; 2134e98e3e1Schristos } 2144e98e3e1Schristos 2154e98e3e1Schristos /* check insertion point correct */ 2164e98e3e1Schristos SIM_ASSERT (next_mapping == NULL || next_mapping->level >= level); 2174e98e3e1Schristos if (next_mapping != NULL && next_mapping->level == level 2184e98e3e1Schristos && next_mapping->base < (addr + (nr_bytes - 1))) 2194e98e3e1Schristos { 2204e98e3e1Schristos #if WITH_HW 2214e98e3e1Schristos sim_hw_abort (sd, client, "memory map %d:0x%lx..0x%lx (%ld bytes) overlaps %d:0x%lx..0x%lx (%ld bytes)", 2224e98e3e1Schristos space, 2234e98e3e1Schristos (long) addr, 2244e98e3e1Schristos (long) (addr + (nr_bytes - 1)), 2254e98e3e1Schristos (long) nr_bytes, 2264e98e3e1Schristos next_mapping->space, 2274e98e3e1Schristos (long) next_mapping->base, 2284e98e3e1Schristos (long) next_mapping->bound, 2294e98e3e1Schristos (long) next_mapping->nr_bytes); 2304e98e3e1Schristos #endif 2314e98e3e1Schristos sim_io_error (sd, "memory map %d:0x%lx..0x%lx (%ld bytes) overlaps %d:0x%lx..0x%lx (%ld bytes)", 2324e98e3e1Schristos space, 2334e98e3e1Schristos (long) addr, 2344e98e3e1Schristos (long) (addr + (nr_bytes - 1)), 2354e98e3e1Schristos (long) nr_bytes, 2364e98e3e1Schristos next_mapping->space, 2374e98e3e1Schristos (long) next_mapping->base, 2384e98e3e1Schristos (long) next_mapping->bound, 2394e98e3e1Schristos (long) next_mapping->nr_bytes); 2404e98e3e1Schristos } 2414e98e3e1Schristos 2424e98e3e1Schristos /* create/insert the new mapping */ 2434e98e3e1Schristos *last_mapping = new_sim_core_mapping (sd, 2444e98e3e1Schristos level, 2454e98e3e1Schristos space, addr, nr_bytes, modulo, 2464e98e3e1Schristos client, buffer, free_buffer); 2474e98e3e1Schristos (*last_mapping)->next = next_mapping; 2484e98e3e1Schristos } 2494e98e3e1Schristos #endif 2504e98e3e1Schristos 2514e98e3e1Schristos 2524e98e3e1Schristos /* Attach memory or a memory mapped device to the simulator. 2534e98e3e1Schristos See sim-core.h for a full description. */ 2544e98e3e1Schristos 2554e98e3e1Schristos #if EXTERN_SIM_CORE_P 2564e98e3e1Schristos void 2574e98e3e1Schristos sim_core_attach (SIM_DESC sd, 2584e98e3e1Schristos sim_cpu *cpu, 2594e98e3e1Schristos int level, 2604e98e3e1Schristos unsigned mapmask, 2614e98e3e1Schristos int space, 2624e98e3e1Schristos address_word addr, 2634e98e3e1Schristos address_word nr_bytes, 2644e98e3e1Schristos unsigned modulo, 2654e98e3e1Schristos struct hw *client, 2664e98e3e1Schristos void *optional_buffer) 2674e98e3e1Schristos { 2684e98e3e1Schristos sim_core *memory = STATE_CORE (sd); 2694e98e3e1Schristos unsigned map; 2704e98e3e1Schristos void *buffer; 2714e98e3e1Schristos void *free_buffer; 2724e98e3e1Schristos 2734e98e3e1Schristos /* check for for attempt to use unimplemented per-processor core map */ 2744e98e3e1Schristos if (cpu != NULL) 2754e98e3e1Schristos sim_io_error (sd, "sim_core_map_attach - processor specific memory map not yet supported"); 2764e98e3e1Schristos 2774e98e3e1Schristos if (client != NULL && modulo != 0) 2784e98e3e1Schristos { 2794e98e3e1Schristos #if (WITH_HW) 2804e98e3e1Schristos sim_hw_abort (sd, client, "sim_core_attach - internal error - modulo and callback memory conflict"); 2814e98e3e1Schristos #endif 2824e98e3e1Schristos sim_io_error (sd, "sim_core_attach - internal error - modulo and callback memory conflict"); 2834e98e3e1Schristos } 2844e98e3e1Schristos if (modulo != 0) 2854e98e3e1Schristos { 2864e98e3e1Schristos unsigned mask = modulo - 1; 2874e98e3e1Schristos /* any zero bits */ 2884b169a6bSchristos while (mask >= sizeof (uint64_t)) /* minimum modulo */ 2894e98e3e1Schristos { 2904e98e3e1Schristos if ((mask & 1) == 0) 2914e98e3e1Schristos mask = 0; 2924e98e3e1Schristos else 2934e98e3e1Schristos mask >>= 1; 2944e98e3e1Schristos } 2954b169a6bSchristos if (mask != sizeof (uint64_t) - 1) 2964e98e3e1Schristos { 2974e98e3e1Schristos #if (WITH_HW) 2984e98e3e1Schristos sim_hw_abort (sd, client, "sim_core_attach - internal error - modulo %lx not power of two", (long) modulo); 2994e98e3e1Schristos #endif 3004e98e3e1Schristos sim_io_error (sd, "sim_core_attach - internal error - modulo %lx not power of two", (long) modulo); 3014e98e3e1Schristos } 3024e98e3e1Schristos } 3034e98e3e1Schristos 3044e98e3e1Schristos /* verify consistency between device and buffer */ 3054e98e3e1Schristos if (client != NULL && optional_buffer != NULL) 3064e98e3e1Schristos { 3074e98e3e1Schristos #if (WITH_HW) 3084e98e3e1Schristos sim_hw_abort (sd, client, "sim_core_attach - internal error - conflicting buffer and attach arguments"); 3094e98e3e1Schristos #endif 3104e98e3e1Schristos sim_io_error (sd, "sim_core_attach - internal error - conflicting buffer and attach arguments"); 3114e98e3e1Schristos } 3124e98e3e1Schristos if (client == NULL) 3134e98e3e1Schristos { 3144e98e3e1Schristos if (optional_buffer == NULL) 3154e98e3e1Schristos { 3164b169a6bSchristos int padding = (addr % sizeof (uint64_t)); 3174e98e3e1Schristos unsigned long bytes = (modulo == 0 ? nr_bytes : modulo) + padding; 3184e98e3e1Schristos free_buffer = zalloc (bytes); 3194e98e3e1Schristos buffer = (char*) free_buffer + padding; 3204e98e3e1Schristos } 3214e98e3e1Schristos else 3224e98e3e1Schristos { 3234e98e3e1Schristos buffer = optional_buffer; 3244e98e3e1Schristos free_buffer = NULL; 3254e98e3e1Schristos } 3264e98e3e1Schristos } 3274e98e3e1Schristos else 3284e98e3e1Schristos { 3294e98e3e1Schristos /* a device */ 3304e98e3e1Schristos buffer = NULL; 3314e98e3e1Schristos free_buffer = NULL; 3324e98e3e1Schristos } 3334e98e3e1Schristos 3344e98e3e1Schristos /* attach the region to all applicable access maps */ 3354e98e3e1Schristos for (map = 0; 3364e98e3e1Schristos map < nr_maps; 3374e98e3e1Schristos map++) 3384e98e3e1Schristos { 3394e98e3e1Schristos if (mapmask & (1 << map)) 3404e98e3e1Schristos { 3414e98e3e1Schristos sim_core_map_attach (sd, &memory->common.map[map], 3424e98e3e1Schristos level, space, addr, nr_bytes, modulo, 3434e98e3e1Schristos client, buffer, free_buffer); 3444e98e3e1Schristos free_buffer = NULL; 3454e98e3e1Schristos } 3464e98e3e1Schristos } 3474e98e3e1Schristos 3484e98e3e1Schristos /* Just copy this map to each of the processor specific data structures. 3494e98e3e1Schristos FIXME - later this will be replaced by true processor specific 3504e98e3e1Schristos maps. */ 3514e98e3e1Schristos { 3524e98e3e1Schristos int i; 3534e98e3e1Schristos for (i = 0; i < MAX_NR_PROCESSORS; i++) 3544e98e3e1Schristos { 3554e98e3e1Schristos CPU_CORE (STATE_CPU (sd, i))->common = STATE_CORE (sd)->common; 3564e98e3e1Schristos } 3574e98e3e1Schristos } 3584e98e3e1Schristos } 3594e98e3e1Schristos #endif 3604e98e3e1Schristos 3614e98e3e1Schristos 3624e98e3e1Schristos /* Remove any memory reference related to this address */ 3634e98e3e1Schristos #if EXTERN_SIM_CORE_P 3644e98e3e1Schristos static void 3654e98e3e1Schristos sim_core_map_detach (SIM_DESC sd, 3664e98e3e1Schristos sim_core_map *access_map, 3674e98e3e1Schristos int level, 3684e98e3e1Schristos int space, 3694e98e3e1Schristos address_word addr) 3704e98e3e1Schristos { 3714e98e3e1Schristos sim_core_mapping **entry; 3724e98e3e1Schristos for (entry = &access_map->first; 3734e98e3e1Schristos (*entry) != NULL; 3744e98e3e1Schristos entry = &(*entry)->next) 3754e98e3e1Schristos { 3764e98e3e1Schristos if ((*entry)->base == addr 3774e98e3e1Schristos && (*entry)->level == level 3784e98e3e1Schristos && (*entry)->space == space) 3794e98e3e1Schristos { 3804e98e3e1Schristos sim_core_mapping *dead = (*entry); 3814e98e3e1Schristos (*entry) = dead->next; 3824e98e3e1Schristos if (dead->free_buffer != NULL) 3834e98e3e1Schristos free (dead->free_buffer); 3844e98e3e1Schristos free (dead); 3854e98e3e1Schristos return; 3864e98e3e1Schristos } 3874e98e3e1Schristos } 3884e98e3e1Schristos } 3894e98e3e1Schristos #endif 3904e98e3e1Schristos 3914e98e3e1Schristos #if EXTERN_SIM_CORE_P 3924e98e3e1Schristos void 3934e98e3e1Schristos sim_core_detach (SIM_DESC sd, 3944e98e3e1Schristos sim_cpu *cpu, 3954e98e3e1Schristos int level, 3964e98e3e1Schristos int address_space, 3974e98e3e1Schristos address_word addr) 3984e98e3e1Schristos { 3994e98e3e1Schristos sim_core *memory = STATE_CORE (sd); 4004e98e3e1Schristos unsigned map; 4014e98e3e1Schristos for (map = 0; map < nr_maps; map++) 4024e98e3e1Schristos { 4034e98e3e1Schristos sim_core_map_detach (sd, &memory->common.map[map], 4044e98e3e1Schristos level, address_space, addr); 4054e98e3e1Schristos } 4064e98e3e1Schristos /* Just copy this update to each of the processor specific data 4074e98e3e1Schristos structures. FIXME - later this will be replaced by true 4084e98e3e1Schristos processor specific maps. */ 4094e98e3e1Schristos { 4104e98e3e1Schristos int i; 4114e98e3e1Schristos for (i = 0; i < MAX_NR_PROCESSORS; i++) 4124e98e3e1Schristos { 4134e98e3e1Schristos CPU_CORE (STATE_CPU (sd, i))->common = STATE_CORE (sd)->common; 4144e98e3e1Schristos } 4154e98e3e1Schristos } 4164e98e3e1Schristos } 4174e98e3e1Schristos #endif 4184e98e3e1Schristos 4194e98e3e1Schristos 4204e98e3e1Schristos STATIC_INLINE_SIM_CORE\ 4214e98e3e1Schristos (sim_core_mapping *) 4224e98e3e1Schristos sim_core_find_mapping (sim_core_common *core, 4234e98e3e1Schristos unsigned map, 4244e98e3e1Schristos address_word addr, 4254e98e3e1Schristos unsigned nr_bytes, 4264e98e3e1Schristos transfer_type transfer, 4274e98e3e1Schristos int abort, /*either 0 or 1 - hint to inline/-O */ 4284e98e3e1Schristos sim_cpu *cpu, /* abort => cpu != NULL */ 4294e98e3e1Schristos sim_cia cia) 4304e98e3e1Schristos { 4314e98e3e1Schristos sim_core_mapping *mapping = core->map[map].first; 4324e98e3e1Schristos ASSERT ((addr & (nr_bytes - 1)) == 0); /* must be aligned */ 4334e98e3e1Schristos ASSERT ((addr + (nr_bytes - 1)) >= addr); /* must not wrap */ 4344e98e3e1Schristos ASSERT (!abort || cpu != NULL); /* abort needs a non null CPU */ 4354e98e3e1Schristos while (mapping != NULL) 4364e98e3e1Schristos { 4374e98e3e1Schristos if (addr >= mapping->base 4384e98e3e1Schristos && (addr + (nr_bytes - 1)) <= mapping->bound) 4394e98e3e1Schristos return mapping; 4404e98e3e1Schristos mapping = mapping->next; 4414e98e3e1Schristos } 4424e98e3e1Schristos if (abort) 4434e98e3e1Schristos { 4444e98e3e1Schristos SIM_CORE_SIGNAL (CPU_STATE (cpu), cpu, cia, map, nr_bytes, addr, transfer, 4454e98e3e1Schristos sim_core_unmapped_signal); 4464e98e3e1Schristos } 4474e98e3e1Schristos return NULL; 4484e98e3e1Schristos } 4494e98e3e1Schristos 4504e98e3e1Schristos 4514e98e3e1Schristos STATIC_INLINE_SIM_CORE\ 4524e98e3e1Schristos (void *) 4534e98e3e1Schristos sim_core_translate (sim_core_mapping *mapping, 4544e98e3e1Schristos address_word addr) 4554e98e3e1Schristos { 4564b169a6bSchristos return (void *)((uint8_t *) mapping->buffer 4574e98e3e1Schristos + ((addr - mapping->base) & mapping->mask)); 4584e98e3e1Schristos } 4594e98e3e1Schristos 4604e98e3e1Schristos 4614e98e3e1Schristos #if EXTERN_SIM_CORE_P 4624b169a6bSchristos /* See include/sim/sim.h. */ 4634b169a6bSchristos char * 4644b169a6bSchristos sim_memory_map (SIM_DESC sd) 4654b169a6bSchristos { 4664b169a6bSchristos sim_core *core = STATE_CORE (sd); 4674b169a6bSchristos unsigned map; 4684b169a6bSchristos char *s1, *s2, *entry; 4694b169a6bSchristos 4704b169a6bSchristos s1 = xstrdup ( 4714b169a6bSchristos "<?xml version='1.0'?>\n" 4724b169a6bSchristos "<!DOCTYPE memory-map PUBLIC '+//IDN gnu.org//DTD GDB Memory Map V1.0//EN'" 4734b169a6bSchristos " 'http://sourceware.org/gdb/gdb-memory-map.dtd'>\n" 4744b169a6bSchristos "<memory-map>\n"); 4754b169a6bSchristos 4764b169a6bSchristos for (map = 0; map < nr_maps; ++map) 4774b169a6bSchristos { 4784b169a6bSchristos sim_core_mapping *mapping; 4794b169a6bSchristos 4804b169a6bSchristos for (mapping = core->common.map[map].first; 4814b169a6bSchristos mapping != NULL; 4824b169a6bSchristos mapping = mapping->next) 4834b169a6bSchristos { 4844b169a6bSchristos /* GDB can only handle a single address space. */ 4854b169a6bSchristos if (mapping->level != 0) 4864b169a6bSchristos continue; 4874b169a6bSchristos 4884b169a6bSchristos entry = xasprintf ("<memory type='ram' start='%#" PRIxTW "' " 4894b169a6bSchristos "length='%#" PRIxTW "'/>\n", 4904b169a6bSchristos mapping->base, mapping->nr_bytes); 4914b169a6bSchristos /* The sim memory map is organized by access, not by addresses. 4924b169a6bSchristos So a RWX memory map will have three independent mappings. 4934b169a6bSchristos GDB's format cannot support overlapping regions, so we have 4944b169a6bSchristos to filter those out. 4954b169a6bSchristos 4964b169a6bSchristos Further, GDB can only handle RX ("rom") or RWX ("ram") mappings. 4974b169a6bSchristos We just emit "ram" everywhere to keep it simple. If GDB ever 4984b169a6bSchristos gains support for more stuff, we can expand this. 4994b169a6bSchristos 5004b169a6bSchristos Using strstr is kind of hacky, but as long as the map is not huge 5014b169a6bSchristos (we're talking <10K), should be fine. */ 5024b169a6bSchristos if (strstr (s1, entry) == NULL) 5034b169a6bSchristos { 5044b169a6bSchristos s2 = concat (s1, entry, NULL); 5054b169a6bSchristos free (s1); 5064b169a6bSchristos s1 = s2; 5074b169a6bSchristos } 5084b169a6bSchristos free (entry); 5094b169a6bSchristos } 5104b169a6bSchristos } 5114b169a6bSchristos 5124b169a6bSchristos s2 = concat (s1, "</memory-map>", NULL); 5134b169a6bSchristos free (s1); 5144b169a6bSchristos return s2; 5154b169a6bSchristos } 5164b169a6bSchristos #endif 5174b169a6bSchristos 5184b169a6bSchristos 5194b169a6bSchristos #if EXTERN_SIM_CORE_P 5204e98e3e1Schristos unsigned 5214e98e3e1Schristos sim_core_read_buffer (SIM_DESC sd, 5224e98e3e1Schristos sim_cpu *cpu, 5234e98e3e1Schristos unsigned map, 5244e98e3e1Schristos void *buffer, 5254e98e3e1Schristos address_word addr, 5264e98e3e1Schristos unsigned len) 5274e98e3e1Schristos { 5284e98e3e1Schristos sim_core_common *core = (cpu == NULL ? &STATE_CORE (sd)->common : &CPU_CORE (cpu)->common); 5294e98e3e1Schristos unsigned count = 0; 5304e98e3e1Schristos while (count < len) 5314e98e3e1Schristos { 5324e98e3e1Schristos address_word raddr = addr + count; 5334e98e3e1Schristos sim_core_mapping *mapping = 5344e98e3e1Schristos sim_core_find_mapping (core, map, 5354e98e3e1Schristos raddr, /*nr-bytes*/1, 5364e98e3e1Schristos read_transfer, 5374e98e3e1Schristos 0 /*dont-abort*/, NULL, NULL_CIA); 5384e98e3e1Schristos if (mapping == NULL) 5394e98e3e1Schristos break; 5404e98e3e1Schristos #if (WITH_HW) 5414e98e3e1Schristos if (mapping->device != NULL) 5424e98e3e1Schristos { 5434e98e3e1Schristos int nr_bytes = len - count; 5444e98e3e1Schristos if (raddr + nr_bytes - 1> mapping->bound) 5454e98e3e1Schristos nr_bytes = mapping->bound - raddr + 1; 546ba340e45Schristos /* If the access was initiated by a cpu, pass it down so errors can 547ba340e45Schristos be propagated properly. For other sources (e.g. GDB or DMA), we 548ba340e45Schristos can only signal errors via the return value. */ 549ba340e45Schristos if (cpu) 550ba340e45Schristos { 551ba340e45Schristos sim_cia cia = cpu ? CPU_PC_GET (cpu) : NULL_CIA; 552ba340e45Schristos sim_cpu_hw_io_read_buffer (cpu, cia, mapping->device, 553ba340e45Schristos (unsigned_1*)buffer + count, 554ba340e45Schristos mapping->space, 555ba340e45Schristos raddr, 556ba340e45Schristos nr_bytes); 557ba340e45Schristos } 558ba340e45Schristos else if (sim_hw_io_read_buffer (sd, mapping->device, 5594e98e3e1Schristos (unsigned_1*)buffer + count, 5604e98e3e1Schristos mapping->space, 5614e98e3e1Schristos raddr, 5624e98e3e1Schristos nr_bytes) != nr_bytes) 5634e98e3e1Schristos break; 5644e98e3e1Schristos count += nr_bytes; 5654e98e3e1Schristos continue; 5664e98e3e1Schristos } 5674e98e3e1Schristos #endif 5684e98e3e1Schristos ((unsigned_1*)buffer)[count] = 5694e98e3e1Schristos *(unsigned_1*)sim_core_translate (mapping, raddr); 5704e98e3e1Schristos count += 1; 5714e98e3e1Schristos } 5724e98e3e1Schristos return count; 5734e98e3e1Schristos } 5744e98e3e1Schristos #endif 5754e98e3e1Schristos 5764e98e3e1Schristos 5774e98e3e1Schristos #if EXTERN_SIM_CORE_P 5784e98e3e1Schristos unsigned 5794e98e3e1Schristos sim_core_write_buffer (SIM_DESC sd, 5804e98e3e1Schristos sim_cpu *cpu, 5814e98e3e1Schristos unsigned map, 5824e98e3e1Schristos const void *buffer, 5834e98e3e1Schristos address_word addr, 5844e98e3e1Schristos unsigned len) 5854e98e3e1Schristos { 5864e98e3e1Schristos sim_core_common *core = (cpu == NULL ? &STATE_CORE (sd)->common : &CPU_CORE (cpu)->common); 5874e98e3e1Schristos unsigned count = 0; 5884e98e3e1Schristos while (count < len) 5894e98e3e1Schristos { 5904e98e3e1Schristos address_word raddr = addr + count; 5914e98e3e1Schristos sim_core_mapping *mapping = 5924e98e3e1Schristos sim_core_find_mapping (core, map, 5934e98e3e1Schristos raddr, /*nr-bytes*/1, 5944e98e3e1Schristos write_transfer, 5954e98e3e1Schristos 0 /*dont-abort*/, NULL, NULL_CIA); 5964e98e3e1Schristos if (mapping == NULL) 5974e98e3e1Schristos break; 598ba340e45Schristos #if (WITH_HW) 599ba340e45Schristos if (mapping->device != NULL) 6004e98e3e1Schristos { 6014e98e3e1Schristos int nr_bytes = len - count; 6024e98e3e1Schristos if (raddr + nr_bytes - 1 > mapping->bound) 6034e98e3e1Schristos nr_bytes = mapping->bound - raddr + 1; 604ba340e45Schristos /* If the access was initiated by a cpu, pass it down so errors can 605ba340e45Schristos be propagated properly. For other sources (e.g. GDB or DMA), we 606ba340e45Schristos can only signal errors via the return value. */ 607ba340e45Schristos if (cpu) 608ba340e45Schristos { 609ba340e45Schristos sim_cia cia = cpu ? CPU_PC_GET (cpu) : NULL_CIA; 610ba340e45Schristos sim_cpu_hw_io_write_buffer (cpu, cia, mapping->device, 6114e98e3e1Schristos (unsigned_1*)buffer + count, 6124e98e3e1Schristos mapping->space, 6134e98e3e1Schristos raddr, 614ba340e45Schristos nr_bytes); 6154e98e3e1Schristos } 616ba340e45Schristos else if (sim_hw_io_write_buffer (sd, mapping->device, 6174e98e3e1Schristos (unsigned_1*)buffer + count, 6184e98e3e1Schristos mapping->space, 6194e98e3e1Schristos raddr, 6204e98e3e1Schristos nr_bytes) != nr_bytes) 6214e98e3e1Schristos break; 6224e98e3e1Schristos count += nr_bytes; 6234e98e3e1Schristos continue; 6244e98e3e1Schristos } 6254e98e3e1Schristos #endif 6264e98e3e1Schristos *(unsigned_1*)sim_core_translate (mapping, raddr) = 6274e98e3e1Schristos ((unsigned_1*)buffer)[count]; 6284e98e3e1Schristos count += 1; 6294e98e3e1Schristos } 6304e98e3e1Schristos return count; 6314e98e3e1Schristos } 6324e98e3e1Schristos #endif 6334e98e3e1Schristos 6344e98e3e1Schristos 6354e98e3e1Schristos #if EXTERN_SIM_CORE_P 6364e98e3e1Schristos void 6374e98e3e1Schristos sim_core_set_xor (SIM_DESC sd, 6384e98e3e1Schristos sim_cpu *cpu, 6394e98e3e1Schristos int is_xor) 6404e98e3e1Schristos { 6414e98e3e1Schristos /* set up the XOR map if required. */ 6424e98e3e1Schristos if (WITH_XOR_ENDIAN) { 6434e98e3e1Schristos { 6444e98e3e1Schristos sim_core *core = STATE_CORE (sd); 6454e98e3e1Schristos sim_cpu_core *cpu_core = (cpu != NULL ? CPU_CORE (cpu) : NULL); 6464e98e3e1Schristos if (cpu_core != NULL) 6474e98e3e1Schristos { 6484e98e3e1Schristos int i = 1; 6494e98e3e1Schristos unsigned mask; 6504e98e3e1Schristos if (is_xor) 6514e98e3e1Schristos mask = WITH_XOR_ENDIAN - 1; 6524e98e3e1Schristos else 6534e98e3e1Schristos mask = 0; 6544e98e3e1Schristos while (i - 1 < WITH_XOR_ENDIAN) 6554e98e3e1Schristos { 6564559860eSchristos cpu_core->byte_xor[i-1] = mask; 6574e98e3e1Schristos mask = (mask << 1) & (WITH_XOR_ENDIAN - 1); 6584e98e3e1Schristos i = (i << 1); 6594e98e3e1Schristos } 6604e98e3e1Schristos } 6614e98e3e1Schristos else 6624e98e3e1Schristos { 6634e98e3e1Schristos if (is_xor) 6644e98e3e1Schristos core->byte_xor = WITH_XOR_ENDIAN - 1; 6654e98e3e1Schristos else 6664e98e3e1Schristos core->byte_xor = 0; 6674e98e3e1Schristos } 6684e98e3e1Schristos } 6694e98e3e1Schristos } 6704e98e3e1Schristos else { 6714e98e3e1Schristos if (is_xor) 6724e98e3e1Schristos sim_engine_abort (sd, NULL, NULL_CIA, 673*88241920Schristos "Attempted to enable xor-endian mode when permanently disabled."); 6744e98e3e1Schristos } 6754e98e3e1Schristos } 6764e98e3e1Schristos #endif 6774e98e3e1Schristos 6784e98e3e1Schristos 6794e98e3e1Schristos #if EXTERN_SIM_CORE_P 6804e98e3e1Schristos static void 6814e98e3e1Schristos reverse_n (unsigned_1 *dest, 6824e98e3e1Schristos const unsigned_1 *src, 6834e98e3e1Schristos int nr_bytes) 6844e98e3e1Schristos { 6854e98e3e1Schristos int i; 6864e98e3e1Schristos for (i = 0; i < nr_bytes; i++) 6874e98e3e1Schristos { 6884e98e3e1Schristos dest [nr_bytes - i - 1] = src [i]; 6894e98e3e1Schristos } 6904e98e3e1Schristos } 6914e98e3e1Schristos #endif 6924e98e3e1Schristos 6934e98e3e1Schristos 6944e98e3e1Schristos #if EXTERN_SIM_CORE_P 6954e98e3e1Schristos unsigned 6964e98e3e1Schristos sim_core_xor_read_buffer (SIM_DESC sd, 6974e98e3e1Schristos sim_cpu *cpu, 6984e98e3e1Schristos unsigned map, 6994e98e3e1Schristos void *buffer, 7004e98e3e1Schristos address_word addr, 7014e98e3e1Schristos unsigned nr_bytes) 7024e98e3e1Schristos { 7034559860eSchristos address_word byte_xor 7044559860eSchristos = (cpu == NULL ? STATE_CORE (sd)->byte_xor : CPU_CORE (cpu)->byte_xor[0]); 7054e98e3e1Schristos if (!WITH_XOR_ENDIAN || !byte_xor) 7064e98e3e1Schristos return sim_core_read_buffer (sd, cpu, map, buffer, addr, nr_bytes); 7074e98e3e1Schristos else 7084e98e3e1Schristos /* only break up transfers when xor-endian is both selected and enabled */ 7094e98e3e1Schristos { 7104e98e3e1Schristos unsigned_1 x[WITH_XOR_ENDIAN + 1]; /* +1 to avoid zero-sized array */ 7114e98e3e1Schristos unsigned nr_transfered = 0; 7124e98e3e1Schristos address_word start = addr; 7134e98e3e1Schristos unsigned nr_this_transfer = (WITH_XOR_ENDIAN - (addr & ~(WITH_XOR_ENDIAN - 1))); 7144e98e3e1Schristos address_word stop; 7154e98e3e1Schristos /* initial and intermediate transfers are broken when they cross 7164e98e3e1Schristos an XOR endian boundary */ 7174e98e3e1Schristos while (nr_transfered + nr_this_transfer < nr_bytes) 7184e98e3e1Schristos /* initial/intermediate transfers */ 7194e98e3e1Schristos { 7204e98e3e1Schristos /* since xor-endian is enabled stop^xor defines the start 7214e98e3e1Schristos address of the transfer */ 7224e98e3e1Schristos stop = start + nr_this_transfer - 1; 7234e98e3e1Schristos SIM_ASSERT (start <= stop); 7244e98e3e1Schristos SIM_ASSERT ((stop ^ byte_xor) <= (start ^ byte_xor)); 7254e98e3e1Schristos if (sim_core_read_buffer (sd, cpu, map, x, stop ^ byte_xor, nr_this_transfer) 7264e98e3e1Schristos != nr_this_transfer) 7274e98e3e1Schristos return nr_transfered; 7284e98e3e1Schristos reverse_n (&((unsigned_1*)buffer)[nr_transfered], x, nr_this_transfer); 7294e98e3e1Schristos nr_transfered += nr_this_transfer; 7304e98e3e1Schristos nr_this_transfer = WITH_XOR_ENDIAN; 7314e98e3e1Schristos start = stop + 1; 7324e98e3e1Schristos } 7334e98e3e1Schristos /* final transfer */ 7344e98e3e1Schristos nr_this_transfer = nr_bytes - nr_transfered; 7354e98e3e1Schristos stop = start + nr_this_transfer - 1; 7364e98e3e1Schristos SIM_ASSERT (stop == (addr + nr_bytes - 1)); 7374e98e3e1Schristos if (sim_core_read_buffer (sd, cpu, map, x, stop ^ byte_xor, nr_this_transfer) 7384e98e3e1Schristos != nr_this_transfer) 7394e98e3e1Schristos return nr_transfered; 7404e98e3e1Schristos reverse_n (&((unsigned_1*)buffer)[nr_transfered], x, nr_this_transfer); 7414e98e3e1Schristos return nr_bytes; 7424e98e3e1Schristos } 7434e98e3e1Schristos } 7444e98e3e1Schristos #endif 7454e98e3e1Schristos 7464e98e3e1Schristos 7474e98e3e1Schristos #if EXTERN_SIM_CORE_P 7484e98e3e1Schristos unsigned 7494e98e3e1Schristos sim_core_xor_write_buffer (SIM_DESC sd, 7504e98e3e1Schristos sim_cpu *cpu, 7514e98e3e1Schristos unsigned map, 7524e98e3e1Schristos const void *buffer, 7534e98e3e1Schristos address_word addr, 7544e98e3e1Schristos unsigned nr_bytes) 7554e98e3e1Schristos { 7564559860eSchristos address_word byte_xor 7574559860eSchristos = (cpu == NULL ? STATE_CORE (sd)->byte_xor : CPU_CORE (cpu)->byte_xor[0]); 7584e98e3e1Schristos if (!WITH_XOR_ENDIAN || !byte_xor) 7594e98e3e1Schristos return sim_core_write_buffer (sd, cpu, map, buffer, addr, nr_bytes); 7604e98e3e1Schristos else 7614e98e3e1Schristos /* only break up transfers when xor-endian is both selected and enabled */ 7624e98e3e1Schristos { 7634e98e3e1Schristos unsigned_1 x[WITH_XOR_ENDIAN + 1]; /* +1 to avoid zero sized array */ 7644e98e3e1Schristos unsigned nr_transfered = 0; 7654e98e3e1Schristos address_word start = addr; 7664e98e3e1Schristos unsigned nr_this_transfer = (WITH_XOR_ENDIAN - (addr & ~(WITH_XOR_ENDIAN - 1))); 7674e98e3e1Schristos address_word stop; 7684e98e3e1Schristos /* initial and intermediate transfers are broken when they cross 7694e98e3e1Schristos an XOR endian boundary */ 7704e98e3e1Schristos while (nr_transfered + nr_this_transfer < nr_bytes) 7714e98e3e1Schristos /* initial/intermediate transfers */ 7724e98e3e1Schristos { 7734e98e3e1Schristos /* since xor-endian is enabled stop^xor defines the start 7744e98e3e1Schristos address of the transfer */ 7754e98e3e1Schristos stop = start + nr_this_transfer - 1; 7764e98e3e1Schristos SIM_ASSERT (start <= stop); 7774e98e3e1Schristos SIM_ASSERT ((stop ^ byte_xor) <= (start ^ byte_xor)); 7784e98e3e1Schristos reverse_n (x, &((unsigned_1*)buffer)[nr_transfered], nr_this_transfer); 7794e98e3e1Schristos if (sim_core_read_buffer (sd, cpu, map, x, stop ^ byte_xor, nr_this_transfer) 7804e98e3e1Schristos != nr_this_transfer) 7814e98e3e1Schristos return nr_transfered; 7824e98e3e1Schristos nr_transfered += nr_this_transfer; 7834e98e3e1Schristos nr_this_transfer = WITH_XOR_ENDIAN; 7844e98e3e1Schristos start = stop + 1; 7854e98e3e1Schristos } 7864e98e3e1Schristos /* final transfer */ 7874e98e3e1Schristos nr_this_transfer = nr_bytes - nr_transfered; 7884e98e3e1Schristos stop = start + nr_this_transfer - 1; 7894e98e3e1Schristos SIM_ASSERT (stop == (addr + nr_bytes - 1)); 7904e98e3e1Schristos reverse_n (x, &((unsigned_1*)buffer)[nr_transfered], nr_this_transfer); 7914e98e3e1Schristos if (sim_core_read_buffer (sd, cpu, map, x, stop ^ byte_xor, nr_this_transfer) 7924e98e3e1Schristos != nr_this_transfer) 7934e98e3e1Schristos return nr_transfered; 7944e98e3e1Schristos return nr_bytes; 7954e98e3e1Schristos } 7964e98e3e1Schristos } 7974e98e3e1Schristos #endif 7984e98e3e1Schristos 7994e98e3e1Schristos #if EXTERN_SIM_CORE_P 8004e98e3e1Schristos void * 8014e98e3e1Schristos sim_core_trans_addr (SIM_DESC sd, 8024e98e3e1Schristos sim_cpu *cpu, 8034e98e3e1Schristos unsigned map, 8044e98e3e1Schristos address_word addr) 8054e98e3e1Schristos { 8064e98e3e1Schristos sim_core_common *core = (cpu == NULL ? &STATE_CORE (sd)->common : &CPU_CORE (cpu)->common); 8074e98e3e1Schristos sim_core_mapping *mapping = 8084e98e3e1Schristos sim_core_find_mapping (core, map, 8094e98e3e1Schristos addr, /*nr-bytes*/1, 8104e98e3e1Schristos write_transfer, 8114e98e3e1Schristos 0 /*dont-abort*/, NULL, NULL_CIA); 8124e98e3e1Schristos if (mapping == NULL) 8134e98e3e1Schristos return NULL; 8144e98e3e1Schristos return sim_core_translate (mapping, addr); 8154e98e3e1Schristos } 8164e98e3e1Schristos #endif 8174e98e3e1Schristos 8184e98e3e1Schristos 8194e98e3e1Schristos 8204e98e3e1Schristos /* define the read/write 1/2/4/8/16/word functions */ 8214e98e3e1Schristos 8224e98e3e1Schristos #define N 16 8234e98e3e1Schristos #include "sim-n-core.h" 8244e98e3e1Schristos 8254e98e3e1Schristos #define N 8 8264e98e3e1Schristos #include "sim-n-core.h" 8274e98e3e1Schristos 8284e98e3e1Schristos #define N 7 8294e98e3e1Schristos #define M 8 8304e98e3e1Schristos #include "sim-n-core.h" 8314e98e3e1Schristos 8324e98e3e1Schristos #define N 6 8334e98e3e1Schristos #define M 8 8344e98e3e1Schristos #include "sim-n-core.h" 8354e98e3e1Schristos 8364e98e3e1Schristos #define N 5 8374e98e3e1Schristos #define M 8 8384e98e3e1Schristos #include "sim-n-core.h" 8394e98e3e1Schristos 8404e98e3e1Schristos #define N 4 8414e98e3e1Schristos #include "sim-n-core.h" 8424e98e3e1Schristos 8434e98e3e1Schristos #define N 3 8444e98e3e1Schristos #define M 4 8454e98e3e1Schristos #include "sim-n-core.h" 8464e98e3e1Schristos 8474e98e3e1Schristos #define N 2 8484e98e3e1Schristos #include "sim-n-core.h" 8494e98e3e1Schristos 8504e98e3e1Schristos #define N 1 8514e98e3e1Schristos #include "sim-n-core.h" 8524e98e3e1Schristos 8534e98e3e1Schristos #endif 854