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 */
51 /* system structure, actual size of processor array determined at
58 os_emul *os_emulation;
61 /* escape routine for inner functions */
63 void *path_to_restart;
65 /* status from last halt */
66 psim_status halt_status;
68 /* the processors proper */
70 int last_cpu; /* CPU that last (tried to) execute an instruction */
71 cpu *processors[MAX_NR_PROCESSORS];
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;
84 /* create the device tree */
90 device *root = device_tree_add_parsed(NULL, "core");
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");
105 find_arg(char *err_msg,
110 if (argv[*ptr_to_argp] == NULL)
112 return argv[*ptr_to_argp];
117 psim_usage(int verbose)
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");
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");
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");
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");
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 printf_filtered("\t-i Print instruction counting statistics\n");
163 if (verbose) { printf_filtered("\n"); }
164 printf_filtered("\t-I Print execution unit statistics\n");
165 if (verbose) { printf_filtered("\n"); }
166 printf_filtered("\t-r <size> Set RAM size in bytes (OEA environments)\n");
167 if (verbose) { printf_filtered("\n"); }
168 printf_filtered("\t-t [!]<trace> Enable (disable) <trace> option\n");
169 if (verbose) { printf_filtered("\n"); }
170 printf_filtered("\t-o <spec> add device <spec> to the device tree\n");
171 if (verbose) { printf_filtered("\n"); }
172 printf_filtered("\t-h -? -H give more detailed usage\n");
173 if (verbose) { printf_filtered("\n"); }
174 printf_filtered("\n");
175 trace_usage(verbose);
176 device_usage(verbose);
178 printf_filtered("\n");
186 psim_options(device *root,
189 device *current = root;
194 while (argv[argp] != NULL && argv[argp][0] == '-') {
195 char *p = argv[argp] + 1;
204 param = find_arg("Missing <emul> option for -e\n", &argp, argv);
205 device_tree_add_parsed(root, "/openprom/options/os-emul %s", param);
215 device_tree_add_parsed(root, "/openprom/trace/print-info 1");
218 device_tree_add_parsed(root, "/openprom/trace/print-info 2");
219 device_tree_add_parsed(root, "/openprom/options/model-issue %d",
220 MODEL_ISSUE_PROCESS);
223 param = find_arg("Missing <model> option for -m\n", &argp, argv);
224 device_tree_add_parsed(root, "/openprom/options/model \"%s", param);
227 param = find_arg("Missing <device> option for -o\n", &argp, argv);
228 current = device_tree_add_parsed(current, "%s", param);
231 param = find_arg("Missing <ram-size> option for -r\n", &argp, argv);
232 device_tree_add_parsed(root, "/openprom/options/oea-memory-size 0x%lx",
236 param = find_arg("Missing <trace> option for -t\n", &argp, argv);
238 device_tree_add_parsed(root, "/openprom/trace/%s 0", param+1);
240 device_tree_add_parsed(root, "/openprom/trace/%s 1", param);
247 /* force the trace node to (re)process its options */
248 device_ioctl(device_tree_find_device(root, "/openprom/trace"), NULL, 0);
250 /* return where the options end */
255 /* create the simulator proper from the device tree and executable */
259 psim_create(const char *file_name,
265 os_emul *os_emulation;
268 /* given this partially populated device tree, os_emul_create() uses
269 it and file_name to determine the selected emulation and hence
270 further populate the tree with any other required nodes. */
272 os_emulation = os_emul_create(file_name, root);
273 if (os_emulation == NULL)
274 error("psim: either file %s was not reconized or unreconized or unknown os-emulation type\n", file_name);
276 /* fill in the missing real number of CPU's */
277 nr_cpus = device_find_integer_property(root, "/openprom/options/smp");
278 if (MAX_NR_PROCESSORS < nr_cpus)
279 error("target and configured number of cpus conflict\n");
281 /* fill in the missing TARGET BYTE ORDER information */
282 current_target_byte_order
283 = (device_find_boolean_property(root, "/options/little-endian?")
286 if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
287 error("target and configured byte order conflict\n");
289 /* fill in the missing HOST BYTE ORDER information */
290 current_host_byte_order = (current_host_byte_order = 1,
291 (*(char*)(¤t_host_byte_order)
294 if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order)
295 error("host and configured byte order conflict\n");
297 /* fill in the missing OEA/VEA information */
298 env = device_find_string_property(root, "/openprom/options/env");
299 current_environment = ((strcmp(env, "user") == 0
300 || strcmp(env, "uea") == 0)
302 : (strcmp(env, "virtual") == 0
303 || strcmp(env, "vea") == 0)
304 ? VIRTUAL_ENVIRONMENT
305 : (strcmp(env, "operating") == 0
306 || strcmp(env, "oea") == 0)
307 ? OPERATING_ENVIRONMENT
309 if (current_environment == 0)
310 error("unreconized /options env property\n");
311 if (CURRENT_ENVIRONMENT != current_environment)
312 error("target and configured environment conflict\n");
314 /* fill in the missing ALLIGNMENT information */
316 = (device_find_boolean_property(root, "/openprom/options/strict-alignment?")
318 : NONSTRICT_ALIGNMENT);
319 if (CURRENT_ALIGNMENT != current_alignment)
320 error("target and configured alignment conflict\n");
322 /* fill in the missing FLOATING POINT information */
323 current_floating_point
324 = (device_find_boolean_property(root, "/openprom/options/floating-point?")
325 ? HARD_FLOATING_POINT
326 : SOFT_FLOATING_POINT);
327 if (CURRENT_FLOATING_POINT != current_floating_point)
328 error("target and configured floating-point conflict\n");
330 /* sort out the level of detail for issue modeling */
332 = device_find_integer_property(root, "/openprom/options/model-issue");
333 if (CURRENT_MODEL_ISSUE != current_model_issue)
334 error("target and configured model-issue conflict\n");
336 /* sort out our model architecture - wrong.
338 FIXME: this should be obtaining the required information from the
339 device tree via the "/chosen" property "cpu" which is an instance
340 (ihandle) for the only executing processor. By converting that
341 ihandle into the corresponding cpu's phandle and then querying
342 the "name" property, the cpu type can be determined. Ok? */
344 model_set(device_find_string_property(root, "/openprom/options/model"));
347 system = ZALLOC(psim);
348 system->events = event_queue_create();
349 system->memory = core_from_device(root);
350 system->monitor = mon_create();
351 system->nr_cpus = nr_cpus;
352 system->os_emulation = os_emulation;
353 system->devices = root;
355 /* now all the processors attaching to each their per-cpu information */
356 for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
357 system->processors[cpu_nr] = cpu_create(system,
359 mon_cpu(system->monitor,
361 system->os_emulation,
365 /* dump out the contents of the device tree */
366 if (ppc_trace[trace_print_device_tree] || ppc_trace[trace_dump_device_tree])
367 device_tree_traverse(root, device_tree_print_device, NULL, NULL);
368 if (ppc_trace[trace_dump_device_tree])
375 /* allow the simulation to stop/restart abnormaly */
379 psim_set_halt_and_restart(psim *system,
381 void *restart_jmp_buf)
383 system->path_to_halt = halt_jmp_buf;
384 system->path_to_restart = restart_jmp_buf;
389 psim_clear_halt_and_restart(psim *system)
391 system->path_to_halt = NULL;
392 system->path_to_restart = NULL;
397 psim_restart(psim *system,
400 system->last_cpu = current_cpu;
401 longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1);
407 psim_halt(psim *system,
412 ASSERT(current_cpu >= 0 && current_cpu < system->nr_cpus);
413 system->last_cpu = current_cpu;
414 system->halt_status.cpu_nr = current_cpu;
415 system->halt_status.reason = reason;
416 system->halt_status.signal = signal;
417 system->halt_status.program_counter =
418 cpu_get_program_counter(system->processors[current_cpu]);
419 longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
424 psim_last_cpu(psim *system)
426 return system->last_cpu;
431 psim_nr_cpus(psim *system)
433 return system->nr_cpus;
438 psim_get_status(psim *system)
440 return system->halt_status;
446 psim_cpu(psim *system,
449 if (cpu_nr < 0 || cpu_nr >= system->nr_cpus)
452 return system->processors[cpu_nr];
458 psim_device(psim *system,
461 return device_tree_find_device(system->devices, path);
466 psim_event_queue(psim *system)
468 return system->events;
475 psim_init(psim *system)
479 /* scrub the monitor */
480 mon_init(system->monitor, system->nr_cpus);
482 /* trash any pending events */
483 event_queue_init(system->events);
485 /* scrub all the cpus */
486 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
487 cpu_init(system->processors[cpu_nr]);
489 /* init all the devices (which updates the cpus) */
490 device_tree_init(system->devices, system);
492 /* and the emulation (which needs an initialized device tree) */
493 os_emul_init(system->os_emulation, system->nr_cpus);
495 /* now sync each cpu against the initialized state of its registers */
496 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) {
497 cpu_synchronize_context(system->processors[cpu_nr]);
498 cpu_page_tlb_invalidate_all(system->processors[cpu_nr]);
501 /* force loop to restart */
502 system->last_cpu = -1; /* when incremented will become 0 - first CPU */
507 psim_stack(psim *system,
511 /* pass the stack device the argv/envp and let it work out what to
513 device *stack_device = device_tree_find_device(system->devices,
514 "/openprom/init/stack");
515 if (stack_device != (device*)0) {
516 unsigned_word stack_pointer;
517 psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer);
518 device_ioctl(stack_device,
529 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
534 psim_step(psim *system)
536 volatile int keep_running = 0;
537 idecode_run_until_stop(system, &keep_running,
538 system->events, system->processors, system->nr_cpus);
543 psim_run(psim *system)
546 system->events, system->processors, system->nr_cpus);
551 psim_run_until_stop(psim *system,
552 volatile int *keep_running)
554 idecode_run_until_stop(system, keep_running,
555 system->events, system->processors, system->nr_cpus);
560 /* storage manipulation functions */
564 psim_read_register(psim *system,
570 register_descriptions description;
571 char cooked_buf[sizeof(unsigned_8)];
574 /* find our processor */
575 if (which_cpu == MAX_NR_PROCESSORS)
576 which_cpu = system->last_cpu;
577 if (which_cpu < 0 || which_cpu >= system->nr_cpus)
578 error("psim_read_register() - invalid processor %d\n", which_cpu);
579 processor = system->processors[which_cpu];
581 /* find the register description */
582 description = register_description(reg);
583 if (description.type == reg_invalid)
584 error("psim_read_register() invalid register name `%s'\n", reg);
586 /* get the cooked value */
587 switch (description.type) {
590 *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index];
594 *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index];
598 *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index];
602 *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index];
606 *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor);
610 *(creg*)cooked_buf = cpu_registers(processor)->cr;
614 *(msreg*)cooked_buf = cpu_registers(processor)->msr;
618 *(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor,
623 if (cpu_model(processor) == NULL)
624 error("$stalls only valid if processor unit model enabled (-I)\n");
625 *(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor));
629 if (cpu_model(processor) == NULL)
630 error("$cycles only valid if processor unit model enabled (-I)\n");
631 *(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor));
635 printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n",
636 (unsigned long)processor, (unsigned long)buf, reg,
637 "read of this register unimplemented");
642 /* the PSIM internal values are in host order. To fetch raw data,
643 they need to be converted into target order and then returned */
644 if (mode == raw_transfer) {
645 /* FIXME - assumes that all registers are simple integers */
646 switch (description.size) {
648 *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf);
651 *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf);
654 *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf);
657 *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf);
662 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
671 psim_write_register(psim *system,
678 register_descriptions description;
679 char cooked_buf[sizeof(unsigned_8)];
681 /* find our processor */
682 if (which_cpu == MAX_NR_PROCESSORS)
683 which_cpu = system->last_cpu;
684 if (which_cpu == -1) {
686 for (i = 0; i < system->nr_cpus; i++)
687 psim_write_register(system, i, buf, reg, mode);
690 else if (which_cpu < 0 || which_cpu >= system->nr_cpus) {
691 error("psim_read_register() - invalid processor %d\n", which_cpu);
694 processor = system->processors[which_cpu];
696 /* find the description of the register */
697 description = register_description(reg);
698 if (description.type == reg_invalid)
699 error("psim_write_register() invalid register name %s\n", reg);
701 /* If the data is comming in raw (target order), need to cook it
702 into host order before putting it into PSIM's internal structures */
703 if (mode == raw_transfer) {
704 switch (description.size) {
706 *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf);
709 *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf);
712 *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf);
715 *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf);
720 memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
723 /* put the cooked value into the register */
724 switch (description.type) {
727 cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf;
731 cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf;
735 cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf);
739 cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf;
743 cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf;
747 cpu_registers(processor)->cr = *(creg*)cooked_buf;
751 cpu_registers(processor)->msr = *(msreg*)cooked_buf;
755 printf_filtered("psim_write_register(processor=0x%lx,cooked_buf=0x%lx,reg=%s) %s\n",
756 (unsigned long)processor, (unsigned long)cooked_buf, reg,
757 "read of this register unimplemented");
768 psim_read_memory(psim *system,
775 if (which_cpu == MAX_NR_PROCESSORS)
776 which_cpu = system->last_cpu;
777 if (which_cpu < 0 || which_cpu >= system->nr_cpus)
778 error("psim_read_memory() invalid cpu\n");
779 processor = system->processors[which_cpu];
780 return vm_data_map_read_buffer(cpu_data_map(processor),
781 buffer, vaddr, nr_bytes);
787 psim_write_memory(psim *system,
792 int violate_read_only_section)
795 if (which_cpu == MAX_NR_PROCESSORS)
796 which_cpu = system->last_cpu;
797 if (which_cpu < 0 || which_cpu >= system->nr_cpus)
798 error("psim_read_memory() invalid cpu\n");
799 processor = system->processors[which_cpu];
800 return vm_data_map_write_buffer(cpu_data_map(processor),
801 buffer, vaddr, nr_bytes, 1);
807 psim_print_info(psim *system,
810 mon_print_info(system, system->monitor, verbose);
814 /* Merge a device tree and a device file. */
818 psim_merge_device_file(device *root,
819 const char *file_name)
821 FILE *description = fopen(file_name, "r");
823 char device_path[1000];
824 device *current = root;
825 while (fgets(device_path, sizeof(device_path), description)) {
826 /* check all of line was read */
827 if (strchr(device_path, '\n') == NULL) {
829 error("create_filed_device_tree() line %d to long: %s\n",
830 line_nr, device_path);
833 /* parse this line */
834 current = device_tree_add_parsed(current, "%s", device_path);
840 #endif /* _PSIM_C_ */