1/* This file is part of the program psim. 2 3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 21 22#ifndef _CORE_C_ 23#define _CORE_C_ 24 25#include "basics.h" 26#include "device_table.h" 27#include "corefile.h" 28 29typedef struct _core_mapping core_mapping; 30struct _core_mapping { 31 /* common */ 32 int level; 33 int space; 34 unsigned_word base; 35 unsigned_word bound; 36 unsigned nr_bytes; 37 /* memory map */ 38 void *free_buffer; 39 void *buffer; 40 /* callback map */ 41 device *device; 42 /* growth */ 43 core_mapping *next; 44}; 45 46struct _core_map { 47 core_mapping *first; 48}; 49 50typedef enum { 51 core_read_map, 52 core_write_map, 53 core_execute_map, 54 nr_core_map_types, 55} core_map_types; 56 57struct _core { 58 core_map map[nr_core_map_types]; 59}; 60 61 62INLINE_CORE\ 63(core *) 64core_create(void) 65{ 66 return ZALLOC(core); 67} 68 69 70INLINE_CORE\ 71(core *) 72core_from_device(device *root) 73{ 74 root = device_root(root); 75 ASSERT(strcmp(device_name(root), "core") == 0); 76 return device_data(root); 77} 78 79 80INLINE_CORE\ 81(void) 82core_init(core *memory) 83{ 84 core_map_types access_type; 85 for (access_type = 0; 86 access_type < nr_core_map_types; 87 access_type++) { 88 core_map *map = memory->map + access_type; 89 /* blow away old mappings */ 90 core_mapping *curr = map->first; 91 while (curr != NULL) { 92 core_mapping *tbd = curr; 93 curr = curr->next; 94 if (tbd->free_buffer != NULL) { 95 ASSERT(tbd->buffer != NULL); 96 zfree(tbd->free_buffer); 97 } 98 zfree(tbd); 99 } 100 map->first = NULL; 101 } 102} 103 104 105 106/* the core has three sub mappings that the more efficient 107 read/write fixed quantity functions use */ 108 109INLINE_CORE\ 110(core_map *) 111core_readable(core *memory) 112{ 113 return memory->map + core_read_map; 114} 115 116INLINE_CORE\ 117(core_map *) 118core_writeable(core *memory) 119{ 120 return memory->map + core_write_map; 121} 122 123INLINE_CORE\ 124(core_map *) 125core_executable(core *memory) 126{ 127 return memory->map + core_execute_map; 128} 129 130 131 132STATIC_INLINE_CORE\ 133(core_mapping *) 134new_core_mapping(attach_type attach, 135 int space, 136 unsigned_word addr, 137 unsigned nr_bytes, 138 device *device, 139 void *buffer, 140 void *free_buffer) 141{ 142 core_mapping *new_mapping = ZALLOC(core_mapping); 143 /* common */ 144 new_mapping->level = attach; 145 new_mapping->space = space; 146 new_mapping->base = addr; 147 new_mapping->nr_bytes = nr_bytes; 148 new_mapping->bound = addr + (nr_bytes - 1); 149 if (attach == attach_raw_memory) { 150 new_mapping->buffer = buffer; 151 new_mapping->free_buffer = free_buffer; 152 } 153 else if (attach >= attach_callback) { 154 new_mapping->device = device; 155 } 156 else { 157 error("new_core_mapping() - internal error - unknown attach type %d\n", 158 attach); 159 } 160 return new_mapping; 161} 162 163 164STATIC_INLINE_CORE\ 165(void) 166core_map_attach(core_map *access_map, 167 attach_type attach, 168 int space, 169 unsigned_word addr, 170 unsigned nr_bytes, /* host limited */ 171 device *client, /*callback/default*/ 172 void *buffer, /*raw_memory*/ 173 void *free_buffer) /*raw_memory*/ 174{ 175 /* find the insertion point for this additional mapping and insert */ 176 core_mapping *next_mapping; 177 core_mapping **last_mapping; 178 179 /* actually do occasionally get a zero size map */ 180 if (nr_bytes == 0) { 181 device_error(client, "called on core_map_attach() with size zero"); 182 } 183 184 /* find the insertion point (between last/next) */ 185 next_mapping = access_map->first; 186 last_mapping = &access_map->first; 187 while(next_mapping != NULL 188 && (next_mapping->level < attach 189 || (next_mapping->level == attach 190 && next_mapping->bound < addr))) { 191 /* provided levels are the same */ 192 /* assert: next_mapping->base > all bases before next_mapping */ 193 /* assert: next_mapping->bound >= all bounds before next_mapping */ 194 last_mapping = &next_mapping->next; 195 next_mapping = next_mapping->next; 196 } 197 198 /* check insertion point correct */ 199 ASSERT(next_mapping == NULL || next_mapping->level >= attach); 200 if (next_mapping != NULL && next_mapping->level == attach 201 && next_mapping->base < (addr + (nr_bytes - 1))) { 202 device_error(client, "map overlap when attaching %d:0x%lx (%ld)", 203 space, (long)addr, (long)nr_bytes); 204 } 205 206 /* create/insert the new mapping */ 207 *last_mapping = new_core_mapping(attach, 208 space, addr, nr_bytes, 209 client, buffer, free_buffer); 210 (*last_mapping)->next = next_mapping; 211} 212 213 214INLINE_CORE\ 215(void) 216core_attach(core *memory, 217 attach_type attach, 218 int space, 219 access_type access, 220 unsigned_word addr, 221 unsigned nr_bytes, /* host limited */ 222 device *client) /*callback/default*/ 223{ 224 core_map_types access_map; 225 void *buffer; 226 void *free_buffer; 227 if (attach == attach_raw_memory) { 228 /* Padd out the raw buffer to ensure that ADDR starts on a 229 correctly aligned boundary */ 230 int padding = (addr % sizeof (unsigned64)); 231 free_buffer = zalloc(nr_bytes + padding); 232 buffer = (char*)free_buffer + padding; 233 } 234 else { 235 buffer = NULL; 236 free_buffer = &buffer; /* marker for assertion */ 237 } 238 for (access_map = 0; 239 access_map < nr_core_map_types; 240 access_map++) { 241 switch (access_map) { 242 case core_read_map: 243 if (access & access_read) 244 core_map_attach(memory->map + access_map, 245 attach, 246 space, addr, nr_bytes, 247 client, buffer, free_buffer); 248 free_buffer = NULL; 249 break; 250 case core_write_map: 251 if (access & access_write) 252 core_map_attach(memory->map + access_map, 253 attach, 254 space, addr, nr_bytes, 255 client, buffer, free_buffer); 256 free_buffer = NULL; 257 break; 258 case core_execute_map: 259 if (access & access_exec) 260 core_map_attach(memory->map + access_map, 261 attach, 262 space, addr, nr_bytes, 263 client, buffer, free_buffer); 264 free_buffer = NULL; 265 break; 266 default: 267 error("core_attach() internal error\n"); 268 break; 269 } 270 } 271 /* allocated buffer must attach to at least one thing */ 272 ASSERT(free_buffer == NULL); 273} 274 275 276STATIC_INLINE_CORE\ 277(core_mapping *) 278core_map_find_mapping(core_map *map, 279 unsigned_word addr, 280 unsigned nr_bytes, 281 cpu *processor, 282 unsigned_word cia, 283 int abort) /*either 0 or 1 - helps inline */ 284{ 285 core_mapping *mapping = map->first; 286 ASSERT((addr & (nr_bytes - 1)) == 0); /* must be aligned */ 287 ASSERT((addr + (nr_bytes - 1)) >= addr); /* must not wrap */ 288 while (mapping != NULL) { 289 if (addr >= mapping->base 290 && (addr + (nr_bytes - 1)) <= mapping->bound) 291 return mapping; 292 mapping = mapping->next; 293 } 294 if (abort) 295 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", 296 addr, nr_bytes, processor, cia); 297 return NULL; 298} 299 300 301STATIC_INLINE_CORE\ 302(void *) 303core_translate(core_mapping *mapping, 304 unsigned_word addr) 305{ 306 return (void *)(((char *)mapping->buffer) + addr - mapping->base); 307} 308 309 310INLINE_CORE\ 311(unsigned) 312core_map_read_buffer(core_map *map, 313 void *buffer, 314 unsigned_word addr, 315 unsigned len) 316{ 317 unsigned count = 0; 318 while (count < len) { 319 unsigned_word raddr = addr + count; 320 core_mapping *mapping = 321 core_map_find_mapping(map, 322 raddr, 1, 323 NULL, /*processor*/ 324 0, /*cia*/ 325 0); /*dont-abort*/ 326 if (mapping == NULL) 327 break; 328 if (mapping->device != NULL) { 329 int nr_bytes = len - count; 330 if (raddr + nr_bytes - 1> mapping->bound) 331 nr_bytes = mapping->bound - raddr + 1; 332 if (device_io_read_buffer(mapping->device, 333 (unsigned_1*)buffer + count, 334 mapping->space, 335 raddr, 336 nr_bytes, 337 0, /*processor*/ 338 0 /*cpu*/) != nr_bytes) 339 break; 340 count += nr_bytes; 341 } 342 else { 343 ((unsigned_1*)buffer)[count] = 344 *(unsigned_1*)core_translate(mapping, raddr); 345 count += 1; 346 } 347 } 348 return count; 349} 350 351 352INLINE_CORE\ 353(unsigned) 354core_map_write_buffer(core_map *map, 355 const void *buffer, 356 unsigned_word addr, 357 unsigned len) 358{ 359 unsigned count = 0; 360 while (count < len) { 361 unsigned_word raddr = addr + count; 362 core_mapping *mapping = core_map_find_mapping(map, 363 raddr, 1, 364 NULL, /*processor*/ 365 0, /*cia*/ 366 0); /*dont-abort*/ 367 if (mapping == NULL) 368 break; 369 if (mapping->device != NULL) { 370 int nr_bytes = len - count; 371 if (raddr + nr_bytes - 1 > mapping->bound) 372 nr_bytes = mapping->bound - raddr + 1; 373 if (device_io_write_buffer(mapping->device, 374 (unsigned_1*)buffer + count, 375 mapping->space, 376 raddr, 377 nr_bytes, 378 0, /*processor*/ 379 0 /*cpu*/) != nr_bytes) 380 break; 381 count += nr_bytes; 382 } 383 else { 384 *(unsigned_1*)core_translate(mapping, raddr) = 385 ((unsigned_1*)buffer)[count]; 386 count += 1; 387 } 388 } 389 return count; 390} 391 392 393/* define the read/write 1/2/4/8/word functions */ 394 395#define N 1 396#include "corefile-n.h" 397#undef N 398 399#define N 2 400#include "corefile-n.h" 401#undef N 402 403#define N 4 404#include "corefile-n.h" 405#undef N 406 407#define N 8 408#include "corefile-n.h" 409#undef N 410 411#define N word 412#include "corefile-n.h" 413#undef N 414 415#endif /* _CORE_C_ */ 416