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 TRACE(trace_create_stack
,
230 ("write_stack_arguments() - %s=0x%x %s=0x%x %s=0x%x %s=0x%x\n",
231 "system", system
, "arg", arg
,
232 "start_block", start_block
, "start_arg", start_arg
));
234 error("write_arguments: character array NULL\n");
235 /* only copy in arguments, memory is already zero */
236 for (; *arg
!= NULL
; arg
++) {
237 int len
= strlen(*arg
)+1;
238 TRACE(trace_create_stack
,
239 ("write_stack_arguments - write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n",
240 "**arg", *arg
, "start_block", start_block
,
241 "len", len
, "start_arg", start_arg
));
242 if (psim_write_memory(system
, 0, *arg
,
244 raw_transfer
, 0) != len
)
245 error("write_arguments() - write of **arg (%s) at 0x%x failed\n",
247 if (psim_write_memory(system
, 0, &start_block
,
248 start_arg
, sizeof(start_block
),
249 cooked_transfer
, 0) != sizeof(start_block
))
250 error("write_arguments() - write of *arg failed\n");
251 start_block
+= ALIGN_8(len
);
252 start_arg
+= sizeof(start_block
);
256 STATIC_INLINE_PSIM
void
257 create_elf_stack_frame(psim
*system
,
258 unsigned_word bottom_of_stack
,
262 /* fixme - this is over aligned */
264 /* information block */
265 const unsigned sizeof_envp_block
= sizeof_argument_strings(envp
);
266 const unsigned_word start_envp_block
= bottom_of_stack
- sizeof_envp_block
;
267 const unsigned sizeof_argv_block
= sizeof_argument_strings(argv
);
268 const unsigned_word start_argv_block
= start_envp_block
- sizeof_argv_block
;
270 /* auxiliary vector - contains only one entry */
271 const unsigned sizeof_aux_entry
= 2*sizeof(unsigned_word
); /* magic */
272 const unsigned_word start_aux
= start_argv_block
- ALIGN_8(sizeof_aux_entry
);
274 /* environment points (including null sentinal) */
275 const unsigned sizeof_envp
= sizeof_arguments(envp
);
276 const unsigned_word start_envp
= start_aux
- sizeof_envp
;
278 /* argument pointers (including null sentinal) */
279 const int argc
= number_of_arguments(argv
);
280 const unsigned sizeof_argv
= sizeof_arguments(argv
);
281 const unsigned_word start_argv
= start_envp
- sizeof_argv
;
283 /* link register save address - alligned to a 16byte boundary */
284 const unsigned_word top_of_stack
= ((start_argv
285 - 2 * sizeof(unsigned_word
))
288 /* force some stack space */
289 if (CURRENT_ENVIRONMENT
== VIRTUAL_ENVIRONMENT
290 && core_stack_lower_bound(system
->memory
) > top_of_stack
) {
291 unsigned_word extra_stack_space
= (core_stack_lower_bound(system
->memory
)
292 - FLOOR_PAGE(top_of_stack
));
293 TRACE(trace_create_stack
,
294 ("create_elf_stack_frame() - growing stack by 0x%x\n",
296 core_add_stack(system
->memory
, extra_stack_space
);
299 /* install arguments on stack */
300 write_stack_arguments(system
, envp
, start_envp_block
, start_envp
);
301 write_stack_arguments(system
, argv
, start_argv_block
, start_argv
);
303 /* set up the registers */
304 psim_write_register(system
, -1,
305 &top_of_stack
, "r1", cooked_transfer
);
306 psim_write_register(system
, -1,
307 &argc
, "r3", cooked_transfer
);
308 psim_write_register(system
, -1,
309 &start_argv
, "r4", cooked_transfer
);
310 psim_write_register(system
, -1,
311 &start_envp
, "r5", cooked_transfer
);
312 psim_write_register(system
, -1,
313 &start_aux
, "r6", cooked_transfer
);
316 STATIC_INLINE_PSIM
void
317 create_aix_stack_frame(psim
*system
,
318 unsigned_word bottom_of_stack
,
322 unsigned_word core_envp
;
323 unsigned_word core_argv
;
324 unsigned_word core_argc
;
325 unsigned_word core_aux
;
326 unsigned_word top_of_stack
;
328 /* cheat - create an elf stack frame */
329 create_elf_stack_frame(system
, bottom_of_stack
, argv
, envp
);
331 /* extract argument addresses from registers */
332 psim_read_register(system
, 0, &top_of_stack
, "r1", cooked_transfer
);
333 psim_read_register(system
, 0, &core_argc
, "r3", cooked_transfer
);
334 psim_read_register(system
, 0, &core_argv
, "r4", cooked_transfer
);
335 psim_read_register(system
, 0, &core_envp
, "r5", cooked_transfer
);
336 psim_read_register(system
, 0, &core_aux
, "r6", cooked_transfer
);
338 /* check stack fits at least this much */
339 if (CURRENT_ENVIRONMENT
== VIRTUAL_ENVIRONMENT
340 && core_stack_lower_bound(system
->memory
) > top_of_stack
) {
341 unsigned_word extra_stack_space
= (core_stack_lower_bound(system
->memory
)
342 - FLOOR_PAGE(top_of_stack
));
343 TRACE(trace_create_stack
,
344 ("create_aix_stack_frame() - growing stack by 0x%x\n",
346 core_add_stack(system
->memory
, extra_stack_space
);
349 /* extract arguments from registers */
350 error("create_aix_stack_frame() - what happens next?\n");
355 psim_load(psim
*system
)
357 unsigned_word program_counter
;
360 /* load in core data */
361 core_init(system
->memory
);
363 /* set up all processor entry points (to same thing). Maybe
364 someday, the device tree could include information specifying the
365 entry point for each processor, one day */
367 ("TBD - device tree specifying entry point of each processor\n"));
368 program_counter
= device_tree_find_int(system
->devices
,
369 "/options/program-counter");
370 psim_write_register(system
, -1,
372 "pc", cooked_transfer
);
373 system
->last_cpu
= system
->nr_cpus
- 1; /* force loop to restart */
375 /* set up the MSR for at least be/le mode */
376 msr
= (device_tree_find_boolean(system
->devices
,
377 "/options/little-endian?")
378 ? msr_little_endian_mode
380 psim_write_register(system
, -1,
382 "msr", cooked_transfer
);
386 psim_stack(psim
*system
,
390 unsigned_word stack_pointer
= device_tree_find_int(system
->devices
,
391 "/options/stack-pointer");
392 if (device_tree_find_boolean(system
->devices
,
394 create_elf_stack_frame(system
, stack_pointer
, argv
, envp
);
396 create_aix_stack_frame(system
, stack_pointer
, argv
, envp
);
401 /* EXECUTE REAL CODE:
403 Unfortunatly, there are multiple cases to consider vis:
405 <icache> X <smp> X <events> X <keep-running-flag> X ...
407 Consequently this function is written in multiple different ways */
409 STATIC_INLINE_PSIM
void
410 run_until_stop(psim
*system
,
411 volatile int *keep_running
)
414 #if (WITH_IDECODE_CACHE == 0 && WITH_SMP == 0)
416 /* CASE 1: No instruction cache and no SMP.
418 In this case, we can take advantage of the fact that the current
419 instruction address does not need to be returned to the cpu
420 object after every execution of an instruction. Instead it only
421 needs to be saved when either A. the main loop exits or B. a
422 cpu-{halt,restart} call forces the loop to be re-entered. The
423 later functions always save the current cpu instruction
428 psim_set_halt_and_restart(system
, &halt
, &restart
);
431 if (!setjmp(restart
)) {
432 cpu
*const processor
= system
->processors
[0];
433 unsigned_word cia
= cpu_get_program_counter(processor
);
436 if (event_queue_tick(system
->events
)) {
437 cpu_set_program_counter(processor
, cia
);
438 event_queue_process(system
->events
);
439 cia
= cpu_get_program_counter(processor
);
443 instruction_word
const instruction
444 = vm_instruction_map_read(cpu_instruction_map(processor
),
446 cia
= idecode_issue(processor
, instruction
, cia
);
448 } while (keep_running
== NULL
|| *keep_running
);
449 cpu_set_program_counter(processor
, cia
);
451 } while(keep_running
== NULL
|| *keep_running
);
453 psim_clear_halt_and_restart(system
);
457 #if (WITH_IDECODE_CACHE > 0 && WITH_SMP == 0)
459 /* CASE 2: Instruction case but no SMP
461 Here, the additional complexity comes from there being two
462 different cache implementations. A simple function address cache
463 or a full cracked instruction cache */
467 psim_set_halt_and_restart(system
, &halt
, &restart
);
470 if (!setjmp(restart
)) {
471 cpu
*const processor
= system
->processors
[0];
472 unsigned_word cia
= cpu_get_program_counter(processor
);
475 if (event_queue_tick(system
->events
)) {
476 cpu_set_program_counter(processor
, cia
);
477 event_queue_process(system
->events
);
478 cia
= cpu_get_program_counter(processor
);
481 idecode_cache
*const cache_entry
482 = cpu_icache(processor
) + (cia
/ 4 % IDECODE_CACHE_SIZE
);
483 if (cache_entry
->address
== cia
) {
484 idecode_semantic
*const semantic
= cache_entry
->semantic
;
485 #if WITH_IDECODE_CACHE == 1
486 cia
= semantic(processor
, cache_entry
->instruction
, cia
);
488 cia
= semantic(processor
, cache_entry
, cia
);
492 instruction_word
const instruction
493 = vm_instruction_map_read(cpu_instruction_map(processor
),
496 #if WITH_IDECODE_CACHE == 1
497 idecode_semantic
*const semantic
= idecode(processor
,
501 idecode_semantic
*const semantic
= idecode(processor
,
506 cache_entry
->address
= cia
;
507 cache_entry
->semantic
= semantic
;
508 #if WITH_IDECODE_CACHE == 1
509 cache_entry
->instruction
= instruction
;
510 cia
= semantic(processor
, instruction
, cia
);
512 cia
= semantic(processor
, cache_entry
, cia
);
516 } while (keep_running
== NULL
|| *keep_running
);
517 cpu_set_program_counter(processor
, cia
);
519 } while(keep_running
== NULL
|| *keep_running
);
521 psim_clear_halt_and_restart(system
);
525 #if (WITH_IDECODE_CACHE == 0 && WITH_SMP > 0)
527 /* CASE 3: No ICACHE but SMP
529 The complexity here comes from needing to correctly restart the
530 system when it is aborted. In particular if cpu0 requests a
531 restart, the next cpu is still cpu1. Cpu0 being restarted after
532 all the other CPU's and the event queue have been processed */
536 psim_set_halt_and_restart(system
, &halt
, &restart
);
539 int first_cpu
= setjmp(restart
);
541 first_cpu
= system
->last_cpu
+ 1;
544 for (current_cpu
= first_cpu
, first_cpu
= 0;
545 current_cpu
< system
->nr_cpus
+ (WITH_EVENTS
? 1 : 0);
547 if (WITH_EVENTS
&& current_cpu
== system
->nr_cpus
) {
548 if (event_queue_tick(system
->events
))
549 event_queue_process(system
->events
);
552 cpu
*const processor
= system
->processors
[current_cpu
];
553 unsigned_word
const cia
= cpu_get_program_counter(processor
);
554 instruction_word instruction
=
555 vm_instruction_map_read(cpu_instruction_map(processor
),
558 cpu_set_program_counter(processor
,
559 idecode_issue(processor
, instruction
, cia
));
561 if (!(keep_running
== NULL
|| *keep_running
)) {
562 system
->last_cpu
= current_cpu
;
566 } while (keep_running
== NULL
|| *keep_running
);
568 psim_clear_halt_and_restart(system
);
571 #if (WITH_IDECODE_CACHE > 0 && WITH_SMP > 0)
573 /* CASE 4: ICACHE and SMP ...
575 This time, everything goes wrong. Need to restart loops
576 correctly, need to save the program counter and finally need to
577 keep track of each processors current address! */
581 psim_set_halt_and_restart(system
, &halt
, &restart
);
584 int first_cpu
= setjmp(restart
);
586 first_cpu
= system
->last_cpu
+ 1;
589 for (current_cpu
= first_cpu
, first_cpu
= 0;
590 current_cpu
< system
->nr_cpus
+ (WITH_EVENTS
? 1 : 0);
592 if (WITH_EVENTS
&& current_cpu
== system
->nr_cpus
) {
593 if (event_queue_tick(system
->events
))
594 event_queue_process(system
->events
);
597 cpu
*processor
= system
->processors
[current_cpu
];
598 unsigned_word
const cia
= cpu_get_program_counter(processor
);
599 idecode_cache
*cache_entry
600 = (cpu_icache(processor
) + (cia
/ 4 % IDECODE_CACHE_SIZE
));
601 if (cache_entry
->address
== cia
) {
602 idecode_semantic
*semantic
= cache_entry
->semantic
;
603 #if WITH_IDECODE_CACHE == 1
604 cpu_set_program_counter(processor
,
606 cache_entry
->instruction
,
609 cpu_set_program_counter(processor
,
616 instruction_word instruction
=
617 vm_instruction_map_read(cpu_instruction_map(processor
),
620 #if WITH_IDECODE_CACHE == 1
621 idecode_semantic
*semantic
= idecode(processor
,
625 idecode_semantic
*semantic
= idecode(processor
,
630 cache_entry
->address
= cia
;
631 cache_entry
->semantic
= semantic
;
632 #if WITH_IDECODE_CACHE == 1
633 cache_entry
->instruction
= instruction
;
634 cpu_set_program_counter(processor
,
635 semantic(processor
, instruction
, cia
));
637 cpu_set_program_counter(processor
,
638 semantic(processor
, cache_entry
, cia
);
642 if (!(keep_running
== NULL
|| *keep_running
))
645 } while (keep_running
== NULL
|| *keep_running
);
647 psim_clear_halt_and_restart(system
);
652 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
656 psim_step(psim
*system
)
658 volatile int keep_running
= 0;
659 psim_run_until_stop(system
, &keep_running
);
663 psim_run(psim
*system
)
665 run_until_stop(system
, NULL
);
669 psim_run_until_stop(psim
*system
,
670 volatile int *keep_running
)
672 run_until_stop(system
, keep_running
);
677 /* storage manipulation functions */
680 psim_read_register(psim
*system
,
686 register_descriptions description
;
687 char cooked_buf
[sizeof(natural_word
)];
690 /* find our processor */
691 if (which_cpu
< 0 || which_cpu
> system
->nr_cpus
)
692 error("psim_read_register() - invalid processor %d\n", which_cpu
);
693 if (which_cpu
== system
->nr_cpus
)
694 which_cpu
= system
->last_cpu
;
695 processor
= system
->processors
[which_cpu
];
697 /* find the register description */
698 description
= register_description(reg
);
699 if (description
.type
== reg_invalid
)
700 error("psim_read_register() invalid register name `%s'\n", reg
);
702 /* get the cooked value */
703 switch (description
.type
) {
706 *(gpreg
*)cooked_buf
= cpu_registers(processor
)->gpr
[description
.index
];
710 *(spreg
*)cooked_buf
= cpu_registers(processor
)->spr
[description
.index
];
714 *(sreg
*)cooked_buf
= cpu_registers(processor
)->sr
[description
.index
];
718 *(fpreg
*)cooked_buf
= cpu_registers(processor
)->fpr
[description
.index
];
722 *(unsigned_word
*)cooked_buf
= cpu_get_program_counter(processor
);
726 *(creg
*)cooked_buf
= cpu_registers(processor
)->cr
;
730 *(msreg
*)cooked_buf
= cpu_registers(processor
)->msr
;
734 printf_filtered("psim_read_register(processor=0x%x,buf=0x%x,reg=%s) %s\n",
736 "read of this register unimplemented");
741 /* the PSIM internal values are in host order. To fetch raw data,
742 they need to be converted into target order and then returned */
743 if (mode
== raw_transfer
) {
744 /* FIXME - assumes that all registers are simple integers */
745 switch (description
.size
) {
747 *(unsigned_1
*)buf
= H2T_1(*(unsigned_1
*)cooked_buf
);
750 *(unsigned_2
*)buf
= H2T_2(*(unsigned_2
*)cooked_buf
);
753 *(unsigned_4
*)buf
= H2T_4(*(unsigned_4
*)cooked_buf
);
756 *(unsigned_8
*)buf
= H2T_8(*(unsigned_8
*)cooked_buf
);
761 bcopy(cooked_buf
, buf
, description
.size
);
769 psim_write_register(psim
*system
,
776 register_descriptions description
;
777 char cooked_buf
[sizeof(natural_word
)];
779 /* find our processor */
780 if (which_cpu
== -1) {
782 for (i
= 0; i
< system
->nr_cpus
; i
++)
783 psim_write_register(system
, i
, buf
, reg
, mode
);
786 else if (which_cpu
== system
->nr_cpus
) {
787 which_cpu
= system
->last_cpu
;
789 else if (which_cpu
< 0 || which_cpu
>= system
->nr_cpus
) {
790 error("psim_read_register() - invalid processor %d\n", which_cpu
);
793 processor
= system
->processors
[which_cpu
];
795 /* find the description of the register */
796 description
= register_description(reg
);
797 if (description
.type
== reg_invalid
)
798 error("psim_write_register() invalid register name %s\n", reg
);
800 /* If the data is comming in raw (target order), need to cook it
801 into host order before putting it into PSIM's internal structures */
802 if (mode
== raw_transfer
) {
803 switch (description
.size
) {
805 *(unsigned_1
*)cooked_buf
= T2H_1(*(unsigned_1
*)buf
);
808 *(unsigned_2
*)cooked_buf
= T2H_2(*(unsigned_2
*)buf
);
811 *(unsigned_4
*)cooked_buf
= T2H_4(*(unsigned_4
*)buf
);
814 *(unsigned_8
*)cooked_buf
= T2H_8(*(unsigned_8
*)buf
);
819 bcopy(buf
, cooked_buf
, description
.size
);
822 /* put the cooked value into the register */
823 switch (description
.type
) {
826 cpu_registers(processor
)->gpr
[description
.index
] = *(gpreg
*)cooked_buf
;
830 cpu_registers(processor
)->fpr
[description
.index
] = *(fpreg
*)cooked_buf
;
834 cpu_set_program_counter(processor
, *(unsigned_word
*)cooked_buf
);
838 cpu_registers(processor
)->spr
[description
.index
] = *(spreg
*)cooked_buf
;
842 cpu_registers(processor
)->sr
[description
.index
] = *(sreg
*)cooked_buf
;
846 cpu_registers(processor
)->cr
= *(creg
*)cooked_buf
;
850 cpu_registers(processor
)->msr
= *(msreg
*)cooked_buf
;
854 printf_filtered("psim_write_register(processor=0x%x,cooked_buf=0x%x,reg=%s) %s\n",
855 processor
, cooked_buf
, reg
,
856 "read of this register unimplemented");
866 psim_read_memory(psim
*system
,
874 if (which_cpu
< 0 || which_cpu
> system
->nr_cpus
)
875 error("psim_read_memory() invalid cpu\n");
876 if (which_cpu
== system
->nr_cpus
)
877 which_cpu
= system
->last_cpu
;
878 processor
= system
->processors
[which_cpu
];
879 return vm_data_map_read_buffer(cpu_data_map(processor
),
880 buffer
, vaddr
, len
, mode
);
885 psim_write_memory(psim
*system
,
891 int violate_read_only_section
)
894 if (which_cpu
< 0 || which_cpu
> system
->nr_cpus
)
895 error("psim_read_memory() invalid cpu\n");
896 if (which_cpu
== system
->nr_cpus
)
897 which_cpu
= system
->last_cpu
;
898 processor
= system
->processors
[which_cpu
];
899 return vm_data_map_write_buffer(cpu_data_map(processor
),
900 buffer
, vaddr
, len
, mode
, 1);
904 #endif /* _PSIM_C_ */