Use lookup_and_goto_tb.
Cleanup and fill in VMStateDescription. -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAl9WkbMdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/fvQf/UvUOipiXP7vafHI1 Qx3NZ3nJHOMRz58eBDLidSkWgQM7+zHjBo1V5CvtM6Ajywpsn4IFe+4SJb7MVAYq 6BSj2VDMq5fCboL52i3xJyBHTE7yqlb4bV3uNSk7dXwf5QQs0sT9PLYp6TuxjSj5 SLicEron3uCc6Y0Z1tX1yKPjl2Lz5PoZ4Z98m6wZhd/pQbbc23+hMlz91fjyVAs2 d9ZDnfxL71XQeTUb5tOLC2OK0rQJDQzzMSAO4Ilnrg/w6k0LGlP/kvYsHI+qya1q Rm+iBRGZQoItzkzkL1sWXP5StF9xLPRK60cET0N7vMnwN6sbpd3fOOWhE9EDtDWB tK0wxQ== =1+dD -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-mb-20200907-2' into staging Use lookup_and_goto_tb. Cleanup and fill in VMStateDescription. # gpg: Signature made Mon 07 Sep 2020 21:01:55 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-mb-20200907-2: configure: Do not set TARGET_ABI32 for microblaze target/microblaze: Put MicroBlazeCPUConfig into DisasContext target/microblaze: Fill in VMStateDescription for cpu target/microblaze: Move mmu parameters to MicroBlazeCPUConfig target/microblaze: Treat pvr_regs as constant target/microblaze: Move pvr regs to MicroBlazeCPUConfig target/microblaze: Reorg MicroBlazeCPUConfig to minimize holes target/microblaze: Split out MicroBlazeCPUConfig target/microblaze: Diagnose invalid insns in delay slots target/microblaze: Use tcg_gen_lookup_and_goto_ptr target/microblaze: Force rtid, rted, rtbd to exit target/microblaze: Handle DISAS_EXIT_NEXT in delay slot target/microblaze: Replace cpustate_changed with DISAS_EXIT_NEXT target/microblaze: Introduce DISAS_EXIT_NEXT, DISAS_EXIT_JUMP target/microblaze: Rename DISAS_UPDATE to DISAS_EXIT target/microblaze: Rename mmu structs target/microblaze: Cleanup mb_cpu_do_interrupt target/microblaze: Renumber D_FLAG Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
00942071a0
1
configure
vendored
1
configure
vendored
@ -7608,7 +7608,6 @@ case "$target_name" in
|
||||
TARGET_SYSTBL_ABI=common
|
||||
mttcg="yes"
|
||||
bflt="yes"
|
||||
echo "TARGET_ABI32=y" >> $config_target_mak
|
||||
;;
|
||||
mips|mipsel)
|
||||
mttcg="yes"
|
||||
|
@ -200,9 +200,9 @@ petalogix_ml605_init(MachineState *machine)
|
||||
}
|
||||
|
||||
/* setup PVR to match kernel settings */
|
||||
cpu->env.pvr.regs[4] = 0xc56b8000;
|
||||
cpu->env.pvr.regs[5] = 0xc56be000;
|
||||
cpu->env.pvr.regs[10] = 0x0e000000; /* virtex 6 */
|
||||
cpu->cfg.pvr_regs[4] = 0xc56b8000;
|
||||
cpu->cfg.pvr_regs[5] = 0xc56be000;
|
||||
cpu->cfg.pvr_regs[10] = 0x0e000000; /* virtex 6 */
|
||||
|
||||
microblaze_load_kernel(cpu, MEMORY_BASEADDR, ram_size,
|
||||
machine->initrd_filename,
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include "cpu.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "fpu/softfloat-helpers.h"
|
||||
|
||||
@ -135,10 +134,6 @@ static void mb_cpu_reset(DeviceState *dev)
|
||||
#else
|
||||
mb_cpu_write_msr(env, 0);
|
||||
mmu_init(&env->mmu);
|
||||
env->mmu.c_mmu = 3;
|
||||
env->mmu.c_mmu_tlb_access = 3;
|
||||
env->mmu.c_mmu_zones = 16;
|
||||
env->mmu.c_addr_mask = MAKE_64BIT_MASK(0, cpu->cfg.addr_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -153,7 +148,6 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
CPUState *cs = CPU(dev);
|
||||
MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(dev);
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
uint8_t version_code = 0;
|
||||
const char *version;
|
||||
int i = 0;
|
||||
@ -173,16 +167,6 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
|
||||
qemu_init_vcpu(cs);
|
||||
|
||||
env->pvr.regs[0] = PVR0_USE_EXC_MASK
|
||||
| PVR0_USE_ICACHE_MASK
|
||||
| PVR0_USE_DCACHE_MASK;
|
||||
env->pvr.regs[2] = PVR2_D_OPB_MASK
|
||||
| PVR2_D_LMB_MASK
|
||||
| PVR2_I_OPB_MASK
|
||||
| PVR2_I_LMB_MASK
|
||||
| PVR2_FPU_EXC_MASK
|
||||
| 0;
|
||||
|
||||
version = cpu->cfg.version ? cpu->cfg.version : DEFAULT_CPU_VERSION;
|
||||
for (i = 0; mb_cpu_lookup[i].name && version; i++) {
|
||||
if (strcmp(mb_cpu_lookup[i].name, version) == 0) {
|
||||
@ -195,46 +179,58 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||
qemu_log("Invalid MicroBlaze version number: %s\n", cpu->cfg.version);
|
||||
}
|
||||
|
||||
env->pvr.regs[0] |= (cpu->cfg.stackprot ? PVR0_SPROT_MASK : 0) |
|
||||
(cpu->cfg.use_fpu ? PVR0_USE_FPU_MASK : 0) |
|
||||
(cpu->cfg.use_hw_mul ? PVR0_USE_HW_MUL_MASK : 0) |
|
||||
(cpu->cfg.use_barrel ? PVR0_USE_BARREL_MASK : 0) |
|
||||
(cpu->cfg.use_div ? PVR0_USE_DIV_MASK : 0) |
|
||||
(cpu->cfg.use_mmu ? PVR0_USE_MMU_MASK : 0) |
|
||||
(cpu->cfg.endi ? PVR0_ENDI_MASK : 0) |
|
||||
(version_code << PVR0_VERSION_SHIFT) |
|
||||
(cpu->cfg.pvr == C_PVR_FULL ? PVR0_PVR_FULL_MASK : 0) |
|
||||
cpu->cfg.pvr_user1;
|
||||
cpu->cfg.pvr_regs[0] =
|
||||
(PVR0_USE_EXC_MASK |
|
||||
PVR0_USE_ICACHE_MASK |
|
||||
PVR0_USE_DCACHE_MASK |
|
||||
(cpu->cfg.stackprot ? PVR0_SPROT_MASK : 0) |
|
||||
(cpu->cfg.use_fpu ? PVR0_USE_FPU_MASK : 0) |
|
||||
(cpu->cfg.use_hw_mul ? PVR0_USE_HW_MUL_MASK : 0) |
|
||||
(cpu->cfg.use_barrel ? PVR0_USE_BARREL_MASK : 0) |
|
||||
(cpu->cfg.use_div ? PVR0_USE_DIV_MASK : 0) |
|
||||
(cpu->cfg.use_mmu ? PVR0_USE_MMU_MASK : 0) |
|
||||
(cpu->cfg.endi ? PVR0_ENDI_MASK : 0) |
|
||||
(version_code << PVR0_VERSION_SHIFT) |
|
||||
(cpu->cfg.pvr == C_PVR_FULL ? PVR0_PVR_FULL_MASK : 0) |
|
||||
cpu->cfg.pvr_user1);
|
||||
|
||||
env->pvr.regs[1] = cpu->cfg.pvr_user2;
|
||||
env->pvr.regs[2] |= (cpu->cfg.use_fpu ? PVR2_USE_FPU_MASK : 0) |
|
||||
(cpu->cfg.use_fpu > 1 ? PVR2_USE_FPU2_MASK : 0) |
|
||||
(cpu->cfg.use_hw_mul ? PVR2_USE_HW_MUL_MASK : 0) |
|
||||
(cpu->cfg.use_hw_mul > 1 ? PVR2_USE_MUL64_MASK : 0) |
|
||||
(cpu->cfg.use_barrel ? PVR2_USE_BARREL_MASK : 0) |
|
||||
(cpu->cfg.use_div ? PVR2_USE_DIV_MASK : 0) |
|
||||
(cpu->cfg.use_msr_instr ? PVR2_USE_MSR_INSTR : 0) |
|
||||
(cpu->cfg.use_pcmp_instr ? PVR2_USE_PCMP_INSTR : 0) |
|
||||
(cpu->cfg.dopb_bus_exception ?
|
||||
PVR2_DOPB_BUS_EXC_MASK : 0) |
|
||||
(cpu->cfg.iopb_bus_exception ?
|
||||
PVR2_IOPB_BUS_EXC_MASK : 0) |
|
||||
(cpu->cfg.div_zero_exception ?
|
||||
PVR2_DIV_ZERO_EXC_MASK : 0) |
|
||||
(cpu->cfg.illegal_opcode_exception ?
|
||||
PVR2_ILL_OPCODE_EXC_MASK : 0) |
|
||||
(cpu->cfg.unaligned_exceptions ?
|
||||
PVR2_UNALIGNED_EXC_MASK : 0) |
|
||||
(cpu->cfg.opcode_0_illegal ?
|
||||
PVR2_OPCODE_0x0_ILL_MASK : 0);
|
||||
cpu->cfg.pvr_regs[1] = cpu->cfg.pvr_user2;
|
||||
|
||||
env->pvr.regs[5] |= cpu->cfg.dcache_writeback ?
|
||||
PVR5_DCACHE_WRITEBACK_MASK : 0;
|
||||
cpu->cfg.pvr_regs[2] =
|
||||
(PVR2_D_OPB_MASK |
|
||||
PVR2_D_LMB_MASK |
|
||||
PVR2_I_OPB_MASK |
|
||||
PVR2_I_LMB_MASK |
|
||||
PVR2_FPU_EXC_MASK |
|
||||
(cpu->cfg.use_fpu ? PVR2_USE_FPU_MASK : 0) |
|
||||
(cpu->cfg.use_fpu > 1 ? PVR2_USE_FPU2_MASK : 0) |
|
||||
(cpu->cfg.use_hw_mul ? PVR2_USE_HW_MUL_MASK : 0) |
|
||||
(cpu->cfg.use_hw_mul > 1 ? PVR2_USE_MUL64_MASK : 0) |
|
||||
(cpu->cfg.use_barrel ? PVR2_USE_BARREL_MASK : 0) |
|
||||
(cpu->cfg.use_div ? PVR2_USE_DIV_MASK : 0) |
|
||||
(cpu->cfg.use_msr_instr ? PVR2_USE_MSR_INSTR : 0) |
|
||||
(cpu->cfg.use_pcmp_instr ? PVR2_USE_PCMP_INSTR : 0) |
|
||||
(cpu->cfg.dopb_bus_exception ? PVR2_DOPB_BUS_EXC_MASK : 0) |
|
||||
(cpu->cfg.iopb_bus_exception ? PVR2_IOPB_BUS_EXC_MASK : 0) |
|
||||
(cpu->cfg.div_zero_exception ? PVR2_DIV_ZERO_EXC_MASK : 0) |
|
||||
(cpu->cfg.illegal_opcode_exception ? PVR2_ILL_OPCODE_EXC_MASK : 0) |
|
||||
(cpu->cfg.unaligned_exceptions ? PVR2_UNALIGNED_EXC_MASK : 0) |
|
||||
(cpu->cfg.opcode_0_illegal ? PVR2_OPCODE_0x0_ILL_MASK : 0));
|
||||
|
||||
env->pvr.regs[10] = 0x0c000000 | /* Default to spartan 3a dsp family. */
|
||||
(cpu->cfg.addr_size - 32) << PVR10_ASIZE_SHIFT;
|
||||
env->pvr.regs[11] = (cpu->cfg.use_mmu ? PVR11_USE_MMU : 0) |
|
||||
16 << 17;
|
||||
cpu->cfg.pvr_regs[5] |=
|
||||
cpu->cfg.dcache_writeback ? PVR5_DCACHE_WRITEBACK_MASK : 0;
|
||||
|
||||
cpu->cfg.pvr_regs[10] =
|
||||
(0x0c000000 | /* Default to spartan 3a dsp family. */
|
||||
(cpu->cfg.addr_size - 32) << PVR10_ASIZE_SHIFT);
|
||||
|
||||
cpu->cfg.pvr_regs[11] = ((cpu->cfg.use_mmu ? PVR11_USE_MMU : 0) |
|
||||
16 << 17);
|
||||
|
||||
cpu->cfg.mmu = 3;
|
||||
cpu->cfg.mmu_tlb_access = 3;
|
||||
cpu->cfg.mmu_zones = 16;
|
||||
cpu->cfg.addr_mask = MAKE_64BIT_MASK(0, cpu->cfg.addr_size);
|
||||
|
||||
mcc->parent_realize(dev, errp);
|
||||
}
|
||||
@ -254,11 +250,6 @@ static void mb_cpu_initfn(Object *obj)
|
||||
#endif
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_mb_cpu = {
|
||||
.name = "cpu",
|
||||
.unmigratable = 1,
|
||||
};
|
||||
|
||||
static Property mb_properties[] = {
|
||||
DEFINE_PROP_UINT32("base-vectors", MicroBlazeCPU, cfg.base_vectors, 0),
|
||||
DEFINE_PROP_BOOL("use-stack-protection", MicroBlazeCPU, cfg.stackprot,
|
||||
@ -338,8 +329,8 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cc->do_transaction_failed = mb_cpu_transaction_failed;
|
||||
cc->get_phys_page_debug = mb_cpu_get_phys_page_debug;
|
||||
#endif
|
||||
dc->vmsd = &vmstate_mb_cpu;
|
||||
#endif
|
||||
device_class_set_props(dc, mb_properties);
|
||||
cc->gdb_num_core_regs = 32 + 27;
|
||||
|
||||
|
@ -264,10 +264,10 @@ struct CPUMBState {
|
||||
/* MSR_UM (1 << 11) */
|
||||
/* MSR_VM (1 << 13) */
|
||||
/* ESR_ESS_MASK [11:5] -- unwind into iflags for unaligned excp */
|
||||
#define D_FLAG (1 << 12) /* Bit in ESR. */
|
||||
#define DRTI_FLAG (1 << 16)
|
||||
#define DRTE_FLAG (1 << 17)
|
||||
#define DRTB_FLAG (1 << 18)
|
||||
#define D_FLAG (1 << 19) /* Bit in ESR. */
|
||||
|
||||
/* TB dependent CPUMBState. */
|
||||
#define IFLAGS_TB_MASK (D_FLAG | BIMM_FLAG | IMM_FLAG | \
|
||||
@ -278,19 +278,54 @@ struct CPUMBState {
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* Unified MMU. */
|
||||
struct microblaze_mmu mmu;
|
||||
MicroBlazeMMU mmu;
|
||||
#endif
|
||||
|
||||
/* Fields up to this point are cleared by a CPU reset */
|
||||
struct {} end_reset_fields;
|
||||
|
||||
/* These fields are preserved on reset. */
|
||||
|
||||
struct {
|
||||
uint32_t regs[13];
|
||||
} pvr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Microblaze Configuration Settings
|
||||
*
|
||||
* Note that the structure is sorted by type and size to minimize holes.
|
||||
*/
|
||||
typedef struct {
|
||||
char *version;
|
||||
|
||||
uint64_t addr_mask;
|
||||
|
||||
uint32_t base_vectors;
|
||||
uint32_t pvr_user2;
|
||||
uint32_t pvr_regs[13];
|
||||
|
||||
uint8_t addr_size;
|
||||
uint8_t use_fpu;
|
||||
uint8_t use_hw_mul;
|
||||
uint8_t pvr_user1;
|
||||
uint8_t pvr;
|
||||
uint8_t mmu;
|
||||
uint8_t mmu_tlb_access;
|
||||
uint8_t mmu_zones;
|
||||
|
||||
bool stackprot;
|
||||
bool use_barrel;
|
||||
bool use_div;
|
||||
bool use_msr_instr;
|
||||
bool use_pcmp_instr;
|
||||
bool use_mmu;
|
||||
bool dcache_writeback;
|
||||
bool endi;
|
||||
bool dopb_bus_exception;
|
||||
bool iopb_bus_exception;
|
||||
bool illegal_opcode_exception;
|
||||
bool opcode_0_illegal;
|
||||
bool div_zero_exception;
|
||||
bool unaligned_exceptions;
|
||||
} MicroBlazeCPUConfig;
|
||||
|
||||
/**
|
||||
* MicroBlazeCPU:
|
||||
* @env: #CPUMBState
|
||||
@ -305,32 +340,7 @@ struct MicroBlazeCPU {
|
||||
|
||||
CPUNegativeOffsetState neg;
|
||||
CPUMBState env;
|
||||
|
||||
/* Microblaze Configuration Settings */
|
||||
struct {
|
||||
bool stackprot;
|
||||
uint32_t base_vectors;
|
||||
uint8_t addr_size;
|
||||
uint8_t use_fpu;
|
||||
uint8_t use_hw_mul;
|
||||
bool use_barrel;
|
||||
bool use_div;
|
||||
bool use_msr_instr;
|
||||
bool use_pcmp_instr;
|
||||
bool use_mmu;
|
||||
bool dcache_writeback;
|
||||
bool endi;
|
||||
bool dopb_bus_exception;
|
||||
bool iopb_bus_exception;
|
||||
bool illegal_opcode_exception;
|
||||
bool opcode_0_illegal;
|
||||
bool div_zero_exception;
|
||||
bool unaligned_exceptions;
|
||||
uint8_t pvr_user1;
|
||||
uint32_t pvr_user2;
|
||||
char *version;
|
||||
uint8_t pvr;
|
||||
} cfg;
|
||||
MicroBlazeCPUConfig cfg;
|
||||
};
|
||||
|
||||
|
||||
@ -419,4 +429,8 @@ static inline int cpu_mmu_index(CPUMBState *env, bool ifetch)
|
||||
return MMU_KERNEL_IDX;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
extern const VMStateDescription vmstate_mb_cpu;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -78,7 +78,7 @@ int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||
break;
|
||||
case GDB_PVR0 ... GDB_PVR11:
|
||||
/* PVR12 is intentionally skipped */
|
||||
val = env->pvr.regs[n - GDB_PVR0];
|
||||
val = cpu->cfg.pvr_regs[n - GDB_PVR0];
|
||||
break;
|
||||
case GDB_EDR:
|
||||
val = env->edr;
|
||||
@ -132,10 +132,6 @@ int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||
case GDB_BTR:
|
||||
env->btr = tmp;
|
||||
break;
|
||||
case GDB_PVR0 ... GDB_PVR11:
|
||||
/* PVR12 is intentionally skipped */
|
||||
env->pvr.regs[n - GDB_PVR0] = tmp;
|
||||
break;
|
||||
case GDB_EDR:
|
||||
env->edr = tmp;
|
||||
break;
|
||||
|
@ -52,7 +52,7 @@ bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
{
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
struct microblaze_mmu_lookup lu;
|
||||
MicroBlazeMMULookup lu;
|
||||
unsigned int hit;
|
||||
int prot;
|
||||
|
||||
@ -64,7 +64,7 @@ bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
return true;
|
||||
}
|
||||
|
||||
hit = mmu_translate(&env->mmu, &lu, address, access_type, mmu_idx);
|
||||
hit = mmu_translate(cpu, &lu, address, access_type, mmu_idx);
|
||||
if (likely(hit)) {
|
||||
uint32_t vaddr = address & TARGET_PAGE_MASK;
|
||||
uint32_t paddr = lu.paddr + vaddr - lu.vaddr;
|
||||
@ -111,6 +111,7 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
uint32_t t, msr = mb_cpu_read_msr(env);
|
||||
bool set_esr;
|
||||
|
||||
/* IMM flag cannot propagate across a branch and into the dslot. */
|
||||
assert((env->iflags & (D_FLAG | IMM_FLAG)) != (D_FLAG | IMM_FLAG));
|
||||
@ -118,142 +119,114 @@ void mb_cpu_do_interrupt(CPUState *cs)
|
||||
assert((env->iflags & (D_FLAG | BIMM_FLAG)) != BIMM_FLAG);
|
||||
/* RTI flags are private to translate. */
|
||||
assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
|
||||
env->res_addr = RES_ADDR_NONE;
|
||||
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_HW_EXCP:
|
||||
if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Exception raised on system without exceptions!\n");
|
||||
return;
|
||||
}
|
||||
case EXCP_HW_EXCP:
|
||||
if (!(cpu->cfg.pvr_regs[0] & PVR0_USE_EXC_MASK)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Exception raised on system without exceptions!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
env->regs[17] = env->pc + 4;
|
||||
env->esr &= ~(1 << 12);
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"INT: HWE at pc=%08x msr=%08x iflags=%x\n",
|
||||
env->pc, msr, env->iflags);
|
||||
|
||||
/* Exception breaks branch + dslot sequence? */
|
||||
if (env->iflags & D_FLAG) {
|
||||
env->esr |= 1 << 12 ;
|
||||
env->btr = env->btarget;
|
||||
}
|
||||
/* Exception breaks branch + dslot sequence? */
|
||||
set_esr = true;
|
||||
env->esr &= ~D_FLAG;
|
||||
if (env->iflags & D_FLAG) {
|
||||
env->esr |= D_FLAG;
|
||||
env->btr = env->btarget;
|
||||
}
|
||||
|
||||
/* Disable the MMU. */
|
||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
msr |= t;
|
||||
/* Exception in progress. */
|
||||
msr |= MSR_EIP;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
/* Exception in progress. */
|
||||
msr |= MSR_EIP;
|
||||
env->regs[17] = env->pc + 4;
|
||||
env->pc = cpu->cfg.base_vectors + 0x20;
|
||||
break;
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"hw exception at pc=%x ear=%" PRIx64 " "
|
||||
"esr=%x iflags=%x\n",
|
||||
env->pc, env->ear,
|
||||
env->esr, env->iflags);
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
env->iflags = 0;
|
||||
env->pc = cpu->cfg.base_vectors + 0x20;
|
||||
break;
|
||||
case EXCP_MMU:
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"INT: MMU at pc=%08x msr=%08x "
|
||||
"ear=%" PRIx64 " iflags=%x\n",
|
||||
env->pc, msr, env->ear, env->iflags);
|
||||
|
||||
case EXCP_MMU:
|
||||
/* Exception breaks branch + dslot sequence? */
|
||||
set_esr = true;
|
||||
env->esr &= ~D_FLAG;
|
||||
if (env->iflags & D_FLAG) {
|
||||
env->esr |= D_FLAG;
|
||||
env->btr = env->btarget;
|
||||
/* Reexecute the branch. */
|
||||
env->regs[17] = env->pc - (env->iflags & BIMM_FLAG ? 8 : 4);
|
||||
} else if (env->iflags & IMM_FLAG) {
|
||||
/* Reexecute the imm. */
|
||||
env->regs[17] = env->pc - 4;
|
||||
} else {
|
||||
env->regs[17] = env->pc;
|
||||
}
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"MMU exception at pc=%x iflags=%x ear=%" PRIx64 "\n",
|
||||
env->pc, env->iflags, env->ear);
|
||||
/* Exception in progress. */
|
||||
msr |= MSR_EIP;
|
||||
env->pc = cpu->cfg.base_vectors + 0x20;
|
||||
break;
|
||||
|
||||
env->esr &= ~(1 << 12);
|
||||
/* Exception breaks branch + dslot sequence? */
|
||||
if (env->iflags & D_FLAG) {
|
||||
env->esr |= 1 << 12 ;
|
||||
env->btr = env->btarget;
|
||||
case EXCP_IRQ:
|
||||
assert(!(msr & (MSR_EIP | MSR_BIP)));
|
||||
assert(msr & MSR_IE);
|
||||
assert(!(env->iflags & (D_FLAG | IMM_FLAG)));
|
||||
|
||||
/* Reexecute the branch. */
|
||||
env->regs[17] -= 4;
|
||||
/* was the branch immprefixed?. */
|
||||
if (env->iflags & BIMM_FLAG) {
|
||||
env->regs[17] -= 4;
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
}
|
||||
} else if (env->iflags & IMM_FLAG) {
|
||||
env->regs[17] -= 4;
|
||||
}
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"INT: DEV at pc=%08x msr=%08x iflags=%x\n",
|
||||
env->pc, msr, env->iflags);
|
||||
set_esr = false;
|
||||
|
||||
/* Disable the MMU. */
|
||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
msr |= t;
|
||||
/* Exception in progress. */
|
||||
msr |= MSR_EIP;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
/* Disable interrupts. */
|
||||
msr &= ~MSR_IE;
|
||||
env->regs[14] = env->pc;
|
||||
env->pc = cpu->cfg.base_vectors + 0x10;
|
||||
break;
|
||||
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"exception at pc=%x ear=%" PRIx64 " iflags=%x\n",
|
||||
env->pc, env->ear, env->iflags);
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
env->iflags = 0;
|
||||
env->pc = cpu->cfg.base_vectors + 0x20;
|
||||
break;
|
||||
case EXCP_HW_BREAK:
|
||||
assert(!(env->iflags & (D_FLAG | IMM_FLAG)));
|
||||
|
||||
case EXCP_IRQ:
|
||||
assert(!(msr & (MSR_EIP | MSR_BIP)));
|
||||
assert(msr & MSR_IE);
|
||||
assert(!(env->iflags & (D_FLAG | IMM_FLAG)));
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"INT: BRK at pc=%08x msr=%08x iflags=%x\n",
|
||||
env->pc, msr, env->iflags);
|
||||
set_esr = false;
|
||||
|
||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||
/* Break in progress. */
|
||||
msr |= MSR_BIP;
|
||||
env->regs[16] = env->pc;
|
||||
env->pc = cpu->cfg.base_vectors + 0x18;
|
||||
break;
|
||||
|
||||
#if 0
|
||||
#include "disas/disas.h"
|
||||
default:
|
||||
cpu_abort(cs, "unhandled exception type=%d\n", cs->exception_index);
|
||||
/* not reached */
|
||||
}
|
||||
|
||||
/* Useful instrumentation when debugging interrupt issues in either
|
||||
the models or in sw. */
|
||||
{
|
||||
const char *sym;
|
||||
/* Save previous mode, disable mmu, disable user-mode. */
|
||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
msr |= t;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
|
||||
sym = lookup_symbol(env->pc);
|
||||
if (sym
|
||||
&& (!strcmp("netif_rx", sym)
|
||||
|| !strcmp("process_backlog", sym))) {
|
||||
env->res_addr = RES_ADDR_NONE;
|
||||
env->iflags = 0;
|
||||
|
||||
qemu_log("interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n",
|
||||
env->pc, msr, t, env->iflags, sym);
|
||||
|
||||
log_cpu_state(cs, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"interrupt at pc=%x msr=%x %x iflags=%x\n",
|
||||
env->pc, msr, t, env->iflags);
|
||||
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM | MSR_IE);
|
||||
msr |= t;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
|
||||
env->regs[14] = env->pc;
|
||||
env->iflags = 0;
|
||||
env->pc = cpu->cfg.base_vectors + 0x10;
|
||||
//log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
break;
|
||||
|
||||
case EXCP_HW_BREAK:
|
||||
assert(!(env->iflags & (D_FLAG | IMM_FLAG)));
|
||||
|
||||
t = (msr & (MSR_VM | MSR_UM)) << 1;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
"break at pc=%x msr=%x %x iflags=%x\n",
|
||||
env->pc, msr, t, env->iflags);
|
||||
log_cpu_state_mask(CPU_LOG_INT, cs, 0);
|
||||
msr &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
|
||||
msr |= t;
|
||||
msr |= MSR_BIP;
|
||||
env->regs[16] = env->pc;
|
||||
env->iflags = 0;
|
||||
env->pc = cpu->cfg.base_vectors + 0x18;
|
||||
mb_cpu_write_msr(env, msr);
|
||||
break;
|
||||
default:
|
||||
cpu_abort(cs, "unhandled exception type=%d\n",
|
||||
cs->exception_index);
|
||||
break;
|
||||
if (!set_esr) {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
" to pc=%08x msr=%08x\n", env->pc, msr);
|
||||
} else if (env->esr & D_FLAG) {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
" to pc=%08x msr=%08x esr=%04x btr=%08x\n",
|
||||
env->pc, msr, env->esr, env->btr);
|
||||
} else {
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
" to pc=%08x msr=%08x esr=%04x\n",
|
||||
env->pc, msr, env->esr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,12 +235,12 @@ hwaddr mb_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
CPUMBState *env = &cpu->env;
|
||||
target_ulong vaddr, paddr = 0;
|
||||
struct microblaze_mmu_lookup lu;
|
||||
MicroBlazeMMULookup lu;
|
||||
int mmu_idx = cpu_mmu_index(env, false);
|
||||
unsigned int hit;
|
||||
|
||||
if (mmu_idx != MMU_NOMMU_IDX) {
|
||||
hit = mmu_translate(&env->mmu, &lu, addr, 0, 0);
|
||||
hit = mmu_translate(cpu, &lu, addr, 0, 0);
|
||||
if (hit) {
|
||||
vaddr = addr & TARGET_PAGE_MASK;
|
||||
paddr = lu.paddr + vaddr - lu.vaddr;
|
||||
|
106
target/microblaze/machine.c
Normal file
106
target/microblaze/machine.c
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Microblaze VMState for qemu.
|
||||
*
|
||||
* Copyright (c) 2020 Linaro, Ltd.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "migration/cpu.h"
|
||||
|
||||
|
||||
static VMStateField vmstate_mmu_fields[] = {
|
||||
VMSTATE_UINT64_2DARRAY(rams, MicroBlazeMMU, 2, TLB_ENTRIES),
|
||||
VMSTATE_UINT8_ARRAY(tids, MicroBlazeMMU, TLB_ENTRIES),
|
||||
VMSTATE_UINT32_ARRAY(regs, MicroBlazeMMU, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_mmu = {
|
||||
.name = "mmu",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = vmstate_mmu_fields,
|
||||
};
|
||||
|
||||
static int get_msr(QEMUFile *f, void *opaque, size_t size,
|
||||
const VMStateField *field)
|
||||
{
|
||||
CPUMBState *env = container_of(opaque, CPUMBState, msr);
|
||||
|
||||
mb_cpu_write_msr(env, qemu_get_be32(f));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int put_msr(QEMUFile *f, void *opaque, size_t size,
|
||||
const VMStateField *field, QJSON *vmdesc)
|
||||
{
|
||||
CPUMBState *env = container_of(opaque, CPUMBState, msr);
|
||||
|
||||
qemu_put_be32(f, mb_cpu_read_msr(env));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateInfo vmstate_msr = {
|
||||
.name = "msr",
|
||||
.get = get_msr,
|
||||
.put = put_msr,
|
||||
};
|
||||
|
||||
static VMStateField vmstate_env_fields[] = {
|
||||
VMSTATE_UINT32_ARRAY(regs, CPUMBState, 32),
|
||||
|
||||
VMSTATE_UINT32(pc, CPUMBState),
|
||||
VMSTATE_SINGLE(msr, CPUMBState, 0, vmstate_msr, uint32_t),
|
||||
VMSTATE_UINT32(esr, CPUMBState),
|
||||
VMSTATE_UINT32(fsr, CPUMBState),
|
||||
VMSTATE_UINT32(btr, CPUMBState),
|
||||
VMSTATE_UINT32(edr, CPUMBState),
|
||||
VMSTATE_UINT32(slr, CPUMBState),
|
||||
VMSTATE_UINT32(shr, CPUMBState),
|
||||
VMSTATE_UINT64(ear, CPUMBState),
|
||||
|
||||
VMSTATE_UINT32(btarget, CPUMBState),
|
||||
VMSTATE_UINT32(imm, CPUMBState),
|
||||
VMSTATE_UINT32(iflags, CPUMBState),
|
||||
|
||||
VMSTATE_UINT32(res_val, CPUMBState),
|
||||
VMSTATE_UINTTL(res_addr, CPUMBState),
|
||||
|
||||
VMSTATE_STRUCT(mmu, CPUMBState, 0, vmstate_mmu, MicroBlazeMMU),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_env = {
|
||||
.name = "env",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = vmstate_env_fields,
|
||||
};
|
||||
|
||||
static VMStateField vmstate_cpu_fields[] = {
|
||||
VMSTATE_CPU(),
|
||||
VMSTATE_STRUCT(env, MicroBlazeCPU, 1, vmstate_env, CPUMBState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
};
|
||||
|
||||
const VMStateDescription vmstate_mb_cpu = {
|
||||
.name = "cpu",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = vmstate_cpu_fields,
|
||||
};
|
@ -11,7 +11,10 @@ microblaze_ss.add(files(
|
||||
))
|
||||
|
||||
microblaze_softmmu_ss = ss.source_set()
|
||||
microblaze_softmmu_ss.add(files('mmu.c'))
|
||||
microblaze_softmmu_ss.add(files(
|
||||
'mmu.c',
|
||||
'machine.c',
|
||||
))
|
||||
|
||||
target_arch += {'microblaze': microblaze_ss}
|
||||
target_softmmu_arch += {'microblaze': microblaze_softmmu_ss}
|
||||
|
@ -35,7 +35,7 @@ static unsigned int tlb_decode_size(unsigned int f)
|
||||
static void mmu_flush_idx(CPUMBState *env, unsigned int idx)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
struct microblaze_mmu *mmu = &env->mmu;
|
||||
MicroBlazeMMU *mmu = &env->mmu;
|
||||
unsigned int tlb_size;
|
||||
uint32_t tlb_tag, end, t;
|
||||
|
||||
@ -55,7 +55,7 @@ static void mmu_flush_idx(CPUMBState *env, unsigned int idx)
|
||||
|
||||
static void mmu_change_pid(CPUMBState *env, unsigned int newpid)
|
||||
{
|
||||
struct microblaze_mmu *mmu = &env->mmu;
|
||||
MicroBlazeMMU *mmu = &env->mmu;
|
||||
unsigned int i;
|
||||
uint32_t t;
|
||||
|
||||
@ -73,10 +73,10 @@ static void mmu_change_pid(CPUMBState *env, unsigned int newpid)
|
||||
}
|
||||
|
||||
/* rw - 0 = read, 1 = write, 2 = fetch. */
|
||||
unsigned int mmu_translate(struct microblaze_mmu *mmu,
|
||||
struct microblaze_mmu_lookup *lu,
|
||||
unsigned int mmu_translate(MicroBlazeCPU *cpu, MicroBlazeMMULookup *lu,
|
||||
target_ulong vaddr, int rw, int mmu_idx)
|
||||
{
|
||||
MicroBlazeMMU *mmu = &cpu->env.mmu;
|
||||
unsigned int i, hit = 0;
|
||||
unsigned int tlb_ex = 0, tlb_wr = 0, tlb_zsel;
|
||||
uint64_t tlb_tag, tlb_rpn, mask;
|
||||
@ -115,13 +115,13 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
|
||||
t0 = mmu->regs[MMU_R_ZPR] >> (30 - (tlb_zsel * 2));
|
||||
t0 &= 0x3;
|
||||
|
||||
if (tlb_zsel > mmu->c_mmu_zones) {
|
||||
if (tlb_zsel > cpu->cfg.mmu_zones) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"tlb zone select out of range! %d\n", tlb_zsel);
|
||||
t0 = 1; /* Ignore. */
|
||||
}
|
||||
|
||||
if (mmu->c_mmu == 1) {
|
||||
if (cpu->cfg.mmu == 1) {
|
||||
t0 = 1; /* Zones are disabled. */
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ unsigned int mmu_translate(struct microblaze_mmu *mmu,
|
||||
tlb_rpn = d & TLB_RPN_MASK;
|
||||
|
||||
lu->vaddr = tlb_tag;
|
||||
lu->paddr = tlb_rpn & mmu->c_addr_mask;
|
||||
lu->paddr = tlb_rpn & cpu->cfg.addr_mask;
|
||||
lu->size = tlb_size;
|
||||
lu->err = ERR_HIT;
|
||||
lu->idx = i;
|
||||
@ -176,10 +176,11 @@ done:
|
||||
/* Writes/reads to the MMU's special regs end up here. */
|
||||
uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn)
|
||||
{
|
||||
MicroBlazeCPU *cpu = env_archcpu(env);
|
||||
unsigned int i;
|
||||
uint32_t r = 0;
|
||||
|
||||
if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) {
|
||||
if (cpu->cfg.mmu < 2 || !cpu->cfg.mmu_tlb_access) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "MMU access on MMU-less system\n");
|
||||
return 0;
|
||||
}
|
||||
@ -192,7 +193,7 @@ uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn)
|
||||
/* Reads to HI/LO trig reads from the mmu rams. */
|
||||
case MMU_R_TLBLO:
|
||||
case MMU_R_TLBHI:
|
||||
if (!(env->mmu.c_mmu_tlb_access & 1)) {
|
||||
if (!(cpu->cfg.mmu_tlb_access & 1)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return 0;
|
||||
@ -205,7 +206,7 @@ uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn)
|
||||
break;
|
||||
case MMU_R_PID:
|
||||
case MMU_R_ZPR:
|
||||
if (!(env->mmu.c_mmu_tlb_access & 1)) {
|
||||
if (!(cpu->cfg.mmu_tlb_access & 1)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return 0;
|
||||
@ -228,12 +229,14 @@ uint32_t mmu_read(CPUMBState *env, bool ext, uint32_t rn)
|
||||
|
||||
void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v)
|
||||
{
|
||||
MicroBlazeCPU *cpu = env_archcpu(env);
|
||||
uint64_t tmp64;
|
||||
unsigned int i;
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn]);
|
||||
|
||||
if (env->mmu.c_mmu < 2 || !env->mmu.c_mmu_tlb_access) {
|
||||
if (cpu->cfg.mmu < 2 || !cpu->cfg.mmu_tlb_access) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "MMU access on MMU-less system\n");
|
||||
return;
|
||||
}
|
||||
@ -259,7 +262,7 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v)
|
||||
env->mmu.rams[rn & 1][i] = deposit64(tmp64, ext * 32, 32, v);
|
||||
break;
|
||||
case MMU_R_ZPR:
|
||||
if (env->mmu.c_mmu_tlb_access <= 1) {
|
||||
if (cpu->cfg.mmu_tlb_access <= 1) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return;
|
||||
@ -273,7 +276,7 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v)
|
||||
env->mmu.regs[rn] = v;
|
||||
break;
|
||||
case MMU_R_PID:
|
||||
if (env->mmu.c_mmu_tlb_access <= 1) {
|
||||
if (cpu->cfg.mmu_tlb_access <= 1) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return;
|
||||
@ -290,17 +293,17 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v)
|
||||
break;
|
||||
case MMU_R_TLBSX:
|
||||
{
|
||||
struct microblaze_mmu_lookup lu;
|
||||
MicroBlazeMMULookup lu;
|
||||
int hit;
|
||||
|
||||
if (env->mmu.c_mmu_tlb_access <= 1) {
|
||||
if (cpu->cfg.mmu_tlb_access <= 1) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid access to MMU reg %d\n", rn);
|
||||
return;
|
||||
}
|
||||
|
||||
hit = mmu_translate(&env->mmu, &lu,
|
||||
v & TLB_EPN_MASK, 0, cpu_mmu_index(env, false));
|
||||
hit = mmu_translate(cpu, &lu, v & TLB_EPN_MASK,
|
||||
0, cpu_mmu_index(env, false));
|
||||
if (hit) {
|
||||
env->mmu.regs[MMU_R_TLBX] = lu.idx;
|
||||
} else {
|
||||
@ -314,7 +317,7 @@ void mmu_write(CPUMBState *env, bool ext, uint32_t rn, uint32_t v)
|
||||
}
|
||||
}
|
||||
|
||||
void mmu_init(struct microblaze_mmu *mmu)
|
||||
void mmu_init(MicroBlazeMMU *mmu)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(mmu->regs); i++) {
|
||||
|
@ -63,23 +63,16 @@
|
||||
|
||||
#define TLB_ENTRIES 64
|
||||
|
||||
struct microblaze_mmu
|
||||
{
|
||||
typedef struct {
|
||||
/* Data and tag brams. */
|
||||
uint64_t rams[2][TLB_ENTRIES];
|
||||
/* We keep a separate ram for the tids to avoid the 48 bit tag width. */
|
||||
uint8_t tids[TLB_ENTRIES];
|
||||
/* Control flops. */
|
||||
uint32_t regs[3];
|
||||
} MicroBlazeMMU;
|
||||
|
||||
int c_mmu;
|
||||
int c_mmu_tlb_access;
|
||||
int c_mmu_zones;
|
||||
uint64_t c_addr_mask; /* Mask to apply to physical addresses. */
|
||||
};
|
||||
|
||||
struct microblaze_mmu_lookup
|
||||
{
|
||||
typedef struct {
|
||||
uint32_t paddr;
|
||||
uint32_t vaddr;
|
||||
unsigned int size;
|
||||
@ -88,13 +81,12 @@ struct microblaze_mmu_lookup
|
||||
enum {
|
||||
ERR_PROT, ERR_MISS, ERR_HIT
|
||||
} err;
|
||||
};
|
||||
} MicroBlazeMMULookup;
|
||||
|
||||
unsigned int mmu_translate(struct microblaze_mmu *mmu,
|
||||
struct microblaze_mmu_lookup *lu,
|
||||
unsigned int mmu_translate(MicroBlazeCPU *cpu, MicroBlazeMMULookup *lu,
|
||||
target_ulong vaddr, int rw, int mmu_idx);
|
||||
uint32_t mmu_read(CPUMBState *env, bool ea, uint32_t rn);
|
||||
void mmu_write(CPUMBState *env, bool ea, uint32_t rn, uint32_t v);
|
||||
void mmu_init(struct microblaze_mmu *mmu);
|
||||
void mmu_init(MicroBlazeMMU *mmu);
|
||||
|
||||
#endif
|
||||
|
@ -134,7 +134,7 @@ static void update_fpu_flags(CPUMBState *env, int flags, uintptr_t ra)
|
||||
raise = 1;
|
||||
}
|
||||
if (raise
|
||||
&& (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
|
||||
&& (env_archcpu(env)->cfg.pvr_regs[2] & PVR2_FPU_EXC_MASK)
|
||||
&& (env->msr & MSR_EE)) {
|
||||
raise_fpu_exception(env, ra);
|
||||
}
|
||||
|
@ -37,7 +37,12 @@
|
||||
|
||||
/* is_jmp field values */
|
||||
#define DISAS_JUMP DISAS_TARGET_0 /* only pc was modified dynamically */
|
||||
#define DISAS_UPDATE DISAS_TARGET_1 /* cpu state was modified dynamically */
|
||||
#define DISAS_EXIT DISAS_TARGET_1 /* all cpu state modified dynamically */
|
||||
|
||||
/* cpu state besides pc was modified dynamically; update pc to next */
|
||||
#define DISAS_EXIT_NEXT DISAS_TARGET_2
|
||||
/* cpu state besides pc was modified dynamically; update pc to btarget */
|
||||
#define DISAS_EXIT_JUMP DISAS_TARGET_3
|
||||
|
||||
static TCGv_i32 cpu_R[32];
|
||||
static TCGv_i32 cpu_pc;
|
||||
@ -55,7 +60,7 @@ static TCGv_i32 cpu_res_val;
|
||||
/* This is the state at translation time. */
|
||||
typedef struct DisasContext {
|
||||
DisasContextBase base;
|
||||
MicroBlazeCPU *cpu;
|
||||
const MicroBlazeCPUConfig *cfg;
|
||||
|
||||
/* TCG op of the current insn_start. */
|
||||
TCGOp *insn_start;
|
||||
@ -65,7 +70,6 @@ typedef struct DisasContext {
|
||||
|
||||
/* Decoder. */
|
||||
uint32_t ext_imm;
|
||||
unsigned int cpustate_changed;
|
||||
unsigned int tb_flags;
|
||||
unsigned int tb_flags_to_set;
|
||||
int mem_index;
|
||||
@ -143,7 +147,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
|
||||
tcg_gen_exit_tb(dc->base.tb, n);
|
||||
} else {
|
||||
tcg_gen_movi_i32(cpu_pc, dest);
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
dc->base.is_jmp = DISAS_NORETURN;
|
||||
}
|
||||
@ -155,7 +159,7 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
|
||||
static bool trap_illegal(DisasContext *dc, bool cond)
|
||||
{
|
||||
if (cond && (dc->tb_flags & MSR_EE)
|
||||
&& dc->cpu->cfg.illegal_opcode_exception) {
|
||||
&& dc->cfg->illegal_opcode_exception) {
|
||||
gen_raise_hw_excp(dc, ESR_EC_ILLEGAL_OP);
|
||||
}
|
||||
return cond;
|
||||
@ -175,6 +179,21 @@ static bool trap_userspace(DisasContext *dc, bool cond)
|
||||
return cond_user;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true, and log an error, if the current insn is
|
||||
* within a delay slot.
|
||||
*/
|
||||
static bool invalid_delay_slot(DisasContext *dc, const char *insn_type)
|
||||
{
|
||||
if (dc->tb_flags & D_FLAG) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"Invalid insn in delay slot: %s at %08x\n",
|
||||
insn_type, (uint32_t)dc->base.pc_next);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static TCGv_i32 reg_for_read(DisasContext *dc, int reg)
|
||||
{
|
||||
if (likely(reg != 0)) {
|
||||
@ -272,7 +291,7 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
|
||||
|
||||
#define DO_TYPEA_CFG(NAME, CFG, SE, FN) \
|
||||
static bool trans_##NAME(DisasContext *dc, arg_typea *a) \
|
||||
{ return dc->cpu->cfg.CFG && do_typea(dc, a, SE, FN); }
|
||||
{ return dc->cfg->CFG && do_typea(dc, a, SE, FN); }
|
||||
|
||||
#define DO_TYPEA0(NAME, SE, FN) \
|
||||
static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
|
||||
@ -280,7 +299,7 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
|
||||
|
||||
#define DO_TYPEA0_CFG(NAME, CFG, SE, FN) \
|
||||
static bool trans_##NAME(DisasContext *dc, arg_typea0 *a) \
|
||||
{ return dc->cpu->cfg.CFG && do_typea0(dc, a, SE, FN); }
|
||||
{ return dc->cfg->CFG && do_typea0(dc, a, SE, FN); }
|
||||
|
||||
#define DO_TYPEBI(NAME, SE, FNI) \
|
||||
static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
|
||||
@ -288,7 +307,7 @@ static bool do_typeb_val(DisasContext *dc, arg_typeb *arg, bool side_effects,
|
||||
|
||||
#define DO_TYPEBI_CFG(NAME, CFG, SE, FNI) \
|
||||
static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
|
||||
{ return dc->cpu->cfg.CFG && do_typeb_imm(dc, a, SE, FNI); }
|
||||
{ return dc->cfg->CFG && do_typeb_imm(dc, a, SE, FNI); }
|
||||
|
||||
#define DO_TYPEBV(NAME, SE, FN) \
|
||||
static bool trans_##NAME(DisasContext *dc, arg_typeb *a) \
|
||||
@ -496,6 +515,9 @@ DO_TYPEA_CFG(idivu, use_div, true, gen_idivu)
|
||||
|
||||
static bool trans_imm(DisasContext *dc, arg_imm *arg)
|
||||
{
|
||||
if (invalid_delay_slot(dc, "imm")) {
|
||||
return true;
|
||||
}
|
||||
dc->ext_imm = arg->imm << 16;
|
||||
tcg_gen_movi_i32(cpu_imm, dc->ext_imm);
|
||||
dc->tb_flags_to_set = IMM_FLAG;
|
||||
@ -661,7 +683,7 @@ static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb)
|
||||
tcg_gen_movi_tl(ret, 0);
|
||||
}
|
||||
|
||||
if ((ra == 1 || rb == 1) && dc->cpu->cfg.stackprot) {
|
||||
if ((ra == 1 || rb == 1) && dc->cfg->stackprot) {
|
||||
gen_helper_stackprot(cpu_env, ret);
|
||||
}
|
||||
return ret;
|
||||
@ -681,7 +703,7 @@ static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
|
||||
tcg_gen_movi_tl(ret, (uint32_t)imm);
|
||||
}
|
||||
|
||||
if (ra == 1 && dc->cpu->cfg.stackprot) {
|
||||
if (ra == 1 && dc->cfg->stackprot) {
|
||||
gen_helper_stackprot(cpu_env, ret);
|
||||
}
|
||||
return ret;
|
||||
@ -690,7 +712,7 @@ static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm)
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
|
||||
{
|
||||
int addr_size = dc->cpu->cfg.addr_size;
|
||||
int addr_size = dc->cfg->addr_size;
|
||||
TCGv ret = tcg_temp_new();
|
||||
|
||||
if (addr_size == 32 || ra == 0) {
|
||||
@ -750,7 +772,7 @@ static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
|
||||
|
||||
if (size > MO_8 &&
|
||||
(dc->tb_flags & MSR_EE) &&
|
||||
dc->cpu->cfg.unaligned_exceptions) {
|
||||
dc->cfg->unaligned_exceptions) {
|
||||
record_unaligned_ess(dc, rd, size, false);
|
||||
mop |= MO_ALIGN;
|
||||
}
|
||||
@ -896,7 +918,7 @@ static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
|
||||
|
||||
if (size > MO_8 &&
|
||||
(dc->tb_flags & MSR_EE) &&
|
||||
dc->cpu->cfg.unaligned_exceptions) {
|
||||
dc->cfg->unaligned_exceptions) {
|
||||
record_unaligned_ess(dc, rd, size, true);
|
||||
mop |= MO_ALIGN;
|
||||
}
|
||||
@ -1063,6 +1085,9 @@ static bool do_branch(DisasContext *dc, int dest_rb, int dest_imm,
|
||||
{
|
||||
uint32_t add_pc;
|
||||
|
||||
if (invalid_delay_slot(dc, "branch")) {
|
||||
return true;
|
||||
}
|
||||
if (delay) {
|
||||
setup_dslot(dc, dest_rb < 0);
|
||||
}
|
||||
@ -1102,6 +1127,9 @@ static bool do_bcc(DisasContext *dc, int dest_rb, int dest_imm,
|
||||
{
|
||||
TCGv_i32 zero, next;
|
||||
|
||||
if (invalid_delay_slot(dc, "bcc")) {
|
||||
return true;
|
||||
}
|
||||
if (delay) {
|
||||
setup_dslot(dc, dest_rb < 0);
|
||||
}
|
||||
@ -1154,6 +1182,10 @@ static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
|
||||
if (trap_userspace(dc, true)) {
|
||||
return true;
|
||||
}
|
||||
if (invalid_delay_slot(dc, "brk")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
tcg_gen_mov_i32(cpu_pc, reg_for_read(dc, arg->rb));
|
||||
if (arg->rd) {
|
||||
tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
|
||||
@ -1161,7 +1193,7 @@ static bool trans_brk(DisasContext *dc, arg_typea_br *arg)
|
||||
tcg_gen_ori_i32(cpu_msr, cpu_msr, MSR_BIP);
|
||||
tcg_gen_movi_tl(cpu_res_addr, -1);
|
||||
|
||||
dc->base.is_jmp = DISAS_UPDATE;
|
||||
dc->base.is_jmp = DISAS_EXIT;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1172,6 +1204,10 @@ static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
|
||||
if (trap_userspace(dc, imm != 0x8 && imm != 0x18)) {
|
||||
return true;
|
||||
}
|
||||
if (invalid_delay_slot(dc, "brki")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
tcg_gen_movi_i32(cpu_pc, imm);
|
||||
if (arg->rd) {
|
||||
tcg_gen_movi_i32(cpu_R[arg->rd], dc->base.pc_next);
|
||||
@ -1202,7 +1238,7 @@ static bool trans_brki(DisasContext *dc, arg_typeb_br *arg)
|
||||
~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM));
|
||||
}
|
||||
tcg_gen_ori_i32(cpu_msr, cpu_msr, msr_to_set);
|
||||
dc->base.is_jmp = DISAS_UPDATE;
|
||||
dc->base.is_jmp = DISAS_EXIT;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@ -1212,6 +1248,11 @@ static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
|
||||
{
|
||||
int mbar_imm = arg->imm;
|
||||
|
||||
/* Note that mbar is a specialized branch instruction. */
|
||||
if (invalid_delay_slot(dc, "mbar")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Data access memory barrier. */
|
||||
if ((mbar_imm & 2) == 0) {
|
||||
tcg_gen_mb(TCG_BAR_SC | TCG_MO_ALL);
|
||||
@ -1250,7 +1291,7 @@ static bool trans_mbar(DisasContext *dc, arg_mbar *arg)
|
||||
*
|
||||
* Therefore, choose to end the TB always.
|
||||
*/
|
||||
dc->cpustate_changed = 1;
|
||||
dc->base.is_jmp = DISAS_EXIT_NEXT;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1259,6 +1300,10 @@ static bool do_rts(DisasContext *dc, arg_typeb_bc *arg, int to_set)
|
||||
if (trap_userspace(dc, to_set)) {
|
||||
return true;
|
||||
}
|
||||
if (invalid_delay_slot(dc, "rts")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dc->tb_flags_to_set |= to_set;
|
||||
setup_dslot(dc, true);
|
||||
|
||||
@ -1280,7 +1325,7 @@ DO_RTS(rtsd, 0)
|
||||
static bool trans_zero(DisasContext *dc, arg_zero *arg)
|
||||
{
|
||||
/* If opcode_0_illegal, trap. */
|
||||
if (dc->cpu->cfg.opcode_0_illegal) {
|
||||
if (dc->cfg->opcode_0_illegal) {
|
||||
trap_illegal(dc, true);
|
||||
return true;
|
||||
}
|
||||
@ -1302,19 +1347,6 @@ static void msr_read(DisasContext *dc, TCGv_i32 d)
|
||||
tcg_temp_free_i32(t);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static void msr_write(DisasContext *dc, TCGv_i32 v)
|
||||
{
|
||||
dc->cpustate_changed = 1;
|
||||
|
||||
/* Install MSR_C. */
|
||||
tcg_gen_extract_i32(cpu_msr_c, v, 2, 1);
|
||||
|
||||
/* Clear MSR_C and MSR_CC; MSR_PVR is not writable, and is always clear. */
|
||||
tcg_gen_andi_i32(cpu_msr, v, ~(MSR_C | MSR_CC | MSR_PVR));
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
|
||||
{
|
||||
uint32_t imm = arg->imm;
|
||||
@ -1347,7 +1379,7 @@ static bool do_msrclrset(DisasContext *dc, arg_type_msr *arg, bool set)
|
||||
} else {
|
||||
tcg_gen_andi_i32(cpu_msr, cpu_msr, ~imm);
|
||||
}
|
||||
dc->cpustate_changed = 1;
|
||||
dc->base.is_jmp = DISAS_EXIT_NEXT;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1380,7 +1412,13 @@ static bool trans_mts(DisasContext *dc, arg_mts *arg)
|
||||
TCGv_i32 src = reg_for_read(dc, arg->ra);
|
||||
switch (arg->rs) {
|
||||
case SR_MSR:
|
||||
msr_write(dc, src);
|
||||
/* Install MSR_C. */
|
||||
tcg_gen_extract_i32(cpu_msr_c, src, 2, 1);
|
||||
/*
|
||||
* Clear MSR_C and MSR_CC;
|
||||
* MSR_PVR is not writable, and is always clear.
|
||||
*/
|
||||
tcg_gen_andi_i32(cpu_msr, src, ~(MSR_C | MSR_CC | MSR_PVR));
|
||||
break;
|
||||
case SR_FSR:
|
||||
tcg_gen_st_i32(src, cpu_env, offsetof(CPUMBState, fsr));
|
||||
@ -1412,7 +1450,7 @@ static bool trans_mts(DisasContext *dc, arg_mts *arg)
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid mts reg 0x%x\n", arg->rs);
|
||||
return true;
|
||||
}
|
||||
dc->cpustate_changed = 1;
|
||||
dc->base.is_jmp = DISAS_EXIT_NEXT;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
@ -1501,7 +1539,8 @@ static bool trans_mfs(DisasContext *dc, arg_mfs *arg)
|
||||
|
||||
case 0x2000 ... 0x200c:
|
||||
tcg_gen_ld_i32(dest, cpu_env,
|
||||
offsetof(CPUMBState, pvr.regs[arg->rs - 0x2000]));
|
||||
offsetof(MicroBlazeCPU, cfg.pvr_regs[arg->rs - 0x2000])
|
||||
- offsetof(MicroBlazeCPU, env));
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "Invalid mfs reg 0x%x\n", arg->rs);
|
||||
@ -1521,7 +1560,6 @@ static void do_rti(DisasContext *dc)
|
||||
tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
|
||||
|
||||
tcg_temp_free_i32(tmp);
|
||||
dc->tb_flags &= ~DRTI_FLAG;
|
||||
}
|
||||
|
||||
static void do_rtb(DisasContext *dc)
|
||||
@ -1534,7 +1572,6 @@ static void do_rtb(DisasContext *dc)
|
||||
tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
|
||||
|
||||
tcg_temp_free_i32(tmp);
|
||||
dc->tb_flags &= ~DRTB_FLAG;
|
||||
}
|
||||
|
||||
static void do_rte(DisasContext *dc)
|
||||
@ -1548,7 +1585,6 @@ static void do_rte(DisasContext *dc)
|
||||
tcg_gen_or_i32(cpu_msr, cpu_msr, tmp);
|
||||
|
||||
tcg_temp_free_i32(tmp);
|
||||
dc->tb_flags &= ~DRTE_FLAG;
|
||||
}
|
||||
|
||||
/* Insns connected to FSL or AXI stream attached devices. */
|
||||
@ -1622,9 +1658,8 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs)
|
||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||
int bound;
|
||||
|
||||
dc->cpu = cpu;
|
||||
dc->cfg = &cpu->cfg;
|
||||
dc->tb_flags = dc->base.tb->flags;
|
||||
dc->cpustate_changed = 0;
|
||||
dc->ext_imm = dc->base.tb->cs_base;
|
||||
dc->r0 = NULL;
|
||||
dc->r0_set = false;
|
||||
@ -1700,20 +1735,47 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs)
|
||||
dc->base.pc_next += 4;
|
||||
|
||||
if (dc->jmp_cond != TCG_COND_NEVER && !(dc->tb_flags & D_FLAG)) {
|
||||
if (dc->tb_flags & DRTI_FLAG) {
|
||||
do_rti(dc);
|
||||
} else if (dc->tb_flags & DRTB_FLAG) {
|
||||
do_rtb(dc);
|
||||
} else if (dc->tb_flags & DRTE_FLAG) {
|
||||
do_rte(dc);
|
||||
/*
|
||||
* Finish any return-from branch.
|
||||
*/
|
||||
uint32_t rt_ibe = dc->tb_flags & (DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
|
||||
if (unlikely(rt_ibe != 0)) {
|
||||
dc->tb_flags &= ~(DRTI_FLAG | DRTB_FLAG | DRTE_FLAG);
|
||||
if (rt_ibe & DRTI_FLAG) {
|
||||
do_rti(dc);
|
||||
} else if (rt_ibe & DRTB_FLAG) {
|
||||
do_rtb(dc);
|
||||
} else {
|
||||
do_rte(dc);
|
||||
}
|
||||
}
|
||||
dc->base.is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
/* Force an exit if the per-tb cpu state has changed. */
|
||||
if (dc->base.is_jmp == DISAS_NEXT && dc->cpustate_changed) {
|
||||
dc->base.is_jmp = DISAS_UPDATE;
|
||||
tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
|
||||
/* Complete the branch, ending the TB. */
|
||||
switch (dc->base.is_jmp) {
|
||||
case DISAS_NORETURN:
|
||||
/*
|
||||
* E.g. illegal insn in a delay slot. We've already exited
|
||||
* and will handle D_FLAG in mb_cpu_do_interrupt.
|
||||
*/
|
||||
break;
|
||||
case DISAS_NEXT:
|
||||
/*
|
||||
* Normal insn a delay slot.
|
||||
* However, the return-from-exception type insns should
|
||||
* return to the main loop, as they have adjusted MSR.
|
||||
*/
|
||||
dc->base.is_jmp = (rt_ibe ? DISAS_EXIT_JUMP : DISAS_JUMP);
|
||||
break;
|
||||
case DISAS_EXIT_NEXT:
|
||||
/*
|
||||
* E.g. mts insn in a delay slot. Continue with btarget,
|
||||
* but still return to the main loop.
|
||||
*/
|
||||
dc->base.is_jmp = DISAS_EXIT_JUMP;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1733,13 +1795,15 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
|
||||
gen_goto_tb(dc, 0, dc->base.pc_next);
|
||||
return;
|
||||
|
||||
case DISAS_UPDATE:
|
||||
if (unlikely(cs->singlestep_enabled)) {
|
||||
gen_raise_exception(dc, EXCP_DEBUG);
|
||||
} else {
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
}
|
||||
return;
|
||||
case DISAS_EXIT:
|
||||
break;
|
||||
case DISAS_EXIT_NEXT:
|
||||
tcg_gen_movi_i32(cpu_pc, dc->base.pc_next);
|
||||
break;
|
||||
case DISAS_EXIT_JUMP:
|
||||
tcg_gen_mov_i32(cpu_pc, cpu_btarget);
|
||||
tcg_gen_discard_i32(cpu_btarget);
|
||||
break;
|
||||
|
||||
case DISAS_JUMP:
|
||||
if (dc->jmp_dest != -1 && !cs->singlestep_enabled) {
|
||||
@ -1774,13 +1838,20 @@ static void mb_tr_tb_stop(DisasContextBase *dcb, CPUState *cs)
|
||||
if (unlikely(cs->singlestep_enabled)) {
|
||||
gen_raise_exception(dc, EXCP_DEBUG);
|
||||
} else {
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
tcg_gen_lookup_and_goto_ptr();
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
/* Finish DISAS_EXIT_* */
|
||||
if (unlikely(cs->singlestep_enabled)) {
|
||||
gen_raise_exception(dc, EXCP_DEBUG);
|
||||
} else {
|
||||
tcg_gen_exit_tb(NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void mb_tr_disas_log(const DisasContextBase *dcb, CPUState *cs)
|
||||
@ -1848,11 +1919,6 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
env->esr, env->fsr, env->btr, env->edr,
|
||||
env->ear, env->slr, env->shr);
|
||||
|
||||
for (i = 0; i < 12; i++) {
|
||||
qemu_fprintf(f, "rpvr%-2d=%08x%c",
|
||||
i, env->pvr.regs[i], i % 4 == 3 ? '\n' : ' ');
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
qemu_fprintf(f, "r%2.2d=%08x%c",
|
||||
i, env->regs[i], i % 4 == 3 ? '\n' : ' ');
|
||||
|
Loading…
Reference in New Issue
Block a user