/* CPUClass::reset() */ static void mb_cpu_reset(CPUState *s) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(s); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(cpu); CPUMBState *env = &cpu->env; mcc->parent_reset(s); memset(env, 0, offsetof(CPUMBState, end_reset_fields)); env->res_addr = RES_ADDR_NONE; /* Disable stack protector. */ env->shr = ~0; env->sregs[SR_PC] = cpu->cfg.base_vectors; #if defined(CONFIG_USER_ONLY) /* start in user mode with interrupts enabled. */ env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM; #else env->sregs[SR_MSR] = 0; mmu_init(&env->mmu); env->mmu.c_mmu = 3; env->mmu.c_mmu_tlb_access = 3; env->mmu.c_mmu_zones = 16; #endif }
static void secondary_cpu_reset(void *opaque) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(opaque); /* Configure secondary cores. */ microblaze_generic_fdt_reset(cpu); }
void mb_cpu_unassigned_access(CPUState *cs, hwaddr addr, bool is_write, bool is_exec, int is_asi, unsigned size) { MicroBlazeCPU *cpu; CPUMBState *env; qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n", addr, is_write ? 1 : 0, is_exec ? 1 : 0); if (cs == NULL) { return; } cpu = MICROBLAZE_CPU(cs); env = &cpu->env; if (!(env->sregs[SR_MSR] & MSR_EE)) { return; } env->sregs[SR_EAR] = addr; if (is_exec) { if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { env->sregs[SR_ESR] = ESR_EC_INSN_BUS; helper_raise_exception(env, EXCP_HW_EXCP); } } else { if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) { env->sregs[SR_ESR] = ESR_EC_DATA_BUS; helper_raise_exception(env, EXCP_HW_EXCP); } } }
/* CPUClass::reset() */ static void mb_cpu_reset(CPUState *s) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(s); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(cpu); CPUMBState *env = &cpu->env; if (qemu_loglevel_mask(CPU_LOG_RESET)) { qemu_log("CPU Reset (CPU %d)\n", s->cpu_index); log_cpu_state(env, 0); } mcc->parent_reset(s); memset(env, 0, offsetof(CPUMBState, breakpoints)); env->res_addr = RES_ADDR_NONE; tlb_flush(env, 1); /* Disable stack protector. */ env->shr = ~0; env->pvr.regs[0] = PVR0_PVR_FULL_MASK \ | PVR0_USE_BARREL_MASK \ | PVR0_USE_DIV_MASK \ | PVR0_USE_HW_MUL_MASK \ | PVR0_USE_EXC_MASK \ | PVR0_USE_ICACHE_MASK \ | PVR0_USE_DCACHE_MASK \ | PVR0_USE_MMU \ | (0xb << 8); env->pvr.regs[2] = PVR2_D_OPB_MASK \ | PVR2_D_LMB_MASK \ | PVR2_I_OPB_MASK \ | PVR2_I_LMB_MASK \ | PVR2_USE_MSR_INSTR \ | PVR2_USE_PCMP_INSTR \ | PVR2_USE_BARREL_MASK \ | PVR2_USE_DIV_MASK \ | PVR2_USE_HW_MUL_MASK \ | PVR2_USE_MUL64_MASK \ | PVR2_USE_FPU_MASK \ | PVR2_USE_FPU2_MASK \ | PVR2_FPU_EXC_MASK \ | 0; env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */ env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17); #if defined(CONFIG_USER_ONLY) /* start in user mode with interrupts enabled. */ env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM; env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp. */ #else env->sregs[SR_MSR] = 0; mmu_init(&env->mmu); env->mmu.c_mmu = 3; env->mmu.c_mmu_tlb_access = 3; env->mmu.c_mmu_zones = 16; #endif }
void mb_cpu_do_interrupt(CPUState *cs) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; cs->exception_index = -1; env->res_addr = RES_ADDR_NONE; env->regs[14] = env->sregs[SR_PC]; }
static void mb_cpu_realizefn(DeviceState *dev, Error **errp) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(dev); MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(dev); cpu_reset(CPU(cpu)); mcc->parent_realize(dev, errp); }
static void mb_cpu_initfn(Object *obj) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); CPUMBState *env = &cpu->env; cpu_exec_init(env); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); }
bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->sregs[SR_MSR] & MSR_IE) && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)) && !(env->iflags & (D_FLAG | IMM_FLAG))) { cs->exception_index = EXCP_IRQ; mb_cpu_do_interrupt(cs); return true; } return false; }
static void mb_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); CPUMBState *env = &cpu->env; cs->env_ptr = env; set_float_rounding_mode(float_round_nearest_even, &env->fp_status); #ifndef CONFIG_USER_ONLY /* Inbound IRQ and FIR lines */ qdev_init_gpio_in(DEVICE(cpu), microblaze_cpu_set_irq, 2); #endif }
static void mb_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); CPUMBState *env = &cpu->env; static bool tcg_initialized; cs->env_ptr = env; cpu_exec_init(env); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); if (tcg_enabled() && !tcg_initialized) { tcg_initialized = true; mb_tcg_init(); } }
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; unsigned int hit; if (env->sregs[SR_MSR] & MSR_VM) { hit = mmu_translate(&env->mmu, &lu, addr, 0, 0); if (hit) { vaddr = addr & TARGET_PAGE_MASK; paddr = lu.paddr + vaddr - lu.vaddr; } else paddr = 0; /* ???. */ } else paddr = addr & TARGET_PAGE_MASK; return paddr; }
static void mb_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); CPUMBState *env = &cpu->env; static bool tcg_initialized; cs->env_ptr = env; cpu_exec_init(env); set_float_rounding_mode(float_round_nearest_even, &env->fp_status); #ifndef CONFIG_USER_ONLY /* Inbound IRQ and FIR lines */ qdev_init_gpio_in(DEVICE(cpu), microblaze_cpu_set_irq, 2); #endif if (tcg_enabled() && !tcg_initialized) { tcg_initialized = true; mb_tcg_init(); } }
static void petalogix_s3adsp1800_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; DeviceState *dev; MicroBlazeCPU *cpu; DriveInfo *dinfo; int i; hwaddr ddr_base = MEMORY_BASEADDR; MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); MemoryRegion *phys_ram = g_new(MemoryRegion, 1); qemu_irq irq[32]; MemoryRegion *sysmem = get_system_memory(); cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); object_property_set_str(OBJECT(cpu), "7.10.d", "version", &error_abort); object_property_set_bool(OBJECT(cpu), true, "realized", &error_abort); /* Attach emulated BRAM through the LMB. */ memory_region_init_ram(phys_lmb_bram, NULL, "petalogix_s3adsp1800.lmb_bram", LMB_BRAM_SIZE, &error_fatal); memory_region_add_subregion(sysmem, 0x00000000, phys_lmb_bram); memory_region_init_ram(phys_ram, NULL, "petalogix_s3adsp1800.ram", ram_size, &error_fatal); memory_region_add_subregion(sysmem, ddr_base, phys_ram); dinfo = drive_get(IF_PFLASH, 0, 0); pflash_cfi01_register(FLASH_BASEADDR, NULL, "petalogix_s3adsp1800.flash", FLASH_SIZE, dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, 64 * KiB, FLASH_SIZE >> 16, 1, 0x89, 0x18, 0x0000, 0x0, 1); dev = qdev_create(NULL, "xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 1 << ETHLITE_IRQ | 1 << UARTLITE_IRQ); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ)); for (i = 0; i < 32; i++) { irq[i] = qdev_get_gpio_in(dev, i); } xilinx_uartlite_create(UARTLITE_BASEADDR, irq[UARTLITE_IRQ], serial_hd(0)); /* 2 timers at irq 2 @ 62 Mhz. */ dev = qdev_create(NULL, "xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", 0); qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]); qemu_check_nic_model(&nd_table[0], "xlnx.xps-ethernetlite"); dev = qdev_create(NULL, "xlnx.xps-ethernetlite"); qdev_set_nic_properties(dev, &nd_table[0]); qdev_prop_set_uint32(dev, "tx-ping-pong", 0); qdev_prop_set_uint32(dev, "rx-ping-pong", 0); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, ETHLITE_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[ETHLITE_IRQ]); create_unimplemented_device("gpio", GPIO_BASEADDR, 0x10000); microblaze_load_kernel(cpu, ddr_base, ram_size, machine->initrd_filename, BINARY_DEVICE_TREE_FILE, NULL); }
static void microblaze_generic_fdt_init(MachineState *machine) { CPUState *cpu; ram_addr_t ram_kernel_base = 0, ram_kernel_size = 0; void *fdt = NULL; const char *dtb_arg, *hw_dtb_arg; QemuOpts *machine_opts; int fdt_size; /* for memory node */ char node_path[DT_PATH_LENGTH]; FDTMachineInfo *fdti; MemoryRegion *main_mem; /* For DMA node */ char dma_path[DT_PATH_LENGTH] = { 0 }; uint32_t memory_phandle; /* For Ethernet nodes */ char **eth_paths; char *phy_path; char *mdio_path; uint32_t n_eth; uint32_t prop_val; machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); if (!machine_opts) { goto no_dtb_arg; } dtb_arg = qemu_opt_get(machine_opts, "dtb"); hw_dtb_arg = qemu_opt_get(machine_opts, "hw-dtb"); if (!dtb_arg && !hw_dtb_arg) { goto no_dtb_arg; } /* If the user only provided a -dtb, use it as the hw description. */ if (!hw_dtb_arg) { hw_dtb_arg = dtb_arg; } fdt = load_device_tree(hw_dtb_arg, &fdt_size); if (!fdt) { hw_error("Error: Unable to load Device Tree %s\n", hw_dtb_arg); return; } if (IS_PETALINUX_MACHINE) { /* Mark the simple-bus as incompatible as it breaks the Microblaze * PetaLinux boot */ add_to_compat_table(NULL, "compatible:simple-bus", NULL); } /* find memory node or add new one if needed */ while (qemu_fdt_get_node_by_name(fdt, node_path, "memory")) { qemu_fdt_add_subnode(fdt, "/memory@0"); qemu_fdt_setprop_cells(fdt, "/memory@0", "reg", 0, machine->ram_size); } if (!qemu_fdt_getprop(fdt, "/memory", "compatible", NULL, 0, NULL)) { qemu_fdt_setprop_string(fdt, "/memory", "compatible", "qemu:memory-region"); qemu_fdt_setprop_cells(fdt, "/memory", "qemu,ram", 1); } if (IS_PETALINUX_MACHINE) { /* If using a *-plnx machine, the AXI DMA memory links are not included * in the DTB by default. To avoid seg faults, add the links in here if * they have not already been added by the user */ qemu_fdt_get_node_by_name(fdt, dma_path, "dma"); if (strcmp(dma_path, "") != 0) { memory_phandle = qemu_fdt_check_phandle(fdt, node_path); if (!memory_phandle) { memory_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_setprop_cells(fdt, "/memory", "linux,phandle", memory_phandle); qemu_fdt_setprop_cells(fdt, "/memory", "phandle", memory_phandle); } if (!qemu_fdt_getprop(fdt, dma_path, "sg", NULL, 0, NULL)) { qemu_fdt_setprop_phandle(fdt, dma_path, "sg", node_path); } if (!qemu_fdt_getprop(fdt, dma_path, "s2mm", NULL, 0, NULL)) { qemu_fdt_setprop_phandle(fdt, dma_path, "s2mm", node_path); } if (!qemu_fdt_getprop(fdt, dma_path, "mm2s", NULL, 0, NULL)) { qemu_fdt_setprop_phandle(fdt, dma_path, "mm2s", node_path); } } /* Copy phyaddr value from phy node reg property */ n_eth = qemu_fdt_get_n_nodes_by_name(fdt, ð_paths, "ethernet"); while (n_eth--) { mdio_path = qemu_fdt_get_child_by_name(fdt, eth_paths[n_eth], "mdio"); if (mdio_path) { phy_path = qemu_fdt_get_child_by_name(fdt, mdio_path, "phy"); if (phy_path) { prop_val = qemu_fdt_getprop_cell(fdt, phy_path, "reg", NULL, 0, NULL, &error_abort); qemu_fdt_setprop_cell(fdt, eth_paths[n_eth], "xlnx,phyaddr", prop_val); g_free(phy_path); } else { qemu_log_mask(LOG_GUEST_ERROR, "phy not found in %s", mdio_path); } g_free(mdio_path); } g_free(eth_paths[n_eth]); } g_free(eth_paths); } /* Instantiate peripherals from the FDT. */ fdti = fdt_generic_create_machine(fdt, NULL); main_mem = MEMORY_REGION(object_resolve_path(node_path, NULL)); ram_kernel_base = object_property_get_int(OBJECT(main_mem), "addr", NULL); ram_kernel_size = object_property_get_int(OBJECT(main_mem), "size", NULL); if (!memory_region_is_mapped(main_mem)) { /* If the memory region is not mapped, map it here. * It has to be mapped somewhere, so guess that the base address * is where the kernel starts */ memory_region_add_subregion(get_system_memory(), ram_kernel_base, main_mem); if (ram_kernel_base && IS_PETALINUX_MACHINE) { /* If the memory added is at an offset from zero QEMU will error * when an ISR/exception is triggered. Add a small amount of hack * RAM to handle this. */ MemoryRegion *hack_ram = g_new(MemoryRegion, 1); memory_region_init_ram(hack_ram, NULL, "hack_ram", 0x1000, &error_abort); vmstate_register_ram_global(hack_ram); memory_region_add_subregion(get_system_memory(), 0, hack_ram); } } fdt_init_destroy_fdti(fdti); fdt_g = fdt; microblaze_load_kernel(MICROBLAZE_CPU(first_cpu), ram_kernel_base, ram_kernel_size, machine->initrd_filename, NULL, microblaze_generic_fdt_reset, 0, fdt, fdt_size); /* Register FDT to prop mapper for secondary cores. */ cpu = CPU_NEXT(first_cpu); while (cpu) { qemu_register_reset(secondary_cpu_reset, cpu); cpu = CPU_NEXT(cpu); } return; no_dtb_arg: if (!QTEST_RUNNING) { hw_error("DTB must be specified for %s machine model\n", MACHINE_NAME); } return; }
static void petalogix_ml605_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev, *dma, *eth0; Object *ds, *cs; MicroBlazeCPU *cpu; SysBusDevice *busdev; DriveInfo *dinfo; int i; MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); MemoryRegion *phys_ram = g_new(MemoryRegion, 1); qemu_irq irq[32]; /* init CPUs */ cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); object_property_set_str(OBJECT(cpu), "8.10.a", "version", &error_abort); /* Use FPU but don't use floating point conversion and square * root instructions */ object_property_set_int(OBJECT(cpu), 1, "use-fpu", &error_abort); object_property_set_bool(OBJECT(cpu), true, "dcache-writeback", &error_abort); object_property_set_bool(OBJECT(cpu), true, "endianness", &error_abort); object_property_set_bool(OBJECT(cpu), true, "realized", &error_abort); /* Attach emulated BRAM through the LMB. */ memory_region_init_ram(phys_lmb_bram, NULL, "petalogix_ml605.lmb_bram", LMB_BRAM_SIZE, &error_fatal); vmstate_register_ram_global(phys_lmb_bram); memory_region_add_subregion(address_space_mem, 0x00000000, phys_lmb_bram); memory_region_init_ram(phys_ram, NULL, "petalogix_ml605.ram", ram_size, &error_fatal); vmstate_register_ram_global(phys_ram); memory_region_add_subregion(address_space_mem, MEMORY_BASEADDR, phys_ram); dinfo = drive_get(IF_PFLASH, 0, 0); /* 5th parameter 2 means bank-width * 10th paremeter 0 means little-endian */ pflash_cfi01_register(FLASH_BASEADDR, NULL, "petalogix_ml605.flash", FLASH_SIZE, dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, (64 * 1024), FLASH_SIZE >> 16, 2, 0x89, 0x18, 0x0000, 0x0, 0); dev = qdev_create(NULL, "xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 1 << TIMER_IRQ); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ)); for (i = 0; i < 32; i++) { irq[i] = qdev_get_gpio_in(dev, i); } serial_mm_init(address_space_mem, UART16550_BASEADDR + 0x1000, 2, irq[UART16550_IRQ], 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN); /* 2 timers at irq 2 @ 100 Mhz. */ dev = qdev_create(NULL, "xlnx.xps-timer"); qdev_prop_set_uint32(dev, "one-timer-only", 0); qdev_prop_set_uint32(dev, "clock-frequency", 100 * 1000000); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]); /* axi ethernet and dma initialization. */ qemu_check_nic_model(&nd_table[0], "xlnx.axi-ethernet"); eth0 = qdev_create(NULL, "xlnx.axi-ethernet"); dma = qdev_create(NULL, "xlnx.axi-dma"); /* FIXME: attach to the sysbus instead */ object_property_add_child(qdev_get_machine(), "xilinx-eth", OBJECT(eth0), NULL); object_property_add_child(qdev_get_machine(), "xilinx-dma", OBJECT(dma), NULL); ds = object_property_get_link(OBJECT(dma), "axistream-connected-target", NULL); cs = object_property_get_link(OBJECT(dma), "axistream-control-connected-target", NULL); qdev_set_nic_properties(eth0, &nd_table[0]); qdev_prop_set_uint32(eth0, "rxmem", 0x1000); qdev_prop_set_uint32(eth0, "txmem", 0x1000); object_property_set_link(OBJECT(eth0), OBJECT(ds), "axistream-connected", &error_abort); object_property_set_link(OBJECT(eth0), OBJECT(cs), "axistream-control-connected", &error_abort); qdev_init_nofail(eth0); sysbus_mmio_map(SYS_BUS_DEVICE(eth0), 0, AXIENET_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(eth0), 0, irq[AXIENET_IRQ]); ds = object_property_get_link(OBJECT(eth0), "axistream-connected-target", NULL); cs = object_property_get_link(OBJECT(eth0), "axistream-control-connected-target", NULL); qdev_prop_set_uint32(dma, "freqhz", 100 * 1000000); object_property_set_link(OBJECT(dma), OBJECT(ds), "axistream-connected", &error_abort); object_property_set_link(OBJECT(dma), OBJECT(cs), "axistream-control-connected", &error_abort); qdev_init_nofail(dma); sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, AXIDMA_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dma), 0, irq[AXIDMA_IRQ0]); sysbus_connect_irq(SYS_BUS_DEVICE(dma), 1, irq[AXIDMA_IRQ1]); { SSIBus *spi; dev = qdev_create(NULL, "xlnx.xps-spi"); qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, SPI_BASEADDR); sysbus_connect_irq(busdev, 0, irq[SPI_IRQ]); spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); for (i = 0; i < NUM_SPI_FLASHES; i++) { qemu_irq cs_line; dev = ssi_create_slave(spi, "n25q128"); cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); sysbus_connect_irq(busdev, i+1, cs_line); } } /* 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 */ microblaze_load_kernel(cpu, MEMORY_BASEADDR, ram_size, machine->initrd_filename, BINARY_DEVICE_TREE_FILE, NULL); }
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; int i = 0; Error *local_err = NULL; cpu_exec_realizefn(cs, &local_err); if (local_err != NULL) { error_propagate(errp, local_err); return; } 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; for (i = 0; mb_cpu_lookup[i].name && cpu->cfg.version; i++) { if (strcmp(mb_cpu_lookup[i].name, cpu->cfg.version) == 0) { version_code = mb_cpu_lookup[i].version_id; break; } } if (!version_code) { 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); 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); env->pvr.regs[5] |= cpu->cfg.dcache_writeback ? PVR5_DCACHE_WRITEBACK_MASK : 0; env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */ env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17); mcc->parent_realize(dev, errp); }
int mb_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int mmu_idx) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; unsigned int hit; unsigned int mmu_available; int r = 1; int prot; mmu_available = 0; if (env->pvr.regs[0] & PVR0_USE_MMU) { mmu_available = 1; if ((env->pvr.regs[0] & PVR0_PVR_FULL_MASK) && (env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) { mmu_available = 0; } } /* Translate if the MMU is available and enabled. */ if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) { target_ulong vaddr, paddr; struct microblaze_mmu_lookup lu; hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx); if (hit) { vaddr = address & TARGET_PAGE_MASK; paddr = lu.paddr + vaddr - lu.vaddr; qemu_log_mask(CPU_LOG_MMU, "MMU map mmu=%d v=%x p=%x prot=%x\n", mmu_idx, vaddr, paddr, lu.prot); tlb_set_page(cs, vaddr, paddr, lu.prot, mmu_idx, TARGET_PAGE_SIZE); r = 0; } else { env->sregs[SR_EAR] = address; qemu_log_mask(CPU_LOG_MMU, "mmu=%d miss v=%" VADDR_PRIx "\n", mmu_idx, address); switch (lu.err) { case ERR_PROT: env->sregs[SR_ESR] = rw == 2 ? 17 : 16; env->sregs[SR_ESR] |= (rw == 1) << 10; break; case ERR_MISS: env->sregs[SR_ESR] = rw == 2 ? 19 : 18; env->sregs[SR_ESR] |= (rw == 1) << 10; break; default: abort(); break; } if (cs->exception_index == EXCP_MMU) { cpu_abort(cs, "recursive faults\n"); } /* TLB miss. */ cs->exception_index = EXCP_MMU; } } else { /* MMU disabled or not available. */ address &= TARGET_PAGE_MASK; prot = PAGE_BITS; tlb_set_page(cs, address, address, prot, mmu_idx, TARGET_PAGE_SIZE); r = 0; } return r; }
static void mb_cpu_set_pc(CPUState *cs, vaddr value) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); cpu->env.sregs[SR_PC] = value; }
static void sprite_engine_init(MachineState *machine) { ram_addr_t ram_size = machine->ram_size; MemoryRegion *address_space_mem = get_system_memory(); DeviceState *dev; MicroBlazeCPU *cpu; DriveInfo *dinfo; int i; MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); MemoryRegion *phys_ram = g_new(MemoryRegion, 1); qemu_irq irq[32]; /* init CPUs */ cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); /* Use FPU but don't use floating point conversion and square * root instructions */ object_property_set_int(OBJECT(cpu), 1, "use-fpu", &error_abort); object_property_set_bool(OBJECT(cpu), true, "dcache-writeback", &error_abort); object_property_set_bool(OBJECT(cpu), true, "endianness", &error_abort); object_property_set_bool(OBJECT(cpu), true, "realized", &error_abort); /* Attach emulated BRAM through the LMB. */ memory_region_init_ram(phys_lmb_bram, NULL, "sprite_engine.lmb_bram", LMB_BRAM_SIZE, &error_fatal); vmstate_register_ram_global(phys_lmb_bram); memory_region_add_subregion(address_space_mem, 0x00000000, phys_lmb_bram); memory_region_init_ram(phys_ram, NULL, "sprite_engine.ram", ram_size, &error_fatal); vmstate_register_ram_global(phys_ram); memory_region_add_subregion(address_space_mem, MEMORY_BASEADDR, phys_ram); dinfo = drive_get(IF_PFLASH, 0, 0); /* 5th parameter 2 means bank-width * 10th paremeter 0 means little-endian */ pflash_cfi01_register(FLASH_BASEADDR, NULL, "sprite_engine.flash", FLASH_SIZE, dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, (64 * 1024), FLASH_SIZE >> 16, 2, 0x89, 0x18, 0x0000, 0x0, 0); dev = qdev_create(NULL, "xlnx.xps-intc"); qdev_prop_set_uint32(dev, "kind-of-intr", 1 << TIMER_IRQ); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(DEVICE(cpu), MB_CPU_IRQ)); for (i = 0; i < 32; i++) { irq[i] = qdev_get_gpio_in(dev, i); } // create a uartlite sysbus_create_simple("xlnx.xps-uartlite", UARTLITE_BASEADDR, irq[UARTLITE_IRQ]); // Create the vsync timer, and connect it to TIMER_IRQ dev = qdev_create(NULL, "sprite-engine.vsync"); qdev_prop_set_uint32(dev, "clock-frequency", 60000); qdev_init_nofail(dev); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]); /* sprite engine init */ dev = qdev_create(NULL, "sprite-engine"); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SPRITE_ENGINE_BASEADDR); /* sprite engine controllers init */ dev = qdev_create(NULL, "sprite-engine-controller"); qdev_prop_set_uint32(dev, "port", 1986); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SPRITE_ENGINE_CONTROLLER_1); dev = qdev_create(NULL, "sprite-engine-controller"); qdev_prop_set_uint32(dev, "port", 1987); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SPRITE_ENGINE_CONTROLLER_2); dev = qdev_create(NULL, "sprite-engine-controller"); qdev_prop_set_uint32(dev, "port", 1988); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SPRITE_ENGINE_CONTROLLER_3); dev = qdev_create(NULL, "sprite-engine-controller"); qdev_prop_set_uint32(dev, "port", 1989); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, SPRITE_ENGINE_CONTROLLER_4); /* 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 */ microblaze_load_kernel(cpu, MEMORY_BASEADDR, ram_size, machine->initrd_filename, BINARY_DEVICE_TREE_FILE, NULL); }
void mb_cpu_do_interrupt(CPUState *cs) { MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); CPUMBState *env = &cpu->env; uint32_t t; /* IMM flag cannot propagate across a branch and into the dslot. */ assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG))); assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); /* assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions. */ 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("Exception raised on system without exceptions!\n"); return; } env->regs[17] = env->sregs[SR_PC] + 4; env->sregs[SR_ESR] &= ~(1 << 12); /* Exception breaks branch + dslot sequence? */ if (env->iflags & D_FLAG) { env->sregs[SR_ESR] |= 1 << 12 ; env->sregs[SR_BTR] = env->btarget; } /* Disable the MMU. */ t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); env->sregs[SR_MSR] |= t; /* Exception in progress. */ env->sregs[SR_MSR] |= MSR_EIP; qemu_log_mask(CPU_LOG_INT, "hw exception at pc=%x ear=%x esr=%x iflags=%x\n", env->sregs[SR_PC], env->sregs[SR_EAR], env->sregs[SR_ESR], env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->iflags &= ~(IMM_FLAG | D_FLAG); env->sregs[SR_PC] = cpu->base_vectors + 0x20; break; case EXCP_MMU: env->regs[17] = env->sregs[SR_PC]; env->sregs[SR_ESR] &= ~(1 << 12); /* Exception breaks branch + dslot sequence? */ if (env->iflags & D_FLAG) { D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm)); env->sregs[SR_ESR] |= 1 << 12 ; env->sregs[SR_BTR] = env->btarget; /* Reexecute the branch. */ env->regs[17] -= 4; /* was the branch immprefixed?. */ if (env->bimm) { qemu_log_mask(CPU_LOG_INT, "bimm exception at pc=%x iflags=%x\n", env->sregs[SR_PC], env->iflags); env->regs[17] -= 4; log_cpu_state_mask(CPU_LOG_INT, cs, 0); } } else if (env->iflags & IMM_FLAG) { D(qemu_log("IMM_FLAG set at exception\n")); env->regs[17] -= 4; } /* Disable the MMU. */ t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); env->sregs[SR_MSR] |= t; /* Exception in progress. */ env->sregs[SR_MSR] |= MSR_EIP; qemu_log_mask(CPU_LOG_INT, "exception at pc=%x ear=%x iflags=%x\n", env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->iflags &= ~(IMM_FLAG | D_FLAG); env->sregs[SR_PC] = cpu->base_vectors + 0x20; break; case EXCP_IRQ: assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))); assert(env->sregs[SR_MSR] & MSR_IE); assert(!(env->iflags & D_FLAG)); t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; #if 0 #include "disas/disas.h" /* Useful instrumentation when debugging interrupt issues in either the models or in sw. */ { const char *sym; sym = lookup_symbol(env->sregs[SR_PC]); if (sym && (!strcmp("netif_rx", sym) || !strcmp("process_backlog", sym))) { qemu_log( "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", env->sregs[SR_PC], env->sregs[SR_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->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \ | MSR_UM | MSR_IE); env->sregs[SR_MSR] |= t; env->regs[14] = env->sregs[SR_PC]; env->sregs[SR_PC] = cpu->base_vectors + 0x10; //log_cpu_state_mask(CPU_LOG_INT, cs, 0); break; case EXCP_BREAK: case EXCP_HW_BREAK: assert(!(env->iflags & IMM_FLAG)); assert(!(env->iflags & D_FLAG)); t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; qemu_log_mask(CPU_LOG_INT, "break at pc=%x msr=%x %x iflags=%x\n", env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); log_cpu_state_mask(CPU_LOG_INT, cs, 0); env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); env->sregs[SR_MSR] |= t; env->sregs[SR_MSR] |= MSR_BIP; if (cs->exception_index == EXCP_HW_BREAK) { env->regs[16] = env->sregs[SR_PC]; env->sregs[SR_MSR] |= MSR_BIP; env->sregs[SR_PC] = cpu->base_vectors + 0x18; } else env->sregs[SR_PC] = env->btarget; break; default: cpu_abort(cs, "unhandled exception type=%d\n", cs->exception_index); break; } }