Fix typo that clobbered the stack and rewrite 2/26 change
[external/binutils.git] / sim / ppc / psim.c
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 _PSIM_C_
23 #define _PSIM_C_
24
25 #include "inline.c"
26
27 #include <stdio.h>
28 #include <ctype.h>
29
30 #ifdef HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif
33
34 #include <setjmp.h>
35
36 #include "cpu.h" /* includes psim.h */
37 #include "idecode.h"
38 #include "options.h"
39
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #else
43 #ifdef HAVE_STRINGS_H
44 #include <strings.h>
45 #endif
46 #endif
47
48 #include "bfd.h"
49
50
51 /* system structure, actual size of processor array determined at
52    runtime */
53
54 struct _psim {
55   event_queue *events;
56   device *devices;
57   mon *monitor;
58   os_emul *os_emulation;
59   core *memory;
60
61   /* escape routine for inner functions */
62   void *path_to_halt;
63   void *path_to_restart;
64
65   /* status from last halt */
66   psim_status halt_status;
67
68   /* the processors proper */
69   int nr_cpus;
70   int last_cpu; /* CPU that last (tried to) execute an instruction */
71   cpu *processors[MAX_NR_PROCESSORS];
72 };
73
74
75 int current_target_byte_order;
76 int current_host_byte_order;
77 int current_environment;
78 int current_alignment;
79 int current_floating_point;
80 int current_model_issue = MODEL_ISSUE_IGNORE;
81 model_enum current_model = WITH_DEFAULT_MODEL;
82
83
84 /* create the device tree */
85
86 INLINE_PSIM\
87 (device *)
88 psim_tree(void)
89 {
90   device *root = core_device_create();
91   device_tree_add_parsed(root, "/aliases");
92   device_tree_add_parsed(root, "/options");
93   device_tree_add_parsed(root, "/chosen");
94   device_tree_add_parsed(root, "/packages");
95   device_tree_add_parsed(root, "/cpus");
96   device_tree_add_parsed(root, "/openprom");
97   device_tree_add_parsed(root, "/openprom/init");
98   device_tree_add_parsed(root, "/openprom/trace");
99   device_tree_add_parsed(root, "/openprom/options");
100   return root;
101 }
102
103 STATIC_INLINE_PSIM\
104 (char *)
105 find_arg(char *err_msg,
106          int *ptr_to_argp,
107          char **argv)
108 {
109   *ptr_to_argp += 1;
110   if (argv[*ptr_to_argp] == NULL)
111     error(err_msg);
112   return argv[*ptr_to_argp];
113 }
114
115 INLINE_PSIM\
116 (void)
117 psim_usage(int verbose)
118 {
119   printf_filtered("Usage:\n");
120   printf_filtered("\n");
121   printf_filtered("\tpsim [ <psim-option> ... ] <image> [ <image-arg> ... ]\n");
122   printf_filtered("\n");
123   printf_filtered("Where\n");
124   printf_filtered("\n");
125   printf_filtered("\t<image>       Name of the PowerPC program to run.\n");
126   if (verbose) {
127   printf_filtered("\t              This can either be a PowerPC binary or\n");
128   printf_filtered("\t              a text file containing a device tree\n");
129   printf_filtered("\t              specification.\n");
130   printf_filtered("\t              PSIM will attempt to determine from the\n");
131   printf_filtered("\t              specified <image> the intended emulation\n");
132   printf_filtered("\t              environment.\n");
133   printf_filtered("\t              If PSIM gets it wrong, the emulation\n");
134   printf_filtered("\t              environment can be specified using the\n");
135   printf_filtered("\t              `-e' option (described below).\n");
136   printf_filtered("\n"); }
137   printf_filtered("\t<image-arg>   Argument to be passed to <image>\n");
138   if (verbose) {
139   printf_filtered("\t              These arguments will be passed to\n");
140   printf_filtered("\t              <image> (as standard C argv, argc)\n");
141   printf_filtered("\t              when <image> is started.\n");
142   printf_filtered("\n"); }
143   printf_filtered("\t<psim-option> See below\n");
144   printf_filtered("\n");
145   printf_filtered("The following are valid <psim-option>s:\n");
146   printf_filtered("\n");
147   printf_filtered("\t-m <model>    Specify the processor to model (604)\n");
148   if (verbose) {
149   printf_filtered("\t              Selects the processor to use when\n");
150   printf_filtered("\t              modeling execution units.  Includes:\n");
151   printf_filtered("\t              604, 603 and 603e\n");
152   printf_filtered("\n"); }
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              chirp - OEA + a few OpenBoot calls\n");
159   printf_filtered("\n"); }
160   printf_filtered("\t-i            Print instruction counting statistics\n");
161   if (verbose) { printf_filtered("\n"); }
162   printf_filtered("\t-I            Print execution unit statistics\n");
163   if (verbose) { printf_filtered("\n"); }
164   printf_filtered("\t-r <size>     Set RAM size in bytes (OEA environments)\n");
165   if (verbose) { printf_filtered("\n"); }
166   printf_filtered("\t-t [!]<trace> Enable (disable) <trace> option\n");
167   if (verbose) { printf_filtered("\n"); }
168   printf_filtered("\t-o <spec>     add device <spec> to the device tree\n");
169   if (verbose) { printf_filtered("\n"); }
170   printf_filtered("\t-h -? -H      give more detailed usage\n");
171   if (verbose) { printf_filtered("\n"); }
172   printf_filtered("\n");
173   trace_usage(verbose);
174   device_usage(verbose);
175   if (verbose > 1) {
176     printf_filtered("\n");
177     print_options();
178   }
179   error("");
180 }
181
182 INLINE_PSIM\
183 (char **)
184 psim_options(device *root,
185              char **argv)
186 {
187   device *current = root;
188   int argp;
189   if (argv == NULL)
190     return NULL;
191   argp = 0;
192   while (argv[argp] != NULL && argv[argp][0] == '-') {
193     char *p = argv[argp] + 1;
194     char *param;
195     while (*p != '\0') {
196       switch (*p) {
197       default:
198         psim_usage(0);
199         error ("");
200         break;
201       case 'e':
202         param = find_arg("Missing <emul> option for -e\n", &argp, argv);
203         device_tree_add_parsed(root, "/openprom/options/os-emul %s", param);
204         break;
205       case 'h':
206       case '?':
207         psim_usage(1);
208         break;
209       case 'H':
210         psim_usage(2);
211         break;
212       case 'i':
213         device_tree_add_parsed(root, "/openprom/trace/print-info 1");
214         break;
215       case 'I':
216         device_tree_add_parsed(root, "/openprom/trace/print-info 2");
217         device_tree_add_parsed(root, "/openprom/options/model-issue %d",
218                                MODEL_ISSUE_PROCESS);
219         break;
220       case 'm':
221         param = find_arg("Missing <model> option for -m\n", &argp, argv);
222         device_tree_add_parsed(root, "/openprom/options/model \"%s", param);
223         break;
224       case 'o':
225         param = find_arg("Missing <device> option for -o\n", &argp, argv);
226         current = device_tree_add_parsed(current, "%s", param);
227         break;
228       case 'r':
229         param = find_arg("Missing <ram-size> option for -r\n", &argp, argv);
230         device_tree_add_parsed(root, "/openprom/options/oea-memory-size 0x%lx",
231                                atol(param));
232         break;
233       case 't':
234         param = find_arg("Missing <trace> option for -t\n", &argp, argv);
235         if (param[0] == '!')
236           device_tree_add_parsed(root, "/openprom/trace/%s 0", param+1);
237         else
238           device_tree_add_parsed(root, "/openprom/trace/%s 1", param);
239         break;
240       }
241       p += 1;
242     }
243     argp += 1;
244   }
245   /* force the trace node to (re)process its options */
246   device_init_data(device_tree_find_device(root, "/openprom/trace"), NULL);
247   /* return where the options end */
248   return argv + argp;
249 }
250
251
252 /* create the simulator proper from the device tree and executable */
253
254 INLINE_PSIM\
255 (psim *)
256 psim_create(const char *file_name,
257             device *root)
258 {
259   int cpu_nr;
260   const char *env;
261   psim *system;
262   os_emul *os_emulation;
263   int nr_cpus;
264
265   /* given this partially populated device tree, os_emul_create() uses
266      it and file_name to determine the selected emulation and hence
267      further populate the tree with any other required nodes. */
268
269   os_emulation = os_emul_create(file_name, root);
270   if (os_emulation == NULL)
271     error("psim: either file %s was not reconized or unreconized or unknown os-emulation type\n", file_name);
272
273   /* fill in the missing real number of CPU's */
274   nr_cpus = device_find_integer_property(root, "/openprom/options/smp");
275   if (MAX_NR_PROCESSORS < nr_cpus)
276     error("target and configured number of cpus conflict\n");
277
278   /* fill in the missing TARGET BYTE ORDER information */
279   current_target_byte_order
280     = (device_find_boolean_property(root, "/options/little-endian?")
281        ? LITTLE_ENDIAN
282        : BIG_ENDIAN);
283   if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
284     error("target and configured byte order conflict\n");
285
286   /* fill in the missing HOST BYTE ORDER information */
287   current_host_byte_order = (current_host_byte_order = 1,
288                              (*(char*)(&current_host_byte_order)
289                               ? LITTLE_ENDIAN
290                               : BIG_ENDIAN));
291   if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order)
292     error("host and configured byte order conflict\n");
293
294   /* fill in the missing OEA/VEA information */
295   env = device_find_string_property(root, "/openprom/options/env");
296   current_environment = ((strcmp(env, "user") == 0
297                           || strcmp(env, "uea") == 0)
298                          ? USER_ENVIRONMENT
299                          : (strcmp(env, "virtual") == 0
300                             || strcmp(env, "vea") == 0)
301                          ? VIRTUAL_ENVIRONMENT
302                          : (strcmp(env, "operating") == 0
303                             || strcmp(env, "oea") == 0)
304                          ? OPERATING_ENVIRONMENT
305                          : 0);
306   if (current_environment == 0)
307     error("unreconized /options env property\n");
308   if (CURRENT_ENVIRONMENT != current_environment)
309     error("target and configured environment conflict\n");
310
311   /* fill in the missing ALLIGNMENT information */
312   current_alignment
313     = (device_find_boolean_property(root, "/openprom/options/strict-alignment?")
314        ? STRICT_ALIGNMENT
315        : NONSTRICT_ALIGNMENT);
316   if (CURRENT_ALIGNMENT != current_alignment)
317     error("target and configured alignment conflict\n");
318
319   /* fill in the missing FLOATING POINT information */
320   current_floating_point
321     = (device_find_boolean_property(root, "/openprom/options/floating-point?")
322        ? HARD_FLOATING_POINT
323        : SOFT_FLOATING_POINT);
324   if (CURRENT_FLOATING_POINT != current_floating_point)
325     error("target and configured floating-point conflict\n");
326
327   /* sort out the level of detail for issue modeling */
328   current_model_issue
329     = device_find_integer_property(root, "/openprom/options/model-issue");
330   if (CURRENT_MODEL_ISSUE != current_model_issue)
331     error("target and configured model-issue conflict\n");
332
333   /* sort out our model architecture - wrong.
334
335      FIXME: this should be obtaining the required information from the
336      device tree via the "/chosen" property "cpu" which is an instance
337      (ihandle) for the only executing processor. By converting that
338      ihandle into the corresponding cpu's phandle and then querying
339      the "name" property, the cpu type can be determined. Ok? */
340
341   model_set(device_find_string_property(root, "/openprom/options/model"));
342
343   /* create things */
344   system = ZALLOC(psim);
345   system->events = event_queue_create();
346   system->memory = core_create(root);
347   system->monitor = mon_create();
348   system->nr_cpus = nr_cpus;
349   system->os_emulation = os_emulation;
350   system->devices = root;
351
352   /* now all the processors attaching to each their per-cpu information */
353   for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
354     system->processors[cpu_nr] = cpu_create(system,
355                                             system->memory,
356                                             system->events,
357                                             mon_cpu(system->monitor,
358                                                     cpu_nr),
359                                             system->os_emulation,
360                                             cpu_nr);
361   }
362
363   /* dump out the contents of the device tree */
364   if (ppc_trace[trace_print_device_tree] || ppc_trace[trace_dump_device_tree])
365     device_tree_traverse(root, device_tree_print_device, NULL, NULL);
366   if (ppc_trace[trace_dump_device_tree])
367     error("");
368
369   return system;
370 }
371
372
373 /* allow the simulation to stop/restart abnormaly */
374
375 STATIC_INLINE_PSIM\
376 (void)
377 psim_set_halt_and_restart(psim *system,
378                           void *halt_jmp_buf,
379                           void *restart_jmp_buf)
380 {
381   system->path_to_halt = halt_jmp_buf;
382   system->path_to_restart = restart_jmp_buf;
383 }
384
385 STATIC_INLINE_PSIM\
386 (void)
387 psim_clear_halt_and_restart(psim *system)
388 {
389   system->path_to_halt = NULL;
390   system->path_to_restart = NULL;
391 }
392
393 INLINE_PSIM\
394 (void)
395 psim_restart(psim *system,
396              int current_cpu)
397 {
398   system->last_cpu = current_cpu;
399   longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1);
400 }
401
402
403 INLINE_PSIM\
404 (void)
405 psim_halt(psim *system,
406           int current_cpu,
407           unsigned_word cia,
408           stop_reason reason,
409           int signal)
410 {
411   system->last_cpu = current_cpu;
412   system->halt_status.cpu_nr = current_cpu;
413   system->halt_status.reason = reason;
414   system->halt_status.signal = signal;
415   system->halt_status.program_counter = cia;
416   longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
417 }
418
419 INLINE_PSIM\
420 (psim_status)
421 psim_get_status(psim *system)
422 {
423   return system->halt_status;
424 }
425
426
427 INLINE_PSIM\
428 (cpu *)
429 psim_cpu(psim *system,
430          int cpu_nr)
431 {
432   if (cpu_nr < 0 || cpu_nr >= system->nr_cpus)
433     return NULL;
434   else
435     return system->processors[cpu_nr];
436 }
437
438
439 INLINE_PSIM\
440 (device *)
441 psim_device(psim *system,
442             const char *path)
443 {
444   return device_tree_find_device(system->devices, path);
445 }
446
447
448
449 INLINE_PSIM\
450 (void)
451 psim_init(psim *system)
452 {
453   int cpu_nr;
454
455   /* scrub the monitor */
456   mon_init(system->monitor, system->nr_cpus);
457   os_emul_init(system->os_emulation, system->nr_cpus);
458   event_queue_init(system->events);
459
460   /* scrub all the cpus */
461   for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
462     cpu_init(system->processors[cpu_nr]);
463
464   /* init all the devices (which updates the cpus) */
465   device_tree_init(system->devices, system);
466
467   /* now sync each cpu against the initialized state of its registers */
468   for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) {
469     cpu_synchronize_context(system->processors[cpu_nr]);
470     cpu_page_tlb_invalidate_all(system->processors[cpu_nr]);
471   }
472
473   /* force loop to restart */
474   system->last_cpu = system->nr_cpus - 1;
475 }
476
477 INLINE_PSIM\
478 (void)
479 psim_stack(psim *system,
480            char **argv,
481            char **envp)
482 {
483   /* pass the stack device the argv/envp and let it work out what to
484      do with it */
485   device *stack_device = device_tree_find_device(system->devices,
486                                                  "/openprom/init/stack");
487   if (stack_device != (device*)0) {
488     unsigned_word stack_pointer;
489     psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer);
490     device_ioctl(stack_device,
491                  system,
492                  NULL, /*cpu*/
493                  0, /*cia*/
494                  stack_pointer,
495                  argv,
496                  envp);
497   }
498 }
499
500
501
502 /* EXECUTE REAL CODE: 
503
504    Unfortunatly, there are multiple cases to consider vis:
505
506         <icache> X <smp> X <events> X <keep-running-flag> X ...
507
508    Consequently this function is written in multiple different ways */
509
510 STATIC_INLINE_PSIM\
511 (void)
512 run_until_stop(psim *system,
513                volatile int *keep_running)
514 {
515   jmp_buf halt;
516   jmp_buf restart;
517 #if WITH_IDECODE_CACHE_SIZE
518   int cpu_nr;
519   for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
520     cpu_flush_icache(system->processors[cpu_nr]);
521 #endif
522   psim_set_halt_and_restart(system, &halt, &restart);
523
524 #if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
525
526   /* CASE 1: No instruction cache and no SMP.
527
528      In this case, we can take advantage of the fact that the current
529      instruction address does not need to be returned to the cpu
530      object after every execution of an instruction.  Instead it only
531      needs to be saved when either A. the main loop exits or B. a
532      cpu-{halt,restart} call forces the loop to be re-entered.  The
533      later functions always save the current cpu instruction
534      address. */
535
536   if (!setjmp(halt)) {
537     do {
538       if (!setjmp(restart)) {
539         cpu *const processor = system->processors[0];
540         unsigned_word cia = cpu_get_program_counter(processor);
541         do {
542           if (WITH_EVENTS) {
543             if (event_queue_tick(system->events)) {
544               cpu_set_program_counter(processor, cia);
545               event_queue_process(system->events);
546               cia = cpu_get_program_counter(processor);
547             }
548           }
549           {
550             instruction_word const instruction
551               = vm_instruction_map_read(cpu_instruction_map(processor),
552                                         processor, cia);
553             cia = idecode_issue(processor, instruction, cia);
554           }
555         } while (keep_running == NULL || *keep_running);
556         cpu_set_program_counter(processor, cia);
557       }
558     } while(keep_running == NULL || *keep_running);
559   }
560 #endif
561
562
563 #if (WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
564
565   /* CASE 2: Instruction case but no SMP
566
567      Here, the additional complexity comes from there being two
568      different cache implementations.  A simple function address cache
569      or a full cracked instruction cache */
570
571   if (!setjmp(halt)) {
572     do {
573       if (!setjmp(restart)) {
574         cpu *const processor = system->processors[0];
575         unsigned_word cia = cpu_get_program_counter(processor);
576         do {
577           if (WITH_EVENTS)
578             if (event_queue_tick(system->events)) {
579               cpu_set_program_counter(processor, cia);
580               event_queue_process(system->events);
581               cia = cpu_get_program_counter(processor);
582             }
583           { 
584             idecode_cache *const cache_entry = cpu_icache_entry(processor,
585                                                                 cia);
586             if (cache_entry->address == cia) {
587               idecode_semantic *const semantic = cache_entry->semantic;
588               cia = semantic(processor, cache_entry, cia);
589             }
590             else {
591               instruction_word const instruction
592                 = vm_instruction_map_read(cpu_instruction_map(processor),
593                                           processor,
594                                           cia);
595               idecode_semantic *const semantic = idecode(processor,
596                                                          instruction,
597                                                          cia,
598                                                          cache_entry);
599
600               if (WITH_MON != 0)
601                 mon_event(mon_event_icache_miss, processor, cia);
602               cache_entry->address = cia;
603               cache_entry->semantic = semantic;
604               cia = semantic(processor, cache_entry, cia);
605             }
606           }
607         } while (keep_running == NULL || *keep_running);
608         cpu_set_program_counter(processor, cia);
609       }
610     } while(keep_running == NULL || *keep_running);
611   }
612 #endif
613
614
615 #if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
616
617   /* CASE 3: No ICACHE but SMP
618
619      The complexity here comes from needing to correctly restart the
620      system when it is aborted.  In particular if cpu0 requests a
621      restart, the next cpu is still cpu1.  Cpu0 being restarted after
622      all the other CPU's and the event queue have been processed */
623
624   if (!setjmp(halt)) {
625     int first_cpu = setjmp(restart);
626     if (first_cpu == 0)
627       first_cpu = system->last_cpu + 1;
628     do {
629       int current_cpu;
630       for (current_cpu = first_cpu, first_cpu = 0;
631            current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
632            current_cpu++) {
633         if (WITH_EVENTS && current_cpu == system->nr_cpus) {
634           if (event_queue_tick(system->events))
635             event_queue_process(system->events);
636         }
637         else {
638           cpu *const processor = system->processors[current_cpu];
639           unsigned_word const cia = cpu_get_program_counter(processor);
640           instruction_word instruction =
641             vm_instruction_map_read(cpu_instruction_map(processor),
642                                     processor,
643                                     cia);
644           cpu_set_program_counter(processor,
645                                   idecode_issue(processor, instruction, cia));
646         }
647         if (!(keep_running == NULL || *keep_running)) {
648           system->last_cpu = current_cpu;
649           break;
650         }
651       }
652     } while (keep_running == NULL || *keep_running);
653   }
654 #endif
655
656 #if (WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
657
658   /* CASE 4: ICACHE and SMP ...
659
660      This time, everything goes wrong.  Need to restart loops
661      correctly, need to save the program counter and finally need to
662      keep track of each processors current address! */
663
664   if (!setjmp(halt)) {
665     int first_cpu = setjmp(restart);
666     if (!first_cpu)
667       first_cpu = system->last_cpu + 1;
668     do {
669       int current_cpu;
670       for (current_cpu = first_cpu, first_cpu = 0;
671            current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
672            current_cpu++) {
673         if (WITH_EVENTS && current_cpu == system->nr_cpus) {
674           if (event_queue_tick(system->events))
675             event_queue_process(system->events);
676         }
677         else {
678           cpu *processor = system->processors[current_cpu];
679           unsigned_word const cia = cpu_get_program_counter(processor);
680           idecode_cache *cache_entry = cpu_icache_entry(processor, cia);
681           if (cache_entry->address == cia) {
682             idecode_semantic *semantic = cache_entry->semantic;
683             cpu_set_program_counter(processor,
684                                     semantic(processor, cache_entry, cia));
685           }
686           else {
687             instruction_word instruction =
688               vm_instruction_map_read(cpu_instruction_map(processor),
689                                       processor,
690                                       cia);
691             idecode_semantic *semantic = idecode(processor,
692                                                  instruction,
693                                                  cia,
694                                                  cache_entry);
695
696             if (WITH_MON != 0)
697               mon_event(mon_event_icache_miss, system->processors[current_cpu], cia);
698             cache_entry->address = cia;
699             cache_entry->semantic = semantic;
700             cpu_set_program_counter(processor,
701                                     semantic(processor, cache_entry, cia));
702           }
703         }
704         if (!(keep_running == NULL || *keep_running))
705           break;
706       }
707     } while (keep_running == NULL || *keep_running);
708   }
709 #endif
710
711   psim_clear_halt_and_restart(system);
712 }
713
714
715 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
716    thing */
717
718 INLINE_PSIM\
719 (void)
720 psim_step(psim *system)
721 {
722   volatile int keep_running = 0;
723   run_until_stop(system, &keep_running);
724 }
725
726 INLINE_PSIM\
727 (void)
728 psim_run(psim *system)
729 {
730   run_until_stop(system, NULL);
731 }
732
733 INLINE_PSIM\
734 (void)
735 psim_run_until_stop(psim *system,
736                     volatile int *keep_running)
737 {
738   run_until_stop(system, keep_running);
739 }
740
741
742
743 /* storage manipulation functions */
744
745 INLINE_PSIM\
746 (void)
747 psim_read_register(psim *system,
748                    int which_cpu,
749                    void *buf,
750                    const char reg[],
751                    transfer_mode mode)
752 {
753   register_descriptions description;
754   char cooked_buf[sizeof(unsigned_8)];
755   cpu *processor;
756
757   /* find our processor */
758   if (which_cpu == MAX_NR_PROCESSORS)
759     which_cpu = system->last_cpu;
760   if (which_cpu < 0 || which_cpu >= system->nr_cpus)
761     error("psim_read_register() - invalid processor %d\n", which_cpu);
762   processor = system->processors[which_cpu];
763
764   /* find the register description */
765   description = register_description(reg);
766   if (description.type == reg_invalid)
767     error("psim_read_register() invalid register name `%s'\n", reg);
768
769   /* get the cooked value */
770   switch (description.type) {
771
772   case reg_gpr:
773     *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index];
774     break;
775
776   case reg_spr:
777     *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index];
778     break;
779     
780   case reg_sr:
781     *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index];
782     break;
783
784   case reg_fpr:
785     *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index];
786     break;
787
788   case reg_pc:
789     *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor);
790     break;
791
792   case reg_cr:
793     *(creg*)cooked_buf = cpu_registers(processor)->cr;
794     break;
795
796   case reg_msr:
797     *(msreg*)cooked_buf = cpu_registers(processor)->msr;
798     break;
799
800   default:
801     printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n",
802                     (unsigned long)processor, (unsigned long)buf, reg,
803                     "read of this register unimplemented");
804     break;
805
806   }
807
808   /* the PSIM internal values are in host order.  To fetch raw data,
809      they need to be converted into target order and then returned */
810   if (mode == raw_transfer) {
811     /* FIXME - assumes that all registers are simple integers */
812     switch (description.size) {
813     case 1: 
814       *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf);
815       break;
816     case 2:
817       *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf);
818       break;
819     case 4:
820       *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf);
821       break;
822     case 8:
823       *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf);
824       break;
825     }
826   }
827   else {
828     memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
829   }
830
831 }
832
833
834
835 INLINE_PSIM\
836 (void)
837 psim_write_register(psim *system,
838                     int which_cpu,
839                     const void *buf,
840                     const char reg[],
841                     transfer_mode mode)
842 {
843   cpu *processor;
844   register_descriptions description;
845   char cooked_buf[sizeof(unsigned_8)];
846
847   /* find our processor */
848   if (which_cpu == MAX_NR_PROCESSORS)
849     which_cpu = system->last_cpu;
850   if (which_cpu == -1) {
851     int i;
852     for (i = 0; i < system->nr_cpus; i++)
853       psim_write_register(system, i, buf, reg, mode);
854     return;
855   }
856   else if (which_cpu < 0 || which_cpu >= system->nr_cpus) {
857     error("psim_read_register() - invalid processor %d\n", which_cpu);
858   }
859
860   processor = system->processors[which_cpu];
861
862   /* find the description of the register */
863   description = register_description(reg);
864   if (description.type == reg_invalid)
865     error("psim_write_register() invalid register name %s\n", reg);
866
867   /* If the data is comming in raw (target order), need to cook it
868      into host order before putting it into PSIM's internal structures */
869   if (mode == raw_transfer) {
870     switch (description.size) {
871     case 1: 
872       *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf);
873       break;
874     case 2:
875       *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf);
876       break;
877     case 4:
878       *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf);
879       break;
880     case 8:
881       *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf);
882       break;
883     }
884   }
885   else {
886     memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
887   }
888
889   /* put the cooked value into the register */
890   switch (description.type) {
891
892   case reg_gpr:
893     cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf;
894     break;
895
896   case reg_fpr:
897     cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf;
898     break;
899
900   case reg_pc:
901     cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf);
902     break;
903
904   case reg_spr:
905     cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf;
906     break;
907
908   case reg_sr:
909     cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf;
910     break;
911
912   case reg_cr:
913     cpu_registers(processor)->cr = *(creg*)cooked_buf;
914     break;
915
916   case reg_msr:
917     cpu_registers(processor)->msr = *(msreg*)cooked_buf;
918     break;
919
920   default:
921     printf_filtered("psim_write_register(processor=0x%lx,cooked_buf=0x%lx,reg=%s) %s\n",
922                     (unsigned long)processor, (unsigned long)cooked_buf, reg,
923                     "read of this register unimplemented");
924     break;
925
926   }
927
928 }
929
930
931
932 INLINE_PSIM\
933 (unsigned)
934 psim_read_memory(psim *system,
935                  int which_cpu,
936                  void *buffer,
937                  unsigned_word vaddr,
938                  unsigned nr_bytes)
939 {
940   cpu *processor;
941   if (which_cpu == MAX_NR_PROCESSORS)
942     which_cpu = system->last_cpu;
943   if (which_cpu < 0 || which_cpu >= system->nr_cpus)
944     error("psim_read_memory() invalid cpu\n");
945   processor = system->processors[which_cpu];
946   return vm_data_map_read_buffer(cpu_data_map(processor),
947                                  buffer, vaddr, nr_bytes);
948 }
949
950
951 INLINE_PSIM\
952 (unsigned)
953 psim_write_memory(psim *system,
954                   int which_cpu,
955                   const void *buffer,
956                   unsigned_word vaddr,
957                   unsigned nr_bytes,
958                   int violate_read_only_section)
959 {
960   cpu *processor;
961   if (which_cpu == MAX_NR_PROCESSORS)
962     which_cpu = system->last_cpu;
963   if (which_cpu < 0 || which_cpu >= system->nr_cpus)
964     error("psim_read_memory() invalid cpu\n");
965   processor = system->processors[which_cpu];
966   return vm_data_map_write_buffer(cpu_data_map(processor),
967                                   buffer, vaddr, nr_bytes, 1);
968 }
969
970
971 INLINE_PSIM\
972 (void)
973 psim_print_info(psim *system,
974                 int verbose)
975 {
976   mon_print_info(system, system->monitor, verbose);
977 }
978
979
980 /* Merge a device tree and a device file. */
981
982 INLINE_PSIM\
983 (void)
984 psim_merge_device_file(device *root,
985                        const char *file_name)
986 {
987   FILE *description = fopen(file_name, "r");
988   int line_nr = 0;
989   char device_path[1000];
990   device *current = root;
991   while (fgets(device_path, sizeof(device_path), description)) {
992     /* check all of line was read */
993     if (strchr(device_path, '\n') == NULL) {
994       fclose(description);
995       error("create_filed_device_tree() line %d to long: %s\n",
996             line_nr, device_path);
997     }
998     line_nr++;
999     /* parse this line */
1000     current = device_tree_add_parsed(current, "%s", device_path);
1001   }
1002   fclose(description);
1003 }
1004
1005
1006 #endif /* _PSIM_C_ */