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.
29 #include "ppc-config.h"
36 #ifndef STATIC_INLINE_PSIM
37 #define STATIC_INLINE_PSIM STATIC_INLINE
42 #include "cpu.h" /* includes psim.h */
58 /* Any starting address less than this is assumed to be an OEA program
60 #ifndef OEA_START_ADDRESS
61 #define OEA_START_ADDRESS 4096
64 /* Any starting address greater than this is assumed to be an OpenBoot
66 #ifndef OPENBOOT_START_ADDRESS
67 #define OPENBOOT_START_ADDRESS 0x80000000
70 #ifndef OEA_MEMORY_SIZE
71 #define OEA_MEMORY_SIZE 0x100000
75 /* system structure, actual size of processor array determined at
83 /* escape routine for inner functions */
85 void *path_to_restart;
86 /* status from last halt */
87 psim_status halt_status;
88 /* the processes proper */
90 int last_cpu; /* CPU that last (tried to) execute an instruction */
91 cpu *processors[MAX_NR_PROCESSORS];
95 int current_target_byte_order;
96 int current_host_byte_order;
97 int current_environment;
98 int current_alignment;
99 int current_floating_point;
100 model_enum current_model = WITH_DEFAULT_MODEL;
103 /* create a device tree from the image */
107 /* Raw hardware tree:
109 A small default set of devices are configured. Each section of the
110 image is loaded directly into physical memory. */
112 STATIC_INLINE_PSIM void
113 create_hardware_device_tree(bfd *image,
117 const memory_size = OEA_MEMORY_SIZE;
120 device_tree_add_passthrough(root, "/options");
121 device_tree_add_integer(root, "/options/smp",
123 device_tree_add_boolean(root, "/options/little-endian?",
124 !image->xvec->byteorder_big_p);
125 device_tree_add_string(root, "/options/env",
127 device_tree_add_boolean(root, "/options/strict-alignment?",
128 (WITH_ALIGNMENT == STRICT_ALIGNMENT
129 || !image->xvec->byteorder_big_p));
130 device_tree_add_boolean(root, "/options/floating-point?",
131 WITH_FLOATING_POINT);
134 name = printd_uw_u_u("/memory", 0, memory_size, access_read_write_exec);
135 device_tree_add_found_device(root, name);
137 device_tree_add_found_device(root, "/iobus@0x400000");
138 device_tree_add_found_device(root, "/iobus/console@0x000000,16");
139 device_tree_add_found_device(root, "/iobus/halt@0x100000,4");
140 device_tree_add_found_device(root, "/iobus/icu@0x200000,4");
143 device_tree_add_passthrough(root, "/init");
144 device_tree_add_found_device(root, "/init/register@pc,0x0");
145 name = printd_c_uw("/init/register", "sp", memory_size);
146 device_tree_add_found_device(root, name);
148 name = printd_c_uw("/init/register", "msr",
149 (image->xvec->byteorder_big_p
151 : msr_little_endian_mode));
152 device_tree_add_found_device(root, name);
154 /* AJC puts the PC at zero and wants a stack while MM puts it above
155 zero and doesn't. Really there should be no stack *but* this
156 makes testing easier */
157 device_tree_add_found_device(root,
158 (bfd_get_start_address(image) == 0
160 : "/init/stack@none"));
161 name = printd_c("/init/load-binary", bfd_get_filename(image));
162 device_tree_add_found_device(root, name);
167 /* Openboot model (under development):
169 An extension of the hardware model. The image is read into memory
170 as a single block. Sections of the image are then mapped as
171 required using a HTAB. */
173 STATIC_INLINE_PSIM void
174 create_openboot_device_tree(bfd *image,
177 create_hardware_device_tree(image, root);
183 Image sections loaded into virtual addresses as specified. A
184 (large) stack is reserved (but only allocated as needed). System
185 calls that include suport for heap growth are attached. */
187 STATIC_INLINE_PSIM void
188 create_vea_device_tree(bfd *image,
191 unsigned_word top_of_stack;
196 /* establish a few defaults */
197 if (image->xvec->flavour == bfd_target_elf_flavour) {
199 top_of_stack = 0xe0000000;
200 stack_size = 0x00100000;
204 top_of_stack = 0x20000000;
205 stack_size = 0x00100000;
209 device_tree_add_passthrough(root, "/options");
210 device_tree_add_integer(root, "/options/smp", 1); /* always */
211 device_tree_add_boolean(root, "/options/little-endian?",
212 !image->xvec->byteorder_big_p);
213 device_tree_add_string(root, "/options/env",
214 (WITH_ENVIRONMENT == USER_ENVIRONMENT
215 ? "user" : "virtual"));
216 device_tree_add_boolean(root, "/options/strict-alignment?",
217 (WITH_ALIGNMENT == STRICT_ALIGNMENT
218 || !image->xvec->byteorder_big_p));
219 device_tree_add_boolean(root, "/options/floating-point?",
220 WITH_FLOATING_POINT);
222 /* virtual memory - handles growth of stack/heap */
223 name = printd_uw_u("/vm", top_of_stack - stack_size, stack_size);
224 device_tree_add_found_device(root, name);
226 name = printd_c("/vm/map-binary", bfd_get_filename(image));
227 device_tree_add_found_device(root, name);
230 /* finish the init */
231 device_tree_add_passthrough(root, "/init");
232 name = printd_c_uw("/init/register", "pc", bfd_get_start_address(image));
233 device_tree_add_found_device(root, name); /*pc*/
235 name = printd_c_uw("/init/register", "sp", top_of_stack);
236 device_tree_add_found_device(root, name);
238 name = printd_c_uw("/init/register", "msr",
239 (image->xvec->byteorder_big_p
241 : msr_little_endian_mode));
242 device_tree_add_found_device(root, name);
244 device_tree_add_found_device(root, (elf_binary
246 : "/init/stack@xcoff"));
252 The file contains lines that specify the describe the device tree
253 to be created, read them in and load them into the tree */
255 STATIC_INLINE_PSIM void
256 create_filed_device_tree(const char *file_name,
259 FILE *description = fopen(file_name, "r");
261 char device_path[1000];
262 while (fgets(device_path, sizeof(device_path), description)) {
263 /* check all of line was read */
265 char *end = strchr(device_path, '\n');
268 error("create_filed_device_tree() line %d to long: %s\n",
269 line_nr, device_path);
274 /* check for leading comment */
275 if (device_path[0] != '/')
277 /* enter it in varying ways */
278 if (strchr(device_path, '@') != NULL) {
279 device_tree_add_found_device(root, device_path);
282 char *space = strchr(device_path, ' ');
284 /* intermediate node */
285 device_tree_add_passthrough(root, device_path);
287 else if (space[-1] == '?') {
290 device_tree_add_boolean(root, device_path, space[1] != '0');
292 else if (isdigit(space[1])) {
295 device_tree_add_integer(root, device_path, strtoul(space+1, 0, 0));
297 else if (space[1] == '"') {
299 char *end = strchr(space+2, '\0');
303 device_tree_add_string(root, device_path, space + 2);
308 device_tree_add_string(root, device_path, space + 1);
316 /* Given the file containing the `image', create a device tree that
317 defines the machine to be modeled */
319 STATIC_INLINE_PSIM device_tree *
320 create_device_tree(const char *file_name,
324 const device *core_device = core_device_create(memory);
325 device_tree *root = device_tree_add_device(NULL, "/", core_device);
327 bfd_init(); /* could be redundant but ... */
330 image = bfd_openr(file_name, NULL);
332 bfd_perror("open failed:");
333 error("nothing loaded\n");
336 /* check it is valid */
337 if (!bfd_check_format(image, bfd_object)) {
338 printf_filtered("create_device_tree() - FIXME - should check more bfd bits\n");
339 printf_filtered("create_device_tree() - %s not an executable, assume device file\n", file_name);
344 /* depending on what was found about the file, load it */
346 if (bfd_get_start_address(image) < OEA_START_ADDRESS) {
347 TRACE(trace_device_tree, ("create_device_tree() - hardware image\n"));
348 create_hardware_device_tree(image, root);
350 else if (bfd_get_start_address(image) < OPENBOOT_START_ADDRESS) {
351 TRACE(trace_device_tree, ("create_device_tree() - vea image\n"));
352 create_vea_device_tree(image, root);
355 TRACE(trace_device_tree, ("create_device_tree() - openboot? image\n"));
356 create_openboot_device_tree(image, root);
361 TRACE(trace_device_tree, ("create_device_tree() - text image\n"));
362 create_filed_device_tree(file_name, root);
371 psim_create(const char *file_name)
378 system = ZALLOC(psim);
379 system->events = event_queue_create();
380 system->memory = core_create();
381 system->monitor = mon_create();
382 system->devices = create_device_tree(file_name, system->memory);
383 for (cpu_nr = 0; cpu_nr < MAX_NR_PROCESSORS; cpu_nr++) {
384 system->processors[cpu_nr] = cpu_create(system,
387 mon_cpu(system->monitor,
392 /* fill in the missing real number of CPU's */
393 system->nr_cpus = device_tree_find_integer(system->devices,
396 /* fill in the missing TARGET BYTE ORDER information */
397 current_target_byte_order = (device_tree_find_boolean(system->devices,
398 "/options/little-endian?")
401 if (CURRENT_TARGET_BYTE_ORDER != current_target_byte_order)
402 error("target byte order conflict\n");
404 /* fill in the missing HOST BYTE ORDER information */
405 current_host_byte_order = (current_host_byte_order = 1,
406 (*(char*)(¤t_host_byte_order)
409 if (CURRENT_HOST_BYTE_ORDER != current_host_byte_order)
410 error("host byte order conflict\n");
412 /* fill in the missing OEA/VEA information */
413 env = device_tree_find_string(system->devices,
415 current_environment = ((strcmp(env, "user") == 0
416 || strcmp(env, "uea") == 0)
418 : (strcmp(env, "virtual") == 0
419 || strcmp(env, "vea") == 0)
420 ? VIRTUAL_ENVIRONMENT
421 : (strcmp(env, "operating") == 0
422 || strcmp(env, "oea") == 0)
423 ? OPERATING_ENVIRONMENT
425 if (current_environment == 0)
426 error("unreconized /options/env\n");
427 if (CURRENT_ENVIRONMENT != current_environment)
428 error("target environment conflict\n");
430 /* fill in the missing ALLIGNMENT information */
431 current_alignment = (device_tree_find_boolean(system->devices,
432 "/options/strict-alignment?")
434 : NONSTRICT_ALIGNMENT);
435 if (CURRENT_ALIGNMENT != current_alignment)
436 error("target alignment conflict\n");
438 /* fill in the missing FLOATING POINT information */
439 current_floating_point = (device_tree_find_boolean(system->devices,
440 "/options/floating-point?")
441 ? HARD_FLOATING_POINT
442 : SOFT_FLOATING_POINT);
443 if (CURRENT_FLOATING_POINT != current_floating_point)
444 error("target floating-point conflict\n");
450 /* allow the simulation to stop/restart abnormaly */
452 STATIC_INLINE_PSIM void
453 psim_set_halt_and_restart(psim *system,
455 void *restart_jmp_buf)
457 system->path_to_halt = halt_jmp_buf;
458 system->path_to_restart = restart_jmp_buf;
461 STATIC_INLINE_PSIM void
462 psim_clear_halt_and_restart(psim *system)
464 system->path_to_halt = NULL;
465 system->path_to_restart = NULL;
469 psim_restart(psim *system,
472 system->last_cpu = current_cpu;
473 longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1);
478 psim_halt(psim *system,
484 system->last_cpu = current_cpu;
485 system->halt_status.cpu_nr = current_cpu;
486 system->halt_status.reason = reason;
487 system->halt_status.signal = signal;
488 system->halt_status.program_counter = cia;
489 longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1);
492 INLINE_PSIM psim_status
493 psim_get_status(psim *system)
495 return system->halt_status;
500 psim_cpu(psim *system,
503 if (cpu_nr < 0 || cpu_nr >= system->nr_cpus)
506 return system->processors[cpu_nr];
511 psim_device(psim *system,
514 return device_tree_find_device(system->devices, path);
520 psim_init(psim *system)
524 /* scrub the monitor */
525 mon_init(system->monitor, system->nr_cpus);
527 /* scrub all the cpus */
528 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
529 cpu_init(system->processors[cpu_nr]);
531 /* init all the devices */
532 device_tree_init(system->devices, system);
534 /* force loop to restart */
535 system->last_cpu = system->nr_cpus - 1;
539 psim_stack(psim *system,
543 /* pass the stack device the argv/envp and let it work out what to
545 const device *stack_device = device_tree_find_device(system->devices,
547 unsigned_word stack_pointer;
548 psim_read_register(system, 0, &stack_pointer, "sp", cooked_transfer);
549 stack_device->callback->ioctl(stack_device,
560 /* EXECUTE REAL CODE:
562 Unfortunatly, there are multiple cases to consider vis:
564 <icache> X <smp> X <events> X <keep-running-flag> X ...
566 Consequently this function is written in multiple different ways */
568 STATIC_INLINE_PSIM void
569 run_until_stop(psim *system,
570 volatile int *keep_running)
575 #if WITH_IDECODE_CACHE_SIZE
576 for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++)
577 cpu_flush_icache(system->processors[cpu_nr]);
579 psim_set_halt_and_restart(system, &halt, &restart);
581 #if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
583 /* CASE 1: No instruction cache and no SMP.
585 In this case, we can take advantage of the fact that the current
586 instruction address does not need to be returned to the cpu
587 object after every execution of an instruction. Instead it only
588 needs to be saved when either A. the main loop exits or B. a
589 cpu-{halt,restart} call forces the loop to be re-entered. The
590 later functions always save the current cpu instruction
595 if (!setjmp(restart)) {
596 cpu *const processor = system->processors[0];
597 unsigned_word cia = cpu_get_program_counter(processor);
600 if (event_queue_tick(system->events)) {
601 cpu_set_program_counter(processor, cia);
602 event_queue_process(system->events);
603 cia = cpu_get_program_counter(processor);
607 instruction_word const instruction
608 = vm_instruction_map_read(cpu_instruction_map(processor),
610 cia = idecode_issue(processor, instruction, cia);
612 } while (keep_running == NULL || *keep_running);
613 cpu_set_program_counter(processor, cia);
615 } while(keep_running == NULL || *keep_running);
620 #if (WITH_IDECODE_CACHE_SIZE && WITH_SMP == 0)
622 /* CASE 2: Instruction case but no SMP
624 Here, the additional complexity comes from there being two
625 different cache implementations. A simple function address cache
626 or a full cracked instruction cache */
630 if (!setjmp(restart)) {
631 cpu *const processor = system->processors[0];
632 unsigned_word cia = cpu_get_program_counter(processor);
635 if (event_queue_tick(system->events)) {
636 cpu_set_program_counter(processor, cia);
637 event_queue_process(system->events);
638 cia = cpu_get_program_counter(processor);
641 idecode_cache *const cache_entry = cpu_icache_entry(processor,
643 if (cache_entry->address == cia) {
644 idecode_semantic *const semantic = cache_entry->semantic;
645 cia = semantic(processor, cache_entry, cia);
648 instruction_word const instruction
649 = vm_instruction_map_read(cpu_instruction_map(processor),
652 idecode_semantic *const semantic = idecode(processor,
657 mon_event(mon_event_icache_miss, processor, cia);
658 cache_entry->address = cia;
659 cache_entry->semantic = semantic;
660 cia = semantic(processor, cache_entry, cia);
663 } while (keep_running == NULL || *keep_running);
664 cpu_set_program_counter(processor, cia);
666 } while(keep_running == NULL || *keep_running);
671 #if (!WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
673 /* CASE 3: No ICACHE but SMP
675 The complexity here comes from needing to correctly restart the
676 system when it is aborted. In particular if cpu0 requests a
677 restart, the next cpu is still cpu1. Cpu0 being restarted after
678 all the other CPU's and the event queue have been processed */
681 int first_cpu = setjmp(restart);
683 first_cpu = system->last_cpu + 1;
686 for (current_cpu = first_cpu, first_cpu = 0;
687 current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
689 if (WITH_EVENTS && current_cpu == system->nr_cpus) {
690 if (event_queue_tick(system->events))
691 event_queue_process(system->events);
694 cpu *const processor = system->processors[current_cpu];
695 unsigned_word const cia = cpu_get_program_counter(processor);
696 instruction_word instruction =
697 vm_instruction_map_read(cpu_instruction_map(processor),
700 cpu_set_program_counter(processor,
701 idecode_issue(processor, instruction, cia));
703 if (!(keep_running == NULL || *keep_running)) {
704 system->last_cpu = current_cpu;
708 } while (keep_running == NULL || *keep_running);
712 #if (WITH_IDECODE_CACHE_SIZE && WITH_SMP > 0)
714 /* CASE 4: ICACHE and SMP ...
716 This time, everything goes wrong. Need to restart loops
717 correctly, need to save the program counter and finally need to
718 keep track of each processors current address! */
721 int first_cpu = setjmp(restart);
723 first_cpu = system->last_cpu + 1;
726 for (current_cpu = first_cpu, first_cpu = 0;
727 current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0);
729 if (WITH_EVENTS && current_cpu == system->nr_cpus) {
730 if (event_queue_tick(system->events))
731 event_queue_process(system->events);
734 cpu *processor = system->processors[current_cpu];
735 unsigned_word const cia = cpu_get_program_counter(processor);
736 idecode_cache *cache_entry = cpu_icache_entry(processor, cia);
737 if (cache_entry->address == cia) {
738 idecode_semantic *semantic = cache_entry->semantic;
739 cpu_set_program_counter(processor,
740 semantic(processor, cache_entry, cia));
743 instruction_word instruction =
744 vm_instruction_map_read(cpu_instruction_map(processor),
747 idecode_semantic *semantic = idecode(processor,
752 mon_event(mon_event_icache_miss, system->processors[current_cpu], cia);
753 cache_entry->address = cia;
754 cache_entry->semantic = semantic;
755 cpu_set_program_counter(processor,
756 semantic(processor, cache_entry, cia));
759 if (!(keep_running == NULL || *keep_running))
762 } while (keep_running == NULL || *keep_running);
766 psim_clear_halt_and_restart(system);
770 /* SIMULATE INSTRUCTIONS, various different ways of achieving the same
774 psim_step(psim *system)
776 volatile int keep_running = 0;
777 run_until_stop(system, &keep_running);
781 psim_run(psim *system)
783 run_until_stop(system, NULL);
787 psim_run_until_stop(psim *system,
788 volatile int *keep_running)
790 run_until_stop(system, keep_running);
795 /* storage manipulation functions */
798 psim_read_register(psim *system,
804 register_descriptions description;
805 char cooked_buf[sizeof(natural_word)];
808 /* find our processor */
809 if (which_cpu == MAX_NR_PROCESSORS)
810 which_cpu = system->last_cpu;
811 if (which_cpu < 0 || which_cpu >= system->nr_cpus)
812 error("psim_read_register() - invalid processor %d\n", which_cpu);
813 processor = system->processors[which_cpu];
815 /* find the register description */
816 description = register_description(reg);
817 if (description.type == reg_invalid)
818 error("psim_read_register() invalid register name `%s'\n", reg);
820 /* get the cooked value */
821 switch (description.type) {
824 *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index];
828 *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index];
832 *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index];
836 *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index];
840 *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor);
844 *(creg*)cooked_buf = cpu_registers(processor)->cr;
848 *(msreg*)cooked_buf = cpu_registers(processor)->msr;
852 printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n",
853 (unsigned long)processor, (unsigned long)buf, reg,
854 "read of this register unimplemented");
859 /* the PSIM internal values are in host order. To fetch raw data,
860 they need to be converted into target order and then returned */
861 if (mode == raw_transfer) {
862 /* FIXME - assumes that all registers are simple integers */
863 switch (description.size) {
865 *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf);
868 *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf);
871 *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf);
874 *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf);
879 memcpy(buf/*dest*/, cooked_buf/*src*/, description.size);
887 psim_write_register(psim *system,
894 register_descriptions description;
895 char cooked_buf[sizeof(natural_word)];
897 /* find our processor */
898 if (which_cpu == MAX_NR_PROCESSORS)
899 which_cpu = system->last_cpu;
900 if (which_cpu == -1) {
902 for (i = 0; i < system->nr_cpus; i++)
903 psim_write_register(system, i, buf, reg, mode);
906 else if (which_cpu < 0 || which_cpu >= system->nr_cpus) {
907 error("psim_read_register() - invalid processor %d\n", which_cpu);
910 processor = system->processors[which_cpu];
912 /* find the description of the register */
913 description = register_description(reg);
914 if (description.type == reg_invalid)
915 error("psim_write_register() invalid register name %s\n", reg);
917 /* If the data is comming in raw (target order), need to cook it
918 into host order before putting it into PSIM's internal structures */
919 if (mode == raw_transfer) {
920 switch (description.size) {
922 *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf);
925 *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf);
928 *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf);
931 *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf);
936 memcpy(cooked_buf/*dest*/, buf/*src*/, description.size);
939 /* put the cooked value into the register */
940 switch (description.type) {
943 cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf;
947 cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf;
951 cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf);
955 cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf;
959 cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf;
963 cpu_registers(processor)->cr = *(creg*)cooked_buf;
967 cpu_registers(processor)->msr = *(msreg*)cooked_buf;
971 printf_filtered("psim_write_register(processor=0x%lx,cooked_buf=0x%lx,reg=%s) %s\n",
972 (unsigned long)processor, (unsigned long)cooked_buf, reg,
973 "read of this register unimplemented");
983 psim_read_memory(psim *system,
990 if (which_cpu == MAX_NR_PROCESSORS)
991 which_cpu = system->last_cpu;
992 if (which_cpu < 0 || which_cpu >= system->nr_cpus)
993 error("psim_read_memory() invalid cpu\n");
994 processor = system->processors[which_cpu];
995 return vm_data_map_read_buffer(cpu_data_map(processor),
996 buffer, vaddr, nr_bytes);
1000 INLINE_PSIM unsigned
1001 psim_write_memory(psim *system,
1004 unsigned_word vaddr,
1006 int violate_read_only_section)
1009 if (which_cpu == MAX_NR_PROCESSORS)
1010 which_cpu = system->last_cpu;
1011 if (which_cpu < 0 || which_cpu >= system->nr_cpus)
1012 error("psim_read_memory() invalid cpu\n");
1013 processor = system->processors[which_cpu];
1014 return vm_data_map_write_buffer(cpu_data_map(processor),
1015 buffer, vaddr, nr_bytes, 1);
1020 psim_print_info(psim *system,
1023 mon_print_info(system, system->monitor, verbose);
1027 #endif /* _PSIM_C_ */