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-c <count> Limit the simulation to <count> iterations\n");
152 printf_filtered("\n");
155 printf_filtered("\t-i or -i2 Print instruction counting statistics\n");
157 printf_filtered("\t Specify -i2 for a more detailed display\n");
158 printf_filtered("\n");
161 printf_filtered("\t-I Print execution unit statistics\n");
162 if (verbose
) { printf_filtered("\n"); }
164 printf_filtered("\t-e <os-emul> specify an OS or platform to model\n");
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");
172 printf_filtered("\n"); }
174 printf_filtered("\t-f <file> Merge <file> into the device tree\n");
175 if (verbose
) { printf_filtered("\n"); }
177 printf_filtered("\t-h -? -H give more detailed usage\n");
178 if (verbose
) { printf_filtered("\n"); }
180 printf_filtered("\t-m <model> Specify the processor to model (604)\n");
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"); }
187 printf_filtered("\t-n <nr-smp> Specify the number of processors in SMP simulations\n");
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"); }
194 printf_filtered("\t-o <dev-spec> Add device <dev-spec> to the device tree\n");
195 if (verbose
) { printf_filtered("\n"); }
197 printf_filtered("\t-r <ram-size> Set RAM size in bytes (OEA environments)\n");
198 if (verbose
) { printf_filtered("\n"); }
200 printf_filtered("\t-t [!]<trace> Enable (disable) <trace> option\n");
201 if (verbose
) { printf_filtered("\n"); }
203 printf_filtered("\n");
204 trace_usage(verbose
);
205 device_usage(verbose
);
207 printf_filtered("\n");
215 psim_options(device
*root
,
218 device
*current
= root
;
223 while (argv
[argp
] != NULL
&& argv
[argp
][0] == '-') {
224 char *p
= argv
[argp
] + 1;
233 param
= find_arg("Missing <count> option for -c (max-iterations)\n", &argp
, argv
);
234 tree_parse(root
, "/openprom/options/max-iterations %s", param
);
237 param
= find_arg("Missing <emul> option for -e (os-emul)\n", &argp
, argv
);
238 tree_parse(root
, "/openprom/options/os-emul %s", param
);
241 param
= find_arg("Missing <file> option for -f\n", &argp
, argv
);
242 psim_merge_device_file(root
, param
);
253 tree_parse(root
, "/openprom/trace/print-info %c", p
[1]);
257 tree_parse(root
, "/openprom/trace/print-info 1");
261 tree_parse(root
, "/openprom/trace/print-info 2");
262 tree_parse(root
, "/openprom/options/model-issue %d",
263 MODEL_ISSUE_PROCESS
);
266 param
= find_arg("Missing <model> option for -m (model)\n", &argp
, argv
);
267 tree_parse(root
, "/openprom/options/model \"%s", param
);
270 param
= find_arg("Missing <nr-smp> option for -n (smp)\n", &argp
, argv
);
271 tree_parse(root
, "/openprom/options/smp %s", param
);
274 param
= find_arg("Missing <dev-spec> option for -o\n", &argp
, argv
);
275 current
= tree_parse(current
, "%s", param
);
278 param
= find_arg("Missing <ram-size> option for -r (oea-memory-size)\n", &argp
, argv
);
279 tree_parse(root
, "/openprom/options/oea-memory-size %s",
283 param
= find_arg("Missing <trace> option for -t (trace/*)\n", &argp
, argv
);
285 tree_parse(root
, "/openprom/trace/%s 0", param
+1);
287 tree_parse(root
, "/openprom/trace/%s 1", param
);
290 /* endian spec, ignored for now */
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"),
302 device_ioctl_set_trace
);
304 /* return where the options end */
310 psim_command(device
*root
,
314 if (argv
[argp
] == NULL
) {
317 else if (strcmp(argv
[argp
], "trace") == 0) {
318 const char *opt
= find_arg("Missing <trace> option", &argp
, argv
);
320 trace_option(opt
+ 1, 0);
322 trace_option(opt
, 1);
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
);
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");
338 /* create the simulator proper from the device tree and executable */
342 psim_create(const char *file_name
,
348 os_emul
*os_emulation
;
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. */
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
);
359 /* fill in the missing real number of CPU's */
360 nr_cpus
= tree_find_integer_property(root
, "/openprom/options/smp");
361 if (MAX_NR_PROCESSORS
< nr_cpus
)
362 error("target and configured number of cpus conflict\n");
364 /* fill in the missing TARGET BYTE ORDER information */
365 current_target_byte_order
366 = (tree_find_boolean_property(root
, "/options/little-endian?")
369 if (CURRENT_TARGET_BYTE_ORDER
!= current_target_byte_order
)
370 error("target and configured byte order conflict\n");
372 /* fill in the missing HOST BYTE ORDER information */
373 current_host_byte_order
= (current_host_byte_order
= 1,
374 (*(char*)(¤t_host_byte_order
)
377 if (CURRENT_HOST_BYTE_ORDER
!= current_host_byte_order
)
378 error("host and configured byte order conflict\n");
380 /* fill in the missing OEA/VEA information */
381 env
= tree_find_string_property(root
, "/openprom/options/env");
382 current_environment
= ((strcmp(env
, "user") == 0
383 || strcmp(env
, "uea") == 0)
385 : (strcmp(env
, "virtual") == 0
386 || strcmp(env
, "vea") == 0)
387 ? VIRTUAL_ENVIRONMENT
388 : (strcmp(env
, "operating") == 0
389 || strcmp(env
, "oea") == 0)
390 ? OPERATING_ENVIRONMENT
392 if (current_environment
== 0)
393 error("unreconized /options env property\n");
394 if (CURRENT_ENVIRONMENT
!= current_environment
)
395 error("target and configured environment conflict\n");
397 /* fill in the missing ALLIGNMENT information */
399 = (tree_find_boolean_property(root
, "/openprom/options/strict-alignment?")
401 : NONSTRICT_ALIGNMENT
);
402 if (CURRENT_ALIGNMENT
!= current_alignment
)
403 error("target and configured alignment conflict\n");
405 /* fill in the missing FLOATING POINT information */
406 current_floating_point
407 = (tree_find_boolean_property(root
, "/openprom/options/floating-point?")
408 ? HARD_FLOATING_POINT
409 : SOFT_FLOATING_POINT
);
410 if (CURRENT_FLOATING_POINT
!= current_floating_point
)
411 error("target and configured floating-point conflict\n");
413 /* fill in the missing STDIO information */
415 = (tree_find_boolean_property(root
, "/openprom/options/use-stdio?")
418 if (CURRENT_STDIO
!= current_stdio
)
419 error("target and configured stdio interface conflict\n");
421 /* sort out the level of detail for issue modeling */
423 = tree_find_integer_property(root
, "/openprom/options/model-issue");
424 if (CURRENT_MODEL_ISSUE
!= current_model_issue
)
425 error("target and configured model-issue conflict\n");
427 /* sort out our model architecture - wrong.
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? */
435 model_set(tree_find_string_property(root
, "/openprom/options/model"));
438 system
= ZALLOC(psim
);
439 system
->events
= event_queue_create();
440 system
->memory
= core_from_device(root
);
441 system
->monitor
= mon_create();
442 system
->nr_cpus
= nr_cpus
;
443 system
->os_emulation
= os_emulation
;
444 system
->devices
= root
;
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
,
450 mon_cpu(system
->monitor
,
452 system
->os_emulation
,
456 /* dump out the contents of the device tree */
457 if (ppc_trace
[trace_print_device_tree
] || ppc_trace
[trace_dump_device_tree
])
459 if (ppc_trace
[trace_dump_device_tree
])
466 /* allow the simulation to stop/restart abnormaly */
470 psim_set_halt_and_restart(psim
*system
,
472 void *restart_jmp_buf
)
474 system
->path_to_halt
= halt_jmp_buf
;
475 system
->path_to_restart
= restart_jmp_buf
;
480 psim_clear_halt_and_restart(psim
*system
)
482 system
->path_to_halt
= NULL
;
483 system
->path_to_restart
= NULL
;
488 psim_restart(psim
*system
,
491 ASSERT(current_cpu
>= 0 && current_cpu
< system
->nr_cpus
);
492 ASSERT(system
->path_to_restart
!= NULL
);
493 system
->last_cpu
= current_cpu
;
494 longjmp(*(jmp_buf*)(system
->path_to_restart
), current_cpu
+ 1);
500 psim_halt(psim
*system
,
505 ASSERT(current_cpu
>= 0 && current_cpu
<= system
->nr_cpus
);
506 ASSERT(system
->path_to_halt
!= NULL
);
507 system
->last_cpu
= current_cpu
;
508 system
->halt_status
.reason
= reason
;
509 system
->halt_status
.signal
= signal
;
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]);
516 system
->halt_status
.cpu_nr
= current_cpu
;
517 system
->halt_status
.program_counter
=
518 cpu_get_program_counter(system
->processors
[current_cpu
]);
520 longjmp(*(jmp_buf*)(system
->path_to_halt
), current_cpu
+ 1);
526 psim_last_cpu(psim
*system
)
528 return system
->last_cpu
;
533 psim_nr_cpus(psim
*system
)
535 return system
->nr_cpus
;
540 psim_get_status(psim
*system
)
542 return system
->halt_status
;
548 psim_cpu(psim
*system
,
551 if (cpu_nr
< 0 || cpu_nr
>= system
->nr_cpus
)
554 return system
->processors
[cpu_nr
];
560 psim_device(psim
*system
,
563 return tree_find_device(system
->devices
, path
);
568 psim_event_queue(psim
*system
)
570 return system
->events
;
577 psim_max_iterations_exceeded(void *data
)
581 system
->nr_cpus
, /* halted during an event */
589 psim_init(psim
*system
)
593 /* scrub the monitor */
594 mon_init(system
->monitor
, system
->nr_cpus
);
596 /* trash any pending events */
597 event_queue_init(system
->events
);
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
,
610 /* scrub all the cpus */
611 for (cpu_nr
= 0; cpu_nr
< system
->nr_cpus
; cpu_nr
++)
612 cpu_init(system
->processors
[cpu_nr
]);
614 /* init all the devices (which updates the cpus) */
615 tree_init(system
->devices
, system
);
617 /* and the emulation (which needs an initialized device tree) */
618 os_emul_init(system
->os_emulation
, system
->nr_cpus
);
620 /* now sync each cpu against the initialized state of its registers */
621 for (cpu_nr
= 0; cpu_nr
< system
->nr_cpus
; cpu_nr
++) {
622 cpu
*processor
= system
->processors
[cpu_nr
];
623 cpu_synchronize_context(processor
, cpu_get_program_counter(processor
));
624 cpu_page_tlb_invalidate_all(processor
);
627 /* force loop to start with first cpu */
628 system
->last_cpu
= -1;
633 psim_stack(psim
*system
,
637 /* pass the stack device the argv/envp and let it work out what to
639 device
*stack_device
= tree_find_device(system
->devices
,
640 "/openprom/init/stack");
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
,
647 device_ioctl_create_stack
,
656 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
661 psim_step(psim
*system
)
663 volatile int keep_running
= 0;
664 idecode_run_until_stop(system
, &keep_running
,
665 system
->events
, system
->processors
, system
->nr_cpus
);
670 psim_run(psim
*system
)
673 system
->events
, system
->processors
, system
->nr_cpus
);
678 psim_run_until_stop(psim
*system
,
679 volatile int *keep_running
)
681 idecode_run_until_stop(system
, keep_running
,
682 system
->events
, system
->processors
, system
->nr_cpus
);
687 /* storage manipulation functions */
691 psim_read_register(psim
*system
,
697 register_descriptions description
;
698 char cooked_buf
[sizeof(unsigned_8
)];
701 /* find our processor */
702 if (which_cpu
== MAX_NR_PROCESSORS
) {
703 if (system
->last_cpu
== system
->nr_cpus
704 || system
->last_cpu
== -1)
707 which_cpu
= system
->last_cpu
;
709 ASSERT(which_cpu
>= 0 && which_cpu
< system
->nr_cpus
);
711 processor
= system
->processors
[which_cpu
];
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
);
718 /* get the cooked value */
719 switch (description
.type
) {
722 *(gpreg
*)cooked_buf
= cpu_registers(processor
)->gpr
[description
.index
];
726 *(spreg
*)cooked_buf
= cpu_registers(processor
)->spr
[description
.index
];
730 *(sreg
*)cooked_buf
= cpu_registers(processor
)->sr
[description
.index
];
734 *(fpreg
*)cooked_buf
= cpu_registers(processor
)->fpr
[description
.index
];
738 *(unsigned_word
*)cooked_buf
= cpu_get_program_counter(processor
);
742 *(creg
*)cooked_buf
= cpu_registers(processor
)->cr
;
746 *(msreg
*)cooked_buf
= cpu_registers(processor
)->msr
;
750 *(unsigned_word
*)cooked_buf
= mon_get_number_of_insns(system
->monitor
,
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
));
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
));
767 printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n",
768 (unsigned long)processor
, (unsigned long)buf
, reg
,
769 "read of this register unimplemented");
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
) {
780 *(unsigned_1
*)buf
= H2T_1(*(unsigned_1
*)cooked_buf
);
783 *(unsigned_2
*)buf
= H2T_2(*(unsigned_2
*)cooked_buf
);
786 *(unsigned_4
*)buf
= H2T_4(*(unsigned_4
*)cooked_buf
);
789 *(unsigned_8
*)buf
= H2T_8(*(unsigned_8
*)cooked_buf
);
794 memcpy(buf
/*dest*/, cooked_buf
/*src*/, description
.size
);
803 psim_write_register(psim
*system
,
810 register_descriptions description
;
811 char cooked_buf
[sizeof(unsigned_8
)];
813 /* find our processor */
814 if (which_cpu
== MAX_NR_PROCESSORS
) {
815 if (system
->last_cpu
== system
->nr_cpus
816 || system
->last_cpu
== -1)
819 which_cpu
= system
->last_cpu
;
821 if (which_cpu
== -1) {
823 for (i
= 0; i
< system
->nr_cpus
; i
++)
824 psim_write_register(system
, i
, buf
, reg
, mode
);
827 ASSERT(which_cpu
>= 0 && which_cpu
< system
->nr_cpus
);
829 processor
= system
->processors
[which_cpu
];
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
);
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
) {
841 *(unsigned_1
*)cooked_buf
= T2H_1(*(unsigned_1
*)buf
);
844 *(unsigned_2
*)cooked_buf
= T2H_2(*(unsigned_2
*)buf
);
847 *(unsigned_4
*)cooked_buf
= T2H_4(*(unsigned_4
*)buf
);
850 *(unsigned_8
*)cooked_buf
= T2H_8(*(unsigned_8
*)buf
);
855 memcpy(cooked_buf
/*dest*/, buf
/*src*/, description
.size
);
858 /* put the cooked value into the register */
859 switch (description
.type
) {
862 cpu_registers(processor
)->gpr
[description
.index
] = *(gpreg
*)cooked_buf
;
866 cpu_registers(processor
)->fpr
[description
.index
] = *(fpreg
*)cooked_buf
;
870 cpu_set_program_counter(processor
, *(unsigned_word
*)cooked_buf
);
874 cpu_registers(processor
)->spr
[description
.index
] = *(spreg
*)cooked_buf
;
878 cpu_registers(processor
)->sr
[description
.index
] = *(sreg
*)cooked_buf
;
882 cpu_registers(processor
)->cr
= *(creg
*)cooked_buf
;
886 cpu_registers(processor
)->msr
= *(msreg
*)cooked_buf
;
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
,
892 "read of this register unimplemented");
903 psim_read_memory(psim
*system
,
910 if (which_cpu
== MAX_NR_PROCESSORS
) {
911 if (system
->last_cpu
== system
->nr_cpus
912 || system
->last_cpu
== -1)
915 which_cpu
= system
->last_cpu
;
917 processor
= system
->processors
[which_cpu
];
918 return vm_data_map_read_buffer(cpu_data_map(processor
),
919 buffer
, vaddr
, nr_bytes
,
926 psim_write_memory(psim
*system
,
931 int violate_read_only_section
)
934 if (which_cpu
== MAX_NR_PROCESSORS
) {
935 if (system
->last_cpu
== system
->nr_cpus
936 || system
->last_cpu
== -1)
939 which_cpu
= system
->last_cpu
;
941 ASSERT(which_cpu
>= 0 && which_cpu
< system
->nr_cpus
);
942 processor
= system
->processors
[which_cpu
];
943 return vm_data_map_write_buffer(cpu_data_map(processor
),
944 buffer
, vaddr
, nr_bytes
, 1/*violate-read-only*/,
951 psim_print_info(psim
*system
,
954 mon_print_info(system
, system
->monitor
, verbose
);
958 /* Merge a device tree and a device file. */
962 psim_merge_device_file(device
*root
,
963 const char *file_name
)
967 char device_path
[1000];
970 /* try opening the file */
971 description
= fopen(file_name
, "r");
972 if (description
== NULL
) {
974 error("Invalid file %s specified", file_name
);
979 while (fgets(device_path
, sizeof(device_path
), description
)) {
981 /* check that the full line was read */
982 if (strchr(device_path
, '\n') == NULL
) {
984 error("%s:%d: line to long - %s",
985 file_name
, line_nr
, device_path
);
988 *strchr(device_path
, '\n') = '\0';
990 /* skip comments ("#" or ";") and blank lines lines */
991 for (device
= device_path
;
992 *device
!= '\0' && isspace(*device
);
996 || device
[0] == '\0')
998 /* merge any appended lines */
999 while (device_path
[strlen(device_path
) - 1] == '\\') {
1000 int curlen
= strlen(device_path
) - 1;
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
);
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
);
1015 *strchr(device_path
, '\n') = '\0';
1018 /* parse this line */
1019 current
= tree_parse(current
, "%s", device
);
1021 fclose(description
);
1025 #endif /* _PSIM_C_ */