1/* This file is part of the program psim. 2 3 Copyright 1994, 1995, 1996, 1997, 2003 Andrew Cagney 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 _PSIM_C_ 23#define _PSIM_C_ 24 25#include "cpu.h" /* includes psim.h */ 26#include "idecode.h" 27#include "options.h" 28 29#include "tree.h" 30 31#include <signal.h> 32 33#include <stdio.h> 34#include <ctype.h> 35 36#ifdef HAVE_STDLIB_H 37#include <stdlib.h> 38#endif 39 40#include <setjmp.h> 41 42#ifdef HAVE_STRING_H 43#include <string.h> 44#else 45#ifdef HAVE_STRINGS_H 46#include <strings.h> 47#endif 48#endif 49 50 51#include "bfd.h" 52#include "libiberty.h" 53#include "gdb/signals.h" 54 55/* system structure, actual size of processor array determined at 56 runtime */ 57 58struct _psim { 59 event_queue *events; 60 device *devices; 61 mon *monitor; 62 os_emul *os_emulation; 63 core *memory; 64 65 /* escape routine for inner functions */ 66 void *path_to_halt; 67 void *path_to_restart; 68 69 /* status from last halt */ 70 psim_status halt_status; 71 72 /* the processors proper */ 73 int nr_cpus; 74 int last_cpu; /* CPU that last (tried to) execute an instruction */ 75 cpu *processors[MAX_NR_PROCESSORS]; 76}; 77 78 79int current_target_byte_order; 80int current_host_byte_order; 81int current_environment; 82int current_alignment; 83int current_floating_point; 84int current_model_issue = MODEL_ISSUE_IGNORE; 85int current_stdio = DO_USE_STDIO; 86model_enum current_model = WITH_DEFAULT_MODEL; 87 88 89/* create the device tree */ 90 91INLINE_PSIM\ 92(device *) 93psim_tree(void) 94{ 95 device *root = tree_parse(NULL, "core"); 96 tree_parse(root, "/aliases"); 97 tree_parse(root, "/options"); 98 tree_parse(root, "/chosen"); 99 tree_parse(root, "/packages"); 100 tree_parse(root, "/cpus"); 101 tree_parse(root, "/openprom"); 102 tree_parse(root, "/openprom/init"); 103 tree_parse(root, "/openprom/trace"); 104 tree_parse(root, "/openprom/options"); 105 return root; 106} 107 108STATIC_INLINE_PSIM\ 109(char *) 110find_arg(char *err_msg, 111 int *ptr_to_argp, 112 char **argv) 113{ 114 *ptr_to_argp += 1; 115 if (argv[*ptr_to_argp] == NULL) 116 error(err_msg); 117 return argv[*ptr_to_argp]; 118} 119 120INLINE_PSIM\ 121(void) 122psim_usage(int verbose) 123{ 124 printf_filtered("Usage:\n"); 125 printf_filtered("\n"); 126 printf_filtered("\tpsim [ <psim-option> ... ] <image> [ <image-arg> ... ]\n"); 127 printf_filtered("\n"); 128 printf_filtered("Where\n"); 129 printf_filtered("\n"); 130 printf_filtered("\t<image> Name of the PowerPC program to run.\n"); 131 if (verbose) { 132 printf_filtered("\t This can either be a PowerPC binary or\n"); 133 printf_filtered("\t a text file containing a device tree\n"); 134 printf_filtered("\t specification.\n"); 135 printf_filtered("\t PSIM will attempt to determine from the\n"); 136 printf_filtered("\t specified <image> the intended emulation\n"); 137 printf_filtered("\t environment.\n"); 138 printf_filtered("\t If PSIM gets it wrong, the emulation\n"); 139 printf_filtered("\t environment can be specified using the\n"); 140 printf_filtered("\t `-e' option (described below).\n"); 141 printf_filtered("\n"); } 142 printf_filtered("\t<image-arg> Argument to be passed to <image>\n"); 143 if (verbose) { 144 printf_filtered("\t These arguments will be passed to\n"); 145 printf_filtered("\t <image> (as standard C argv, argc)\n"); 146 printf_filtered("\t when <image> is started.\n"); 147 printf_filtered("\n"); } 148 printf_filtered("\t<psim-option> See below\n"); 149 printf_filtered("\n"); 150 printf_filtered("The following are valid <psim-option>s:\n"); 151 printf_filtered("\n"); 152 153 printf_filtered("\t-c <count> Limit the simulation to <count> iterations\n"); 154 if (verbose) { 155 printf_filtered("\n"); 156 } 157 158 printf_filtered("\t-i or -i2 Print instruction counting statistics\n"); 159 if (verbose) { 160 printf_filtered("\t Specify -i2 for a more detailed display\n"); 161 printf_filtered("\n"); 162 } 163 164 printf_filtered("\t-I Print execution unit statistics\n"); 165 if (verbose) { printf_filtered("\n"); } 166 167 printf_filtered("\t-e <os-emul> specify an OS or platform to model\n"); 168 if (verbose) { 169 printf_filtered("\t Can be any of the following:\n"); 170 printf_filtered("\t bug - OEA + MOTO BUG ROM calls\n"); 171 printf_filtered("\t netbsd - UEA + NetBSD system calls\n"); 172 printf_filtered("\t solaris - UEA + Solaris system calls\n"); 173 printf_filtered("\t linux - UEA + Linux system calls\n"); 174 printf_filtered("\t chirp - OEA + a few OpenBoot calls\n"); 175 printf_filtered("\n"); } 176 177 printf_filtered("\t-E <endian> Specify the endianness of the target\n"); 178 if (verbose) { 179 printf_filtered("\t Can be any of the following:\n"); 180 printf_filtered("\t big - big endian target\n"); 181 printf_filtered("\t little - little endian target\n"); 182 printf_filtered("\n"); } 183 184 printf_filtered("\t-f <file> Merge <file> into the device tree\n"); 185 if (verbose) { printf_filtered("\n"); } 186 187 printf_filtered("\t-h -? -H give more detailed usage\n"); 188 if (verbose) { printf_filtered("\n"); } 189 190 printf_filtered("\t-m <model> Specify the processor to model (604)\n"); 191 if (verbose) { 192 printf_filtered("\t Selects the processor to use when\n"); 193 printf_filtered("\t modeling execution units. Includes:\n"); 194 printf_filtered("\t 604, 603 and 603e\n"); 195 printf_filtered("\n"); } 196 197 printf_filtered("\t-n <nr-smp> Specify the number of processors in SMP simulations\n"); 198 if (verbose) { 199 printf_filtered("\t Specifies the number of processors that are\n"); 200 printf_filtered("\t to be modeled in a symetric multi-processor (SMP)\n"); 201 printf_filtered("\t simulation\n"); 202 printf_filtered("\n"); } 203 204 printf_filtered("\t-o <dev-spec> Add device <dev-spec> to the device tree\n"); 205 if (verbose) { printf_filtered("\n"); } 206 207 printf_filtered("\t-r <ram-size> Set RAM size in bytes (OEA environments)\n"); 208 if (verbose) { printf_filtered("\n"); } 209 210 printf_filtered("\t-t [!]<trace> Enable (disable) <trace> option\n"); 211 if (verbose) { printf_filtered("\n"); } 212 213 printf_filtered("\n"); 214 trace_usage(verbose); 215 device_usage(verbose); 216 if (verbose > 1) { 217 printf_filtered("\n"); 218 print_options(); 219 } 220 error(""); 221} 222 223/* Test "string" for containing a string of digits that form a number 224between "min" and "max". The return value is the number or "err". */ 225static 226int is_num( char *string, int min, int max, int err) 227{ 228 int result = 0; 229 230 for ( ; *string; ++string) 231 { 232 if (!isdigit(*string)) 233 { 234 result = err; 235 break; 236 } 237 result = result * 10 + (*string - '0'); 238 } 239 if (result < min || result > max) 240 result = err; 241 242 return result; 243} 244 245INLINE_PSIM\ 246(char **) 247psim_options(device *root, 248 char **argv) 249{ 250 device *current = root; 251 int argp; 252 if (argv == NULL) 253 return NULL; 254 argp = 0; 255 while (argv[argp] != NULL && argv[argp][0] == '-') { 256 char *p = argv[argp] + 1; 257 char *param; 258 while (*p != '\0') { 259 switch (*p) { 260 default: 261 psim_usage(0); 262 error (""); 263 break; 264 case 'c': 265 param = find_arg("Missing <count> option for -c (max-iterations)\n", &argp, argv); 266 tree_parse(root, "/openprom/options/max-iterations %s", param); 267 break; 268 case 'e': 269 param = find_arg("Missing <emul> option for -e (os-emul)\n", &argp, argv); 270 tree_parse(root, "/openprom/options/os-emul %s", param); 271 break; 272 case 'E': 273 /* endian spec, ignored for now */ 274 param = find_arg("Missing <endian> option for -E (target-endian)\n", &argp, argv); 275 if (strcmp (param, "big") == 0) 276 tree_parse (root, "/options/little-endian? false"); 277 else if (strcmp (param, "little") == 0) 278 tree_parse (root, "/options/little-endian? true"); 279 else 280 { 281 printf_filtered ("Invalid <endian> option for -E (target-endian)\n"); 282 psim_usage (0); 283 } 284 break; 285 case 'f': 286 param = find_arg("Missing <file> option for -f\n", &argp, argv); 287 psim_merge_device_file(root, param); 288 break; 289 case 'h': 290 case '?': 291 psim_usage(1); 292 break; 293 case 'H': 294 psim_usage(2); 295 break; 296 case 'i': 297 if (isdigit(p[1])) { 298 tree_parse(root, "/openprom/trace/print-info %c", p[1]); 299 p++; 300 } 301 else { 302 tree_parse(root, "/openprom/trace/print-info 1"); 303 } 304 break; 305 case 'I': 306 tree_parse(root, "/openprom/trace/print-info 2"); 307 tree_parse(root, "/openprom/options/model-issue %d", 308 MODEL_ISSUE_PROCESS); 309 break; 310 case 'm': 311 param = find_arg("Missing <model> option for -m (model)\n", &argp, argv); 312 tree_parse(root, "/openprom/options/model \"%s", param); 313 break; 314 case 'n': 315 param = find_arg("Missing <nr-smp> option for -n (smp)\n", &argp, argv); 316 tree_parse(root, "/openprom/options/smp %s", param); 317 break; 318 case 'o': 319 param = find_arg("Missing <dev-spec> option for -o\n", &argp, argv); 320 if (memcmp(param, "mpc860c0", 8) == 0) 321 { 322 if (param[8] == '\0') 323 tree_parse(root, "/options/mpc860c0 5"); 324 else if (param[8] == '=' && is_num(param+9, 1, 10, 0)) 325 { 326 tree_parse(root, "/options/mpc860c0 %s", param+9); 327 } 328 else error("Invalid mpc860c0 option for -o\n"); 329 } 330 else 331 current = tree_parse(current, "%s", param); 332 break; 333 case 'r': 334 param = find_arg("Missing <ram-size> option for -r (oea-memory-size)\n", &argp, argv); 335 tree_parse(root, "/openprom/options/oea-memory-size %s", 336 param); 337 break; 338 case 't': 339 param = find_arg("Missing <trace> option for -t (trace/*)\n", &argp, argv); 340 if (param[0] == '!') 341 tree_parse(root, "/openprom/trace/%s 0", param+1); 342 else 343 tree_parse(root, "/openprom/trace/%s 1", param); 344 break; 345 case '-': 346 /* it's a long option of the form --optionname=optionvalue. 347 Such options can be passed through if we are invoked by 348 gdb. */ 349 if (strstr(argv[argp], "architecture") != NULL) { 350 /* we must consume the argument here, so that we get out 351 of the loop. */ 352 p = argv[argp] + strlen(argv[argp]) - 1; 353 printf_filtered("Warning - architecture parameter ignored\n"); 354 } 355 else 356 error("Unrecognized option"); 357 break; 358 } 359 p += 1; 360 } 361 argp += 1; 362 } 363 /* force the trace node to process its options now *before* the tree 364 initialization occures */ 365 device_ioctl(tree_find_device(root, "/openprom/trace"), 366 NULL, 0, 367 device_ioctl_set_trace); 368 369 { 370 void semantic_init(device* root); 371 semantic_init(root); 372 } 373 374 /* return where the options end */ 375 return argv + argp; 376} 377 378INLINE_PSIM\ 379(void) 380psim_command(device *root, 381 char **argv) 382{ 383 int argp = 0; 384 if (argv[argp] == NULL) { 385 return; 386 } 387 else if (strcmp(argv[argp], "trace") == 0) { 388 const char *opt = find_arg("Missing <trace> option", &argp, argv); 389 if (opt[0] == '!') 390 trace_option(opt + 1, 0); 391 else 392 trace_option(opt, 1); 393 } 394 else if (strcmp(*argv, "change-media") == 0) { 395 char *device = find_arg("Missing device name", &argp, argv); 396 char *media = argv[++argp]; 397 device_ioctl(tree_find_device(root, device), NULL, 0, 398 device_ioctl_change_media, media); 399 } 400 else { 401 printf_filtered("Unknown PSIM command %s, try\n", argv[argp]); 402 printf_filtered(" trace <trace-option>\n"); 403 printf_filtered(" change-media <device> [ <new-image> ]\n"); 404 } 405} 406 407 408/* create the simulator proper from the device tree and executable */ 409 410INLINE_PSIM\ 411(psim *) 412psim_create(const char *file_name, 413 device *root) 414{ 415 int cpu_nr; 416 const char *env; 417 psim *system; 418 os_emul *os_emulation; 419 int nr_cpus; 420 421 /* given this partially populated device tree, os_emul_create() uses 422 it and file_name to determine the selected emulation and hence 423 further populate the tree with any other required nodes. */ 424 425 os_emulation = os_emul_create(file_name, root); 426 if (os_emulation == NULL) 427 error("psim: either file %s was not reconized or unreconized or unknown os-emulation type\n", file_name); 428 429 /* fill in the missing real number of CPU's */ 430 nr_cpus = tree_find_integer_property(root, "/openprom/options/smp"); 431 if (MAX_NR_PROCESSORS < nr_cpus) 432 error("target and configured number of cpus conflict\n"); 433 434 /* fill in the missing TARGET BYTE ORDER information */ 435 current_target_byte_order 436 = (tree_find_boolean_property(root, "/options/little-endian?") 437 ? LITTLE_ENDIAN 438 : BIG_ENDIAN); 439 if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order) 440 error("target and configured byte order conflict\n"); 441 442 /* fill in the missing HOST BYTE ORDER information */ 443 current_host_byte_order = (current_host_byte_order = 1, 444 (*(char*)(¤t_host_byte_order) 445 ? LITTLE_ENDIAN 446 : BIG_ENDIAN)); 447 if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order) 448 error("host and configured byte order conflict\n"); 449 450 /* fill in the missing OEA/VEA information */ 451 env = tree_find_string_property(root, "/openprom/options/env"); 452 current_environment = ((strcmp(env, "user") == 0 453 || strcmp(env, "uea") == 0) 454 ? USER_ENVIRONMENT 455 : (strcmp(env, "virtual") == 0 456 || strcmp(env, "vea") == 0) 457 ? VIRTUAL_ENVIRONMENT 458 : (strcmp(env, "operating") == 0 459 || strcmp(env, "oea") == 0) 460 ? OPERATING_ENVIRONMENT 461 : 0); 462 if (current_environment == 0) 463 error("unreconized /options env property\n"); 464 if (CURRENT_ENVIRONMENT != current_environment) 465 error("target and configured environment conflict\n"); 466 467 /* fill in the missing ALLIGNMENT information */ 468 current_alignment 469 = (tree_find_boolean_property(root, "/openprom/options/strict-alignment?") 470 ? STRICT_ALIGNMENT 471 : NONSTRICT_ALIGNMENT); 472 if (CURRENT_ALIGNMENT != current_alignment) 473 error("target and configured alignment conflict\n"); 474 475 /* fill in the missing FLOATING POINT information */ 476 current_floating_point 477 = (tree_find_boolean_property(root, "/openprom/options/floating-point?") 478 ? HARD_FLOATING_POINT 479 : SOFT_FLOATING_POINT); 480 if (CURRENT_FLOATING_POINT != current_floating_point) 481 error("target and configured floating-point conflict\n"); 482 483 /* fill in the missing STDIO information */ 484 current_stdio 485 = (tree_find_boolean_property(root, "/openprom/options/use-stdio?") 486 ? DO_USE_STDIO 487 : DONT_USE_STDIO); 488 if (CURRENT_STDIO != current_stdio) 489 error("target and configured stdio interface conflict\n"); 490 491 /* sort out the level of detail for issue modeling */ 492 current_model_issue 493 = tree_find_integer_property(root, "/openprom/options/model-issue"); 494 if (CURRENT_MODEL_ISSUE != current_model_issue) 495 error("target and configured model-issue conflict\n"); 496 497 /* sort out our model architecture - wrong. 498 499 FIXME: this should be obtaining the required information from the 500 device tree via the "/chosen" property "cpu" which is an instance 501 (ihandle) for the only executing processor. By converting that 502 ihandle into the corresponding cpu's phandle and then querying 503 the "name" property, the cpu type can be determined. Ok? */ 504 505 model_set(tree_find_string_property(root, "/openprom/options/model")); 506 507 /* create things */ 508 system = ZALLOC(psim); 509 system->events = event_queue_create(); 510 system->memory = core_from_device(root); 511 system->monitor = mon_create(); 512 system->nr_cpus = nr_cpus; 513 system->os_emulation = os_emulation; 514 system->devices = root; 515 516 /* now all the processors attaching to each their per-cpu information */ 517 for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) { 518 system->processors[cpu_nr] = cpu_create(system, 519 system->memory, 520 mon_cpu(system->monitor, 521 cpu_nr), 522 system->os_emulation, 523 cpu_nr); 524 } 525 526 /* dump out the contents of the device tree */ 527 if (ppc_trace[trace_print_device_tree] || ppc_trace[trace_dump_device_tree]) 528 tree_print(root); 529 if (ppc_trace[trace_dump_device_tree]) 530 error(""); 531 532 return system; 533} 534 535 536/* allow the simulation to stop/restart abnormaly */ 537 538INLINE_PSIM\ 539(void) 540psim_set_halt_and_restart(psim *system, 541 void *halt_jmp_buf, 542 void *restart_jmp_buf) 543{ 544 system->path_to_halt = halt_jmp_buf; 545 system->path_to_restart = restart_jmp_buf; 546} 547 548INLINE_PSIM\ 549(void) 550psim_clear_halt_and_restart(psim *system) 551{ 552 system->path_to_halt = NULL; 553 system->path_to_restart = NULL; 554} 555 556INLINE_PSIM\ 557(void) 558psim_restart(psim *system, 559 int current_cpu) 560{ 561 ASSERT(current_cpu >= 0 && current_cpu < system->nr_cpus); 562 ASSERT(system->path_to_restart != NULL); 563 system->last_cpu = current_cpu; 564 longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1); 565} 566 567 568static void 569cntrl_c_simulation(void *data) 570{ 571 psim *system = data; 572 psim_halt(system, 573 psim_nr_cpus(system), 574 was_continuing, 575 TARGET_SIGNAL_INT); 576} 577 578INLINE_PSIM\ 579(void) 580psim_stop(psim *system) 581{ 582 event_queue_schedule_after_signal(psim_event_queue(system), 583 0 /*NOW*/, 584 cntrl_c_simulation, 585 system); 586} 587 588INLINE_PSIM\ 589(void) 590psim_halt(psim *system, 591 int current_cpu, 592 stop_reason reason, 593 int signal) 594{ 595 ASSERT(current_cpu >= 0 && current_cpu <= system->nr_cpus); 596 ASSERT(system->path_to_halt != NULL); 597 system->last_cpu = current_cpu; 598 system->halt_status.reason = reason; 599 system->halt_status.signal = signal; 600 if (current_cpu == system->nr_cpus) { 601 system->halt_status.cpu_nr = 0; 602 system->halt_status.program_counter = 603 cpu_get_program_counter(system->processors[0]); 604 } 605 else { 606 system->halt_status.cpu_nr = current_cpu; 607 system->halt_status.program_counter = 608 cpu_get_program_counter(system->processors[current_cpu]); 609 } 610 longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1); 611} 612 613 614INLINE_PSIM\ 615(int) 616psim_last_cpu(psim *system) 617{ 618 return system->last_cpu; 619} 620 621INLINE_PSIM\ 622(int) 623psim_nr_cpus(psim *system) 624{ 625 return system->nr_cpus; 626} 627 628INLINE_PSIM\ 629(psim_status) 630psim_get_status(psim *system) 631{ 632 return system->halt_status; 633} 634 635 636INLINE_PSIM\ 637(cpu *) 638psim_cpu(psim *system, 639 int cpu_nr) 640{ 641 if (cpu_nr < 0 || cpu_nr >= system->nr_cpus) 642 return NULL; 643 else 644 return system->processors[cpu_nr]; 645} 646 647 648INLINE_PSIM\ 649(device *) 650psim_device(psim *system, 651 const char *path) 652{ 653 return tree_find_device(system->devices, path); 654} 655 656INLINE_PSIM\ 657(event_queue *) 658psim_event_queue(psim *system) 659{ 660 return system->events; 661} 662 663 664 665STATIC_INLINE_PSIM\ 666(void) 667psim_max_iterations_exceeded(void *data) 668{ 669 psim *system = data; 670 psim_halt(system, 671 system->nr_cpus, /* halted during an event */ 672 was_signalled, 673 -1); 674} 675 676 677INLINE_PSIM\ 678(void) 679psim_init(psim *system) 680{ 681 int cpu_nr; 682 683 /* scrub the monitor */ 684 mon_init(system->monitor, system->nr_cpus); 685 686 /* trash any pending events */ 687 event_queue_init(system->events); 688 689 /* if needed, schedule a halt event. FIXME - In the future this 690 will be replaced by a more generic change to psim_command(). A 691 new command `schedule NNN halt' being added. */ 692 if (tree_find_property(system->devices, "/openprom/options/max-iterations")) { 693 event_queue_schedule(system->events, 694 tree_find_integer_property(system->devices, 695 "/openprom/options/max-iterations") - 2, 696 psim_max_iterations_exceeded, 697 system); 698 } 699 700 /* scrub all the cpus */ 701 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) 702 cpu_init(system->processors[cpu_nr]); 703 704 /* init all the devices (which updates the cpus) */ 705 tree_init(system->devices, system); 706 707 /* and the emulation (which needs an initialized device tree) */ 708 os_emul_init(system->os_emulation, system->nr_cpus); 709 710 /* now sync each cpu against the initialized state of its registers */ 711 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) { 712 cpu *processor = system->processors[cpu_nr]; 713 cpu_synchronize_context(processor, cpu_get_program_counter(processor)); 714 cpu_page_tlb_invalidate_all(processor); 715 } 716 717 /* force loop to start with first cpu */ 718 system->last_cpu = -1; 719} 720 721INLINE_PSIM\ 722(void) 723psim_stack(psim *system, 724 char **argv, 725 char **envp) 726{ 727 /* pass the stack device the argv/envp and let it work out what to 728 do with it */ 729 device *stack_device = tree_find_device(system->devices, 730 "/openprom/init/stack"); 731 if (stack_device != (device*)0) { 732 unsigned_word stack_pointer; 733 ASSERT (psim_read_register(system, 0, &stack_pointer, "sp", 734 cooked_transfer) > 0); 735 device_ioctl(stack_device, 736 NULL, /*cpu*/ 737 0, /*cia*/ 738 device_ioctl_create_stack, 739 stack_pointer, 740 argv, 741 envp); 742 } 743} 744 745 746 747/* SIMULATE INSTRUCTIONS, various different ways of achieving the same 748 thing */ 749 750INLINE_PSIM\ 751(void) 752psim_step(psim *system) 753{ 754 volatile int keep_running = 0; 755 idecode_run_until_stop(system, &keep_running, 756 system->events, system->processors, system->nr_cpus); 757} 758 759INLINE_PSIM\ 760(void) 761psim_run(psim *system) 762{ 763 idecode_run(system, 764 system->events, system->processors, system->nr_cpus); 765} 766 767 768/* storage manipulation functions */ 769 770INLINE_PSIM\ 771(int) 772psim_read_register(psim *system, 773 int which_cpu, 774 void *buf, 775 const char reg[], 776 transfer_mode mode) 777{ 778 register_descriptions description; 779 char *cooked_buf; 780 cpu *processor; 781 782 /* find our processor */ 783 if (which_cpu == MAX_NR_PROCESSORS) { 784 if (system->last_cpu == system->nr_cpus 785 || system->last_cpu == -1) 786 which_cpu = 0; 787 else 788 which_cpu = system->last_cpu; 789 } 790 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus); 791 792 processor = system->processors[which_cpu]; 793 794 /* find the register description */ 795 description = register_description(reg); 796 if (description.type == reg_invalid) 797 return 0; 798 cooked_buf = alloca (description.size); 799 800 /* get the cooked value */ 801 switch (description.type) { 802 803 case reg_gpr: 804 *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index]; 805 break; 806 807 case reg_spr: 808 *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index]; 809 break; 810 811 case reg_sr: 812 *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index]; 813 break; 814 815 case reg_fpr: 816 *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index]; 817 break; 818 819 case reg_pc: 820 *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor); 821 break; 822 823 case reg_cr: 824 *(creg*)cooked_buf = cpu_registers(processor)->cr; 825 break; 826 827 case reg_msr: 828 *(msreg*)cooked_buf = cpu_registers(processor)->msr; 829 break; 830 831 case reg_fpscr: 832 *(fpscreg*)cooked_buf = cpu_registers(processor)->fpscr; 833 break; 834 835 case reg_insns: 836 *(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor, 837 which_cpu); 838 break; 839 840 case reg_stalls: 841 if (cpu_model(processor) == NULL) 842 error("$stalls only valid if processor unit model enabled (-I)\n"); 843 *(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor)); 844 break; 845 846 case reg_cycles: 847 if (cpu_model(processor) == NULL) 848 error("$cycles only valid if processor unit model enabled (-I)\n"); 849 *(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor)); 850 break; 851 852#ifdef WITH_ALTIVEC 853 case reg_vr: 854 *(vreg*)cooked_buf = cpu_registers(processor)->altivec.vr[description.index]; 855 break; 856 857 case reg_vscr: 858 *(vscreg*)cooked_buf = cpu_registers(processor)->altivec.vscr; 859 break; 860#endif 861 862#ifdef WITH_E500 863 case reg_gprh: 864 *(gpreg*)cooked_buf = cpu_registers(processor)->e500.gprh[description.index]; 865 break; 866 867 case reg_evr: 868 *(unsigned64*)cooked_buf = EVR(description.index); 869 break; 870 871 case reg_acc: 872 *(accreg*)cooked_buf = cpu_registers(processor)->e500.acc; 873 break; 874#endif 875 876 default: 877 printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n", 878 (unsigned long)processor, (unsigned long)buf, reg, 879 "read of this register unimplemented"); 880 break; 881 882 } 883 884 /* the PSIM internal values are in host order. To fetch raw data, 885 they need to be converted into target order and then returned */ 886 if (mode == raw_transfer) { 887 /* FIXME - assumes that all registers are simple integers */ 888 switch (description.size) { 889 case 1: 890 *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf); 891 break; 892 case 2: 893 *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf); 894 break; 895 case 4: 896 *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf); 897 break; 898 case 8: 899 *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf); 900 break; 901#ifdef WITH_ALTIVEC 902 case 16: 903 if (CURRENT_HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER) 904 { 905 union { vreg v; unsigned_8 d[2]; } h, t; 906 memcpy(&h.v/*dest*/, cooked_buf/*src*/, description.size); 907 { _SWAP_8(t.d[0] =, h.d[1]); } 908 { _SWAP_8(t.d[1] =, h.d[0]); } 909 memcpy(buf/*dest*/, &t/*src*/, description.size); 910 break; 911 } 912 else 913 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size); 914 break; 915#endif 916 } 917 } 918 else { 919 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size); 920 } 921 922 return description.size; 923} 924 925 926 927INLINE_PSIM\ 928(int) 929psim_write_register(psim *system, 930 int which_cpu, 931 const void *buf, 932 const char reg[], 933 transfer_mode mode) 934{ 935 cpu *processor; 936 register_descriptions description; 937 char *cooked_buf; 938 939 /* find our processor */ 940 if (which_cpu == MAX_NR_PROCESSORS) { 941 if (system->last_cpu == system->nr_cpus 942 || system->last_cpu == -1) 943 which_cpu = 0; 944 else 945 which_cpu = system->last_cpu; 946 } 947 948 /* find the description of the register */ 949 description = register_description(reg); 950 if (description.type == reg_invalid) 951 return 0; 952 cooked_buf = alloca (description.size); 953 954 if (which_cpu == -1) { 955 int i; 956 for (i = 0; i < system->nr_cpus; i++) 957 psim_write_register(system, i, buf, reg, mode); 958 return description.size; 959 } 960 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus); 961 962 processor = system->processors[which_cpu]; 963 964 /* If the data is comming in raw (target order), need to cook it 965 into host order before putting it into PSIM's internal structures */ 966 if (mode == raw_transfer) { 967 switch (description.size) { 968 case 1: 969 *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf); 970 break; 971 case 2: 972 *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf); 973 break; 974 case 4: 975 *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf); 976 break; 977 case 8: 978 *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf); 979 break; 980#ifdef WITH_ALTIVEC 981 case 16: 982 if (CURRENT_HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER) 983 { 984 union { vreg v; unsigned_8 d[2]; } h, t; 985 memcpy(&t.v/*dest*/, buf/*src*/, description.size); 986 { _SWAP_8(h.d[0] =, t.d[1]); } 987 { _SWAP_8(h.d[1] =, t.d[0]); } 988 memcpy(cooked_buf/*dest*/, &h/*src*/, description.size); 989 break; 990 } 991 else 992 memcpy(cooked_buf/*dest*/, buf/*src*/, description.size); 993#endif 994 } 995 } 996 else { 997 memcpy(cooked_buf/*dest*/, buf/*src*/, description.size); 998 } 999 1000 /* put the cooked value into the register */ 1001 switch (description.type) { 1002 1003 case reg_gpr: 1004 cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf; 1005 break; 1006 1007 case reg_fpr: 1008 cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf; 1009 break; 1010 1011 case reg_pc: 1012 cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf); 1013 break; 1014 1015 case reg_spr: 1016 cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf; 1017 break; 1018 1019 case reg_sr: 1020 cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf; 1021 break; 1022 1023 case reg_cr: 1024 cpu_registers(processor)->cr = *(creg*)cooked_buf; 1025 break; 1026 1027 case reg_msr: 1028 cpu_registers(processor)->msr = *(msreg*)cooked_buf; 1029 break; 1030 1031 case reg_fpscr: 1032 cpu_registers(processor)->fpscr = *(fpscreg*)cooked_buf; 1033 break; 1034 1035#ifdef WITH_E500 1036 case reg_gprh: 1037 cpu_registers(processor)->e500.gprh[description.index] = *(gpreg*)cooked_buf; 1038 break; 1039 1040 case reg_evr: 1041 { 1042 unsigned64 v; 1043 v = *(unsigned64*)cooked_buf; 1044 cpu_registers(processor)->e500.gprh[description.index] = v >> 32; 1045 cpu_registers(processor)->gpr[description.index] = v; 1046 break; 1047 } 1048 1049 case reg_acc: 1050 cpu_registers(processor)->e500.acc = *(accreg*)cooked_buf; 1051 break; 1052#endif 1053 1054#ifdef WITH_ALTIVEC 1055 case reg_vr: 1056 cpu_registers(processor)->altivec.vr[description.index] = *(vreg*)cooked_buf; 1057 break; 1058 1059 case reg_vscr: 1060 cpu_registers(processor)->altivec.vscr = *(vscreg*)cooked_buf; 1061 break; 1062#endif 1063 1064 default: 1065 printf_filtered("psim_write_register(processor=0x%lx,cooked_buf=0x%lx,reg=%s) %s\n", 1066 (unsigned long)processor, (unsigned long)cooked_buf, reg, 1067 "read of this register unimplemented"); 1068 break; 1069 1070 } 1071 1072 return description.size; 1073} 1074 1075 1076 1077INLINE_PSIM\ 1078(unsigned) 1079psim_read_memory(psim *system, 1080 int which_cpu, 1081 void *buffer, 1082 unsigned_word vaddr, 1083 unsigned nr_bytes) 1084{ 1085 cpu *processor; 1086 if (which_cpu == MAX_NR_PROCESSORS) { 1087 if (system->last_cpu == system->nr_cpus 1088 || system->last_cpu == -1) 1089 which_cpu = 0; 1090 else 1091 which_cpu = system->last_cpu; 1092 } 1093 processor = system->processors[which_cpu]; 1094 return vm_data_map_read_buffer(cpu_data_map(processor), 1095 buffer, vaddr, nr_bytes, 1096 NULL, -1); 1097} 1098 1099 1100INLINE_PSIM\ 1101(unsigned) 1102psim_write_memory(psim *system, 1103 int which_cpu, 1104 const void *buffer, 1105 unsigned_word vaddr, 1106 unsigned nr_bytes, 1107 int violate_read_only_section) 1108{ 1109 cpu *processor; 1110 if (which_cpu == MAX_NR_PROCESSORS) { 1111 if (system->last_cpu == system->nr_cpus 1112 || system->last_cpu == -1) 1113 which_cpu = 0; 1114 else 1115 which_cpu = system->last_cpu; 1116 } 1117 ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus); 1118 processor = system->processors[which_cpu]; 1119 return vm_data_map_write_buffer(cpu_data_map(processor), 1120 buffer, vaddr, nr_bytes, 1/*violate-read-only*/, 1121 NULL, -1); 1122} 1123 1124 1125INLINE_PSIM\ 1126(void) 1127psim_print_info(psim *system, 1128 int verbose) 1129{ 1130 mon_print_info(system, system->monitor, verbose); 1131} 1132 1133 1134/* Merge a device tree and a device file. */ 1135 1136INLINE_PSIM\ 1137(void) 1138psim_merge_device_file(device *root, 1139 const char *file_name) 1140{ 1141 FILE *description; 1142 int line_nr; 1143 char device_path[1000]; 1144 device *current; 1145 1146 /* try opening the file */ 1147 description = fopen(file_name, "r"); 1148 if (description == NULL) { 1149 perror(file_name); 1150 error("Invalid file %s specified", file_name); 1151 } 1152 1153 line_nr = 0; 1154 current = root; 1155 while (fgets(device_path, sizeof(device_path), description)) { 1156 char *device; 1157 /* check that the full line was read */ 1158 if (strchr(device_path, '\n') == NULL) { 1159 fclose(description); 1160 error("%s:%d: line to long - %s", 1161 file_name, line_nr, device_path); 1162 } 1163 else 1164 *strchr(device_path, '\n') = '\0'; 1165 line_nr++; 1166 /* skip comments ("#" or ";") and blank lines lines */ 1167 for (device = device_path; 1168 *device != '\0' && isspace(*device); 1169 device++); 1170 if (device[0] == '#' 1171 || device[0] == ';' 1172 || device[0] == '\0') 1173 continue; 1174 /* merge any appended lines */ 1175 while (device_path[strlen(device_path) - 1] == '\\') { 1176 int curlen = strlen(device_path) - 1; 1177 /* zap \ */ 1178 device_path[curlen] = '\0'; 1179 /* append the next line */ 1180 if (!fgets(device_path + curlen, sizeof(device_path) - curlen, description)) { 1181 fclose(description); 1182 error("%s:%s: unexpected eof in line continuation - %s", 1183 file_name, line_nr, device_path); 1184 } 1185 if (strchr(device_path, '\n') == NULL) { 1186 fclose(description); 1187 error("%s:%d: line to long - %s", 1188 file_name, line_nr, device_path); 1189 } 1190 else 1191 *strchr(device_path, '\n') = '\0'; 1192 line_nr++; 1193 } 1194 /* parse this line */ 1195 current = tree_parse(current, "%s", device); 1196 } 1197 fclose(description); 1198} 1199 1200 1201#endif /* _PSIM_C_ */ 1202