psim_halt(psim *system, int current_cpu, stop_reason reason, int signal) { ASSERT(current_cpu >= 0 && current_cpu <= system->nr_cpus); ASSERT(system->path_to_halt != NULL); system->last_cpu = current_cpu; system->halt_status.reason = reason; system->halt_status.signal = signal; if (current_cpu == system->nr_cpus) { system->halt_status.cpu_nr = 0; system->halt_status.program_counter = cpu_get_program_counter(system->processors[0]); } else { system->halt_status.cpu_nr = current_cpu; system->halt_status.program_counter = cpu_get_program_counter(system->processors[current_cpu]); } longjmp(*(jmp_buf*)(system->path_to_halt), current_cpu + 1); }
deliver_hardware_interrupt(void *data) { cpu *processor = (cpu*)data; interrupts *ints = cpu_interrupts(processor); ints->delivery_scheduled = NULL; if (cpu_registers(processor)->msr & msr_external_interrupt_enable) { /* external interrupts have a high priority and remain pending */ if (ints->pending_interrupts & external_interrupt_pending) { unsigned_word cia = cpu_get_program_counter(processor); unsigned_word nia = perform_oea_interrupt(processor, cia, 0x00500, 0, 0, 0, 0); cpu_set_program_counter(processor, nia); } /* decrementer interrupts have a lower priority and are once only */ else if (ints->pending_interrupts & decrementer_interrupt_pending) { unsigned_word cia = cpu_get_program_counter(processor); unsigned_word nia = perform_oea_interrupt(processor, cia, 0x00900, 0, 0, 0, 0); cpu_set_program_counter(processor, nia); ints->pending_interrupts &= ~decrementer_interrupt_pending; } } }
psim_init(psim *system) { int cpu_nr; /* scrub the monitor */ mon_init(system->monitor, system->nr_cpus); /* trash any pending events */ event_queue_init(system->events); /* if needed, schedule a halt event. FIXME - In the future this will be replaced by a more generic change to psim_command(). A new command `schedule NNN halt' being added. */ if (tree_find_property(system->devices, "/openprom/options/max-iterations")) { event_queue_schedule(system->events, tree_find_integer_property(system->devices, "/openprom/options/max-iterations") - 2, psim_max_iterations_exceeded, system); } /* scrub all the cpus */ for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) cpu_init(system->processors[cpu_nr]); /* init all the devices (which updates the cpus) */ tree_init(system->devices, system); /* and the emulation (which needs an initialized device tree) */ os_emul_init(system->os_emulation, system->nr_cpus); /* now sync each cpu against the initialized state of its registers */ for (cpu_nr = 0; cpu_nr < system->nr_cpus; cpu_nr++) { cpu *processor = system->processors[cpu_nr]; cpu_synchronize_context(processor, cpu_get_program_counter(processor)); cpu_page_tlb_invalidate_all(processor); } /* force loop to start with first cpu */ system->last_cpu = -1; }
psim_read_register(psim *system, int which_cpu, void *buf, const char reg[], transfer_mode mode) { register_descriptions description; char *cooked_buf; cpu *processor; /* find our processor */ if (which_cpu == MAX_NR_PROCESSORS) { if (system->last_cpu == system->nr_cpus || system->last_cpu == -1) which_cpu = 0; else which_cpu = system->last_cpu; } ASSERT(which_cpu >= 0 && which_cpu < system->nr_cpus); processor = system->processors[which_cpu]; /* find the register description */ description = register_description(reg); if (description.type == reg_invalid) return 0; cooked_buf = alloca (description.size); /* 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; case reg_fpscr: *(fpscreg*)cooked_buf = cpu_registers(processor)->fpscr; break; case reg_insns: *(unsigned_word*)cooked_buf = mon_get_number_of_insns(system->monitor, which_cpu); break; case reg_stalls: if (cpu_model(processor) == NULL) error("$stalls only valid if processor unit model enabled (-I)\n"); *(unsigned_word*)cooked_buf = model_get_number_of_stalls(cpu_model(processor)); break; case reg_cycles: if (cpu_model(processor) == NULL) error("$cycles only valid if processor unit model enabled (-I)\n"); *(unsigned_word*)cooked_buf = model_get_number_of_cycles(cpu_model(processor)); break; #ifdef WITH_ALTIVEC case reg_vr: *(vreg*)cooked_buf = cpu_registers(processor)->altivec.vr[description.index]; break; case reg_vscr: *(vscreg*)cooked_buf = cpu_registers(processor)->altivec.vscr; break; #endif #ifdef WITH_E500 case reg_gprh: *(gpreg*)cooked_buf = cpu_registers(processor)->e500.gprh[description.index]; break; case reg_evr: *(unsigned64*)cooked_buf = EVR(description.index); break; case reg_acc: *(accreg*)cooked_buf = cpu_registers(processor)->e500.acc; break; #endif default: printf_filtered("psim_read_register(processor=0x%lx,buf=0x%lx,reg=%s) %s\n", (unsigned long)processor, (unsigned long)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; #ifdef WITH_ALTIVEC case 16: if (CURRENT_HOST_BYTE_ORDER != CURRENT_TARGET_BYTE_ORDER) { union { vreg v; unsigned_8 d[2]; } h, t; memcpy(&h.v/*dest*/, cooked_buf/*src*/, description.size); { _SWAP_8(t.d[0] =, h.d[1]); } { _SWAP_8(t.d[1] =, h.d[0]); } memcpy(buf/*dest*/, &t/*src*/, description.size); break; } else memcpy(buf/*dest*/, cooked_buf/*src*/, description.size); break; #endif } }