1 /* This file is part of the program psim.
3 Copyright (C) 1994-1995, 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.
26 #include "ppc-config.h"
29 #ifndef STATIC_INLINE_PSIM
30 #define STATIC_INLINE_PSIM STATIC_INLINE
36 #include "cpu.h" /* includes psim.h */
42 /* system structure, actual size of processor array determined at
49 /* escape routine for inner functions */
51 void *path_to_restart
;
52 /* status from last halt */
53 psim_status halt_status
;
54 /* the processes proper */
56 int last_cpu
; /* CPU that last (tried to) execute an instruction */
61 int current_target_byte_order
;
62 int current_host_byte_order
;
63 int current_environment
;
64 int current_alignment
;
67 psim_create(const char *file_name
,
74 if (nr_processors
<= 0
75 || (!WITH_SMP
&& nr_processors
!= 1))
76 error("psim_create() invalid number of cpus\n");
79 system
= (psim
*)zalloc(sizeof(psim
)
80 + sizeof(cpu
*) * (nr_processors
+ 1));
81 system
->nr_cpus
= nr_processors
;
82 system
->events
= event_queue_create();
83 system
->devices
= device_tree_create(file_name
);
84 system
->memory
= core_create(system
->devices
, 0);
85 for (cpu_nr
= 0; cpu_nr
< nr_processors
; cpu_nr
++) {
86 system
->processors
[cpu_nr
] = cpu_create(system
,
92 /* fill in the missing endian information */
93 current_target_byte_order
94 = (device_tree_find_boolean(system
->devices
, "/options/little-endian?")
97 if (WITH_TARGET_BYTE_ORDER
98 && WITH_TARGET_BYTE_ORDER
!= current_target_byte_order
)
99 error("target byte order conflict\n");
101 current_host_byte_order
= 1;
102 current_host_byte_order
= (*(char*)(¤t_host_byte_order
)
105 if (WITH_HOST_BYTE_ORDER
106 && WITH_HOST_BYTE_ORDER
!= current_host_byte_order
)
107 error("host byte order conflict\n");
109 /* fill in the missing OEA/VEA information */
110 current_environment
= (device_tree_find_boolean(system
->devices
,
112 ? VIRTUAL_ENVIRONMENT
113 : OPERATING_ENVIRONMENT
);
115 /* fill in the missing ALLIGNMENT information */
116 current_alignment
= (device_tree_find_boolean(system
->devices
,
119 : NONSTRICT_ALIGNMENT
);
121 && CURRENT_ALIGNMENT
!= WITH_ALIGNMENT
)
122 error("target alignment support conflict\n");
128 /* allow the simulation to stop/restart abnormaly */
130 STATIC_INLINE_PSIM
void
131 psim_set_halt_and_restart(psim
*system
,
133 void *restart_jmp_buf
)
135 system
->path_to_halt
= halt_jmp_buf
;
136 system
->path_to_restart
= restart_jmp_buf
;
139 STATIC_INLINE_PSIM
void
140 psim_clear_halt_and_restart(psim
*system
)
142 system
->path_to_halt
= NULL
;
143 system
->path_to_restart
= NULL
;
147 psim_restart(psim
*system
,
150 system
->last_cpu
= current_cpu
;
151 longjmp(*(jmp_buf*)(system
->path_to_restart
), current_cpu
+ 1);
156 psim_halt(psim
*system
,
162 system
->last_cpu
= current_cpu
;
163 system
->halt_status
.cpu_nr
= current_cpu
;
164 system
->halt_status
.reason
= reason
;
165 system
->halt_status
.signal
= signal
;
166 system
->halt_status
.program_counter
= cia
;
167 longjmp(*(jmp_buf*)(system
->path_to_halt
), current_cpu
+ 1);
170 INLINE_PSIM psim_status
171 psim_get_status(psim
*system
)
173 return system
->halt_status
;
178 psim_cpu(psim
*system
,
181 if (cpu_nr
< 0 || cpu_nr
>= system
->nr_cpus
)
184 return system
->processors
[cpu_nr
];
189 STATIC_INLINE_PSIM
int
190 sizeof_argument_strings(char **arg
)
192 int sizeof_strings
= 0;
198 /* add up all the string sizes (padding as we go) */
199 for (; *arg
!= NULL
; arg
++) {
200 int len
= strlen(*arg
) + 1;
201 sizeof_strings
+= ALIGN_8(len
);
204 return sizeof_strings
;
207 STATIC_INLINE_PSIM
int
208 number_of_arguments(char **arg
)
213 for (nr
= 0; *arg
!= NULL
; arg
++, nr
++);
217 STATIC_INLINE_PSIM
int
218 sizeof_arguments(char **arg
)
220 return ALIGN_8((number_of_arguments(arg
) + 1) * sizeof(unsigned_word
));
223 STATIC_INLINE_PSIM
void
224 write_stack_arguments(psim
*system
,
226 unsigned_word start_block
,
227 unsigned_word start_arg
)
229 if (CURRENT_ENVIRONMENT
!= VIRTUAL_ENVIRONMENT
)
231 TRACE(trace_create_stack
, ("write_stack_arguments() - skipping, OEA program\n"));
235 TRACE(trace_create_stack
,
236 ("write_stack_arguments() - %s=0x%x %s=0x%x %s=0x%x %s=0x%x\n",
237 "system", system
, "arg", arg
,
238 "start_block", start_block
, "start_arg", start_arg
));
240 error("write_arguments: character array NULL\n");
241 /* only copy in arguments, memory is already zero */
242 for (; *arg
!= NULL
; arg
++) {
243 int len
= strlen(*arg
)+1;
244 TRACE(trace_create_stack
,
245 ("write_stack_arguments - write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n",
246 "**arg", *arg
, "start_block", start_block
,
247 "len", len
, "start_arg", start_arg
));
248 if (psim_write_memory(system
, 0, *arg
,
250 raw_transfer
, 0) != len
)
251 error("write_arguments() - write of **arg (%s) at 0x%x failed\n",
253 if (psim_write_memory(system
, 0, &start_block
,
254 start_arg
, sizeof(start_block
),
255 cooked_transfer
, 0) != sizeof(start_block
))
256 error("write_arguments() - write of *arg failed\n");
257 start_block
+= ALIGN_8(len
);
258 start_arg
+= sizeof(start_block
);
262 STATIC_INLINE_PSIM
void
263 create_elf_stack_frame(psim
*system
,
264 unsigned_word bottom_of_stack
,
268 /* fixme - this is over aligned */
270 /* information block */
271 const unsigned sizeof_envp_block
= sizeof_argument_strings(envp
);
272 const unsigned_word start_envp_block
= bottom_of_stack
- sizeof_envp_block
;
273 const unsigned sizeof_argv_block
= sizeof_argument_strings(argv
);
274 const unsigned_word start_argv_block
= start_envp_block
- sizeof_argv_block
;
276 /* auxiliary vector - contains only one entry */
277 const unsigned sizeof_aux_entry
= 2*sizeof(unsigned_word
); /* magic */
278 const unsigned_word start_aux
= start_argv_block
- ALIGN_8(sizeof_aux_entry
);
280 /* environment points (including null sentinal) */
281 const unsigned sizeof_envp
= sizeof_arguments(envp
);
282 const unsigned_word start_envp
= start_aux
- sizeof_envp
;
284 /* argument pointers (including null sentinal) */
285 const int argc
= number_of_arguments(argv
);
286 const unsigned sizeof_argv
= sizeof_arguments(argv
);
287 const unsigned_word start_argv
= start_envp
- sizeof_argv
;
289 /* link register save address - alligned to a 16byte boundary */
290 const unsigned_word top_of_stack
= ((start_argv
291 - 2 * sizeof(unsigned_word
))
294 /* force some stack space */
295 if (CURRENT_ENVIRONMENT
== VIRTUAL_ENVIRONMENT
296 && core_stack_lower_bound(system
->memory
) > top_of_stack
) {
297 unsigned_word extra_stack_space
= (core_stack_lower_bound(system
->memory
)
298 - FLOOR_PAGE(top_of_stack
));
299 TRACE(trace_create_stack
,
300 ("create_elf_stack_frame() - growing stack by 0x%x\n",
302 core_add_stack(system
->memory
, extra_stack_space
);
305 /* install arguments on stack */
306 write_stack_arguments(system
, envp
, start_envp_block
, start_envp
);
307 write_stack_arguments(system
, argv
, start_argv_block
, start_argv
);
309 /* set up the registers */
310 psim_write_register(system
, -1,
311 &top_of_stack
, "r1", cooked_transfer
);
312 psim_write_register(system
, -1,
313 &argc
, "r3", cooked_transfer
);
314 psim_write_register(system
, -1,
315 &start_argv
, "r4", cooked_transfer
);
316 psim_write_register(system
, -1,
317 &start_envp
, "r5", cooked_transfer
);
318 psim_write_register(system
, -1,
319 &start_aux
, "r6", cooked_transfer
);
322 STATIC_INLINE_PSIM
void
323 create_aix_stack_frame(psim
*system
,
324 unsigned_word bottom_of_stack
,
328 unsigned_word core_envp
;
329 unsigned_word core_argv
;
330 unsigned_word core_argc
;
331 unsigned_word core_aux
;
332 unsigned_word top_of_stack
;
334 /* cheat - create an elf stack frame */
335 create_elf_stack_frame(system
, bottom_of_stack
, argv
, envp
);
337 /* extract argument addresses from registers */
338 psim_read_register(system
, 0, &top_of_stack
, "r1", cooked_transfer
);
339 psim_read_register(system
, 0, &core_argc
, "r3", cooked_transfer
);
340 psim_read_register(system
, 0, &core_argv
, "r4", cooked_transfer
);
341 psim_read_register(system
, 0, &core_envp
, "r5", cooked_transfer
);
342 psim_read_register(system
, 0, &core_aux
, "r6", cooked_transfer
);
344 /* check stack fits at least this much */
345 if (CURRENT_ENVIRONMENT
== VIRTUAL_ENVIRONMENT
346 && core_stack_lower_bound(system
->memory
) > top_of_stack
) {
347 unsigned_word extra_stack_space
= (core_stack_lower_bound(system
->memory
)
348 - FLOOR_PAGE(top_of_stack
));
349 TRACE(trace_create_stack
,
350 ("create_aix_stack_frame() - growing stack by 0x%x\n",
352 core_add_stack(system
->memory
, extra_stack_space
);
355 /* extract arguments from registers */
356 error("create_aix_stack_frame() - what happens next?\n");
361 psim_load(psim
*system
)
363 unsigned_word program_counter
;
366 /* load in core data */
367 core_init(system
->memory
);
369 /* set up all processor entry points (to same thing). Maybe
370 someday, the device tree could include information specifying the
371 entry point for each processor, one day */
373 ("TBD - device tree specifying entry point of each processor\n"));
374 program_counter
= device_tree_find_int(system
->devices
,
375 "/options/program-counter");
376 psim_write_register(system
, -1,
378 "pc", cooked_transfer
);
379 system
->last_cpu
= system
->nr_cpus
- 1; /* force loop to restart */
381 /* set up the MSR for at least be/le mode */
382 msr
= (device_tree_find_boolean(system
->devices
,
383 "/options/little-endian?")
384 ? msr_little_endian_mode
386 psim_write_register(system
, -1,
388 "msr", cooked_transfer
);
392 psim_stack(psim
*system
,
396 unsigned_word stack_pointer
= device_tree_find_int(system
->devices
,
397 "/options/stack-pointer");
398 if (device_tree_find_boolean(system
->devices
,
400 create_elf_stack_frame(system
, stack_pointer
, argv
, envp
);
402 create_aix_stack_frame(system
, stack_pointer
, argv
, envp
);
407 /* EXECUTE REAL CODE:
409 Unfortunatly, there are multiple cases to consider vis:
411 <icache> X <smp> X <events> X <keep-running-flag> X ...
413 Consequently this function is written in multiple different ways */
415 STATIC_INLINE_PSIM
void
416 run_until_stop(psim
*system
,
417 volatile int *keep_running
)
420 #if (WITH_IDECODE_CACHE == 0 && WITH_SMP == 0)
422 /* CASE 1: No instruction cache and no SMP.
424 In this case, we can take advantage of the fact that the current
425 instruction address does not need to be returned to the cpu
426 object after every execution of an instruction. Instead it only
427 needs to be saved when either A. the main loop exits or B. a
428 cpu-{halt,restart} call forces the loop to be re-entered. The
429 later functions always save the current cpu instruction
434 psim_set_halt_and_restart(system
, &halt
, &restart
);
437 if (!setjmp(restart
)) {
438 cpu
*const processor
= system
->processors
[0];
439 unsigned_word cia
= cpu_get_program_counter(processor
);
442 if (event_queue_tick(system
->events
)) {
443 cpu_set_program_counter(processor
, cia
);
444 event_queue_process(system
->events
);
445 cia
= cpu_get_program_counter(processor
);
449 instruction_word
const instruction
450 = vm_instruction_map_read(cpu_instruction_map(processor
),
452 cia
= idecode_issue(processor
, instruction
, cia
);
454 } while (keep_running
== NULL
|| *keep_running
);
455 cpu_set_program_counter(processor
, cia
);
457 } while(keep_running
== NULL
|| *keep_running
);
459 psim_clear_halt_and_restart(system
);
463 #if (WITH_IDECODE_CACHE > 0 && WITH_SMP == 0)
465 /* CASE 2: Instruction case but no SMP
467 Here, the additional complexity comes from there being two
468 different cache implementations. A simple function address cache
469 or a full cracked instruction cache */
473 psim_set_halt_and_restart(system
, &halt
, &restart
);
476 if (!setjmp(restart
)) {
477 cpu
*const processor
= system
->processors
[0];
478 unsigned_word cia
= cpu_get_program_counter(processor
);
481 if (event_queue_tick(system
->events
)) {
482 cpu_set_program_counter(processor
, cia
);
483 event_queue_process(system
->events
);
484 cia
= cpu_get_program_counter(processor
);
487 idecode_cache
*const cache_entry
488 = cpu_icache(processor
) + (cia
/ 4 % IDECODE_CACHE_SIZE
);
489 if (cache_entry
->address
== cia
) {
490 idecode_semantic
*const semantic
= cache_entry
->semantic
;
491 #if WITH_IDECODE_CACHE == 1
492 cia
= semantic(processor
, cache_entry
->instruction
, cia
);
494 cia
= semantic(processor
, cache_entry
, cia
);
498 instruction_word
const instruction
499 = vm_instruction_map_read(cpu_instruction_map(processor
),
502 #if WITH_IDECODE_CACHE == 1
503 idecode_semantic
*const semantic
= idecode(processor
,
507 idecode_semantic
*const semantic
= idecode(processor
,
512 cache_entry
->address
= cia
;
513 cache_entry
->semantic
= semantic
;
514 #if WITH_IDECODE_CACHE == 1
515 cache_entry
->instruction
= instruction
;
516 cia
= semantic(processor
, instruction
, cia
);
518 cia
= semantic(processor
, cache_entry
, cia
);
522 } while (keep_running
== NULL
|| *keep_running
);
523 cpu_set_program_counter(processor
, cia
);
525 } while(keep_running
== NULL
|| *keep_running
);
527 psim_clear_halt_and_restart(system
);
531 #if (WITH_IDECODE_CACHE == 0 && WITH_SMP > 0)
533 /* CASE 3: No ICACHE but SMP
535 The complexity here comes from needing to correctly restart the
536 system when it is aborted. In particular if cpu0 requests a
537 restart, the next cpu is still cpu1. Cpu0 being restarted after
538 all the other CPU's and the event queue have been processed */
542 psim_set_halt_and_restart(system
, &halt
, &restart
);
545 int first_cpu
= setjmp(restart
);
547 first_cpu
= system
->last_cpu
+ 1;
550 for (current_cpu
= first_cpu
, first_cpu
= 0;
551 current_cpu
< system
->nr_cpus
+ (WITH_EVENTS
? 1 : 0);
553 if (WITH_EVENTS
&& current_cpu
== system
->nr_cpus
) {
554 if (event_queue_tick(system
->events
))
555 event_queue_process(system
->events
);
558 cpu
*const processor
= system
->processors
[current_cpu
];
559 unsigned_word
const cia
= cpu_get_program_counter(processor
);
560 instruction_word instruction
=
561 vm_instruction_map_read(cpu_instruction_map(processor
),
564 cpu_set_program_counter(processor
,
565 idecode_issue(processor
, instruction
, cia
));
567 if (!(keep_running
== NULL
|| *keep_running
)) {
568 system
->last_cpu
= current_cpu
;
572 } while (keep_running
== NULL
|| *keep_running
);
574 psim_clear_halt_and_restart(system
);
577 #if (WITH_IDECODE_CACHE > 0 && WITH_SMP > 0)
579 /* CASE 4: ICACHE and SMP ...
581 This time, everything goes wrong. Need to restart loops
582 correctly, need to save the program counter and finally need to
583 keep track of each processors current address! */
587 psim_set_halt_and_restart(system
, &halt
, &restart
);
590 int first_cpu
= setjmp(restart
);
592 first_cpu
= system
->last_cpu
+ 1;
595 for (current_cpu
= first_cpu
, first_cpu
= 0;
596 current_cpu
< system
->nr_cpus
+ (WITH_EVENTS
? 1 : 0);
598 if (WITH_EVENTS
&& current_cpu
== system
->nr_cpus
) {
599 if (event_queue_tick(system
->events
))
600 event_queue_process(system
->events
);
603 cpu
*processor
= system
->processors
[current_cpu
];
604 unsigned_word
const cia
= cpu_get_program_counter(processor
);
605 idecode_cache
*cache_entry
606 = (cpu_icache(processor
) + (cia
/ 4 % IDECODE_CACHE_SIZE
));
607 if (cache_entry
->address
== cia
) {
608 idecode_semantic
*semantic
= cache_entry
->semantic
;
609 #if WITH_IDECODE_CACHE == 1
610 cpu_set_program_counter(processor
,
612 cache_entry
->instruction
,
615 cpu_set_program_counter(processor
,
622 instruction_word instruction
=
623 vm_instruction_map_read(cpu_instruction_map(processor
),
626 #if WITH_IDECODE_CACHE == 1
627 idecode_semantic
*semantic
= idecode(processor
,
631 idecode_semantic
*semantic
= idecode(processor
,
636 cache_entry
->address
= cia
;
637 cache_entry
->semantic
= semantic
;
638 #if WITH_IDECODE_CACHE == 1
639 cache_entry
->instruction
= instruction
;
640 cpu_set_program_counter(processor
,
641 semantic(processor
, instruction
, cia
));
643 cpu_set_program_counter(processor
,
644 semantic(processor
, cache_entry
, cia
);
648 if (!(keep_running
== NULL
|| *keep_running
))
651 } while (keep_running
== NULL
|| *keep_running
);
653 psim_clear_halt_and_restart(system
);
658 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
662 psim_step(psim
*system
)
664 volatile int keep_running
= 0;
665 psim_run_until_stop(system
, &keep_running
);
669 psim_run(psim
*system
)
671 run_until_stop(system
, NULL
);
675 psim_run_until_stop(psim
*system
,
676 volatile int *keep_running
)
678 run_until_stop(system
, keep_running
);
683 /* storage manipulation functions */
686 psim_read_register(psim
*system
,
692 register_descriptions description
;
693 char cooked_buf
[sizeof(natural_word
)];
696 /* find our processor */
697 if (which_cpu
< 0 || which_cpu
> system
->nr_cpus
)
698 error("psim_read_register() - invalid processor %d\n", which_cpu
);
699 if (which_cpu
== system
->nr_cpus
)
700 which_cpu
= system
->last_cpu
;
701 processor
= system
->processors
[which_cpu
];
703 /* find the register description */
704 description
= register_description(reg
);
705 if (description
.type
== reg_invalid
)
706 error("psim_read_register() invalid register name `%s'\n", reg
);
708 /* get the cooked value */
709 switch (description
.type
) {
712 *(gpreg
*)cooked_buf
= cpu_registers(processor
)->gpr
[description
.index
];
716 *(spreg
*)cooked_buf
= cpu_registers(processor
)->spr
[description
.index
];
720 *(sreg
*)cooked_buf
= cpu_registers(processor
)->sr
[description
.index
];
724 *(fpreg
*)cooked_buf
= cpu_registers(processor
)->fpr
[description
.index
];
728 *(unsigned_word
*)cooked_buf
= cpu_get_program_counter(processor
);
732 *(creg
*)cooked_buf
= cpu_registers(processor
)->cr
;
736 *(msreg
*)cooked_buf
= cpu_registers(processor
)->msr
;
740 printf_filtered("psim_read_register(processor=0x%x,buf=0x%x,reg=%s) %s\n",
742 "read of this register unimplemented");
747 /* the PSIM internal values are in host order. To fetch raw data,
748 they need to be converted into target order and then returned */
749 if (mode
== raw_transfer
) {
750 /* FIXME - assumes that all registers are simple integers */
751 switch (description
.size
) {
753 *(unsigned_1
*)buf
= H2T_1(*(unsigned_1
*)cooked_buf
);
756 *(unsigned_2
*)buf
= H2T_2(*(unsigned_2
*)cooked_buf
);
759 *(unsigned_4
*)buf
= H2T_4(*(unsigned_4
*)cooked_buf
);
762 *(unsigned_8
*)buf
= H2T_8(*(unsigned_8
*)cooked_buf
);
767 bcopy(cooked_buf
, buf
, description
.size
);
775 psim_write_register(psim
*system
,
782 register_descriptions description
;
783 char cooked_buf
[sizeof(natural_word
)];
785 /* find our processor */
786 if (which_cpu
== -1) {
788 for (i
= 0; i
< system
->nr_cpus
; i
++)
789 psim_write_register(system
, i
, buf
, reg
, mode
);
792 else if (which_cpu
== system
->nr_cpus
) {
793 which_cpu
= system
->last_cpu
;
795 else if (which_cpu
< 0 || which_cpu
>= system
->nr_cpus
) {
796 error("psim_read_register() - invalid processor %d\n", which_cpu
);
799 processor
= system
->processors
[which_cpu
];
801 /* find the description of the register */
802 description
= register_description(reg
);
803 if (description
.type
== reg_invalid
)
804 error("psim_write_register() invalid register name %s\n", reg
);
806 /* If the data is comming in raw (target order), need to cook it
807 into host order before putting it into PSIM's internal structures */
808 if (mode
== raw_transfer
) {
809 switch (description
.size
) {
811 *(unsigned_1
*)cooked_buf
= T2H_1(*(unsigned_1
*)buf
);
814 *(unsigned_2
*)cooked_buf
= T2H_2(*(unsigned_2
*)buf
);
817 *(unsigned_4
*)cooked_buf
= T2H_4(*(unsigned_4
*)buf
);
820 *(unsigned_8
*)cooked_buf
= T2H_8(*(unsigned_8
*)buf
);
825 bcopy(buf
, cooked_buf
, description
.size
);
828 /* put the cooked value into the register */
829 switch (description
.type
) {
832 cpu_registers(processor
)->gpr
[description
.index
] = *(gpreg
*)cooked_buf
;
836 cpu_registers(processor
)->fpr
[description
.index
] = *(fpreg
*)cooked_buf
;
840 cpu_set_program_counter(processor
, *(unsigned_word
*)cooked_buf
);
844 cpu_registers(processor
)->spr
[description
.index
] = *(spreg
*)cooked_buf
;
848 cpu_registers(processor
)->sr
[description
.index
] = *(sreg
*)cooked_buf
;
852 cpu_registers(processor
)->cr
= *(creg
*)cooked_buf
;
856 cpu_registers(processor
)->msr
= *(msreg
*)cooked_buf
;
860 printf_filtered("psim_write_register(processor=0x%x,cooked_buf=0x%x,reg=%s) %s\n",
861 processor
, cooked_buf
, reg
,
862 "read of this register unimplemented");
872 psim_read_memory(psim
*system
,
880 if (which_cpu
< 0 || which_cpu
> system
->nr_cpus
)
881 error("psim_read_memory() invalid cpu\n");
882 if (which_cpu
== system
->nr_cpus
)
883 which_cpu
= system
->last_cpu
;
884 processor
= system
->processors
[which_cpu
];
885 return vm_data_map_read_buffer(cpu_data_map(processor
),
886 buffer
, vaddr
, len
, mode
);
891 psim_write_memory(psim
*system
,
897 int violate_read_only_section
)
900 if (which_cpu
< 0 || which_cpu
> system
->nr_cpus
)
901 error("psim_read_memory() invalid cpu\n");
902 if (which_cpu
== system
->nr_cpus
)
903 which_cpu
= system
->last_cpu
;
904 processor
= system
->processors
[which_cpu
];
905 return vm_data_map_write_buffer(cpu_data_map(processor
),
906 buffer
, vaddr
, len
, mode
, 1);
911 psim_print_info(psim
*system
, int verbose
)
914 for (i
= 0; i
< system
->nr_cpus
; i
++)
915 cpu_print_info (system
->processors
[i
], verbose
);
918 #endif /* _PSIM_C_ */