?? ppc.c
字號:
/* * QEMU generic PowerPC hardware System Emulator * * Copyright (c) 2003-2007 Jocelyn Mayer * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include "hw.h"#include "ppc.h"#include "qemu-timer.h"#include "sysemu.h"#include "nvram.h"//#define PPC_DEBUG_IRQ//#define PPC_DEBUG_TBextern FILE *logfile;extern int loglevel;static void cpu_ppc_tb_stop (CPUState *env);static void cpu_ppc_tb_start (CPUState *env);static void ppc_set_irq (CPUState *env, int n_IRQ, int level){ if (level) { env->pending_interrupts |= 1 << n_IRQ; cpu_interrupt(env, CPU_INTERRUPT_HARD); } else { env->pending_interrupts &= ~(1 << n_IRQ); if (env->pending_interrupts == 0) cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); }#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08" PRIx32 "req %08x\n", __func__, env, n_IRQ, level, env->pending_interrupts, env->interrupt_request); }#endif}/* PowerPC 6xx / 7xx internal IRQ controller */static void ppc6xx_set_irq (void *opaque, int pin, int level){ CPUState *env = opaque; int cur_level;#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: env %p pin %d level %d\n", __func__, env, pin, level); }#endif cur_level = (env->irq_input_state >> pin) & 1; /* Don't generate spurious events */ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { switch (pin) { case PPC6xx_INPUT_TBEN: /* Level sensitive - active high */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: %s the time base\n", __func__, level ? "start" : "stop"); }#endif if (level) { cpu_ppc_tb_start(env); } else { cpu_ppc_tb_stop(env); } case PPC6xx_INPUT_INT: /* Level sensitive - active high */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the external IRQ state to %d\n", __func__, level); }#endif ppc_set_irq(env, PPC_INTERRUPT_EXT, level); break; case PPC6xx_INPUT_SMI: /* Level sensitive - active high */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__, level); }#endif ppc_set_irq(env, PPC_INTERRUPT_SMI, level); break; case PPC6xx_INPUT_MCP: /* Negative edge sensitive */ /* XXX: TODO: actual reaction may depends on HID0 status * 603/604/740/750: check HID0[EMCP] */ if (cur_level == 1 && level == 0) {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: raise machine check state\n", __func__); }#endif ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); } break; case PPC6xx_INPUT_CKSTP_IN: /* Level sensitive - active low */ /* XXX: TODO: relay the signal to CKSTP_OUT pin */ /* XXX: Note that the only way to restart the CPU is to reset it */ if (level) {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: stop the CPU\n", __func__); }#endif env->halted = 1; } break; case PPC6xx_INPUT_HRESET: /* Level sensitive - active low */ if (level) {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: reset the CPU\n", __func__); }#endif env->interrupt_request |= CPU_INTERRUPT_EXITTB; /* XXX: TOFIX */#if 0 cpu_ppc_reset(env);#else qemu_system_reset_request();#endif } break; case PPC6xx_INPUT_SRESET:#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the RESET IRQ state to %d\n", __func__, level); }#endif ppc_set_irq(env, PPC_INTERRUPT_RESET, level); break; default: /* Unknown pin - do nothing */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin); }#endif return; } if (level) env->irq_input_state |= 1 << pin; else env->irq_input_state &= ~(1 << pin); }}void ppc6xx_irq_init (CPUState *env){ env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, PPC6xx_INPUT_NB);}#if defined(TARGET_PPC64)/* PowerPC 970 internal IRQ controller */static void ppc970_set_irq (void *opaque, int pin, int level){ CPUState *env = opaque; int cur_level;#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: env %p pin %d level %d\n", __func__, env, pin, level); }#endif cur_level = (env->irq_input_state >> pin) & 1; /* Don't generate spurious events */ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { switch (pin) { case PPC970_INPUT_INT: /* Level sensitive - active high */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the external IRQ state to %d\n", __func__, level); }#endif ppc_set_irq(env, PPC_INTERRUPT_EXT, level); break; case PPC970_INPUT_THINT: /* Level sensitive - active high */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__, level); }#endif ppc_set_irq(env, PPC_INTERRUPT_THERM, level); break; case PPC970_INPUT_MCP: /* Negative edge sensitive */ /* XXX: TODO: actual reaction may depends on HID0 status * 603/604/740/750: check HID0[EMCP] */ if (cur_level == 1 && level == 0) {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: raise machine check state\n", __func__); }#endif ppc_set_irq(env, PPC_INTERRUPT_MCK, 1); } break; case PPC970_INPUT_CKSTP: /* Level sensitive - active low */ /* XXX: TODO: relay the signal to CKSTP_OUT pin */ if (level) {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: stop the CPU\n", __func__); }#endif env->halted = 1; } else {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: restart the CPU\n", __func__); }#endif env->halted = 0; } break; case PPC970_INPUT_HRESET: /* Level sensitive - active low */ if (level) {#if 0 // XXX: TOFIX#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: reset the CPU\n", __func__); }#endif cpu_reset(env);#endif } break; case PPC970_INPUT_SRESET:#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the RESET IRQ state to %d\n", __func__, level); }#endif ppc_set_irq(env, PPC_INTERRUPT_RESET, level); break; case PPC970_INPUT_TBEN:#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the TBEN state to %d\n", __func__, level); }#endif /* XXX: TODO */ break; default: /* Unknown pin - do nothing */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin); }#endif return; } if (level) env->irq_input_state |= 1 << pin; else env->irq_input_state &= ~(1 << pin); }}void ppc970_irq_init (CPUState *env){ env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, PPC970_INPUT_NB);}#endif /* defined(TARGET_PPC64) *//* PowerPC 40x internal IRQ controller */static void ppc40x_set_irq (void *opaque, int pin, int level){ CPUState *env = opaque; int cur_level;#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: env %p pin %d level %d\n", __func__, env, pin, level); }#endif cur_level = (env->irq_input_state >> pin) & 1; /* Don't generate spurious events */ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) { switch (pin) { case PPC40x_INPUT_RESET_SYS: if (level) {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: reset the PowerPC system\n", __func__); }#endif ppc40x_system_reset(env); } break; case PPC40x_INPUT_RESET_CHIP: if (level) {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: reset the PowerPC chip\n", __func__); }#endif ppc40x_chip_reset(env); } break; case PPC40x_INPUT_RESET_CORE: /* XXX: TODO: update DBSR[MRR] */ if (level) {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: reset the PowerPC core\n", __func__); }#endif ppc40x_core_reset(env); } break; case PPC40x_INPUT_CINT: /* Level sensitive - active high */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the critical IRQ state to %d\n", __func__, level); }#endif ppc_set_irq(env, PPC_INTERRUPT_CEXT, level); break; case PPC40x_INPUT_INT: /* Level sensitive - active high */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the external IRQ state to %d\n", __func__, level); }#endif ppc_set_irq(env, PPC_INTERRUPT_EXT, level); break; case PPC40x_INPUT_HALT: /* Level sensitive - active low */ if (level) {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: stop the CPU\n", __func__); }#endif env->halted = 1; } else {#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: restart the CPU\n", __func__); }#endif env->halted = 0; } break; case PPC40x_INPUT_DEBUG: /* Level sensitive - active high */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: set the debug pin state to %d\n", __func__, level); }#endif ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level); break; default: /* Unknown pin - do nothing */#if defined(PPC_DEBUG_IRQ) if (loglevel & CPU_LOG_INT) { fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin); }#endif return; } if (level) env->irq_input_state |= 1 << pin; else env->irq_input_state &= ~(1 << pin); }}void ppc40x_irq_init (CPUState *env){ env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq, env, PPC40x_INPUT_NB);}/*****************************************************************************//* PowerPC time base and decrementer emulation */struct ppc_tb_t { /* Time base management */ int64_t tb_offset; /* Compensation */ int64_t atb_offset; /* Compensation */ uint32_t tb_freq; /* TB frequency */ /* Decrementer management */ uint64_t decr_next; /* Tick for next decr interrupt */ uint32_t decr_freq; /* decrementer frequency */ struct QEMUTimer *decr_timer; /* Hypervisor decrementer management */ uint64_t hdecr_next; /* Tick for next hdecr interrupt */ struct QEMUTimer *hdecr_timer; uint64_t purr_load; uint64_t purr_start; void *opaque;};static always_inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, uint64_t vmclk, int64_t tb_offset){ /* TB time in tb periods */ return muldiv64(vmclk, tb_env->tb_freq, ticks_per_sec) + tb_offset;}uint32_t cpu_ppc_load_tbl (CPUState *env){ ppc_tb_t *tb_env = env->tb_env; uint64_t tb; tb = cpu_ppc_get_tb(tb_env, qemu_get_clock(vm_clock), tb_env->tb_offset);#if defined(PPC_DEBUG_TB) if (loglevel != 0) { fprintf(logfile, "%s: tb %016" PRIx64 "\n", __func__, tb); }#endif return tb & 0xFFFFFFFF;}static always_inline uint32_t _cpu_ppc_load_tbu (CPUState *env){ ppc_tb_t *tb_env = env->tb_env; uint64_t tb;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -