diff options
Diffstat (limited to 'sim/ppc/psim.c')
-rw-r--r-- | sim/ppc/psim.c | 904 |
1 files changed, 904 insertions, 0 deletions
diff --git a/sim/ppc/psim.c b/sim/ppc/psim.c new file mode 100644 index 0000000..45fb821 --- /dev/null +++ b/sim/ppc/psim.c @@ -0,0 +1,904 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _PSIM_C_ +#define _PSIM_C_ + +#include "config.h" +#include "ppc-config.h" +#include "inline.h" + +#ifndef STATIC_INLINE_PSIM +#define STATIC_INLINE_PSIM STATIC_INLINE +#endif + +#include <string.h> +#include <setjmp.h> + +#include "cpu.h" /* includes psim.h */ +#include "idecode.h" + +#include "inline.c" + + +/* system structure, actual size of processor array determined at + runtime */ + +struct _psim { + event_queue *events; + device_node *devices; + core *memory; + /* escape routine for inner functions */ + void *path_to_halt; + void *path_to_restart; + /* status from last halt */ + psim_status halt_status; + /* the processes proper */ + int nr_cpus; + int last_cpu; /* CPU that last (tried to) execute an instruction */ + cpu *processors[0]; +}; + + +int current_target_byte_order; +int current_host_byte_order; +int current_environment; +int current_alignment; + +INLINE_PSIM psim * +psim_create(const char *file_name, + int nr_processors) +{ + int cpu_nr; + psim *system; + + /* sanity check */ + if (nr_processors <= 0 + || (!WITH_SMP && nr_processors != 1)) + error("psim_create() invalid number of cpus\n"); + + /* create things */ + system = (psim*)zalloc(sizeof(psim) + + sizeof(cpu*) * (nr_processors + 1)); + system->nr_cpus = nr_processors; + system->events = event_queue_create(); + system->devices = device_tree_create(file_name); + system->memory = core_create(system->devices, 0); + for (cpu_nr = 0; cpu_nr < nr_processors; cpu_nr++) { + system->processors[cpu_nr] = cpu_create(system, + system->memory, + system->events, + cpu_nr); + } + + /* fill in the missing endian information */ + current_target_byte_order + = (device_tree_find_boolean(system->devices, "/options/little-endian?") + ? LITTLE_ENDIAN + : BIG_ENDIAN); + if (WITH_TARGET_BYTE_ORDER + && WITH_TARGET_BYTE_ORDER != current_target_byte_order) + error("target byte order conflict\n"); + + current_host_byte_order = 1; + current_host_byte_order = (*(char*)(¤t_host_byte_order) + ? LITTLE_ENDIAN + : BIG_ENDIAN); + if (WITH_HOST_BYTE_ORDER + && WITH_HOST_BYTE_ORDER != current_host_byte_order) + error("host byte order conflict\n"); + + /* fill in the missing OEA/VEA information */ + current_environment = (device_tree_find_boolean(system->devices, + "/options/vea?") + ? VIRTUAL_ENVIRONMENT + : OPERATING_ENVIRONMENT); + + /* fill in the missing ALLIGNMENT information */ + current_alignment = (device_tree_find_boolean(system->devices, + "/options/aligned?") + ? STRICT_ALIGNMENT + : NONSTRICT_ALIGNMENT); + if (WITH_ALIGNMENT + && CURRENT_ALIGNMENT != WITH_ALIGNMENT) + error("target alignment support conflict\n"); + + return system; +} + + +/* allow the simulation to stop/restart abnormaly */ + +STATIC_INLINE_PSIM void +psim_set_halt_and_restart(psim *system, + void *halt_jmp_buf, + void *restart_jmp_buf) +{ + system->path_to_halt = halt_jmp_buf; + system->path_to_restart = restart_jmp_buf; +} + +STATIC_INLINE_PSIM void +psim_clear_halt_and_restart(psim *system) +{ + system->path_to_halt = NULL; + system->path_to_restart = NULL; +} + +INLINE_PSIM void +psim_restart(psim *system, + int current_cpu) +{ + system->last_cpu = current_cpu; + longjmp(*(jmp_buf*)(system->path_to_restart), current_cpu + 1); +} + + +INLINE_PSIM void +psim_halt(psim *system, + int current_cpu, + unsigned_word cia, + stop_reason reason, + int signal) +{ + system->last_cpu = current_cpu; + system->halt_status.cpu_nr = current_cpu; + system->halt_status.reason = reason; + system->halt_status.signal = signal; + system->halt_status.program_counter = cia; + longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1); +} + +INLINE_PSIM psim_status +psim_get_status(psim *system) +{ + return system->halt_status; +} + + +cpu * +psim_cpu(psim *system, + int cpu_nr) +{ + if (cpu_nr < 0 || cpu_nr >= system->nr_cpus) + return NULL; + else + return system->processors[cpu_nr]; +} + + + +STATIC_INLINE_PSIM int +sizeof_argument_strings(char **arg) +{ + int sizeof_strings = 0; + + /* robust */ + if (arg == NULL) + return 0; + + /* add up all the string sizes (padding as we go) */ + for (; *arg != NULL; arg++) { + int len = strlen(*arg) + 1; + sizeof_strings += ALIGN_8(len); + } + + return sizeof_strings; +} + +STATIC_INLINE_PSIM int +number_of_arguments(char **arg) +{ + int nr; + if (arg == NULL) + return 0; + for (nr = 0; *arg != NULL; arg++, nr++); + return nr; +} + +STATIC_INLINE_PSIM int +sizeof_arguments(char **arg) +{ + return ALIGN_8((number_of_arguments(arg) + 1) * sizeof(unsigned_word)); +} + +STATIC_INLINE_PSIM void +write_stack_arguments(psim *system, + char **arg, + unsigned_word start_block, + unsigned_word start_arg) +{ + TRACE(trace_create_stack, + ("write_stack_arguments() - %s=0x%x %s=0x%x %s=0x%x %s=0x%x\n", + "system", system, "arg", arg, + "start_block", start_block, "start_arg", start_arg)); + if (arg == NULL) + error("write_arguments: character array NULL\n"); + /* only copy in arguments, memory is already zero */ + for (; *arg != NULL; arg++) { + int len = strlen(*arg)+1; + TRACE(trace_create_stack, + ("write_stack_arguments - write %s=%s at %s=0x%x %s=0x%x %s=0x%x\n", + "**arg", *arg, "start_block", start_block, + "len", len, "start_arg", start_arg)); + if (psim_write_memory(system, 0, *arg, + start_block, len, + raw_transfer, 0) != len) + error("write_arguments() - write of **arg (%s) at 0x%x failed\n", + *arg, start_block); + if (psim_write_memory(system, 0, &start_block, + start_arg, sizeof(start_block), + cooked_transfer, 0) != sizeof(start_block)) + error("write_arguments() - write of *arg failed\n"); + start_block += ALIGN_8(len); + start_arg += sizeof(start_block); + } +} + +STATIC_INLINE_PSIM void +create_elf_stack_frame(psim *system, + unsigned_word bottom_of_stack, + char **argv, + char **envp) +{ + /* fixme - this is over aligned */ + + /* information block */ + const unsigned sizeof_envp_block = sizeof_argument_strings(envp); + const unsigned_word start_envp_block = bottom_of_stack - sizeof_envp_block; + const unsigned sizeof_argv_block = sizeof_argument_strings(argv); + const unsigned_word start_argv_block = start_envp_block - sizeof_argv_block; + + /* auxiliary vector - contains only one entry */ + const unsigned sizeof_aux_entry = 2*sizeof(unsigned_word); /* magic */ + const unsigned_word start_aux = start_argv_block - ALIGN_8(sizeof_aux_entry); + + /* environment points (including null sentinal) */ + const unsigned sizeof_envp = sizeof_arguments(envp); + const unsigned_word start_envp = start_aux - sizeof_envp; + + /* argument pointers (including null sentinal) */ + const int argc = number_of_arguments(argv); + const unsigned sizeof_argv = sizeof_arguments(argv); + const unsigned_word start_argv = start_envp - sizeof_argv; + + /* link register save address - alligned to a 16byte boundary */ + const unsigned_word top_of_stack = ((start_argv + - 2 * sizeof(unsigned_word)) + & ~0xf); + + /* force some stack space */ + if (CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT + && core_stack_lower_bound(system->memory) > top_of_stack) { + unsigned_word extra_stack_space = (core_stack_lower_bound(system->memory) + - FLOOR_PAGE(top_of_stack)); + TRACE(trace_create_stack, + ("create_elf_stack_frame() - growing stack by 0x%x\n", + extra_stack_space)); + core_add_stack(system->memory, extra_stack_space); + } + + /* install arguments on stack */ + write_stack_arguments(system, envp, start_envp_block, start_envp); + write_stack_arguments(system, argv, start_argv_block, start_argv); + + /* set up the registers */ + psim_write_register(system, -1, + &top_of_stack, "r1", cooked_transfer); + psim_write_register(system, -1, + &argc, "r3", cooked_transfer); + psim_write_register(system, -1, + &start_argv, "r4", cooked_transfer); + psim_write_register(system, -1, + &start_envp, "r5", cooked_transfer); + psim_write_register(system, -1, + &start_aux, "r6", cooked_transfer); +} + +STATIC_INLINE_PSIM void +create_aix_stack_frame(psim *system, + unsigned_word bottom_of_stack, + char **argv, + char **envp) +{ + unsigned_word core_envp; + unsigned_word core_argv; + unsigned_word core_argc; + unsigned_word core_aux; + unsigned_word top_of_stack; + + /* cheat - create an elf stack frame */ + create_elf_stack_frame(system, bottom_of_stack, argv, envp); + + /* extract argument addresses from registers */ + psim_read_register(system, 0, &top_of_stack, "r1", cooked_transfer); + psim_read_register(system, 0, &core_argc, "r3", cooked_transfer); + psim_read_register(system, 0, &core_argv, "r4", cooked_transfer); + psim_read_register(system, 0, &core_envp, "r5", cooked_transfer); + psim_read_register(system, 0, &core_aux, "r6", cooked_transfer); + + /* check stack fits at least this much */ + if (CURRENT_ENVIRONMENT == VIRTUAL_ENVIRONMENT + && core_stack_lower_bound(system->memory) > top_of_stack) { + unsigned_word extra_stack_space = (core_stack_lower_bound(system->memory) + - FLOOR_PAGE(top_of_stack)); + TRACE(trace_create_stack, + ("create_aix_stack_frame() - growing stack by 0x%x\n", + extra_stack_space)); + core_add_stack(system->memory, extra_stack_space); + } + + /* extract arguments from registers */ + error("create_aix_stack_frame() - what happens next?\n"); +} + + +INLINE_PSIM void +psim_load(psim *system) +{ + unsigned_word program_counter; + msreg msr; + + /* load in core data */ + core_init(system->memory); + + /* set up all processor entry points (to same thing). Maybe + someday, the device tree could include information specifying the + entry point for each processor, one day */ + TRACE(trace_tbd, + ("TBD - device tree specifying entry point of each processor\n")); + program_counter = device_tree_find_int(system->devices, + "/options/program-counter"); + psim_write_register(system, -1, + &program_counter, + "pc", cooked_transfer); + system->last_cpu = system->nr_cpus - 1; /* force loop to restart */ + + /* set up the MSR for at least be/le mode */ + msr = (device_tree_find_boolean(system->devices, + "/options/little-endian?") + ? msr_little_endian_mode + : 0); + psim_write_register(system, -1, + &msr, + "msr", cooked_transfer); +} + +INLINE_PSIM void +psim_stack(psim *system, + char **argv, + char **envp) +{ + unsigned_word stack_pointer = device_tree_find_int(system->devices, + "/options/stack-pointer"); + if (device_tree_find_boolean(system->devices, + "/options/elf?")) + create_elf_stack_frame(system, stack_pointer, argv, envp); + else + create_aix_stack_frame(system, stack_pointer, argv, envp); +} + + + +/* EXECUTE REAL CODE: + + Unfortunatly, there are multiple cases to consider vis: + + <icache> X <smp> X <events> X <keep-running-flag> X ... + + Consequently this function is written in multiple different ways */ + +STATIC_INLINE_PSIM void +run_until_stop(psim *system, + volatile int *keep_running) +{ + +#if (WITH_IDECODE_CACHE == 0 && WITH_SMP == 0) + + /* CASE 1: No instruction cache and no SMP. + + In this case, we can take advantage of the fact that the current + instruction address does not need to be returned to the cpu + object after every execution of an instruction. Instead it only + needs to be saved when either A. the main loop exits or B. a + cpu-{halt,restart} call forces the loop to be re-entered. The + later functions always save the current cpu instruction + address. */ + + jmp_buf halt; + jmp_buf restart; + psim_set_halt_and_restart(system, &halt, &restart); + if (!setjmp(halt)) { + do { + if (!setjmp(restart)) { + cpu *const processor = system->processors[0]; + unsigned_word cia = cpu_get_program_counter(processor); + do { + if (WITH_EVENTS) { + if (event_queue_tick(system->events)) { + cpu_set_program_counter(processor, cia); + event_queue_process(system->events); + cia = cpu_get_program_counter(processor); + } + } + { + instruction_word const instruction + = vm_instruction_map_read(cpu_instruction_map(processor), + processor, cia); + cia = idecode_issue(processor, instruction, cia); + } + } while (keep_running == NULL || *keep_running); + cpu_set_program_counter(processor, cia); + } + } while(keep_running == NULL || *keep_running); + } + psim_clear_halt_and_restart(system); +#endif + + +#if (WITH_IDECODE_CACHE > 0 && WITH_SMP == 0) + + /* CASE 2: Instruction case but no SMP + + Here, the additional complexity comes from there being two + different cache implementations. A simple function address cache + or a full cracked instruction cache */ + + jmp_buf halt; + jmp_buf restart; + psim_set_halt_and_restart(system, &halt, &restart); + if (!setjmp(halt)) { + do { + if (!setjmp(restart)) { + cpu *const processor = system->processors[0]; + unsigned_word cia = cpu_get_program_counter(processor); + do { + if (WITH_EVENTS) + if (event_queue_tick(system->events)) { + cpu_set_program_counter(processor, cia); + event_queue_process(system->events); + cia = cpu_get_program_counter(processor); + } + { + idecode_cache *const cache_entry + = cpu_icache(processor) + (cia / 4 % IDECODE_CACHE_SIZE); + if (cache_entry->address == cia) { + idecode_semantic *const semantic = cache_entry->semantic; +#if WITH_IDECODE_CACHE == 1 + cia = semantic(processor, cache_entry->instruction, cia); +#else + cia = semantic(processor, cache_entry, cia); +#endif + } + else { + instruction_word const instruction + = vm_instruction_map_read(cpu_instruction_map(processor), + processor, + cia); +#if WITH_IDECODE_CACHE == 1 + idecode_semantic *const semantic = idecode(processor, + instruction, + cia); +#else + idecode_semantic *const semantic = idecode(processor, + instruction, + cia, + cache_entry); +#endif + cache_entry->address = cia; + cache_entry->semantic = semantic; +#if WITH_IDECODE_CACHE == 1 + cache_entry->instruction = instruction; + cia = semantic(processor, instruction, cia); +#else + cia = semantic(processor, cache_entry, cia); +#endif + } + } + } while (keep_running == NULL || *keep_running); + cpu_set_program_counter(processor, cia); + } + } while(keep_running == NULL || *keep_running); + } + psim_clear_halt_and_restart(system); +#endif + + +#if (WITH_IDECODE_CACHE == 0 && WITH_SMP > 0) + + /* CASE 3: No ICACHE but SMP + + The complexity here comes from needing to correctly restart the + system when it is aborted. In particular if cpu0 requests a + restart, the next cpu is still cpu1. Cpu0 being restarted after + all the other CPU's and the event queue have been processed */ + + jmp_buf halt; + jmp_buf restart; + psim_set_halt_and_restart(system, &halt, &restart); + + if (!setjmp(halt)) { + int first_cpu = setjmp(restart); + if (first_cpu == 0) + first_cpu = system->last_cpu + 1; + do { + int current_cpu; + for (current_cpu = first_cpu, first_cpu = 0; + current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0); + current_cpu++) { + if (WITH_EVENTS && current_cpu == system->nr_cpus) { + if (event_queue_tick(system->events)) + event_queue_process(system->events); + } + else { + cpu *const processor = system->processors[current_cpu]; + unsigned_word const cia = cpu_get_program_counter(processor); + instruction_word instruction = + vm_instruction_map_read(cpu_instruction_map(processor), + processor, + cia); + cpu_set_program_counter(processor, + idecode_issue(processor, instruction, cia)); + } + if (!(keep_running == NULL || *keep_running)) { + system->last_cpu = current_cpu; + break; + } + } + } while (keep_running == NULL || *keep_running); + } + psim_clear_halt_and_restart(system); +#endif + +#if (WITH_IDECODE_CACHE > 0 && WITH_SMP > 0) + + /* CASE 4: ICACHE and SMP ... + + This time, everything goes wrong. Need to restart loops + correctly, need to save the program counter and finally need to + keep track of each processors current address! */ + + jmp_buf halt; + jmp_buf restart; + psim_set_halt_and_restart(system, &halt, &restart); + + if (!setjmp(halt)) { + int first_cpu = setjmp(restart); + if (!first_cpu) + first_cpu = system->last_cpu + 1; + do { + int current_cpu; + for (current_cpu = first_cpu, first_cpu = 0; + current_cpu < system->nr_cpus + (WITH_EVENTS ? 1 : 0); + current_cpu++) { + if (WITH_EVENTS && current_cpu == system->nr_cpus) { + if (event_queue_tick(system->events)) + event_queue_process(system->events); + } + else { + cpu *processor = system->processors[current_cpu]; + unsigned_word const cia = cpu_get_program_counter(processor); + idecode_cache *cache_entry + = (cpu_icache(processor) + (cia / 4 % IDECODE_CACHE_SIZE)); + if (cache_entry->address == cia) { + idecode_semantic *semantic = cache_entry->semantic; +#if WITH_IDECODE_CACHE == 1 + cpu_set_program_counter(processor, + semantic(processor, + cache_entry->instruction, + cia); +#else + cpu_set_program_counter(processor, + semantic(processor, + cache_entry, + cia); +#endif + } + else { + instruction_word instruction = + vm_instruction_map_read(cpu_instruction_map(processor), + processor, + cia); +#if WITH_IDECODE_CACHE == 1 + idecode_semantic *semantic = idecode(processor, + instruction, + cia); +#else + idecode_semantic *semantic = idecode(processor, + instruction, + cia, + cache_entry); +#endif + cache_entry->address = cia; + cache_entry->semantic = semantic; +#if WITH_IDECODE_CACHE == 1 + cache_entry->instruction = instruction; + cpu_set_program_counter(processor, + semantic(processor, instruction, cia)); +#else + cpu_set_program_counter(processor, + semantic(processor, cache_entry, cia); +#endif + } + } + if (!(keep_running == NULL || *keep_running)) + break; + } + } while (keep_running == NULL || *keep_running); + } + psim_clear_halt_and_restart(system); +#endif +} + + +/* SIMULATE INSTRUCTIONS, various different ways of achieving the same + thing */ + +INLINE_PSIM void +psim_step(psim *system) +{ + volatile int keep_running = 0; + psim_run_until_stop(system, &keep_running); +} + +INLINE_PSIM void +psim_run(psim *system) +{ + run_until_stop(system, NULL); +} + +INLINE_PSIM void +psim_run_until_stop(psim *system, + volatile int *keep_running) +{ + run_until_stop(system, keep_running); +} + + + +/* storage manipulation functions */ + +INLINE_PSIM void +psim_read_register(psim *system, + int which_cpu, + void *buf, + const char reg[], + transfer_mode mode) +{ + register_descriptions description; + char cooked_buf[sizeof(natural_word)]; + cpu *processor; + + /* find our processor */ + if (which_cpu < 0 || which_cpu > system->nr_cpus) + error("psim_read_register() - invalid processor %d\n", which_cpu); + if (which_cpu == system->nr_cpus) + which_cpu = system->last_cpu; + processor = system->processors[which_cpu]; + + /* find the register description */ + description = register_description(reg); + if (description.type == reg_invalid) + error("psim_read_register() invalid register name `%s'\n", reg); + + /* get the cooked value */ + switch (description.type) { + + case reg_gpr: + *(gpreg*)cooked_buf = cpu_registers(processor)->gpr[description.index]; + break; + + case reg_spr: + *(spreg*)cooked_buf = cpu_registers(processor)->spr[description.index]; + break; + + case reg_sr: + *(sreg*)cooked_buf = cpu_registers(processor)->sr[description.index]; + break; + + case reg_fpr: + *(fpreg*)cooked_buf = cpu_registers(processor)->fpr[description.index]; + break; + + case reg_pc: + *(unsigned_word*)cooked_buf = cpu_get_program_counter(processor); + break; + + case reg_cr: + *(creg*)cooked_buf = cpu_registers(processor)->cr; + break; + + case reg_msr: + *(msreg*)cooked_buf = cpu_registers(processor)->msr; + break; + + default: + printf_filtered("psim_read_register(processor=0x%x,buf=0x%x,reg=%s) %s\n", + processor, buf, reg, + "read of this register unimplemented"); + break; + + } + + /* the PSIM internal values are in host order. To fetch raw data, + they need to be converted into target order and then returned */ + if (mode == raw_transfer) { + /* FIXME - assumes that all registers are simple integers */ + switch (description.size) { + case 1: + *(unsigned_1*)buf = H2T_1(*(unsigned_1*)cooked_buf); + break; + case 2: + *(unsigned_2*)buf = H2T_2(*(unsigned_2*)cooked_buf); + break; + case 4: + *(unsigned_4*)buf = H2T_4(*(unsigned_4*)cooked_buf); + break; + case 8: + *(unsigned_8*)buf = H2T_8(*(unsigned_8*)cooked_buf); + break; + } + } + else { + bcopy(cooked_buf, buf, description.size); + } + +} + + + +INLINE_PSIM void +psim_write_register(psim *system, + int which_cpu, + const void *buf, + const char reg[], + transfer_mode mode) +{ + cpu *processor; + register_descriptions description; + char cooked_buf[sizeof(natural_word)]; + + /* find our processor */ + if (which_cpu == -1) { + int i; + for (i = 0; i < system->nr_cpus; i++) + psim_write_register(system, i, buf, reg, mode); + return; + } + else if (which_cpu == system->nr_cpus) { + which_cpu = system->last_cpu; + } + else if (which_cpu < 0 || which_cpu >= system->nr_cpus) { + error("psim_read_register() - invalid processor %d\n", which_cpu); + } + + processor = system->processors[which_cpu]; + + /* find the description of the register */ + description = register_description(reg); + if (description.type == reg_invalid) + error("psim_write_register() invalid register name %s\n", reg); + + /* If the data is comming in raw (target order), need to cook it + into host order before putting it into PSIM's internal structures */ + if (mode == raw_transfer) { + switch (description.size) { + case 1: + *(unsigned_1*)cooked_buf = T2H_1(*(unsigned_1*)buf); + break; + case 2: + *(unsigned_2*)cooked_buf = T2H_2(*(unsigned_2*)buf); + break; + case 4: + *(unsigned_4*)cooked_buf = T2H_4(*(unsigned_4*)buf); + break; + case 8: + *(unsigned_8*)cooked_buf = T2H_8(*(unsigned_8*)buf); + break; + } + } + else { + bcopy(buf, cooked_buf, description.size); + } + + /* put the cooked value into the register */ + switch (description.type) { + + case reg_gpr: + cpu_registers(processor)->gpr[description.index] = *(gpreg*)cooked_buf; + break; + + case reg_fpr: + cpu_registers(processor)->fpr[description.index] = *(fpreg*)cooked_buf; + break; + + case reg_pc: + cpu_set_program_counter(processor, *(unsigned_word*)cooked_buf); + break; + + case reg_spr: + cpu_registers(processor)->spr[description.index] = *(spreg*)cooked_buf; + break; + + case reg_sr: + cpu_registers(processor)->sr[description.index] = *(sreg*)cooked_buf; + break; + + case reg_cr: + cpu_registers(processor)->cr = *(creg*)cooked_buf; + break; + + case reg_msr: + cpu_registers(processor)->msr = *(msreg*)cooked_buf; + break; + + default: + printf_filtered("psim_write_register(processor=0x%x,cooked_buf=0x%x,reg=%s) %s\n", + processor, cooked_buf, reg, + "read of this register unimplemented"); + break; + + } + +} + + + +INLINE_PSIM unsigned +psim_read_memory(psim *system, + int which_cpu, + void *buffer, + unsigned_word vaddr, + unsigned len, + transfer_mode mode) +{ + cpu *processor; + if (which_cpu < 0 || which_cpu > system->nr_cpus) + error("psim_read_memory() invalid cpu\n"); + if (which_cpu == system->nr_cpus) + which_cpu = system->last_cpu; + processor = system->processors[which_cpu]; + return vm_data_map_read_buffer(cpu_data_map(processor), + buffer, vaddr, len, mode); +} + + +INLINE_PSIM unsigned +psim_write_memory(psim *system, + int which_cpu, + const void *buffer, + unsigned_word vaddr, + unsigned len, + transfer_mode mode, + int violate_read_only_section) +{ + cpu *processor; + if (which_cpu < 0 || which_cpu > system->nr_cpus) + error("psim_read_memory() invalid cpu\n"); + if (which_cpu == system->nr_cpus) + which_cpu = system->last_cpu; + processor = system->processors[which_cpu]; + return vm_data_map_write_buffer(cpu_data_map(processor), + buffer, vaddr, len, mode, 1); +} + + +#endif /* _PSIM_C_ */ |