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