1 /* This file is part of the program psim.
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
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.
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.
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.
25 #include "cpu.h" /* includes psim.h */
52 /* system structure, actual size of processor array determined at
59 os_emul
*os_emulation
;
62 /* escape routine for inner functions */
64 void *path_to_restart
;
66 /* status from last halt */
67 psim_status halt_status
;
69 /* the processors proper */
71 int last_cpu
; /* CPU that last (tried to) execute an instruction */
72 cpu
*processors
[MAX_NR_PROCESSORS
];
76 int current_target_byte_order
;
77 int current_host_byte_order
;
78 int current_environment
;
79 int current_alignment
;
80 int current_floating_point
;
81 int current_model_issue
= MODEL_ISSUE_IGNORE
;
82 int current_stdio
= DO_USE_STDIO
;
83 model_enum current_model
= WITH_DEFAULT_MODEL
;
86 /* create the device tree */
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");
107 find_arg(char *err_msg
,
112 if (argv
[*ptr_to_argp
] == NULL
)
114 return argv
[*ptr_to_argp
];
119 psim_usage(int verbose
)
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");
127 printf_filtered("\t<image> Name of the PowerPC program to run.\n");
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");
138 printf_filtered("\n"); }
139 printf_filtered("\t<image-arg> Argument to be passed to <image>\n");
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");
144 printf_filtered("\n"); }
145 printf_filtered("\t<psim-option> See below\n");
146 printf_filtered("\n");
147 printf_filtered("The following are valid <psim-option>s:\n");
148 printf_filtered("\n");
150 printf_filtered("\t-i Print instruction counting statistics\n");
151 if (verbose
) { printf_filtered("\n"); }
153 printf_filtered("\t-I Print execution unit statistics\n");
154 if (verbose
) { printf_filtered("\n"); }
156 printf_filtered("\t-e <os-emul> specify an OS or platform to model\n");
158 printf_filtered("\t Can be any of the following:\n");
159 printf_filtered("\t bug - OEA + MOTO BUG ROM calls\n");
160 printf_filtered("\t netbsd - UEA + NetBSD system calls\n");
161 printf_filtered("\t solaris - UEA + Solaris system calls\n");
162 printf_filtered("\t linux - UEA + Linux system calls\n");
163 printf_filtered("\t chirp - OEA + a few OpenBoot calls\n");
164 printf_filtered("\n"); }
166 printf_filtered("\t-f <file> Merge <file> into the device tree\n");
167 if (verbose
) { printf_filtered("\n"); }
169 printf_filtered("\t-h -? -H give more detailed usage\n");
170 if (verbose
) { printf_filtered("\n"); }
172 printf_filtered("\t-m <model> Specify the processor to model (604)\n");
174 printf_filtered("\t Selects the processor to use when\n");
175 printf_filtered("\t modeling execution units. Includes:\n");
176 printf_filtered("\t 604, 603 and 603e\n");
177 printf_filtered("\n"); }
179 printf_filtered("\t-n <nr-smp> Specify the number of processors in SMP simulations\n");
181 printf_filtered("\t Specifies the number of processors that are\n");
182 printf_filtered("\t to be modeled in a symetric multi-processor (SMP)\n");
183 printf_filtered("\t simulation\n");
184 printf_filtered("\n"); }
186 printf_filtered("\t-o <dev-spec> Add device <dev-spec> to the device tree\n");
187 if (verbose
) { printf_filtered("\n"); }
189 printf_filtered("\t-r <ram-size> Set RAM size in bytes (OEA environments)\n");
190 if (verbose
) { printf_filtered("\n"); }
192 printf_filtered("\t-t [!]<trace> Enable (disable) <trace> option\n");
193 if (verbose
) { printf_filtered("\n"); }
195 printf_filtered("\n");
196 trace_usage(verbose
);
197 device_usage(verbose
);
199 printf_filtered("\n");
207 psim_options(device
*root
,
210 device
*current
= root
;
215 while (argv
[argp
] != NULL
&& argv
[argp
][0] == '-') {
216 char *p
= argv
[argp
] + 1;
225 param
= find_arg("Missing <emul> option for -e\n", &argp
, argv
);
226 tree_parse(root
, "/openprom/options/os-emul %s", param
);
229 param
= find_arg("Missing <file> option for -f\n", &argp
, argv
);
230 psim_merge_device_file(root
, param
);
240 tree_parse(root
, "/openprom/trace/print-info 1");
243 tree_parse(root
, "/openprom/trace/print-info 2");
244 tree_parse(root
, "/openprom/options/model-issue %d",
245 MODEL_ISSUE_PROCESS
);
248 param
= find_arg("Missing <model> option for -m\n", &argp
, argv
);
249 tree_parse(root
, "/openprom/options/model \"%s", param
);
252 param
= find_arg("Missing <nr-smp> option for -n\n", &argp
, argv
);
253 tree_parse(root
, "/openprom/options/smp %s", param
);
256 param
= find_arg("Missing <dev-spec> option for -o\n", &argp
, argv
);
257 current
= tree_parse(current
, "%s", param
);
260 param
= find_arg("Missing <ram-size> option for -r\n", &argp
, argv
);
261 tree_parse(root
, "/openprom/options/oea-memory-size %s",
265 param
= find_arg("Missing <trace> option for -t\n", &argp
, argv
);
267 tree_parse(root
, "/openprom/trace/%s 0", param
+1);
269 tree_parse(root
, "/openprom/trace/%s 1", param
);
276 /* force the trace node to process its options now *before* the tree
277 initialization occures */
278 device_ioctl(tree_find_device(root
, "/openprom/trace"),
280 device_ioctl_set_trace
);
282 /* return where the options end */
288 psim_command(device
*root
,
292 if (argv
[argp
] == NULL
) {
295 else if (strcmp(argv
[argp
], "trace") == 0) {
296 const char *opt
= find_arg("Missing <trace> option", &argp
, argv
);
298 trace_option(opt
+ 1, 0);
300 trace_option(opt
, 1);
302 else if (strcmp(*argv
, "change-media") == 0) {
303 char *device
= find_arg("Missing device name", &argp
, argv
);
304 char *media
= argv
[++argp
];
305 device_ioctl(tree_find_device(root
, device
), NULL
, 0,
306 device_ioctl_change_media
, media
);
309 printf_filtered("Unknown PSIM command %s, try\n", argv
[argp
]);
310 printf_filtered(" trace <trace-option>\n");
311 printf_filtered(" change-media <device> [ <new-image> ]\n");
316 /* create the simulator proper from the device tree and executable */
320 psim_create(const char *file_name
,
326 os_emul
*os_emulation
;
329 /* given this partially populated device tree, os_emul_create() uses
330 it and file_name to determine the selected emulation and hence
331 further populate the tree with any other required nodes. */
333 os_emulation
= os_emul_create(file_name
, root
);
334 if (os_emulation
== NULL
)
335 error("psim: either file %s was not reconized or unreconized or unknown os-emulation type\n", file_name
);
337 /* fill in the missing real number of CPU's */
338 nr_cpus
= tree_find_integer_property(root
, "/openprom/options/smp");
339 if (MAX_NR_PROCESSORS
< nr_cpus
)
340 error("target and configured number of cpus conflict\n");
342 /* fill in the missing TARGET BYTE ORDER information */
343 current_target_byte_order
344 = (tree_find_boolean_property(root
, "/options/little-endian?")
347 if (CURRENT_TARGET_BYTE_ORDER
!= current_target_byte_order
)
348 error("target and configured byte order conflict\n");
350 /* fill in the missing HOST BYTE ORDER information */
351 current_host_byte_order
= (current_host_byte_order
= 1,
352 (*(char*)(¤t_host_byte_order
)
355 if (CURRENT_HOST_BYTE_ORDER
!= current_host_byte_order
)
356 error("host and configured byte order conflict\n");
358 /* fill in the missing OEA/VEA information */
359 env
= tree_find_string_property(root
, "/openprom/options/env");
360 current_environment
= ((strcmp(env
, "user") == 0
361 || strcmp(env
, "uea") == 0)
363 : (strcmp(env
, "virtual") == 0
364 || strcmp(env
, "vea") == 0)
365 ? VIRTUAL_ENVIRONMENT
366 : (strcmp(env
, "operating") == 0
367 || strcmp(env
, "oea") == 0)
368 ? OPERATING_ENVIRONMENT
370 if (current_environment
== 0)
371 error("unreconized /options env property\n");
372 if (CURRENT_ENVIRONMENT
!= current_environment
)
373 error("target and configured environment conflict\n");
375 /* fill in the missing ALLIGNMENT information */
377 = (tree_find_boolean_property(root
, "/openprom/options/strict-alignment?")
379 : NONSTRICT_ALIGNMENT
);
380 if (CURRENT_ALIGNMENT
!= current_alignment
)
381 error("target and configured alignment conflict\n");
383 /* fill in the missing FLOATING POINT information */
384 current_floating_point
385 = (tree_find_boolean_property(root
, "/openprom/options/floating-point?")
386 ? HARD_FLOATING_POINT
387 : SOFT_FLOATING_POINT
);
388 if (CURRENT_FLOATING_POINT
!= current_floating_point
)
389 error("target and configured floating-point conflict\n");
391 /* fill in the missing STDIO information */
393 = (tree_find_boolean_property(root
, "/openprom/options/use-stdio?")
396 if (CURRENT_STDIO
!= current_stdio
)
397 error("target and configured stdio interface conflict\n");
399 /* sort out the level of detail for issue modeling */
401 = tree_find_integer_property(root
, "/openprom/options/model-issue");
402 if (CURRENT_MODEL_ISSUE
!= current_model_issue
)
403 error("target and configured model-issue conflict\n");
405 /* sort out our model architecture - wrong.
407 FIXME: this should be obtaining the required information from the
408 device tree via the "/chosen" property "cpu" which is an instance
409 (ihandle) for the only executing processor. By converting that
410 ihandle into the corresponding cpu's phandle and then querying
411 the "name" property, the cpu type can be determined. Ok? */
413 model_set(tree_find_string_property(root
, "/openprom/options/model"));
416 system
= ZALLOC(psim
);
417 system
->events
= event_queue_create();
418 system
->memory
= core_from_device(root
);
419 system
->monitor
= mon_create();
420 system
->nr_cpus
= nr_cpus
;
421 system
->os_emulation
= os_emulation
;
422 system
->devices
= root
;
424 /* now all the processors attaching to each their per-cpu information */
425 for (cpu_nr
= 0; cpu_nr
< MAX_NR_PROCESSORS
; cpu_nr
++) {
426 system
->processors
[cpu_nr
] = cpu_create(system
,
428 mon_cpu(system
->monitor
,
430 system
->os_emulation
,
434 /* dump out the contents of the device tree */
435 if (ppc_trace
[trace_print_device_tree
] || ppc_trace
[trace_dump_device_tree
])
437 if (ppc_trace
[trace_dump_device_tree
])
444 /* allow the simulation to stop/restart abnormaly */
448 psim_set_halt_and_restart(psim
*system
,
450 void *restart_jmp_buf
)
452 system
->path_to_halt
= halt_jmp_buf
;
453 system
->path_to_restart
= restart_jmp_buf
;
458 psim_clear_halt_and_restart(psim
*system
)
460 system
->path_to_halt
= NULL
;
461 system
->path_to_restart
= NULL
;
466 psim_restart(psim
*system
,
469 system
->last_cpu
= current_cpu
;
470 longjmp(*(jmp_buf*)(system
->path_to_restart
), current_cpu
+ 1);
476 psim_halt(psim
*system
,
481 ASSERT(current_cpu
>= 0 && current_cpu
< system
->nr_cpus
);
482 system
->last_cpu
= current_cpu
;
483 system
->halt_status
.cpu_nr
= current_cpu
;
484 system
->halt_status
.reason
= reason
;
485 system
->halt_status
.signal
= signal
;
486 system
->halt_status
.program_counter
=
487 cpu_get_program_counter(system
->processors
[current_cpu
]);
488 longjmp(*(jmp_buf*)(system
->path_to_halt
), current_cpu
+ 1);
494 psim_last_cpu(psim
*system
)
496 return system
->last_cpu
;
501 psim_nr_cpus(psim
*system
)
503 return system
->nr_cpus
;
508 psim_get_status(psim
*system
)
510 return system
->halt_status
;
516 psim_cpu(psim
*system
,
519 if (cpu_nr
< 0 || cpu_nr
>= system
->nr_cpus
)
522 return system
->processors
[cpu_nr
];
528 psim_device(psim
*system
,
531 return tree_find_device(system
->devices
, path
);
536 psim_event_queue(psim
*system
)
538 return system
->events
;
545 psim_init(psim
*system
)
549 /* scrub the monitor */
550 mon_init(system
->monitor
, system
->nr_cpus
);
552 /* trash any pending events */
553 event_queue_init(system
->events
);
555 /* scrub all the cpus */
556 for (cpu_nr
= 0; cpu_nr
< system
->nr_cpus
; cpu_nr
++)
557 cpu_init(system
->processors
[cpu_nr
]);
559 /* init all the devices (which updates the cpus) */
560 tree_init(system
->devices
, system
);
562 /* and the emulation (which needs an initialized device tree) */
563 os_emul_init(system
->os_emulation
, system
->nr_cpus
);
565 /* now sync each cpu against the initialized state of its registers */
566 for (cpu_nr
= 0; cpu_nr
< system
->nr_cpus
; cpu_nr
++) {
567 cpu
*processor
= system
->processors
[cpu_nr
];
568 cpu_synchronize_context(processor
, cpu_get_program_counter(processor
));
569 cpu_page_tlb_invalidate_all(processor
);
572 /* force loop to start with first cpu (after processing events) */
573 system
->last_cpu
= system
->nr_cpus
- 1;
578 psim_stack(psim
*system
,
582 /* pass the stack device the argv/envp and let it work out what to
584 device
*stack_device
= tree_find_device(system
->devices
,
585 "/openprom/init/stack");
586 if (stack_device
!= (device
*)0) {
587 unsigned_word stack_pointer
;
588 psim_read_register(system
, 0, &stack_pointer
, "sp", cooked_transfer
);
589 device_ioctl(stack_device
,
592 device_ioctl_create_stack
,
601 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
606 psim_step(psim
*system
)
608 volatile int keep_running
= 0;
609 idecode_run_until_stop(system
, &keep_running
,
610 system
->events
, system
->processors
, system
->nr_cpus
);
615 psim_run(psim
*system
)
618 system
->events
, system
->processors
, system
->nr_cpus
);
623 psim_run_until_stop(psim
*system
,
624 volatile int *keep_running
)
626 idecode_run_until_stop(system
, keep_running
,
627 system
->events
, system
->processors
, system
->nr_cpus
);
632 /* storage manipulation functions */
636 psim_read_register(psim
*system
,
642 register_descriptions description
;
643 char cooked_buf
[sizeof(unsigned_8
)];
646 /* find our processor */
647 if (which_cpu
== MAX_NR_PROCESSORS
)
648 which_cpu
= system
->last_cpu
;
649 if (which_cpu
< 0 || which_cpu
>= system
->nr_cpus
)
650 error("psim_read_register() - invalid processor %d\n", which_cpu
);
651 processor
= system
->processors
[which_cpu
];
653 /* find the register description */
654 description
= register_description(reg
);
655 if (description
.type
== reg_invalid
)
656 error("psim_read_register() invalid register name `%s'\n", reg
);
658 /* get the cooked value */
659 switch (description
.type
) {
662 *(gpreg
*)cooked_buf
= cpu_registers(processor
)->gpr
[description
.index
];
666 *(spreg
*)cooked_buf
= cpu_registers(processor
)->spr
[description
.index
];
670 *(sreg
*)cooked_buf
= cpu_registers(processor
)->sr
[description
.index
];
674 *(fpreg
*)cooked_buf
= cpu_registers(processor
)->fpr
[description
.index
];
678 *(unsigned_word
*)cooked_buf
= cpu_get_program_counter(processor
);
682 *(creg
*)cooked_buf
= cpu_registers(processor
)->cr
;
686 *(msreg
*)cooked_buf
= cpu_registers(processor
)->msr
;
690 *(unsigned_word
*)cooked_buf
= mon_get_number_of_insns(system
->monitor
,
695 if (cpu_model(processor
) == NULL
)
696 error("$stalls only valid if processor unit model enabled (-I)\n");
697 *(unsigned_word
*)cooked_buf
= model_get_number_of_stalls(cpu_model(processor
));
701 if (cpu_model(processor
) == NULL
)
702 error("$cycles only valid if processor unit model enabled (-I)\n");
703 *(unsigned_word
*)cooked_buf
= model_get_number_of_cycles(cpu_model(processor
));
707 printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n",
708 (unsigned long)processor
, (unsigned long)buf
, reg
,
709 "read of this register unimplemented");
714 /* the PSIM internal values are in host order. To fetch raw data,
715 they need to be converted into target order and then returned */
716 if (mode
== raw_transfer
) {
717 /* FIXME - assumes that all registers are simple integers */
718 switch (description
.size
) {
720 *(unsigned_1
*)buf
= H2T_1(*(unsigned_1
*)cooked_buf
);
723 *(unsigned_2
*)buf
= H2T_2(*(unsigned_2
*)cooked_buf
);
726 *(unsigned_4
*)buf
= H2T_4(*(unsigned_4
*)cooked_buf
);
729 *(unsigned_8
*)buf
= H2T_8(*(unsigned_8
*)cooked_buf
);
734 memcpy(buf
/*dest*/, cooked_buf
/*src*/, description
.size
);
743 psim_write_register(psim
*system
,
750 register_descriptions description
;
751 char cooked_buf
[sizeof(unsigned_8
)];
753 /* find our processor */
754 if (which_cpu
== MAX_NR_PROCESSORS
)
755 which_cpu
= system
->last_cpu
;
756 if (which_cpu
== -1) {
758 for (i
= 0; i
< system
->nr_cpus
; i
++)
759 psim_write_register(system
, i
, buf
, reg
, mode
);
762 else if (which_cpu
< 0 || which_cpu
>= system
->nr_cpus
) {
763 error("psim_read_register() - invalid processor %d\n", which_cpu
);
766 processor
= system
->processors
[which_cpu
];
768 /* find the description of the register */
769 description
= register_description(reg
);
770 if (description
.type
== reg_invalid
)
771 error("psim_write_register() invalid register name %s\n", reg
);
773 /* If the data is comming in raw (target order), need to cook it
774 into host order before putting it into PSIM's internal structures */
775 if (mode
== raw_transfer
) {
776 switch (description
.size
) {
778 *(unsigned_1
*)cooked_buf
= T2H_1(*(unsigned_1
*)buf
);
781 *(unsigned_2
*)cooked_buf
= T2H_2(*(unsigned_2
*)buf
);
784 *(unsigned_4
*)cooked_buf
= T2H_4(*(unsigned_4
*)buf
);
787 *(unsigned_8
*)cooked_buf
= T2H_8(*(unsigned_8
*)buf
);
792 memcpy(cooked_buf
/*dest*/, buf
/*src*/, description
.size
);
795 /* put the cooked value into the register */
796 switch (description
.type
) {
799 cpu_registers(processor
)->gpr
[description
.index
] = *(gpreg
*)cooked_buf
;
803 cpu_registers(processor
)->fpr
[description
.index
] = *(fpreg
*)cooked_buf
;
807 cpu_set_program_counter(processor
, *(unsigned_word
*)cooked_buf
);
811 cpu_registers(processor
)->spr
[description
.index
] = *(spreg
*)cooked_buf
;
815 cpu_registers(processor
)->sr
[description
.index
] = *(sreg
*)cooked_buf
;
819 cpu_registers(processor
)->cr
= *(creg
*)cooked_buf
;
823 cpu_registers(processor
)->msr
= *(msreg
*)cooked_buf
;
827 printf_filtered("psim_write_register(processor=0x%lx,cooked_buf=0x%lx,reg=%s) %s\n",
828 (unsigned long)processor
, (unsigned long)cooked_buf
, reg
,
829 "read of this register unimplemented");
840 psim_read_memory(psim
*system
,
847 if (which_cpu
== MAX_NR_PROCESSORS
)
848 which_cpu
= system
->last_cpu
;
849 if (which_cpu
< 0 || which_cpu
>= system
->nr_cpus
)
850 error("psim_read_memory() invalid cpu\n");
851 processor
= system
->processors
[which_cpu
];
852 return vm_data_map_read_buffer(cpu_data_map(processor
),
853 buffer
, vaddr
, nr_bytes
,
860 psim_write_memory(psim
*system
,
865 int violate_read_only_section
)
868 if (which_cpu
== MAX_NR_PROCESSORS
)
869 which_cpu
= system
->last_cpu
;
870 if (which_cpu
< 0 || which_cpu
>= system
->nr_cpus
)
871 error("psim_read_memory() invalid cpu\n");
872 processor
= system
->processors
[which_cpu
];
873 return vm_data_map_write_buffer(cpu_data_map(processor
),
874 buffer
, vaddr
, nr_bytes
, 1/*violate-read-only*/,
881 psim_print_info(psim
*system
,
884 mon_print_info(system
, system
->monitor
, verbose
);
888 /* Merge a device tree and a device file. */
892 psim_merge_device_file(device
*root
,
893 const char *file_name
)
897 char device_path
[1000];
900 /* try opening the file */
901 description
= fopen(file_name
, "r");
902 if (description
== NULL
) {
904 error("Invalid file %s specified", file_name
);
909 while (fgets(device_path
, sizeof(device_path
), description
)) {
911 /* check that the full line was read */
912 if (strchr(device_path
, '\n') == NULL
) {
914 error("%s:%d: line to long - %s",
915 file_name
, line_nr
, device_path
);
918 *strchr(device_path
, '\n') = '\0';
920 /* skip comments ("#" or ";") and blank lines lines */
921 for (device
= device_path
;
922 *device
!= '\0' && isspace(*device
);
926 || device
[0] == '\0')
928 /* merge any appended lines */
929 while (device_path
[strlen(device_path
) - 1] == '\\') {
930 int curlen
= strlen(device_path
) - 1;
932 device_path
[curlen
] = '\0';
933 /* append the next line */
934 if (!fgets(device_path
+ curlen
, sizeof(device_path
) - curlen
, description
)) {
936 error("%s:%s: unexpected eof in line continuation - %s",
937 file_name
, line_nr
, device_path
);
939 if (strchr(device_path
, '\n') == NULL
) {
941 error("%s:%d: line to long - %s",
942 file_name
, line_nr
, device_path
);
945 *strchr(device_path
, '\n') = '\0';
948 /* parse this line */
949 current
= tree_parse(current
, "%s", device
);
955 #endif /* _PSIM_C_ */