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