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